mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	USB: Add MUSB and TUSB support
This patch adds support for MUSB and TUSB controllers integrated into omap2430 and davinci. It also adds support for external tusb6010 controller. Cc: David Brownell <dbrownell@users.sourceforge.net> Cc: Tony Lindgren <tony@atomide.com> Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
		
							parent
							
								
									f331e40ee8
								
							
						
					
					
						commit
						550a7375fe
					
				
					 30 changed files with 15764 additions and 0 deletions
				
			
		| 
						 | 
					@ -2928,6 +2928,12 @@ M:	jirislaby@gmail.com
 | 
				
			||||||
L:	linux-kernel@vger.kernel.org
 | 
					L:	linux-kernel@vger.kernel.org
 | 
				
			||||||
S:	Maintained
 | 
					S:	Maintained
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER
 | 
				
			||||||
 | 
					P:     Felipe Balbi
 | 
				
			||||||
 | 
					M:     felipe.balbi@nokia.com
 | 
				
			||||||
 | 
					L:     linux-usb@vger.kernel.org
 | 
				
			||||||
 | 
					S:     Maintained
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MYRICOM MYRI-10G 10GbE DRIVER (MYRI10GE)
 | 
					MYRICOM MYRI-10G 10GbE DRIVER (MYRI10GE)
 | 
				
			||||||
P:	Andrew Gallatin
 | 
					P:	Andrew Gallatin
 | 
				
			||||||
M:	gallatin@myri.com
 | 
					M:	gallatin@myri.com
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,6 +57,7 @@ obj-$(CONFIG_ATA_OVER_ETH)	+= block/aoe/
 | 
				
			||||||
obj-$(CONFIG_PARIDE) 		+= block/paride/
 | 
					obj-$(CONFIG_PARIDE) 		+= block/paride/
 | 
				
			||||||
obj-$(CONFIG_TC)		+= tc/
 | 
					obj-$(CONFIG_TC)		+= tc/
 | 
				
			||||||
obj-$(CONFIG_USB)		+= usb/
 | 
					obj-$(CONFIG_USB)		+= usb/
 | 
				
			||||||
 | 
					obj-$(CONFIG_USB_MUSB_HDRC)	+= usb/musb/
 | 
				
			||||||
obj-$(CONFIG_PCI)		+= usb/
 | 
					obj-$(CONFIG_PCI)		+= usb/
 | 
				
			||||||
obj-$(CONFIG_USB_GADGET)	+= usb/gadget/
 | 
					obj-$(CONFIG_USB_GADGET)	+= usb/gadget/
 | 
				
			||||||
obj-$(CONFIG_SERIO)		+= input/serio/
 | 
					obj-$(CONFIG_SERIO)		+= input/serio/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -99,6 +99,8 @@ source "drivers/usb/mon/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
source "drivers/usb/host/Kconfig"
 | 
					source "drivers/usb/host/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					source "drivers/usb/musb/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
source "drivers/usb/class/Kconfig"
 | 
					source "drivers/usb/class/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
source "drivers/usb/storage/Kconfig"
 | 
					source "drivers/usb/storage/Kconfig"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -284,6 +284,16 @@ config USB_LH7A40X
 | 
				
			||||||
	default USB_GADGET
 | 
						default USB_GADGET
 | 
				
			||||||
	select USB_GADGET_SELECTED
 | 
						select USB_GADGET_SELECTED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# built in ../musb along with host support
 | 
				
			||||||
 | 
					config USB_GADGET_MUSB_HDRC
 | 
				
			||||||
 | 
						boolean "Inventra HDRC USB Peripheral (TI, ...)"
 | 
				
			||||||
 | 
						depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
 | 
				
			||||||
 | 
						select USB_GADGET_DUALSPEED
 | 
				
			||||||
 | 
						select USB_GADGET_SELECTED
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  This OTG-capable silicon IP is used in dual designs including
 | 
				
			||||||
 | 
						  the TI DaVinci, OMAP 243x, OMAP 343x, and TUSB 6010.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config USB_GADGET_OMAP
 | 
					config USB_GADGET_OMAP
 | 
				
			||||||
	boolean "OMAP USB Device Controller"
 | 
						boolean "OMAP USB Device Controller"
 | 
				
			||||||
	depends on ARCH_OMAP
 | 
						depends on ARCH_OMAP
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										176
									
								
								drivers/usb/musb/Kconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								drivers/usb/musb/Kconfig
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,176 @@
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# USB Dual Role (OTG-ready) Controller Drivers
 | 
				
			||||||
 | 
					# 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) && HAVE_CLK
 | 
				
			||||||
 | 
						select TWL4030_USB if MACH_OMAP_3430SDP
 | 
				
			||||||
 | 
						tristate 'Inventra Highspeed Dual Role Controller (TI, ...)'
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  Say Y here if your system has a dual role high speed USB
 | 
				
			||||||
 | 
						  controller based on the Mentor Graphics silicon IP.  Then
 | 
				
			||||||
 | 
						  configure options to match your silicon and the board
 | 
				
			||||||
 | 
						  it's being used with, including the USB peripheral role,
 | 
				
			||||||
 | 
						  or the USB host role, or both.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  Texas Instruments parts using this IP include DaVinci 644x,
 | 
				
			||||||
 | 
						  OMAP 243x, OMAP 343x, and TUSB 6010.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  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".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config USB_MUSB_SOC
 | 
				
			||||||
 | 
						boolean
 | 
				
			||||||
 | 
						depends on USB_MUSB_HDRC
 | 
				
			||||||
 | 
						default y if ARCH_DAVINCI
 | 
				
			||||||
 | 
						default y if ARCH_OMAP2430
 | 
				
			||||||
 | 
						default y if ARCH_OMAP34XX
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  Use a static <asm/arch/hdrc_cnf.h> file to describe how the
 | 
				
			||||||
 | 
						  controller is configured (endpoints, mechanisms, etc) on the
 | 
				
			||||||
 | 
						  current iteration of a given system-on-chip.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					comment "DaVinci 644x USB support"
 | 
				
			||||||
 | 
						depends on USB_MUSB_HDRC && ARCH_DAVINCI
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					comment "OMAP 243x high speed USB support"
 | 
				
			||||||
 | 
						depends on USB_MUSB_HDRC && ARCH_OMAP2430
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					comment "OMAP 343x high speed USB support"
 | 
				
			||||||
 | 
						depends on USB_MUSB_HDRC && ARCH_OMAP34XX
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config USB_TUSB6010
 | 
				
			||||||
 | 
						boolean "TUSB 6010 support"
 | 
				
			||||||
 | 
						depends on USB_MUSB_HDRC && !USB_MUSB_SOC
 | 
				
			||||||
 | 
						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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						   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.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						   Select this if your system has a Mini-AB connector, or
 | 
				
			||||||
 | 
						   to simplify certain kinds of configuration.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						   To implement your OTG Targeted Peripherals List (TPL), enable
 | 
				
			||||||
 | 
						   USB_OTG_WHITELIST and update "drivers/usb/core/otg_whitelist.h"
 | 
				
			||||||
 | 
						   to match your requirements.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					endchoice
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config MUSB_PIO_ONLY
 | 
				
			||||||
 | 
						bool 'Disable DMA (always use PIO)'
 | 
				
			||||||
 | 
						depends on USB_MUSB_HDRC
 | 
				
			||||||
 | 
						default y if USB_TUSB6010
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  All data is copied between memory and FIFO by the CPU.
 | 
				
			||||||
 | 
						  DMA controllers are ignored.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  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_INVENTRA_DMA
 | 
				
			||||||
 | 
						bool
 | 
				
			||||||
 | 
						depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
 | 
				
			||||||
 | 
						default ARCH_OMAP2430 || ARCH_OMAP34XX
 | 
				
			||||||
 | 
						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
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  Enable DMA transfers when TI CPPI DMA is available.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config USB_TUSB_OMAP_DMA
 | 
				
			||||||
 | 
						bool
 | 
				
			||||||
 | 
						depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
 | 
				
			||||||
 | 
						depends on USB_TUSB6010
 | 
				
			||||||
 | 
						depends on ARCH_OMAP
 | 
				
			||||||
 | 
						default y
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  Enable DMA transfers on TUSB 6010 when OMAP DMA is available.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config	USB_MUSB_LOGLEVEL
 | 
				
			||||||
 | 
						depends on USB_MUSB_HDRC
 | 
				
			||||||
 | 
						int  'Logging Level (0 - none / 3 - annoying / ... )'
 | 
				
			||||||
 | 
						default 0
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  Set the logging level. 0 disables the debugging altogether,
 | 
				
			||||||
 | 
						  although when USB_DEBUG is set the value is at least 1.
 | 
				
			||||||
 | 
						  Starting at level 3, per-transfer (urb, usb_request, packet,
 | 
				
			||||||
 | 
						  or dma transfer) tracing may kick in.
 | 
				
			||||||
							
								
								
									
										86
									
								
								drivers/usb/musb/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								drivers/usb/musb/Makefile
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,86 @@
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# for USB OTG silicon based on Mentor Graphics INVENTRA designs
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					musb_hdrc-objs := musb_core.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-$(CONFIG_USB_MUSB_HDRC)	+= musb_hdrc.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ($(CONFIG_ARCH_DAVINCI),y)
 | 
				
			||||||
 | 
						musb_hdrc-objs	+= davinci.o
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ($(CONFIG_USB_TUSB6010),y)
 | 
				
			||||||
 | 
						musb_hdrc-objs	+= tusb6010.o
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ($(CONFIG_ARCH_OMAP2430),y)
 | 
				
			||||||
 | 
						musb_hdrc-objs	+= omap2430.o
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ($(CONFIG_ARCH_OMAP3430),y)
 | 
				
			||||||
 | 
						musb_hdrc-objs	+= omap2430.o
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ($(CONFIG_USB_GADGET_MUSB_HDRC),y)
 | 
				
			||||||
 | 
						musb_hdrc-objs		+= musb_gadget_ep0.o musb_gadget.o
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ($(CONFIG_USB_MUSB_HDRC_HCD),y)
 | 
				
			||||||
 | 
						musb_hdrc-objs		+= musb_virthub.o musb_host.o
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 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-objs		+= musbhsdma.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    ifeq ($(CONFIG_USB_TI_CPPI_DMA),y)
 | 
				
			||||||
 | 
					      musb_hdrc-objs		+= cppi_dma.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      ifeq ($(CONFIG_USB_TUSB_OMAP_DMA),y)
 | 
				
			||||||
 | 
					        musb_hdrc-objs		+= tusb6010_omap.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      endif
 | 
				
			||||||
 | 
					    endif
 | 
				
			||||||
 | 
					  endif
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					################################################################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# FIXME remove all these extra "-DMUSB_* things, stick to CONFIG_*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ($(CONFIG_USB_INVENTRA_MUSB_HAS_AHB_ID),y)
 | 
				
			||||||
 | 
						EXTRA_CFLAGS += -DMUSB_AHB_ID
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Debugging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MUSB_DEBUG:=$(CONFIG_USB_MUSB_LOGLEVEL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ("$(strip $(MUSB_DEBUG))","")
 | 
				
			||||||
 | 
					    ifdef CONFIG_USB_DEBUG
 | 
				
			||||||
 | 
						MUSB_DEBUG:=1
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
						MUSB_DEBUG:=0
 | 
				
			||||||
 | 
					    endif
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifneq ($(MUSB_DEBUG),0)
 | 
				
			||||||
 | 
					    EXTRA_CFLAGS += -DDEBUG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ifeq ($(CONFIG_PROC_FS),y)
 | 
				
			||||||
 | 
						musb_hdrc-objs		+= musb_procfs.o
 | 
				
			||||||
 | 
					    endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EXTRA_CFLAGS += -DMUSB_DEBUG=$(MUSB_DEBUG)
 | 
				
			||||||
							
								
								
									
										1540
									
								
								drivers/usb/musb/cppi_dma.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1540
									
								
								drivers/usb/musb/cppi_dma.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										133
									
								
								drivers/usb/musb/cppi_dma.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								drivers/usb/musb/cppi_dma.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,133 @@
 | 
				
			||||||
 | 
					/* Copyright (C) 2005-2006 by Texas Instruments */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _CPPI_DMA_H_
 | 
				
			||||||
 | 
					#define _CPPI_DMA_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/slab.h>
 | 
				
			||||||
 | 
					#include <linux/list.h>
 | 
				
			||||||
 | 
					#include <linux/smp_lock.h>
 | 
				
			||||||
 | 
					#include <linux/errno.h>
 | 
				
			||||||
 | 
					#include <linux/dmapool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "musb_dma.h"
 | 
				
			||||||
 | 
					#include "musb_core.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* FIXME fully isolate CPPI from DaVinci ... the "CPPI generic" registers
 | 
				
			||||||
 | 
					 * would seem to be shared with the TUSB6020 (over VLYNQ).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "davinci.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* CPPI RX/TX state RAM */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct cppi_tx_stateram {
 | 
				
			||||||
 | 
						u32 tx_head;			/* "DMA packet" head descriptor */
 | 
				
			||||||
 | 
						u32 tx_buf;
 | 
				
			||||||
 | 
						u32 tx_current;			/* current descriptor */
 | 
				
			||||||
 | 
						u32 tx_buf_current;
 | 
				
			||||||
 | 
						u32 tx_info;			/* flags, remaining buflen */
 | 
				
			||||||
 | 
						u32 tx_rem_len;
 | 
				
			||||||
 | 
						u32 tx_dummy;			/* unused */
 | 
				
			||||||
 | 
						u32 tx_complete;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct cppi_rx_stateram {
 | 
				
			||||||
 | 
						u32 rx_skipbytes;
 | 
				
			||||||
 | 
						u32 rx_head;
 | 
				
			||||||
 | 
						u32 rx_sop;			/* "DMA packet" head descriptor */
 | 
				
			||||||
 | 
						u32 rx_current;			/* current descriptor */
 | 
				
			||||||
 | 
						u32 rx_buf_current;
 | 
				
			||||||
 | 
						u32 rx_len_len;
 | 
				
			||||||
 | 
						u32 rx_cnt_cnt;
 | 
				
			||||||
 | 
						u32 rx_complete;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* hw_options bits in CPPI buffer descriptors */
 | 
				
			||||||
 | 
					#define CPPI_SOP_SET	((u32)(1 << 31))
 | 
				
			||||||
 | 
					#define CPPI_EOP_SET	((u32)(1 << 30))
 | 
				
			||||||
 | 
					#define CPPI_OWN_SET	((u32)(1 << 29))	/* owned by cppi */
 | 
				
			||||||
 | 
					#define CPPI_EOQ_MASK	((u32)(1 << 28))
 | 
				
			||||||
 | 
					#define CPPI_ZERO_SET	((u32)(1 << 23))	/* rx saw zlp; tx issues one */
 | 
				
			||||||
 | 
					#define CPPI_RXABT_MASK	((u32)(1 << 19))	/* need more rx buffers */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CPPI_RECV_PKTLEN_MASK 0xFFFF
 | 
				
			||||||
 | 
					#define CPPI_BUFFER_LEN_MASK 0xFFFF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CPPI_TEAR_READY ((u32)(1 << 31))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* CPPI data structure definitions */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define	CPPI_DESCRIPTOR_ALIGN	16	/* bytes; 5-dec docs say 4-byte align */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct cppi_descriptor {
 | 
				
			||||||
 | 
						/* hardware overlay */
 | 
				
			||||||
 | 
						u32		hw_next;	/* next buffer descriptor Pointer */
 | 
				
			||||||
 | 
						u32		hw_bufp;	/* i/o buffer pointer */
 | 
				
			||||||
 | 
						u32		hw_off_len;	/* buffer_offset16, buffer_length16 */
 | 
				
			||||||
 | 
						u32		hw_options;	/* flags:  SOP, EOP etc*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct cppi_descriptor *next;
 | 
				
			||||||
 | 
						dma_addr_t	dma;		/* address of this descriptor */
 | 
				
			||||||
 | 
						u32		buflen;		/* for RX: original buffer length */
 | 
				
			||||||
 | 
					} __attribute__ ((aligned(CPPI_DESCRIPTOR_ALIGN)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct cppi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* CPPI  Channel Control structure */
 | 
				
			||||||
 | 
					struct cppi_channel {
 | 
				
			||||||
 | 
						struct dma_channel	channel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* back pointer to the DMA controller structure */
 | 
				
			||||||
 | 
						struct cppi		*controller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* which direction of which endpoint? */
 | 
				
			||||||
 | 
						struct musb_hw_ep	*hw_ep;
 | 
				
			||||||
 | 
						bool			transmit;
 | 
				
			||||||
 | 
						u8			index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* DMA modes:  RNDIS or "transparent" */
 | 
				
			||||||
 | 
						u8			is_rndis;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* book keeping for current transfer request */
 | 
				
			||||||
 | 
						dma_addr_t		buf_dma;
 | 
				
			||||||
 | 
						u32			buf_len;
 | 
				
			||||||
 | 
						u32			maxpacket;
 | 
				
			||||||
 | 
						u32			offset;		/* dma requested */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void __iomem		*state_ram;	/* CPPI state */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct cppi_descriptor	*freelist;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* BD management fields */
 | 
				
			||||||
 | 
						struct cppi_descriptor	*head;
 | 
				
			||||||
 | 
						struct cppi_descriptor	*tail;
 | 
				
			||||||
 | 
						struct cppi_descriptor	*last_processed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* use tx_complete in host role to track endpoints waiting for
 | 
				
			||||||
 | 
						 * FIFONOTEMPTY to clear.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct list_head	tx_complete;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* CPPI DMA controller object */
 | 
				
			||||||
 | 
					struct cppi {
 | 
				
			||||||
 | 
						struct dma_controller		controller;
 | 
				
			||||||
 | 
						struct musb			*musb;
 | 
				
			||||||
 | 
						void __iomem			*mregs;		/* Mentor regs */
 | 
				
			||||||
 | 
						void __iomem			*tibase;	/* TI/CPPI regs */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct cppi_channel		tx[MUSB_C_NUM_EPT - 1];
 | 
				
			||||||
 | 
						struct cppi_channel		rx[MUSB_C_NUM_EPR - 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct dma_pool			*pool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct list_head		tx_complete;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* irq handling hook */
 | 
				
			||||||
 | 
					extern void cppi_completion(struct musb *, u32 rx, u32 tx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif				/* end of ifndef _CPPI_DMA_H_ */
 | 
				
			||||||
							
								
								
									
										462
									
								
								drivers/usb/musb/davinci.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										462
									
								
								drivers/usb/musb/davinci.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,462 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2005-2006 by Texas Instruments
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This file is part of the Inventra Controller Driver for Linux.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Inventra Controller Driver for Linux is free software; you
 | 
				
			||||||
 | 
					 * can redistribute it and/or modify it under the terms of the GNU
 | 
				
			||||||
 | 
					 * General Public License version 2 as published by the Free Software
 | 
				
			||||||
 | 
					 * Foundation.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Inventra Controller Driver for Linux is distributed in
 | 
				
			||||||
 | 
					 * the hope that it will be useful, but WITHOUT ANY WARRANTY;
 | 
				
			||||||
 | 
					 * without even the implied warranty of MERCHANTABILITY or
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 | 
				
			||||||
 | 
					 * License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 * along with The Inventra Controller Driver for Linux ; if not,
 | 
				
			||||||
 | 
					 * write to the Free Software Foundation, Inc., 59 Temple Place,
 | 
				
			||||||
 | 
					 * Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include <linux/sched.h>
 | 
				
			||||||
 | 
					#include <linux/slab.h>
 | 
				
			||||||
 | 
					#include <linux/init.h>
 | 
				
			||||||
 | 
					#include <linux/list.h>
 | 
				
			||||||
 | 
					#include <linux/delay.h>
 | 
				
			||||||
 | 
					#include <linux/clk.h>
 | 
				
			||||||
 | 
					#include <linux/io.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <asm/arch/hardware.h>
 | 
				
			||||||
 | 
					#include <asm/arch/memory.h>
 | 
				
			||||||
 | 
					#include <asm/arch/gpio.h>
 | 
				
			||||||
 | 
					#include <asm/mach-types.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "musb_core.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_MACH_DAVINCI_EVM
 | 
				
			||||||
 | 
					#include <asm/arch/i2c-client.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "davinci.h"
 | 
				
			||||||
 | 
					#include "cppi_dma.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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
 | 
				
			||||||
 | 
					 * (overriding SUSPENDM?) then likely needs to stay off.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void phy_on(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* start the on-chip PHY and its PLL */
 | 
				
			||||||
 | 
						__raw_writel(USBPHY_SESNDEN | USBPHY_VBDTCTEN | USBPHY_PHYPLLON,
 | 
				
			||||||
 | 
								(void __force __iomem *) IO_ADDRESS(USBPHY_CTL_PADDR));
 | 
				
			||||||
 | 
						while ((__raw_readl((void __force __iomem *)
 | 
				
			||||||
 | 
									IO_ADDRESS(USBPHY_CTL_PADDR))
 | 
				
			||||||
 | 
								& USBPHY_PHYCLKGD) == 0)
 | 
				
			||||||
 | 
							cpu_relax();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void phy_off(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* powerdown the on-chip PHY and its oscillator */
 | 
				
			||||||
 | 
						__raw_writel(USBPHY_OSCPDWN | USBPHY_PHYPDWN, (void __force __iomem *)
 | 
				
			||||||
 | 
								IO_ADDRESS(USBPHY_CTL_PADDR));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int dma_off = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void musb_platform_enable(struct musb *musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u32	tmp, old, val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* workaround:  setup irqs through both register sets */
 | 
				
			||||||
 | 
						tmp = (musb->epmask & DAVINCI_USB_TX_ENDPTS_MASK)
 | 
				
			||||||
 | 
								<< DAVINCI_USB_TXINT_SHIFT;
 | 
				
			||||||
 | 
						musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp);
 | 
				
			||||||
 | 
						old = tmp;
 | 
				
			||||||
 | 
						tmp = (musb->epmask & (0xfffe & DAVINCI_USB_RX_ENDPTS_MASK))
 | 
				
			||||||
 | 
								<< DAVINCI_USB_RXINT_SHIFT;
 | 
				
			||||||
 | 
						musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp);
 | 
				
			||||||
 | 
						tmp |= old;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						val = ~MUSB_INTR_SOF;
 | 
				
			||||||
 | 
						tmp |= ((val & 0x01ff) << DAVINCI_USB_USBINT_SHIFT);
 | 
				
			||||||
 | 
						musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (is_dma_capable() && !dma_off)
 | 
				
			||||||
 | 
							printk(KERN_WARNING "%s %s: dma not reactivated\n",
 | 
				
			||||||
 | 
									__FILE__, __func__);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							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,
 | 
				
			||||||
 | 
								DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Disable the HDRC and flush interrupts
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void musb_platform_disable(struct musb *musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* because we don't set CTRLR.UINT, "important" to:
 | 
				
			||||||
 | 
						 *  - not read/write INTRUSB/INTRUSBE
 | 
				
			||||||
 | 
						 *  - (except during initial setup, as workaround)
 | 
				
			||||||
 | 
						 *  - use INTSETR/INTCLRR instead
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_CLR_REG,
 | 
				
			||||||
 | 
								  DAVINCI_USB_USBINT_MASK
 | 
				
			||||||
 | 
								| DAVINCI_USB_TXINT_MASK
 | 
				
			||||||
 | 
								| DAVINCI_USB_RXINT_MASK);
 | 
				
			||||||
 | 
						musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
 | 
				
			||||||
 | 
						musb_writel(musb->ctrl_base, DAVINCI_USB_EOI_REG, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (is_dma_capable() && !dma_off)
 | 
				
			||||||
 | 
							WARNING("dma still active\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* REVISIT it's not clear whether DaVinci can support full OTG.  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int vbus_state = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_MUSB_HDRC_HCD
 | 
				
			||||||
 | 
					#define	portstate(stmt)		stmt
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define	portstate(stmt)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* VBUS SWITCHING IS BOARD-SPECIFIC */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_MACH_DAVINCI_EVM
 | 
				
			||||||
 | 
					#ifndef CONFIG_MACH_DAVINCI_EVM_OTG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* I2C operations are always synchronous, and require a task context.
 | 
				
			||||||
 | 
					 * With unloaded systems, using the shared workqueue seems to suffice
 | 
				
			||||||
 | 
					 * to satisfy the 100msec A_WAIT_VRISE timeout...
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void evm_deferred_drvvbus(struct work_struct *ignored)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						davinci_i2c_expander_op(0x3a, USB_DRVVBUS, vbus_state);
 | 
				
			||||||
 | 
						vbus_state = !vbus_state;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static DECLARE_WORK(evm_vbus_work, evm_deferred_drvvbus);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif	/* modified board */
 | 
				
			||||||
 | 
					#endif	/* EVM */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void davinci_source_power(struct musb *musb, int is_on, int immediate)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (is_on)
 | 
				
			||||||
 | 
							is_on = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (vbus_state == is_on)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						vbus_state = !is_on;		/* 0/1 vs "-1 == unknown/init" */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_MACH_DAVINCI_EVM
 | 
				
			||||||
 | 
						if (machine_is_davinci_evm()) {
 | 
				
			||||||
 | 
					#ifdef CONFIG_MACH_DAVINCI_EVM_OTG
 | 
				
			||||||
 | 
							/* modified EVM board switching VBUS with GPIO(6) not I2C
 | 
				
			||||||
 | 
							 * NOTE:  PINMUX0.RGB888 (bit23) must be clear
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (is_on)
 | 
				
			||||||
 | 
								gpio_set(GPIO(6));
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								gpio_clear(GPIO(6));
 | 
				
			||||||
 | 
							immediate = 1;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							if (immediate)
 | 
				
			||||||
 | 
								davinci_i2c_expander_op(0x3a, USB_DRVVBUS, !is_on);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								schedule_work(&evm_vbus_work);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						if (immediate)
 | 
				
			||||||
 | 
							vbus_state = is_on;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void davinci_set_vbus(struct musb *musb, int is_on)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						WARN_ON(is_on && is_peripheral_active(musb));
 | 
				
			||||||
 | 
						davinci_source_power(musb, is_on, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define	POLL_SECONDS	2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct timer_list otg_workaround;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void otg_timer(unsigned long _musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct musb		*musb = (void *)_musb;
 | 
				
			||||||
 | 
						void __iomem		*mregs = musb->mregs;
 | 
				
			||||||
 | 
						u8			devctl;
 | 
				
			||||||
 | 
						unsigned long		flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* We poll because DaVinci's won't expose several OTG-critical
 | 
				
			||||||
 | 
						* status change events (from the transceiver) otherwise.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						devctl = musb_readb(mregs, MUSB_DEVCTL);
 | 
				
			||||||
 | 
						DBG(7, "poll devctl %02x (%s)\n", devctl, otg_state_string(musb));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_irqsave(&musb->lock, flags);
 | 
				
			||||||
 | 
						switch (musb->xceiv.state) {
 | 
				
			||||||
 | 
						case OTG_STATE_A_WAIT_VFALL:
 | 
				
			||||||
 | 
							/* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL
 | 
				
			||||||
 | 
							 * seems to mis-handle session "start" otherwise (or in our
 | 
				
			||||||
 | 
							 * case "recover"), in routine "VBUS was valid by the time
 | 
				
			||||||
 | 
							 * VBUSERR got reported during enumeration" cases.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (devctl & MUSB_DEVCTL_VBUS) {
 | 
				
			||||||
 | 
								mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
 | 
				
			||||||
 | 
							musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
 | 
				
			||||||
 | 
								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
 | 
				
			||||||
 | 
							 * when to switch to the A-Default state machine (by setting
 | 
				
			||||||
 | 
							 * the DEVCTL.SESSION flag).
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * Workaround:  whenever we're in B_IDLE, try setting the
 | 
				
			||||||
 | 
							 * session flag every few seconds.  If it works, ID was
 | 
				
			||||||
 | 
							 * grounded and we're now in the A-Default state machine.
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * NOTE setting the session flag is _supposed_ to trigger
 | 
				
			||||||
 | 
							 * SRP, but clearly it doesn't.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							musb_writeb(mregs, MUSB_DEVCTL,
 | 
				
			||||||
 | 
									devctl | MUSB_DEVCTL_SESSION);
 | 
				
			||||||
 | 
							devctl = musb_readb(mregs, MUSB_DEVCTL);
 | 
				
			||||||
 | 
							if (devctl & MUSB_DEVCTL_BDEVICE)
 | 
				
			||||||
 | 
								mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								musb->xceiv.state = OTG_STATE_A_IDLE;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						spin_unlock_irqrestore(&musb->lock, flags);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static irqreturn_t davinci_interrupt(int irq, void *__hci)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned long	flags;
 | 
				
			||||||
 | 
						irqreturn_t	retval = IRQ_NONE;
 | 
				
			||||||
 | 
						struct musb	*musb = __hci;
 | 
				
			||||||
 | 
						void __iomem	*tibase = musb->ctrl_base;
 | 
				
			||||||
 | 
						u32		tmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_irqsave(&musb->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* NOTE: DaVinci shadows the Mentor IRQs.  Don't manage them through
 | 
				
			||||||
 | 
						 * the Mentor registers (except for setup), use the TI ones and EOI.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Docs describe irq "vector" registers asociated with the CPPI and
 | 
				
			||||||
 | 
						 * USB EOI registers.  These hold a bitmask corresponding to the
 | 
				
			||||||
 | 
						 * current IRQ, not an irq handler address.  Would using those bits
 | 
				
			||||||
 | 
						 * resolve some of the races observed in this dispatch code??
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* CPPI interrupts share the same IRQ line, but have their own
 | 
				
			||||||
 | 
						 * mask, state, "vector", and EOI registers.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (is_cppi_enabled()) {
 | 
				
			||||||
 | 
							u32 cppi_tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
 | 
				
			||||||
 | 
							u32 cppi_rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (cppi_tx || cppi_rx) {
 | 
				
			||||||
 | 
								DBG(4, "CPPI IRQ t%x r%x\n", cppi_tx, cppi_rx);
 | 
				
			||||||
 | 
								cppi_completion(musb, cppi_rx, cppi_tx);
 | 
				
			||||||
 | 
								retval = IRQ_HANDLED;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						musb->int_rx = (tmp & DAVINCI_USB_RXINT_MASK)
 | 
				
			||||||
 | 
								>> DAVINCI_USB_RXINT_SHIFT;
 | 
				
			||||||
 | 
						musb->int_tx = (tmp & DAVINCI_USB_TXINT_MASK)
 | 
				
			||||||
 | 
								>> DAVINCI_USB_TXINT_SHIFT;
 | 
				
			||||||
 | 
						musb->int_usb = (tmp & DAVINCI_USB_USBINT_MASK)
 | 
				
			||||||
 | 
								>> DAVINCI_USB_USBINT_SHIFT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* DRVVBUS irqs are the only proxy we have (a very poor one!) for
 | 
				
			||||||
 | 
						 * DaVinci'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 we know its
 | 
				
			||||||
 | 
						 * value, but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
 | 
				
			||||||
 | 
						 * Also, DRVVBUS pulses for SRP (but not at 5V) ...
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (tmp & (DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT)) {
 | 
				
			||||||
 | 
							int	drvvbus = musb_readl(tibase, DAVINCI_USB_STAT_REG);
 | 
				
			||||||
 | 
							void __iomem *mregs = musb->mregs;
 | 
				
			||||||
 | 
							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);
 | 
				
			||||||
 | 
							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 (on EVM, a **long** time) for VBUS
 | 
				
			||||||
 | 
								 * to stop registering in devctl.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								musb->int_usb &= ~MUSB_INTR_VBUSERROR;
 | 
				
			||||||
 | 
								musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
 | 
				
			||||||
 | 
								mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
 | 
				
			||||||
 | 
								WARNING("VBUS error workaround (delay coming)\n");
 | 
				
			||||||
 | 
							} else if (is_host_enabled(musb) && drvvbus) {
 | 
				
			||||||
 | 
								musb->is_active = 1;
 | 
				
			||||||
 | 
								MUSB_HST_MODE(musb);
 | 
				
			||||||
 | 
								musb->xceiv.default_a = 1;
 | 
				
			||||||
 | 
								musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
 | 
				
			||||||
 | 
								portstate(musb->port1_status |= USB_PORT_STAT_POWER);
 | 
				
			||||||
 | 
								del_timer(&otg_workaround);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								musb->is_active = 0;
 | 
				
			||||||
 | 
								MUSB_DEV_MODE(musb);
 | 
				
			||||||
 | 
								musb->xceiv.default_a = 0;
 | 
				
			||||||
 | 
								musb->xceiv.state = OTG_STATE_B_IDLE;
 | 
				
			||||||
 | 
								portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* NOTE:  this must complete poweron within 100 msec */
 | 
				
			||||||
 | 
							davinci_source_power(musb, drvvbus, 0);
 | 
				
			||||||
 | 
							DBG(2, "VBUS %s (%s)%s, devctl %02x\n",
 | 
				
			||||||
 | 
									drvvbus ? "on" : "off",
 | 
				
			||||||
 | 
									otg_state_string(musb),
 | 
				
			||||||
 | 
									err ? " ERROR" : "",
 | 
				
			||||||
 | 
									devctl);
 | 
				
			||||||
 | 
							retval = IRQ_HANDLED;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (musb->int_tx || musb->int_rx || musb->int_usb)
 | 
				
			||||||
 | 
							retval |= musb_interrupt(musb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* irq stays asserted until EOI is written */
 | 
				
			||||||
 | 
						musb_writel(tibase, DAVINCI_USB_EOI_REG, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* poll for ID change */
 | 
				
			||||||
 | 
						if (is_otg_enabled(musb)
 | 
				
			||||||
 | 
								&& musb->xceiv.state == OTG_STATE_B_IDLE)
 | 
				
			||||||
 | 
							mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_unlock_irqrestore(&musb->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* REVISIT we sometimes get unhandled IRQs
 | 
				
			||||||
 | 
						 * (e.g. ep0).  not clear why...
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (retval != IRQ_HANDLED)
 | 
				
			||||||
 | 
							DBG(5, "unhandled? %08x\n", tmp);
 | 
				
			||||||
 | 
						return IRQ_HANDLED;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int __init musb_platform_init(struct musb *musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						void __iomem	*tibase = musb->ctrl_base;
 | 
				
			||||||
 | 
						u32		revision;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						musb->mregs += DAVINCI_BASE_OFFSET;
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
						/* REVISIT there's something odd about clocking, this
 | 
				
			||||||
 | 
						 * didn't appear do the job ...
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						musb->clock = clk_get(pDevice, "usb");
 | 
				
			||||||
 | 
						if (IS_ERR(musb->clock))
 | 
				
			||||||
 | 
							return PTR_ERR(musb->clock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status = clk_enable(musb->clock);
 | 
				
			||||||
 | 
						if (status < 0)
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* returns zero if e.g. not clocked */
 | 
				
			||||||
 | 
						revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
 | 
				
			||||||
 | 
						if (revision == 0)
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (is_host_enabled(musb))
 | 
				
			||||||
 | 
							setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						musb->board_set_vbus = davinci_set_vbus;
 | 
				
			||||||
 | 
						davinci_source_power(musb, 0, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* reset the controller */
 | 
				
			||||||
 | 
						musb_writel(tibase, DAVINCI_USB_CTRL_REG, 0x1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* start the on-chip PHY and its PLL */
 | 
				
			||||||
 | 
						phy_on();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msleep(5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* NOTE:  irqs are in mixed mode, not bypass to pure-musb */
 | 
				
			||||||
 | 
						pr_debug("DaVinci OTG revision %08x phy %03x control %02x\n",
 | 
				
			||||||
 | 
							revision, __raw_readl((void __force __iomem *)
 | 
				
			||||||
 | 
									IO_ADDRESS(USBPHY_CTL_PADDR)),
 | 
				
			||||||
 | 
							musb_readb(tibase, DAVINCI_USB_CTRL_REG));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						musb->isr = davinci_interrupt;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int musb_platform_exit(struct musb *musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (is_host_enabled(musb))
 | 
				
			||||||
 | 
							del_timer_sync(&otg_workaround);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						davinci_source_power(musb, 0 /*off*/, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* delay, to avoid problems with module reload */
 | 
				
			||||||
 | 
						if (is_host_enabled(musb) && musb->xceiv.default_a) {
 | 
				
			||||||
 | 
							int	maxdelay = 30;
 | 
				
			||||||
 | 
							u8	devctl, warn = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* if there's no peripheral connected, this can take a
 | 
				
			||||||
 | 
							 * long time to fall, especially on EVM with huge C133.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							do {
 | 
				
			||||||
 | 
								devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
 | 
				
			||||||
 | 
								if (!(devctl & MUSB_DEVCTL_VBUS))
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								if ((devctl & MUSB_DEVCTL_VBUS) != warn) {
 | 
				
			||||||
 | 
									warn = devctl & MUSB_DEVCTL_VBUS;
 | 
				
			||||||
 | 
									DBG(1, "VBUS %d\n",
 | 
				
			||||||
 | 
										warn >> MUSB_DEVCTL_VBUS_SHIFT);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								msleep(1000);
 | 
				
			||||||
 | 
								maxdelay--;
 | 
				
			||||||
 | 
							} while (maxdelay > 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* in OTG mode, another host might be connected */
 | 
				
			||||||
 | 
							if (devctl & MUSB_DEVCTL_VBUS)
 | 
				
			||||||
 | 
								DBG(1, "VBUS off timeout (devctl %02x)\n", devctl);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						phy_off();
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										100
									
								
								drivers/usb/musb/davinci.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								drivers/usb/musb/davinci.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,100 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2005-2006 by Texas Instruments
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __MUSB_HDRDF_H__
 | 
				
			||||||
 | 
					#define __MUSB_HDRDF_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * DaVinci-specific definitions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Integrated highspeed/otg PHY */
 | 
				
			||||||
 | 
					#define	USBPHY_CTL_PADDR	(DAVINCI_SYSTEM_MODULE_BASE + 0x34)
 | 
				
			||||||
 | 
					#define	USBPHY_PHYCLKGD		(1 << 8)
 | 
				
			||||||
 | 
					#define	USBPHY_SESNDEN		(1 << 7)	/* v(sess_end) comparator */
 | 
				
			||||||
 | 
					#define	USBPHY_VBDTCTEN		(1 << 6)	/* v(bus) comparator */
 | 
				
			||||||
 | 
					#define	USBPHY_PHYPLLON		(1 << 4)	/* override pll suspend */
 | 
				
			||||||
 | 
					#define	USBPHY_CLKO1SEL		(1 << 3)
 | 
				
			||||||
 | 
					#define	USBPHY_OSCPDWN		(1 << 2)
 | 
				
			||||||
 | 
					#define	USBPHY_PHYPDWN		(1 << 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* For now include usb OTG module registers here */
 | 
				
			||||||
 | 
					#define DAVINCI_USB_VERSION_REG		0x00
 | 
				
			||||||
 | 
					#define DAVINCI_USB_CTRL_REG		0x04
 | 
				
			||||||
 | 
					#define DAVINCI_USB_STAT_REG		0x08
 | 
				
			||||||
 | 
					#define DAVINCI_RNDIS_REG		0x10
 | 
				
			||||||
 | 
					#define DAVINCI_AUTOREQ_REG		0x14
 | 
				
			||||||
 | 
					#define DAVINCI_USB_INT_SOURCE_REG	0x20
 | 
				
			||||||
 | 
					#define DAVINCI_USB_INT_SET_REG		0x24
 | 
				
			||||||
 | 
					#define DAVINCI_USB_INT_SRC_CLR_REG	0x28
 | 
				
			||||||
 | 
					#define DAVINCI_USB_INT_MASK_REG	0x2c
 | 
				
			||||||
 | 
					#define DAVINCI_USB_INT_MASK_SET_REG	0x30
 | 
				
			||||||
 | 
					#define DAVINCI_USB_INT_MASK_CLR_REG	0x34
 | 
				
			||||||
 | 
					#define DAVINCI_USB_INT_SRC_MASKED_REG	0x38
 | 
				
			||||||
 | 
					#define DAVINCI_USB_EOI_REG		0x3c
 | 
				
			||||||
 | 
					#define DAVINCI_USB_EOI_INTVEC		0x40
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* BEGIN CPPI-generic (?) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* CPPI related registers */
 | 
				
			||||||
 | 
					#define DAVINCI_TXCPPI_CTRL_REG		0x80
 | 
				
			||||||
 | 
					#define DAVINCI_TXCPPI_TEAR_REG		0x84
 | 
				
			||||||
 | 
					#define DAVINCI_CPPI_EOI_REG		0x88
 | 
				
			||||||
 | 
					#define DAVINCI_CPPI_INTVEC_REG		0x8c
 | 
				
			||||||
 | 
					#define DAVINCI_TXCPPI_MASKED_REG	0x90
 | 
				
			||||||
 | 
					#define DAVINCI_TXCPPI_RAW_REG		0x94
 | 
				
			||||||
 | 
					#define DAVINCI_TXCPPI_INTENAB_REG	0x98
 | 
				
			||||||
 | 
					#define DAVINCI_TXCPPI_INTCLR_REG	0x9c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DAVINCI_RXCPPI_CTRL_REG		0xC0
 | 
				
			||||||
 | 
					#define DAVINCI_RXCPPI_MASKED_REG	0xD0
 | 
				
			||||||
 | 
					#define DAVINCI_RXCPPI_RAW_REG		0xD4
 | 
				
			||||||
 | 
					#define DAVINCI_RXCPPI_INTENAB_REG	0xD8
 | 
				
			||||||
 | 
					#define DAVINCI_RXCPPI_INTCLR_REG	0xDC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DAVINCI_RXCPPI_BUFCNT0_REG	0xE0
 | 
				
			||||||
 | 
					#define DAVINCI_RXCPPI_BUFCNT1_REG	0xE4
 | 
				
			||||||
 | 
					#define DAVINCI_RXCPPI_BUFCNT2_REG	0xE8
 | 
				
			||||||
 | 
					#define DAVINCI_RXCPPI_BUFCNT3_REG	0xEC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* CPPI state RAM entries */
 | 
				
			||||||
 | 
					#define DAVINCI_CPPI_STATERAM_BASE_OFFSET   0x100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DAVINCI_TXCPPI_STATERAM_OFFSET(chnum) \
 | 
				
			||||||
 | 
						(DAVINCI_CPPI_STATERAM_BASE_OFFSET +       ((chnum) * 0x40))
 | 
				
			||||||
 | 
					#define DAVINCI_RXCPPI_STATERAM_OFFSET(chnum) \
 | 
				
			||||||
 | 
						(DAVINCI_CPPI_STATERAM_BASE_OFFSET + 0x20 + ((chnum) * 0x40))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* CPPI masks */
 | 
				
			||||||
 | 
					#define DAVINCI_DMA_CTRL_ENABLE		1
 | 
				
			||||||
 | 
					#define DAVINCI_DMA_CTRL_DISABLE	0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DAVINCI_DMA_ALL_CHANNELS_ENABLE	0xF
 | 
				
			||||||
 | 
					#define DAVINCI_DMA_ALL_CHANNELS_DISABLE 0xF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* END CPPI-generic (?) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DAVINCI_USB_TX_ENDPTS_MASK	0x1f		/* ep0 + 4 tx */
 | 
				
			||||||
 | 
					#define DAVINCI_USB_RX_ENDPTS_MASK	0x1e		/* 4 rx */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DAVINCI_USB_USBINT_SHIFT	16
 | 
				
			||||||
 | 
					#define DAVINCI_USB_TXINT_SHIFT		0
 | 
				
			||||||
 | 
					#define DAVINCI_USB_RXINT_SHIFT		8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DAVINCI_INTR_DRVVBUS		0x0100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DAVINCI_USB_USBINT_MASK		0x01ff0000	/* 8 Mentor, DRVVBUS */
 | 
				
			||||||
 | 
					#define DAVINCI_USB_TXINT_MASK \
 | 
				
			||||||
 | 
						(DAVINCI_USB_TX_ENDPTS_MASK << DAVINCI_USB_TXINT_SHIFT)
 | 
				
			||||||
 | 
					#define DAVINCI_USB_RXINT_MASK \
 | 
				
			||||||
 | 
						(DAVINCI_USB_RX_ENDPTS_MASK << DAVINCI_USB_RXINT_SHIFT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DAVINCI_BASE_OFFSET		0x400
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif	/* __MUSB_HDRDF_H__ */
 | 
				
			||||||
							
								
								
									
										2266
									
								
								drivers/usb/musb/musb_core.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2266
									
								
								drivers/usb/musb/musb_core.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										517
									
								
								drivers/usb/musb/musb_core.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										517
									
								
								drivers/usb/musb/musb_core.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,517 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * MUSB OTG driver defines
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2005 Mentor Graphics Corporation
 | 
				
			||||||
 | 
					 * Copyright (C) 2005-2006 by Texas Instruments
 | 
				
			||||||
 | 
					 * Copyright (C) 2006-2007 Nokia Corporation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 | 
				
			||||||
 | 
					 * 02110-1301 USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 | 
				
			||||||
 | 
					 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
				
			||||||
 | 
					 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
				
			||||||
 | 
					 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 | 
				
			||||||
 | 
					 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
				
			||||||
 | 
					 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
				
			||||||
 | 
					 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __MUSB_CORE_H__
 | 
				
			||||||
 | 
					#define __MUSB_CORE_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/slab.h>
 | 
				
			||||||
 | 
					#include <linux/list.h>
 | 
				
			||||||
 | 
					#include <linux/interrupt.h>
 | 
				
			||||||
 | 
					#include <linux/smp_lock.h>
 | 
				
			||||||
 | 
					#include <linux/errno.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>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct musb;
 | 
				
			||||||
 | 
					struct musb_hw_ep;
 | 
				
			||||||
 | 
					struct musb_ep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "musb_debug.h"
 | 
				
			||||||
 | 
					#include "musb_dma.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_MUSB_SOC
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Get core configuration from a header converted (by cfg_conv)
 | 
				
			||||||
 | 
					 * from the Verilog config file generated by the core config utility
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * For now we assume that header is provided along with other
 | 
				
			||||||
 | 
					 * arch-specific files.  Discrete chips will need a build tweak.
 | 
				
			||||||
 | 
					 * So will using AHB IDs from silicon that provides them.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#include <asm/arch/hdrc_cnf.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "musb_io.h"
 | 
				
			||||||
 | 
					#include "musb_regs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "musb_gadget.h"
 | 
				
			||||||
 | 
					#include "../core/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 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/****************************** CONSTANTS ********************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef MUSB_C_NUM_EPS
 | 
				
			||||||
 | 
					#define MUSB_C_NUM_EPS ((u8)16)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef MUSB_MAX_END0_PACKET
 | 
				
			||||||
 | 
					#define MUSB_MAX_END0_PACKET ((u16)MUSB_EP0_FIFOSIZE)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* host side ep0 states */
 | 
				
			||||||
 | 
					enum musb_h_ep0_state {
 | 
				
			||||||
 | 
						MUSB_EP0_IDLE,
 | 
				
			||||||
 | 
						MUSB_EP0_START,			/* expect ack of setup */
 | 
				
			||||||
 | 
						MUSB_EP0_IN,			/* expect IN DATA */
 | 
				
			||||||
 | 
						MUSB_EP0_OUT,			/* expect ack of OUT DATA */
 | 
				
			||||||
 | 
						MUSB_EP0_STATUS,		/* expect ack of STATUS */
 | 
				
			||||||
 | 
					} __attribute__ ((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* peripheral side ep0 states */
 | 
				
			||||||
 | 
					enum musb_g_ep0_state {
 | 
				
			||||||
 | 
						MUSB_EP0_STAGE_SETUP,		/* idle, waiting for setup */
 | 
				
			||||||
 | 
						MUSB_EP0_STAGE_TX,		/* IN data */
 | 
				
			||||||
 | 
						MUSB_EP0_STAGE_RX,		/* OUT data */
 | 
				
			||||||
 | 
						MUSB_EP0_STAGE_STATUSIN,	/* (after OUT data) */
 | 
				
			||||||
 | 
						MUSB_EP0_STAGE_STATUSOUT,	/* (after IN data) */
 | 
				
			||||||
 | 
						MUSB_EP0_STAGE_ACKWAIT,		/* after zlp, before statusin */
 | 
				
			||||||
 | 
					} __attribute__ ((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* OTG protocol constants */
 | 
				
			||||||
 | 
					#define OTG_TIME_A_WAIT_VRISE	100		/* msec (max) */
 | 
				
			||||||
 | 
					#define OTG_TIME_A_WAIT_BCON	0		/* 0=infinite; min 1000 msec */
 | 
				
			||||||
 | 
					#define OTG_TIME_A_IDLE_BDIS	200		/* msec (min) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*************************** REGISTER ACCESS ********************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Endpoint registers (other than dynfifo setup) can be accessed either
 | 
				
			||||||
 | 
					 * 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)
 | 
				
			||||||
 | 
					/* REVISIT indexed access seemed to
 | 
				
			||||||
 | 
					 * misbehave (on DaVinci) for at least peripheral IN ...
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define	MUSB_FLAT_REG
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* TUSB mapping: "flat" plus ep0 special cases */
 | 
				
			||||||
 | 
					#if	defined(CONFIG_USB_TUSB6010)
 | 
				
			||||||
 | 
					#define musb_ep_select(_mbase, _epnum) \
 | 
				
			||||||
 | 
						musb_writeb((_mbase), MUSB_INDEX, (_epnum))
 | 
				
			||||||
 | 
					#define	MUSB_EP_OFFSET			MUSB_TUSB_OFFSET
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* "flat" mapping: each endpoint has its own i/o address */
 | 
				
			||||||
 | 
					#elif	defined(MUSB_FLAT_REG)
 | 
				
			||||||
 | 
					#define musb_ep_select(_mbase, _epnum)	(((void)(_mbase)), ((void)(_epnum)))
 | 
				
			||||||
 | 
					#define	MUSB_EP_OFFSET			MUSB_FLAT_OFFSET
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* "indexed" mapping: INDEX register controls register bank select */
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define musb_ep_select(_mbase, _epnum) \
 | 
				
			||||||
 | 
						musb_writeb((_mbase), MUSB_INDEX, (_epnum))
 | 
				
			||||||
 | 
					#define	MUSB_EP_OFFSET			MUSB_INDEXED_OFFSET
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/****************************** FUNCTIONS ********************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MUSB_HST_MODE(_musb)\
 | 
				
			||||||
 | 
						{ (_musb)->is_host = true; }
 | 
				
			||||||
 | 
					#define MUSB_DEV_MODE(_musb) \
 | 
				
			||||||
 | 
						{ (_musb)->is_host = false; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define test_devctl_hst_mode(_x) \
 | 
				
			||||||
 | 
						(musb_readb((_x)->mregs, MUSB_DEVCTL)&MUSB_DEVCTL_HM)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MUSB_MODE(musb) ((musb)->is_host ? "Host" : "Peripheral")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/******************************** TYPES *************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * struct musb_hw_ep - endpoint hardware (bidirectional)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Ordered slightly for better cacheline locality.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct musb_hw_ep {
 | 
				
			||||||
 | 
						struct musb		*musb;
 | 
				
			||||||
 | 
						void __iomem		*fifo;
 | 
				
			||||||
 | 
						void __iomem		*regs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_TUSB6010
 | 
				
			||||||
 | 
						void __iomem		*conf;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* index in musb->endpoints[]  */
 | 
				
			||||||
 | 
						u8			epnum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* hardware configuration, possibly dynamic */
 | 
				
			||||||
 | 
						bool			is_shared_fifo;
 | 
				
			||||||
 | 
						bool			tx_double_buffered;
 | 
				
			||||||
 | 
						bool			rx_double_buffered;
 | 
				
			||||||
 | 
						u16			max_packet_sz_tx;
 | 
				
			||||||
 | 
						u16			max_packet_sz_rx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct dma_channel	*tx_channel;
 | 
				
			||||||
 | 
						struct dma_channel	*rx_channel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_TUSB6010
 | 
				
			||||||
 | 
						/* 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 */
 | 
				
			||||||
 | 
						struct musb_qh		*in_qh;
 | 
				
			||||||
 | 
						struct musb_qh		*out_qh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#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)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_GADGET_MUSB_HDRC
 | 
				
			||||||
 | 
						return next_request(&hw_ep->ep_out);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * struct musb - Driver instance data.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct musb {
 | 
				
			||||||
 | 
						/* device lock */
 | 
				
			||||||
 | 
						spinlock_t		lock;
 | 
				
			||||||
 | 
						struct clk		*clock;
 | 
				
			||||||
 | 
						irqreturn_t		(*isr)(int, void *);
 | 
				
			||||||
 | 
						struct work_struct	irq_work;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* bulk traffic normally dedicates endpoint hardware, and each
 | 
				
			||||||
 | 
						 * direction has its own ring of host side endpoints.
 | 
				
			||||||
 | 
						 * we try to progress the transfer at the head of each endpoint's
 | 
				
			||||||
 | 
						 * queue until it completes or NAKs too much; then we try the next
 | 
				
			||||||
 | 
						 * endpoint.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct musb_hw_ep	*bulk_ep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct list_head	control;	/* of musb_qh */
 | 
				
			||||||
 | 
						struct list_head	in_bulk;	/* of musb_qh */
 | 
				
			||||||
 | 
						struct list_head	out_bulk;	/* of musb_qh */
 | 
				
			||||||
 | 
						struct musb_qh		*periodic[32];	/* tree of interrupt+iso */
 | 
				
			||||||
 | 
					#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 dma_controller	*dma_controller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct device		*controller;
 | 
				
			||||||
 | 
						void __iomem		*ctrl_base;
 | 
				
			||||||
 | 
						void __iomem		*mregs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_TUSB6010
 | 
				
			||||||
 | 
						dma_addr_t		async;
 | 
				
			||||||
 | 
						dma_addr_t		sync;
 | 
				
			||||||
 | 
						void __iomem		*sync_va;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* passed down from chip/board specific irq handlers */
 | 
				
			||||||
 | 
						u8			int_usb;
 | 
				
			||||||
 | 
						u16			int_rx;
 | 
				
			||||||
 | 
						u16			int_tx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct otg_transceiver	xceiv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int nIrq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct musb_hw_ep	 endpoints[MUSB_C_NUM_EPS];
 | 
				
			||||||
 | 
					#define control_ep		endpoints
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define VBUSERR_RETRY_COUNT	3
 | 
				
			||||||
 | 
						u16			vbuserr_retry;
 | 
				
			||||||
 | 
						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 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool			is_host;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int			a_wait_bcon;	/* VBUS timeout in msecs */
 | 
				
			||||||
 | 
						unsigned long		idle_timeout;	/* Next timeout in jiffies */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* active means connected and not suspended */
 | 
				
			||||||
 | 
						unsigned		is_active:1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unsigned is_multipoint:1;
 | 
				
			||||||
 | 
						unsigned ignore_disconnect:1;	/* during bus resets */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef C_MP_TX
 | 
				
			||||||
 | 
						unsigned bulk_split:1;
 | 
				
			||||||
 | 
					#define	can_bulk_split(musb,type) \
 | 
				
			||||||
 | 
							(((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_split)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define	can_bulk_split(musb, type)	0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef C_MP_RX
 | 
				
			||||||
 | 
						unsigned bulk_combine:1;
 | 
				
			||||||
 | 
					#define	can_bulk_combine(musb,type) \
 | 
				
			||||||
 | 
							(((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_combine)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define	can_bulk_combine(musb, type)	0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_GADGET_MUSB_HDRC
 | 
				
			||||||
 | 
						/* is_suspended means USB B_PERIPHERAL suspend */
 | 
				
			||||||
 | 
						unsigned		is_suspended:1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* may_wakeup means remote wakeup is enabled */
 | 
				
			||||||
 | 
						unsigned		may_wakeup:1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* is_self_powered is reported in device status and the
 | 
				
			||||||
 | 
						 * config descriptor.  is_bus_powered means B_PERIPHERAL
 | 
				
			||||||
 | 
						 * draws some VBUS current; both can be true.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						unsigned		is_self_powered:1;
 | 
				
			||||||
 | 
						unsigned		is_bus_powered:1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unsigned		set_address:1;
 | 
				
			||||||
 | 
						unsigned		test_mode:1;
 | 
				
			||||||
 | 
						unsigned		softconnect:1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u8			address;
 | 
				
			||||||
 | 
						u8			test_mode_nr;
 | 
				
			||||||
 | 
						u16			ackpend;		/* ep0 */
 | 
				
			||||||
 | 
						enum musb_g_ep0_state	ep0_state;
 | 
				
			||||||
 | 
						struct usb_gadget	g;			/* the gadget */
 | 
				
			||||||
 | 
						struct usb_gadget_driver *gadget_driver;	/* its driver */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef MUSB_CONFIG_PROC_FS
 | 
				
			||||||
 | 
						struct proc_dir_entry *proc_entry;
 | 
				
			||||||
 | 
					#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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***************************** Glue it together *****************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const char musb_driver_name[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern void musb_start(struct musb *musb);
 | 
				
			||||||
 | 
					extern void musb_stop(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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 void musb_platform_set_mode(struct musb *musb, u8 musb_mode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(CONFIG_USB_TUSB6010) || \
 | 
				
			||||||
 | 
						defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
 | 
				
			||||||
 | 
					extern void musb_platform_try_idle(struct musb *musb, unsigned long timeout);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define musb_platform_try_idle(x, y)		do {} while (0)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_TUSB6010
 | 
				
			||||||
 | 
					extern int musb_platform_get_vbus_status(struct musb *musb);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define musb_platform_get_vbus_status(x)	0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int __init musb_platform_init(struct musb *musb);
 | 
				
			||||||
 | 
					extern int musb_platform_exit(struct musb *musb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*-------------------------- ProcFS definitions ---------------------*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct proc_dir_entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if (MUSB_DEBUG > 0) && defined(MUSB_CONFIG_PROC_FS)
 | 
				
			||||||
 | 
					extern struct proc_dir_entry *musb_debug_create(char *name, struct musb *data);
 | 
				
			||||||
 | 
					extern void musb_debug_delete(char *name, struct musb *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					static inline struct proc_dir_entry *
 | 
				
			||||||
 | 
					musb_debug_create(char *name, struct musb *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static inline void musb_debug_delete(char *name, struct musb *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif	/* __MUSB_CORE_H__ */
 | 
				
			||||||
							
								
								
									
										66
									
								
								drivers/usb/musb/musb_debug.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								drivers/usb/musb/musb_debug.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,66 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * MUSB OTG driver debug defines
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2005 Mentor Graphics Corporation
 | 
				
			||||||
 | 
					 * Copyright (C) 2005-2006 by Texas Instruments
 | 
				
			||||||
 | 
					 * Copyright (C) 2006-2007 Nokia Corporation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 | 
				
			||||||
 | 
					 * 02110-1301 USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 | 
				
			||||||
 | 
					 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
				
			||||||
 | 
					 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
				
			||||||
 | 
					 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 | 
				
			||||||
 | 
					 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
				
			||||||
 | 
					 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
				
			||||||
 | 
					 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __MUSB_LINUX_DEBUG_H__
 | 
				
			||||||
 | 
					#define __MUSB_LINUX_DEBUG_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define yprintk(facility, format, args...) \
 | 
				
			||||||
 | 
						do { printk(facility "%s %d: " format , \
 | 
				
			||||||
 | 
						__func__, __LINE__ , ## args); } while (0)
 | 
				
			||||||
 | 
					#define WARNING(fmt, args...) yprintk(KERN_WARNING, fmt, ## args)
 | 
				
			||||||
 | 
					#define INFO(fmt, args...) yprintk(KERN_INFO, fmt, ## args)
 | 
				
			||||||
 | 
					#define ERR(fmt, args...) yprintk(KERN_ERR, fmt, ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define xprintk(level, facility, format, args...) do { \
 | 
				
			||||||
 | 
						if (_dbg_level(level)) { \
 | 
				
			||||||
 | 
							printk(facility "%s %d: " format , \
 | 
				
			||||||
 | 
									__func__, __LINE__ , ## args); \
 | 
				
			||||||
 | 
						} } while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if MUSB_DEBUG > 0
 | 
				
			||||||
 | 
					extern unsigned debug;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define debug	0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int _dbg_level(unsigned l)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return debug >= l;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DBG(level, fmt, args...) xprintk(level, KERN_DEBUG, fmt, ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const char *otg_state_string(struct musb *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif				/*  __MUSB_LINUX_DEBUG_H__ */
 | 
				
			||||||
							
								
								
									
										172
									
								
								drivers/usb/musb/musb_dma.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								drivers/usb/musb/musb_dma.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,172 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * MUSB OTG driver DMA controller abstraction
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2005 Mentor Graphics Corporation
 | 
				
			||||||
 | 
					 * Copyright (C) 2005-2006 by Texas Instruments
 | 
				
			||||||
 | 
					 * Copyright (C) 2006-2007 Nokia Corporation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 | 
				
			||||||
 | 
					 * 02110-1301 USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 | 
				
			||||||
 | 
					 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
				
			||||||
 | 
					 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
				
			||||||
 | 
					 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 | 
				
			||||||
 | 
					 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
				
			||||||
 | 
					 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
				
			||||||
 | 
					 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __MUSB_DMA_H__
 | 
				
			||||||
 | 
					#define __MUSB_DMA_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct musb_hw_ep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * DMA Controller Abstraction
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * DMA Controllers are abstracted to allow use of a variety of different
 | 
				
			||||||
 | 
					 * implementations of DMA, as allowed by the Inventra USB cores.  On the
 | 
				
			||||||
 | 
					 * host side, usbcore sets up the DMA mappings and flushes caches; on the
 | 
				
			||||||
 | 
					 * peripheral side, the gadget controller driver does.  Responsibilities
 | 
				
			||||||
 | 
					 * of a DMA controller driver include:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  - Handling the details of moving multiple USB packets
 | 
				
			||||||
 | 
					 *    in cooperation with the Inventra USB core, including especially
 | 
				
			||||||
 | 
					 *    the correct RX side treatment of short packets and buffer-full
 | 
				
			||||||
 | 
					 *    states (both of which terminate transfers).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  - Knowing the correlation between dma channels and the
 | 
				
			||||||
 | 
					 *    Inventra core's local endpoint resources and data direction.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  - Maintaining a list of allocated/available channels.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  - Updating channel status on interrupts,
 | 
				
			||||||
 | 
					 *    whether shared with the Inventra core or separate.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CONFIG_MUSB_PIO_ONLY
 | 
				
			||||||
 | 
					#define	is_dma_capable()	(1)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define	is_dma_capable()	(0)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_TI_CPPI_DMA
 | 
				
			||||||
 | 
					#define	is_cppi_enabled()	1
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define	is_cppi_enabled()	0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_TUSB_OMAP_DMA
 | 
				
			||||||
 | 
					#define tusb_dma_omap()			1
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define tusb_dma_omap()			0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * DMA channel status ... updated by the dma controller driver whenever that
 | 
				
			||||||
 | 
					 * status changes, and protected by the overall controller spinlock.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					enum dma_channel_status {
 | 
				
			||||||
 | 
						/* unallocated */
 | 
				
			||||||
 | 
						MUSB_DMA_STATUS_UNKNOWN,
 | 
				
			||||||
 | 
						/* allocated ... but not busy, no errors */
 | 
				
			||||||
 | 
						MUSB_DMA_STATUS_FREE,
 | 
				
			||||||
 | 
						/* busy ... transactions are active */
 | 
				
			||||||
 | 
						MUSB_DMA_STATUS_BUSY,
 | 
				
			||||||
 | 
						/* transaction(s) aborted due to ... dma or memory bus error */
 | 
				
			||||||
 | 
						MUSB_DMA_STATUS_BUS_ABORT,
 | 
				
			||||||
 | 
						/* transaction(s) aborted due to ... core error or USB fault */
 | 
				
			||||||
 | 
						MUSB_DMA_STATUS_CORE_ABORT
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct dma_controller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * struct dma_channel - A DMA channel.
 | 
				
			||||||
 | 
					 * @private_data: channel-private data
 | 
				
			||||||
 | 
					 * @max_len: the maximum number of bytes the channel can move in one
 | 
				
			||||||
 | 
					 *	transaction (typically representing many USB maximum-sized packets)
 | 
				
			||||||
 | 
					 * @actual_len: how many bytes have been transferred
 | 
				
			||||||
 | 
					 * @status: current channel status (updated e.g. on interrupt)
 | 
				
			||||||
 | 
					 * @desired_mode: true if mode 1 is desired; false if mode 0 is desired
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * channels are associated with an endpoint for the duration of at least
 | 
				
			||||||
 | 
					 * one usb transfer.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct dma_channel {
 | 
				
			||||||
 | 
						void			*private_data;
 | 
				
			||||||
 | 
						/* FIXME not void* private_data, but a dma_controller * */
 | 
				
			||||||
 | 
						size_t			max_len;
 | 
				
			||||||
 | 
						size_t			actual_len;
 | 
				
			||||||
 | 
						enum dma_channel_status	status;
 | 
				
			||||||
 | 
						bool			desired_mode;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * dma_channel_status - return status of dma channel
 | 
				
			||||||
 | 
					 * @c: the channel
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns the software's view of the channel status.  If that status is BUSY
 | 
				
			||||||
 | 
					 * then it's possible that the hardware has completed (or aborted) a transfer,
 | 
				
			||||||
 | 
					 * so the driver needs to update that status.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline enum dma_channel_status
 | 
				
			||||||
 | 
					dma_channel_status(struct dma_channel *c)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return (is_dma_capable() && c) ? c->status : MUSB_DMA_STATUS_UNKNOWN;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * struct dma_controller - A DMA Controller.
 | 
				
			||||||
 | 
					 * @start: call this to start a DMA controller;
 | 
				
			||||||
 | 
					 *	return 0 on success, else negative errno
 | 
				
			||||||
 | 
					 * @stop: call this to stop a DMA controller
 | 
				
			||||||
 | 
					 *	return 0 on success, else negative errno
 | 
				
			||||||
 | 
					 * @channel_alloc: call this to allocate a DMA channel
 | 
				
			||||||
 | 
					 * @channel_release: call this to release a DMA channel
 | 
				
			||||||
 | 
					 * @channel_abort: call this to abort a pending DMA transaction,
 | 
				
			||||||
 | 
					 *	returning it to FREE (but allocated) state
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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 *);
 | 
				
			||||||
 | 
						int			(*channel_program)(struct dma_channel *channel,
 | 
				
			||||||
 | 
												u16 maxpacket, u8 mode,
 | 
				
			||||||
 | 
												dma_addr_t dma_addr,
 | 
				
			||||||
 | 
												u32 length);
 | 
				
			||||||
 | 
						int			(*channel_abort)(struct dma_channel *);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* called after channel_program(), may indicate a fault */
 | 
				
			||||||
 | 
					extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct dma_controller *__init
 | 
				
			||||||
 | 
					dma_controller_create(struct musb *, void __iomem *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern void dma_controller_destroy(struct dma_controller *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif	/* __MUSB_DMA_H__ */
 | 
				
			||||||
							
								
								
									
										2033
									
								
								drivers/usb/musb/musb_gadget.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2033
									
								
								drivers/usb/musb/musb_gadget.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										108
									
								
								drivers/usb/musb/musb_gadget.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								drivers/usb/musb/musb_gadget.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,108 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * MUSB OTG driver peripheral defines
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2005 Mentor Graphics Corporation
 | 
				
			||||||
 | 
					 * Copyright (C) 2005-2006 by Texas Instruments
 | 
				
			||||||
 | 
					 * Copyright (C) 2006-2007 Nokia Corporation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 | 
				
			||||||
 | 
					 * 02110-1301 USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 | 
				
			||||||
 | 
					 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
				
			||||||
 | 
					 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
				
			||||||
 | 
					 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 | 
				
			||||||
 | 
					 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
				
			||||||
 | 
					 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
				
			||||||
 | 
					 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __MUSB_GADGET_H
 | 
				
			||||||
 | 
					#define __MUSB_GADGET_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct musb_request {
 | 
				
			||||||
 | 
						struct usb_request	request;
 | 
				
			||||||
 | 
						struct musb_ep		*ep;
 | 
				
			||||||
 | 
						struct musb		*musb;
 | 
				
			||||||
 | 
						u8 tx;			/* endpoint direction */
 | 
				
			||||||
 | 
						u8 epnum;
 | 
				
			||||||
 | 
						u8 mapped;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct musb_request *to_musb_request(struct usb_request *req)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return req ? container_of(req, struct musb_request, request) : NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct usb_request *
 | 
				
			||||||
 | 
					musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags);
 | 
				
			||||||
 | 
					extern void musb_free_request(struct usb_ep *ep, struct usb_request *req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * struct musb_ep - peripheral side view of endpoint rx or tx side
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct musb_ep {
 | 
				
			||||||
 | 
						/* stuff towards the head is basically write-once. */
 | 
				
			||||||
 | 
						struct usb_ep			end_point;
 | 
				
			||||||
 | 
						char				name[12];
 | 
				
			||||||
 | 
						struct musb_hw_ep		*hw_ep;
 | 
				
			||||||
 | 
						struct musb			*musb;
 | 
				
			||||||
 | 
						u8				current_epnum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* ... when enabled/disabled ... */
 | 
				
			||||||
 | 
						u8				type;
 | 
				
			||||||
 | 
						u8				is_in;
 | 
				
			||||||
 | 
						u16				packet_sz;
 | 
				
			||||||
 | 
						const struct usb_endpoint_descriptor	*desc;
 | 
				
			||||||
 | 
						struct dma_channel		*dma;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* later things are modified based on usage */
 | 
				
			||||||
 | 
						struct list_head		req_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* true if lock must be dropped but req_list may not be advanced */
 | 
				
			||||||
 | 
						u8				busy;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct list_head	*queue = &ep->req_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (list_empty(queue))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						return container_of(queue->next, struct usb_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 int musb_gadget_set_halt(struct usb_ep *ep, int value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif		/* __MUSB_GADGET_H */
 | 
				
			||||||
							
								
								
									
										981
									
								
								drivers/usb/musb/musb_gadget_ep0.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										981
									
								
								drivers/usb/musb/musb_gadget_ep0.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,981 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * MUSB OTG peripheral driver ep0 handling
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2005 Mentor Graphics Corporation
 | 
				
			||||||
 | 
					 * Copyright (C) 2005-2006 by Texas Instruments
 | 
				
			||||||
 | 
					 * Copyright (C) 2006-2007 Nokia Corporation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 | 
				
			||||||
 | 
					 * 02110-1301 USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 | 
				
			||||||
 | 
					 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
				
			||||||
 | 
					 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
				
			||||||
 | 
					 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 | 
				
			||||||
 | 
					 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
				
			||||||
 | 
					 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
				
			||||||
 | 
					 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include <linux/list.h>
 | 
				
			||||||
 | 
					#include <linux/timer.h>
 | 
				
			||||||
 | 
					#include <linux/spinlock.h>
 | 
				
			||||||
 | 
					#include <linux/init.h>
 | 
				
			||||||
 | 
					#include <linux/device.h>
 | 
				
			||||||
 | 
					#include <linux/interrupt.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "musb_core.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ep0 is always musb->endpoints[0].ep_in */
 | 
				
			||||||
 | 
					#define	next_ep0_request(musb)	next_in_request(&(musb)->endpoints[0])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * locking note:  we use only the controller lock, for simpler correctness.
 | 
				
			||||||
 | 
					 * It's always held with IRQs blocked.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * It protects the ep0 request queue as well as ep0_state, not just the
 | 
				
			||||||
 | 
					 * controller and indexed registers.  And that lock stays held unless it
 | 
				
			||||||
 | 
					 * needs to be dropped to allow reentering this driver ... like upcalls to
 | 
				
			||||||
 | 
					 * the gadget driver, or adjusting endpoint halt status.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char *decode_ep0stage(u8 stage)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (stage) {
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_SETUP:	return "idle";
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_TX:		return "in";
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_RX:		return "out";
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_ACKWAIT:	return "wait";
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_STATUSIN:	return "in/status";
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_STATUSOUT:	return "out/status";
 | 
				
			||||||
 | 
						default:			return "?";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* handle a standard GET_STATUS request
 | 
				
			||||||
 | 
					 * Context:  caller holds controller lock
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int service_tx_status_request(
 | 
				
			||||||
 | 
						struct musb *musb,
 | 
				
			||||||
 | 
						const struct usb_ctrlrequest *ctrlrequest)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						void __iomem	*mbase = musb->mregs;
 | 
				
			||||||
 | 
						int handled = 1;
 | 
				
			||||||
 | 
						u8 result[2], epnum = 0;
 | 
				
			||||||
 | 
						const u8 recip = ctrlrequest->bRequestType & USB_RECIP_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result[1] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (recip) {
 | 
				
			||||||
 | 
						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;
 | 
				
			||||||
 | 
								result[0] |= musb->g.a_alt_hnp_support
 | 
				
			||||||
 | 
									<< USB_DEVICE_A_ALT_HNP_SUPPORT;
 | 
				
			||||||
 | 
								result[0] |= musb->g.a_hnp_support
 | 
				
			||||||
 | 
									<< USB_DEVICE_A_HNP_SUPPORT;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case USB_RECIP_INTERFACE:
 | 
				
			||||||
 | 
							result[0] = 0;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case USB_RECIP_ENDPOINT: {
 | 
				
			||||||
 | 
							int		is_in;
 | 
				
			||||||
 | 
							struct musb_ep	*ep;
 | 
				
			||||||
 | 
							u16		tmp;
 | 
				
			||||||
 | 
							void __iomem	*regs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							epnum = (u8) ctrlrequest->wIndex;
 | 
				
			||||||
 | 
							if (!epnum) {
 | 
				
			||||||
 | 
								result[0] = 0;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							is_in = epnum & USB_DIR_IN;
 | 
				
			||||||
 | 
							if (is_in) {
 | 
				
			||||||
 | 
								epnum &= 0x0f;
 | 
				
			||||||
 | 
								ep = &musb->endpoints[epnum].ep_in;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								ep = &musb->endpoints[epnum].ep_out;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							regs = musb->endpoints[epnum].regs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (epnum >= MUSB_C_NUM_EPS || !ep->desc) {
 | 
				
			||||||
 | 
								handled = -EINVAL;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							musb_ep_select(mbase, epnum);
 | 
				
			||||||
 | 
							if (is_in)
 | 
				
			||||||
 | 
								tmp = musb_readw(regs, MUSB_TXCSR)
 | 
				
			||||||
 | 
											& MUSB_TXCSR_P_SENDSTALL;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								tmp = musb_readw(regs, MUSB_RXCSR)
 | 
				
			||||||
 | 
											& MUSB_RXCSR_P_SENDSTALL;
 | 
				
			||||||
 | 
							musb_ep_select(mbase, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							result[0] = tmp ? 1 : 0;
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							/* class, vendor, etc ... delegate */
 | 
				
			||||||
 | 
							handled = 0;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* fill up the fifo; caller updates csr0 */
 | 
				
			||||||
 | 
						if (handled > 0) {
 | 
				
			||||||
 | 
							u16	len = le16_to_cpu(ctrlrequest->wLength);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (len > 2)
 | 
				
			||||||
 | 
								len = 2;
 | 
				
			||||||
 | 
							musb_write_fifo(&musb->endpoints[0], len, result);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return handled;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * handle a control-IN request, the end0 buffer contains the current request
 | 
				
			||||||
 | 
					 * that is supposed to be a standard control request. Assumes the fifo to
 | 
				
			||||||
 | 
					 * be at least 2 bytes long.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return 0 if the request was NOT HANDLED,
 | 
				
			||||||
 | 
					 * < 0 when error
 | 
				
			||||||
 | 
					 * > 0 when the request is processed
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Context:  caller holds controller lock
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					service_in_request(struct musb *musb, const struct usb_ctrlrequest *ctrlrequest)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int handled = 0;	/* not handled */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((ctrlrequest->bRequestType & USB_TYPE_MASK)
 | 
				
			||||||
 | 
								== USB_TYPE_STANDARD) {
 | 
				
			||||||
 | 
							switch (ctrlrequest->bRequest) {
 | 
				
			||||||
 | 
							case USB_REQ_GET_STATUS:
 | 
				
			||||||
 | 
								handled = service_tx_status_request(musb,
 | 
				
			||||||
 | 
										ctrlrequest);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* case USB_REQ_SYNC_FRAME: */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return handled;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Context:  caller holds controller lock
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void musb_g_ep0_giveback(struct musb *musb, struct usb_request *req)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						musb_g_giveback(&musb->endpoints[0].ep_in, req, 0);
 | 
				
			||||||
 | 
						musb->ep0_state = MUSB_EP0_STAGE_SETUP;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Tries to start B-device HNP negotiation if enabled via sysfs
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void musb_try_b_hnp_enable(struct musb *musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						void __iomem	*mbase = musb->mregs;
 | 
				
			||||||
 | 
						u8		devctl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DBG(1, "HNP: Setting HR\n");
 | 
				
			||||||
 | 
						devctl = musb_readb(mbase, MUSB_DEVCTL);
 | 
				
			||||||
 | 
						musb_writeb(mbase, MUSB_DEVCTL, devctl | MUSB_DEVCTL_HR);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Handle all control requests with no DATA stage, including standard
 | 
				
			||||||
 | 
					 * requests such as:
 | 
				
			||||||
 | 
					 * USB_REQ_SET_CONFIGURATION, USB_REQ_SET_INTERFACE, unrecognized
 | 
				
			||||||
 | 
					 *	always delegated to the gadget driver
 | 
				
			||||||
 | 
					 * USB_REQ_SET_ADDRESS, USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE
 | 
				
			||||||
 | 
					 *	always handled here, except for class/vendor/... features
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Context:  caller holds controller lock
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					service_zero_data_request(struct musb *musb,
 | 
				
			||||||
 | 
							struct usb_ctrlrequest *ctrlrequest)
 | 
				
			||||||
 | 
					__releases(musb->lock)
 | 
				
			||||||
 | 
					__acquires(musb->lock)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int handled = -EINVAL;
 | 
				
			||||||
 | 
						void __iomem *mbase = musb->mregs;
 | 
				
			||||||
 | 
						const u8 recip = ctrlrequest->bRequestType & USB_RECIP_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* the gadget driver handles everything except what we MUST handle */
 | 
				
			||||||
 | 
						if ((ctrlrequest->bRequestType & USB_TYPE_MASK)
 | 
				
			||||||
 | 
								== USB_TYPE_STANDARD) {
 | 
				
			||||||
 | 
							switch (ctrlrequest->bRequest) {
 | 
				
			||||||
 | 
							case USB_REQ_SET_ADDRESS:
 | 
				
			||||||
 | 
								/* change it after the status stage */
 | 
				
			||||||
 | 
								musb->set_address = true;
 | 
				
			||||||
 | 
								musb->address = (u8) (ctrlrequest->wValue & 0x7f);
 | 
				
			||||||
 | 
								handled = 1;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case USB_REQ_CLEAR_FEATURE:
 | 
				
			||||||
 | 
								switch (recip) {
 | 
				
			||||||
 | 
								case USB_RECIP_DEVICE:
 | 
				
			||||||
 | 
									if (ctrlrequest->wValue
 | 
				
			||||||
 | 
											!= USB_DEVICE_REMOTE_WAKEUP)
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									musb->may_wakeup = 0;
 | 
				
			||||||
 | 
									handled = 1;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case USB_RECIP_INTERFACE:
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case USB_RECIP_ENDPOINT:{
 | 
				
			||||||
 | 
									const u8 num = ctrlrequest->wIndex & 0x0f;
 | 
				
			||||||
 | 
									struct musb_ep *musb_ep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (num == 0
 | 
				
			||||||
 | 
											|| num >= MUSB_C_NUM_EPS
 | 
				
			||||||
 | 
											|| ctrlrequest->wValue
 | 
				
			||||||
 | 
												!= USB_ENDPOINT_HALT)
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (ctrlrequest->wIndex & USB_DIR_IN)
 | 
				
			||||||
 | 
										musb_ep = &musb->endpoints[num].ep_in;
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
										musb_ep = &musb->endpoints[num].ep_out;
 | 
				
			||||||
 | 
									if (!musb_ep->desc)
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/* REVISIT do it directly, no locking games */
 | 
				
			||||||
 | 
									spin_unlock(&musb->lock);
 | 
				
			||||||
 | 
									musb_gadget_set_halt(&musb_ep->end_point, 0);
 | 
				
			||||||
 | 
									spin_lock(&musb->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/* select ep0 again */
 | 
				
			||||||
 | 
									musb_ep_select(mbase, 0);
 | 
				
			||||||
 | 
									handled = 1;
 | 
				
			||||||
 | 
									} break;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									/* class, vendor, etc ... delegate */
 | 
				
			||||||
 | 
									handled = 0;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case USB_REQ_SET_FEATURE:
 | 
				
			||||||
 | 
								switch (recip) {
 | 
				
			||||||
 | 
								case USB_RECIP_DEVICE:
 | 
				
			||||||
 | 
									handled = 1;
 | 
				
			||||||
 | 
									switch (ctrlrequest->wValue) {
 | 
				
			||||||
 | 
									case USB_DEVICE_REMOTE_WAKEUP:
 | 
				
			||||||
 | 
										musb->may_wakeup = 1;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									case USB_DEVICE_TEST_MODE:
 | 
				
			||||||
 | 
										if (musb->g.speed != USB_SPEED_HIGH)
 | 
				
			||||||
 | 
											goto stall;
 | 
				
			||||||
 | 
										if (ctrlrequest->wIndex & 0xff)
 | 
				
			||||||
 | 
											goto stall;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										switch (ctrlrequest->wIndex >> 8) {
 | 
				
			||||||
 | 
										case 1:
 | 
				
			||||||
 | 
											pr_debug("TEST_J\n");
 | 
				
			||||||
 | 
											/* TEST_J */
 | 
				
			||||||
 | 
											musb->test_mode_nr =
 | 
				
			||||||
 | 
												MUSB_TEST_J;
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										case 2:
 | 
				
			||||||
 | 
											/* TEST_K */
 | 
				
			||||||
 | 
											pr_debug("TEST_K\n");
 | 
				
			||||||
 | 
											musb->test_mode_nr =
 | 
				
			||||||
 | 
												MUSB_TEST_K;
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										case 3:
 | 
				
			||||||
 | 
											/* TEST_SE0_NAK */
 | 
				
			||||||
 | 
											pr_debug("TEST_SE0_NAK\n");
 | 
				
			||||||
 | 
											musb->test_mode_nr =
 | 
				
			||||||
 | 
												MUSB_TEST_SE0_NAK;
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										case 4:
 | 
				
			||||||
 | 
											/* TEST_PACKET */
 | 
				
			||||||
 | 
											pr_debug("TEST_PACKET\n");
 | 
				
			||||||
 | 
											musb->test_mode_nr =
 | 
				
			||||||
 | 
												MUSB_TEST_PACKET;
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										default:
 | 
				
			||||||
 | 
											goto stall;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										/* enter test mode after irq */
 | 
				
			||||||
 | 
										if (handled > 0)
 | 
				
			||||||
 | 
											musb->test_mode = true;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_MUSB_OTG
 | 
				
			||||||
 | 
									case USB_DEVICE_B_HNP_ENABLE:
 | 
				
			||||||
 | 
										if (!musb->g.is_otg)
 | 
				
			||||||
 | 
											goto stall;
 | 
				
			||||||
 | 
										musb->g.b_hnp_enable = 1;
 | 
				
			||||||
 | 
										musb_try_b_hnp_enable(musb);
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									case USB_DEVICE_A_HNP_SUPPORT:
 | 
				
			||||||
 | 
										if (!musb->g.is_otg)
 | 
				
			||||||
 | 
											goto stall;
 | 
				
			||||||
 | 
										musb->g.a_hnp_support = 1;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									case USB_DEVICE_A_ALT_HNP_SUPPORT:
 | 
				
			||||||
 | 
										if (!musb->g.is_otg)
 | 
				
			||||||
 | 
											goto stall;
 | 
				
			||||||
 | 
										musb->g.a_alt_hnp_support = 1;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					stall:
 | 
				
			||||||
 | 
									default:
 | 
				
			||||||
 | 
										handled = -EINVAL;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								case USB_RECIP_INTERFACE:
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								case USB_RECIP_ENDPOINT:{
 | 
				
			||||||
 | 
									const u8		epnum =
 | 
				
			||||||
 | 
										ctrlrequest->wIndex & 0x0f;
 | 
				
			||||||
 | 
									struct musb_ep		*musb_ep;
 | 
				
			||||||
 | 
									struct musb_hw_ep	*ep;
 | 
				
			||||||
 | 
									void __iomem		*regs;
 | 
				
			||||||
 | 
									int			is_in;
 | 
				
			||||||
 | 
									u16			csr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (epnum == 0
 | 
				
			||||||
 | 
											|| epnum >= MUSB_C_NUM_EPS
 | 
				
			||||||
 | 
											|| ctrlrequest->wValue
 | 
				
			||||||
 | 
												!= USB_ENDPOINT_HALT)
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									ep = musb->endpoints + epnum;
 | 
				
			||||||
 | 
									regs = ep->regs;
 | 
				
			||||||
 | 
									is_in = ctrlrequest->wIndex & USB_DIR_IN;
 | 
				
			||||||
 | 
									if (is_in)
 | 
				
			||||||
 | 
										musb_ep = &ep->ep_in;
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
										musb_ep = &ep->ep_out;
 | 
				
			||||||
 | 
									if (!musb_ep->desc)
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									musb_ep_select(mbase, epnum);
 | 
				
			||||||
 | 
									if (is_in) {
 | 
				
			||||||
 | 
										csr = musb_readw(regs,
 | 
				
			||||||
 | 
												MUSB_TXCSR);
 | 
				
			||||||
 | 
										if (csr & MUSB_TXCSR_FIFONOTEMPTY)
 | 
				
			||||||
 | 
											csr |= MUSB_TXCSR_FLUSHFIFO;
 | 
				
			||||||
 | 
										csr |= MUSB_TXCSR_P_SENDSTALL
 | 
				
			||||||
 | 
											| MUSB_TXCSR_CLRDATATOG
 | 
				
			||||||
 | 
											| MUSB_TXCSR_P_WZC_BITS;
 | 
				
			||||||
 | 
										musb_writew(regs, MUSB_TXCSR,
 | 
				
			||||||
 | 
												csr);
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										csr = musb_readw(regs,
 | 
				
			||||||
 | 
												MUSB_RXCSR);
 | 
				
			||||||
 | 
										csr |= MUSB_RXCSR_P_SENDSTALL
 | 
				
			||||||
 | 
											| MUSB_RXCSR_FLUSHFIFO
 | 
				
			||||||
 | 
											| MUSB_RXCSR_CLRDATATOG
 | 
				
			||||||
 | 
											| MUSB_TXCSR_P_WZC_BITS;
 | 
				
			||||||
 | 
										musb_writew(regs, MUSB_RXCSR,
 | 
				
			||||||
 | 
												csr);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/* select ep0 again */
 | 
				
			||||||
 | 
									musb_ep_select(mbase, 0);
 | 
				
			||||||
 | 
									handled = 1;
 | 
				
			||||||
 | 
									} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									/* class, vendor, etc ... delegate */
 | 
				
			||||||
 | 
									handled = 0;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								/* delegate SET_CONFIGURATION, etc */
 | 
				
			||||||
 | 
								handled = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							handled = 0;
 | 
				
			||||||
 | 
						return handled;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* we have an ep0out data packet
 | 
				
			||||||
 | 
					 * Context:  caller holds controller lock
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void ep0_rxstate(struct musb *musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						void __iomem		*regs = musb->control_ep->regs;
 | 
				
			||||||
 | 
						struct usb_request	*req;
 | 
				
			||||||
 | 
						u16			tmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req = next_ep0_request(musb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* read packet and ack; or stall because of gadget driver bug:
 | 
				
			||||||
 | 
						 * should have provided the rx buffer before setup() returned.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (req) {
 | 
				
			||||||
 | 
							void		*buf = req->buf + req->actual;
 | 
				
			||||||
 | 
							unsigned	len = req->length - req->actual;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* read the buffer */
 | 
				
			||||||
 | 
							tmp = musb_readb(regs, MUSB_COUNT0);
 | 
				
			||||||
 | 
							if (tmp > len) {
 | 
				
			||||||
 | 
								req->status = -EOVERFLOW;
 | 
				
			||||||
 | 
								tmp = len;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							musb_read_fifo(&musb->endpoints[0], tmp, buf);
 | 
				
			||||||
 | 
							req->actual += tmp;
 | 
				
			||||||
 | 
							tmp = MUSB_CSR0_P_SVDRXPKTRDY;
 | 
				
			||||||
 | 
							if (tmp < 64 || req->actual == req->length) {
 | 
				
			||||||
 | 
								musb->ep0_state = MUSB_EP0_STAGE_STATUSIN;
 | 
				
			||||||
 | 
								tmp |= MUSB_CSR0_P_DATAEND;
 | 
				
			||||||
 | 
							} else
 | 
				
			||||||
 | 
								req = NULL;
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							tmp = MUSB_CSR0_P_SVDRXPKTRDY | MUSB_CSR0_P_SENDSTALL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Completion handler may choose to stall, e.g. because the
 | 
				
			||||||
 | 
						 * message just received holds invalid data.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (req) {
 | 
				
			||||||
 | 
							musb->ackpend = tmp;
 | 
				
			||||||
 | 
							musb_g_ep0_giveback(musb, req);
 | 
				
			||||||
 | 
							if (!musb->ackpend)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							musb->ackpend = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						musb_writew(regs, MUSB_CSR0, tmp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * transmitting to the host (IN), this code might be called from IRQ
 | 
				
			||||||
 | 
					 * and from kernel thread.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Context:  caller holds controller lock
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void ep0_txstate(struct musb *musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						void __iomem		*regs = musb->control_ep->regs;
 | 
				
			||||||
 | 
						struct usb_request	*request = next_ep0_request(musb);
 | 
				
			||||||
 | 
						u16			csr = MUSB_CSR0_TXPKTRDY;
 | 
				
			||||||
 | 
						u8			*fifo_src;
 | 
				
			||||||
 | 
						u8			fifo_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!request) {
 | 
				
			||||||
 | 
							/* WARN_ON(1); */
 | 
				
			||||||
 | 
							DBG(2, "odd; csr0 %04x\n", musb_readw(regs, MUSB_CSR0));
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* load the data */
 | 
				
			||||||
 | 
						fifo_src = (u8 *) request->buf + request->actual;
 | 
				
			||||||
 | 
						fifo_count = min((unsigned) MUSB_EP0_FIFOSIZE,
 | 
				
			||||||
 | 
							request->length - request->actual);
 | 
				
			||||||
 | 
						musb_write_fifo(&musb->endpoints[0], fifo_count, fifo_src);
 | 
				
			||||||
 | 
						request->actual += fifo_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* update the flags */
 | 
				
			||||||
 | 
						if (fifo_count < MUSB_MAX_END0_PACKET
 | 
				
			||||||
 | 
								|| request->actual == request->length) {
 | 
				
			||||||
 | 
							musb->ep0_state = MUSB_EP0_STAGE_STATUSOUT;
 | 
				
			||||||
 | 
							csr |= MUSB_CSR0_P_DATAEND;
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							request = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* report completions as soon as the fifo's loaded; there's no
 | 
				
			||||||
 | 
						 * win in waiting till this last packet gets acked.  (other than
 | 
				
			||||||
 | 
						 * very precise fault reporting, needed by USB TMC; possible with
 | 
				
			||||||
 | 
						 * this hardware, but not usable from portable gadget drivers.)
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (request) {
 | 
				
			||||||
 | 
							musb->ackpend = csr;
 | 
				
			||||||
 | 
							musb_g_ep0_giveback(musb, request);
 | 
				
			||||||
 | 
							if (!musb->ackpend)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							musb->ackpend = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* send it out, triggering a "txpktrdy cleared" irq */
 | 
				
			||||||
 | 
						musb_writew(regs, MUSB_CSR0, csr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Read a SETUP packet (struct usb_ctrlrequest) from the hardware.
 | 
				
			||||||
 | 
					 * Fields are left in USB byte-order.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Context:  caller holds controller lock.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					musb_read_setup(struct musb *musb, struct usb_ctrlrequest *req)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usb_request	*r;
 | 
				
			||||||
 | 
						void __iomem		*regs = musb->control_ep->regs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						musb_read_fifo(&musb->endpoints[0], sizeof *req, (u8 *)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",
 | 
				
			||||||
 | 
							req->bRequestType,
 | 
				
			||||||
 | 
							req->bRequest,
 | 
				
			||||||
 | 
							le16_to_cpu(req->wValue),
 | 
				
			||||||
 | 
							le16_to_cpu(req->wIndex),
 | 
				
			||||||
 | 
							le16_to_cpu(req->wLength));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* clean up any leftover transfers */
 | 
				
			||||||
 | 
						r = next_ep0_request(musb);
 | 
				
			||||||
 | 
						if (r)
 | 
				
			||||||
 | 
							musb_g_ep0_giveback(musb, r);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* For zero-data requests we want to delay the STATUS stage to
 | 
				
			||||||
 | 
						 * avoid SETUPEND errors.  If we read data (OUT), delay accepting
 | 
				
			||||||
 | 
						 * packets until there's a buffer to store them in.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * If we write data, the controller acts happier if we enable
 | 
				
			||||||
 | 
						 * the TX FIFO right away, and give the controller a moment
 | 
				
			||||||
 | 
						 * to switch modes...
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						musb->set_address = false;
 | 
				
			||||||
 | 
						musb->ackpend = MUSB_CSR0_P_SVDRXPKTRDY;
 | 
				
			||||||
 | 
						if (req->wLength == 0) {
 | 
				
			||||||
 | 
							if (req->bRequestType & USB_DIR_IN)
 | 
				
			||||||
 | 
								musb->ackpend |= MUSB_CSR0_TXPKTRDY;
 | 
				
			||||||
 | 
							musb->ep0_state = MUSB_EP0_STAGE_ACKWAIT;
 | 
				
			||||||
 | 
						} else if (req->bRequestType & USB_DIR_IN) {
 | 
				
			||||||
 | 
							musb->ep0_state = MUSB_EP0_STAGE_TX;
 | 
				
			||||||
 | 
							musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDRXPKTRDY);
 | 
				
			||||||
 | 
							while ((musb_readw(regs, MUSB_CSR0)
 | 
				
			||||||
 | 
									& MUSB_CSR0_RXPKTRDY) != 0)
 | 
				
			||||||
 | 
								cpu_relax();
 | 
				
			||||||
 | 
							musb->ackpend = 0;
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							musb->ep0_state = MUSB_EP0_STAGE_RX;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					forward_to_driver(struct musb *musb, const struct usb_ctrlrequest *ctrlrequest)
 | 
				
			||||||
 | 
					__releases(musb->lock)
 | 
				
			||||||
 | 
					__acquires(musb->lock)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int retval;
 | 
				
			||||||
 | 
						if (!musb->gadget_driver)
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
						spin_unlock(&musb->lock);
 | 
				
			||||||
 | 
						retval = musb->gadget_driver->setup(&musb->g, ctrlrequest);
 | 
				
			||||||
 | 
						spin_lock(&musb->lock);
 | 
				
			||||||
 | 
						return retval;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Handle peripheral ep0 interrupt
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Context: irq handler; we won't re-enter the driver that way.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					irqreturn_t musb_g_ep0_irq(struct musb *musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u16		csr;
 | 
				
			||||||
 | 
						u16		len;
 | 
				
			||||||
 | 
						void __iomem	*mbase = musb->mregs;
 | 
				
			||||||
 | 
						void __iomem	*regs = musb->endpoints[0].regs;
 | 
				
			||||||
 | 
						irqreturn_t	retval = IRQ_NONE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						musb_ep_select(mbase, 0);	/* select ep0 */
 | 
				
			||||||
 | 
						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));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* I sent a stall.. need to acknowledge it now.. */
 | 
				
			||||||
 | 
						if (csr & MUSB_CSR0_P_SENTSTALL) {
 | 
				
			||||||
 | 
							musb_writew(regs, MUSB_CSR0,
 | 
				
			||||||
 | 
									csr & ~MUSB_CSR0_P_SENTSTALL);
 | 
				
			||||||
 | 
							retval = IRQ_HANDLED;
 | 
				
			||||||
 | 
							musb->ep0_state = MUSB_EP0_STAGE_SETUP;
 | 
				
			||||||
 | 
							csr = musb_readw(regs, MUSB_CSR0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* request ended "early" */
 | 
				
			||||||
 | 
						if (csr & MUSB_CSR0_P_SETUPEND) {
 | 
				
			||||||
 | 
							musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDSETUPEND);
 | 
				
			||||||
 | 
							retval = IRQ_HANDLED;
 | 
				
			||||||
 | 
							musb->ep0_state = MUSB_EP0_STAGE_SETUP;
 | 
				
			||||||
 | 
							csr = musb_readw(regs, MUSB_CSR0);
 | 
				
			||||||
 | 
							/* NOTE:  request may need completion */
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* docs from Mentor only describe tx, rx, and idle/setup states.
 | 
				
			||||||
 | 
						 * we need to handle nuances around status stages, and also the
 | 
				
			||||||
 | 
						 * case where status and setup stages come back-to-back ...
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						switch (musb->ep0_state) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_TX:
 | 
				
			||||||
 | 
							/* irq on clearing txpktrdy */
 | 
				
			||||||
 | 
							if ((csr & MUSB_CSR0_TXPKTRDY) == 0) {
 | 
				
			||||||
 | 
								ep0_txstate(musb);
 | 
				
			||||||
 | 
								retval = IRQ_HANDLED;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_RX:
 | 
				
			||||||
 | 
							/* irq on set rxpktrdy */
 | 
				
			||||||
 | 
							if (csr & MUSB_CSR0_RXPKTRDY) {
 | 
				
			||||||
 | 
								ep0_rxstate(musb);
 | 
				
			||||||
 | 
								retval = IRQ_HANDLED;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_STATUSIN:
 | 
				
			||||||
 | 
							/* end of sequence #2 (OUT/RX state) or #3 (no data) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* update address (if needed) only @ the end of the
 | 
				
			||||||
 | 
							 * status phase per usb spec, which also guarantees
 | 
				
			||||||
 | 
							 * we get 10 msec to receive this irq... until this
 | 
				
			||||||
 | 
							 * is done we won't see the next packet.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (musb->set_address) {
 | 
				
			||||||
 | 
								musb->set_address = false;
 | 
				
			||||||
 | 
								musb_writeb(mbase, MUSB_FADDR, musb->address);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* enter test mode if needed (exit by reset) */
 | 
				
			||||||
 | 
							else if (musb->test_mode) {
 | 
				
			||||||
 | 
								DBG(1, "entering TESTMODE\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (MUSB_TEST_PACKET == musb->test_mode_nr)
 | 
				
			||||||
 | 
									musb_load_testpacket(musb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								musb_writeb(mbase, MUSB_TESTMODE,
 | 
				
			||||||
 | 
										musb->test_mode_nr);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							/* FALLTHROUGH */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_STATUSOUT:
 | 
				
			||||||
 | 
							/* end of sequence #1: write to host (TX state) */
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								struct usb_request	*req;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								req = next_ep0_request(musb);
 | 
				
			||||||
 | 
								if (req)
 | 
				
			||||||
 | 
									musb_g_ep0_giveback(musb, req);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							retval = IRQ_HANDLED;
 | 
				
			||||||
 | 
							musb->ep0_state = MUSB_EP0_STAGE_SETUP;
 | 
				
			||||||
 | 
							/* FALLTHROUGH */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_SETUP:
 | 
				
			||||||
 | 
							if (csr & MUSB_CSR0_RXPKTRDY) {
 | 
				
			||||||
 | 
								struct usb_ctrlrequest	setup;
 | 
				
			||||||
 | 
								int			handled = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (len != 8) {
 | 
				
			||||||
 | 
									ERR("SETUP packet len %d != 8 ?\n", len);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								musb_read_setup(musb, &setup);
 | 
				
			||||||
 | 
								retval = IRQ_HANDLED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* sometimes the RESET won't be reported */
 | 
				
			||||||
 | 
								if (unlikely(musb->g.speed == USB_SPEED_UNKNOWN)) {
 | 
				
			||||||
 | 
									u8	power;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									printk(KERN_NOTICE "%s: peripheral reset "
 | 
				
			||||||
 | 
											"irq lost!\n",
 | 
				
			||||||
 | 
											musb_driver_name);
 | 
				
			||||||
 | 
									power = musb_readb(mbase, MUSB_POWER);
 | 
				
			||||||
 | 
									musb->g.speed = (power & MUSB_POWER_HSMODE)
 | 
				
			||||||
 | 
										? USB_SPEED_HIGH : USB_SPEED_FULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								switch (musb->ep0_state) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* sequence #3 (no data stage), includes requests
 | 
				
			||||||
 | 
								 * we can't forward (notably SET_ADDRESS and the
 | 
				
			||||||
 | 
								 * device/endpoint feature set/clear operations)
 | 
				
			||||||
 | 
								 * plus SET_CONFIGURATION and others we must
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								case MUSB_EP0_STAGE_ACKWAIT:
 | 
				
			||||||
 | 
									handled = service_zero_data_request(
 | 
				
			||||||
 | 
											musb, &setup);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/* status stage might be immediate */
 | 
				
			||||||
 | 
									if (handled > 0) {
 | 
				
			||||||
 | 
										musb->ackpend |= MUSB_CSR0_P_DATAEND;
 | 
				
			||||||
 | 
										musb->ep0_state =
 | 
				
			||||||
 | 
											MUSB_EP0_STAGE_STATUSIN;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* sequence #1 (IN to host), includes GET_STATUS
 | 
				
			||||||
 | 
								 * requests that we can't forward, GET_DESCRIPTOR
 | 
				
			||||||
 | 
								 * and others that we must
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								case MUSB_EP0_STAGE_TX:
 | 
				
			||||||
 | 
									handled = service_in_request(musb, &setup);
 | 
				
			||||||
 | 
									if (handled > 0) {
 | 
				
			||||||
 | 
										musb->ackpend = MUSB_CSR0_TXPKTRDY
 | 
				
			||||||
 | 
											| MUSB_CSR0_P_DATAEND;
 | 
				
			||||||
 | 
										musb->ep0_state =
 | 
				
			||||||
 | 
											MUSB_EP0_STAGE_STATUSOUT;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* sequence #2 (OUT from host), always forward */
 | 
				
			||||||
 | 
								default:		/* MUSB_EP0_STAGE_RX */
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								DBG(3, "handled %d, csr %04x, ep0stage %s\n",
 | 
				
			||||||
 | 
									handled, csr,
 | 
				
			||||||
 | 
									decode_ep0stage(musb->ep0_state));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* unless we need to delegate this to the gadget
 | 
				
			||||||
 | 
								 * driver, we know how to wrap this up:  csr0 has
 | 
				
			||||||
 | 
								 * not yet been written.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								if (handled < 0)
 | 
				
			||||||
 | 
									goto stall;
 | 
				
			||||||
 | 
								else if (handled > 0)
 | 
				
			||||||
 | 
									goto finish;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								handled = forward_to_driver(musb, &setup);
 | 
				
			||||||
 | 
								if (handled < 0) {
 | 
				
			||||||
 | 
									musb_ep_select(mbase, 0);
 | 
				
			||||||
 | 
					stall:
 | 
				
			||||||
 | 
									DBG(3, "stall (%d)\n", handled);
 | 
				
			||||||
 | 
									musb->ackpend |= MUSB_CSR0_P_SENDSTALL;
 | 
				
			||||||
 | 
									musb->ep0_state = MUSB_EP0_STAGE_SETUP;
 | 
				
			||||||
 | 
					finish:
 | 
				
			||||||
 | 
									musb_writew(regs, MUSB_CSR0,
 | 
				
			||||||
 | 
											musb->ackpend);
 | 
				
			||||||
 | 
									musb->ackpend = 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_ACKWAIT:
 | 
				
			||||||
 | 
							/* This should not happen. But happens with tusb6010 with
 | 
				
			||||||
 | 
							 * g_file_storage and high speed. Do nothing.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							retval = IRQ_HANDLED;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							/* "can't happen" */
 | 
				
			||||||
 | 
							WARN_ON(1);
 | 
				
			||||||
 | 
							musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SENDSTALL);
 | 
				
			||||||
 | 
							musb->ep0_state = MUSB_EP0_STAGE_SETUP;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return retval;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					musb_g_ep0_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* always enabled */
 | 
				
			||||||
 | 
						return -EINVAL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int musb_g_ep0_disable(struct usb_ep *e)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* always enabled */
 | 
				
			||||||
 | 
						return -EINVAL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					musb_g_ep0_queue(struct usb_ep *e, struct usb_request *r, gfp_t gfp_flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct musb_ep		*ep;
 | 
				
			||||||
 | 
						struct musb_request	*req;
 | 
				
			||||||
 | 
						struct musb		*musb;
 | 
				
			||||||
 | 
						int			status;
 | 
				
			||||||
 | 
						unsigned long		lockflags;
 | 
				
			||||||
 | 
						void __iomem		*regs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!e || !r)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ep = to_musb_ep(e);
 | 
				
			||||||
 | 
						musb = ep->musb;
 | 
				
			||||||
 | 
						regs = musb->control_ep->regs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req = to_musb_request(r);
 | 
				
			||||||
 | 
						req->musb = musb;
 | 
				
			||||||
 | 
						req->request.actual = 0;
 | 
				
			||||||
 | 
						req->request.status = -EINPROGRESS;
 | 
				
			||||||
 | 
						req->tx = ep->is_in;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_irqsave(&musb->lock, lockflags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!list_empty(&ep->req_list)) {
 | 
				
			||||||
 | 
							status = -EBUSY;
 | 
				
			||||||
 | 
							goto cleanup;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (musb->ep0_state) {
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_RX:		/* control-OUT data */
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_TX:		/* control-IN data */
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_ACKWAIT:	/* zero-length data */
 | 
				
			||||||
 | 
							status = 0;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							DBG(1, "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));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DBG(3, "queue to %s (%s), length=%d\n",
 | 
				
			||||||
 | 
								ep->name, ep->is_in ? "IN/TX" : "OUT/RX",
 | 
				
			||||||
 | 
								req->request.length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						musb_ep_select(musb->mregs, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* sequence #1, IN ... start writing the data */
 | 
				
			||||||
 | 
						if (musb->ep0_state == MUSB_EP0_STAGE_TX)
 | 
				
			||||||
 | 
							ep0_txstate(musb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* sequence #3, no-data ... issue IN status */
 | 
				
			||||||
 | 
						else if (musb->ep0_state == MUSB_EP0_STAGE_ACKWAIT) {
 | 
				
			||||||
 | 
							if (req->request.length)
 | 
				
			||||||
 | 
								status = -EINVAL;
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								musb->ep0_state = MUSB_EP0_STAGE_STATUSIN;
 | 
				
			||||||
 | 
								musb_writew(regs, MUSB_CSR0,
 | 
				
			||||||
 | 
										musb->ackpend | MUSB_CSR0_P_DATAEND);
 | 
				
			||||||
 | 
								musb->ackpend = 0;
 | 
				
			||||||
 | 
								musb_g_ep0_giveback(ep->musb, r);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* else for sequence #2 (OUT), caller provides a buffer
 | 
				
			||||||
 | 
						 * before the next packet arrives.  deferred responses
 | 
				
			||||||
 | 
						 * (after SETUP is acked) are racey.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						} else if (musb->ackpend) {
 | 
				
			||||||
 | 
							musb_writew(regs, MUSB_CSR0, musb->ackpend);
 | 
				
			||||||
 | 
							musb->ackpend = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cleanup:
 | 
				
			||||||
 | 
						spin_unlock_irqrestore(&musb->lock, lockflags);
 | 
				
			||||||
 | 
						return status;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int musb_g_ep0_dequeue(struct usb_ep *ep, struct usb_request *req)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* we just won't support this */
 | 
				
			||||||
 | 
						return -EINVAL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int musb_g_ep0_halt(struct usb_ep *e, int value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct musb_ep		*ep;
 | 
				
			||||||
 | 
						struct musb		*musb;
 | 
				
			||||||
 | 
						void __iomem		*base, *regs;
 | 
				
			||||||
 | 
						unsigned long		flags;
 | 
				
			||||||
 | 
						int			status;
 | 
				
			||||||
 | 
						u16			csr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!e || !value)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ep = to_musb_ep(e);
 | 
				
			||||||
 | 
						musb = ep->musb;
 | 
				
			||||||
 | 
						base = musb->mregs;
 | 
				
			||||||
 | 
						regs = musb->control_ep->regs;
 | 
				
			||||||
 | 
						status = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_irqsave(&musb->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!list_empty(&ep->req_list)) {
 | 
				
			||||||
 | 
							status = -EBUSY;
 | 
				
			||||||
 | 
							goto cleanup;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						musb_ep_select(base, 0);
 | 
				
			||||||
 | 
						csr = musb->ackpend;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (musb->ep0_state) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Stalls are usually issued after parsing SETUP packet, either
 | 
				
			||||||
 | 
						 * directly in irq context from setup() or else later.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_TX:		/* control-IN data */
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_ACKWAIT:	/* STALL for zero-length data */
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_RX:		/* control-OUT data */
 | 
				
			||||||
 | 
							csr = musb_readw(regs, MUSB_CSR0);
 | 
				
			||||||
 | 
							/* FALLTHROUGH */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* It's also OK to issue stalls during callbacks when a non-empty
 | 
				
			||||||
 | 
						 * DATA stage buffer has been read (or even written).
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_STATUSIN:	/* control-OUT status */
 | 
				
			||||||
 | 
						case MUSB_EP0_STAGE_STATUSOUT:	/* control-IN status */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							csr |= MUSB_CSR0_P_SENDSTALL;
 | 
				
			||||||
 | 
							musb_writew(regs, MUSB_CSR0, csr);
 | 
				
			||||||
 | 
							musb->ep0_state = MUSB_EP0_STAGE_SETUP;
 | 
				
			||||||
 | 
							musb->ackpend = 0;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							DBG(1, "ep0 can't halt in state %d\n", musb->ep0_state);
 | 
				
			||||||
 | 
							status = -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cleanup:
 | 
				
			||||||
 | 
						spin_unlock_irqrestore(&musb->lock, flags);
 | 
				
			||||||
 | 
						return status;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct usb_ep_ops musb_g_ep0_ops = {
 | 
				
			||||||
 | 
						.enable		= musb_g_ep0_enable,
 | 
				
			||||||
 | 
						.disable	= musb_g_ep0_disable,
 | 
				
			||||||
 | 
						.alloc_request	= musb_alloc_request,
 | 
				
			||||||
 | 
						.free_request	= musb_free_request,
 | 
				
			||||||
 | 
						.queue		= musb_g_ep0_queue,
 | 
				
			||||||
 | 
						.dequeue	= musb_g_ep0_dequeue,
 | 
				
			||||||
 | 
						.set_halt	= musb_g_ep0_halt,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										2170
									
								
								drivers/usb/musb/musb_host.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2170
									
								
								drivers/usb/musb/musb_host.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										110
									
								
								drivers/usb/musb/musb_host.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								drivers/usb/musb/musb_host.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,110 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * MUSB OTG driver host defines
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2005 Mentor Graphics Corporation
 | 
				
			||||||
 | 
					 * Copyright (C) 2005-2006 by Texas Instruments
 | 
				
			||||||
 | 
					 * Copyright (C) 2006-2007 Nokia Corporation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 | 
				
			||||||
 | 
					 * 02110-1301 USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 | 
				
			||||||
 | 
					 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
				
			||||||
 | 
					 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
				
			||||||
 | 
					 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 | 
				
			||||||
 | 
					 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
				
			||||||
 | 
					 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
				
			||||||
 | 
					 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* stored in "usb_host_endpoint.hcpriv" for scheduled endpoints */
 | 
				
			||||||
 | 
					struct musb_qh {
 | 
				
			||||||
 | 
						struct usb_host_endpoint *hep;		/* usbcore info */
 | 
				
			||||||
 | 
						struct usb_device	*dev;
 | 
				
			||||||
 | 
						struct musb_hw_ep	*hw_ep;		/* current binding */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct list_head	ring;		/* of musb_qh */
 | 
				
			||||||
 | 
						/* struct musb_qh		*next; */	/* for periodic tree */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unsigned		offset;		/* in urb->transfer_buffer */
 | 
				
			||||||
 | 
						unsigned		segsize;	/* current xfer fragment */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u8			type_reg;	/* {rx,tx} type register */
 | 
				
			||||||
 | 
						u8			intv_reg;	/* {rx,tx} interval register */
 | 
				
			||||||
 | 
						u8			addr_reg;	/* device address register */
 | 
				
			||||||
 | 
						u8			h_addr_reg;	/* hub address register */
 | 
				
			||||||
 | 
						u8			h_port_reg;	/* hub port register */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u8			is_ready;	/* safe to modify hw_ep */
 | 
				
			||||||
 | 
						u8			type;		/* XFERTYPE_* */
 | 
				
			||||||
 | 
						u8			epnum;
 | 
				
			||||||
 | 
						u16			maxpacket;
 | 
				
			||||||
 | 
						u16			frame;		/* for periodic schedule */
 | 
				
			||||||
 | 
						unsigned		iso_idx;	/* in urb->iso_frame_desc[] */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* map from control or bulk queue head to the first qh on that ring */
 | 
				
			||||||
 | 
					static inline struct musb_qh *first_qh(struct list_head *q)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (list_empty(q))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						return list_entry(q->next, struct musb_qh, ring);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern void musb_root_disconnect(struct musb *musb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usb_hcd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int musb_hub_status_data(struct usb_hcd *hcd, char *buf);
 | 
				
			||||||
 | 
					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)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						queue = &qh->hep->urb_list;
 | 
				
			||||||
 | 
						if (list_empty(queue))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						return list_entry(queue->next, struct urb, urb_list);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif				/* _MUSB_HOST_H */
 | 
				
			||||||
							
								
								
									
										115
									
								
								drivers/usb/musb/musb_io.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								drivers/usb/musb/musb_io.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,115 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * MUSB OTG driver register I/O
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2005 Mentor Graphics Corporation
 | 
				
			||||||
 | 
					 * Copyright (C) 2005-2006 by Texas Instruments
 | 
				
			||||||
 | 
					 * Copyright (C) 2006-2007 Nokia Corporation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 | 
				
			||||||
 | 
					 * 02110-1301 USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 | 
				
			||||||
 | 
					 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
				
			||||||
 | 
					 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
				
			||||||
 | 
					 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 | 
				
			||||||
 | 
					 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
				
			||||||
 | 
					 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
				
			||||||
 | 
					 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __MUSB_LINUX_PLATFORM_ARCH_H__
 | 
				
			||||||
 | 
					#define __MUSB_LINUX_PLATFORM_ARCH_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/io.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef	CONFIG_ARM
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* NOTE:  these offsets are all in bytes */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline u16 musb_readw(const void __iomem *addr, unsigned offset)
 | 
				
			||||||
 | 
						{ return __raw_readw(addr + offset); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline u32 musb_readl(const void __iomem *addr, unsigned offset)
 | 
				
			||||||
 | 
						{ return __raw_readl(addr + offset); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data)
 | 
				
			||||||
 | 
						{ __raw_writew(data, addr + offset); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data)
 | 
				
			||||||
 | 
						{ __raw_writel(data, addr + offset); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_TUSB6010
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u16 tmp;
 | 
				
			||||||
 | 
						u8 val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tmp = __raw_readw(addr + (offset & ~1));
 | 
				
			||||||
 | 
						if (offset & 1)
 | 
				
			||||||
 | 
							val = (tmp >> 8);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							val = tmp & 0xff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return val;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u16 tmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tmp = __raw_readw(addr + (offset & ~1));
 | 
				
			||||||
 | 
						if (offset & 1)
 | 
				
			||||||
 | 
							tmp = (data << 8) | (tmp & 0xff);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							tmp = (tmp & 0xff00) | data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						__raw_writew(tmp, addr + (offset & ~1));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
 | 
				
			||||||
 | 
						{ return __raw_readb(addr + offset); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
 | 
				
			||||||
 | 
						{ __raw_writeb(data, addr + offset); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif	/* CONFIG_USB_TUSB6010 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										830
									
								
								drivers/usb/musb/musb_procfs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										830
									
								
								drivers/usb/musb/musb_procfs.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,830 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * MUSB OTG driver debug support
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2005 Mentor Graphics Corporation
 | 
				
			||||||
 | 
					 * Copyright (C) 2005-2006 by Texas Instruments
 | 
				
			||||||
 | 
					 * Copyright (C) 2006-2007 Nokia Corporation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 | 
				
			||||||
 | 
					 * 02110-1301 USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 | 
				
			||||||
 | 
					 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
				
			||||||
 | 
					 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
				
			||||||
 | 
					 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 | 
				
			||||||
 | 
					 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
				
			||||||
 | 
					 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
				
			||||||
 | 
					 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include <linux/proc_fs.h>
 | 
				
			||||||
 | 
					#include <linux/seq_file.h>
 | 
				
			||||||
 | 
					#include <linux/uaccess.h>	/* FIXME remove procfs writes */
 | 
				
			||||||
 | 
					#include <asm/arch/hardware.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "musb_core.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "davinci.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_MUSB_HDRC_HCD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int dump_qh(struct musb_qh *qh, char *buf, unsigned max)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int				count;
 | 
				
			||||||
 | 
						int				tmp;
 | 
				
			||||||
 | 
						struct usb_host_endpoint	*hep = qh->hep;
 | 
				
			||||||
 | 
						struct urb			*urb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						count = snprintf(buf, max, "    qh %p dev%d ep%d%s max%d\n",
 | 
				
			||||||
 | 
								qh, qh->dev->devnum, qh->epnum,
 | 
				
			||||||
 | 
								({ char *s; switch (qh->type) {
 | 
				
			||||||
 | 
								case USB_ENDPOINT_XFER_BULK:
 | 
				
			||||||
 | 
									s = "-bulk"; break;
 | 
				
			||||||
 | 
								case USB_ENDPOINT_XFER_INT:
 | 
				
			||||||
 | 
									s = "-int"; break;
 | 
				
			||||||
 | 
								case USB_ENDPOINT_XFER_CONTROL:
 | 
				
			||||||
 | 
									s = ""; break;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									s = "iso"; break;
 | 
				
			||||||
 | 
								}; s; }),
 | 
				
			||||||
 | 
								qh->maxpacket);
 | 
				
			||||||
 | 
						if (count <= 0)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						buf += count;
 | 
				
			||||||
 | 
						max -= count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each_entry(urb, &hep->urb_list, urb_list) {
 | 
				
			||||||
 | 
							tmp = snprintf(buf, max, "\t%s urb %p %d/%d\n",
 | 
				
			||||||
 | 
									usb_pipein(urb->pipe) ? "in" : "out",
 | 
				
			||||||
 | 
									urb, urb->actual_length,
 | 
				
			||||||
 | 
									urb->transfer_buffer_length);
 | 
				
			||||||
 | 
							if (tmp <= 0)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							tmp = min(tmp, (int)max);
 | 
				
			||||||
 | 
							count += tmp;
 | 
				
			||||||
 | 
							buf += tmp;
 | 
				
			||||||
 | 
							max -= tmp;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					dump_queue(struct list_head *q, char *buf, unsigned max)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int		count = 0;
 | 
				
			||||||
 | 
						struct musb_qh	*qh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each_entry(qh, q, ring) {
 | 
				
			||||||
 | 
							int	tmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							tmp = dump_qh(qh, buf, max);
 | 
				
			||||||
 | 
							if (tmp <= 0)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							tmp = min(tmp, (int)max);
 | 
				
			||||||
 | 
							count += tmp;
 | 
				
			||||||
 | 
							buf += tmp;
 | 
				
			||||||
 | 
							max -= tmp;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif	/* HCD */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_GADGET_MUSB_HDRC
 | 
				
			||||||
 | 
					static int dump_ep(struct musb_ep *ep, char *buffer, unsigned max)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char		*buf = buffer;
 | 
				
			||||||
 | 
						int		code = 0;
 | 
				
			||||||
 | 
						void __iomem	*regs = ep->hw_ep->regs;
 | 
				
			||||||
 | 
						char		*mode = "1buf";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ep->is_in) {
 | 
				
			||||||
 | 
							if (ep->hw_ep->tx_double_buffered)
 | 
				
			||||||
 | 
								mode = "2buf";
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if (ep->hw_ep->rx_double_buffered)
 | 
				
			||||||
 | 
								mode = "2buf";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						do {
 | 
				
			||||||
 | 
							struct usb_request	*req;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							code = snprintf(buf, max,
 | 
				
			||||||
 | 
									"\n%s (hw%d): %s%s, csr %04x maxp %04x\n",
 | 
				
			||||||
 | 
									ep->name, ep->current_epnum,
 | 
				
			||||||
 | 
									mode, ep->dma ? " dma" : "",
 | 
				
			||||||
 | 
									musb_readw(regs,
 | 
				
			||||||
 | 
										(ep->is_in || !ep->current_epnum)
 | 
				
			||||||
 | 
											? MUSB_TXCSR
 | 
				
			||||||
 | 
											: MUSB_RXCSR),
 | 
				
			||||||
 | 
									musb_readw(regs, ep->is_in
 | 
				
			||||||
 | 
											? MUSB_TXMAXP
 | 
				
			||||||
 | 
											: MUSB_RXMAXP)
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
							if (code <= 0)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							code = min(code, (int) max);
 | 
				
			||||||
 | 
							buf += code;
 | 
				
			||||||
 | 
							max -= code;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (is_cppi_enabled() && ep->current_epnum) {
 | 
				
			||||||
 | 
								unsigned	cppi = ep->current_epnum - 1;
 | 
				
			||||||
 | 
								void __iomem	*base = ep->musb->ctrl_base;
 | 
				
			||||||
 | 
								unsigned	off1 = cppi << 2;
 | 
				
			||||||
 | 
								void __iomem	*ram = base;
 | 
				
			||||||
 | 
								char		tmp[16];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (ep->is_in) {
 | 
				
			||||||
 | 
									ram += DAVINCI_TXCPPI_STATERAM_OFFSET(cppi);
 | 
				
			||||||
 | 
									tmp[0] = 0;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									ram += DAVINCI_RXCPPI_STATERAM_OFFSET(cppi);
 | 
				
			||||||
 | 
									snprintf(tmp, sizeof tmp, "%d left, ",
 | 
				
			||||||
 | 
										musb_readl(base,
 | 
				
			||||||
 | 
										DAVINCI_RXCPPI_BUFCNT0_REG + off1));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								code = snprintf(buf, max, "%cX DMA%d: %s"
 | 
				
			||||||
 | 
										"%08x %08x, %08x %08x; "
 | 
				
			||||||
 | 
										"%08x %08x %08x .. %08x\n",
 | 
				
			||||||
 | 
									ep->is_in ? 'T' : 'R',
 | 
				
			||||||
 | 
									ep->current_epnum - 1, tmp,
 | 
				
			||||||
 | 
									musb_readl(ram, 0 * 4),
 | 
				
			||||||
 | 
									musb_readl(ram, 1 * 4),
 | 
				
			||||||
 | 
									musb_readl(ram, 2 * 4),
 | 
				
			||||||
 | 
									musb_readl(ram, 3 * 4),
 | 
				
			||||||
 | 
									musb_readl(ram, 4 * 4),
 | 
				
			||||||
 | 
									musb_readl(ram, 5 * 4),
 | 
				
			||||||
 | 
									musb_readl(ram, 6 * 4),
 | 
				
			||||||
 | 
									musb_readl(ram, 7 * 4));
 | 
				
			||||||
 | 
								if (code <= 0)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								code = min(code, (int) max);
 | 
				
			||||||
 | 
								buf += code;
 | 
				
			||||||
 | 
								max -= code;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (list_empty(&ep->req_list)) {
 | 
				
			||||||
 | 
								code = snprintf(buf, max, "\t(queue empty)\n");
 | 
				
			||||||
 | 
								if (code <= 0)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								code = min(code, (int) max);
 | 
				
			||||||
 | 
								buf += code;
 | 
				
			||||||
 | 
								max -= code;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							list_for_each_entry(req, &ep->req_list, list) {
 | 
				
			||||||
 | 
								code = snprintf(buf, max, "\treq %p, %s%s%d/%d\n",
 | 
				
			||||||
 | 
										req,
 | 
				
			||||||
 | 
										req->zero ? "zero, " : "",
 | 
				
			||||||
 | 
										req->short_not_ok ? "!short, " : "",
 | 
				
			||||||
 | 
										req->actual, req->length);
 | 
				
			||||||
 | 
								if (code <= 0)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								code = min(code, (int) max);
 | 
				
			||||||
 | 
								buf += code;
 | 
				
			||||||
 | 
								max -= code;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} while (0);
 | 
				
			||||||
 | 
						return buf - buffer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					dump_end_info(struct musb *musb, u8 epnum, char *aBuffer, unsigned max)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int			code = 0;
 | 
				
			||||||
 | 
						char			*buf = aBuffer;
 | 
				
			||||||
 | 
						struct musb_hw_ep	*hw_ep = &musb->endpoints[epnum];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						do {
 | 
				
			||||||
 | 
							musb_ep_select(musb->mregs, epnum);
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_MUSB_HDRC_HCD
 | 
				
			||||||
 | 
							if (is_host_active(musb)) {
 | 
				
			||||||
 | 
								int		dump_rx, dump_tx;
 | 
				
			||||||
 | 
								void __iomem	*regs = hw_ep->regs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* TEMPORARY (!) until we have a real periodic
 | 
				
			||||||
 | 
								 * schedule tree ...
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								if (!epnum) {
 | 
				
			||||||
 | 
									/* control is shared, uses RX queue
 | 
				
			||||||
 | 
									 * but (mostly) shadowed tx registers
 | 
				
			||||||
 | 
									 */
 | 
				
			||||||
 | 
									dump_tx = !list_empty(&musb->control);
 | 
				
			||||||
 | 
									dump_rx = 0;
 | 
				
			||||||
 | 
								} else if (hw_ep == musb->bulk_ep) {
 | 
				
			||||||
 | 
									dump_tx = !list_empty(&musb->out_bulk);
 | 
				
			||||||
 | 
									dump_rx = !list_empty(&musb->in_bulk);
 | 
				
			||||||
 | 
								} else if (musb->periodic[epnum]) {
 | 
				
			||||||
 | 
									struct usb_host_endpoint	*hep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									hep = musb->periodic[epnum]->hep;
 | 
				
			||||||
 | 
									dump_rx = hep->desc.bEndpointAddress
 | 
				
			||||||
 | 
											& USB_ENDPOINT_DIR_MASK;
 | 
				
			||||||
 | 
									dump_tx = !dump_rx;
 | 
				
			||||||
 | 
								} else
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								/* END TEMPORARY */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (dump_rx) {
 | 
				
			||||||
 | 
									code = snprintf(buf, max,
 | 
				
			||||||
 | 
										"\nRX%d: %s rxcsr %04x interval %02x "
 | 
				
			||||||
 | 
										"max %04x type %02x; "
 | 
				
			||||||
 | 
										"dev %d hub %d port %d"
 | 
				
			||||||
 | 
										"\n",
 | 
				
			||||||
 | 
										epnum,
 | 
				
			||||||
 | 
										hw_ep->rx_double_buffered
 | 
				
			||||||
 | 
											? "2buf" : "1buf",
 | 
				
			||||||
 | 
										musb_readw(regs, MUSB_RXCSR),
 | 
				
			||||||
 | 
										musb_readb(regs, MUSB_RXINTERVAL),
 | 
				
			||||||
 | 
										musb_readw(regs, MUSB_RXMAXP),
 | 
				
			||||||
 | 
										musb_readb(regs, MUSB_RXTYPE),
 | 
				
			||||||
 | 
										/* FIXME:  assumes multipoint */
 | 
				
			||||||
 | 
										musb_readb(musb->mregs,
 | 
				
			||||||
 | 
											MUSB_BUSCTL_OFFSET(epnum,
 | 
				
			||||||
 | 
											MUSB_RXFUNCADDR)),
 | 
				
			||||||
 | 
										musb_readb(musb->mregs,
 | 
				
			||||||
 | 
											MUSB_BUSCTL_OFFSET(epnum,
 | 
				
			||||||
 | 
											MUSB_RXHUBADDR)),
 | 
				
			||||||
 | 
										musb_readb(musb->mregs,
 | 
				
			||||||
 | 
											MUSB_BUSCTL_OFFSET(epnum,
 | 
				
			||||||
 | 
											MUSB_RXHUBPORT))
 | 
				
			||||||
 | 
										);
 | 
				
			||||||
 | 
									if (code <= 0)
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									code = min(code, (int) max);
 | 
				
			||||||
 | 
									buf += code;
 | 
				
			||||||
 | 
									max -= code;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (is_cppi_enabled()
 | 
				
			||||||
 | 
											&& epnum
 | 
				
			||||||
 | 
											&& hw_ep->rx_channel) {
 | 
				
			||||||
 | 
										unsigned	cppi = epnum - 1;
 | 
				
			||||||
 | 
										unsigned	off1 = cppi << 2;
 | 
				
			||||||
 | 
										void __iomem	*base;
 | 
				
			||||||
 | 
										void __iomem	*ram;
 | 
				
			||||||
 | 
										char		tmp[16];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										base = musb->ctrl_base;
 | 
				
			||||||
 | 
										ram = DAVINCI_RXCPPI_STATERAM_OFFSET(
 | 
				
			||||||
 | 
												cppi) + base;
 | 
				
			||||||
 | 
										snprintf(tmp, sizeof tmp, "%d left, ",
 | 
				
			||||||
 | 
											musb_readl(base,
 | 
				
			||||||
 | 
											DAVINCI_RXCPPI_BUFCNT0_REG
 | 
				
			||||||
 | 
													+ off1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										code = snprintf(buf, max,
 | 
				
			||||||
 | 
											"    rx dma%d: %s"
 | 
				
			||||||
 | 
											"%08x %08x, %08x %08x; "
 | 
				
			||||||
 | 
											"%08x %08x %08x .. %08x\n",
 | 
				
			||||||
 | 
											cppi, tmp,
 | 
				
			||||||
 | 
											musb_readl(ram, 0 * 4),
 | 
				
			||||||
 | 
											musb_readl(ram, 1 * 4),
 | 
				
			||||||
 | 
											musb_readl(ram, 2 * 4),
 | 
				
			||||||
 | 
											musb_readl(ram, 3 * 4),
 | 
				
			||||||
 | 
											musb_readl(ram, 4 * 4),
 | 
				
			||||||
 | 
											musb_readl(ram, 5 * 4),
 | 
				
			||||||
 | 
											musb_readl(ram, 6 * 4),
 | 
				
			||||||
 | 
											musb_readl(ram, 7 * 4));
 | 
				
			||||||
 | 
										if (code <= 0)
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										code = min(code, (int) max);
 | 
				
			||||||
 | 
										buf += code;
 | 
				
			||||||
 | 
										max -= code;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (hw_ep == musb->bulk_ep
 | 
				
			||||||
 | 
											&& !list_empty(
 | 
				
			||||||
 | 
												&musb->in_bulk)) {
 | 
				
			||||||
 | 
										code = dump_queue(&musb->in_bulk,
 | 
				
			||||||
 | 
												buf, max);
 | 
				
			||||||
 | 
										if (code <= 0)
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										code = min(code, (int) max);
 | 
				
			||||||
 | 
										buf += code;
 | 
				
			||||||
 | 
										max -= code;
 | 
				
			||||||
 | 
									} else if (musb->periodic[epnum]) {
 | 
				
			||||||
 | 
										code = dump_qh(musb->periodic[epnum],
 | 
				
			||||||
 | 
												buf, max);
 | 
				
			||||||
 | 
										if (code <= 0)
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										code = min(code, (int) max);
 | 
				
			||||||
 | 
										buf += code;
 | 
				
			||||||
 | 
										max -= code;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (dump_tx) {
 | 
				
			||||||
 | 
									code = snprintf(buf, max,
 | 
				
			||||||
 | 
										"\nTX%d: %s txcsr %04x interval %02x "
 | 
				
			||||||
 | 
										"max %04x type %02x; "
 | 
				
			||||||
 | 
										"dev %d hub %d port %d"
 | 
				
			||||||
 | 
										"\n",
 | 
				
			||||||
 | 
										epnum,
 | 
				
			||||||
 | 
										hw_ep->tx_double_buffered
 | 
				
			||||||
 | 
											? "2buf" : "1buf",
 | 
				
			||||||
 | 
										musb_readw(regs, MUSB_TXCSR),
 | 
				
			||||||
 | 
										musb_readb(regs, MUSB_TXINTERVAL),
 | 
				
			||||||
 | 
										musb_readw(regs, MUSB_TXMAXP),
 | 
				
			||||||
 | 
										musb_readb(regs, MUSB_TXTYPE),
 | 
				
			||||||
 | 
										/* FIXME:  assumes multipoint */
 | 
				
			||||||
 | 
										musb_readb(musb->mregs,
 | 
				
			||||||
 | 
											MUSB_BUSCTL_OFFSET(epnum,
 | 
				
			||||||
 | 
											MUSB_TXFUNCADDR)),
 | 
				
			||||||
 | 
										musb_readb(musb->mregs,
 | 
				
			||||||
 | 
											MUSB_BUSCTL_OFFSET(epnum,
 | 
				
			||||||
 | 
											MUSB_TXHUBADDR)),
 | 
				
			||||||
 | 
										musb_readb(musb->mregs,
 | 
				
			||||||
 | 
											MUSB_BUSCTL_OFFSET(epnum,
 | 
				
			||||||
 | 
											MUSB_TXHUBPORT))
 | 
				
			||||||
 | 
										);
 | 
				
			||||||
 | 
									if (code <= 0)
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									code = min(code, (int) max);
 | 
				
			||||||
 | 
									buf += code;
 | 
				
			||||||
 | 
									max -= code;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (is_cppi_enabled()
 | 
				
			||||||
 | 
											&& epnum
 | 
				
			||||||
 | 
											&& hw_ep->tx_channel) {
 | 
				
			||||||
 | 
										unsigned	cppi = epnum - 1;
 | 
				
			||||||
 | 
										void __iomem	*base;
 | 
				
			||||||
 | 
										void __iomem	*ram;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										base = musb->ctrl_base;
 | 
				
			||||||
 | 
										ram = DAVINCI_RXCPPI_STATERAM_OFFSET(
 | 
				
			||||||
 | 
												cppi) + base;
 | 
				
			||||||
 | 
										code = snprintf(buf, max,
 | 
				
			||||||
 | 
											"    tx dma%d: "
 | 
				
			||||||
 | 
											"%08x %08x, %08x %08x; "
 | 
				
			||||||
 | 
											"%08x %08x %08x .. %08x\n",
 | 
				
			||||||
 | 
											cppi,
 | 
				
			||||||
 | 
											musb_readl(ram, 0 * 4),
 | 
				
			||||||
 | 
											musb_readl(ram, 1 * 4),
 | 
				
			||||||
 | 
											musb_readl(ram, 2 * 4),
 | 
				
			||||||
 | 
											musb_readl(ram, 3 * 4),
 | 
				
			||||||
 | 
											musb_readl(ram, 4 * 4),
 | 
				
			||||||
 | 
											musb_readl(ram, 5 * 4),
 | 
				
			||||||
 | 
											musb_readl(ram, 6 * 4),
 | 
				
			||||||
 | 
											musb_readl(ram, 7 * 4));
 | 
				
			||||||
 | 
										if (code <= 0)
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										code = min(code, (int) max);
 | 
				
			||||||
 | 
										buf += code;
 | 
				
			||||||
 | 
										max -= code;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (hw_ep == musb->control_ep
 | 
				
			||||||
 | 
											&& !list_empty(
 | 
				
			||||||
 | 
												&musb->control)) {
 | 
				
			||||||
 | 
										code = dump_queue(&musb->control,
 | 
				
			||||||
 | 
												buf, max);
 | 
				
			||||||
 | 
										if (code <= 0)
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										code = min(code, (int) max);
 | 
				
			||||||
 | 
										buf += code;
 | 
				
			||||||
 | 
										max -= code;
 | 
				
			||||||
 | 
									} else if (hw_ep == musb->bulk_ep
 | 
				
			||||||
 | 
											&& !list_empty(
 | 
				
			||||||
 | 
												&musb->out_bulk)) {
 | 
				
			||||||
 | 
										code = dump_queue(&musb->out_bulk,
 | 
				
			||||||
 | 
												buf, max);
 | 
				
			||||||
 | 
										if (code <= 0)
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										code = min(code, (int) max);
 | 
				
			||||||
 | 
										buf += code;
 | 
				
			||||||
 | 
										max -= code;
 | 
				
			||||||
 | 
									} else if (musb->periodic[epnum]) {
 | 
				
			||||||
 | 
										code = dump_qh(musb->periodic[epnum],
 | 
				
			||||||
 | 
												buf, max);
 | 
				
			||||||
 | 
										if (code <= 0)
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										code = min(code, (int) max);
 | 
				
			||||||
 | 
										buf += code;
 | 
				
			||||||
 | 
										max -= code;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_GADGET_MUSB_HDRC
 | 
				
			||||||
 | 
							if (is_peripheral_active(musb)) {
 | 
				
			||||||
 | 
								code = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (hw_ep->ep_in.desc || !epnum) {
 | 
				
			||||||
 | 
									code = dump_ep(&hw_ep->ep_in, buf, max);
 | 
				
			||||||
 | 
									if (code <= 0)
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									code = min(code, (int) max);
 | 
				
			||||||
 | 
									buf += code;
 | 
				
			||||||
 | 
									max -= code;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (hw_ep->ep_out.desc) {
 | 
				
			||||||
 | 
									code = dump_ep(&hw_ep->ep_out, buf, max);
 | 
				
			||||||
 | 
									if (code <= 0)
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									code = min(code, (int) max);
 | 
				
			||||||
 | 
									buf += code;
 | 
				
			||||||
 | 
									max -= code;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						} while (0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return buf - aBuffer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Dump the current status and compile options.
 | 
				
			||||||
 | 
					 * @param musb the device driver instance
 | 
				
			||||||
 | 
					 * @param buffer where to dump the status; it must be big enough to hold the
 | 
				
			||||||
 | 
					 * result otherwise "BAD THINGS HAPPENS(TM)".
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int dump_header_stats(struct musb *musb, char *buffer)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int code, count = 0;
 | 
				
			||||||
 | 
						const void __iomem *mbase = musb->mregs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*buffer = 0;
 | 
				
			||||||
 | 
						count = sprintf(buffer, "Status: %sHDRC, Mode=%s "
 | 
				
			||||||
 | 
									"(Power=%02x, DevCtl=%02x)\n",
 | 
				
			||||||
 | 
								(musb->is_multipoint ? "M" : ""), MUSB_MODE(musb),
 | 
				
			||||||
 | 
								musb_readb(mbase, MUSB_POWER),
 | 
				
			||||||
 | 
								musb_readb(mbase, MUSB_DEVCTL));
 | 
				
			||||||
 | 
						if (count <= 0)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						buffer += count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						code = sprintf(buffer, "OTG state: %s; %sactive\n",
 | 
				
			||||||
 | 
								otg_state_string(musb),
 | 
				
			||||||
 | 
								musb->is_active ? "" : "in");
 | 
				
			||||||
 | 
						if (code <= 0)
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
						buffer += code;
 | 
				
			||||||
 | 
						count += code;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						code = sprintf(buffer,
 | 
				
			||||||
 | 
								"Options: "
 | 
				
			||||||
 | 
					#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 [eps=%d]\n",
 | 
				
			||||||
 | 
							debug,
 | 
				
			||||||
 | 
							musb->nr_endpoints);
 | 
				
			||||||
 | 
						if (code <= 0)
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
						count += code;
 | 
				
			||||||
 | 
						buffer += code;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef	CONFIG_USB_GADGET_MUSB_HDRC
 | 
				
			||||||
 | 
						code = sprintf(buffer, "Peripheral address: %02x\n",
 | 
				
			||||||
 | 
								musb_readb(musb->ctrl_base, MUSB_FADDR));
 | 
				
			||||||
 | 
						if (code <= 0)
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
						buffer += code;
 | 
				
			||||||
 | 
						count += code;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef	CONFIG_USB_MUSB_HDRC_HCD
 | 
				
			||||||
 | 
						code = sprintf(buffer, "Root port status: %08x\n",
 | 
				
			||||||
 | 
								musb->port1_status);
 | 
				
			||||||
 | 
						if (code <= 0)
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
						buffer += code;
 | 
				
			||||||
 | 
						count += code;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef	CONFIG_ARCH_DAVINCI
 | 
				
			||||||
 | 
						code = sprintf(buffer,
 | 
				
			||||||
 | 
								"DaVinci: ctrl=%02x stat=%1x phy=%03x\n"
 | 
				
			||||||
 | 
								"\trndis=%05x auto=%04x intsrc=%08x intmsk=%08x"
 | 
				
			||||||
 | 
								"\n",
 | 
				
			||||||
 | 
								musb_readl(musb->ctrl_base, DAVINCI_USB_CTRL_REG),
 | 
				
			||||||
 | 
								musb_readl(musb->ctrl_base, DAVINCI_USB_STAT_REG),
 | 
				
			||||||
 | 
								__raw_readl((void __force __iomem *)
 | 
				
			||||||
 | 
										IO_ADDRESS(USBPHY_CTL_PADDR)),
 | 
				
			||||||
 | 
								musb_readl(musb->ctrl_base, DAVINCI_RNDIS_REG),
 | 
				
			||||||
 | 
								musb_readl(musb->ctrl_base, DAVINCI_AUTOREQ_REG),
 | 
				
			||||||
 | 
								musb_readl(musb->ctrl_base,
 | 
				
			||||||
 | 
										DAVINCI_USB_INT_SOURCE_REG),
 | 
				
			||||||
 | 
								musb_readl(musb->ctrl_base,
 | 
				
			||||||
 | 
										DAVINCI_USB_INT_MASK_REG));
 | 
				
			||||||
 | 
						if (code <= 0)
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
						count += code;
 | 
				
			||||||
 | 
						buffer += code;
 | 
				
			||||||
 | 
					#endif	/* DAVINCI */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_TUSB6010
 | 
				
			||||||
 | 
						code = sprintf(buffer,
 | 
				
			||||||
 | 
								"TUSB6010: devconf %08x, phy enable %08x drive %08x"
 | 
				
			||||||
 | 
								"\n\totg %03x timer %08x"
 | 
				
			||||||
 | 
								"\n\tprcm conf %08x mgmt %08x; int src %08x mask %08x"
 | 
				
			||||||
 | 
								"\n",
 | 
				
			||||||
 | 
								musb_readl(musb->ctrl_base, TUSB_DEV_CONF),
 | 
				
			||||||
 | 
								musb_readl(musb->ctrl_base, TUSB_PHY_OTG_CTRL_ENABLE),
 | 
				
			||||||
 | 
								musb_readl(musb->ctrl_base, TUSB_PHY_OTG_CTRL),
 | 
				
			||||||
 | 
								musb_readl(musb->ctrl_base, TUSB_DEV_OTG_STAT),
 | 
				
			||||||
 | 
								musb_readl(musb->ctrl_base, TUSB_DEV_OTG_TIMER),
 | 
				
			||||||
 | 
								musb_readl(musb->ctrl_base, TUSB_PRCM_CONF),
 | 
				
			||||||
 | 
								musb_readl(musb->ctrl_base, TUSB_PRCM_MNGMT),
 | 
				
			||||||
 | 
								musb_readl(musb->ctrl_base, TUSB_INT_SRC),
 | 
				
			||||||
 | 
								musb_readl(musb->ctrl_base, TUSB_INT_MASK));
 | 
				
			||||||
 | 
						if (code <= 0)
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
						count += code;
 | 
				
			||||||
 | 
						buffer += code;
 | 
				
			||||||
 | 
					#endif	/* DAVINCI */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (is_cppi_enabled() && musb->dma_controller) {
 | 
				
			||||||
 | 
							code = sprintf(buffer,
 | 
				
			||||||
 | 
									"CPPI: txcr=%d txsrc=%01x txena=%01x; "
 | 
				
			||||||
 | 
									"rxcr=%d rxsrc=%01x rxena=%01x "
 | 
				
			||||||
 | 
									"\n",
 | 
				
			||||||
 | 
									musb_readl(musb->ctrl_base,
 | 
				
			||||||
 | 
											DAVINCI_TXCPPI_CTRL_REG),
 | 
				
			||||||
 | 
									musb_readl(musb->ctrl_base,
 | 
				
			||||||
 | 
											DAVINCI_TXCPPI_RAW_REG),
 | 
				
			||||||
 | 
									musb_readl(musb->ctrl_base,
 | 
				
			||||||
 | 
											DAVINCI_TXCPPI_INTENAB_REG),
 | 
				
			||||||
 | 
									musb_readl(musb->ctrl_base,
 | 
				
			||||||
 | 
											DAVINCI_RXCPPI_CTRL_REG),
 | 
				
			||||||
 | 
									musb_readl(musb->ctrl_base,
 | 
				
			||||||
 | 
											DAVINCI_RXCPPI_RAW_REG),
 | 
				
			||||||
 | 
									musb_readl(musb->ctrl_base,
 | 
				
			||||||
 | 
											DAVINCI_RXCPPI_INTENAB_REG));
 | 
				
			||||||
 | 
							if (code <= 0)
 | 
				
			||||||
 | 
								goto done;
 | 
				
			||||||
 | 
							count += code;
 | 
				
			||||||
 | 
							buffer += code;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_GADGET_MUSB_HDRC
 | 
				
			||||||
 | 
						if (is_peripheral_enabled(musb)) {
 | 
				
			||||||
 | 
							code = sprintf(buffer, "Gadget driver: %s\n",
 | 
				
			||||||
 | 
									musb->gadget_driver
 | 
				
			||||||
 | 
										? musb->gadget_driver->driver.name
 | 
				
			||||||
 | 
										: "(none)");
 | 
				
			||||||
 | 
							if (code <= 0)
 | 
				
			||||||
 | 
								goto done;
 | 
				
			||||||
 | 
							count += code;
 | 
				
			||||||
 | 
							buffer += code;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					done:
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Write to ProcFS
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * C soft-connect
 | 
				
			||||||
 | 
					 * c soft-disconnect
 | 
				
			||||||
 | 
					 * I enable HS
 | 
				
			||||||
 | 
					 * i disable HS
 | 
				
			||||||
 | 
					 * s stop session
 | 
				
			||||||
 | 
					 * F force session (OTG-unfriendly)
 | 
				
			||||||
 | 
					 * E rElinquish bus (OTG)
 | 
				
			||||||
 | 
					 * H request host mode
 | 
				
			||||||
 | 
					 * h cancel host request
 | 
				
			||||||
 | 
					 * T start sending TEST_PACKET
 | 
				
			||||||
 | 
					 * D<num> set/query the debug level
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int musb_proc_write(struct file *file, const char __user *buffer,
 | 
				
			||||||
 | 
								unsigned long count, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char cmd;
 | 
				
			||||||
 | 
						u8 reg;
 | 
				
			||||||
 | 
						struct musb *musb = (struct musb *)data;
 | 
				
			||||||
 | 
						void __iomem *mbase = musb->mregs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* MOD_INC_USE_COUNT; */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (unlikely(copy_from_user(&cmd, buffer, 1)))
 | 
				
			||||||
 | 
							return -EFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (cmd) {
 | 
				
			||||||
 | 
						case 'C':
 | 
				
			||||||
 | 
							if (mbase) {
 | 
				
			||||||
 | 
								reg = musb_readb(mbase, MUSB_POWER)
 | 
				
			||||||
 | 
										| MUSB_POWER_SOFTCONN;
 | 
				
			||||||
 | 
								musb_writeb(mbase, MUSB_POWER, reg);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case 'c':
 | 
				
			||||||
 | 
							if (mbase) {
 | 
				
			||||||
 | 
								reg = musb_readb(mbase, MUSB_POWER)
 | 
				
			||||||
 | 
										& ~MUSB_POWER_SOFTCONN;
 | 
				
			||||||
 | 
								musb_writeb(mbase, MUSB_POWER, reg);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case 'I':
 | 
				
			||||||
 | 
							if (mbase) {
 | 
				
			||||||
 | 
								reg = musb_readb(mbase, MUSB_POWER)
 | 
				
			||||||
 | 
										| MUSB_POWER_HSENAB;
 | 
				
			||||||
 | 
								musb_writeb(mbase, MUSB_POWER, reg);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case 'i':
 | 
				
			||||||
 | 
							if (mbase) {
 | 
				
			||||||
 | 
								reg = musb_readb(mbase, MUSB_POWER)
 | 
				
			||||||
 | 
										& ~MUSB_POWER_HSENAB;
 | 
				
			||||||
 | 
								musb_writeb(mbase, MUSB_POWER, reg);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case 'F':
 | 
				
			||||||
 | 
							reg = musb_readb(mbase, MUSB_DEVCTL);
 | 
				
			||||||
 | 
							reg |= MUSB_DEVCTL_SESSION;
 | 
				
			||||||
 | 
							musb_writeb(mbase, MUSB_DEVCTL, reg);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case 'H':
 | 
				
			||||||
 | 
							if (mbase) {
 | 
				
			||||||
 | 
								reg = musb_readb(mbase, MUSB_DEVCTL);
 | 
				
			||||||
 | 
								reg |= MUSB_DEVCTL_HR;
 | 
				
			||||||
 | 
								musb_writeb(mbase, MUSB_DEVCTL, reg);
 | 
				
			||||||
 | 
								/* MUSB_HST_MODE( ((struct musb*)data) ); */
 | 
				
			||||||
 | 
								/* WARNING("Host Mode\n"); */
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case 'h':
 | 
				
			||||||
 | 
							if (mbase) {
 | 
				
			||||||
 | 
								reg = musb_readb(mbase, MUSB_DEVCTL);
 | 
				
			||||||
 | 
								reg &= ~MUSB_DEVCTL_HR;
 | 
				
			||||||
 | 
								musb_writeb(mbase, MUSB_DEVCTL, reg);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case 'T':
 | 
				
			||||||
 | 
							if (mbase) {
 | 
				
			||||||
 | 
								musb_load_testpacket(musb);
 | 
				
			||||||
 | 
								musb_writeb(mbase, MUSB_TESTMODE,
 | 
				
			||||||
 | 
										MUSB_TEST_PACKET);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if (MUSB_DEBUG > 0)
 | 
				
			||||||
 | 
							/* set/read debug level */
 | 
				
			||||||
 | 
						case 'D':{
 | 
				
			||||||
 | 
								if (count > 1) {
 | 
				
			||||||
 | 
									char digits[8], *p = digits;
 | 
				
			||||||
 | 
									int i = 0, level = 0, sign = 1;
 | 
				
			||||||
 | 
									int len = min(count - 1, (unsigned long)8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (copy_from_user(&digits, &buffer[1], len))
 | 
				
			||||||
 | 
										return -EFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/* optional sign */
 | 
				
			||||||
 | 
									if (*p == '-') {
 | 
				
			||||||
 | 
										len -= 1;
 | 
				
			||||||
 | 
										sign = -sign;
 | 
				
			||||||
 | 
										p++;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/* read it */
 | 
				
			||||||
 | 
									while (i++ < len && *p > '0' && *p < '9') {
 | 
				
			||||||
 | 
										level = level * 10 + (*p - '0');
 | 
				
			||||||
 | 
										p++;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									level *= sign;
 | 
				
			||||||
 | 
									DBG(1, "debug level %d\n", level);
 | 
				
			||||||
 | 
									debug = level;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case '?':
 | 
				
			||||||
 | 
							INFO("?: you are seeing it\n");
 | 
				
			||||||
 | 
							INFO("C/c: soft connect enable/disable\n");
 | 
				
			||||||
 | 
							INFO("I/i: hispeed enable/disable\n");
 | 
				
			||||||
 | 
							INFO("F: force session start\n");
 | 
				
			||||||
 | 
							INFO("H: host mode\n");
 | 
				
			||||||
 | 
							INFO("T: start sending TEST_PACKET\n");
 | 
				
			||||||
 | 
							INFO("D: set/read dbug level\n");
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							ERR("Command %c not implemented\n", cmd);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						musb_platform_try_idle(musb, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int musb_proc_read(char *page, char **start,
 | 
				
			||||||
 | 
								off_t off, int count, int *eof, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *buffer = page;
 | 
				
			||||||
 | 
						int code = 0;
 | 
				
			||||||
 | 
						unsigned long	flags;
 | 
				
			||||||
 | 
						struct musb	*musb = data;
 | 
				
			||||||
 | 
						unsigned	epnum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						count -= off;
 | 
				
			||||||
 | 
						count -= 1;		/* for NUL at end */
 | 
				
			||||||
 | 
						if (count <= 0)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_irqsave(&musb->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						code = dump_header_stats(musb, buffer);
 | 
				
			||||||
 | 
						if (code > 0) {
 | 
				
			||||||
 | 
							buffer += code;
 | 
				
			||||||
 | 
							count -= code;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* generate the report for the end points */
 | 
				
			||||||
 | 
						/* REVISIT ... not unless something's connected! */
 | 
				
			||||||
 | 
						for (epnum = 0; count >= 0 && epnum < musb->nr_endpoints;
 | 
				
			||||||
 | 
								epnum++) {
 | 
				
			||||||
 | 
							code = dump_end_info(musb, epnum, buffer, count);
 | 
				
			||||||
 | 
							if (code > 0) {
 | 
				
			||||||
 | 
								buffer += code;
 | 
				
			||||||
 | 
								count -= code;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						musb_platform_try_idle(musb, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_unlock_irqrestore(&musb->lock, flags);
 | 
				
			||||||
 | 
						*eof = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return buffer - page;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void __devexit musb_debug_delete(char *name, struct musb *musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (musb->proc_entry)
 | 
				
			||||||
 | 
							remove_proc_entry(name, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct proc_dir_entry *__init
 | 
				
			||||||
 | 
					musb_debug_create(char *name, struct musb *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct proc_dir_entry	*pde;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* FIXME convert everything to seq_file; then later, debugfs */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!name)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pde = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, NULL);
 | 
				
			||||||
 | 
						data->proc_entry = pde;
 | 
				
			||||||
 | 
						if (pde) {
 | 
				
			||||||
 | 
							pde->data = data;
 | 
				
			||||||
 | 
							/* pde->owner = THIS_MODULE; */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pde->read_proc = musb_proc_read;
 | 
				
			||||||
 | 
							pde->write_proc = musb_proc_write;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pde->size = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pr_debug("Registered /proc/%s\n", name);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							pr_debug("Cannot create a valid proc file entry");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return pde;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										300
									
								
								drivers/usb/musb/musb_regs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										300
									
								
								drivers/usb/musb/musb_regs.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,300 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * MUSB OTG driver register defines
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2005 Mentor Graphics Corporation
 | 
				
			||||||
 | 
					 * Copyright (C) 2005-2006 by Texas Instruments
 | 
				
			||||||
 | 
					 * Copyright (C) 2006-2007 Nokia Corporation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 | 
				
			||||||
 | 
					 * 02110-1301 USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 | 
				
			||||||
 | 
					 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
				
			||||||
 | 
					 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
				
			||||||
 | 
					 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 | 
				
			||||||
 | 
					 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
				
			||||||
 | 
					 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
				
			||||||
 | 
					 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __MUSB_REGS_H__
 | 
				
			||||||
 | 
					#define __MUSB_REGS_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MUSB_EP0_FIFOSIZE	64	/* This is non-configurable */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Common USB registers
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MUSB_FADDR		0x00	/* 8-bit */
 | 
				
			||||||
 | 
					#define MUSB_POWER		0x01	/* 8-bit */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MUSB_INTRTX		0x02	/* 16-bit */
 | 
				
			||||||
 | 
					#define MUSB_INTRRX		0x04
 | 
				
			||||||
 | 
					#define MUSB_INTRTXE		0x06
 | 
				
			||||||
 | 
					#define MUSB_INTRRXE		0x08
 | 
				
			||||||
 | 
					#define MUSB_INTRUSB		0x0A	/* 8 bit */
 | 
				
			||||||
 | 
					#define MUSB_INTRUSBE		0x0B	/* 8 bit */
 | 
				
			||||||
 | 
					#define MUSB_FRAME		0x0C
 | 
				
			||||||
 | 
					#define MUSB_INDEX		0x0E	/* 8 bit */
 | 
				
			||||||
 | 
					#define MUSB_TESTMODE		0x0F	/* 8 bit */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Get offset for a given FIFO from musb->mregs */
 | 
				
			||||||
 | 
					#ifdef	CONFIG_USB_TUSB6010
 | 
				
			||||||
 | 
					#define MUSB_FIFO_OFFSET(epnum)	(0x200 + ((epnum) * 0x20))
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define MUSB_FIFO_OFFSET(epnum)	(0x20 + ((epnum) * 4))
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Additional Control Registers
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MUSB_DEVCTL		0x60	/* 8 bit */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* These are always controlled through the INDEX register */
 | 
				
			||||||
 | 
					#define MUSB_TXFIFOSZ		0x62	/* 8-bit (see masks) */
 | 
				
			||||||
 | 
					#define MUSB_RXFIFOSZ		0x63	/* 8-bit (see masks) */
 | 
				
			||||||
 | 
					#define MUSB_TXFIFOADD		0x64	/* 16-bit offset shifted right 3 */
 | 
				
			||||||
 | 
					#define MUSB_RXFIFOADD		0x66	/* 16-bit offset shifted right 3 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* REVISIT: vctrl/vstatus: optional vendor utmi+phy register at 0x68 */
 | 
				
			||||||
 | 
					#define MUSB_HWVERS		0x6C	/* 8 bit */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MUSB_EPINFO		0x78	/* 8 bit */
 | 
				
			||||||
 | 
					#define MUSB_RAMINFO		0x79	/* 8 bit */
 | 
				
			||||||
 | 
					#define MUSB_LINKINFO		0x7a	/* 8 bit */
 | 
				
			||||||
 | 
					#define MUSB_VPLEN		0x7b	/* 8 bit */
 | 
				
			||||||
 | 
					#define MUSB_HS_EOF1		0x7c	/* 8 bit */
 | 
				
			||||||
 | 
					#define MUSB_FS_EOF1		0x7d	/* 8 bit */
 | 
				
			||||||
 | 
					#define MUSB_LS_EOF1		0x7e	/* 8 bit */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Offsets to endpoint registers */
 | 
				
			||||||
 | 
					#define MUSB_TXMAXP		0x00
 | 
				
			||||||
 | 
					#define MUSB_TXCSR		0x02
 | 
				
			||||||
 | 
					#define MUSB_CSR0		MUSB_TXCSR	/* Re-used for EP0 */
 | 
				
			||||||
 | 
					#define MUSB_RXMAXP		0x04
 | 
				
			||||||
 | 
					#define MUSB_RXCSR		0x06
 | 
				
			||||||
 | 
					#define MUSB_RXCOUNT		0x08
 | 
				
			||||||
 | 
					#define MUSB_COUNT0		MUSB_RXCOUNT	/* Re-used for EP0 */
 | 
				
			||||||
 | 
					#define MUSB_TXTYPE		0x0A
 | 
				
			||||||
 | 
					#define MUSB_TYPE0		MUSB_TXTYPE	/* Re-used for EP0 */
 | 
				
			||||||
 | 
					#define MUSB_TXINTERVAL		0x0B
 | 
				
			||||||
 | 
					#define MUSB_NAKLIMIT0		MUSB_TXINTERVAL	/* Re-used for EP0 */
 | 
				
			||||||
 | 
					#define MUSB_RXTYPE		0x0C
 | 
				
			||||||
 | 
					#define MUSB_RXINTERVAL		0x0D
 | 
				
			||||||
 | 
					#define MUSB_FIFOSIZE		0x0F
 | 
				
			||||||
 | 
					#define MUSB_CONFIGDATA		MUSB_FIFOSIZE	/* Re-used for EP0 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Offsets to endpoint registers in indexed model (using INDEX register) */
 | 
				
			||||||
 | 
					#define MUSB_INDEXED_OFFSET(_epnum, _offset)	\
 | 
				
			||||||
 | 
						(0x10 + (_offset))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Offsets to endpoint registers in flat models */
 | 
				
			||||||
 | 
					#define MUSB_FLAT_OFFSET(_epnum, _offset)	\
 | 
				
			||||||
 | 
						(0x100 + (0x10*(_epnum)) + (_offset))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_TUSB6010
 | 
				
			||||||
 | 
					/* TUSB6010 EP0 configuration register is special */
 | 
				
			||||||
 | 
					#define MUSB_TUSB_OFFSET(_epnum, _offset)	\
 | 
				
			||||||
 | 
						(0x10 + _offset)
 | 
				
			||||||
 | 
					#include "tusb6010.h"		/* Needed "only" for TUSB_EP0_CONF */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* "bus control"/target registers, for host side multipoint (external hubs) */
 | 
				
			||||||
 | 
					#define MUSB_TXFUNCADDR		0x00
 | 
				
			||||||
 | 
					#define MUSB_TXHUBADDR		0x02
 | 
				
			||||||
 | 
					#define MUSB_TXHUBPORT		0x03
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MUSB_RXFUNCADDR		0x04
 | 
				
			||||||
 | 
					#define MUSB_RXHUBADDR		0x06
 | 
				
			||||||
 | 
					#define MUSB_RXHUBPORT		0x07
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MUSB_BUSCTL_OFFSET(_epnum, _offset) \
 | 
				
			||||||
 | 
						(0x80 + (8*(_epnum)) + (_offset))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * MUSB Register bits
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* POWER */
 | 
				
			||||||
 | 
					#define MUSB_POWER_ISOUPDATE	0x80
 | 
				
			||||||
 | 
					#define MUSB_POWER_SOFTCONN	0x40
 | 
				
			||||||
 | 
					#define MUSB_POWER_HSENAB	0x20
 | 
				
			||||||
 | 
					#define MUSB_POWER_HSMODE	0x10
 | 
				
			||||||
 | 
					#define MUSB_POWER_RESET	0x08
 | 
				
			||||||
 | 
					#define MUSB_POWER_RESUME	0x04
 | 
				
			||||||
 | 
					#define MUSB_POWER_SUSPENDM	0x02
 | 
				
			||||||
 | 
					#define MUSB_POWER_ENSUSPEND	0x01
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* INTRUSB */
 | 
				
			||||||
 | 
					#define MUSB_INTR_SUSPEND	0x01
 | 
				
			||||||
 | 
					#define MUSB_INTR_RESUME	0x02
 | 
				
			||||||
 | 
					#define MUSB_INTR_RESET		0x04
 | 
				
			||||||
 | 
					#define MUSB_INTR_BABBLE	0x04
 | 
				
			||||||
 | 
					#define MUSB_INTR_SOF		0x08
 | 
				
			||||||
 | 
					#define MUSB_INTR_CONNECT	0x10
 | 
				
			||||||
 | 
					#define MUSB_INTR_DISCONNECT	0x20
 | 
				
			||||||
 | 
					#define MUSB_INTR_SESSREQ	0x40
 | 
				
			||||||
 | 
					#define MUSB_INTR_VBUSERROR	0x80	/* For SESSION end */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* DEVCTL */
 | 
				
			||||||
 | 
					#define MUSB_DEVCTL_BDEVICE	0x80
 | 
				
			||||||
 | 
					#define MUSB_DEVCTL_FSDEV	0x40
 | 
				
			||||||
 | 
					#define MUSB_DEVCTL_LSDEV	0x20
 | 
				
			||||||
 | 
					#define MUSB_DEVCTL_VBUS	0x18
 | 
				
			||||||
 | 
					#define MUSB_DEVCTL_VBUS_SHIFT	3
 | 
				
			||||||
 | 
					#define MUSB_DEVCTL_HM		0x04
 | 
				
			||||||
 | 
					#define MUSB_DEVCTL_HR		0x02
 | 
				
			||||||
 | 
					#define MUSB_DEVCTL_SESSION	0x01
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* TESTMODE */
 | 
				
			||||||
 | 
					#define MUSB_TEST_FORCE_HOST	0x80
 | 
				
			||||||
 | 
					#define MUSB_TEST_FIFO_ACCESS	0x40
 | 
				
			||||||
 | 
					#define MUSB_TEST_FORCE_FS	0x20
 | 
				
			||||||
 | 
					#define MUSB_TEST_FORCE_HS	0x10
 | 
				
			||||||
 | 
					#define MUSB_TEST_PACKET	0x08
 | 
				
			||||||
 | 
					#define MUSB_TEST_K		0x04
 | 
				
			||||||
 | 
					#define MUSB_TEST_J		0x02
 | 
				
			||||||
 | 
					#define MUSB_TEST_SE0_NAK	0x01
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Allocate for double-packet buffering (effectively doubles assigned _SIZE) */
 | 
				
			||||||
 | 
					#define MUSB_FIFOSZ_DPB	0x10
 | 
				
			||||||
 | 
					/* Allocation size (8, 16, 32, ... 4096) */
 | 
				
			||||||
 | 
					#define MUSB_FIFOSZ_SIZE	0x0f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* CSR0 */
 | 
				
			||||||
 | 
					#define MUSB_CSR0_FLUSHFIFO	0x0100
 | 
				
			||||||
 | 
					#define MUSB_CSR0_TXPKTRDY	0x0002
 | 
				
			||||||
 | 
					#define MUSB_CSR0_RXPKTRDY	0x0001
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* CSR0 in Peripheral mode */
 | 
				
			||||||
 | 
					#define MUSB_CSR0_P_SVDSETUPEND	0x0080
 | 
				
			||||||
 | 
					#define MUSB_CSR0_P_SVDRXPKTRDY	0x0040
 | 
				
			||||||
 | 
					#define MUSB_CSR0_P_SENDSTALL	0x0020
 | 
				
			||||||
 | 
					#define MUSB_CSR0_P_SETUPEND	0x0010
 | 
				
			||||||
 | 
					#define MUSB_CSR0_P_DATAEND	0x0008
 | 
				
			||||||
 | 
					#define MUSB_CSR0_P_SENTSTALL	0x0004
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* CSR0 in Host mode */
 | 
				
			||||||
 | 
					#define MUSB_CSR0_H_DIS_PING		0x0800
 | 
				
			||||||
 | 
					#define MUSB_CSR0_H_WR_DATATOGGLE	0x0400	/* Set to allow setting: */
 | 
				
			||||||
 | 
					#define MUSB_CSR0_H_DATATOGGLE		0x0200	/* Data toggle control */
 | 
				
			||||||
 | 
					#define MUSB_CSR0_H_NAKTIMEOUT		0x0080
 | 
				
			||||||
 | 
					#define MUSB_CSR0_H_STATUSPKT		0x0040
 | 
				
			||||||
 | 
					#define MUSB_CSR0_H_REQPKT		0x0020
 | 
				
			||||||
 | 
					#define MUSB_CSR0_H_ERROR		0x0010
 | 
				
			||||||
 | 
					#define MUSB_CSR0_H_SETUPPKT		0x0008
 | 
				
			||||||
 | 
					#define MUSB_CSR0_H_RXSTALL		0x0004
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */
 | 
				
			||||||
 | 
					#define MUSB_CSR0_P_WZC_BITS	\
 | 
				
			||||||
 | 
						(MUSB_CSR0_P_SENTSTALL)
 | 
				
			||||||
 | 
					#define MUSB_CSR0_H_WZC_BITS	\
 | 
				
			||||||
 | 
						(MUSB_CSR0_H_NAKTIMEOUT | MUSB_CSR0_H_RXSTALL \
 | 
				
			||||||
 | 
						| MUSB_CSR0_RXPKTRDY)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* TxType/RxType */
 | 
				
			||||||
 | 
					#define MUSB_TYPE_SPEED		0xc0
 | 
				
			||||||
 | 
					#define MUSB_TYPE_SPEED_SHIFT	6
 | 
				
			||||||
 | 
					#define MUSB_TYPE_PROTO		0x30	/* Implicitly zero for ep0 */
 | 
				
			||||||
 | 
					#define MUSB_TYPE_PROTO_SHIFT	4
 | 
				
			||||||
 | 
					#define MUSB_TYPE_REMOTE_END	0xf	/* Implicitly zero for ep0 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* CONFIGDATA */
 | 
				
			||||||
 | 
					#define MUSB_CONFIGDATA_MPRXE		0x80	/* Auto bulk pkt combining */
 | 
				
			||||||
 | 
					#define MUSB_CONFIGDATA_MPTXE		0x40	/* Auto bulk pkt splitting */
 | 
				
			||||||
 | 
					#define MUSB_CONFIGDATA_BIGENDIAN	0x20
 | 
				
			||||||
 | 
					#define MUSB_CONFIGDATA_HBRXE		0x10	/* HB-ISO for RX */
 | 
				
			||||||
 | 
					#define MUSB_CONFIGDATA_HBTXE		0x08	/* HB-ISO for TX */
 | 
				
			||||||
 | 
					#define MUSB_CONFIGDATA_DYNFIFO		0x04	/* Dynamic FIFO sizing */
 | 
				
			||||||
 | 
					#define MUSB_CONFIGDATA_SOFTCONE	0x02	/* SoftConnect */
 | 
				
			||||||
 | 
					#define MUSB_CONFIGDATA_UTMIDW		0x01	/* Data width 0/1 => 8/16bits */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* TXCSR in Peripheral and Host mode */
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_AUTOSET		0x8000
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_MODE			0x2000
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_DMAENAB		0x1000
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_FRCDATATOG		0x0800
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_DMAMODE		0x0400
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_CLRDATATOG		0x0040
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_FLUSHFIFO		0x0008
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_FIFONOTEMPTY		0x0002
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_TXPKTRDY		0x0001
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* TXCSR in Peripheral mode */
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_P_ISO		0x4000
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_P_INCOMPTX		0x0080
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_P_SENTSTALL		0x0020
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_P_SENDSTALL		0x0010
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_P_UNDERRUN		0x0004
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* TXCSR in Host mode */
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_H_WR_DATATOGGLE	0x0200
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_H_DATATOGGLE		0x0100
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_H_NAKTIMEOUT		0x0080
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_H_RXSTALL		0x0020
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_H_ERROR		0x0004
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_P_WZC_BITS	\
 | 
				
			||||||
 | 
						(MUSB_TXCSR_P_INCOMPTX | MUSB_TXCSR_P_SENTSTALL \
 | 
				
			||||||
 | 
						| MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_FIFONOTEMPTY)
 | 
				
			||||||
 | 
					#define MUSB_TXCSR_H_WZC_BITS	\
 | 
				
			||||||
 | 
						(MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \
 | 
				
			||||||
 | 
						| MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* RXCSR in Peripheral and Host mode */
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_AUTOCLEAR		0x8000
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_DMAENAB		0x2000
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_DISNYET		0x1000
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_PID_ERR		0x1000
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_DMAMODE		0x0800
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_INCOMPRX		0x0100
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_CLRDATATOG		0x0080
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_FLUSHFIFO		0x0010
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_DATAERROR		0x0008
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_FIFOFULL		0x0002
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_RXPKTRDY		0x0001
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* RXCSR in Peripheral mode */
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_P_ISO		0x4000
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_P_SENTSTALL		0x0040
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_P_SENDSTALL		0x0020
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_P_OVERRUN		0x0004
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* RXCSR in Host mode */
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_H_AUTOREQ		0x4000
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_H_WR_DATATOGGLE	0x0400
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_H_DATATOGGLE		0x0200
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_H_RXSTALL		0x0040
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_H_REQPKT		0x0020
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_H_ERROR		0x0004
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_P_WZC_BITS	\
 | 
				
			||||||
 | 
						(MUSB_RXCSR_P_SENTSTALL | MUSB_RXCSR_P_OVERRUN \
 | 
				
			||||||
 | 
						| MUSB_RXCSR_RXPKTRDY)
 | 
				
			||||||
 | 
					#define MUSB_RXCSR_H_WZC_BITS	\
 | 
				
			||||||
 | 
						(MUSB_RXCSR_H_RXSTALL | MUSB_RXCSR_H_ERROR \
 | 
				
			||||||
 | 
						| MUSB_RXCSR_DATAERROR | MUSB_RXCSR_RXPKTRDY)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* HUBADDR */
 | 
				
			||||||
 | 
					#define MUSB_HUBADDR_MULTI_TT		0x80
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif	/* __MUSB_REGS_H__ */
 | 
				
			||||||
							
								
								
									
										425
									
								
								drivers/usb/musb/musb_virthub.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										425
									
								
								drivers/usb/musb/musb_virthub.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,425 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * MUSB OTG driver virtual root hub support
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2005 Mentor Graphics Corporation
 | 
				
			||||||
 | 
					 * Copyright (C) 2005-2006 by Texas Instruments
 | 
				
			||||||
 | 
					 * Copyright (C) 2006-2007 Nokia Corporation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 | 
				
			||||||
 | 
					 * 02110-1301 USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 | 
				
			||||||
 | 
					 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
				
			||||||
 | 
					 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
				
			||||||
 | 
					 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 | 
				
			||||||
 | 
					 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
				
			||||||
 | 
					 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
				
			||||||
 | 
					 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include <linux/sched.h>
 | 
				
			||||||
 | 
					#include <linux/slab.h>
 | 
				
			||||||
 | 
					#include <linux/errno.h>
 | 
				
			||||||
 | 
					#include <linux/init.h>
 | 
				
			||||||
 | 
					#include <linux/time.h>
 | 
				
			||||||
 | 
					#include <linux/timer.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <asm/unaligned.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "musb_core.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void musb_port_suspend(struct musb *musb, bool do_suspend)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8		power;
 | 
				
			||||||
 | 
						void __iomem	*mbase = musb->mregs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!is_host_active(musb))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* NOTE:  this doesn't necessarily put PHY into low power mode,
 | 
				
			||||||
 | 
						 * turning off its clock; that's a function of PHY integration and
 | 
				
			||||||
 | 
						 * MUSB_POWER_ENSUSPEND.  PHY may need a clock (sigh) to detect
 | 
				
			||||||
 | 
						 * SE0 changing to connect (J) or wakeup (K) states.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						power = musb_readb(mbase, MUSB_POWER);
 | 
				
			||||||
 | 
						if (do_suspend) {
 | 
				
			||||||
 | 
							int retries = 10000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							power &= ~MUSB_POWER_RESUME;
 | 
				
			||||||
 | 
							power |= MUSB_POWER_SUSPENDM;
 | 
				
			||||||
 | 
							musb_writeb(mbase, MUSB_POWER, power);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Needed for OPT A tests */
 | 
				
			||||||
 | 
							power = musb_readb(mbase, MUSB_POWER);
 | 
				
			||||||
 | 
							while (power & MUSB_POWER_SUSPENDM) {
 | 
				
			||||||
 | 
								power = musb_readb(mbase, MUSB_POWER);
 | 
				
			||||||
 | 
								if (retries-- < 1)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							DBG(3, "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_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_platform_try_idle(musb, 0);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								DBG(1, "bogus rh suspend? %s\n",
 | 
				
			||||||
 | 
									otg_state_string(musb));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* later, GetPortStatus will stop RESUME signaling */
 | 
				
			||||||
 | 
							musb->port1_status |= MUSB_PORT_STAT_RESUME;
 | 
				
			||||||
 | 
							musb->rh_timer = jiffies + msecs_to_jiffies(20);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static 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");
 | 
				
			||||||
 | 
							musb->port1_status &= ~USB_PORT_STAT_RESET;
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!is_host_active(musb))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* NOTE:  caller guarantees it will turn off the reset when
 | 
				
			||||||
 | 
						 * the appropriate amount of time has passed
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						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
 | 
				
			||||||
 | 
							 * generating SOFs. If we don't do this, OPT HS A 6.8 tests
 | 
				
			||||||
 | 
							 * fail with "Error! Did not receive an SOF before suspend
 | 
				
			||||||
 | 
							 * detected".
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (power &  MUSB_POWER_RESUME) {
 | 
				
			||||||
 | 
								while (time_before(jiffies, musb->rh_timer))
 | 
				
			||||||
 | 
									msleep(1);
 | 
				
			||||||
 | 
								musb_writeb(mbase, MUSB_POWER,
 | 
				
			||||||
 | 
									power & ~MUSB_POWER_RESUME);
 | 
				
			||||||
 | 
								msleep(1);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							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);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							DBG(4, "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");
 | 
				
			||||||
 | 
								musb->port1_status |= USB_PORT_STAT_HIGH_SPEED;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							musb->port1_status &= ~USB_PORT_STAT_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));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void musb_root_disconnect(struct musb *musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						musb->port1_status = (1 << USB_PORT_FEAT_POWER)
 | 
				
			||||||
 | 
								| (1 << USB_PORT_FEAT_C_CONNECTION);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usb_hcd_poll_rh_status(musb_to_hcd(musb));
 | 
				
			||||||
 | 
						musb->is_active = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (musb->xceiv.state) {
 | 
				
			||||||
 | 
						case OTG_STATE_A_HOST:
 | 
				
			||||||
 | 
						case OTG_STATE_A_SUSPEND:
 | 
				
			||||||
 | 
							musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
 | 
				
			||||||
 | 
							musb->is_active = 0;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case OTG_STATE_A_WAIT_VFALL:
 | 
				
			||||||
 | 
							musb->xceiv.state = OTG_STATE_B_IDLE;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							DBG(1, "host disconnect (%s)\n", otg_state_string(musb));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*---------------------------------------------------------------------*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Caller may or may not hold musb->lock */
 | 
				
			||||||
 | 
					int musb_hub_status_data(struct usb_hcd *hcd, char *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct musb	*musb = hcd_to_musb(hcd);
 | 
				
			||||||
 | 
						int		retval = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* called in_irq() via usb_hcd_poll_rh_status() */
 | 
				
			||||||
 | 
						if (musb->port1_status & 0xffff0000) {
 | 
				
			||||||
 | 
							*buf = 0x02;
 | 
				
			||||||
 | 
							retval = 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return retval;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int musb_hub_control(
 | 
				
			||||||
 | 
						struct usb_hcd	*hcd,
 | 
				
			||||||
 | 
						u16		typeReq,
 | 
				
			||||||
 | 
						u16		wValue,
 | 
				
			||||||
 | 
						u16		wIndex,
 | 
				
			||||||
 | 
						char		*buf,
 | 
				
			||||||
 | 
						u16		wLength)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct musb	*musb = hcd_to_musb(hcd);
 | 
				
			||||||
 | 
						u32		temp;
 | 
				
			||||||
 | 
						int		retval = 0;
 | 
				
			||||||
 | 
						unsigned long	flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_irqsave(&musb->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
 | 
				
			||||||
 | 
							spin_unlock_irqrestore(&musb->lock, flags);
 | 
				
			||||||
 | 
							return -ESHUTDOWN;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* hub features:  always zero, setting is a NOP
 | 
				
			||||||
 | 
						 * port features: reported, sometimes updated when host is active
 | 
				
			||||||
 | 
						 * no indicators
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						switch (typeReq) {
 | 
				
			||||||
 | 
						case ClearHubFeature:
 | 
				
			||||||
 | 
						case SetHubFeature:
 | 
				
			||||||
 | 
							switch (wValue) {
 | 
				
			||||||
 | 
							case C_HUB_OVER_CURRENT:
 | 
				
			||||||
 | 
							case C_HUB_LOCAL_POWER:
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ClearPortFeature:
 | 
				
			||||||
 | 
							if ((wIndex & 0xff) != 1)
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (wValue) {
 | 
				
			||||||
 | 
							case USB_PORT_FEAT_ENABLE:
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case USB_PORT_FEAT_SUSPEND:
 | 
				
			||||||
 | 
								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);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case USB_PORT_FEAT_C_CONNECTION:
 | 
				
			||||||
 | 
							case USB_PORT_FEAT_C_ENABLE:
 | 
				
			||||||
 | 
							case USB_PORT_FEAT_C_OVER_CURRENT:
 | 
				
			||||||
 | 
							case USB_PORT_FEAT_C_RESET:
 | 
				
			||||||
 | 
							case USB_PORT_FEAT_C_SUSPEND:
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							DBG(5, "clear feature %d\n", wValue);
 | 
				
			||||||
 | 
							musb->port1_status &= ~(1 << wValue);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case GetHubDescriptor:
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
							struct usb_hub_descriptor *desc = (void *)buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							desc->bDescLength = 9;
 | 
				
			||||||
 | 
							desc->bDescriptorType = 0x29;
 | 
				
			||||||
 | 
							desc->bNbrPorts = 1;
 | 
				
			||||||
 | 
							desc->wHubCharacteristics = __constant_cpu_to_le16(
 | 
				
			||||||
 | 
									  0x0001	/* per-port power switching */
 | 
				
			||||||
 | 
									| 0x0010	/* no overcurrent reporting */
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
							desc->bPwrOn2PwrGood = 5;	/* msec/2 */
 | 
				
			||||||
 | 
							desc->bHubContrCurrent = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* workaround bogus struct definition */
 | 
				
			||||||
 | 
							desc->DeviceRemovable[0] = 0x02;	/* port 1 */
 | 
				
			||||||
 | 
							desc->DeviceRemovable[1] = 0xff;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case GetHubStatus:
 | 
				
			||||||
 | 
							temp = 0;
 | 
				
			||||||
 | 
							*(__le32 *) buf = cpu_to_le32(temp);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case GetPortStatus:
 | 
				
			||||||
 | 
							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",
 | 
				
			||||||
 | 
									musb->port1_status);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SetPortFeature:
 | 
				
			||||||
 | 
							if ((wIndex & 0xff) != 1)
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (wValue) {
 | 
				
			||||||
 | 
							case USB_PORT_FEAT_POWER:
 | 
				
			||||||
 | 
								/* NOTE: this controller has a strange state machine
 | 
				
			||||||
 | 
								 * that involves "requesting sessions" according to
 | 
				
			||||||
 | 
								 * magic side effects from incompletely-described
 | 
				
			||||||
 | 
								 * rules about startup...
 | 
				
			||||||
 | 
								 *
 | 
				
			||||||
 | 
								 * This call is what really starts the host mode; be
 | 
				
			||||||
 | 
								 * very careful about side effects if you reorder any
 | 
				
			||||||
 | 
								 * 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))
 | 
				
			||||||
 | 
									musb_start(musb);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case USB_PORT_FEAT_RESET:
 | 
				
			||||||
 | 
								musb_port_reset(musb, true);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case USB_PORT_FEAT_SUSPEND:
 | 
				
			||||||
 | 
								musb_port_suspend(musb, true);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case USB_PORT_FEAT_TEST:
 | 
				
			||||||
 | 
								if (unlikely(is_host_active(musb)))
 | 
				
			||||||
 | 
									goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								wIndex >>= 8;
 | 
				
			||||||
 | 
								switch (wIndex) {
 | 
				
			||||||
 | 
								case 1:
 | 
				
			||||||
 | 
									pr_debug("TEST_J\n");
 | 
				
			||||||
 | 
									temp = MUSB_TEST_J;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case 2:
 | 
				
			||||||
 | 
									pr_debug("TEST_K\n");
 | 
				
			||||||
 | 
									temp = MUSB_TEST_K;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case 3:
 | 
				
			||||||
 | 
									pr_debug("TEST_SE0_NAK\n");
 | 
				
			||||||
 | 
									temp = MUSB_TEST_SE0_NAK;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case 4:
 | 
				
			||||||
 | 
									pr_debug("TEST_PACKET\n");
 | 
				
			||||||
 | 
									temp = MUSB_TEST_PACKET;
 | 
				
			||||||
 | 
									musb_load_testpacket(musb);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case 5:
 | 
				
			||||||
 | 
									pr_debug("TEST_FORCE_ENABLE\n");
 | 
				
			||||||
 | 
									temp = MUSB_TEST_FORCE_HOST
 | 
				
			||||||
 | 
										| MUSB_TEST_FORCE_HS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									musb_writeb(musb->mregs, MUSB_DEVCTL,
 | 
				
			||||||
 | 
											MUSB_DEVCTL_SESSION);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case 6:
 | 
				
			||||||
 | 
									pr_debug("TEST_FIFO_ACCESS\n");
 | 
				
			||||||
 | 
									temp = MUSB_TEST_FIFO_ACCESS;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									goto error;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								musb_writeb(musb->mregs, MUSB_TESTMODE, temp);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							DBG(5, "set feature %d\n", wValue);
 | 
				
			||||||
 | 
							musb->port1_status |= 1 << wValue;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
					error:
 | 
				
			||||||
 | 
							/* "protocol stall" on error */
 | 
				
			||||||
 | 
							retval = -EPIPE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						spin_unlock_irqrestore(&musb->lock, flags);
 | 
				
			||||||
 | 
						return retval;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										433
									
								
								drivers/usb/musb/musbhsdma.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										433
									
								
								drivers/usb/musb/musbhsdma.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,433 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * MUSB OTG driver - support for Mentor's DMA controller
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2005 Mentor Graphics Corporation
 | 
				
			||||||
 | 
					 * Copyright (C) 2005-2007 by Texas Instruments
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 | 
				
			||||||
 | 
					 * 02110-1301 USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 | 
				
			||||||
 | 
					 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
				
			||||||
 | 
					 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
				
			||||||
 | 
					 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 | 
				
			||||||
 | 
					 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
				
			||||||
 | 
					 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
				
			||||||
 | 
					 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#include <linux/device.h>
 | 
				
			||||||
 | 
					#include <linux/interrupt.h>
 | 
				
			||||||
 | 
					#include <linux/platform_device.h>
 | 
				
			||||||
 | 
					#include "musb_core.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
 | 
				
			||||||
 | 
					#include "omap2430.h"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MUSB_HSDMA_BASE		0x200
 | 
				
			||||||
 | 
					#define MUSB_HSDMA_INTR		(MUSB_HSDMA_BASE + 0)
 | 
				
			||||||
 | 
					#define MUSB_HSDMA_CONTROL		0x4
 | 
				
			||||||
 | 
					#define MUSB_HSDMA_ADDRESS		0x8
 | 
				
			||||||
 | 
					#define MUSB_HSDMA_COUNT		0xc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MUSB_HSDMA_CHANNEL_OFFSET(_bChannel, _offset)		\
 | 
				
			||||||
 | 
							(MUSB_HSDMA_BASE + (_bChannel << 4) + _offset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* control register (16-bit): */
 | 
				
			||||||
 | 
					#define MUSB_HSDMA_ENABLE_SHIFT		0
 | 
				
			||||||
 | 
					#define MUSB_HSDMA_TRANSMIT_SHIFT		1
 | 
				
			||||||
 | 
					#define MUSB_HSDMA_MODE1_SHIFT		2
 | 
				
			||||||
 | 
					#define MUSB_HSDMA_IRQENABLE_SHIFT		3
 | 
				
			||||||
 | 
					#define MUSB_HSDMA_ENDPOINT_SHIFT		4
 | 
				
			||||||
 | 
					#define MUSB_HSDMA_BUSERROR_SHIFT		8
 | 
				
			||||||
 | 
					#define MUSB_HSDMA_BURSTMODE_SHIFT		9
 | 
				
			||||||
 | 
					#define MUSB_HSDMA_BURSTMODE		(3 << MUSB_HSDMA_BURSTMODE_SHIFT)
 | 
				
			||||||
 | 
					#define MUSB_HSDMA_BURSTMODE_UNSPEC	0
 | 
				
			||||||
 | 
					#define MUSB_HSDMA_BURSTMODE_INCR4	1
 | 
				
			||||||
 | 
					#define MUSB_HSDMA_BURSTMODE_INCR8	2
 | 
				
			||||||
 | 
					#define MUSB_HSDMA_BURSTMODE_INCR16	3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MUSB_HSDMA_CHANNELS		8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct musb_dma_controller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct musb_dma_channel {
 | 
				
			||||||
 | 
						struct dma_channel		Channel;
 | 
				
			||||||
 | 
						struct musb_dma_controller	*controller;
 | 
				
			||||||
 | 
						u32				dwStartAddress;
 | 
				
			||||||
 | 
						u32				len;
 | 
				
			||||||
 | 
						u16				wMaxPacketSize;
 | 
				
			||||||
 | 
						u8				bIndex;
 | 
				
			||||||
 | 
						u8				epnum;
 | 
				
			||||||
 | 
						u8				transmit;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct musb_dma_controller {
 | 
				
			||||||
 | 
						struct dma_controller		Controller;
 | 
				
			||||||
 | 
						struct musb_dma_channel		aChannel[MUSB_HSDMA_CHANNELS];
 | 
				
			||||||
 | 
						void				*pDmaPrivate;
 | 
				
			||||||
 | 
						void __iomem			*pCoreBase;
 | 
				
			||||||
 | 
						u8				bChannelCount;
 | 
				
			||||||
 | 
						u8				bmUsedChannels;
 | 
				
			||||||
 | 
						u8				irq;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int dma_controller_start(struct dma_controller *c)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* nothing to do */
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void dma_channel_release(struct dma_channel *pChannel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int dma_controller_stop(struct dma_controller *c)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct musb_dma_controller *controller =
 | 
				
			||||||
 | 
							container_of(c, struct musb_dma_controller, Controller);
 | 
				
			||||||
 | 
						struct musb *musb = (struct musb *) controller->pDmaPrivate;
 | 
				
			||||||
 | 
						struct dma_channel *pChannel;
 | 
				
			||||||
 | 
						u8 bBit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (controller->bmUsedChannels != 0) {
 | 
				
			||||||
 | 
							dev_err(musb->controller,
 | 
				
			||||||
 | 
								"Stopping DMA controller while channel active\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (bBit = 0; bBit < MUSB_HSDMA_CHANNELS; bBit++) {
 | 
				
			||||||
 | 
								if (controller->bmUsedChannels & (1 << bBit)) {
 | 
				
			||||||
 | 
									pChannel = &controller->aChannel[bBit].Channel;
 | 
				
			||||||
 | 
									dma_channel_release(pChannel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (!controller->bmUsedChannels)
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct dma_channel *dma_channel_allocate(struct dma_controller *c,
 | 
				
			||||||
 | 
									struct musb_hw_ep *hw_ep, u8 transmit)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8 bBit;
 | 
				
			||||||
 | 
						struct dma_channel *pChannel = NULL;
 | 
				
			||||||
 | 
						struct musb_dma_channel *pImplChannel = NULL;
 | 
				
			||||||
 | 
						struct musb_dma_controller *controller =
 | 
				
			||||||
 | 
								container_of(c, struct musb_dma_controller, Controller);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (bBit = 0; bBit < MUSB_HSDMA_CHANNELS; bBit++) {
 | 
				
			||||||
 | 
							if (!(controller->bmUsedChannels & (1 << bBit))) {
 | 
				
			||||||
 | 
								controller->bmUsedChannels |= (1 << bBit);
 | 
				
			||||||
 | 
								pImplChannel = &(controller->aChannel[bBit]);
 | 
				
			||||||
 | 
								pImplChannel->controller = controller;
 | 
				
			||||||
 | 
								pImplChannel->bIndex = bBit;
 | 
				
			||||||
 | 
								pImplChannel->epnum = hw_ep->epnum;
 | 
				
			||||||
 | 
								pImplChannel->transmit = transmit;
 | 
				
			||||||
 | 
								pChannel = &(pImplChannel->Channel);
 | 
				
			||||||
 | 
								pChannel->private_data = pImplChannel;
 | 
				
			||||||
 | 
								pChannel->status = MUSB_DMA_STATUS_FREE;
 | 
				
			||||||
 | 
								pChannel->max_len = 0x10000;
 | 
				
			||||||
 | 
								/* Tx => mode 1; Rx => mode 0 */
 | 
				
			||||||
 | 
								pChannel->desired_mode = transmit;
 | 
				
			||||||
 | 
								pChannel->actual_len = 0;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return pChannel;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void dma_channel_release(struct dma_channel *pChannel)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct musb_dma_channel *pImplChannel =
 | 
				
			||||||
 | 
							(struct musb_dma_channel *) pChannel->private_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pChannel->actual_len = 0;
 | 
				
			||||||
 | 
						pImplChannel->dwStartAddress = 0;
 | 
				
			||||||
 | 
						pImplChannel->len = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pImplChannel->controller->bmUsedChannels &=
 | 
				
			||||||
 | 
							~(1 << pImplChannel->bIndex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pChannel->status = MUSB_DMA_STATUS_UNKNOWN;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void configure_channel(struct dma_channel *pChannel,
 | 
				
			||||||
 | 
									u16 packet_sz, u8 mode,
 | 
				
			||||||
 | 
									dma_addr_t dma_addr, u32 len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct musb_dma_channel *pImplChannel =
 | 
				
			||||||
 | 
							(struct musb_dma_channel *) pChannel->private_data;
 | 
				
			||||||
 | 
						struct musb_dma_controller *controller = pImplChannel->controller;
 | 
				
			||||||
 | 
						void __iomem *mbase = controller->pCoreBase;
 | 
				
			||||||
 | 
						u8 bChannel = pImplChannel->bIndex;
 | 
				
			||||||
 | 
						u16 csr = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DBG(4, "%p, pkt_sz %d, addr 0x%x, len %d, mode %d\n",
 | 
				
			||||||
 | 
								pChannel, packet_sz, dma_addr, len, mode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mode) {
 | 
				
			||||||
 | 
							csr |= 1 << MUSB_HSDMA_MODE1_SHIFT;
 | 
				
			||||||
 | 
							BUG_ON(len < packet_sz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (packet_sz >= 64) {
 | 
				
			||||||
 | 
								csr |= MUSB_HSDMA_BURSTMODE_INCR16
 | 
				
			||||||
 | 
										<< MUSB_HSDMA_BURSTMODE_SHIFT;
 | 
				
			||||||
 | 
							} else if (packet_sz >= 32) {
 | 
				
			||||||
 | 
								csr |= MUSB_HSDMA_BURSTMODE_INCR8
 | 
				
			||||||
 | 
										<< MUSB_HSDMA_BURSTMODE_SHIFT;
 | 
				
			||||||
 | 
							} else if (packet_sz >= 16) {
 | 
				
			||||||
 | 
								csr |= MUSB_HSDMA_BURSTMODE_INCR4
 | 
				
			||||||
 | 
										<< MUSB_HSDMA_BURSTMODE_SHIFT;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						csr |= (pImplChannel->epnum << MUSB_HSDMA_ENDPOINT_SHIFT)
 | 
				
			||||||
 | 
							| (1 << MUSB_HSDMA_ENABLE_SHIFT)
 | 
				
			||||||
 | 
							| (1 << MUSB_HSDMA_IRQENABLE_SHIFT)
 | 
				
			||||||
 | 
							| (pImplChannel->transmit
 | 
				
			||||||
 | 
									? (1 << MUSB_HSDMA_TRANSMIT_SHIFT)
 | 
				
			||||||
 | 
									: 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* address/count */
 | 
				
			||||||
 | 
						musb_writel(mbase,
 | 
				
			||||||
 | 
							MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_ADDRESS),
 | 
				
			||||||
 | 
							dma_addr);
 | 
				
			||||||
 | 
						musb_writel(mbase,
 | 
				
			||||||
 | 
							MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_COUNT),
 | 
				
			||||||
 | 
							len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* control (this should start things) */
 | 
				
			||||||
 | 
						musb_writew(mbase,
 | 
				
			||||||
 | 
							MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_CONTROL),
 | 
				
			||||||
 | 
							csr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int dma_channel_program(struct dma_channel *pChannel,
 | 
				
			||||||
 | 
									u16 packet_sz, u8 mode,
 | 
				
			||||||
 | 
									dma_addr_t dma_addr, u32 len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct musb_dma_channel *pImplChannel =
 | 
				
			||||||
 | 
								(struct musb_dma_channel *) pChannel->private_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DBG(2, "ep%d-%s pkt_sz %d, dma_addr 0x%x length %d, mode %d\n",
 | 
				
			||||||
 | 
							pImplChannel->epnum,
 | 
				
			||||||
 | 
							pImplChannel->transmit ? "Tx" : "Rx",
 | 
				
			||||||
 | 
							packet_sz, dma_addr, len, mode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BUG_ON(pChannel->status == MUSB_DMA_STATUS_UNKNOWN ||
 | 
				
			||||||
 | 
							pChannel->status == MUSB_DMA_STATUS_BUSY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pChannel->actual_len = 0;
 | 
				
			||||||
 | 
						pImplChannel->dwStartAddress = dma_addr;
 | 
				
			||||||
 | 
						pImplChannel->len = len;
 | 
				
			||||||
 | 
						pImplChannel->wMaxPacketSize = packet_sz;
 | 
				
			||||||
 | 
						pChannel->status = MUSB_DMA_STATUS_BUSY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((mode == 1) && (len >= packet_sz))
 | 
				
			||||||
 | 
							configure_channel(pChannel, packet_sz, 1, dma_addr, len);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							configure_channel(pChannel, packet_sz, 0, dma_addr, len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int dma_channel_abort(struct dma_channel *pChannel)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct musb_dma_channel *pImplChannel =
 | 
				
			||||||
 | 
							(struct musb_dma_channel *) pChannel->private_data;
 | 
				
			||||||
 | 
						u8 bChannel = pImplChannel->bIndex;
 | 
				
			||||||
 | 
						void __iomem *mbase = pImplChannel->controller->pCoreBase;
 | 
				
			||||||
 | 
						u16 csr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pChannel->status == MUSB_DMA_STATUS_BUSY) {
 | 
				
			||||||
 | 
							if (pImplChannel->transmit) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								csr = musb_readw(mbase,
 | 
				
			||||||
 | 
									MUSB_EP_OFFSET(pImplChannel->epnum,
 | 
				
			||||||
 | 
											MUSB_TXCSR));
 | 
				
			||||||
 | 
								csr &= ~(MUSB_TXCSR_AUTOSET |
 | 
				
			||||||
 | 
									 MUSB_TXCSR_DMAENAB |
 | 
				
			||||||
 | 
									 MUSB_TXCSR_DMAMODE);
 | 
				
			||||||
 | 
								musb_writew(mbase,
 | 
				
			||||||
 | 
									MUSB_EP_OFFSET(pImplChannel->epnum,
 | 
				
			||||||
 | 
											MUSB_TXCSR),
 | 
				
			||||||
 | 
									csr);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								csr = musb_readw(mbase,
 | 
				
			||||||
 | 
									MUSB_EP_OFFSET(pImplChannel->epnum,
 | 
				
			||||||
 | 
											MUSB_RXCSR));
 | 
				
			||||||
 | 
								csr &= ~(MUSB_RXCSR_AUTOCLEAR |
 | 
				
			||||||
 | 
									 MUSB_RXCSR_DMAENAB |
 | 
				
			||||||
 | 
									 MUSB_RXCSR_DMAMODE);
 | 
				
			||||||
 | 
								musb_writew(mbase,
 | 
				
			||||||
 | 
									MUSB_EP_OFFSET(pImplChannel->epnum,
 | 
				
			||||||
 | 
											MUSB_RXCSR),
 | 
				
			||||||
 | 
									csr);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							musb_writew(mbase,
 | 
				
			||||||
 | 
								MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_CONTROL),
 | 
				
			||||||
 | 
								0);
 | 
				
			||||||
 | 
							musb_writel(mbase,
 | 
				
			||||||
 | 
								MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_ADDRESS),
 | 
				
			||||||
 | 
								0);
 | 
				
			||||||
 | 
							musb_writel(mbase,
 | 
				
			||||||
 | 
								MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_COUNT),
 | 
				
			||||||
 | 
								0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pChannel->status = MUSB_DMA_STATUS_FREE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static irqreturn_t dma_controller_irq(int irq, void *private_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct musb_dma_controller *controller =
 | 
				
			||||||
 | 
							(struct musb_dma_controller *)private_data;
 | 
				
			||||||
 | 
						struct musb_dma_channel *pImplChannel;
 | 
				
			||||||
 | 
						struct musb *musb = controller->pDmaPrivate;
 | 
				
			||||||
 | 
						void __iomem *mbase = controller->pCoreBase;
 | 
				
			||||||
 | 
						struct dma_channel *pChannel;
 | 
				
			||||||
 | 
						u8 bChannel;
 | 
				
			||||||
 | 
						u16 csr;
 | 
				
			||||||
 | 
						u32 dwAddress;
 | 
				
			||||||
 | 
						u8 int_hsdma;
 | 
				
			||||||
 | 
						irqreturn_t retval = IRQ_NONE;
 | 
				
			||||||
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_irqsave(&musb->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int_hsdma = musb_readb(mbase, MUSB_HSDMA_INTR);
 | 
				
			||||||
 | 
						if (!int_hsdma)
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (bChannel = 0; bChannel < MUSB_HSDMA_CHANNELS; bChannel++) {
 | 
				
			||||||
 | 
							if (int_hsdma & (1 << bChannel)) {
 | 
				
			||||||
 | 
								pImplChannel = (struct musb_dma_channel *)
 | 
				
			||||||
 | 
										&(controller->aChannel[bChannel]);
 | 
				
			||||||
 | 
								pChannel = &pImplChannel->Channel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								csr = musb_readw(mbase,
 | 
				
			||||||
 | 
										MUSB_HSDMA_CHANNEL_OFFSET(bChannel,
 | 
				
			||||||
 | 
												MUSB_HSDMA_CONTROL));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (csr & (1 << MUSB_HSDMA_BUSERROR_SHIFT))
 | 
				
			||||||
 | 
									pImplChannel->Channel.status =
 | 
				
			||||||
 | 
										MUSB_DMA_STATUS_BUS_ABORT;
 | 
				
			||||||
 | 
								else {
 | 
				
			||||||
 | 
									u8 devctl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									dwAddress = musb_readl(mbase,
 | 
				
			||||||
 | 
											MUSB_HSDMA_CHANNEL_OFFSET(
 | 
				
			||||||
 | 
												bChannel,
 | 
				
			||||||
 | 
												MUSB_HSDMA_ADDRESS));
 | 
				
			||||||
 | 
									pChannel->actual_len = dwAddress
 | 
				
			||||||
 | 
										- pImplChannel->dwStartAddress;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									DBG(2, "ch %p, 0x%x -> 0x%x (%d / %d) %s\n",
 | 
				
			||||||
 | 
										pChannel, pImplChannel->dwStartAddress,
 | 
				
			||||||
 | 
										dwAddress, pChannel->actual_len,
 | 
				
			||||||
 | 
										pImplChannel->len,
 | 
				
			||||||
 | 
										(pChannel->actual_len
 | 
				
			||||||
 | 
											< pImplChannel->len) ?
 | 
				
			||||||
 | 
										"=> reconfig 0" : "=> complete");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									devctl = musb_readb(mbase, MUSB_DEVCTL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									pChannel->status = MUSB_DMA_STATUS_FREE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/* completed */
 | 
				
			||||||
 | 
									if ((devctl & MUSB_DEVCTL_HM)
 | 
				
			||||||
 | 
										&& (pImplChannel->transmit)
 | 
				
			||||||
 | 
										&& ((pChannel->desired_mode == 0)
 | 
				
			||||||
 | 
										    || (pChannel->actual_len &
 | 
				
			||||||
 | 
										    (pImplChannel->wMaxPacketSize - 1)))
 | 
				
			||||||
 | 
										 ) {
 | 
				
			||||||
 | 
										/* Send out the packet */
 | 
				
			||||||
 | 
										musb_ep_select(mbase,
 | 
				
			||||||
 | 
											pImplChannel->epnum);
 | 
				
			||||||
 | 
										musb_writew(mbase, MUSB_EP_OFFSET(
 | 
				
			||||||
 | 
												pImplChannel->epnum,
 | 
				
			||||||
 | 
												MUSB_TXCSR),
 | 
				
			||||||
 | 
											MUSB_TXCSR_TXPKTRDY);
 | 
				
			||||||
 | 
									} else
 | 
				
			||||||
 | 
										musb_dma_completion(
 | 
				
			||||||
 | 
											musb,
 | 
				
			||||||
 | 
											pImplChannel->epnum,
 | 
				
			||||||
 | 
											pImplChannel->transmit);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						retval = IRQ_HANDLED;
 | 
				
			||||||
 | 
					done:
 | 
				
			||||||
 | 
						spin_unlock_irqrestore(&musb->lock, flags);
 | 
				
			||||||
 | 
						return retval;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void dma_controller_destroy(struct dma_controller *c)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct musb_dma_controller *controller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						controller = container_of(c, struct musb_dma_controller, Controller);
 | 
				
			||||||
 | 
						if (!controller)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (controller->irq)
 | 
				
			||||||
 | 
							free_irq(controller->irq, c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kfree(controller);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct dma_controller *__init
 | 
				
			||||||
 | 
					dma_controller_create(struct musb *musb, void __iomem *pCoreBase)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (irq == 0) {
 | 
				
			||||||
 | 
							dev_err(dev, "No DMA interrupt line!\n");
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						controller = kzalloc(sizeof(struct musb_dma_controller), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!controller)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						controller->bChannelCount = MUSB_HSDMA_CHANNELS;
 | 
				
			||||||
 | 
						controller->pDmaPrivate = musb;
 | 
				
			||||||
 | 
						controller->pCoreBase = pCoreBase;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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,
 | 
				
			||||||
 | 
								musb->controller->bus_id, &controller->Controller)) {
 | 
				
			||||||
 | 
							dev_err(dev, "request_irq %d failed!\n", irq);
 | 
				
			||||||
 | 
							dma_controller_destroy(&controller->Controller);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						controller->irq = irq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &controller->Controller;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										324
									
								
								drivers/usb/musb/omap2430.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										324
									
								
								drivers/usb/musb/omap2430.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,324 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2005-2007 by Texas Instruments
 | 
				
			||||||
 | 
					 * Some code has been taken from tusb6010.c
 | 
				
			||||||
 | 
					 * Copyrights for that are attributable to:
 | 
				
			||||||
 | 
					 * Copyright (C) 2006 Nokia Corporation
 | 
				
			||||||
 | 
					 * Jarkko Nikula <jarkko.nikula@nokia.com>
 | 
				
			||||||
 | 
					 * Tony Lindgren <tony@atomide.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This file is part of the Inventra Controller Driver for Linux.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Inventra Controller Driver for Linux is free software; you
 | 
				
			||||||
 | 
					 * can redistribute it and/or modify it under the terms of the GNU
 | 
				
			||||||
 | 
					 * General Public License version 2 as published by the Free Software
 | 
				
			||||||
 | 
					 * Foundation.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Inventra Controller Driver for Linux is distributed in
 | 
				
			||||||
 | 
					 * the hope that it will be useful, but WITHOUT ANY WARRANTY;
 | 
				
			||||||
 | 
					 * without even the implied warranty of MERCHANTABILITY or
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 | 
				
			||||||
 | 
					 * License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 * along with The Inventra Controller Driver for Linux ; if not,
 | 
				
			||||||
 | 
					 * write to the Free Software Foundation, Inc., 59 Temple Place,
 | 
				
			||||||
 | 
					 * Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include <linux/sched.h>
 | 
				
			||||||
 | 
					#include <linux/slab.h>
 | 
				
			||||||
 | 
					#include <linux/init.h>
 | 
				
			||||||
 | 
					#include <linux/list.h>
 | 
				
			||||||
 | 
					#include <linux/clk.h>
 | 
				
			||||||
 | 
					#include <linux/io.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <asm/mach-types.h>
 | 
				
			||||||
 | 
					#include <asm/arch/hardware.h>
 | 
				
			||||||
 | 
					#include <asm/arch/mux.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "musb_core.h"
 | 
				
			||||||
 | 
					#include "omap2430.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_ARCH_OMAP3430
 | 
				
			||||||
 | 
					#define	get_cpu_rev()	2
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MUSB_TIMEOUT_A_WAIT_BCON	1100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct timer_list musb_idle_timer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void musb_do_idle(unsigned long _musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct musb	*musb = (void *)_musb;
 | 
				
			||||||
 | 
						unsigned long	flags;
 | 
				
			||||||
 | 
						u8	power;
 | 
				
			||||||
 | 
						u8	devctl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_irqsave(&musb->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (musb->xceiv.state) {
 | 
				
			||||||
 | 
						case OTG_STATE_A_WAIT_BCON:
 | 
				
			||||||
 | 
							devctl &= ~MUSB_DEVCTL_SESSION;
 | 
				
			||||||
 | 
							musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
 | 
				
			||||||
 | 
							if (devctl & MUSB_DEVCTL_BDEVICE) {
 | 
				
			||||||
 | 
								musb->xceiv.state = OTG_STATE_B_IDLE;
 | 
				
			||||||
 | 
								MUSB_DEV_MODE(musb);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								musb->xceiv.state = OTG_STATE_A_IDLE;
 | 
				
			||||||
 | 
								MUSB_HST_MODE(musb);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					#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);
 | 
				
			||||||
 | 
								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));
 | 
				
			||||||
 | 
								/* 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;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						spin_unlock_irqrestore(&musb->lock, flags);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned long		default_timeout = jiffies + msecs_to_jiffies(3);
 | 
				
			||||||
 | 
						static unsigned long	last_timer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (timeout == 0)
 | 
				
			||||||
 | 
							timeout = default_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));
 | 
				
			||||||
 | 
							del_timer(&musb_idle_timer);
 | 
				
			||||||
 | 
							last_timer = jiffies;
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (time_after(last_timer, timeout)) {
 | 
				
			||||||
 | 
							if (!timer_pending(&musb_idle_timer))
 | 
				
			||||||
 | 
								last_timer = timeout;
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								DBG(4, "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),
 | 
				
			||||||
 | 
							(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_vbus_power(struct musb *musb, int is_on, int sleeping)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void omap_set_vbus(struct musb *musb, int is_on)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8		devctl;
 | 
				
			||||||
 | 
						/* 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) {
 | 
				
			||||||
 | 
							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);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							musb->is_active = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* NOTE:  we're skipping A_WAIT_VFALL -> A_IDLE and
 | 
				
			||||||
 | 
							 * jumping right to B_IDLE...
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							musb->xceiv.default_a = 0;
 | 
				
			||||||
 | 
							musb->xceiv.state = OTG_STATE_B_IDLE;
 | 
				
			||||||
 | 
							devctl &= ~MUSB_DEVCTL_SESSION;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							MUSB_DEV_MODE(musb);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DBG(1, "VBUS %s, devctl %02x "
 | 
				
			||||||
 | 
							/* otg %3x conf %08x prcm %08x */ "\n",
 | 
				
			||||||
 | 
							otg_state_string(musb),
 | 
				
			||||||
 | 
							musb_readb(musb->mregs, MUSB_DEVCTL));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static int omap_set_power(struct otg_transceiver *x, unsigned mA)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int musb_platform_resume(struct musb *musb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8	devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						devctl |= MUSB_DEVCTL_SESSION;
 | 
				
			||||||
 | 
						musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (musb_mode) {
 | 
				
			||||||
 | 
						case MUSB_HOST:
 | 
				
			||||||
 | 
							otg_set_host(&musb->xceiv, musb->xceiv.host);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case MUSB_PERIPHERAL:
 | 
				
			||||||
 | 
							otg_set_peripheral(&musb->xceiv, musb->xceiv.gadget);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case MUSB_OTG:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int __init musb_platform_init(struct musb *musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u32 l;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(CONFIG_ARCH_OMAP2430)
 | 
				
			||||||
 | 
						omap_cfg_reg(AE5_2430_USB0HS_STP);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						musb_platform_resume(musb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						l = omap_readl(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 */
 | 
				
			||||||
 | 
						l |= AUTOIDLE;		/* enable auto idle */
 | 
				
			||||||
 | 
						omap_writel(l, OTG_SYSCONFIG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						l = omap_readl(OTG_INTERFSEL);
 | 
				
			||||||
 | 
						l |= ULPI_12PIN;
 | 
				
			||||||
 | 
						omap_writel(l, OTG_INTERFSEL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
 | 
				
			||||||
 | 
								"sysstatus 0x%x, intrfsel 0x%x, simenable  0x%x\n",
 | 
				
			||||||
 | 
								omap_readl(OTG_REVISION), omap_readl(OTG_SYSCONFIG),
 | 
				
			||||||
 | 
								omap_readl(OTG_SYSSTATUS), omap_readl(OTG_INTERFSEL),
 | 
				
			||||||
 | 
								omap_readl(OTG_SIMENABLE));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						omap_vbus_power(musb, musb->board_mode == MUSB_HOST, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (is_host_enabled(musb))
 | 
				
			||||||
 | 
							musb->board_set_vbus = omap_set_vbus;
 | 
				
			||||||
 | 
						if (is_peripheral_enabled(musb))
 | 
				
			||||||
 | 
							musb->xceiv.set_power = omap_set_power;
 | 
				
			||||||
 | 
						musb->a_wait_bcon = MUSB_TIMEOUT_A_WAIT_BCON;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int musb_platform_suspend(struct musb *musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u32 l;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!musb->clock)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* in any role */
 | 
				
			||||||
 | 
						l = omap_readl(OTG_FORCESTDBY);
 | 
				
			||||||
 | 
						l |= ENABLEFORCE;	/* enable MSTANDBY */
 | 
				
			||||||
 | 
						omap_writel(l, OTG_FORCESTDBY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						l = omap_readl(OTG_SYSCONFIG);
 | 
				
			||||||
 | 
						l |= ENABLEWAKEUP;	/* enable wakeup */
 | 
				
			||||||
 | 
						omap_writel(l, OTG_SYSCONFIG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (musb->xceiv.set_suspend)
 | 
				
			||||||
 | 
							musb->xceiv.set_suspend(&musb->xceiv, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (musb->set_clock)
 | 
				
			||||||
 | 
							musb->set_clock(musb->clock, 0);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							clk_disable(musb->clock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int musb_platform_resume(struct musb *musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u32 l;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!musb->clock)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (musb->xceiv.set_suspend)
 | 
				
			||||||
 | 
							musb->xceiv.set_suspend(&musb->xceiv, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (musb->set_clock)
 | 
				
			||||||
 | 
							musb->set_clock(musb->clock, 1);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							clk_enable(musb->clock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						l = omap_readl(OTG_SYSCONFIG);
 | 
				
			||||||
 | 
						l &= ~ENABLEWAKEUP;	/* disable wakeup */
 | 
				
			||||||
 | 
						omap_writel(l, OTG_SYSCONFIG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						l = omap_readl(OTG_FORCESTDBY);
 | 
				
			||||||
 | 
						l &= ~ENABLEFORCE;	/* disable MSTANDBY */
 | 
				
			||||||
 | 
						omap_writel(l, OTG_FORCESTDBY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int musb_platform_exit(struct musb *musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						omap_vbus_power(musb, 0 /*off*/, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						musb_platform_suspend(musb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						clk_put(musb->clock);
 | 
				
			||||||
 | 
						musb->clock = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										56
									
								
								drivers/usb/musb/omap2430.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								drivers/usb/musb/omap2430.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,56 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2005-2006 by Texas Instruments
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __MUSB_OMAP243X_H__
 | 
				
			||||||
 | 
					#define __MUSB_OMAP243X_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
 | 
				
			||||||
 | 
					#include <asm/arch/hardware.h>
 | 
				
			||||||
 | 
					#include <asm/arch/usb.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * OMAP2430-specific definitions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MENTOR_BASE_OFFSET	0
 | 
				
			||||||
 | 
					#if	defined(CONFIG_ARCH_OMAP2430)
 | 
				
			||||||
 | 
					#define	OMAP_HSOTG_BASE		(OMAP243X_HS_BASE)
 | 
				
			||||||
 | 
					#elif	defined(CONFIG_ARCH_OMAP3430)
 | 
				
			||||||
 | 
					#define	OMAP_HSOTG_BASE		(OMAP34XX_HSUSB_OTG_BASE)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#define OMAP_HSOTG(offset)	(OMAP_HSOTG_BASE + 0x400 + (offset))
 | 
				
			||||||
 | 
					#define OTG_REVISION		OMAP_HSOTG(0x0)
 | 
				
			||||||
 | 
					#define OTG_SYSCONFIG		OMAP_HSOTG(0x4)
 | 
				
			||||||
 | 
					#	define	MIDLEMODE	12	/* bit position */
 | 
				
			||||||
 | 
					#	define	FORCESTDBY		(0 << MIDLEMODE)
 | 
				
			||||||
 | 
					#	define	NOSTDBY			(1 << MIDLEMODE)
 | 
				
			||||||
 | 
					#	define	SMARTSTDBY		(2 << MIDLEMODE)
 | 
				
			||||||
 | 
					#	define	SIDLEMODE		3	/* bit position */
 | 
				
			||||||
 | 
					#	define	FORCEIDLE		(0 << SIDLEMODE)
 | 
				
			||||||
 | 
					#	define	NOIDLE			(1 << SIDLEMODE)
 | 
				
			||||||
 | 
					#	define	SMARTIDLE		(2 << SIDLEMODE)
 | 
				
			||||||
 | 
					#	define	ENABLEWAKEUP		(1 << 2)
 | 
				
			||||||
 | 
					#	define	SOFTRST			(1 << 1)
 | 
				
			||||||
 | 
					#	define	AUTOIDLE		(1 << 0)
 | 
				
			||||||
 | 
					#define OTG_SYSSTATUS		OMAP_HSOTG(0x8)
 | 
				
			||||||
 | 
					#	define	RESETDONE		(1 << 0)
 | 
				
			||||||
 | 
					#define OTG_INTERFSEL		OMAP_HSOTG(0xc)
 | 
				
			||||||
 | 
					#	define	EXTCP			(1 << 2)
 | 
				
			||||||
 | 
					#	define	PHYSEL		0	/* bit position */
 | 
				
			||||||
 | 
					#	define	UTMI_8BIT		(0 << PHYSEL)
 | 
				
			||||||
 | 
					#	define	ULPI_12PIN		(1 << PHYSEL)
 | 
				
			||||||
 | 
					#	define	ULPI_8PIN		(2 << PHYSEL)
 | 
				
			||||||
 | 
					#define OTG_SIMENABLE		OMAP_HSOTG(0x10)
 | 
				
			||||||
 | 
					#	define	TM1			(1 << 0)
 | 
				
			||||||
 | 
					#define OTG_FORCESTDBY		OMAP_HSOTG(0x14)
 | 
				
			||||||
 | 
					#	define	ENABLEFORCE		(1 << 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif	/* CONFIG_ARCH_OMAP2430 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif	/* __MUSB_OMAP243X_H__ */
 | 
				
			||||||
							
								
								
									
										1151
									
								
								drivers/usb/musb/tusb6010.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1151
									
								
								drivers/usb/musb/tusb6010.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										402
									
								
								drivers/usb/musb/tusb6010.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										402
									
								
								drivers/usb/musb/tusb6010.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,402 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Definitions for TUSB6010 USB 2.0 OTG Dual Role controller
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2006 Nokia Corporation
 | 
				
			||||||
 | 
					 * Jarkko Nikula <jarkko.nikula@nokia.com>
 | 
				
			||||||
 | 
					 * Tony Lindgren <tony@atomide.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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
 | 
				
			||||||
 | 
					#define tusb_dma_omap()			0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* VLYNQ control register. 32-bit at offset 0x000 */
 | 
				
			||||||
 | 
					#define TUSB_VLYNQ_CTRL			0x004
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Mentor Graphics OTG core registers. 8,- 16- and 32-bit at offset 0x400 */
 | 
				
			||||||
 | 
					#define TUSB_BASE_OFFSET		0x400
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* FIFO registers 32-bit at offset 0x600 */
 | 
				
			||||||
 | 
					#define TUSB_FIFO_BASE			0x600
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Device System & Control registers. 32-bit at offset 0x800 */
 | 
				
			||||||
 | 
					#define TUSB_SYS_REG_BASE		0x800
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TUSB_DEV_CONF			(TUSB_SYS_REG_BASE + 0x000)
 | 
				
			||||||
 | 
					#define		TUSB_DEV_CONF_USB_HOST_MODE		(1 << 16)
 | 
				
			||||||
 | 
					#define		TUSB_DEV_CONF_PROD_TEST_MODE		(1 << 15)
 | 
				
			||||||
 | 
					#define		TUSB_DEV_CONF_SOFT_ID			(1 << 1)
 | 
				
			||||||
 | 
					#define		TUSB_DEV_CONF_ID_SEL			(1 << 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TUSB_PHY_OTG_CTRL_ENABLE	(TUSB_SYS_REG_BASE + 0x004)
 | 
				
			||||||
 | 
					#define TUSB_PHY_OTG_CTRL		(TUSB_SYS_REG_BASE + 0x008)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_WRPROTECT		(0xa5 << 24)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP		(1 << 23)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_OTG_VBUS_DET_EN	(1 << 19)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_OTG_SESS_END_EN	(1 << 18)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_TESTM2		(1 << 17)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_TESTM1		(1 << 16)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_TESTM0		(1 << 15)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_TX_DATA2		(1 << 14)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_TX_GZ2		(1 << 13)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_TX_ENABLE2		(1 << 12)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_DM_PULLDOWN		(1 << 11)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_DP_PULLDOWN		(1 << 10)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_OSC_EN		(1 << 9)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_PHYREF_CLKSEL(v)	(((v) & 3) << 7)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_PD			(1 << 6)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_PLL_ON		(1 << 5)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_EXT_RPU		(1 << 4)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_PWR_GOOD		(1 << 3)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_RESET			(1 << 2)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_SUSPENDM		(1 << 1)
 | 
				
			||||||
 | 
					#define		TUSB_PHY_OTG_CTRL_CLK_MODE		(1 << 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*OTG status register */
 | 
				
			||||||
 | 
					#define TUSB_DEV_OTG_STAT		(TUSB_SYS_REG_BASE + 0x00c)
 | 
				
			||||||
 | 
					#define		TUSB_DEV_OTG_STAT_PWR_CLK_GOOD		(1 << 8)
 | 
				
			||||||
 | 
					#define		TUSB_DEV_OTG_STAT_SESS_END		(1 << 7)
 | 
				
			||||||
 | 
					#define		TUSB_DEV_OTG_STAT_SESS_VALID		(1 << 6)
 | 
				
			||||||
 | 
					#define		TUSB_DEV_OTG_STAT_VBUS_VALID		(1 << 5)
 | 
				
			||||||
 | 
					#define		TUSB_DEV_OTG_STAT_VBUS_SENSE		(1 << 4)
 | 
				
			||||||
 | 
					#define		TUSB_DEV_OTG_STAT_ID_STATUS		(1 << 3)
 | 
				
			||||||
 | 
					#define		TUSB_DEV_OTG_STAT_HOST_DISCON		(1 << 2)
 | 
				
			||||||
 | 
					#define		TUSB_DEV_OTG_STAT_LINE_STATE		(3 << 0)
 | 
				
			||||||
 | 
					#define		TUSB_DEV_OTG_STAT_DP_ENABLE		(1 << 1)
 | 
				
			||||||
 | 
					#define		TUSB_DEV_OTG_STAT_DM_ENABLE		(1 << 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TUSB_DEV_OTG_TIMER		(TUSB_SYS_REG_BASE + 0x010)
 | 
				
			||||||
 | 
					#	define TUSB_DEV_OTG_TIMER_ENABLE		(1 << 31)
 | 
				
			||||||
 | 
					#	define TUSB_DEV_OTG_TIMER_VAL(v)		((v) & 0x07ffffff)
 | 
				
			||||||
 | 
					#define TUSB_PRCM_REV			(TUSB_SYS_REG_BASE + 0x014)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* PRCM configuration register */
 | 
				
			||||||
 | 
					#define TUSB_PRCM_CONF			(TUSB_SYS_REG_BASE + 0x018)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_CONF_SFW_CPEN		(1 << 24)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_CONF_SYS_CLKSEL(v)	(((v) & 3) << 16)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* PRCM management register */
 | 
				
			||||||
 | 
					#define TUSB_PRCM_MNGMT			(TUSB_SYS_REG_BASE + 0x01c)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_MNGMT_SRP_FIX_TIMER(v)	(((v) & 0xf) << 25)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_MNGMT_SRP_FIX_EN		(1 << 24)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_MNGMT_VBUS_VALID_TIMER(v)	(((v) & 0xf) << 20)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_MNGMT_VBUS_VALID_FLT_EN	(1 << 19)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_MNGMT_DFT_CLK_DIS		(1 << 18)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_MNGMT_VLYNQ_CLK_DIS		(1 << 17)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_MNGMT_OTG_SESS_END_EN		(1 << 10)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN		(1 << 9)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_MNGMT_OTG_ID_PULLUP		(1 << 8)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_MNGMT_15_SW_EN		(1 << 4)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_MNGMT_33_SW_EN		(1 << 3)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_MNGMT_5V_CPEN			(1 << 2)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_MNGMT_PM_IDLE			(1 << 1)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_MNGMT_DEV_IDLE		(1 << 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Wake-up source clear and mask registers */
 | 
				
			||||||
 | 
					#define TUSB_PRCM_WAKEUP_SOURCE		(TUSB_SYS_REG_BASE + 0x020)
 | 
				
			||||||
 | 
					#define TUSB_PRCM_WAKEUP_CLEAR		(TUSB_SYS_REG_BASE + 0x028)
 | 
				
			||||||
 | 
					#define TUSB_PRCM_WAKEUP_MASK		(TUSB_SYS_REG_BASE + 0x02c)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_WAKEUP_RESERVED_BITS	(0xffffe << 13)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_WGPIO_7	(1 << 12)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_WGPIO_6	(1 << 11)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_WGPIO_5	(1 << 10)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_WGPIO_4	(1 << 9)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_WGPIO_3	(1 << 8)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_WGPIO_2	(1 << 7)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_WGPIO_1	(1 << 6)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_WGPIO_0	(1 << 5)
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_WHOSTDISCON	(1 << 4)	/* Host disconnect */
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_WBUS		(1 << 3)	/* USB bus resume */
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_WNORCS	(1 << 2)	/* NOR chip select */
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_WVBUS		(1 << 1)	/* OTG PHY VBUS */
 | 
				
			||||||
 | 
					#define		TUSB_PRCM_WID		(1 << 0)	/* OTG PHY ID detect */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TUSB_PULLUP_1_CTRL		(TUSB_SYS_REG_BASE + 0x030)
 | 
				
			||||||
 | 
					#define TUSB_PULLUP_2_CTRL		(TUSB_SYS_REG_BASE + 0x034)
 | 
				
			||||||
 | 
					#define TUSB_INT_CTRL_REV		(TUSB_SYS_REG_BASE + 0x038)
 | 
				
			||||||
 | 
					#define TUSB_INT_CTRL_CONF		(TUSB_SYS_REG_BASE + 0x03c)
 | 
				
			||||||
 | 
					#define TUSB_USBIP_INT_SRC		(TUSB_SYS_REG_BASE + 0x040)
 | 
				
			||||||
 | 
					#define TUSB_USBIP_INT_SET		(TUSB_SYS_REG_BASE + 0x044)
 | 
				
			||||||
 | 
					#define TUSB_USBIP_INT_CLEAR		(TUSB_SYS_REG_BASE + 0x048)
 | 
				
			||||||
 | 
					#define TUSB_USBIP_INT_MASK		(TUSB_SYS_REG_BASE + 0x04c)
 | 
				
			||||||
 | 
					#define TUSB_DMA_INT_SRC		(TUSB_SYS_REG_BASE + 0x050)
 | 
				
			||||||
 | 
					#define TUSB_DMA_INT_SET		(TUSB_SYS_REG_BASE + 0x054)
 | 
				
			||||||
 | 
					#define TUSB_DMA_INT_CLEAR		(TUSB_SYS_REG_BASE + 0x058)
 | 
				
			||||||
 | 
					#define TUSB_DMA_INT_MASK		(TUSB_SYS_REG_BASE + 0x05c)
 | 
				
			||||||
 | 
					#define TUSB_GPIO_INT_SRC		(TUSB_SYS_REG_BASE + 0x060)
 | 
				
			||||||
 | 
					#define TUSB_GPIO_INT_SET		(TUSB_SYS_REG_BASE + 0x064)
 | 
				
			||||||
 | 
					#define TUSB_GPIO_INT_CLEAR		(TUSB_SYS_REG_BASE + 0x068)
 | 
				
			||||||
 | 
					#define TUSB_GPIO_INT_MASK		(TUSB_SYS_REG_BASE + 0x06c)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* NOR flash interrupt source registers */
 | 
				
			||||||
 | 
					#define TUSB_INT_SRC			(TUSB_SYS_REG_BASE + 0x070)
 | 
				
			||||||
 | 
					#define TUSB_INT_SRC_SET		(TUSB_SYS_REG_BASE + 0x074)
 | 
				
			||||||
 | 
					#define TUSB_INT_SRC_CLEAR		(TUSB_SYS_REG_BASE + 0x078)
 | 
				
			||||||
 | 
					#define TUSB_INT_MASK			(TUSB_SYS_REG_BASE + 0x07c)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_TXRX_DMA_DONE		(1 << 24)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_USB_IP_CORE		(1 << 17)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_OTG_TIMEOUT		(1 << 16)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_VBUS_SENSE_CHNG		(1 << 15)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_ID_STATUS_CHNG		(1 << 14)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_DEV_WAKEUP			(1 << 13)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_DEV_READY			(1 << 12)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_USB_IP_TX			(1 << 9)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_USB_IP_RX			(1 << 8)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_USB_IP_VBUS_ERR		(1 << 7)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_USB_IP_VBUS_REQ		(1 << 6)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_USB_IP_DISCON		(1 << 5)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_USB_IP_CONN		(1 << 4)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_USB_IP_SOF			(1 << 3)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_USB_IP_RST_BABBLE		(1 << 2)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_USB_IP_RESUME		(1 << 1)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_USB_IP_SUSPEND		(1 << 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* NOR flash interrupt registers reserved bits. Must be written as 0 */
 | 
				
			||||||
 | 
					#define		TUSB_INT_MASK_RESERVED_17		(0x3fff << 17)
 | 
				
			||||||
 | 
					#define		TUSB_INT_MASK_RESERVED_13		(1 << 13)
 | 
				
			||||||
 | 
					#define		TUSB_INT_MASK_RESERVED_8		(0xf << 8)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_RESERVED_26		(0x1f << 26)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_RESERVED_18		(0x3f << 18)
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_RESERVED_10		(0x03 << 10)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Reserved bits for NOR flash interrupt mask and clear register */
 | 
				
			||||||
 | 
					#define		TUSB_INT_MASK_RESERVED_BITS	(TUSB_INT_MASK_RESERVED_17 | \
 | 
				
			||||||
 | 
											TUSB_INT_MASK_RESERVED_13 | \
 | 
				
			||||||
 | 
											TUSB_INT_MASK_RESERVED_8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Reserved bits for NOR flash interrupt status register */
 | 
				
			||||||
 | 
					#define		TUSB_INT_SRC_RESERVED_BITS	(TUSB_INT_SRC_RESERVED_26 | \
 | 
				
			||||||
 | 
											TUSB_INT_SRC_RESERVED_18 | \
 | 
				
			||||||
 | 
											TUSB_INT_SRC_RESERVED_10)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TUSB_GPIO_REV			(TUSB_SYS_REG_BASE + 0x080)
 | 
				
			||||||
 | 
					#define TUSB_GPIO_CONF			(TUSB_SYS_REG_BASE + 0x084)
 | 
				
			||||||
 | 
					#define TUSB_DMA_CTRL_REV		(TUSB_SYS_REG_BASE + 0x100)
 | 
				
			||||||
 | 
					#define TUSB_DMA_REQ_CONF		(TUSB_SYS_REG_BASE + 0x104)
 | 
				
			||||||
 | 
					#define TUSB_EP0_CONF			(TUSB_SYS_REG_BASE + 0x108)
 | 
				
			||||||
 | 
					#define TUSB_DMA_EP_MAP			(TUSB_SYS_REG_BASE + 0x148)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Offsets from each ep base register */
 | 
				
			||||||
 | 
					#define TUSB_EP_TX_OFFSET		0x10c	/* EP_IN in docs */
 | 
				
			||||||
 | 
					#define TUSB_EP_RX_OFFSET		0x14c	/* EP_OUT in docs */
 | 
				
			||||||
 | 
					#define TUSB_EP_MAX_PACKET_SIZE_OFFSET	0x188
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TUSB_WAIT_COUNT			(TUSB_SYS_REG_BASE + 0x1c8)
 | 
				
			||||||
 | 
					#define TUSB_SCRATCH_PAD		(TUSB_SYS_REG_BASE + 0x1c4)
 | 
				
			||||||
 | 
					#define TUSB_PROD_TEST_RESET		(TUSB_SYS_REG_BASE + 0x1d8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Device System & Control register bitfields */
 | 
				
			||||||
 | 
					#define TUSB_INT_CTRL_CONF_INT_RELCYC(v)	(((v) & 0x7) << 18)
 | 
				
			||||||
 | 
					#define TUSB_INT_CTRL_CONF_INT_POLARITY		(1 << 17)
 | 
				
			||||||
 | 
					#define TUSB_INT_CTRL_CONF_INT_MODE		(1 << 16)
 | 
				
			||||||
 | 
					#define TUSB_GPIO_CONF_DMAREQ(v)		(((v) & 0x3f) << 24)
 | 
				
			||||||
 | 
					#define TUSB_DMA_REQ_CONF_BURST_SIZE(v)		(((v) & 3) << 26)
 | 
				
			||||||
 | 
					#define TUSB_DMA_REQ_CONF_DMA_REQ_EN(v)		(((v) & 0x3f) << 20)
 | 
				
			||||||
 | 
					#define TUSB_DMA_REQ_CONF_DMA_REQ_ASSER(v)	(((v) & 0xf) << 16)
 | 
				
			||||||
 | 
					#define TUSB_EP0_CONFIG_SW_EN			(1 << 8)
 | 
				
			||||||
 | 
					#define TUSB_EP0_CONFIG_DIR_TX			(1 << 7)
 | 
				
			||||||
 | 
					#define TUSB_EP0_CONFIG_XFR_SIZE(v)		((v) & 0x7f)
 | 
				
			||||||
 | 
					#define TUSB_EP_CONFIG_SW_EN			(1 << 31)
 | 
				
			||||||
 | 
					#define TUSB_EP_CONFIG_XFR_SIZE(v)		((v) & 0x7fffffff)
 | 
				
			||||||
 | 
					#define TUSB_PROD_TEST_RESET_VAL		0xa596
 | 
				
			||||||
 | 
					#define TUSB_EP_FIFO(ep)			(TUSB_FIFO_BASE + (ep) * 0x20)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TUSB_DIDR1_LO				(TUSB_SYS_REG_BASE + 0x1f8)
 | 
				
			||||||
 | 
					#define TUSB_DIDR1_HI				(TUSB_SYS_REG_BASE + 0x1fc)
 | 
				
			||||||
 | 
					#define		TUSB_DIDR1_HI_CHIP_REV(v)		(((v) >> 17) & 0xf)
 | 
				
			||||||
 | 
					#define			TUSB_DIDR1_HI_REV_20		0
 | 
				
			||||||
 | 
					#define			TUSB_DIDR1_HI_REV_30		1
 | 
				
			||||||
 | 
					#define			TUSB_DIDR1_HI_REV_31		2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TUSB_REV_10	0x10
 | 
				
			||||||
 | 
					#define TUSB_REV_20	0x20
 | 
				
			||||||
 | 
					#define TUSB_REV_30	0x30
 | 
				
			||||||
 | 
					#define TUSB_REV_31	0x31
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*----------------------------------------------------------------------------*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_TUSB6010
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* configuration parameters specific to this silicon */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Number of Tx endpoints. Legal values are 1 - 16 (this value includes EP0) */
 | 
				
			||||||
 | 
					#define MUSB_C_NUM_EPT 16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Number of Rx endpoints. Legal values are 1 - 16 (this value includes EP0) */
 | 
				
			||||||
 | 
					#define MUSB_C_NUM_EPR 16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Endpoint 1 to 15 direction types. C_EP1_DEF is defined if either Tx endpoint
 | 
				
			||||||
 | 
					 * 1 or Rx endpoint 1 are used.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define MUSB_C_EP1_DEF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* C_EP1_TX_DEF is defined if Tx endpoint 1 is used */
 | 
				
			||||||
 | 
					#define MUSB_C_EP1_TX_DEF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* C_EP1_RX_DEF is defined if Rx endpoint 1 is used */
 | 
				
			||||||
 | 
					#define MUSB_C_EP1_RX_DEF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* C_EP1_TOR_DEF is defined if Tx endpoint 1 and Rx endpoint 1 share a FIFO */
 | 
				
			||||||
 | 
					/* #define C_EP1_TOR_DEF */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* C_EP1_TAR_DEF is defined if both Tx endpoint 1 and Rx endpoint 1 are used
 | 
				
			||||||
 | 
					 * and do not share a FIFO.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define MUSB_C_EP1_TAR_DEF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Similarly for all other used endpoints */
 | 
				
			||||||
 | 
					#define MUSB_C_EP2_DEF
 | 
				
			||||||
 | 
					#define MUSB_C_EP2_TX_DEF
 | 
				
			||||||
 | 
					#define MUSB_C_EP2_RX_DEF
 | 
				
			||||||
 | 
					#define MUSB_C_EP2_TAR_DEF
 | 
				
			||||||
 | 
					#define MUSB_C_EP3_DEF
 | 
				
			||||||
 | 
					#define MUSB_C_EP3_TX_DEF
 | 
				
			||||||
 | 
					#define MUSB_C_EP3_RX_DEF
 | 
				
			||||||
 | 
					#define MUSB_C_EP3_TAR_DEF
 | 
				
			||||||
 | 
					#define MUSB_C_EP4_DEF
 | 
				
			||||||
 | 
					#define MUSB_C_EP4_TX_DEF
 | 
				
			||||||
 | 
					#define MUSB_C_EP4_RX_DEF
 | 
				
			||||||
 | 
					#define MUSB_C_EP4_TAR_DEF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Endpoint 1 to 15 FIFO address bits. Legal values are 3 to 13 - corresponding
 | 
				
			||||||
 | 
					 * to FIFO sizes of 8 to 8192 bytes. If an Tx endpoint shares a FIFO with an Rx
 | 
				
			||||||
 | 
					 * endpoint then the Rx FIFO size must be the same as the Tx FIFO size. All
 | 
				
			||||||
 | 
					 * endpoints 1 to 15 must be defined, unused endpoints should be set to 2.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define MUSB_C_EP1T_BITS 5
 | 
				
			||||||
 | 
					#define MUSB_C_EP1R_BITS 5
 | 
				
			||||||
 | 
					#define MUSB_C_EP2T_BITS 5
 | 
				
			||||||
 | 
					#define MUSB_C_EP2R_BITS 5
 | 
				
			||||||
 | 
					#define MUSB_C_EP3T_BITS 3
 | 
				
			||||||
 | 
					#define MUSB_C_EP3R_BITS 3
 | 
				
			||||||
 | 
					#define MUSB_C_EP4T_BITS 3
 | 
				
			||||||
 | 
					#define MUSB_C_EP4R_BITS 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MUSB_C_EP5T_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP5R_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP6T_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP6R_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP7T_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP7R_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP8T_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP8R_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP9T_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP9R_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP10T_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP10R_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP11T_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP11R_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP12T_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP12R_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP13T_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP13R_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP14T_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP14R_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP15T_BITS 2
 | 
				
			||||||
 | 
					#define MUSB_C_EP15R_BITS 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Define the following constant if the USB2.0 Transceiver Macrocell data width
 | 
				
			||||||
 | 
					 * is 16-bits.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* #define C_UTM_16 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Define this constant if the CPU uses big-endian byte ordering. */
 | 
				
			||||||
 | 
					/* #define C_BIGEND */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Define the following constant if any Tx endpoint is required to support
 | 
				
			||||||
 | 
					 * multiple bulk packets.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* #define C_MP_TX */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Define the following constant if any Rx endpoint is required to support
 | 
				
			||||||
 | 
					 * multiple bulk packets.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* #define C_MP_RX */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Define the following constant if any Tx endpoint is required to support high
 | 
				
			||||||
 | 
					 * bandwidth ISO.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* #define C_HB_TX */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Define the following constant if any Rx endpoint is required to support high
 | 
				
			||||||
 | 
					 * bandwidth ISO.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* #define C_HB_RX */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Define the following constant if software connect/disconnect control is
 | 
				
			||||||
 | 
					 * required.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define MUSB_C_SOFT_CON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Define the following constant if Vendor Control Registers are required. */
 | 
				
			||||||
 | 
					/* #define C_VEND_REG */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Vendor control register widths. */
 | 
				
			||||||
 | 
					#define MUSB_C_VCTL_BITS 4
 | 
				
			||||||
 | 
					#define MUSB_C_VSTAT_BITS 8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Define the following constant to include a DMA controller. */
 | 
				
			||||||
 | 
					/* #define C_DMA */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Define the following constant if 2 or more DMA channels are required. */
 | 
				
			||||||
 | 
					/* #define C_DMA2 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Define the following constant if 3 or more DMA channels are required. */
 | 
				
			||||||
 | 
					/* #define C_DMA3 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Define the following constant if 4 or more DMA channels are required. */
 | 
				
			||||||
 | 
					/* #define C_DMA4 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Define the following constant if 5 or more DMA channels are required. */
 | 
				
			||||||
 | 
					/* #define C_DMA5 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Define the following constant if 6 or more DMA channels are required. */
 | 
				
			||||||
 | 
					/* #define C_DMA6 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Define the following constant if 7 or more DMA channels are required. */
 | 
				
			||||||
 | 
					/* #define C_DMA7 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Define the following constant if 8 or more DMA channels are required. */
 | 
				
			||||||
 | 
					/* #define C_DMA8 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Enable Dynamic FIFO Sizing */
 | 
				
			||||||
 | 
					#define MUSB_C_DYNFIFO_DEF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived constants. The following constants are derived from the previous
 | 
				
			||||||
 | 
					 * configuration constants
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Total number of endpoints. Legal values are 2 - 16. This must be equal to
 | 
				
			||||||
 | 
					 * the larger of C_NUM_EPT, C_NUM_EPR
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* #define MUSB_C_NUM_EPS 5 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* C_EPMAX_BITS is equal to the largest endpoint FIFO word address bits */
 | 
				
			||||||
 | 
					#define MUSB_C_EPMAX_BITS 11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* C_RAM_BITS is the number of address bits required to address the RAM (32-bit
 | 
				
			||||||
 | 
					 * addresses).  It is defined as log2 of the sum of 2** of all the endpoint FIFO
 | 
				
			||||||
 | 
					 * dword address bits (rounded up).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define MUSB_C_RAM_BITS 12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CONFIG_USB_TUSB6010 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __TUSB6010_H__ */
 | 
				
			||||||
							
								
								
									
										719
									
								
								drivers/usb/musb/tusb6010_omap.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										719
									
								
								drivers/usb/musb/tusb6010_omap.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,719 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * TUSB6010 USB 2.0 OTG Dual Role controller OMAP DMA interface
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2006 Nokia Corporation
 | 
				
			||||||
 | 
					 * Tony Lindgren <tony@atomide.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#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 <asm/arch/dma.h>
 | 
				
			||||||
 | 
					#include <asm/arch/mux.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "musb_core.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define to_chdat(c)		((struct tusb_omap_dma_ch *)(c)->private_data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_DMAREQ		5	/* REVISIT: Really 6, but req5 not OK */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct tusb_omap_dma_ch {
 | 
				
			||||||
 | 
						struct musb		*musb;
 | 
				
			||||||
 | 
						void __iomem		*tbase;
 | 
				
			||||||
 | 
						unsigned long		phys_offset;
 | 
				
			||||||
 | 
						int			epnum;
 | 
				
			||||||
 | 
						u8			tx;
 | 
				
			||||||
 | 
						struct musb_hw_ep	*hw_ep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int			ch;
 | 
				
			||||||
 | 
						s8			dmareq;
 | 
				
			||||||
 | 
						s8			sync_dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct tusb_omap_dma	*tusb_dma;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void __iomem		*dma_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u32			len;
 | 
				
			||||||
 | 
						u16			packet_sz;
 | 
				
			||||||
 | 
						u16			transfer_packet_sz;
 | 
				
			||||||
 | 
						u32			transfer_len;
 | 
				
			||||||
 | 
						u32			completed_len;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct tusb_omap_dma {
 | 
				
			||||||
 | 
						struct dma_controller		controller;
 | 
				
			||||||
 | 
						struct musb			*musb;
 | 
				
			||||||
 | 
						void __iomem			*tbase;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int				ch;
 | 
				
			||||||
 | 
						s8				dmareq;
 | 
				
			||||||
 | 
						s8				sync_dev;
 | 
				
			||||||
 | 
						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
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					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",
 | 
				
			||||||
 | 
								chdat->epnum, reg & 0xf);
 | 
				
			||||||
 | 
							return -EAGAIN;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (chdat->tx)
 | 
				
			||||||
 | 
							reg = (1 << 4) | chdat->epnum;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							reg = chdat->epnum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						musb_writel(chdat->tbase, TUSB_DMA_EP_MAP, reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void tusb_omap_free_shared_dmareq(struct tusb_omap_dma_ch *chdat)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u32		reg = musb_readl(chdat->tbase, TUSB_DMA_EP_MAP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((reg & 0xf) != chdat->epnum) {
 | 
				
			||||||
 | 
							printk(KERN_ERR "ep%i trying to release dmareq0 for ep%i\n",
 | 
				
			||||||
 | 
								chdat->epnum, reg & 0xf);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						musb_writel(chdat->tbase, TUSB_DMA_EP_MAP, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * See also musb_dma_completion in plat_uds.c and musb_g_[tx|rx]() in
 | 
				
			||||||
 | 
					 * musb_gadget.c.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void tusb_omap_dma_cb(int lch, u16 ch_status, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct dma_channel	*channel = (struct dma_channel *)data;
 | 
				
			||||||
 | 
						struct tusb_omap_dma_ch	*chdat = to_chdat(channel);
 | 
				
			||||||
 | 
						struct tusb_omap_dma	*tusb_dma = chdat->tusb_dma;
 | 
				
			||||||
 | 
						struct musb		*musb = chdat->musb;
 | 
				
			||||||
 | 
						struct musb_hw_ep	*hw_ep = chdat->hw_ep;
 | 
				
			||||||
 | 
						void __iomem		*ep_conf = hw_ep->conf;
 | 
				
			||||||
 | 
						void __iomem		*mbase = musb->mregs;
 | 
				
			||||||
 | 
						unsigned long		remaining, flags, pio;
 | 
				
			||||||
 | 
						int			ch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_irqsave(&musb->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (tusb_dma->multichannel)
 | 
				
			||||||
 | 
							ch = chdat->ch;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							ch = tusb_dma->ch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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",
 | 
				
			||||||
 | 
							chdat->epnum, chdat->tx ? "tx" : "rx",
 | 
				
			||||||
 | 
							ch, ch_status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (chdat->tx)
 | 
				
			||||||
 | 
							remaining = musb_readl(ep_conf, TUSB_EP_TX_OFFSET);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							remaining = musb_readl(ep_conf, TUSB_EP_RX_OFFSET);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						remaining = TUSB_EP_CONFIG_XFR_SIZE(remaining);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* 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",
 | 
				
			||||||
 | 
								chdat->tx ? "tx" : "rx", chdat->ch,
 | 
				
			||||||
 | 
								remaining);
 | 
				
			||||||
 | 
							remaining = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						channel->actual_len = chdat->transfer_len - remaining;
 | 
				
			||||||
 | 
						pio = chdat->len - channel->actual_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DBG(3, "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);
 | 
				
			||||||
 | 
							buf = phys_to_virt((u32)chdat->dma_addr) + chdat->transfer_len;
 | 
				
			||||||
 | 
							if (chdat->tx) {
 | 
				
			||||||
 | 
								dma_cache_maint(phys_to_virt((u32)chdat->dma_addr),
 | 
				
			||||||
 | 
										chdat->transfer_len, DMA_TO_DEVICE);
 | 
				
			||||||
 | 
								musb_write_fifo(hw_ep, pio, buf);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								musb_read_fifo(hw_ep, pio, buf);
 | 
				
			||||||
 | 
								dma_cache_maint(phys_to_virt((u32)chdat->dma_addr),
 | 
				
			||||||
 | 
										chdat->transfer_len, DMA_FROM_DEVICE);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							channel->actual_len += pio;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!tusb_dma->multichannel)
 | 
				
			||||||
 | 
							tusb_omap_free_shared_dmareq(chdat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						channel->status = MUSB_DMA_STATUS_FREE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Handle only RX callbacks here. TX callbacks must be handled based
 | 
				
			||||||
 | 
						 * on the TUSB DMA status interrupt.
 | 
				
			||||||
 | 
						 * REVISIT: Use both TUSB DMA status interrupt and OMAP DMA callback
 | 
				
			||||||
 | 
						 * interrupt for RX and TX.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (!chdat->tx)
 | 
				
			||||||
 | 
							musb_dma_completion(musb, chdat->epnum, chdat->tx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* We must terminate short tx transfers manually by setting TXPKTRDY.
 | 
				
			||||||
 | 
						 * REVISIT: This same problem may occur with other MUSB dma as well.
 | 
				
			||||||
 | 
						 * Easy to test with g_ether by pinging the MUSB board with ping -s54.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if ((chdat->transfer_len < chdat->packet_sz)
 | 
				
			||||||
 | 
								|| (chdat->transfer_len % chdat->packet_sz != 0)) {
 | 
				
			||||||
 | 
							u16	csr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (chdat->tx) {
 | 
				
			||||||
 | 
								DBG(3, "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
 | 
				
			||||||
 | 
									| MUSB_TXCSR_P_WZC_BITS;
 | 
				
			||||||
 | 
								musb_writew(hw_ep->regs, MUSB_TXCSR, csr);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_unlock_irqrestore(&musb->lock, flags);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,
 | 
				
			||||||
 | 
									u8 rndis_mode, dma_addr_t dma_addr, u32 len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct tusb_omap_dma_ch		*chdat = to_chdat(channel);
 | 
				
			||||||
 | 
						struct tusb_omap_dma		*tusb_dma = chdat->tusb_dma;
 | 
				
			||||||
 | 
						struct musb			*musb = chdat->musb;
 | 
				
			||||||
 | 
						struct musb_hw_ep		*hw_ep = chdat->hw_ep;
 | 
				
			||||||
 | 
						void __iomem			*mbase = musb->mregs;
 | 
				
			||||||
 | 
						void __iomem			*ep_conf = hw_ep->conf;
 | 
				
			||||||
 | 
						dma_addr_t			fifo = hw_ep->fifo_sync;
 | 
				
			||||||
 | 
						struct omap_dma_channel_params	dma_params;
 | 
				
			||||||
 | 
						u32				dma_remaining;
 | 
				
			||||||
 | 
						int				src_burst, dst_burst;
 | 
				
			||||||
 | 
						u16				csr;
 | 
				
			||||||
 | 
						int				ch;
 | 
				
			||||||
 | 
						s8				dmareq;
 | 
				
			||||||
 | 
						s8				sync_dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (unlikely(dma_addr & 0x1) || (len < 32) || (len > packet_sz))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * HW issue #10: Async dma will eventually corrupt the XFR_SIZE
 | 
				
			||||||
 | 
						 * register which will cause missed DMA interrupt. We could try to
 | 
				
			||||||
 | 
						 * use a timer for the callback, but it is unsafe as the XFR_SIZE
 | 
				
			||||||
 | 
						 * register is corrupt, and we won't know if the DMA worked.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (dma_addr & 0x2)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Because of HW issue #10, it seems like mixing sync DMA and async
 | 
				
			||||||
 | 
						 * PIO access can confuse the DMA. Make sure XFR_SIZE is reset before
 | 
				
			||||||
 | 
						 * using the channel for DMA.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (chdat->tx)
 | 
				
			||||||
 | 
							dma_remaining = musb_readl(ep_conf, TUSB_EP_TX_OFFSET);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							dma_remaining = musb_readl(ep_conf, TUSB_EP_RX_OFFSET);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dma_remaining = TUSB_EP_CONFIG_XFR_SIZE(dma_remaining);
 | 
				
			||||||
 | 
						if (dma_remaining) {
 | 
				
			||||||
 | 
							DBG(2, "Busy %s dma ch%i, not using: %08x\n",
 | 
				
			||||||
 | 
								chdat->tx ? "tx" : "rx", chdat->ch,
 | 
				
			||||||
 | 
								dma_remaining);
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						chdat->transfer_len = len & ~0x1f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (len < packet_sz)
 | 
				
			||||||
 | 
							chdat->transfer_packet_sz = chdat->transfer_len;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							chdat->transfer_packet_sz = packet_sz;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (tusb_dma->multichannel) {
 | 
				
			||||||
 | 
							ch = chdat->ch;
 | 
				
			||||||
 | 
							dmareq = chdat->dmareq;
 | 
				
			||||||
 | 
							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);
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (tusb_dma->ch < 0) {
 | 
				
			||||||
 | 
								/* REVISIT: This should get blocked earlier, happens
 | 
				
			||||||
 | 
								 * with MSC ErrorRecoveryTest
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								WARN_ON(1);
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ch = tusb_dma->ch;
 | 
				
			||||||
 | 
							dmareq = tusb_dma->dmareq;
 | 
				
			||||||
 | 
							sync_dev = tusb_dma->sync_dev;
 | 
				
			||||||
 | 
							omap_set_dma_callback(ch, tusb_omap_dma_cb, channel);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						chdat->packet_sz = packet_sz;
 | 
				
			||||||
 | 
						chdat->len = len;
 | 
				
			||||||
 | 
						channel->actual_len = 0;
 | 
				
			||||||
 | 
						chdat->dma_addr = (void __iomem *)dma_addr;
 | 
				
			||||||
 | 
						channel->status = MUSB_DMA_STATUS_BUSY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Since we're recycling dma areas, we need to clean or invalidate */
 | 
				
			||||||
 | 
						if (chdat->tx)
 | 
				
			||||||
 | 
							dma_cache_maint(phys_to_virt(dma_addr), len, DMA_TO_DEVICE);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							dma_cache_maint(phys_to_virt(dma_addr), len, DMA_FROM_DEVICE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Use 16-bit transfer if dma_addr is not 32-bit aligned */
 | 
				
			||||||
 | 
						if ((dma_addr & 0x3) == 0) {
 | 
				
			||||||
 | 
							dma_params.data_type = OMAP_DMA_DATA_TYPE_S32;
 | 
				
			||||||
 | 
							dma_params.elem_count = 8;		/* Elements in frame */
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							dma_params.data_type = OMAP_DMA_DATA_TYPE_S16;
 | 
				
			||||||
 | 
							dma_params.elem_count = 16;		/* Elements in frame */
 | 
				
			||||||
 | 
							fifo = hw_ep->fifo_async;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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",
 | 
				
			||||||
 | 
							chdat->epnum, chdat->tx ? "tx" : "rx",
 | 
				
			||||||
 | 
							ch, dma_addr, chdat->transfer_len, len,
 | 
				
			||||||
 | 
							chdat->transfer_packet_sz, packet_sz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Prepare omap DMA for transfer
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (chdat->tx) {
 | 
				
			||||||
 | 
							dma_params.src_amode	= OMAP_DMA_AMODE_POST_INC;
 | 
				
			||||||
 | 
							dma_params.src_start	= (unsigned long)dma_addr;
 | 
				
			||||||
 | 
							dma_params.src_ei	= 0;
 | 
				
			||||||
 | 
							dma_params.src_fi	= 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dma_params.dst_amode	= OMAP_DMA_AMODE_DOUBLE_IDX;
 | 
				
			||||||
 | 
							dma_params.dst_start	= (unsigned long)fifo;
 | 
				
			||||||
 | 
							dma_params.dst_ei	= 1;
 | 
				
			||||||
 | 
							dma_params.dst_fi	= -31;	/* Loop 32 byte window */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dma_params.trigger	= sync_dev;
 | 
				
			||||||
 | 
							dma_params.sync_mode	= OMAP_DMA_SYNC_FRAME;
 | 
				
			||||||
 | 
							dma_params.src_or_dst_synch	= 0;	/* Dest sync */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							src_burst = OMAP_DMA_DATA_BURST_16;	/* 16x32 read */
 | 
				
			||||||
 | 
							dst_burst = OMAP_DMA_DATA_BURST_8;	/* 8x32 write */
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							dma_params.src_amode	= OMAP_DMA_AMODE_DOUBLE_IDX;
 | 
				
			||||||
 | 
							dma_params.src_start	= (unsigned long)fifo;
 | 
				
			||||||
 | 
							dma_params.src_ei	= 1;
 | 
				
			||||||
 | 
							dma_params.src_fi	= -31;	/* Loop 32 byte window */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dma_params.dst_amode	= OMAP_DMA_AMODE_POST_INC;
 | 
				
			||||||
 | 
							dma_params.dst_start	= (unsigned long)dma_addr;
 | 
				
			||||||
 | 
							dma_params.dst_ei	= 0;
 | 
				
			||||||
 | 
							dma_params.dst_fi	= 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dma_params.trigger	= sync_dev;
 | 
				
			||||||
 | 
							dma_params.sync_mode	= OMAP_DMA_SYNC_FRAME;
 | 
				
			||||||
 | 
							dma_params.src_or_dst_synch	= 1;	/* Source sync */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							src_burst = OMAP_DMA_DATA_BURST_8;	/* 8x32 read */
 | 
				
			||||||
 | 
							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",
 | 
				
			||||||
 | 
							chdat->epnum, chdat->tx ? "tx" : "rx",
 | 
				
			||||||
 | 
							(dma_params.data_type == OMAP_DMA_DATA_TYPE_S32) ? 32 : 16,
 | 
				
			||||||
 | 
							((dma_addr & 0x3) == 0) ? "sync" : "async",
 | 
				
			||||||
 | 
							dma_params.src_start, dma_params.dst_start);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						omap_set_dma_params(ch, &dma_params);
 | 
				
			||||||
 | 
						omap_set_dma_src_burst_mode(ch, src_burst);
 | 
				
			||||||
 | 
						omap_set_dma_dest_burst_mode(ch, dst_burst);
 | 
				
			||||||
 | 
						omap_set_dma_write_mode(ch, OMAP_DMA_WRITE_LAST_NON_POSTED);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Prepare MUSB for DMA transfer
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (chdat->tx) {
 | 
				
			||||||
 | 
							musb_ep_select(mbase, chdat->epnum);
 | 
				
			||||||
 | 
							csr = musb_readw(hw_ep->regs, MUSB_TXCSR);
 | 
				
			||||||
 | 
							csr |= (MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB
 | 
				
			||||||
 | 
								| MUSB_TXCSR_DMAMODE | MUSB_TXCSR_MODE);
 | 
				
			||||||
 | 
							csr &= ~MUSB_TXCSR_P_UNDERRUN;
 | 
				
			||||||
 | 
							musb_writew(hw_ep->regs, MUSB_TXCSR, csr);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							musb_ep_select(mbase, chdat->epnum);
 | 
				
			||||||
 | 
							csr = musb_readw(hw_ep->regs, MUSB_RXCSR);
 | 
				
			||||||
 | 
							csr |= MUSB_RXCSR_DMAENAB;
 | 
				
			||||||
 | 
							csr &= ~(MUSB_RXCSR_AUTOCLEAR | MUSB_RXCSR_DMAMODE);
 | 
				
			||||||
 | 
							musb_writew(hw_ep->regs, MUSB_RXCSR,
 | 
				
			||||||
 | 
								csr | MUSB_RXCSR_P_WZC_BITS);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Start DMA transfer
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						omap_start_dma(ch);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (chdat->tx) {
 | 
				
			||||||
 | 
							/* Send transfer_packet_sz packets at a time */
 | 
				
			||||||
 | 
							musb_writel(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET,
 | 
				
			||||||
 | 
								chdat->transfer_packet_sz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							musb_writel(ep_conf, TUSB_EP_TX_OFFSET,
 | 
				
			||||||
 | 
								TUSB_EP_CONFIG_XFR_SIZE(chdat->transfer_len));
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							/* Receive transfer_packet_sz packets at a time */
 | 
				
			||||||
 | 
							musb_writel(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET,
 | 
				
			||||||
 | 
								chdat->transfer_packet_sz << 16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							musb_writel(ep_conf, TUSB_EP_RX_OFFSET,
 | 
				
			||||||
 | 
								TUSB_EP_CONFIG_XFR_SIZE(chdat->transfer_len));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int tusb_omap_dma_abort(struct dma_channel *channel)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct tusb_omap_dma_ch	*chdat = to_chdat(channel);
 | 
				
			||||||
 | 
						struct tusb_omap_dma	*tusb_dma = chdat->tusb_dma;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!tusb_dma->multichannel) {
 | 
				
			||||||
 | 
							if (tusb_dma->ch >= 0) {
 | 
				
			||||||
 | 
								omap_stop_dma(tusb_dma->ch);
 | 
				
			||||||
 | 
								omap_free_dma(tusb_dma->ch);
 | 
				
			||||||
 | 
								tusb_dma->ch = -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							tusb_dma->dmareq = -1;
 | 
				
			||||||
 | 
							tusb_dma->sync_dev = -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						channel->status = MUSB_DMA_STATUS_FREE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int tusb_omap_dma_allocate_dmareq(struct tusb_omap_dma_ch *chdat)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u32		reg = musb_readl(chdat->tbase, TUSB_DMA_EP_MAP);
 | 
				
			||||||
 | 
						int		i, dmareq_nr = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const int sync_dev[6] = {
 | 
				
			||||||
 | 
							OMAP24XX_DMA_EXT_DMAREQ0,
 | 
				
			||||||
 | 
							OMAP24XX_DMA_EXT_DMAREQ1,
 | 
				
			||||||
 | 
							OMAP242X_DMA_EXT_DMAREQ2,
 | 
				
			||||||
 | 
							OMAP242X_DMA_EXT_DMAREQ3,
 | 
				
			||||||
 | 
							OMAP242X_DMA_EXT_DMAREQ4,
 | 
				
			||||||
 | 
							OMAP242X_DMA_EXT_DMAREQ5,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < MAX_DMAREQ; i++) {
 | 
				
			||||||
 | 
							int cur = (reg & (0xf << (i * 5))) >> (i * 5);
 | 
				
			||||||
 | 
							if (cur == 0) {
 | 
				
			||||||
 | 
								dmareq_nr = i;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dmareq_nr == -1)
 | 
				
			||||||
 | 
							return -EAGAIN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg |= (chdat->epnum << (dmareq_nr * 5));
 | 
				
			||||||
 | 
						if (chdat->tx)
 | 
				
			||||||
 | 
							reg |= ((1 << 4) << (dmareq_nr * 5));
 | 
				
			||||||
 | 
						musb_writel(chdat->tbase, TUSB_DMA_EP_MAP, reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						chdat->dmareq = dmareq_nr;
 | 
				
			||||||
 | 
						chdat->sync_dev = sync_dev[chdat->dmareq];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void tusb_omap_dma_free_dmareq(struct tusb_omap_dma_ch *chdat)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u32 reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!chdat || chdat->dmareq < 0)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg = musb_readl(chdat->tbase, TUSB_DMA_EP_MAP);
 | 
				
			||||||
 | 
						reg &= ~(0x1f << (chdat->dmareq * 5));
 | 
				
			||||||
 | 
						musb_writel(chdat->tbase, TUSB_DMA_EP_MAP, reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						chdat->dmareq = -1;
 | 
				
			||||||
 | 
						chdat->sync_dev = -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct dma_channel *dma_channel_pool[MAX_DMAREQ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct dma_channel *
 | 
				
			||||||
 | 
					tusb_omap_dma_allocate(struct dma_controller *c,
 | 
				
			||||||
 | 
							struct musb_hw_ep *hw_ep,
 | 
				
			||||||
 | 
							u8 tx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret, i;
 | 
				
			||||||
 | 
						const char		*dev_name;
 | 
				
			||||||
 | 
						struct tusb_omap_dma	*tusb_dma;
 | 
				
			||||||
 | 
						struct musb		*musb;
 | 
				
			||||||
 | 
						void __iomem		*tbase;
 | 
				
			||||||
 | 
						struct dma_channel	*channel = NULL;
 | 
				
			||||||
 | 
						struct tusb_omap_dma_ch	*chdat = NULL;
 | 
				
			||||||
 | 
						u32			reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tusb_dma = container_of(c, struct tusb_omap_dma, controller);
 | 
				
			||||||
 | 
						musb = tusb_dma->musb;
 | 
				
			||||||
 | 
						tbase = musb->ctrl_base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg = musb_readl(tbase, TUSB_DMA_INT_MASK);
 | 
				
			||||||
 | 
						if (tx)
 | 
				
			||||||
 | 
							reg &= ~(1 << hw_ep->epnum);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							reg &= ~(1 << (hw_ep->epnum + 15));
 | 
				
			||||||
 | 
						musb_writel(tbase, TUSB_DMA_INT_MASK, reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* REVISIT: Why does dmareq5 not work? */
 | 
				
			||||||
 | 
						if (hw_ep->epnum == 0) {
 | 
				
			||||||
 | 
							DBG(3, "Not allowing DMA for ep0 %s\n", tx ? "tx" : "rx");
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < MAX_DMAREQ; i++) {
 | 
				
			||||||
 | 
							struct dma_channel *ch = dma_channel_pool[i];
 | 
				
			||||||
 | 
							if (ch->status == MUSB_DMA_STATUS_UNKNOWN) {
 | 
				
			||||||
 | 
								ch->status = MUSB_DMA_STATUS_FREE;
 | 
				
			||||||
 | 
								channel = ch;
 | 
				
			||||||
 | 
								chdat = ch->private_data;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!channel)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (tx) {
 | 
				
			||||||
 | 
							chdat->tx = 1;
 | 
				
			||||||
 | 
							dev_name = "TUSB transmit";
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							chdat->tx = 0;
 | 
				
			||||||
 | 
							dev_name = "TUSB receive";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						chdat->musb = tusb_dma->musb;
 | 
				
			||||||
 | 
						chdat->tbase = tusb_dma->tbase;
 | 
				
			||||||
 | 
						chdat->hw_ep = hw_ep;
 | 
				
			||||||
 | 
						chdat->epnum = hw_ep->epnum;
 | 
				
			||||||
 | 
						chdat->dmareq = -1;
 | 
				
			||||||
 | 
						chdat->completed_len = 0;
 | 
				
			||||||
 | 
						chdat->tusb_dma = tusb_dma;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						channel->max_len = 0x7fffffff;
 | 
				
			||||||
 | 
						channel->desired_mode = 0;
 | 
				
			||||||
 | 
						channel->actual_len = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (tusb_dma->multichannel) {
 | 
				
			||||||
 | 
							ret = tusb_omap_dma_allocate_dmareq(chdat);
 | 
				
			||||||
 | 
							if (ret != 0)
 | 
				
			||||||
 | 
								goto free_dmareq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ret = omap_request_dma(chdat->sync_dev, dev_name,
 | 
				
			||||||
 | 
									tusb_omap_dma_cb, channel, &chdat->ch);
 | 
				
			||||||
 | 
							if (ret != 0)
 | 
				
			||||||
 | 
								goto free_dmareq;
 | 
				
			||||||
 | 
						} else if (tusb_dma->ch == -1) {
 | 
				
			||||||
 | 
							tusb_dma->dmareq = 0;
 | 
				
			||||||
 | 
							tusb_dma->sync_dev = OMAP24XX_DMA_EXT_DMAREQ0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Callback data gets set later in the shared dmareq case */
 | 
				
			||||||
 | 
							ret = omap_request_dma(tusb_dma->sync_dev, "TUSB shared",
 | 
				
			||||||
 | 
									tusb_omap_dma_cb, NULL, &tusb_dma->ch);
 | 
				
			||||||
 | 
							if (ret != 0)
 | 
				
			||||||
 | 
								goto free_dmareq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							chdat->dmareq = -1;
 | 
				
			||||||
 | 
							chdat->ch = -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DBG(3, "ep%i %s dma: %s dma%i dmareq%i sync%i\n",
 | 
				
			||||||
 | 
							chdat->epnum,
 | 
				
			||||||
 | 
							chdat->tx ? "tx" : "rx",
 | 
				
			||||||
 | 
							chdat->ch >= 0 ? "dedicated" : "shared",
 | 
				
			||||||
 | 
							chdat->ch >= 0 ? chdat->ch : tusb_dma->ch,
 | 
				
			||||||
 | 
							chdat->dmareq >= 0 ? chdat->dmareq : tusb_dma->dmareq,
 | 
				
			||||||
 | 
							chdat->sync_dev >= 0 ? chdat->sync_dev : tusb_dma->sync_dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return channel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					free_dmareq:
 | 
				
			||||||
 | 
						tusb_omap_dma_free_dmareq(chdat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DBG(3, "ep%i: Could not get a DMA channel\n", chdat->epnum);
 | 
				
			||||||
 | 
						channel->status = MUSB_DMA_STATUS_UNKNOWN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void tusb_omap_dma_release(struct dma_channel *channel)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct tusb_omap_dma_ch	*chdat = to_chdat(channel);
 | 
				
			||||||
 | 
						struct musb		*musb = chdat->musb;
 | 
				
			||||||
 | 
						void __iomem		*tbase = musb->ctrl_base;
 | 
				
			||||||
 | 
						u32			reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DBG(3, "ep%i ch%i\n", chdat->epnum, chdat->ch);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg = musb_readl(tbase, TUSB_DMA_INT_MASK);
 | 
				
			||||||
 | 
						if (chdat->tx)
 | 
				
			||||||
 | 
							reg |= (1 << chdat->epnum);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							reg |= (1 << (chdat->epnum + 15));
 | 
				
			||||||
 | 
						musb_writel(tbase, TUSB_DMA_INT_MASK, reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg = musb_readl(tbase, TUSB_DMA_INT_CLEAR);
 | 
				
			||||||
 | 
						if (chdat->tx)
 | 
				
			||||||
 | 
							reg |= (1 << chdat->epnum);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							reg |= (1 << (chdat->epnum + 15));
 | 
				
			||||||
 | 
						musb_writel(tbase, TUSB_DMA_INT_CLEAR, reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						channel->status = MUSB_DMA_STATUS_UNKNOWN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (chdat->ch >= 0) {
 | 
				
			||||||
 | 
							omap_stop_dma(chdat->ch);
 | 
				
			||||||
 | 
							omap_free_dma(chdat->ch);
 | 
				
			||||||
 | 
							chdat->ch = -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (chdat->dmareq >= 0)
 | 
				
			||||||
 | 
							tusb_omap_dma_free_dmareq(chdat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						channel = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void dma_controller_destroy(struct dma_controller *c)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct tusb_omap_dma	*tusb_dma;
 | 
				
			||||||
 | 
						int			i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tusb_dma = container_of(c, struct tusb_omap_dma, controller);
 | 
				
			||||||
 | 
						for (i = 0; i < MAX_DMAREQ; i++) {
 | 
				
			||||||
 | 
							struct dma_channel *ch = dma_channel_pool[i];
 | 
				
			||||||
 | 
							if (ch) {
 | 
				
			||||||
 | 
								kfree(ch->private_data);
 | 
				
			||||||
 | 
								kfree(ch);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!tusb_dma->multichannel && tusb_dma && tusb_dma->ch >= 0)
 | 
				
			||||||
 | 
							omap_free_dma(tusb_dma->ch);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kfree(tusb_dma);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct dma_controller *__init
 | 
				
			||||||
 | 
					dma_controller_create(struct musb *musb, void __iomem *base)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						void __iomem		*tbase = musb->ctrl_base;
 | 
				
			||||||
 | 
						struct tusb_omap_dma	*tusb_dma;
 | 
				
			||||||
 | 
						int			i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* REVISIT: Get dmareq lines used from board-*.c */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						musb_writel(musb->ctrl_base, TUSB_DMA_INT_MASK, 0x7fffffff);
 | 
				
			||||||
 | 
						musb_writel(musb->ctrl_base, TUSB_DMA_EP_MAP, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						musb_writel(tbase, TUSB_DMA_REQ_CONF,
 | 
				
			||||||
 | 
							TUSB_DMA_REQ_CONF_BURST_SIZE(2)
 | 
				
			||||||
 | 
							| TUSB_DMA_REQ_CONF_DMA_REQ_EN(0x3f)
 | 
				
			||||||
 | 
							| TUSB_DMA_REQ_CONF_DMA_REQ_ASSER(2));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tusb_dma = kzalloc(sizeof(struct tusb_omap_dma), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!tusb_dma)
 | 
				
			||||||
 | 
							goto cleanup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tusb_dma->musb = musb;
 | 
				
			||||||
 | 
						tusb_dma->tbase = musb->ctrl_base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tusb_dma->ch = -1;
 | 
				
			||||||
 | 
						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)
 | 
				
			||||||
 | 
							tusb_dma->multichannel = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < MAX_DMAREQ; i++) {
 | 
				
			||||||
 | 
							struct dma_channel	*ch;
 | 
				
			||||||
 | 
							struct tusb_omap_dma_ch	*chdat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ch = kzalloc(sizeof(struct dma_channel), GFP_KERNEL);
 | 
				
			||||||
 | 
							if (!ch)
 | 
				
			||||||
 | 
								goto cleanup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dma_channel_pool[i] = ch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							chdat = kzalloc(sizeof(struct tusb_omap_dma_ch), GFP_KERNEL);
 | 
				
			||||||
 | 
							if (!chdat)
 | 
				
			||||||
 | 
								goto cleanup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ch->status = MUSB_DMA_STATUS_UNKNOWN;
 | 
				
			||||||
 | 
							ch->private_data = chdat;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &tusb_dma->controller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cleanup:
 | 
				
			||||||
 | 
						dma_controller_destroy(&tusb_dma->controller);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										70
									
								
								include/linux/usb/musb.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								include/linux/usb/musb.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,70 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This is used to for host and peripheral modes of the driver for
 | 
				
			||||||
 | 
					 * Inventra (Multidrop) Highspeed Dual-Role Controllers:  (M)HDRC.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Board initialization should put one of these into dev->platform_data,
 | 
				
			||||||
 | 
					 * probably on some platform_device named "musb_hdrc".  It encapsulates
 | 
				
			||||||
 | 
					 * key configuration differences between boards.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* The USB role is defined by the connector used on the board, so long as
 | 
				
			||||||
 | 
					 * standards are being followed.  (Developer boards sometimes won't.)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					enum musb_mode {
 | 
				
			||||||
 | 
						MUSB_UNDEFINED = 0,
 | 
				
			||||||
 | 
						MUSB_HOST,		/* A or Mini-A connector */
 | 
				
			||||||
 | 
						MUSB_PERIPHERAL,	/* B or Mini-B connector */
 | 
				
			||||||
 | 
						MUSB_OTG		/* Mini-AB connector */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct clk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct musb_hdrc_platform_data {
 | 
				
			||||||
 | 
						/* MUSB_HOST, MUSB_PERIPHERAL, or MUSB_OTG */
 | 
				
			||||||
 | 
						u8		mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* for clk_get() */
 | 
				
			||||||
 | 
						const char	*clock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* (HOST or OTG) switch VBUS on/off */
 | 
				
			||||||
 | 
						int		(*set_vbus)(struct device *dev, int is_on);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* (HOST or OTG) mA/2 power supplied on (default = 8mA) */
 | 
				
			||||||
 | 
						u8		power;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* (PERIPHERAL) mA/2 max power consumed (default = 100mA) */
 | 
				
			||||||
 | 
						u8		min_power;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* (HOST or OTG) msec/2 after VBUS on till power good */
 | 
				
			||||||
 | 
						u8		potpgt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* TBD:  chip defaults should probably go someplace else,
 | 
				
			||||||
 | 
						 * e.g. number of tx/rx endpoints, etc
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						unsigned	multipoint:1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Power the device on or off */
 | 
				
			||||||
 | 
						int		(*set_power)(int state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Turn device clock on or off */
 | 
				
			||||||
 | 
						int		(*set_clock)(struct clk *clock, int is_on);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* TUSB 6010 support */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define	TUSB6010_OSCCLK_60	16667	/* psec/clk @ 60.0 MHz */
 | 
				
			||||||
 | 
					#define	TUSB6010_REFCLK_24	41667	/* psec/clk @ 24.0 MHz XI */
 | 
				
			||||||
 | 
					#define	TUSB6010_REFCLK_19	52083	/* psec/clk @ 19.2 MHz CLKIN */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef	CONFIG_ARCH_OMAP2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int __init tusb6010_setup_interface(
 | 
				
			||||||
 | 
							struct musb_hdrc_platform_data *data,
 | 
				
			||||||
 | 
							unsigned ps_refclk, unsigned waitpin,
 | 
				
			||||||
 | 
							unsigned async_cs, unsigned sync_cs,
 | 
				
			||||||
 | 
							unsigned irq, unsigned dmachan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int tusb6010_platform_retime(unsigned is_refclk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif	/* OMAP2 */
 | 
				
			||||||
		Loading…
	
		Reference in a new issue