USB patches for 3.20-rc1
Here's the big pull request for the USB driver tree for 3.20-rc1. Nothing major happening here, just lots of gadget driver updates, new device ids, and a bunch of cleanups. All of these have been in linux-next for a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iEYEABECAAYFAlTgtrcACgkQMUfUDdst+yn0tACgygJPNvu1l3ukNJCCpWuOErIj 3KsAnjiEXv90DLYJiVLJ4EbLPw0V9wAv =DrJx -----END PGP SIGNATURE----- Merge tag 'usb-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB patches from Greg KH: "Here's the big pull request for the USB driver tree for 3.20-rc1. Nothing major happening here, just lots of gadget driver updates, new device ids, and a bunch of cleanups. All of these have been in linux-next for a while with no reported issues" * tag 'usb-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (299 commits) usb: musb: fix device hotplug behind hub usb: dwc2: Fix a bug in reading the endpoint directions from reg. staging: emxx_udc: fix the build error usb: Retry port status check on resume to work around RH bugs Revert "usb: Reset USB-3 devices on USB-3 link bounce" uhci-hub: use HUB_CHAR_* usb: kconfig: replace PPC_OF with PPC ehci-pci: disable for Intel MID platforms (update) usb: gadget: Kconfig: use bool instead of boolean usb: musb: blackfin: remove incorrect __exit_p() USB: fix use-after-free bug in usb_hcd_unlink_urb() ehci-pci: disable for Intel MID platforms usb: host: pci_quirks: joing string literals USB: add flag for HCDs that can't receive wakeup requests (isp1760-hcd) USB: usbfs: allow URBs to be reaped after disconnection cdc-acm: kill unnecessary messages cdc-acm: add sanity checks usb: phy: phy-generic: Fix USB PHY gpio reset usb: dwc2: fix USB core dependencies usb: renesas_usbhs: fix NULL pointer dereference in dma_release_channel() ...
This commit is contained in:
		
				commit
				
					
						e29876723f
					
				
			
		
					 184 changed files with 9308 additions and 3049 deletions
				
			
		
							
								
								
									
										265
									
								
								Documentation/ABI/testing/configfs-usb-gadget-uvc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								Documentation/ABI/testing/configfs-usb-gadget-uvc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,265 @@
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	UVC function directory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							streaming_maxburst	- 0..15 (ss only)
 | 
				
			||||||
 | 
							streaming_maxpacket	- 1..1023 (fs), 1..3072 (hs/ss)
 | 
				
			||||||
 | 
							streaming_interval	- 1..16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/control
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Control descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/control/class
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Class descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/control/class/ss
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Super speed control class descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/control/class/fs
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Full speed control class descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/control/terminal
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Terminal descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/control/terminal/output
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Output terminal descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/control/terminal/output/default
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Default output terminal descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							All attributes read only:
 | 
				
			||||||
 | 
							iTerminal	- index of string descriptor
 | 
				
			||||||
 | 
							bSourceID 	- id of the terminal to which this terminal
 | 
				
			||||||
 | 
									is connected
 | 
				
			||||||
 | 
							bAssocTerminal	- id of the input terminal to which this output
 | 
				
			||||||
 | 
									terminal is associated
 | 
				
			||||||
 | 
							wTerminalType	- terminal type
 | 
				
			||||||
 | 
							bTerminalID	- a non-zero id of this terminal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/control/terminal/camera
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Camera terminal descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/control/terminal/camera/default
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Default camera terminal descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							All attributes read only:
 | 
				
			||||||
 | 
							bmControls		- bitmap specifying which controls are
 | 
				
			||||||
 | 
										supported for the video stream
 | 
				
			||||||
 | 
							wOcularFocalLength	- the value of Locular
 | 
				
			||||||
 | 
							wObjectiveFocalLengthMax- the value of Lmin
 | 
				
			||||||
 | 
							wObjectiveFocalLengthMin- the value of Lmax
 | 
				
			||||||
 | 
							iTerminal		- index of string descriptor
 | 
				
			||||||
 | 
							bAssocTerminal		- id of the output terminal to which
 | 
				
			||||||
 | 
										this terminal is connected
 | 
				
			||||||
 | 
							wTerminalType		- terminal type
 | 
				
			||||||
 | 
							bTerminalID		- a non-zero id of this terminal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/control/processing
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Processing unit descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/control/processing/default
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Default processing unit descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							All attributes read only:
 | 
				
			||||||
 | 
							iProcessing	- index of string descriptor
 | 
				
			||||||
 | 
							bmControls	- bitmap specifying which controls are
 | 
				
			||||||
 | 
									supported for the video stream
 | 
				
			||||||
 | 
							wMaxMultiplier	- maximum digital magnification x100
 | 
				
			||||||
 | 
							bSourceID	- id of the terminal to which this unit is
 | 
				
			||||||
 | 
									connected
 | 
				
			||||||
 | 
							bUnitID		- a non-zero id of this unit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/control/header
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Control header descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/control/header/name
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Specific control header descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dwClockFrequency
 | 
				
			||||||
 | 
					bcdUVC
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/streaming
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Streaming descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/class
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Streaming class descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/class/ss
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Super speed streaming class descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/class/hs
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	High speed streaming class descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/class/fs
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Full speed streaming class descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/color_matching
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Color matching descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/color_matching/default
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Default color matching descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							All attributes read only:
 | 
				
			||||||
 | 
							bMatrixCoefficients	- matrix used to compute luma and
 | 
				
			||||||
 | 
										chroma values from the color primaries
 | 
				
			||||||
 | 
							bTransferCharacteristics- optoelectronic transfer
 | 
				
			||||||
 | 
										characteristic of the source picutre,
 | 
				
			||||||
 | 
										also called the gamma function
 | 
				
			||||||
 | 
							bColorPrimaries		- color primaries and the reference
 | 
				
			||||||
 | 
										white
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/mjpeg
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	MJPEG format descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/mjpeg/name
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Specific MJPEG format descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							All attributes read only,
 | 
				
			||||||
 | 
							except bmaControls and bDefaultFrameIndex:
 | 
				
			||||||
 | 
							bmaControls		- this format's data for bmaControls in
 | 
				
			||||||
 | 
										the streaming header
 | 
				
			||||||
 | 
							bmInterfaceFlags	- specifies interlace information,
 | 
				
			||||||
 | 
										read-only
 | 
				
			||||||
 | 
							bAspectRatioY		- the X dimension of the picture aspect
 | 
				
			||||||
 | 
										ratio, read-only
 | 
				
			||||||
 | 
							bAspectRatioX		- the Y dimension of the picture aspect
 | 
				
			||||||
 | 
										ratio, read-only
 | 
				
			||||||
 | 
							bmFlags			- characteristics of this format,
 | 
				
			||||||
 | 
										read-only
 | 
				
			||||||
 | 
							bDefaultFrameIndex	- optimum frame index for this stream
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/mjpeg/name/name
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Specific MJPEG frame descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dwFrameInterval		- indicates how frame interval can be
 | 
				
			||||||
 | 
										programmed; a number of values
 | 
				
			||||||
 | 
										separated by newline can be specified
 | 
				
			||||||
 | 
							dwDefaultFrameInterval	- the frame interval the device would
 | 
				
			||||||
 | 
										like to use as default
 | 
				
			||||||
 | 
							dwMaxVideoFrameBufferSize- the maximum number of bytes the
 | 
				
			||||||
 | 
										compressor will produce for a video
 | 
				
			||||||
 | 
										frame or still image
 | 
				
			||||||
 | 
							dwMaxBitRate		- the maximum bit rate at the shortest
 | 
				
			||||||
 | 
										frame interval in bps
 | 
				
			||||||
 | 
							dwMinBitRate		- the minimum bit rate at the longest
 | 
				
			||||||
 | 
										frame interval in bps
 | 
				
			||||||
 | 
							wHeight			- height of decoded bitmap frame in px
 | 
				
			||||||
 | 
							wWidth			- width of decoded bitmam frame in px
 | 
				
			||||||
 | 
							bmCapabilities		- still image support, fixed frame-rate
 | 
				
			||||||
 | 
										support
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/uncompressed
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Uncompressed format descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/uncompressed/name
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Specific uncompressed format descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bmaControls		- this format's data for bmaControls in
 | 
				
			||||||
 | 
										the streaming header
 | 
				
			||||||
 | 
							bmInterfaceFlags	- specifies interlace information,
 | 
				
			||||||
 | 
										read-only
 | 
				
			||||||
 | 
							bAspectRatioY		- the X dimension of the picture aspect
 | 
				
			||||||
 | 
										ratio, read-only
 | 
				
			||||||
 | 
							bAspectRatioX		- the Y dimension of the picture aspect
 | 
				
			||||||
 | 
										ratio, read-only
 | 
				
			||||||
 | 
							bDefaultFrameIndex	- optimum frame index for this stream
 | 
				
			||||||
 | 
							bBitsPerPixel		- number of bits per pixel used to
 | 
				
			||||||
 | 
										specify color in the decoded video
 | 
				
			||||||
 | 
										frame
 | 
				
			||||||
 | 
							guidFormat		- globally unique id used to identify
 | 
				
			||||||
 | 
										stream-encoding format
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/uncompressed/name/name
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Specific uncompressed frame descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dwFrameInterval		- indicates how frame interval can be
 | 
				
			||||||
 | 
										programmed; a number of values
 | 
				
			||||||
 | 
										separated by newline can be specified
 | 
				
			||||||
 | 
							dwDefaultFrameInterval	- the frame interval the device would
 | 
				
			||||||
 | 
										like to use as default
 | 
				
			||||||
 | 
							dwMaxVideoFrameBufferSize- the maximum number of bytes the
 | 
				
			||||||
 | 
										compressor will produce for a video
 | 
				
			||||||
 | 
										frame or still image
 | 
				
			||||||
 | 
							dwMaxBitRate		- the maximum bit rate at the shortest
 | 
				
			||||||
 | 
										frame interval in bps
 | 
				
			||||||
 | 
							dwMinBitRate		- the minimum bit rate at the longest
 | 
				
			||||||
 | 
										frame interval in bps
 | 
				
			||||||
 | 
							wHeight			- height of decoded bitmap frame in px
 | 
				
			||||||
 | 
							wWidth			- width of decoded bitmam frame in px
 | 
				
			||||||
 | 
							bmCapabilities		- still image support, fixed frame-rate
 | 
				
			||||||
 | 
										support
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/header
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Streaming header descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/header/name
 | 
				
			||||||
 | 
					Date:		Dec 2014
 | 
				
			||||||
 | 
					KernelVersion:	3.20
 | 
				
			||||||
 | 
					Description:	Specific streaming header descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							All attributes read only:
 | 
				
			||||||
 | 
							bTriggerUsage		- how the host software will respond to
 | 
				
			||||||
 | 
										a hardware trigger interrupt event
 | 
				
			||||||
 | 
							bTriggerSupport		- flag specifying if hardware
 | 
				
			||||||
 | 
										triggering is supported
 | 
				
			||||||
 | 
							bStillCaptureMethod	- method of still image caputre
 | 
				
			||||||
 | 
										supported
 | 
				
			||||||
 | 
							bTerminalLink		- id of the output terminal to which
 | 
				
			||||||
 | 
										the video endpoint of this interface
 | 
				
			||||||
 | 
										is connected
 | 
				
			||||||
 | 
							bmInfo			- capabilities of this video streaming
 | 
				
			||||||
 | 
										interface
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,7 @@ Required properties (port (child) node):
 | 
				
			||||||
		  filled in "reg". It can also contain the offset of the system configuration
 | 
							  filled in "reg". It can also contain the offset of the system configuration
 | 
				
			||||||
		  registers used as glue-logic to setup the device for SATA/PCIe or USB3
 | 
							  registers used as glue-logic to setup the device for SATA/PCIe or USB3
 | 
				
			||||||
		  devices.
 | 
							  devices.
 | 
				
			||||||
 | 
					- st,syscfg	: Offset of the parent configuration register.
 | 
				
			||||||
- resets	: phandle to the parent reset controller.
 | 
					- resets	: phandle to the parent reset controller.
 | 
				
			||||||
- reset-names	: Associated name must be "miphy-sw-rst".
 | 
					- reset-names	: Associated name must be "miphy-sw-rst".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,18 +55,12 @@ example:
 | 
				
			||||||
			phy_port0: port@9b22000 {
 | 
								phy_port0: port@9b22000 {
 | 
				
			||||||
				reg = <0x9b22000 0xff>,
 | 
									reg = <0x9b22000 0xff>,
 | 
				
			||||||
				      <0x9b09000 0xff>,
 | 
									      <0x9b09000 0xff>,
 | 
				
			||||||
				      <0x9b04000 0xff>,
 | 
									      <0x9b04000 0xff>;
 | 
				
			||||||
				      <0x114 0x4>, /* sysctrl MiPHY cntrl */
 | 
					 | 
				
			||||||
				      <0x818 0x4>, /* sysctrl MiPHY status*/
 | 
					 | 
				
			||||||
				      <0xe0  0x4>, /* sysctrl PCIe */
 | 
					 | 
				
			||||||
				      <0xec  0x4>; /* sysctrl SATA */
 | 
					 | 
				
			||||||
				reg-names = "sata-up",
 | 
									reg-names = "sata-up",
 | 
				
			||||||
					    "pcie-up",
 | 
										    "pcie-up",
 | 
				
			||||||
					    "pipew",
 | 
										    "pipew";
 | 
				
			||||||
					    "miphy-ctrl-glue",
 | 
					
 | 
				
			||||||
					    "miphy-status-glue",
 | 
									st,syscfg = <0x114 0x818 0xe0 0xec>;
 | 
				
			||||||
					    "pcie-glue",
 | 
					 | 
				
			||||||
					    "sata-glue";
 | 
					 | 
				
			||||||
				#phy-cells = <1>;
 | 
									#phy-cells = <1>;
 | 
				
			||||||
				st,osc-rdy;
 | 
									st,osc-rdy;
 | 
				
			||||||
				reset-names = "miphy-sw-rst";
 | 
									reset-names = "miphy-sw-rst";
 | 
				
			||||||
| 
						 | 
					@ -75,18 +70,13 @@ example:
 | 
				
			||||||
			phy_port1: port@9b2a000 {
 | 
								phy_port1: port@9b2a000 {
 | 
				
			||||||
				reg = <0x9b2a000 0xff>,
 | 
									reg = <0x9b2a000 0xff>,
 | 
				
			||||||
				      <0x9b19000 0xff>,
 | 
									      <0x9b19000 0xff>,
 | 
				
			||||||
				      <0x9b14000 0xff>,
 | 
									      <0x9b14000 0xff>;
 | 
				
			||||||
				      <0x118 0x4>,
 | 
					 | 
				
			||||||
				      <0x81c 0x4>,
 | 
					 | 
				
			||||||
				      <0xe4  0x4>,
 | 
					 | 
				
			||||||
				      <0xf0  0x4>;
 | 
					 | 
				
			||||||
				reg-names = "sata-up",
 | 
									reg-names = "sata-up",
 | 
				
			||||||
					    "pcie-up",
 | 
										    "pcie-up",
 | 
				
			||||||
					    "pipew",
 | 
										    "pipew";
 | 
				
			||||||
					    "miphy-ctrl-glue",
 | 
					
 | 
				
			||||||
					    "miphy-status-glue",
 | 
									st,syscfg = <0x118 0x81c 0xe4 0xf0>;
 | 
				
			||||||
					    "pcie-glue",
 | 
					
 | 
				
			||||||
					    "sata-glue";
 | 
					 | 
				
			||||||
				#phy-cells = <1>;
 | 
									#phy-cells = <1>;
 | 
				
			||||||
				st,osc-force-ext;
 | 
									st,osc-force-ext;
 | 
				
			||||||
				reset-names = "miphy-sw-rst";
 | 
									reset-names = "miphy-sw-rst";
 | 
				
			||||||
| 
						 | 
					@ -95,13 +85,12 @@ example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			phy_port2: port@8f95000 {
 | 
								phy_port2: port@8f95000 {
 | 
				
			||||||
				reg = <0x8f95000 0xff>,
 | 
									reg = <0x8f95000 0xff>,
 | 
				
			||||||
				      <0x8f90000 0xff>,
 | 
									      <0x8f90000 0xff>;
 | 
				
			||||||
				      <0x11c 0x4>,
 | 
					 | 
				
			||||||
				      <0x820 0x4>;
 | 
					 | 
				
			||||||
				reg-names = "pipew",
 | 
									reg-names = "pipew",
 | 
				
			||||||
				    "usb3-up",
 | 
										    "usb3-up";
 | 
				
			||||||
				    "miphy-ctrl-glue",
 | 
					
 | 
				
			||||||
				    "miphy-status-glue";
 | 
									st,syscfg = <0x11c 0x820>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				#phy-cells = <1>;
 | 
									#phy-cells = <1>;
 | 
				
			||||||
				reset-names = "miphy-sw-rst";
 | 
									reset-names = "miphy-sw-rst";
 | 
				
			||||||
				resets = <&softreset STIH407_MIPHY2_SOFTRESET>;
 | 
									resets = <&softreset STIH407_MIPHY2_SOFTRESET>;
 | 
				
			||||||
| 
						 | 
					@ -125,4 +114,4 @@ example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Macro definitions for the supported miphy configuration can be found in:
 | 
					Macro definitions for the supported miphy configuration can be found in:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include/dt-bindings/phy/phy-miphy28lp.h
 | 
					include/dt-bindings/phy/phy.h
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										37
									
								
								Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,37 @@
 | 
				
			||||||
 | 
					ROCKCHIP USB2 PHY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Required properties:
 | 
				
			||||||
 | 
					 - compatible: rockchip,rk3288-usb-phy
 | 
				
			||||||
 | 
					 - rockchip,grf : phandle to the syscon managing the "general
 | 
				
			||||||
 | 
					   register files"
 | 
				
			||||||
 | 
					 - #address-cells: should be 1
 | 
				
			||||||
 | 
					 - #size-cells: should be 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Sub-nodes:
 | 
				
			||||||
 | 
					Each PHY should be represented as a sub-node.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Sub-nodes
 | 
				
			||||||
 | 
					required properties:
 | 
				
			||||||
 | 
					- #phy-cells: should be 0
 | 
				
			||||||
 | 
					- reg: PHY configure reg address offset in GRF
 | 
				
			||||||
 | 
							"0x320" - for PHY attach to OTG controller
 | 
				
			||||||
 | 
							"0x334" - for PHY attach to HOST0 controller
 | 
				
			||||||
 | 
							"0x348" - for PHY attach to HOST1 controller
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Optional Properties:
 | 
				
			||||||
 | 
					- clocks : phandle + clock specifier for the phy clocks
 | 
				
			||||||
 | 
					- clock-names: string, clock name, must be "phyclk"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					usbphy: phy {
 | 
				
			||||||
 | 
						compatible = "rockchip,rk3288-usb-phy";
 | 
				
			||||||
 | 
						rockchip,grf = <&grf>;
 | 
				
			||||||
 | 
						#address-cells = <1>;
 | 
				
			||||||
 | 
						#size-cells = <0>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usbphy0: usb-phy0 {
 | 
				
			||||||
 | 
							#phy-cells = <0>;
 | 
				
			||||||
 | 
							reg = <0x320>;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -3,8 +3,8 @@ Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Required properties:
 | 
					Required properties:
 | 
				
			||||||
- compatible : should be "samsung,s5pv210-mipi-video-phy";
 | 
					- compatible : should be "samsung,s5pv210-mipi-video-phy";
 | 
				
			||||||
- reg : offset and length of the MIPI DPHY register set;
 | 
					 | 
				
			||||||
- #phy-cells : from the generic phy bindings, must be 1;
 | 
					- #phy-cells : from the generic phy bindings, must be 1;
 | 
				
			||||||
 | 
					- syscon - phandle to the PMU system controller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
For "samsung,s5pv210-mipi-video-phy" compatible PHYs the second cell in
 | 
					For "samsung,s5pv210-mipi-video-phy" compatible PHYs the second cell in
 | 
				
			||||||
the PHY specifier identifies the PHY and its meaning is as follows:
 | 
					the PHY specifier identifies the PHY and its meaning is as follows:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -51,7 +51,10 @@ usb1: gadget@fffa4000 {
 | 
				
			||||||
Atmel High-Speed USB device controller
 | 
					Atmel High-Speed USB device controller
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Required properties:
 | 
					Required properties:
 | 
				
			||||||
 - compatible: Should be "atmel,at91sam9rl-udc"
 | 
					 - compatible: Should be one of the following
 | 
				
			||||||
 | 
						       "at91sam9rl-udc"
 | 
				
			||||||
 | 
						       "at91sam9g45-udc"
 | 
				
			||||||
 | 
						       "sama5d3-udc"
 | 
				
			||||||
 - reg: Address and length of the register set for the device
 | 
					 - reg: Address and length of the register set for the device
 | 
				
			||||||
 - interrupts: Should contain usba interrupt
 | 
					 - interrupts: Should contain usba interrupt
 | 
				
			||||||
 - ep childnode: To specify the number of endpoints and their properties.
 | 
					 - ep childnode: To specify the number of endpoints and their properties.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,6 +20,10 @@ Optional properties:
 | 
				
			||||||
Refer to phy/phy-bindings.txt for generic phy consumer properties
 | 
					Refer to phy/phy-bindings.txt for generic phy consumer properties
 | 
				
			||||||
- dr_mode: shall be one of "host", "peripheral" and "otg"
 | 
					- dr_mode: shall be one of "host", "peripheral" and "otg"
 | 
				
			||||||
  Refer to usb/generic.txt
 | 
					  Refer to usb/generic.txt
 | 
				
			||||||
 | 
					- g-use-dma: enable dma usage in gadget driver.
 | 
				
			||||||
 | 
					- g-rx-fifo-size: size of rx fifo size in gadget mode.
 | 
				
			||||||
 | 
					- g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget mode.
 | 
				
			||||||
 | 
					- g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) in gadget mode.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Example:
 | 
					Example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,8 @@ Optional properties:
 | 
				
			||||||
			 function should be enabled
 | 
								 function should be enabled
 | 
				
			||||||
  - phys: phandle + phy specifier pair
 | 
					  - phys: phandle + phy specifier pair
 | 
				
			||||||
  - phy-names: must be "usb"
 | 
					  - phy-names: must be "usb"
 | 
				
			||||||
 | 
					  - dmas: Must contain a list of references to DMA specifiers.
 | 
				
			||||||
 | 
					  - dma-names : Must contain a list of DMA names, "tx" or "rx".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Example:
 | 
					Example:
 | 
				
			||||||
	usbhs: usb@e6590000 {
 | 
						usbhs: usb@e6590000 {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@ Optional properties:
 | 
				
			||||||
 - big-endian-regs : boolean, set this for hcds with big-endian registers
 | 
					 - big-endian-regs : boolean, set this for hcds with big-endian registers
 | 
				
			||||||
 - big-endian-desc : boolean, set this for hcds with big-endian descriptors
 | 
					 - big-endian-desc : boolean, set this for hcds with big-endian descriptors
 | 
				
			||||||
 - big-endian : boolean, for hcds with big-endian-regs + big-endian-desc
 | 
					 - big-endian : boolean, for hcds with big-endian-regs + big-endian-desc
 | 
				
			||||||
 | 
					 - needs-reset-on-resume : boolean, set this to force EHCI reset after resume
 | 
				
			||||||
 - clocks : a list of phandle + clock specifier pairs
 | 
					 - clocks : a list of phandle + clock specifier pairs
 | 
				
			||||||
 - phys : phandle + phy specifier pair
 | 
					 - phys : phandle + phy specifier pair
 | 
				
			||||||
 - phy-names : "usb"
 | 
					 - phy-names : "usb"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,10 +13,15 @@ Optional properties:
 | 
				
			||||||
- clock-frequency: the clock frequency (in Hz) that the PHY clock must
 | 
					- clock-frequency: the clock frequency (in Hz) that the PHY clock must
 | 
				
			||||||
  be configured to.
 | 
					  be configured to.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- vcc-supply: phandle to the regulator that provides RESET to the PHY.
 | 
					- vcc-supply: phandle to the regulator that provides power to the PHY.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- reset-gpios: Should specify the GPIO for reset.
 | 
					- reset-gpios: Should specify the GPIO for reset.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- vbus-detect-gpio: should specify the GPIO detecting a VBus insertion
 | 
				
			||||||
 | 
					                    (see Documentation/devicetree/bindings/gpio/gpio.txt)
 | 
				
			||||||
 | 
					- vbus-regulator : should specifiy the regulator supplying current drawn from
 | 
				
			||||||
 | 
					  the VBus line (see Documentation/devicetree/bindings/regulator/regulator.txt).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Example:
 | 
					Example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hsusb1_phy {
 | 
						hsusb1_phy {
 | 
				
			||||||
| 
						 | 
					@ -26,8 +31,11 @@ Example:
 | 
				
			||||||
		clock-names = "main_clk";
 | 
							clock-names = "main_clk";
 | 
				
			||||||
		vcc-supply = <&hsusb1_vcc_regulator>;
 | 
							vcc-supply = <&hsusb1_vcc_regulator>;
 | 
				
			||||||
		reset-gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
 | 
							reset-gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
 | 
				
			||||||
 | 
							vbus-detect-gpio = <&gpio2 13 GPIO_ACTIVE_HIGH>;
 | 
				
			||||||
 | 
							vbus-regulator = <&vbus_regulator>;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
hsusb1_phy is a NOP USB PHY device that gets its clock from an oscillator
 | 
					hsusb1_phy is a NOP USB PHY device that gets its clock from an oscillator
 | 
				
			||||||
and expects that clock to be configured to 19.2MHz by the NOP PHY driver.
 | 
					and expects that clock to be configured to 19.2MHz by the NOP PHY driver.
 | 
				
			||||||
hsusb1_vcc_regulator provides power to the PHY and GPIO 7 controls RESET.
 | 
					hsusb1_vcc_regulator provides power to the PHY and GPIO 7 controls RESET.
 | 
				
			||||||
 | 
					GPIO 13 detects VBus insertion, and accordingly notifies the vbus-regulator.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										728
									
								
								Documentation/usb/gadget-testing.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										728
									
								
								Documentation/usb/gadget-testing.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,728 @@
 | 
				
			||||||
 | 
					This file summarizes information on basic testing of USB functions
 | 
				
			||||||
 | 
					provided by gadgets.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. ACM function
 | 
				
			||||||
 | 
					2. ECM function
 | 
				
			||||||
 | 
					3. ECM subset function
 | 
				
			||||||
 | 
					4. EEM function
 | 
				
			||||||
 | 
					5. FFS function
 | 
				
			||||||
 | 
					6. HID function
 | 
				
			||||||
 | 
					7. LOOPBACK function
 | 
				
			||||||
 | 
					8. MASS STORAGE function
 | 
				
			||||||
 | 
					9. MIDI function
 | 
				
			||||||
 | 
					10. NCM function
 | 
				
			||||||
 | 
					11. OBEX function
 | 
				
			||||||
 | 
					12. PHONET function
 | 
				
			||||||
 | 
					13. RNDIS function
 | 
				
			||||||
 | 
					14. SERIAL function
 | 
				
			||||||
 | 
					15. SOURCESINK function
 | 
				
			||||||
 | 
					16. UAC1 function
 | 
				
			||||||
 | 
					17. UAC2 function
 | 
				
			||||||
 | 
					18. UVC function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. ACM function
 | 
				
			||||||
 | 
					===============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function is provided by usb_f_acm.ko module.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Function-specific configfs interface
 | 
				
			||||||
 | 
					------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function name to use when creating the function directory is "acm".
 | 
				
			||||||
 | 
					The ACM function provides just one attribute in its function directory:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						port_num
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The attribute is read-only.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There can be at most 4 ACM/generic serial/OBEX ports in the system.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing the ACM function
 | 
				
			||||||
 | 
					------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On the host: cat > /dev/ttyACM<X>
 | 
				
			||||||
 | 
					On the device : cat /dev/ttyGS<Y>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					then the other way round
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On the device: cat > /dev/ttyGS<Y>
 | 
				
			||||||
 | 
					On the host: cat /dev/ttyACM<X>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. ECM function
 | 
				
			||||||
 | 
					===============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function is provided by usb_f_ecm.ko module.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Function-specific configfs interface
 | 
				
			||||||
 | 
					------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function name to use when creating the function directory is "ecm".
 | 
				
			||||||
 | 
					The ECM function provides these attributes in its function directory:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ifname		- network device interface name associated with this
 | 
				
			||||||
 | 
								function instance
 | 
				
			||||||
 | 
						qmult		- queue length multiplier for high and super speed
 | 
				
			||||||
 | 
						host_addr	- MAC address of host's end of this
 | 
				
			||||||
 | 
								Ethernet over USB link
 | 
				
			||||||
 | 
						dev_addr	- MAC address of device's end of this
 | 
				
			||||||
 | 
								Ethernet over USB link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					and after creating the functions/ecm.<instance name> they contain default
 | 
				
			||||||
 | 
					values: qmult is 5, dev_addr and host_addr are randomly selected.
 | 
				
			||||||
 | 
					Except for ifname they can be written to until the function is linked to a
 | 
				
			||||||
 | 
					configuration. The ifname is read-only and contains the name of the interface
 | 
				
			||||||
 | 
					which was assigned by the net core, e. g. usb0.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing the ECM function
 | 
				
			||||||
 | 
					------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Configure IP addresses of the device and the host. Then:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On the device: ping <host's IP>
 | 
				
			||||||
 | 
					On the host: ping <device's IP>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3. ECM subset function
 | 
				
			||||||
 | 
					======================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function is provided by usb_f_ecm_subset.ko module.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Function-specific configfs interface
 | 
				
			||||||
 | 
					------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function name to use when creating the function directory is "geth".
 | 
				
			||||||
 | 
					The ECM subset function provides these attributes in its function directory:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ifname		- network device interface name associated with this
 | 
				
			||||||
 | 
								function instance
 | 
				
			||||||
 | 
						qmult		- queue length multiplier for high and super speed
 | 
				
			||||||
 | 
						host_addr	- MAC address of host's end of this
 | 
				
			||||||
 | 
								Ethernet over USB link
 | 
				
			||||||
 | 
						dev_addr	- MAC address of device's end of this
 | 
				
			||||||
 | 
								Ethernet over USB link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					and after creating the functions/ecm.<instance name> they contain default
 | 
				
			||||||
 | 
					values: qmult is 5, dev_addr and host_addr are randomly selected.
 | 
				
			||||||
 | 
					Except for ifname they can be written to until the function is linked to a
 | 
				
			||||||
 | 
					configuration. The ifname is read-only and contains the name of the interface
 | 
				
			||||||
 | 
					which was assigned by the net core, e. g. usb0.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing the ECM subset function
 | 
				
			||||||
 | 
					-------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Configure IP addresses of the device and the host. Then:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On the device: ping <host's IP>
 | 
				
			||||||
 | 
					On the host: ping <device's IP>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					4. EEM function
 | 
				
			||||||
 | 
					===============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function is provided by usb_f_eem.ko module.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Function-specific configfs interface
 | 
				
			||||||
 | 
					------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function name to use when creating the function directory is "eem".
 | 
				
			||||||
 | 
					The EEM function provides these attributes in its function directory:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ifname		- network device interface name associated with this
 | 
				
			||||||
 | 
								function instance
 | 
				
			||||||
 | 
						qmult		- queue length multiplier for high and super speed
 | 
				
			||||||
 | 
						host_addr	- MAC address of host's end of this
 | 
				
			||||||
 | 
								Ethernet over USB link
 | 
				
			||||||
 | 
						dev_addr	- MAC address of device's end of this
 | 
				
			||||||
 | 
								Ethernet over USB link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					and after creating the functions/eem.<instance name> they contain default
 | 
				
			||||||
 | 
					values: qmult is 5, dev_addr and host_addr are randomly selected.
 | 
				
			||||||
 | 
					Except for ifname they can be written to until the function is linked to a
 | 
				
			||||||
 | 
					configuration. The ifname is read-only and contains the name of the interface
 | 
				
			||||||
 | 
					which was assigned by the net core, e. g. usb0.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing the EEM function
 | 
				
			||||||
 | 
					------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Configure IP addresses of the device and the host. Then:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On the device: ping <host's IP>
 | 
				
			||||||
 | 
					On the host: ping <device's IP>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					5. FFS function
 | 
				
			||||||
 | 
					===============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function is provided by usb_f_fs.ko module.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Function-specific configfs interface
 | 
				
			||||||
 | 
					------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function name to use when creating the function directory is "ffs".
 | 
				
			||||||
 | 
					The function directory is intentionally empty and not modifiable.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					After creating the directory there is a new instance (a "device") of FunctionFS
 | 
				
			||||||
 | 
					available in the system. Once a "device" is available, the user should follow
 | 
				
			||||||
 | 
					the standard procedure for using FunctionFS (mount it, run the userspace
 | 
				
			||||||
 | 
					process which implements the function proper). The gadget should be enabled
 | 
				
			||||||
 | 
					by writing a suitable string to usb_gadget/<gadget>/UDC.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing the FFS function
 | 
				
			||||||
 | 
					------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On the device: start the function's userspace daemon, enable the gadget
 | 
				
			||||||
 | 
					On the host: use the USB function provided by the device
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					6. HID function
 | 
				
			||||||
 | 
					===============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function is provided by usb_f_hid.ko module.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Function-specific configfs interface
 | 
				
			||||||
 | 
					------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function name to use when creating the function directory is "hid".
 | 
				
			||||||
 | 
					The HID function provides these attributes in its function directory:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protocol	- HID protocol to use
 | 
				
			||||||
 | 
						report_desc	- data to be used in HID reports, except data
 | 
				
			||||||
 | 
								passed with /dev/hidg<X>
 | 
				
			||||||
 | 
						report_length	- HID report length
 | 
				
			||||||
 | 
						subclass	- HID subclass to use
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For a keyboard the protocol and the subclass are 1, the report_length is 8,
 | 
				
			||||||
 | 
					while the report_desc is:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ hd my_report_desc
 | 
				
			||||||
 | 
					00000000  05 01 09 06 a1 01 05 07  19 e0 29 e7 15 00 25 01  |..........)...%.|
 | 
				
			||||||
 | 
					00000010  75 01 95 08 81 02 95 01  75 08 81 03 95 05 75 01  |u.......u.....u.|
 | 
				
			||||||
 | 
					00000020  05 08 19 01 29 05 91 02  95 01 75 03 91 03 95 06  |....).....u.....|
 | 
				
			||||||
 | 
					00000030  75 08 15 00 25 65 05 07  19 00 29 65 81 00 c0     |u...%e....)e...|
 | 
				
			||||||
 | 
					0000003f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Such a sequence of bytes can be stored to the attribute with echo:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ echo -ne \\x05\\x01\\x09\\x06\\xa1.....
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing the HID function
 | 
				
			||||||
 | 
					------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Device:
 | 
				
			||||||
 | 
					- create the gadget
 | 
				
			||||||
 | 
					- connect the gadget to a host, preferably not the one used
 | 
				
			||||||
 | 
					to control the gadget
 | 
				
			||||||
 | 
					- run a program which writes to /dev/hidg<N>, e.g.
 | 
				
			||||||
 | 
					a userspace program found in Documentation/usb/gadget_hid.txt:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ ./hid_gadget_test /dev/hidg0 keyboard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Host:
 | 
				
			||||||
 | 
					- observe the keystrokes from the gadget
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					7. LOOPBACK function
 | 
				
			||||||
 | 
					====================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function is provided by usb_f_ss_lb.ko module.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Function-specific configfs interface
 | 
				
			||||||
 | 
					------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function name to use when creating the function directory is "Loopback".
 | 
				
			||||||
 | 
					The LOOPBACK function provides these attributes in its function directory:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						qlen		- depth of loopback queue
 | 
				
			||||||
 | 
						bulk_buflen	- buffer length
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing the LOOPBACK function
 | 
				
			||||||
 | 
					-----------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					device: run the gadget
 | 
				
			||||||
 | 
					host: test-usb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					http://www.linux-usb.org/usbtest/testusb.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					8. MASS STORAGE function
 | 
				
			||||||
 | 
					========================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function is provided by usb_f_mass_storage.ko module.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Function-specific configfs interface
 | 
				
			||||||
 | 
					------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function name to use when creating the function directory is "mass_storage".
 | 
				
			||||||
 | 
					The MASS STORAGE function provides these attributes in its directory:
 | 
				
			||||||
 | 
					files:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						stall		- Set to permit function to halt bulk endpoints.
 | 
				
			||||||
 | 
								Disabled on some USB devices known not to work
 | 
				
			||||||
 | 
								correctly. You should set it to true.
 | 
				
			||||||
 | 
						num_buffers	- Number of pipeline buffers. Valid numbers
 | 
				
			||||||
 | 
								are 2..4. Available only if
 | 
				
			||||||
 | 
								CONFIG_USB_GADGET_DEBUG_FILES is set.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					and a default lun.0 directory corresponding to SCSI LUN #0.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A new lun can be added with mkdir:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ mkdir functions/mass_storage.0/partition.5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Lun numbering does not have to be continuous, except for lun #0 which is
 | 
				
			||||||
 | 
					created by default. A maximum of 8 luns can be specified and they all must be
 | 
				
			||||||
 | 
					named following the <name>.<number> scheme. The numbers can be 0..8.
 | 
				
			||||||
 | 
					Probably a good convention is to name the luns "lun.<number>",
 | 
				
			||||||
 | 
					although it is not mandatory.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In each lun directory there are the following attribute files:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						file		- The path to the backing file for the LUN.
 | 
				
			||||||
 | 
								Required if LUN is not marked as removable.
 | 
				
			||||||
 | 
						ro		- Flag specifying access to the LUN shall be
 | 
				
			||||||
 | 
								read-only. This is implied if CD-ROM emulation
 | 
				
			||||||
 | 
								is enabled as well as when it was impossible
 | 
				
			||||||
 | 
								to open "filename" in R/W mode.
 | 
				
			||||||
 | 
						removable	- Flag specifying that LUN shall be indicated as
 | 
				
			||||||
 | 
								being removable.
 | 
				
			||||||
 | 
						cdrom		- Flag specifying that LUN shall be reported as
 | 
				
			||||||
 | 
								being a CD-ROM.
 | 
				
			||||||
 | 
						nofua		- Flag specifying that FUA flag
 | 
				
			||||||
 | 
								in SCSI WRITE(10,12)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing the MASS STORAGE function
 | 
				
			||||||
 | 
					---------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					device: connect the gadget, enable it
 | 
				
			||||||
 | 
					host: dmesg, see the USB drives appear (if system configured to automatically
 | 
				
			||||||
 | 
					mount)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					9. MIDI function
 | 
				
			||||||
 | 
					================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function is provided by usb_f_midi.ko module.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Function-specific configfs interface
 | 
				
			||||||
 | 
					------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function name to use when creating the function directory is "midi".
 | 
				
			||||||
 | 
					The MIDI function provides these attributes in its function directory:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buflen		- MIDI buffer length
 | 
				
			||||||
 | 
						id		- ID string for the USB MIDI adapter
 | 
				
			||||||
 | 
						in_ports	- number of MIDI input ports
 | 
				
			||||||
 | 
						index		- index value for the USB MIDI adapter
 | 
				
			||||||
 | 
						out_ports	- number of MIDI output ports
 | 
				
			||||||
 | 
						qlen		- USB read request queue length
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing the MIDI function
 | 
				
			||||||
 | 
					-------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There are two cases: playing a mid from the gadget to
 | 
				
			||||||
 | 
					the host and playing a mid from the host to the gadget.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1) Playing a mid from the gadget to the host
 | 
				
			||||||
 | 
					host)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ arecordmidi -l
 | 
				
			||||||
 | 
					 Port    Client name                      Port name
 | 
				
			||||||
 | 
					 14:0    Midi Through                     Midi Through Port-0
 | 
				
			||||||
 | 
					 24:0    MIDI Gadget                      MIDI Gadget MIDI 1
 | 
				
			||||||
 | 
					$ arecordmidi -p 24:0 from_gadget.mid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gadget)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ aplaymidi -l
 | 
				
			||||||
 | 
					 Port    Client name                      Port name
 | 
				
			||||||
 | 
					 20:0    f_midi                           f_midi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ aplaymidi -p 20:0 to_host.mid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2) Playing a mid from the host to the gadget
 | 
				
			||||||
 | 
					gadget)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ arecordmidi -l
 | 
				
			||||||
 | 
					 Port    Client name                      Port name
 | 
				
			||||||
 | 
					 20:0    f_midi                           f_midi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ arecordmidi -p 20:0 from_host.mid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					host)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ aplaymidi -l
 | 
				
			||||||
 | 
					 Port    Client name                      Port name
 | 
				
			||||||
 | 
					 14:0    Midi Through                     Midi Through Port-0
 | 
				
			||||||
 | 
					 24:0    MIDI Gadget                      MIDI Gadget MIDI 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ aplaymidi -p24:0 to_gadget.mid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The from_gadget.mid should sound identical to the to_host.mid.
 | 
				
			||||||
 | 
					The from_host.id should sound identical to the to_gadget.mid.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MIDI files can be played to speakers/headphones with e.g. timidity installed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ aplaymidi -l
 | 
				
			||||||
 | 
					 Port    Client name                      Port name
 | 
				
			||||||
 | 
					 14:0    Midi Through                     Midi Through Port-0
 | 
				
			||||||
 | 
					 24:0    MIDI Gadget                      MIDI Gadget MIDI 1
 | 
				
			||||||
 | 
					128:0    TiMidity                         TiMidity port 0
 | 
				
			||||||
 | 
					128:1    TiMidity                         TiMidity port 1
 | 
				
			||||||
 | 
					128:2    TiMidity                         TiMidity port 2
 | 
				
			||||||
 | 
					128:3    TiMidity                         TiMidity port 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ aplaymidi -p 128:0 file.mid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MIDI ports can be logically connected using the aconnect utility, e.g.:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ aconnect 24:0 128:0 # try it on the host
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					After the gadget's MIDI port is connected to timidity's MIDI port,
 | 
				
			||||||
 | 
					whatever is played at the gadget side with aplaymidi -l is audible
 | 
				
			||||||
 | 
					in host's speakers/headphones.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					10. NCM function
 | 
				
			||||||
 | 
					================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function is provided by usb_f_ncm.ko module.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Function-specific configfs interface
 | 
				
			||||||
 | 
					------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function name to use when creating the function directory is "ncm".
 | 
				
			||||||
 | 
					The NCM function provides these attributes in its function directory:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ifname		- network device interface name associated with this
 | 
				
			||||||
 | 
								function instance
 | 
				
			||||||
 | 
						qmult		- queue length multiplier for high and super speed
 | 
				
			||||||
 | 
						host_addr	- MAC address of host's end of this
 | 
				
			||||||
 | 
								Ethernet over USB link
 | 
				
			||||||
 | 
						dev_addr	- MAC address of device's end of this
 | 
				
			||||||
 | 
								Ethernet over USB link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					and after creating the functions/ncm.<instance name> they contain default
 | 
				
			||||||
 | 
					values: qmult is 5, dev_addr and host_addr are randomly selected.
 | 
				
			||||||
 | 
					Except for ifname they can be written to until the function is linked to a
 | 
				
			||||||
 | 
					configuration. The ifname is read-only and contains the name of the interface
 | 
				
			||||||
 | 
					which was assigned by the net core, e. g. usb0.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing the NCM function
 | 
				
			||||||
 | 
					------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Configure IP addresses of the device and the host. Then:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On the device: ping <host's IP>
 | 
				
			||||||
 | 
					On the host: ping <device's IP>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					11. OBEX function
 | 
				
			||||||
 | 
					=================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function is provided by usb_f_obex.ko module.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Function-specific configfs interface
 | 
				
			||||||
 | 
					------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function name to use when creating the function directory is "obex".
 | 
				
			||||||
 | 
					The OBEX function provides just one attribute in its function directory:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						port_num
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The attribute is read-only.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There can be at most 4 ACM/generic serial/OBEX ports in the system.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing the OBEX function
 | 
				
			||||||
 | 
					-------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On device: seriald -f /dev/ttyGS<Y> -s 1024
 | 
				
			||||||
 | 
					On host: serialc -v <vendorID> -p <productID> -i<interface#> -a1 -s1024 \
 | 
				
			||||||
 | 
					             -t<out endpoint addr> -r<in endpoint addr>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					where seriald and serialc are Felipe's utilities found here:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					https://git.gitorious.org/usb/usb-tools.git master
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					12. PHONET function
 | 
				
			||||||
 | 
					===================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function is provided by usb_f_phonet.ko module.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Function-specific configfs interface
 | 
				
			||||||
 | 
					------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function name to use when creating the function directory is "phonet".
 | 
				
			||||||
 | 
					The PHONET function provides just one attribute in its function directory:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ifname		- network device interface name associated with this
 | 
				
			||||||
 | 
								function instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing the PHONET function
 | 
				
			||||||
 | 
					---------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It is not possible to test the SOCK_STREAM protocol without a specific piece
 | 
				
			||||||
 | 
					of hardware, so only SOCK_DGRAM has been tested. For the latter to work,
 | 
				
			||||||
 | 
					in the past I had to apply the patch mentioned here:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					http://www.spinics.net/lists/linux-usb/msg85689.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					These tools are required:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git://git.gitorious.org/meego-cellular/phonet-utils.git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On the host:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ ./phonet -a 0x10 -i usbpn0
 | 
				
			||||||
 | 
					$ ./pnroute add 0x6c usbpn0
 | 
				
			||||||
 | 
					$./pnroute add 0x10 usbpn0
 | 
				
			||||||
 | 
					$ ifconfig usbpn0 up
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On the device:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ ./phonet -a 0x6c -i upnlink0
 | 
				
			||||||
 | 
					$ ./pnroute add 0x10 upnlink0
 | 
				
			||||||
 | 
					$ ifconfig upnlink0 up
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Then a test program can be used:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					http://www.spinics.net/lists/linux-usb/msg85690.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On the device:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ ./pnxmit -a 0x6c -r
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On the host:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ ./pnxmit -a 0x10 -s 0x6c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					As a result some data should be sent from host to device.
 | 
				
			||||||
 | 
					Then the other way round:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On the host:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ ./pnxmit -a 0x10 -r
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On the device:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ ./pnxmit -a 0x6c -s 0x10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					13. RNDIS function
 | 
				
			||||||
 | 
					==================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function is provided by usb_f_rndis.ko module.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Function-specific configfs interface
 | 
				
			||||||
 | 
					------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function name to use when creating the function directory is "rndis".
 | 
				
			||||||
 | 
					The RNDIS function provides these attributes in its function directory:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ifname		- network device interface name associated with this
 | 
				
			||||||
 | 
								function instance
 | 
				
			||||||
 | 
						qmult		- queue length multiplier for high and super speed
 | 
				
			||||||
 | 
						host_addr	- MAC address of host's end of this
 | 
				
			||||||
 | 
								Ethernet over USB link
 | 
				
			||||||
 | 
						dev_addr	- MAC address of device's end of this
 | 
				
			||||||
 | 
								Ethernet over USB link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					and after creating the functions/rndis.<instance name> they contain default
 | 
				
			||||||
 | 
					values: qmult is 5, dev_addr and host_addr are randomly selected.
 | 
				
			||||||
 | 
					Except for ifname they can be written to until the function is linked to a
 | 
				
			||||||
 | 
					configuration. The ifname is read-only and contains the name of the interface
 | 
				
			||||||
 | 
					which was assigned by the net core, e. g. usb0.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					By default there can be only 1 RNDIS interface in the system.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing the RNDIS function
 | 
				
			||||||
 | 
					--------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Configure IP addresses of the device and the host. Then:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On the device: ping <host's IP>
 | 
				
			||||||
 | 
					On the host: ping <device's IP>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					14. SERIAL function
 | 
				
			||||||
 | 
					===================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function is provided by usb_f_gser.ko module.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Function-specific configfs interface
 | 
				
			||||||
 | 
					------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function name to use when creating the function directory is "gser".
 | 
				
			||||||
 | 
					The SERIAL function provides just one attribute in its function directory:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						port_num
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The attribute is read-only.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There can be at most 4 ACM/generic serial/OBEX ports in the system.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing the SERIAL function
 | 
				
			||||||
 | 
					---------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On host: insmod usbserial
 | 
				
			||||||
 | 
						 echo VID PID >/sys/bus/usb-serial/drivers/generic/new_id
 | 
				
			||||||
 | 
					On host: cat > /dev/ttyUSB<X>
 | 
				
			||||||
 | 
					On target: cat /dev/ttyGS<Y>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					then the other way round
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On target: cat > /dev/ttyGS<Y>
 | 
				
			||||||
 | 
					On host: cat /dev/ttyUSB<X>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					15. SOURCESINK function
 | 
				
			||||||
 | 
					=======================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function is provided by usb_f_ss_lb.ko module.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Function-specific configfs interface
 | 
				
			||||||
 | 
					------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function name to use when creating the function directory is "SourceSink".
 | 
				
			||||||
 | 
					The SOURCESINK function provides these attributes in its function directory:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pattern		- 0 (all zeros), 1 (mod63), 2 (none)
 | 
				
			||||||
 | 
						isoc_interval	- 1..16
 | 
				
			||||||
 | 
						isoc_maxpacket	- 0 - 1023 (fs), 0 - 1024 (hs/ss)
 | 
				
			||||||
 | 
						isoc_mult	- 0..2 (hs/ss only)
 | 
				
			||||||
 | 
						isoc_maxburst	- 0..15 (ss only)
 | 
				
			||||||
 | 
						bulk_buflen	- buffer length
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing the SOURCESINK function
 | 
				
			||||||
 | 
					-------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					device: run the gadget
 | 
				
			||||||
 | 
					host: test-usb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					http://www.linux-usb.org/usbtest/testusb.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					16. UAC1 function
 | 
				
			||||||
 | 
					=================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function is provided by usb_f_uac1.ko module.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Function-specific configfs interface
 | 
				
			||||||
 | 
					------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function name to use when creating the function directory is "uac1".
 | 
				
			||||||
 | 
					The uac1 function provides these attributes in its function directory:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						audio_buf_size - audio buffer size
 | 
				
			||||||
 | 
						fn_cap - capture pcm device file name
 | 
				
			||||||
 | 
						fn_cntl - control device file name
 | 
				
			||||||
 | 
						fn_play - playback pcm device file name
 | 
				
			||||||
 | 
						req_buf_size - ISO OUT endpoint request buffer size
 | 
				
			||||||
 | 
						req_count - ISO OUT endpoint request count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The attributes have sane default values.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing the UAC1 function
 | 
				
			||||||
 | 
					-------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					device: run the gadget
 | 
				
			||||||
 | 
					host: aplay -l # should list our USB Audio Gadget
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					17. UAC2 function
 | 
				
			||||||
 | 
					=================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function is provided by usb_f_uac2.ko module.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Function-specific configfs interface
 | 
				
			||||||
 | 
					------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function name to use when creating the function directory is "uac2".
 | 
				
			||||||
 | 
					The uac2 function provides these attributes in its function directory:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						chmask - capture channel mask
 | 
				
			||||||
 | 
						c_srate - capture sampling rate
 | 
				
			||||||
 | 
						c_ssize - capture sample size (bytes)
 | 
				
			||||||
 | 
						p_chmask - playback channel mask
 | 
				
			||||||
 | 
						p_srate - playback sampling rate
 | 
				
			||||||
 | 
						p_ssize - playback sample size (bytes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The attributes have sane default values.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing the UAC2 function
 | 
				
			||||||
 | 
					-------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					device: run the gadget
 | 
				
			||||||
 | 
					host: aplay -l # should list our USB Audio Gadget
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This function does not require real hardware support, it just
 | 
				
			||||||
 | 
					sends a stream of audio data to/from the host. In order to
 | 
				
			||||||
 | 
					actually hear something at the device side, a command similar
 | 
				
			||||||
 | 
					to this must be used at the device side:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ arecord -f dat -t wav -D hw:2,0 | aplay -D hw:0,0 &
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					e.g.:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$ arecord -f dat -t wav -D hw:CARD=UAC2Gadget,DEV=0 | \
 | 
				
			||||||
 | 
					aplay -D default:CARD=OdroidU3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					18. UVC function
 | 
				
			||||||
 | 
					================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function is provided by usb_f_uvc.ko module.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Function-specific configfs interface
 | 
				
			||||||
 | 
					------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The function name to use when creating the function directory is "uvc".
 | 
				
			||||||
 | 
					The uvc function provides these attributes in its function directory:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						streaming_interval - interval for polling endpoint for data transfers
 | 
				
			||||||
 | 
						streaming_maxburst - bMaxBurst for super speed companion descriptor
 | 
				
			||||||
 | 
						streaming_maxpacket - maximum packet size this endpoint is capable of
 | 
				
			||||||
 | 
								      sending or receiving when this configuration is
 | 
				
			||||||
 | 
								      selected
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There are also "control" and "streaming" subdirectories, each of which contain
 | 
				
			||||||
 | 
					a number of their subdirectories. There are some sane defaults provided, but
 | 
				
			||||||
 | 
					the user must provide the following:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						control header - create in control/header, link from control/class/fs
 | 
				
			||||||
 | 
								and/or control/class/ss
 | 
				
			||||||
 | 
						streaming header - create in streaming/header, link from
 | 
				
			||||||
 | 
								streaming/class/fs and/or streaming/class/hs and/or
 | 
				
			||||||
 | 
								streaming/class/ss
 | 
				
			||||||
 | 
						format description - create in streaming/mjpeg and/or
 | 
				
			||||||
 | 
								streaming/uncompressed
 | 
				
			||||||
 | 
						frame description - create in streaming/mjpeg/<format> and/or in
 | 
				
			||||||
 | 
								streaming/uncompressed/<format>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Each frame description contains frame interval specification, and each
 | 
				
			||||||
 | 
					such specification consists of a number of lines with an inverval value
 | 
				
			||||||
 | 
					in each line. The rules stated above are best illustrated with an example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# mkdir functions/uvc.usb0/control/header/h
 | 
				
			||||||
 | 
					# cd functions/uvc.usb0/control/header/h
 | 
				
			||||||
 | 
					# ln -s header/h class/fs
 | 
				
			||||||
 | 
					# ln -s header/h class/ss
 | 
				
			||||||
 | 
					# mkdir -p functions/uvc.usb0/streaming/uncompressed/u/360p
 | 
				
			||||||
 | 
					# cat <<EOF > functions/uvc.usb0/streaming/uncompressed/u/360p/dwFrameInterval
 | 
				
			||||||
 | 
					666666
 | 
				
			||||||
 | 
					1000000
 | 
				
			||||||
 | 
					5000000
 | 
				
			||||||
 | 
					EOF
 | 
				
			||||||
 | 
					# cd $GADGET_CONFIGFS_ROOT
 | 
				
			||||||
 | 
					# mkdir functions/uvc.usb0/streaming/header/h
 | 
				
			||||||
 | 
					# cd functions/uvc.usb0/streaming/header/h
 | 
				
			||||||
 | 
					# ln -s ../../uncompressed/u
 | 
				
			||||||
 | 
					# cd ../../class/fs
 | 
				
			||||||
 | 
					# ln -s ../../header/h
 | 
				
			||||||
 | 
					# cd ../../class/hs
 | 
				
			||||||
 | 
					# ln -s ../../header/h
 | 
				
			||||||
 | 
					# cd ../../class/ss
 | 
				
			||||||
 | 
					# ln -s ../../header/h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing the UVC function
 | 
				
			||||||
 | 
					------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					device: run the gadget, modprobe vivid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# uvc-gadget -u /dev/video<uvc video node #> -v /dev/video<vivid video node #>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					where uvc-gadget is this program:
 | 
				
			||||||
 | 
					http://git.ideasonboard.org/uvc-gadget.git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					with these patches:
 | 
				
			||||||
 | 
					http://www.spinics.net/lists/linux-usb/msg99220.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					host: luvcview -f yuv
 | 
				
			||||||
| 
						 | 
					@ -236,8 +236,12 @@ I:  If#= 0 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=serial
 | 
				
			||||||
E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
 | 
					E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
 | 
				
			||||||
E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
 | 
					E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
 | 
				
			||||||
 | 
					
 | 
				
			||||||
You must explicitly load the usbserial driver with parameters to
 | 
					You must load the usbserial driver and explicitly set its parameters
 | 
				
			||||||
configure it to recognize the gadget serial device, like this:
 | 
					to configure it to recognize the gadget serial device, like this:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  echo 0x0525 0xA4A6 >/sys/bus/usb-serial/drivers/generic/new_id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The legacy way is to use module parameters:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  modprobe usbserial vendor=0x0525 product=0xA4A6
 | 
					  modprobe usbserial vendor=0x0525 product=0xA4A6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,7 +72,7 @@ to listen on a single bus, otherwise, to listen on all buses, type:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# cat /sys/kernel/debug/usb/usbmon/0u > /tmp/1.mon.out
 | 
					# cat /sys/kernel/debug/usb/usbmon/0u > /tmp/1.mon.out
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This process will be reading until killed. Naturally, the output can be
 | 
					This process will read until it is killed. Naturally, the output can be
 | 
				
			||||||
redirected to a desirable location. This is preferred, because it is going
 | 
					redirected to a desirable location. This is preferred, because it is going
 | 
				
			||||||
to be quite long.
 | 
					to be quite long.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3048,7 +3048,7 @@ S:	Maintained
 | 
				
			||||||
F:	drivers/platform/x86/dell-wmi.c
 | 
					F:	drivers/platform/x86/dell-wmi.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DESIGNWARE USB2 DRD IP DRIVER
 | 
					DESIGNWARE USB2 DRD IP DRIVER
 | 
				
			||||||
M:	Paul Zimmerman <paulz@synopsys.com>
 | 
					M:	John Youn <johnyoun@synopsys.com>
 | 
				
			||||||
L:	linux-usb@vger.kernel.org
 | 
					L:	linux-usb@vger.kernel.org
 | 
				
			||||||
T:	git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 | 
					T:	git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 | 
				
			||||||
S:	Maintained
 | 
					S:	Maintained
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -77,7 +77,7 @@ static DEFINE_MUTEX(octeon2_usb_clocks_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int octeon2_usb_clock_start_cnt;
 | 
					static int octeon2_usb_clock_start_cnt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void octeon2_usb_clocks_start(void)
 | 
					static void octeon2_usb_clocks_start(struct device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u64 div;
 | 
						u64 div;
 | 
				
			||||||
	union cvmx_uctlx_if_ena if_ena;
 | 
						union cvmx_uctlx_if_ena if_ena;
 | 
				
			||||||
| 
						 | 
					@ -86,6 +86,8 @@ static void octeon2_usb_clocks_start(void)
 | 
				
			||||||
	union cvmx_uctlx_uphy_portx_ctl_status port_ctl_status;
 | 
						union cvmx_uctlx_uphy_portx_ctl_status port_ctl_status;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	unsigned long io_clk_64_to_ns;
 | 
						unsigned long io_clk_64_to_ns;
 | 
				
			||||||
 | 
						u32 clock_rate = 12000000;
 | 
				
			||||||
 | 
						bool is_crystal_clock = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&octeon2_usb_clocks_mutex);
 | 
						mutex_lock(&octeon2_usb_clocks_mutex);
 | 
				
			||||||
| 
						 | 
					@ -96,6 +98,28 @@ static void octeon2_usb_clocks_start(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate();
 | 
						io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dev->of_node) {
 | 
				
			||||||
 | 
							struct device_node *uctl_node;
 | 
				
			||||||
 | 
							const char *clock_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uctl_node = of_get_parent(dev->of_node);
 | 
				
			||||||
 | 
							if (!uctl_node) {
 | 
				
			||||||
 | 
								dev_err(dev, "No UCTL device node\n");
 | 
				
			||||||
 | 
								goto exit;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							i = of_property_read_u32(uctl_node,
 | 
				
			||||||
 | 
										 "refclk-frequency", &clock_rate);
 | 
				
			||||||
 | 
							if (i) {
 | 
				
			||||||
 | 
								dev_err(dev, "No UCTL \"refclk-frequency\"\n");
 | 
				
			||||||
 | 
								goto exit;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							i = of_property_read_string(uctl_node,
 | 
				
			||||||
 | 
										    "refclk-type", &clock_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!i && strcmp("crystal", clock_type) == 0)
 | 
				
			||||||
 | 
								is_crystal_clock = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Step 1: Wait for voltages stable.  That surely happened
 | 
						 * Step 1: Wait for voltages stable.  That surely happened
 | 
				
			||||||
	 * before starting the kernel.
 | 
						 * before starting the kernel.
 | 
				
			||||||
| 
						 | 
					@ -126,9 +150,22 @@ static void octeon2_usb_clocks_start(void)
 | 
				
			||||||
	cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
 | 
						cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* 3b */
 | 
						/* 3b */
 | 
				
			||||||
	/* 12MHz crystal. */
 | 
						clk_rst_ctl.s.p_refclk_sel = is_crystal_clock ? 0 : 1;
 | 
				
			||||||
	clk_rst_ctl.s.p_refclk_sel = 0;
 | 
						switch (clock_rate) {
 | 
				
			||||||
	clk_rst_ctl.s.p_refclk_div = 0;
 | 
						default:
 | 
				
			||||||
 | 
							pr_err("Invalid UCTL clock rate of %u, using 12000000 instead\n",
 | 
				
			||||||
 | 
								clock_rate);
 | 
				
			||||||
 | 
							/* Fall through */
 | 
				
			||||||
 | 
						case 12000000:
 | 
				
			||||||
 | 
							clk_rst_ctl.s.p_refclk_div = 0;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case 24000000:
 | 
				
			||||||
 | 
							clk_rst_ctl.s.p_refclk_div = 1;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case 48000000:
 | 
				
			||||||
 | 
							clk_rst_ctl.s.p_refclk_div = 2;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
 | 
						cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* 3c */
 | 
						/* 3c */
 | 
				
			||||||
| 
						 | 
					@ -259,7 +296,7 @@ static void octeon2_usb_clocks_stop(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int octeon_ehci_power_on(struct platform_device *pdev)
 | 
					static int octeon_ehci_power_on(struct platform_device *pdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	octeon2_usb_clocks_start();
 | 
						octeon2_usb_clocks_start(&pdev->dev);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -273,15 +310,16 @@ static struct usb_ehci_pdata octeon_ehci_pdata = {
 | 
				
			||||||
#ifdef __BIG_ENDIAN
 | 
					#ifdef __BIG_ENDIAN
 | 
				
			||||||
	.big_endian_mmio	= 1,
 | 
						.big_endian_mmio	= 1,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
						.dma_mask_64	= 1,
 | 
				
			||||||
	.power_on	= octeon_ehci_power_on,
 | 
						.power_on	= octeon_ehci_power_on,
 | 
				
			||||||
	.power_off	= octeon_ehci_power_off,
 | 
						.power_off	= octeon_ehci_power_off,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __init octeon_ehci_hw_start(void)
 | 
					static void __init octeon_ehci_hw_start(struct device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	union cvmx_uctlx_ehci_ctl ehci_ctl;
 | 
						union cvmx_uctlx_ehci_ctl ehci_ctl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	octeon2_usb_clocks_start();
 | 
						octeon2_usb_clocks_start(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ehci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_EHCI_CTL(0));
 | 
						ehci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_EHCI_CTL(0));
 | 
				
			||||||
	/* Use 64-bit addressing. */
 | 
						/* Use 64-bit addressing. */
 | 
				
			||||||
| 
						 | 
					@ -294,64 +332,30 @@ static void __init octeon_ehci_hw_start(void)
 | 
				
			||||||
	octeon2_usb_clocks_stop();
 | 
						octeon2_usb_clocks_stop();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static u64 octeon_ehci_dma_mask = DMA_BIT_MASK(64);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int __init octeon_ehci_device_init(void)
 | 
					static int __init octeon_ehci_device_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct platform_device *pd;
 | 
						struct platform_device *pd;
 | 
				
			||||||
 | 
						struct device_node *ehci_node;
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct resource usb_resources[] = {
 | 
						ehci_node = of_find_node_by_name(NULL, "ehci");
 | 
				
			||||||
		{
 | 
						if (!ehci_node)
 | 
				
			||||||
			.flags	= IORESOURCE_MEM,
 | 
					 | 
				
			||||||
		}, {
 | 
					 | 
				
			||||||
			.flags	= IORESOURCE_IRQ,
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Only Octeon2 has ehci/ohci */
 | 
					 | 
				
			||||||
	if (!OCTEON_IS_MODEL(OCTEON_CN63XX))
 | 
					 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (octeon_is_simulation() || usb_disabled())
 | 
						pd = of_find_device_by_node(ehci_node);
 | 
				
			||||||
		return 0; /* No USB in the simulator. */
 | 
						if (!pd)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pd = platform_device_alloc("ehci-platform", 0);
 | 
					 | 
				
			||||||
	if (!pd) {
 | 
					 | 
				
			||||||
		ret = -ENOMEM;
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	usb_resources[0].start = 0x00016F0000000000ULL;
 | 
					 | 
				
			||||||
	usb_resources[0].end = usb_resources[0].start + 0x100;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	usb_resources[1].start = OCTEON_IRQ_USB0;
 | 
					 | 
				
			||||||
	usb_resources[1].end = OCTEON_IRQ_USB0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = platform_device_add_resources(pd, usb_resources,
 | 
					 | 
				
			||||||
					    ARRAY_SIZE(usb_resources));
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		goto fail;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pd->dev.dma_mask = &octeon_ehci_dma_mask;
 | 
					 | 
				
			||||||
	pd->dev.platform_data = &octeon_ehci_pdata;
 | 
						pd->dev.platform_data = &octeon_ehci_pdata;
 | 
				
			||||||
	octeon_ehci_hw_start();
 | 
						octeon_ehci_hw_start(&pd->dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = platform_device_add(pd);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		goto fail;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
fail:
 | 
					 | 
				
			||||||
	platform_device_put(pd);
 | 
					 | 
				
			||||||
out:
 | 
					 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
device_initcall(octeon_ehci_device_init);
 | 
					device_initcall(octeon_ehci_device_init);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int octeon_ohci_power_on(struct platform_device *pdev)
 | 
					static int octeon_ohci_power_on(struct platform_device *pdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	octeon2_usb_clocks_start();
 | 
						octeon2_usb_clocks_start(&pdev->dev);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -369,11 +373,11 @@ static struct usb_ohci_pdata octeon_ohci_pdata = {
 | 
				
			||||||
	.power_off	= octeon_ohci_power_off,
 | 
						.power_off	= octeon_ohci_power_off,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __init octeon_ohci_hw_start(void)
 | 
					static void __init octeon_ohci_hw_start(struct device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	union cvmx_uctlx_ohci_ctl ohci_ctl;
 | 
						union cvmx_uctlx_ohci_ctl ohci_ctl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	octeon2_usb_clocks_start();
 | 
						octeon2_usb_clocks_start(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ohci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_OHCI_CTL(0));
 | 
						ohci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_OHCI_CTL(0));
 | 
				
			||||||
	ohci_ctl.s.l2c_addr_msb = 0;
 | 
						ohci_ctl.s.l2c_addr_msb = 0;
 | 
				
			||||||
| 
						 | 
					@ -387,57 +391,27 @@ static void __init octeon_ohci_hw_start(void)
 | 
				
			||||||
static int __init octeon_ohci_device_init(void)
 | 
					static int __init octeon_ohci_device_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct platform_device *pd;
 | 
						struct platform_device *pd;
 | 
				
			||||||
 | 
						struct device_node *ohci_node;
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct resource usb_resources[] = {
 | 
						ohci_node = of_find_node_by_name(NULL, "ohci");
 | 
				
			||||||
		{
 | 
						if (!ohci_node)
 | 
				
			||||||
			.flags	= IORESOURCE_MEM,
 | 
					 | 
				
			||||||
		}, {
 | 
					 | 
				
			||||||
			.flags	= IORESOURCE_IRQ,
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Only Octeon2 has ehci/ohci */
 | 
					 | 
				
			||||||
	if (!OCTEON_IS_MODEL(OCTEON_CN63XX))
 | 
					 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (octeon_is_simulation() || usb_disabled())
 | 
						pd = of_find_device_by_node(ohci_node);
 | 
				
			||||||
		return 0; /* No USB in the simulator. */
 | 
						if (!pd)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
	pd = platform_device_alloc("ohci-platform", 0);
 | 
					 | 
				
			||||||
	if (!pd) {
 | 
					 | 
				
			||||||
		ret = -ENOMEM;
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	usb_resources[0].start = 0x00016F0000000400ULL;
 | 
					 | 
				
			||||||
	usb_resources[0].end = usb_resources[0].start + 0x100;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	usb_resources[1].start = OCTEON_IRQ_USB0;
 | 
					 | 
				
			||||||
	usb_resources[1].end = OCTEON_IRQ_USB0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = platform_device_add_resources(pd, usb_resources,
 | 
					 | 
				
			||||||
					    ARRAY_SIZE(usb_resources));
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		goto fail;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pd->dev.platform_data = &octeon_ohci_pdata;
 | 
						pd->dev.platform_data = &octeon_ohci_pdata;
 | 
				
			||||||
	octeon_ohci_hw_start();
 | 
						octeon_ohci_hw_start(&pd->dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = platform_device_add(pd);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		goto fail;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
fail:
 | 
					 | 
				
			||||||
	platform_device_put(pd);
 | 
					 | 
				
			||||||
out:
 | 
					 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
device_initcall(octeon_ohci_device_init);
 | 
					device_initcall(octeon_ohci_device_init);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* CONFIG_USB */
 | 
					#endif /* CONFIG_USB */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct of_device_id __initdata octeon_ids[] = {
 | 
					static struct of_device_id __initdata octeon_ids[] = {
 | 
				
			||||||
	{ .compatible = "simple-bus", },
 | 
						{ .compatible = "simple-bus", },
 | 
				
			||||||
	{ .compatible = "cavium,octeon-6335-uctl", },
 | 
						{ .compatible = "cavium,octeon-6335-uctl", },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -239,6 +239,13 @@ config PHY_QCOM_IPQ806X_SATA
 | 
				
			||||||
	depends on OF
 | 
						depends on OF
 | 
				
			||||||
	select GENERIC_PHY
 | 
						select GENERIC_PHY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config PHY_ROCKCHIP_USB
 | 
				
			||||||
 | 
						tristate "Rockchip USB2 PHY Driver"
 | 
				
			||||||
 | 
						depends on ARCH_ROCKCHIP && OF
 | 
				
			||||||
 | 
						select GENERIC_PHY
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  Enable this to support the Rockchip USB 2.0 PHY.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config PHY_ST_SPEAR1310_MIPHY
 | 
					config PHY_ST_SPEAR1310_MIPHY
 | 
				
			||||||
	tristate "ST SPEAR1310-MIPHY driver"
 | 
						tristate "ST SPEAR1310-MIPHY driver"
 | 
				
			||||||
	select GENERIC_PHY
 | 
						select GENERIC_PHY
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,6 +28,7 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2)	+= phy-exynos5250-usb2.o
 | 
				
			||||||
phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2)	+= phy-s5pv210-usb2.o
 | 
					phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2)	+= phy-s5pv210-usb2.o
 | 
				
			||||||
obj-$(CONFIG_PHY_EXYNOS5_USBDRD)	+= phy-exynos5-usbdrd.o
 | 
					obj-$(CONFIG_PHY_EXYNOS5_USBDRD)	+= phy-exynos5-usbdrd.o
 | 
				
			||||||
obj-$(CONFIG_PHY_QCOM_APQ8064_SATA)	+= phy-qcom-apq8064-sata.o
 | 
					obj-$(CONFIG_PHY_QCOM_APQ8064_SATA)	+= phy-qcom-apq8064-sata.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
 | 
				
			||||||
obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA)	+= phy-qcom-ipq806x-sata.o
 | 
					obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA)	+= phy-qcom-ipq806x-sata.o
 | 
				
			||||||
obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY)	+= phy-spear1310-miphy.o
 | 
					obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY)	+= phy-spear1310-miphy.o
 | 
				
			||||||
obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)	+= phy-spear1340-miphy.o
 | 
					obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)	+= phy-spear1340-miphy.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -118,8 +118,8 @@ static int armada375_usb_phy_probe(struct platform_device *pdev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
						res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
				
			||||||
	usb_cluster_base = devm_ioremap_resource(&pdev->dev, res);
 | 
						usb_cluster_base = devm_ioremap_resource(&pdev->dev, res);
 | 
				
			||||||
	if (!usb_cluster_base)
 | 
						if (IS_ERR(usb_cluster_base))
 | 
				
			||||||
		return -ENOMEM;
 | 
							return PTR_ERR(usb_cluster_base);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	phy = devm_phy_create(dev, NULL, &armada375_usb_phy_ops);
 | 
						phy = devm_phy_create(dev, NULL, &armada375_usb_phy_ops);
 | 
				
			||||||
	if (IS_ERR(phy)) {
 | 
						if (IS_ERR(phy)) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,19 +12,18 @@
 | 
				
			||||||
#include <linux/err.h>
 | 
					#include <linux/err.h>
 | 
				
			||||||
#include <linux/io.h>
 | 
					#include <linux/io.h>
 | 
				
			||||||
#include <linux/kernel.h>
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include <linux/mfd/syscon/exynos4-pmu.h>
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
#include <linux/of.h>
 | 
					#include <linux/of.h>
 | 
				
			||||||
#include <linux/of_address.h>
 | 
					#include <linux/of_address.h>
 | 
				
			||||||
#include <linux/phy/phy.h>
 | 
					#include <linux/phy/phy.h>
 | 
				
			||||||
#include <linux/platform_device.h>
 | 
					#include <linux/platform_device.h>
 | 
				
			||||||
 | 
					#include <linux/regmap.h>
 | 
				
			||||||
#include <linux/spinlock.h>
 | 
					#include <linux/spinlock.h>
 | 
				
			||||||
 | 
					#include <linux/mfd/syscon.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* MIPI_PHYn_CONTROL register offset: n = 0..1 */
 | 
					/* MIPI_PHYn_CONTROL reg. offset (for base address from ioremap): n = 0..1 */
 | 
				
			||||||
#define EXYNOS_MIPI_PHY_CONTROL(n)	((n) * 4)
 | 
					#define EXYNOS_MIPI_PHY_CONTROL(n)	((n) * 4)
 | 
				
			||||||
#define EXYNOS_MIPI_PHY_ENABLE		(1 << 0)
 | 
					 | 
				
			||||||
#define EXYNOS_MIPI_PHY_SRESETN		(1 << 1)
 | 
					 | 
				
			||||||
#define EXYNOS_MIPI_PHY_MRESETN		(1 << 2)
 | 
					 | 
				
			||||||
#define EXYNOS_MIPI_PHY_RESET_MASK	(3 << 1)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum exynos_mipi_phy_id {
 | 
					enum exynos_mipi_phy_id {
 | 
				
			||||||
	EXYNOS_MIPI_PHY_ID_CSIS0,
 | 
						EXYNOS_MIPI_PHY_ID_CSIS0,
 | 
				
			||||||
| 
						 | 
					@ -38,43 +37,62 @@ enum exynos_mipi_phy_id {
 | 
				
			||||||
	((id) == EXYNOS_MIPI_PHY_ID_DSIM0 || (id) == EXYNOS_MIPI_PHY_ID_DSIM1)
 | 
						((id) == EXYNOS_MIPI_PHY_ID_DSIM0 || (id) == EXYNOS_MIPI_PHY_ID_DSIM1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct exynos_mipi_video_phy {
 | 
					struct exynos_mipi_video_phy {
 | 
				
			||||||
	spinlock_t slock;
 | 
					 | 
				
			||||||
	struct video_phy_desc {
 | 
						struct video_phy_desc {
 | 
				
			||||||
		struct phy *phy;
 | 
							struct phy *phy;
 | 
				
			||||||
		unsigned int index;
 | 
							unsigned int index;
 | 
				
			||||||
	} phys[EXYNOS_MIPI_PHYS_NUM];
 | 
						} phys[EXYNOS_MIPI_PHYS_NUM];
 | 
				
			||||||
 | 
						spinlock_t slock;
 | 
				
			||||||
	void __iomem *regs;
 | 
						void __iomem *regs;
 | 
				
			||||||
 | 
						struct mutex mutex;
 | 
				
			||||||
 | 
						struct regmap *regmap;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __set_phy_state(struct exynos_mipi_video_phy *state,
 | 
					static int __set_phy_state(struct exynos_mipi_video_phy *state,
 | 
				
			||||||
			enum exynos_mipi_phy_id id, unsigned int on)
 | 
								enum exynos_mipi_phy_id id, unsigned int on)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						const unsigned int offset = EXYNOS4_MIPI_PHY_CONTROL(id / 2);
 | 
				
			||||||
	void __iomem *addr;
 | 
						void __iomem *addr;
 | 
				
			||||||
	u32 reg, reset;
 | 
						u32 val, reset;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	addr = state->regs + EXYNOS_MIPI_PHY_CONTROL(id / 2);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (is_mipi_dsim_phy_id(id))
 | 
						if (is_mipi_dsim_phy_id(id))
 | 
				
			||||||
		reset = EXYNOS_MIPI_PHY_MRESETN;
 | 
							reset = EXYNOS4_MIPI_PHY_MRESETN;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		reset = EXYNOS_MIPI_PHY_SRESETN;
 | 
							reset = EXYNOS4_MIPI_PHY_SRESETN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock(&state->slock);
 | 
						if (state->regmap) {
 | 
				
			||||||
	reg = readl(addr);
 | 
							mutex_lock(&state->mutex);
 | 
				
			||||||
	if (on)
 | 
							regmap_read(state->regmap, offset, &val);
 | 
				
			||||||
		reg |= reset;
 | 
							if (on)
 | 
				
			||||||
	else
 | 
								val |= reset;
 | 
				
			||||||
		reg &= ~reset;
 | 
							else
 | 
				
			||||||
	writel(reg, addr);
 | 
								val &= ~reset;
 | 
				
			||||||
 | 
							regmap_write(state->regmap, offset, val);
 | 
				
			||||||
 | 
							if (on)
 | 
				
			||||||
 | 
								val |= EXYNOS4_MIPI_PHY_ENABLE;
 | 
				
			||||||
 | 
							else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK))
 | 
				
			||||||
 | 
								val &= ~EXYNOS4_MIPI_PHY_ENABLE;
 | 
				
			||||||
 | 
							regmap_write(state->regmap, offset, val);
 | 
				
			||||||
 | 
							mutex_unlock(&state->mutex);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							addr = state->regs + EXYNOS_MIPI_PHY_CONTROL(id / 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Clear ENABLE bit only if MRESETN, SRESETN bits are not set. */
 | 
							spin_lock(&state->slock);
 | 
				
			||||||
	if (on)
 | 
							val = readl(addr);
 | 
				
			||||||
		reg |= EXYNOS_MIPI_PHY_ENABLE;
 | 
							if (on)
 | 
				
			||||||
	else if (!(reg & EXYNOS_MIPI_PHY_RESET_MASK))
 | 
								val |= reset;
 | 
				
			||||||
		reg &= ~EXYNOS_MIPI_PHY_ENABLE;
 | 
							else
 | 
				
			||||||
 | 
								val &= ~reset;
 | 
				
			||||||
 | 
							writel(val, addr);
 | 
				
			||||||
 | 
							/* Clear ENABLE bit only if MRESETN, SRESETN bits are not set */
 | 
				
			||||||
 | 
							if (on)
 | 
				
			||||||
 | 
								val |= EXYNOS4_MIPI_PHY_ENABLE;
 | 
				
			||||||
 | 
							else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK))
 | 
				
			||||||
 | 
								val &= ~EXYNOS4_MIPI_PHY_ENABLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							writel(val, addr);
 | 
				
			||||||
 | 
							spin_unlock(&state->slock);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	writel(reg, addr);
 | 
					 | 
				
			||||||
	spin_unlock(&state->slock);
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -118,7 +136,6 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct exynos_mipi_video_phy *state;
 | 
						struct exynos_mipi_video_phy *state;
 | 
				
			||||||
	struct device *dev = &pdev->dev;
 | 
						struct device *dev = &pdev->dev;
 | 
				
			||||||
	struct resource *res;
 | 
					 | 
				
			||||||
	struct phy_provider *phy_provider;
 | 
						struct phy_provider *phy_provider;
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -126,14 +143,22 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
 | 
				
			||||||
	if (!state)
 | 
						if (!state)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
						state->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
 | 
				
			||||||
 | 
						if (IS_ERR(state->regmap)) {
 | 
				
			||||||
 | 
							struct resource *res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	state->regs = devm_ioremap_resource(dev, res);
 | 
							dev_info(dev, "regmap lookup failed: %ld\n",
 | 
				
			||||||
	if (IS_ERR(state->regs))
 | 
								 PTR_ERR(state->regmap));
 | 
				
			||||||
		return PTR_ERR(state->regs);
 | 
					
 | 
				
			||||||
 | 
							res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
				
			||||||
 | 
							state->regs = devm_ioremap_resource(dev, res);
 | 
				
			||||||
 | 
							if (IS_ERR(state->regs))
 | 
				
			||||||
 | 
								return PTR_ERR(state->regs);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_set_drvdata(dev, state);
 | 
						dev_set_drvdata(dev, state);
 | 
				
			||||||
	spin_lock_init(&state->slock);
 | 
						spin_lock_init(&state->slock);
 | 
				
			||||||
 | 
						mutex_init(&state->mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
 | 
						for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
 | 
				
			||||||
		struct phy *phy = devm_phy_create(dev, NULL,
 | 
							struct phy *phy = devm_phy_create(dev, NULL,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -194,6 +194,14 @@
 | 
				
			||||||
#define MIPHY_SATA_BANK_NB	3
 | 
					#define MIPHY_SATA_BANK_NB	3
 | 
				
			||||||
#define MIPHY_PCIE_BANK_NB	2
 | 
					#define MIPHY_PCIE_BANK_NB	2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						SYSCFG_CTRL,
 | 
				
			||||||
 | 
						SYSCFG_STATUS,
 | 
				
			||||||
 | 
						SYSCFG_PCI,
 | 
				
			||||||
 | 
						SYSCFG_SATA,
 | 
				
			||||||
 | 
						SYSCFG_REG_MAX,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct miphy28lp_phy {
 | 
					struct miphy28lp_phy {
 | 
				
			||||||
	struct phy *phy;
 | 
						struct phy *phy;
 | 
				
			||||||
	struct miphy28lp_dev *phydev;
 | 
						struct miphy28lp_dev *phydev;
 | 
				
			||||||
| 
						 | 
					@ -211,10 +219,7 @@ struct miphy28lp_phy {
 | 
				
			||||||
	u32 sata_gen;
 | 
						u32 sata_gen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Sysconfig registers offsets needed to configure the device */
 | 
						/* Sysconfig registers offsets needed to configure the device */
 | 
				
			||||||
	u32 syscfg_miphy_ctrl;
 | 
						u32 syscfg_reg[SYSCFG_REG_MAX];
 | 
				
			||||||
	u32 syscfg_miphy_status;
 | 
					 | 
				
			||||||
	u32 syscfg_pci;
 | 
					 | 
				
			||||||
	u32 syscfg_sata;
 | 
					 | 
				
			||||||
	u8 type;
 | 
						u8 type;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -834,12 +839,12 @@ static int miphy_osc_is_ready(struct miphy28lp_phy *miphy_phy)
 | 
				
			||||||
	if (!miphy_phy->osc_rdy)
 | 
						if (!miphy_phy->osc_rdy)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!miphy_phy->syscfg_miphy_status)
 | 
						if (!miphy_phy->syscfg_reg[SYSCFG_STATUS])
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	do {
 | 
						do {
 | 
				
			||||||
		regmap_read(miphy_dev->regmap, miphy_phy->syscfg_miphy_status,
 | 
							regmap_read(miphy_dev->regmap,
 | 
				
			||||||
			    &val);
 | 
									miphy_phy->syscfg_reg[SYSCFG_STATUS], &val);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ((val & MIPHY_OSC_RDY) != MIPHY_OSC_RDY)
 | 
							if ((val & MIPHY_OSC_RDY) != MIPHY_OSC_RDY)
 | 
				
			||||||
			cpu_relax();
 | 
								cpu_relax();
 | 
				
			||||||
| 
						 | 
					@ -888,7 +893,7 @@ static int miphy28lp_setup(struct miphy28lp_phy *miphy_phy, u32 miphy_val)
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
 | 
						struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!miphy_phy->syscfg_miphy_ctrl)
 | 
						if (!miphy_phy->syscfg_reg[SYSCFG_CTRL])
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = reset_control_assert(miphy_phy->miphy_rst);
 | 
						err = reset_control_assert(miphy_phy->miphy_rst);
 | 
				
			||||||
| 
						 | 
					@ -900,7 +905,8 @@ static int miphy28lp_setup(struct miphy28lp_phy *miphy_phy, u32 miphy_val)
 | 
				
			||||||
	if (miphy_phy->osc_force_ext)
 | 
						if (miphy_phy->osc_force_ext)
 | 
				
			||||||
		miphy_val |= MIPHY_OSC_FORCE_EXT;
 | 
							miphy_val |= MIPHY_OSC_FORCE_EXT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_miphy_ctrl,
 | 
						regmap_update_bits(miphy_dev->regmap,
 | 
				
			||||||
 | 
								   miphy_phy->syscfg_reg[SYSCFG_CTRL],
 | 
				
			||||||
			   MIPHY_CTRL_MASK, miphy_val);
 | 
								   MIPHY_CTRL_MASK, miphy_val);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = reset_control_deassert(miphy_phy->miphy_rst);
 | 
						err = reset_control_deassert(miphy_phy->miphy_rst);
 | 
				
			||||||
| 
						 | 
					@ -917,8 +923,9 @@ static int miphy28lp_init_sata(struct miphy28lp_phy *miphy_phy)
 | 
				
			||||||
	struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
 | 
						struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
 | 
				
			||||||
	int err, sata_conf = SATA_CTRL_SELECT_SATA;
 | 
						int err, sata_conf = SATA_CTRL_SELECT_SATA;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((!miphy_phy->syscfg_sata) || (!miphy_phy->syscfg_pci)
 | 
						if ((!miphy_phy->syscfg_reg[SYSCFG_SATA]) ||
 | 
				
			||||||
		|| (!miphy_phy->base))
 | 
								(!miphy_phy->syscfg_reg[SYSCFG_PCI]) ||
 | 
				
			||||||
 | 
								(!miphy_phy->base))
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_info(miphy_dev->dev, "sata-up mode, addr 0x%p\n", miphy_phy->base);
 | 
						dev_info(miphy_dev->dev, "sata-up mode, addr 0x%p\n", miphy_phy->base);
 | 
				
			||||||
| 
						 | 
					@ -926,10 +933,11 @@ static int miphy28lp_init_sata(struct miphy28lp_phy *miphy_phy)
 | 
				
			||||||
	/* Configure the glue-logic */
 | 
						/* Configure the glue-logic */
 | 
				
			||||||
	sata_conf |= ((miphy_phy->sata_gen - SATA_GEN1) << SATA_SPDMODE);
 | 
						sata_conf |= ((miphy_phy->sata_gen - SATA_GEN1) << SATA_SPDMODE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_sata,
 | 
						regmap_update_bits(miphy_dev->regmap,
 | 
				
			||||||
 | 
								   miphy_phy->syscfg_reg[SYSCFG_SATA],
 | 
				
			||||||
			   SATA_CTRL_MASK, sata_conf);
 | 
								   SATA_CTRL_MASK, sata_conf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_pci,
 | 
						regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_reg[SYSCFG_PCI],
 | 
				
			||||||
			   PCIE_CTRL_MASK, SATA_CTRL_SELECT_PCIE);
 | 
								   PCIE_CTRL_MASK, SATA_CTRL_SELECT_PCIE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* MiPHY path and clocking init */
 | 
						/* MiPHY path and clocking init */
 | 
				
			||||||
| 
						 | 
					@ -951,17 +959,19 @@ static int miphy28lp_init_pcie(struct miphy28lp_phy *miphy_phy)
 | 
				
			||||||
	struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
 | 
						struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((!miphy_phy->syscfg_sata) || (!miphy_phy->syscfg_pci)
 | 
						if ((!miphy_phy->syscfg_reg[SYSCFG_SATA]) ||
 | 
				
			||||||
 | 
								(!miphy_phy->syscfg_reg[SYSCFG_PCI])
 | 
				
			||||||
		|| (!miphy_phy->base) || (!miphy_phy->pipebase))
 | 
							|| (!miphy_phy->base) || (!miphy_phy->pipebase))
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_info(miphy_dev->dev, "pcie-up mode, addr 0x%p\n", miphy_phy->base);
 | 
						dev_info(miphy_dev->dev, "pcie-up mode, addr 0x%p\n", miphy_phy->base);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Configure the glue-logic */
 | 
						/* Configure the glue-logic */
 | 
				
			||||||
	regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_sata,
 | 
						regmap_update_bits(miphy_dev->regmap,
 | 
				
			||||||
 | 
								   miphy_phy->syscfg_reg[SYSCFG_SATA],
 | 
				
			||||||
			   SATA_CTRL_MASK, SATA_CTRL_SELECT_PCIE);
 | 
								   SATA_CTRL_MASK, SATA_CTRL_SELECT_PCIE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_pci,
 | 
						regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_reg[SYSCFG_PCI],
 | 
				
			||||||
			   PCIE_CTRL_MASK, SYSCFG_PCIE_PCIE_VAL);
 | 
								   PCIE_CTRL_MASK, SYSCFG_PCIE_PCIE_VAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* MiPHY path and clocking init */
 | 
						/* MiPHY path and clocking init */
 | 
				
			||||||
| 
						 | 
					@ -1156,7 +1166,8 @@ static int miphy28lp_probe_resets(struct device_node *node,
 | 
				
			||||||
static int miphy28lp_of_probe(struct device_node *np,
 | 
					static int miphy28lp_of_probe(struct device_node *np,
 | 
				
			||||||
			      struct miphy28lp_phy *miphy_phy)
 | 
								      struct miphy28lp_phy *miphy_phy)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct resource res;
 | 
						int i;
 | 
				
			||||||
 | 
						u32 ctrlreg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	miphy_phy->osc_force_ext =
 | 
						miphy_phy->osc_force_ext =
 | 
				
			||||||
		of_property_read_bool(np, "st,osc-force-ext");
 | 
							of_property_read_bool(np, "st,osc-force-ext");
 | 
				
			||||||
| 
						 | 
					@ -1175,18 +1186,10 @@ static int miphy28lp_of_probe(struct device_node *np,
 | 
				
			||||||
	if (!miphy_phy->sata_gen)
 | 
						if (!miphy_phy->sata_gen)
 | 
				
			||||||
		miphy_phy->sata_gen = SATA_GEN1;
 | 
							miphy_phy->sata_gen = SATA_GEN1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!miphy28lp_get_resource_byname(np, "miphy-ctrl-glue", &res))
 | 
						for (i = 0; i < SYSCFG_REG_MAX; i++) {
 | 
				
			||||||
		miphy_phy->syscfg_miphy_ctrl = res.start;
 | 
							if (!of_property_read_u32_index(np, "st,syscfg", i, &ctrlreg))
 | 
				
			||||||
 | 
								miphy_phy->syscfg_reg[i] = ctrlreg;
 | 
				
			||||||
	if (!miphy28lp_get_resource_byname(np, "miphy-status-glue", &res))
 | 
						}
 | 
				
			||||||
		miphy_phy->syscfg_miphy_status = res.start;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!miphy28lp_get_resource_byname(np, "pcie-glue", &res))
 | 
					 | 
				
			||||||
		miphy_phy->syscfg_pci = res.start;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!miphy28lp_get_resource_byname(np, "sata-glue", &res))
 | 
					 | 
				
			||||||
		miphy_phy->syscfg_sata = res.start;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										158
									
								
								drivers/phy/phy-rockchip-usb.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								drivers/phy/phy-rockchip-usb.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,158 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Rockchip usb PHY driver
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2014 Yunzhi Li <lyz@rock-chips.com>
 | 
				
			||||||
 | 
					 * Copyright (C) 2014 ROCKCHIP, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 2 of the License.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/clk.h>
 | 
				
			||||||
 | 
					#include <linux/io.h>
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					#include <linux/mutex.h>
 | 
				
			||||||
 | 
					#include <linux/of.h>
 | 
				
			||||||
 | 
					#include <linux/of_address.h>
 | 
				
			||||||
 | 
					#include <linux/phy/phy.h>
 | 
				
			||||||
 | 
					#include <linux/platform_device.h>
 | 
				
			||||||
 | 
					#include <linux/regulator/consumer.h>
 | 
				
			||||||
 | 
					#include <linux/reset.h>
 | 
				
			||||||
 | 
					#include <linux/regmap.h>
 | 
				
			||||||
 | 
					#include <linux/mfd/syscon.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * The higher 16-bit of this register is used for write protection
 | 
				
			||||||
 | 
					 * only if BIT(13 + 16) set to 1 the BIT(13) can be written.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define SIDDQ_WRITE_ENA	BIT(29)
 | 
				
			||||||
 | 
					#define SIDDQ_ON		BIT(13)
 | 
				
			||||||
 | 
					#define SIDDQ_OFF		(0 << 13)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct rockchip_usb_phy {
 | 
				
			||||||
 | 
						unsigned int	reg_offset;
 | 
				
			||||||
 | 
						struct regmap	*reg_base;
 | 
				
			||||||
 | 
						struct clk	*clk;
 | 
				
			||||||
 | 
						struct phy	*phy;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy,
 | 
				
			||||||
 | 
										   bool siddq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return regmap_write(phy->reg_base, phy->reg_offset,
 | 
				
			||||||
 | 
								    SIDDQ_WRITE_ENA | (siddq ? SIDDQ_ON : SIDDQ_OFF));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rockchip_usb_phy_power_off(struct phy *_phy)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Power down usb phy analog blocks by set siddq 1 */
 | 
				
			||||||
 | 
						ret = rockchip_usb_phy_power(phy, 1);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						clk_disable_unprepare(phy->clk);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rockchip_usb_phy_power_on(struct phy *_phy)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = clk_prepare_enable(phy->clk);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Power up usb phy analog blocks by set siddq 0 */
 | 
				
			||||||
 | 
						ret = rockchip_usb_phy_power(phy, 0);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct phy_ops ops = {
 | 
				
			||||||
 | 
						.power_on	= rockchip_usb_phy_power_on,
 | 
				
			||||||
 | 
						.power_off	= rockchip_usb_phy_power_off,
 | 
				
			||||||
 | 
						.owner		= THIS_MODULE,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rockchip_usb_phy_probe(struct platform_device *pdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct device *dev = &pdev->dev;
 | 
				
			||||||
 | 
						struct rockchip_usb_phy *rk_phy;
 | 
				
			||||||
 | 
						struct phy_provider *phy_provider;
 | 
				
			||||||
 | 
						struct device_node *child;
 | 
				
			||||||
 | 
						struct regmap *grf;
 | 
				
			||||||
 | 
						unsigned int reg_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
 | 
				
			||||||
 | 
						if (IS_ERR(grf)) {
 | 
				
			||||||
 | 
							dev_err(&pdev->dev, "Missing rockchip,grf property\n");
 | 
				
			||||||
 | 
							return PTR_ERR(grf);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for_each_available_child_of_node(dev->of_node, child) {
 | 
				
			||||||
 | 
							rk_phy = devm_kzalloc(dev, sizeof(*rk_phy), GFP_KERNEL);
 | 
				
			||||||
 | 
							if (!rk_phy)
 | 
				
			||||||
 | 
								return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (of_property_read_u32(child, "reg", ®_offset)) {
 | 
				
			||||||
 | 
								dev_err(dev, "missing reg property in node %s\n",
 | 
				
			||||||
 | 
									child->name);
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rk_phy->reg_offset = reg_offset;
 | 
				
			||||||
 | 
							rk_phy->reg_base = grf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rk_phy->clk = of_clk_get_by_name(child, "phyclk");
 | 
				
			||||||
 | 
							if (IS_ERR(rk_phy->clk))
 | 
				
			||||||
 | 
								rk_phy->clk = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rk_phy->phy = devm_phy_create(dev, child, &ops);
 | 
				
			||||||
 | 
							if (IS_ERR(rk_phy->phy)) {
 | 
				
			||||||
 | 
								dev_err(dev, "failed to create PHY\n");
 | 
				
			||||||
 | 
								return PTR_ERR(rk_phy->phy);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							phy_set_drvdata(rk_phy->phy, rk_phy);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 | 
				
			||||||
 | 
						return PTR_ERR_OR_ZERO(phy_provider);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct of_device_id rockchip_usb_phy_dt_ids[] = {
 | 
				
			||||||
 | 
						{ .compatible = "rockchip,rk3288-usb-phy" },
 | 
				
			||||||
 | 
						{}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MODULE_DEVICE_TABLE(of, rockchip_usb_phy_dt_ids);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct platform_driver rockchip_usb_driver = {
 | 
				
			||||||
 | 
						.probe		= rockchip_usb_phy_probe,
 | 
				
			||||||
 | 
						.driver		= {
 | 
				
			||||||
 | 
							.name	= "rockchip-usb-phy",
 | 
				
			||||||
 | 
							.owner	= THIS_MODULE,
 | 
				
			||||||
 | 
							.of_match_table = rockchip_usb_phy_dt_ids,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module_platform_driver(rockchip_usb_driver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MODULE_AUTHOR("Yunzhi Li <lyz@rock-chips.com>");
 | 
				
			||||||
 | 
					MODULE_DESCRIPTION("Rockchip USB 2.0 PHY driver");
 | 
				
			||||||
 | 
					MODULE_LICENSE("GPL v2");
 | 
				
			||||||
| 
						 | 
					@ -28,6 +28,7 @@
 | 
				
			||||||
#include <linux/delay.h>
 | 
					#include <linux/delay.h>
 | 
				
			||||||
#include <linux/phy/omap_control_phy.h>
 | 
					#include <linux/phy/omap_control_phy.h>
 | 
				
			||||||
#include <linux/of_platform.h>
 | 
					#include <linux/of_platform.h>
 | 
				
			||||||
 | 
					#include <linux/spinlock.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define	PLL_STATUS		0x00000004
 | 
					#define	PLL_STATUS		0x00000004
 | 
				
			||||||
#define	PLL_GO			0x00000008
 | 
					#define	PLL_GO			0x00000008
 | 
				
			||||||
| 
						 | 
					@ -82,6 +83,10 @@ struct ti_pipe3 {
 | 
				
			||||||
	struct clk		*refclk;
 | 
						struct clk		*refclk;
 | 
				
			||||||
	struct clk		*div_clk;
 | 
						struct clk		*div_clk;
 | 
				
			||||||
	struct pipe3_dpll_map	*dpll_map;
 | 
						struct pipe3_dpll_map	*dpll_map;
 | 
				
			||||||
 | 
						bool			enabled;
 | 
				
			||||||
 | 
						spinlock_t		lock;	/* serialize clock enable/disable */
 | 
				
			||||||
 | 
						/* the below flag is needed specifically for SATA */
 | 
				
			||||||
 | 
						bool			refclk_enabled;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct pipe3_dpll_map dpll_map_usb[] = {
 | 
					static struct pipe3_dpll_map dpll_map_usb[] = {
 | 
				
			||||||
| 
						 | 
					@ -307,6 +312,7 @@ static int ti_pipe3_probe(struct platform_device *pdev)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	phy->dev		= &pdev->dev;
 | 
						phy->dev		= &pdev->dev;
 | 
				
			||||||
 | 
						spin_lock_init(&phy->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
 | 
						if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
 | 
				
			||||||
		match = of_match_device(of_match_ptr(ti_pipe3_id_table),
 | 
							match = of_match_device(of_match_ptr(ti_pipe3_id_table),
 | 
				
			||||||
| 
						 | 
					@ -333,21 +339,24 @@ static int ti_pipe3_probe(struct platform_device *pdev)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						phy->refclk = devm_clk_get(phy->dev, "refclk");
 | 
				
			||||||
 | 
						if (IS_ERR(phy->refclk)) {
 | 
				
			||||||
 | 
							dev_err(&pdev->dev, "unable to get refclk\n");
 | 
				
			||||||
 | 
							/* older DTBs have missing refclk in SATA PHY
 | 
				
			||||||
 | 
							 * so don't bail out in case of SATA PHY.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (!of_device_is_compatible(node, "ti,phy-pipe3-sata"))
 | 
				
			||||||
 | 
								return PTR_ERR(phy->refclk);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) {
 | 
						if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) {
 | 
				
			||||||
		phy->wkupclk = devm_clk_get(phy->dev, "wkupclk");
 | 
							phy->wkupclk = devm_clk_get(phy->dev, "wkupclk");
 | 
				
			||||||
		if (IS_ERR(phy->wkupclk)) {
 | 
							if (IS_ERR(phy->wkupclk)) {
 | 
				
			||||||
			dev_err(&pdev->dev, "unable to get wkupclk\n");
 | 
								dev_err(&pdev->dev, "unable to get wkupclk\n");
 | 
				
			||||||
			return PTR_ERR(phy->wkupclk);
 | 
								return PTR_ERR(phy->wkupclk);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		phy->refclk = devm_clk_get(phy->dev, "refclk");
 | 
					 | 
				
			||||||
		if (IS_ERR(phy->refclk)) {
 | 
					 | 
				
			||||||
			dev_err(&pdev->dev, "unable to get refclk\n");
 | 
					 | 
				
			||||||
			return PTR_ERR(phy->refclk);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		phy->wkupclk = ERR_PTR(-ENODEV);
 | 
							phy->wkupclk = ERR_PTR(-ENODEV);
 | 
				
			||||||
		phy->refclk = ERR_PTR(-ENODEV);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
 | 
						if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
 | 
				
			||||||
| 
						 | 
					@ -426,33 +435,42 @@ static int ti_pipe3_remove(struct platform_device *pdev)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_PM
 | 
					#ifdef CONFIG_PM
 | 
				
			||||||
 | 
					static int ti_pipe3_enable_refclk(struct ti_pipe3 *phy)
 | 
				
			||||||
static int ti_pipe3_runtime_suspend(struct device *dev)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ti_pipe3	*phy = dev_get_drvdata(dev);
 | 
						if (!IS_ERR(phy->refclk) && !phy->refclk_enabled) {
 | 
				
			||||||
 | 
							int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!IS_ERR(phy->wkupclk))
 | 
							ret = clk_prepare_enable(phy->refclk);
 | 
				
			||||||
		clk_disable_unprepare(phy->wkupclk);
 | 
							if (ret) {
 | 
				
			||||||
	if (!IS_ERR(phy->refclk))
 | 
								dev_err(phy->dev, "Failed to enable refclk %d\n", ret);
 | 
				
			||||||
		clk_disable_unprepare(phy->refclk);
 | 
								return ret;
 | 
				
			||||||
	if (!IS_ERR(phy->div_clk))
 | 
							}
 | 
				
			||||||
		clk_disable_unprepare(phy->div_clk);
 | 
							phy->refclk_enabled = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ti_pipe3_runtime_resume(struct device *dev)
 | 
					static void ti_pipe3_disable_refclk(struct ti_pipe3 *phy)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32 ret = 0;
 | 
						if (!IS_ERR(phy->refclk))
 | 
				
			||||||
	struct ti_pipe3	*phy = dev_get_drvdata(dev);
 | 
							clk_disable_unprepare(phy->refclk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!IS_ERR(phy->refclk)) {
 | 
						phy->refclk_enabled = false;
 | 
				
			||||||
		ret = clk_prepare_enable(phy->refclk);
 | 
					}
 | 
				
			||||||
		if (ret) {
 | 
					
 | 
				
			||||||
			dev_err(phy->dev, "Failed to enable refclk %d\n", ret);
 | 
					static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy)
 | 
				
			||||||
			goto err1;
 | 
					{
 | 
				
			||||||
		}
 | 
						int ret = 0;
 | 
				
			||||||
	}
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_irqsave(&phy->lock, flags);
 | 
				
			||||||
 | 
						if (phy->enabled)
 | 
				
			||||||
 | 
							goto err1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = ti_pipe3_enable_refclk(phy);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto err1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!IS_ERR(phy->wkupclk)) {
 | 
						if (!IS_ERR(phy->wkupclk)) {
 | 
				
			||||||
		ret = clk_prepare_enable(phy->wkupclk);
 | 
							ret = clk_prepare_enable(phy->wkupclk);
 | 
				
			||||||
| 
						 | 
					@ -469,6 +487,9 @@ static int ti_pipe3_runtime_resume(struct device *dev)
 | 
				
			||||||
			goto err3;
 | 
								goto err3;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						phy->enabled = true;
 | 
				
			||||||
 | 
						spin_unlock_irqrestore(&phy->lock, flags);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
err3:
 | 
					err3:
 | 
				
			||||||
| 
						 | 
					@ -479,20 +500,80 @@ err2:
 | 
				
			||||||
	if (!IS_ERR(phy->refclk))
 | 
						if (!IS_ERR(phy->refclk))
 | 
				
			||||||
		clk_disable_unprepare(phy->refclk);
 | 
							clk_disable_unprepare(phy->refclk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ti_pipe3_disable_refclk(phy);
 | 
				
			||||||
err1:
 | 
					err1:
 | 
				
			||||||
 | 
						spin_unlock_irqrestore(&phy->lock, flags);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_irqsave(&phy->lock, flags);
 | 
				
			||||||
 | 
						if (!phy->enabled) {
 | 
				
			||||||
 | 
							spin_unlock_irqrestore(&phy->lock, flags);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!IS_ERR(phy->wkupclk))
 | 
				
			||||||
 | 
							clk_disable_unprepare(phy->wkupclk);
 | 
				
			||||||
 | 
						/* Don't disable refclk for SATA PHY due to Errata i783 */
 | 
				
			||||||
 | 
						if (!of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata"))
 | 
				
			||||||
 | 
							ti_pipe3_disable_refclk(phy);
 | 
				
			||||||
 | 
						if (!IS_ERR(phy->div_clk))
 | 
				
			||||||
 | 
							clk_disable_unprepare(phy->div_clk);
 | 
				
			||||||
 | 
						phy->enabled = false;
 | 
				
			||||||
 | 
						spin_unlock_irqrestore(&phy->lock, flags);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ti_pipe3_runtime_suspend(struct device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ti_pipe3	*phy = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ti_pipe3_disable_clocks(phy);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ti_pipe3_runtime_resume(struct device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ti_pipe3	*phy = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = ti_pipe3_enable_clocks(phy);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ti_pipe3_suspend(struct device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ti_pipe3	*phy = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ti_pipe3_disable_clocks(phy);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ti_pipe3_resume(struct device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ti_pipe3	*phy = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = ti_pipe3_enable_clocks(phy);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pm_runtime_disable(dev);
 | 
				
			||||||
 | 
						pm_runtime_set_active(dev);
 | 
				
			||||||
 | 
						pm_runtime_enable(dev);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct dev_pm_ops ti_pipe3_pm_ops = {
 | 
					static const struct dev_pm_ops ti_pipe3_pm_ops = {
 | 
				
			||||||
	SET_RUNTIME_PM_OPS(ti_pipe3_runtime_suspend,
 | 
						SET_RUNTIME_PM_OPS(ti_pipe3_runtime_suspend,
 | 
				
			||||||
			   ti_pipe3_runtime_resume, NULL)
 | 
								   ti_pipe3_runtime_resume, NULL)
 | 
				
			||||||
 | 
						SET_SYSTEM_SLEEP_PM_OPS(ti_pipe3_suspend, ti_pipe3_resume)
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DEV_PM_OPS     (&ti_pipe3_pm_ops)
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
#define DEV_PM_OPS     NULL
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef CONFIG_OF
 | 
					#ifdef CONFIG_OF
 | 
				
			||||||
static const struct of_device_id ti_pipe3_id_table[] = {
 | 
					static const struct of_device_id ti_pipe3_id_table[] = {
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					@ -520,7 +601,7 @@ static struct platform_driver ti_pipe3_driver = {
 | 
				
			||||||
	.remove		= ti_pipe3_remove,
 | 
						.remove		= ti_pipe3_remove,
 | 
				
			||||||
	.driver		= {
 | 
						.driver		= {
 | 
				
			||||||
		.name	= "ti-pipe3",
 | 
							.name	= "ti-pipe3",
 | 
				
			||||||
		.pm	= DEV_PM_OPS,
 | 
							.pm	= &ti_pipe3_pm_ops,
 | 
				
			||||||
		.of_match_table = of_match_ptr(ti_pipe3_id_table),
 | 
							.of_match_table = of_match_ptr(ti_pipe3_id_table),
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1608,7 +1608,7 @@ static int std_req_get_status(struct nbu2ss_udc *udc)
 | 
				
			||||||
	switch (recipient) {
 | 
						switch (recipient) {
 | 
				
			||||||
	case USB_RECIP_DEVICE:
 | 
						case USB_RECIP_DEVICE:
 | 
				
			||||||
		if (udc->ctrl.wIndex == 0x0000) {
 | 
							if (udc->ctrl.wIndex == 0x0000) {
 | 
				
			||||||
			if (udc->self_powered)
 | 
								if (udc->gadget.is_selfpowered)
 | 
				
			||||||
				status_data |= (1 << USB_DEVICE_SELF_POWERED);
 | 
									status_data |= (1 << USB_DEVICE_SELF_POWERED);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (udc->remote_wakeup)
 | 
								if (udc->remote_wakeup)
 | 
				
			||||||
| 
						 | 
					@ -3117,7 +3117,7 @@ static int nbu2ss_gad_wakeup(struct usb_gadget *pgadget)
 | 
				
			||||||
static int nbu2ss_gad_set_selfpowered(struct usb_gadget *pgadget,
 | 
					static int nbu2ss_gad_set_selfpowered(struct usb_gadget *pgadget,
 | 
				
			||||||
					int is_selfpowered)
 | 
										int is_selfpowered)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nbu2ss_udc	*udc;
 | 
						struct nbu2ss_udc       *udc;
 | 
				
			||||||
	unsigned long		flags;
 | 
						unsigned long		flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*	INFO("=== %s()\n", __func__); */
 | 
					/*	INFO("=== %s()\n", __func__); */
 | 
				
			||||||
| 
						 | 
					@ -3130,7 +3130,7 @@ static int nbu2ss_gad_set_selfpowered(struct usb_gadget *pgadget,
 | 
				
			||||||
	udc = container_of(pgadget, struct nbu2ss_udc, gadget);
 | 
						udc = container_of(pgadget, struct nbu2ss_udc, gadget);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock_irqsave(&udc->lock, flags);
 | 
						spin_lock_irqsave(&udc->lock, flags);
 | 
				
			||||||
	udc->self_powered = (is_selfpowered != 0);
 | 
						pgadget->is_selfpowered = (is_selfpowered != 0);
 | 
				
			||||||
	spin_unlock_irqrestore(&udc->lock, flags);
 | 
						spin_unlock_irqrestore(&udc->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -3308,7 +3308,7 @@ static int __init nbu2ss_drv_contest_init(
 | 
				
			||||||
	spin_lock_init(&udc->lock);
 | 
						spin_lock_init(&udc->lock);
 | 
				
			||||||
	udc->dev = &pdev->dev;
 | 
						udc->dev = &pdev->dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	udc->self_powered = 1;
 | 
						udc->gadget.is_selfpowered = 1;
 | 
				
			||||||
	udc->devstate = USB_STATE_NOTATTACHED;
 | 
						udc->devstate = USB_STATE_NOTATTACHED;
 | 
				
			||||||
	udc->pdev = pdev;
 | 
						udc->pdev = pdev;
 | 
				
			||||||
	udc->mA = 0;
 | 
						udc->mA = 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -624,7 +624,6 @@ struct nbu2ss_udc {
 | 
				
			||||||
	unsigned		linux_suspended:1;
 | 
						unsigned		linux_suspended:1;
 | 
				
			||||||
	unsigned		linux_resume:1;
 | 
						unsigned		linux_resume:1;
 | 
				
			||||||
	unsigned		usb_suspended:1;
 | 
						unsigned		usb_suspended:1;
 | 
				
			||||||
	unsigned		self_powered:1;
 | 
					 | 
				
			||||||
	unsigned		remote_wakeup:1;
 | 
						unsigned		remote_wakeup:1;
 | 
				
			||||||
	unsigned		udc_enabled:1;
 | 
						unsigned		udc_enabled:1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -104,6 +104,8 @@ source "drivers/usb/dwc2/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
source "drivers/usb/chipidea/Kconfig"
 | 
					source "drivers/usb/chipidea/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					source "drivers/usb/isp1760/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
comment "USB port drivers"
 | 
					comment "USB port drivers"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if USB
 | 
					if USB
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@ obj-$(CONFIG_USB)		+= core/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-$(CONFIG_USB_DWC3)		+= dwc3/
 | 
					obj-$(CONFIG_USB_DWC3)		+= dwc3/
 | 
				
			||||||
obj-$(CONFIG_USB_DWC2)		+= dwc2/
 | 
					obj-$(CONFIG_USB_DWC2)		+= dwc2/
 | 
				
			||||||
 | 
					obj-$(CONFIG_USB_ISP1760)	+= isp1760/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-$(CONFIG_USB_MON)		+= mon/
 | 
					obj-$(CONFIG_USB_MON)		+= mon/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +24,6 @@ obj-$(CONFIG_USB_ISP1362_HCD)	+= host/
 | 
				
			||||||
obj-$(CONFIG_USB_U132_HCD)	+= host/
 | 
					obj-$(CONFIG_USB_U132_HCD)	+= host/
 | 
				
			||||||
obj-$(CONFIG_USB_R8A66597_HCD)	+= host/
 | 
					obj-$(CONFIG_USB_R8A66597_HCD)	+= host/
 | 
				
			||||||
obj-$(CONFIG_USB_HWA_HCD)	+= host/
 | 
					obj-$(CONFIG_USB_HWA_HCD)	+= host/
 | 
				
			||||||
obj-$(CONFIG_USB_ISP1760_HCD)	+= host/
 | 
					 | 
				
			||||||
obj-$(CONFIG_USB_IMX21_HCD)	+= host/
 | 
					obj-$(CONFIG_USB_IMX21_HCD)	+= host/
 | 
				
			||||||
obj-$(CONFIG_USB_FSL_MPH_DR_OF)	+= host/
 | 
					obj-$(CONFIG_USB_FSL_MPH_DR_OF)	+= host/
 | 
				
			||||||
obj-$(CONFIG_USB_FUSBH200_HCD)	+= host/
 | 
					obj-$(CONFIG_USB_FUSBH200_HCD)	+= host/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -111,6 +111,9 @@ static void ci_hdrc_pci_remove(struct pci_dev *pdev)
 | 
				
			||||||
 * PCI device structure
 | 
					 * PCI device structure
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Check "pci.h" for details
 | 
					 * Check "pci.h" for details
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note: ehci-pci driver may try to probe the device first. You have to add an
 | 
				
			||||||
 | 
					 * ID to the bypass_pci_id_table in ehci-pci driver to prevent this.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static const struct pci_device_id ci_hdrc_pci_id_table[] = {
 | 
					static const struct pci_device_id ci_hdrc_pci_id_table[] = {
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -819,8 +819,8 @@ __acquires(hwep->lock)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
 | 
						if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
 | 
				
			||||||
		/* Assume that device is bus powered for now. */
 | 
							*(u16 *)req->buf = (ci->remote_wakeup << 1) |
 | 
				
			||||||
		*(u16 *)req->buf = ci->remote_wakeup << 1;
 | 
								ci->gadget.is_selfpowered;
 | 
				
			||||||
	} else if ((setup->bRequestType & USB_RECIP_MASK) \
 | 
						} else if ((setup->bRequestType & USB_RECIP_MASK) \
 | 
				
			||||||
		   == USB_RECIP_ENDPOINT) {
 | 
							   == USB_RECIP_ENDPOINT) {
 | 
				
			||||||
		dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
 | 
							dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
 | 
				
			||||||
| 
						 | 
					@ -1520,6 +1520,19 @@ static int ci_udc_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
 | 
				
			||||||
	return -ENOTSUPP;
 | 
						return -ENOTSUPP;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ci_udc_selfpowered(struct usb_gadget *_gadget, int is_on)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
 | 
				
			||||||
 | 
						struct ci_hw_ep *hwep = ci->ep0in;
 | 
				
			||||||
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_irqsave(hwep->lock, flags);
 | 
				
			||||||
 | 
						_gadget->is_selfpowered = (is_on != 0);
 | 
				
			||||||
 | 
						spin_unlock_irqrestore(hwep->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Change Data+ pullup status
 | 
					/* Change Data+ pullup status
 | 
				
			||||||
 * this func is used by usb_gadget_connect/disconnet
 | 
					 * this func is used by usb_gadget_connect/disconnet
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -1549,6 +1562,7 @@ static int ci_udc_stop(struct usb_gadget *gadget);
 | 
				
			||||||
static const struct usb_gadget_ops usb_gadget_ops = {
 | 
					static const struct usb_gadget_ops usb_gadget_ops = {
 | 
				
			||||||
	.vbus_session	= ci_udc_vbus_session,
 | 
						.vbus_session	= ci_udc_vbus_session,
 | 
				
			||||||
	.wakeup		= ci_udc_wakeup,
 | 
						.wakeup		= ci_udc_wakeup,
 | 
				
			||||||
 | 
						.set_selfpowered	= ci_udc_selfpowered,
 | 
				
			||||||
	.pullup		= ci_udc_pullup,
 | 
						.pullup		= ci_udc_pullup,
 | 
				
			||||||
	.vbus_draw	= ci_udc_vbus_draw,
 | 
						.vbus_draw	= ci_udc_vbus_draw,
 | 
				
			||||||
	.udc_start	= ci_udc_start,
 | 
						.udc_start	= ci_udc_start,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1091,6 +1091,7 @@ static int acm_probe(struct usb_interface *intf,
 | 
				
			||||||
	unsigned long quirks;
 | 
						unsigned long quirks;
 | 
				
			||||||
	int num_rx_buf;
 | 
						int num_rx_buf;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
						unsigned int elength = 0;
 | 
				
			||||||
	int combined_interfaces = 0;
 | 
						int combined_interfaces = 0;
 | 
				
			||||||
	struct device *tty_dev;
 | 
						struct device *tty_dev;
 | 
				
			||||||
	int rv = -ENOMEM;
 | 
						int rv = -ENOMEM;
 | 
				
			||||||
| 
						 | 
					@ -1136,9 +1137,12 @@ static int acm_probe(struct usb_interface *intf,
 | 
				
			||||||
			dev_err(&intf->dev, "skipping garbage\n");
 | 
								dev_err(&intf->dev, "skipping garbage\n");
 | 
				
			||||||
			goto next_desc;
 | 
								goto next_desc;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							elength = buffer[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		switch (buffer[2]) {
 | 
							switch (buffer[2]) {
 | 
				
			||||||
		case USB_CDC_UNION_TYPE: /* we've found it */
 | 
							case USB_CDC_UNION_TYPE: /* we've found it */
 | 
				
			||||||
 | 
								if (elength < sizeof(struct usb_cdc_union_desc))
 | 
				
			||||||
 | 
									goto next_desc;
 | 
				
			||||||
			if (union_header) {
 | 
								if (union_header) {
 | 
				
			||||||
				dev_err(&intf->dev, "More than one "
 | 
									dev_err(&intf->dev, "More than one "
 | 
				
			||||||
					"union descriptor, skipping ...\n");
 | 
										"union descriptor, skipping ...\n");
 | 
				
			||||||
| 
						 | 
					@ -1147,29 +1151,36 @@ static int acm_probe(struct usb_interface *intf,
 | 
				
			||||||
			union_header = (struct usb_cdc_union_desc *)buffer;
 | 
								union_header = (struct usb_cdc_union_desc *)buffer;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
 | 
							case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
 | 
				
			||||||
 | 
								if (elength < sizeof(struct usb_cdc_country_functional_desc))
 | 
				
			||||||
 | 
									goto next_desc;
 | 
				
			||||||
			cfd = (struct usb_cdc_country_functional_desc *)buffer;
 | 
								cfd = (struct usb_cdc_country_functional_desc *)buffer;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case USB_CDC_HEADER_TYPE: /* maybe check version */
 | 
							case USB_CDC_HEADER_TYPE: /* maybe check version */
 | 
				
			||||||
			break; /* for now we ignore it */
 | 
								break; /* for now we ignore it */
 | 
				
			||||||
		case USB_CDC_ACM_TYPE:
 | 
							case USB_CDC_ACM_TYPE:
 | 
				
			||||||
 | 
								if (elength < 4)
 | 
				
			||||||
 | 
									goto next_desc;
 | 
				
			||||||
			ac_management_function = buffer[3];
 | 
								ac_management_function = buffer[3];
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case USB_CDC_CALL_MANAGEMENT_TYPE:
 | 
							case USB_CDC_CALL_MANAGEMENT_TYPE:
 | 
				
			||||||
 | 
								if (elength < 5)
 | 
				
			||||||
 | 
									goto next_desc;
 | 
				
			||||||
			call_management_function = buffer[3];
 | 
								call_management_function = buffer[3];
 | 
				
			||||||
			call_interface_num = buffer[4];
 | 
								call_interface_num = buffer[4];
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			/* there are LOTS more CDC descriptors that
 | 
								/*
 | 
				
			||||||
 | 
								 * there are LOTS more CDC descriptors that
 | 
				
			||||||
			 * could legitimately be found here.
 | 
								 * could legitimately be found here.
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			dev_dbg(&intf->dev, "Ignoring descriptor: "
 | 
								dev_dbg(&intf->dev, "Ignoring descriptor: "
 | 
				
			||||||
					"type %02x, length %d\n",
 | 
										"type %02x, length %ud\n",
 | 
				
			||||||
					buffer[2], buffer[0]);
 | 
										buffer[2], elength);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
next_desc:
 | 
					next_desc:
 | 
				
			||||||
		buflen -= buffer[0];
 | 
							buflen -= elength;
 | 
				
			||||||
		buffer += buffer[0];
 | 
							buffer += elength;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!union_header) {
 | 
						if (!union_header) {
 | 
				
			||||||
| 
						 | 
					@ -1287,10 +1298,8 @@ made_compressed_probe:
 | 
				
			||||||
	dev_dbg(&intf->dev, "interfaces are valid\n");
 | 
						dev_dbg(&intf->dev, "interfaces are valid\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
 | 
						acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
 | 
				
			||||||
	if (acm == NULL) {
 | 
						if (acm == NULL)
 | 
				
			||||||
		dev_err(&intf->dev, "out of memory (acm kzalloc)\n");
 | 
					 | 
				
			||||||
		goto alloc_fail;
 | 
							goto alloc_fail;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	minor = acm_alloc_minor(acm);
 | 
						minor = acm_alloc_minor(acm);
 | 
				
			||||||
	if (minor == ACM_TTY_MINORS) {
 | 
						if (minor == ACM_TTY_MINORS) {
 | 
				
			||||||
| 
						 | 
					@ -1329,42 +1338,32 @@ made_compressed_probe:
 | 
				
			||||||
	acm->quirks = quirks;
 | 
						acm->quirks = quirks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
 | 
						buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
 | 
				
			||||||
	if (!buf) {
 | 
						if (!buf)
 | 
				
			||||||
		dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n");
 | 
					 | 
				
			||||||
		goto alloc_fail2;
 | 
							goto alloc_fail2;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	acm->ctrl_buffer = buf;
 | 
						acm->ctrl_buffer = buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (acm_write_buffers_alloc(acm) < 0) {
 | 
						if (acm_write_buffers_alloc(acm) < 0)
 | 
				
			||||||
		dev_err(&intf->dev, "out of memory (write buffer alloc)\n");
 | 
					 | 
				
			||||||
		goto alloc_fail4;
 | 
							goto alloc_fail4;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
 | 
						acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
 | 
				
			||||||
	if (!acm->ctrlurb) {
 | 
						if (!acm->ctrlurb)
 | 
				
			||||||
		dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
 | 
					 | 
				
			||||||
		goto alloc_fail5;
 | 
							goto alloc_fail5;
 | 
				
			||||||
	}
 | 
					
 | 
				
			||||||
	for (i = 0; i < num_rx_buf; i++) {
 | 
						for (i = 0; i < num_rx_buf; i++) {
 | 
				
			||||||
		struct acm_rb *rb = &(acm->read_buffers[i]);
 | 
							struct acm_rb *rb = &(acm->read_buffers[i]);
 | 
				
			||||||
		struct urb *urb;
 | 
							struct urb *urb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,
 | 
							rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,
 | 
				
			||||||
								&rb->dma);
 | 
													&rb->dma);
 | 
				
			||||||
		if (!rb->base) {
 | 
							if (!rb->base)
 | 
				
			||||||
			dev_err(&intf->dev, "out of memory "
 | 
					 | 
				
			||||||
					"(read bufs usb_alloc_coherent)\n");
 | 
					 | 
				
			||||||
			goto alloc_fail6;
 | 
								goto alloc_fail6;
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		rb->index = i;
 | 
							rb->index = i;
 | 
				
			||||||
		rb->instance = acm;
 | 
							rb->instance = acm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		urb = usb_alloc_urb(0, GFP_KERNEL);
 | 
							urb = usb_alloc_urb(0, GFP_KERNEL);
 | 
				
			||||||
		if (!urb) {
 | 
							if (!urb)
 | 
				
			||||||
			dev_err(&intf->dev,
 | 
					 | 
				
			||||||
				"out of memory (read urbs usb_alloc_urb)\n");
 | 
					 | 
				
			||||||
			goto alloc_fail6;
 | 
								goto alloc_fail6;
 | 
				
			||||||
		}
 | 
					
 | 
				
			||||||
		urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 | 
							urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 | 
				
			||||||
		urb->transfer_dma = rb->dma;
 | 
							urb->transfer_dma = rb->dma;
 | 
				
			||||||
		if (acm->is_int_ep) {
 | 
							if (acm->is_int_ep) {
 | 
				
			||||||
| 
						 | 
					@ -1389,11 +1388,8 @@ made_compressed_probe:
 | 
				
			||||||
		struct acm_wb *snd = &(acm->wb[i]);
 | 
							struct acm_wb *snd = &(acm->wb[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		snd->urb = usb_alloc_urb(0, GFP_KERNEL);
 | 
							snd->urb = usb_alloc_urb(0, GFP_KERNEL);
 | 
				
			||||||
		if (snd->urb == NULL) {
 | 
							if (snd->urb == NULL)
 | 
				
			||||||
			dev_err(&intf->dev,
 | 
					 | 
				
			||||||
				"out of memory (write urbs usb_alloc_urb)\n");
 | 
					 | 
				
			||||||
			goto alloc_fail7;
 | 
								goto alloc_fail7;
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (usb_endpoint_xfer_int(epwrite))
 | 
							if (usb_endpoint_xfer_int(epwrite))
 | 
				
			||||||
			usb_fill_int_urb(snd->urb, usb_dev,
 | 
								usb_fill_int_urb(snd->urb, usb_dev,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,17 +22,25 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* FIXME tune these based on pool statistics ... */
 | 
					/* FIXME tune these based on pool statistics ... */
 | 
				
			||||||
static const size_t	pool_max[HCD_BUFFER_POOLS] = {
 | 
					static size_t pool_max[HCD_BUFFER_POOLS] = {
 | 
				
			||||||
	/* platforms without dma-friendly caches might need to
 | 
						32, 128, 512, 2048,
 | 
				
			||||||
	 * prevent cacheline sharing...
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	32,
 | 
					 | 
				
			||||||
	128,
 | 
					 | 
				
			||||||
	512,
 | 
					 | 
				
			||||||
	PAGE_SIZE / 2
 | 
					 | 
				
			||||||
	/* bigger --> allocate pages */
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void __init usb_init_pool_max(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * The pool_max values must never be smaller than
 | 
				
			||||||
 | 
						 * ARCH_KMALLOC_MINALIGN.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (ARCH_KMALLOC_MINALIGN <= 32)
 | 
				
			||||||
 | 
							;			/* Original value is okay */
 | 
				
			||||||
 | 
						else if (ARCH_KMALLOC_MINALIGN <= 64)
 | 
				
			||||||
 | 
							pool_max[0] = 64;
 | 
				
			||||||
 | 
						else if (ARCH_KMALLOC_MINALIGN <= 128)
 | 
				
			||||||
 | 
							pool_max[0] = 0;	/* Don't use this pool */
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							BUILD_BUG();		/* We don't allow this */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* SETUP primitives */
 | 
					/* SETUP primitives */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1689,7 +1689,7 @@ static struct async *reap_as(struct usb_dev_state *ps)
 | 
				
			||||||
	for (;;) {
 | 
						for (;;) {
 | 
				
			||||||
		__set_current_state(TASK_INTERRUPTIBLE);
 | 
							__set_current_state(TASK_INTERRUPTIBLE);
 | 
				
			||||||
		as = async_getcompleted(ps);
 | 
							as = async_getcompleted(ps);
 | 
				
			||||||
		if (as)
 | 
							if (as || !connected(ps))
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		if (signal_pending(current))
 | 
							if (signal_pending(current))
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
| 
						 | 
					@ -1712,7 +1712,7 @@ static int proc_reapurb(struct usb_dev_state *ps, void __user *arg)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (signal_pending(current))
 | 
						if (signal_pending(current))
 | 
				
			||||||
		return -EINTR;
 | 
							return -EINTR;
 | 
				
			||||||
	return -EIO;
 | 
						return -ENODEV;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)
 | 
					static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)
 | 
				
			||||||
| 
						 | 
					@ -1721,10 +1721,11 @@ static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)
 | 
				
			||||||
	struct async *as;
 | 
						struct async *as;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	as = async_getcompleted(ps);
 | 
						as = async_getcompleted(ps);
 | 
				
			||||||
	retval = -EAGAIN;
 | 
					 | 
				
			||||||
	if (as) {
 | 
						if (as) {
 | 
				
			||||||
		retval = processcompl(as, (void __user * __user *)arg);
 | 
							retval = processcompl(as, (void __user * __user *)arg);
 | 
				
			||||||
		free_async(as);
 | 
							free_async(as);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							retval = (connected(ps) ? -EAGAIN : -ENODEV);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return retval;
 | 
						return retval;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1854,7 +1855,7 @@ static int proc_reapurb_compat(struct usb_dev_state *ps, void __user *arg)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (signal_pending(current))
 | 
						if (signal_pending(current))
 | 
				
			||||||
		return -EINTR;
 | 
							return -EINTR;
 | 
				
			||||||
	return -EIO;
 | 
						return -ENODEV;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *arg)
 | 
					static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *arg)
 | 
				
			||||||
| 
						 | 
					@ -1862,11 +1863,12 @@ static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *ar
 | 
				
			||||||
	int retval;
 | 
						int retval;
 | 
				
			||||||
	struct async *as;
 | 
						struct async *as;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	retval = -EAGAIN;
 | 
					 | 
				
			||||||
	as = async_getcompleted(ps);
 | 
						as = async_getcompleted(ps);
 | 
				
			||||||
	if (as) {
 | 
						if (as) {
 | 
				
			||||||
		retval = processcompl_compat(as, (void __user * __user *)arg);
 | 
							retval = processcompl_compat(as, (void __user * __user *)arg);
 | 
				
			||||||
		free_async(as);
 | 
							free_async(as);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							retval = (connected(ps) ? -EAGAIN : -ENODEV);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return retval;
 | 
						return retval;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2038,7 +2040,8 @@ static int proc_get_capabilities(struct usb_dev_state *ps, void __user *arg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	__u32 caps;
 | 
						__u32 caps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM;
 | 
						caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM |
 | 
				
			||||||
 | 
								USBDEVFS_CAP_REAP_AFTER_DISCONNECT;
 | 
				
			||||||
	if (!ps->dev->bus->no_stop_on_short)
 | 
						if (!ps->dev->bus->no_stop_on_short)
 | 
				
			||||||
		caps |= USBDEVFS_CAP_BULK_CONTINUATION;
 | 
							caps |= USBDEVFS_CAP_BULK_CONTINUATION;
 | 
				
			||||||
	if (ps->dev->bus->sg_tablesize)
 | 
						if (ps->dev->bus->sg_tablesize)
 | 
				
			||||||
| 
						 | 
					@ -2138,6 +2141,32 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
 | 
				
			||||||
		return -EPERM;
 | 
							return -EPERM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	usb_lock_device(dev);
 | 
						usb_lock_device(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Reap operations are allowed even after disconnection */
 | 
				
			||||||
 | 
						switch (cmd) {
 | 
				
			||||||
 | 
						case USBDEVFS_REAPURB:
 | 
				
			||||||
 | 
							snoop(&dev->dev, "%s: REAPURB\n", __func__);
 | 
				
			||||||
 | 
							ret = proc_reapurb(ps, p);
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case USBDEVFS_REAPURBNDELAY:
 | 
				
			||||||
 | 
							snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
 | 
				
			||||||
 | 
							ret = proc_reapurbnonblock(ps, p);
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_COMPAT
 | 
				
			||||||
 | 
						case USBDEVFS_REAPURB32:
 | 
				
			||||||
 | 
							snoop(&dev->dev, "%s: REAPURB32\n", __func__);
 | 
				
			||||||
 | 
							ret = proc_reapurb_compat(ps, p);
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case USBDEVFS_REAPURBNDELAY32:
 | 
				
			||||||
 | 
							snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
 | 
				
			||||||
 | 
							ret = proc_reapurbnonblock_compat(ps, p);
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!connected(ps)) {
 | 
						if (!connected(ps)) {
 | 
				
			||||||
		usb_unlock_device(dev);
 | 
							usb_unlock_device(dev);
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
| 
						 | 
					@ -2231,16 +2260,6 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
 | 
				
			||||||
			inode->i_mtime = CURRENT_TIME;
 | 
								inode->i_mtime = CURRENT_TIME;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case USBDEVFS_REAPURB32:
 | 
					 | 
				
			||||||
		snoop(&dev->dev, "%s: REAPURB32\n", __func__);
 | 
					 | 
				
			||||||
		ret = proc_reapurb_compat(ps, p);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	case USBDEVFS_REAPURBNDELAY32:
 | 
					 | 
				
			||||||
		snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
 | 
					 | 
				
			||||||
		ret = proc_reapurbnonblock_compat(ps, p);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	case USBDEVFS_IOCTL32:
 | 
						case USBDEVFS_IOCTL32:
 | 
				
			||||||
		snoop(&dev->dev, "%s: IOCTL32\n", __func__);
 | 
							snoop(&dev->dev, "%s: IOCTL32\n", __func__);
 | 
				
			||||||
		ret = proc_ioctl_compat(ps, ptr_to_compat(p));
 | 
							ret = proc_ioctl_compat(ps, ptr_to_compat(p));
 | 
				
			||||||
| 
						 | 
					@ -2252,16 +2271,6 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
 | 
				
			||||||
		ret = proc_unlinkurb(ps, p);
 | 
							ret = proc_unlinkurb(ps, p);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case USBDEVFS_REAPURB:
 | 
					 | 
				
			||||||
		snoop(&dev->dev, "%s: REAPURB\n", __func__);
 | 
					 | 
				
			||||||
		ret = proc_reapurb(ps, p);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	case USBDEVFS_REAPURBNDELAY:
 | 
					 | 
				
			||||||
		snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
 | 
					 | 
				
			||||||
		ret = proc_reapurbnonblock(ps, p);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	case USBDEVFS_DISCSIGNAL:
 | 
						case USBDEVFS_DISCSIGNAL:
 | 
				
			||||||
		snoop(&dev->dev, "%s: DISCSIGNAL\n", __func__);
 | 
							snoop(&dev->dev, "%s: DISCSIGNAL\n", __func__);
 | 
				
			||||||
		ret = proc_disconnectsignal(ps, p);
 | 
							ret = proc_disconnectsignal(ps, p);
 | 
				
			||||||
| 
						 | 
					@ -2304,6 +2313,8 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
 | 
				
			||||||
		ret = proc_free_streams(ps, p);
 | 
							ret = proc_free_streams(ps, p);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 done:
 | 
				
			||||||
	usb_unlock_device(dev);
 | 
						usb_unlock_device(dev);
 | 
				
			||||||
	if (ret >= 0)
 | 
						if (ret >= 0)
 | 
				
			||||||
		inode->i_atime = CURRENT_TIME;
 | 
							inode->i_atime = CURRENT_TIME;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -275,21 +275,6 @@ static int usb_unbind_device(struct device *dev)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Cancel any pending scheduled resets
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * [see usb_queue_reset_device()]
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Called after unconfiguring / when releasing interfaces. See
 | 
					 | 
				
			||||||
 * comments in __usb_queue_reset_device() regarding
 | 
					 | 
				
			||||||
 * udev->reset_running.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static void usb_cancel_queued_reset(struct usb_interface *iface)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (iface->reset_running == 0)
 | 
					 | 
				
			||||||
		cancel_work_sync(&iface->reset_ws);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* called from driver core with dev locked */
 | 
					/* called from driver core with dev locked */
 | 
				
			||||||
static int usb_probe_interface(struct device *dev)
 | 
					static int usb_probe_interface(struct device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -380,7 +365,6 @@ static int usb_probe_interface(struct device *dev)
 | 
				
			||||||
	usb_set_intfdata(intf, NULL);
 | 
						usb_set_intfdata(intf, NULL);
 | 
				
			||||||
	intf->needs_remote_wakeup = 0;
 | 
						intf->needs_remote_wakeup = 0;
 | 
				
			||||||
	intf->condition = USB_INTERFACE_UNBOUND;
 | 
						intf->condition = USB_INTERFACE_UNBOUND;
 | 
				
			||||||
	usb_cancel_queued_reset(intf);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If the LPM disable succeeded, balance the ref counts. */
 | 
						/* If the LPM disable succeeded, balance the ref counts. */
 | 
				
			||||||
	if (!lpm_disable_error)
 | 
						if (!lpm_disable_error)
 | 
				
			||||||
| 
						 | 
					@ -425,7 +409,6 @@ static int usb_unbind_interface(struct device *dev)
 | 
				
			||||||
		usb_disable_interface(udev, intf, false);
 | 
							usb_disable_interface(udev, intf, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	driver->disconnect(intf);
 | 
						driver->disconnect(intf);
 | 
				
			||||||
	usb_cancel_queued_reset(intf);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Free streams */
 | 
						/* Free streams */
 | 
				
			||||||
	for (i = 0, j = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
 | 
						for (i = 0, j = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
 | 
				
			||||||
| 
						 | 
					@ -1797,6 +1780,18 @@ static int autosuspend_check(struct usb_device *udev)
 | 
				
			||||||
		dev_dbg(&udev->dev, "remote wakeup needed for autosuspend\n");
 | 
							dev_dbg(&udev->dev, "remote wakeup needed for autosuspend\n");
 | 
				
			||||||
		return -EOPNOTSUPP;
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * If the device is a direct child of the root hub and the HCD
 | 
				
			||||||
 | 
						 * doesn't handle wakeup requests, don't allow autosuspend when
 | 
				
			||||||
 | 
						 * wakeup is needed.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (w && udev->parent == udev->bus->root_hub &&
 | 
				
			||||||
 | 
								bus_to_hcd(udev->bus)->cant_recv_wakeups) {
 | 
				
			||||||
 | 
							dev_dbg(&udev->dev, "HCD doesn't handle wakeup requests\n");
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	udev->do_remote_wakeup = w;
 | 
						udev->do_remote_wakeup = w;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1618,6 +1618,7 @@ static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status)
 | 
				
			||||||
int usb_hcd_unlink_urb (struct urb *urb, int status)
 | 
					int usb_hcd_unlink_urb (struct urb *urb, int status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct usb_hcd		*hcd;
 | 
						struct usb_hcd		*hcd;
 | 
				
			||||||
 | 
						struct usb_device	*udev = urb->dev;
 | 
				
			||||||
	int			retval = -EIDRM;
 | 
						int			retval = -EIDRM;
 | 
				
			||||||
	unsigned long		flags;
 | 
						unsigned long		flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1629,20 +1630,19 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
 | 
				
			||||||
	spin_lock_irqsave(&hcd_urb_unlink_lock, flags);
 | 
						spin_lock_irqsave(&hcd_urb_unlink_lock, flags);
 | 
				
			||||||
	if (atomic_read(&urb->use_count) > 0) {
 | 
						if (atomic_read(&urb->use_count) > 0) {
 | 
				
			||||||
		retval = 0;
 | 
							retval = 0;
 | 
				
			||||||
		usb_get_dev(urb->dev);
 | 
							usb_get_dev(udev);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	spin_unlock_irqrestore(&hcd_urb_unlink_lock, flags);
 | 
						spin_unlock_irqrestore(&hcd_urb_unlink_lock, flags);
 | 
				
			||||||
	if (retval == 0) {
 | 
						if (retval == 0) {
 | 
				
			||||||
		hcd = bus_to_hcd(urb->dev->bus);
 | 
							hcd = bus_to_hcd(urb->dev->bus);
 | 
				
			||||||
		retval = unlink1(hcd, urb, status);
 | 
							retval = unlink1(hcd, urb, status);
 | 
				
			||||||
		usb_put_dev(urb->dev);
 | 
							if (retval == 0)
 | 
				
			||||||
 | 
								retval = -EINPROGRESS;
 | 
				
			||||||
 | 
							else if (retval != -EIDRM && retval != -EBUSY)
 | 
				
			||||||
 | 
								dev_dbg(&udev->dev, "hcd_unlink_urb %p fail %d\n",
 | 
				
			||||||
 | 
										urb, retval);
 | 
				
			||||||
 | 
							usb_put_dev(udev);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (retval == 0)
 | 
					 | 
				
			||||||
		retval = -EINPROGRESS;
 | 
					 | 
				
			||||||
	else if (retval != -EIDRM && retval != -EBUSY)
 | 
					 | 
				
			||||||
		dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n",
 | 
					 | 
				
			||||||
				urb, retval);
 | 
					 | 
				
			||||||
	return retval;
 | 
						return retval;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2896,10 +2896,12 @@ static int port_is_suspended(struct usb_hub *hub, unsigned portstatus)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int check_port_resume_type(struct usb_device *udev,
 | 
					static int check_port_resume_type(struct usb_device *udev,
 | 
				
			||||||
		struct usb_hub *hub, int port1,
 | 
							struct usb_hub *hub, int port1,
 | 
				
			||||||
		int status, unsigned portchange, unsigned portstatus)
 | 
							int status, u16 portchange, u16 portstatus)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct usb_port *port_dev = hub->ports[port1 - 1];
 | 
						struct usb_port *port_dev = hub->ports[port1 - 1];
 | 
				
			||||||
 | 
						int retries = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 retry:
 | 
				
			||||||
	/* Is a warm reset needed to recover the connection? */
 | 
						/* Is a warm reset needed to recover the connection? */
 | 
				
			||||||
	if (status == 0 && udev->reset_resume
 | 
						if (status == 0 && udev->reset_resume
 | 
				
			||||||
		&& hub_port_warm_reset_required(hub, port1, portstatus)) {
 | 
							&& hub_port_warm_reset_required(hub, port1, portstatus)) {
 | 
				
			||||||
| 
						 | 
					@ -2907,10 +2909,17 @@ static int check_port_resume_type(struct usb_device *udev,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	/* Is the device still present? */
 | 
						/* Is the device still present? */
 | 
				
			||||||
	else if (status || port_is_suspended(hub, portstatus) ||
 | 
						else if (status || port_is_suspended(hub, portstatus) ||
 | 
				
			||||||
			!port_is_power_on(hub, portstatus) ||
 | 
								!port_is_power_on(hub, portstatus)) {
 | 
				
			||||||
			!(portstatus & USB_PORT_STAT_CONNECTION)) {
 | 
					 | 
				
			||||||
		if (status >= 0)
 | 
							if (status >= 0)
 | 
				
			||||||
			status = -ENODEV;
 | 
								status = -ENODEV;
 | 
				
			||||||
 | 
						} else if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
 | 
				
			||||||
 | 
							if (retries--) {
 | 
				
			||||||
 | 
								usleep_range(200, 300);
 | 
				
			||||||
 | 
								status = hub_port_status(hub, port1, &portstatus,
 | 
				
			||||||
 | 
												     &portchange);
 | 
				
			||||||
 | 
								goto retry;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							status = -ENODEV;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Can't do a normal resume if the port isn't enabled,
 | 
						/* Can't do a normal resume if the port isn't enabled,
 | 
				
			||||||
| 
						 | 
					@ -4643,9 +4652,13 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
 | 
				
			||||||
	if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
 | 
						if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
 | 
				
			||||||
			test_bit(port1, hub->removed_bits)) {
 | 
								test_bit(port1, hub->removed_bits)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* maybe switch power back on (e.g. root hub was reset) */
 | 
							/*
 | 
				
			||||||
 | 
							 * maybe switch power back on (e.g. root hub was reset)
 | 
				
			||||||
 | 
							 * but only if the port isn't owned by someone else.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
		if (hub_is_port_power_switchable(hub)
 | 
							if (hub_is_port_power_switchable(hub)
 | 
				
			||||||
				&& !port_is_power_on(hub, portstatus))
 | 
									&& !port_is_power_on(hub, portstatus)
 | 
				
			||||||
 | 
									&& !port_dev->port_owner)
 | 
				
			||||||
			set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
 | 
								set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (portstatus & USB_PORT_STAT_ENABLE)
 | 
							if (portstatus & USB_PORT_STAT_ENABLE)
 | 
				
			||||||
| 
						 | 
					@ -4870,7 +4883,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
 | 
				
			||||||
static void port_event(struct usb_hub *hub, int port1)
 | 
					static void port_event(struct usb_hub *hub, int port1)
 | 
				
			||||||
		__must_hold(&port_dev->status_lock)
 | 
							__must_hold(&port_dev->status_lock)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int connect_change, reset_device = 0;
 | 
						int connect_change;
 | 
				
			||||||
	struct usb_port *port_dev = hub->ports[port1 - 1];
 | 
						struct usb_port *port_dev = hub->ports[port1 - 1];
 | 
				
			||||||
	struct usb_device *udev = port_dev->child;
 | 
						struct usb_device *udev = port_dev->child;
 | 
				
			||||||
	struct usb_device *hdev = hub->hdev;
 | 
						struct usb_device *hdev = hub->hdev;
 | 
				
			||||||
| 
						 | 
					@ -4958,30 +4971,14 @@ static void port_event(struct usb_hub *hub, int port1)
 | 
				
			||||||
			if (hub_port_reset(hub, port1, NULL,
 | 
								if (hub_port_reset(hub, port1, NULL,
 | 
				
			||||||
					HUB_BH_RESET_TIME, true) < 0)
 | 
										HUB_BH_RESET_TIME, true) < 0)
 | 
				
			||||||
				hub_port_disable(hub, port1, 1);
 | 
									hub_port_disable(hub, port1, 1);
 | 
				
			||||||
		} else
 | 
							} else {
 | 
				
			||||||
			reset_device = 1;
 | 
								usb_unlock_port(port_dev);
 | 
				
			||||||
	}
 | 
								usb_lock_device(udev);
 | 
				
			||||||
 | 
								usb_reset_device(udev);
 | 
				
			||||||
	/*
 | 
								usb_unlock_device(udev);
 | 
				
			||||||
	 * On disconnect USB3 protocol ports transit from U0 to
 | 
								usb_lock_port(port_dev);
 | 
				
			||||||
	 * SS.Inactive to Rx.Detect. If this happens a warm-
 | 
								connect_change = 0;
 | 
				
			||||||
	 * reset is not needed, but a (re)connect may happen
 | 
							}
 | 
				
			||||||
	 * before hub_wq runs and sees the disconnect, and the
 | 
					 | 
				
			||||||
	 * device may be an unknown state.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * If the port went through SS.Inactive without hub_wq
 | 
					 | 
				
			||||||
	 * seeing it the C_LINK_STATE change flag will be set,
 | 
					 | 
				
			||||||
	 * and we reset the dev to put it in a known state.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (reset_device || (udev && hub_is_superspeed(hub->hdev)
 | 
					 | 
				
			||||||
				&& (portchange & USB_PORT_STAT_C_LINK_STATE)
 | 
					 | 
				
			||||||
				&& (portstatus & USB_PORT_STAT_CONNECTION))) {
 | 
					 | 
				
			||||||
		usb_unlock_port(port_dev);
 | 
					 | 
				
			||||||
		usb_lock_device(udev);
 | 
					 | 
				
			||||||
		usb_reset_device(udev);
 | 
					 | 
				
			||||||
		usb_unlock_device(udev);
 | 
					 | 
				
			||||||
		usb_lock_port(port_dev);
 | 
					 | 
				
			||||||
		connect_change = 0;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (connect_change)
 | 
						if (connect_change)
 | 
				
			||||||
| 
						 | 
					@ -5577,26 +5574,19 @@ EXPORT_SYMBOL_GPL(usb_reset_device);
 | 
				
			||||||
 *   possible; depending on how the driver attached to each interface
 | 
					 *   possible; depending on how the driver attached to each interface
 | 
				
			||||||
 *   handles ->pre_reset(), the second reset might happen or not.
 | 
					 *   handles ->pre_reset(), the second reset might happen or not.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * - If a driver is unbound and it had a pending reset, the reset will
 | 
					 * - If the reset is delayed so long that the interface is unbound from
 | 
				
			||||||
 *   be cancelled.
 | 
					 *   its driver, the reset will be skipped.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * - This function can be called during .probe() or .disconnect()
 | 
					 * - This function can be called during .probe().  It can also be called
 | 
				
			||||||
 *   times. On return from .disconnect(), any pending resets will be
 | 
					 *   during .disconnect(), but doing so is pointless because the reset
 | 
				
			||||||
 *   cancelled.
 | 
					 *   will not occur.  If you really want to reset the device during
 | 
				
			||||||
 *
 | 
					 *   .disconnect(), call usb_reset_device() directly -- but watch out
 | 
				
			||||||
 * There is no no need to lock/unlock the @reset_ws as schedule_work()
 | 
					 *   for nested unbinding issues!
 | 
				
			||||||
 * does its own.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * NOTE: We don't do any reference count tracking because it is not
 | 
					 | 
				
			||||||
 *     needed. The lifecycle of the work_struct is tied to the
 | 
					 | 
				
			||||||
 *     usb_interface. Before destroying the interface we cancel the
 | 
					 | 
				
			||||||
 *     work_struct, so the fact that work_struct is queued and or
 | 
					 | 
				
			||||||
 *     running means the interface (and thus, the device) exist and
 | 
					 | 
				
			||||||
 *     are referenced.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void usb_queue_reset_device(struct usb_interface *iface)
 | 
					void usb_queue_reset_device(struct usb_interface *iface)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	schedule_work(&iface->reset_ws);
 | 
						if (schedule_work(&iface->reset_ws))
 | 
				
			||||||
 | 
							usb_get_intf(iface);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(usb_queue_reset_device);
 | 
					EXPORT_SYMBOL_GPL(usb_queue_reset_device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1551,6 +1551,7 @@ static void usb_release_interface(struct device *dev)
 | 
				
			||||||
			altsetting_to_usb_interface_cache(intf->altsetting);
 | 
								altsetting_to_usb_interface_cache(intf->altsetting);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kref_put(&intfc->ref, usb_release_interface_cache);
 | 
						kref_put(&intfc->ref, usb_release_interface_cache);
 | 
				
			||||||
 | 
						usb_put_dev(interface_to_usbdev(intf));
 | 
				
			||||||
	kfree(intf);
 | 
						kfree(intf);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1626,24 +1627,6 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Internal function to queue a device reset
 | 
					 * Internal function to queue a device reset
 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This is initialized into the workstruct in 'struct
 | 
					 | 
				
			||||||
 * usb_device->reset_ws' that is launched by
 | 
					 | 
				
			||||||
 * message.c:usb_set_configuration() when initializing each 'struct
 | 
					 | 
				
			||||||
 * usb_interface'.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * It is safe to get the USB device without reference counts because
 | 
					 | 
				
			||||||
 * the life cycle of @iface is bound to the life cycle of @udev. Then,
 | 
					 | 
				
			||||||
 * this function will be ran only if @iface is alive (and before
 | 
					 | 
				
			||||||
 * freeing it any scheduled instances of it will have been cancelled).
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * We need to set a flag (usb_dev->reset_running) because when we call
 | 
					 | 
				
			||||||
 * the reset, the interfaces might be unbound. The current interface
 | 
					 | 
				
			||||||
 * cannot try to remove the queued work as it would cause a deadlock
 | 
					 | 
				
			||||||
 * (you cannot remove your work from within your executing
 | 
					 | 
				
			||||||
 * workqueue). This flag lets it know, so that
 | 
					 | 
				
			||||||
 * usb_cancel_queued_reset() doesn't try to do it.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * See usb_queue_reset_device() for more details
 | 
					 * See usb_queue_reset_device() for more details
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void __usb_queue_reset_device(struct work_struct *ws)
 | 
					static void __usb_queue_reset_device(struct work_struct *ws)
 | 
				
			||||||
| 
						 | 
					@ -1655,11 +1638,10 @@ static void __usb_queue_reset_device(struct work_struct *ws)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = usb_lock_device_for_reset(udev, iface);
 | 
						rc = usb_lock_device_for_reset(udev, iface);
 | 
				
			||||||
	if (rc >= 0) {
 | 
						if (rc >= 0) {
 | 
				
			||||||
		iface->reset_running = 1;
 | 
					 | 
				
			||||||
		usb_reset_device(udev);
 | 
							usb_reset_device(udev);
 | 
				
			||||||
		iface->reset_running = 0;
 | 
					 | 
				
			||||||
		usb_unlock_device(udev);
 | 
							usb_unlock_device(udev);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						usb_put_intf(iface);	/* Undo _get_ in usb_queue_reset_device() */
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1854,6 +1836,7 @@ free_interfaces:
 | 
				
			||||||
		dev_set_name(&intf->dev, "%d-%s:%d.%d",
 | 
							dev_set_name(&intf->dev, "%d-%s:%d.%d",
 | 
				
			||||||
			dev->bus->busnum, dev->devpath,
 | 
								dev->bus->busnum, dev->devpath,
 | 
				
			||||||
			configuration, alt->desc.bInterfaceNumber);
 | 
								configuration, alt->desc.bInterfaceNumber);
 | 
				
			||||||
 | 
							usb_get_dev(dev);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	kfree(new_interfaces);
 | 
						kfree(new_interfaces);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1049,6 +1049,7 @@ static int __init usb_init(void)
 | 
				
			||||||
		pr_info("%s: USB support disabled\n", usbcore_name);
 | 
							pr_info("%s: USB support disabled\n", usbcore_name);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						usb_init_pool_max();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	retval = usb_debugfs_init();
 | 
						retval = usb_debugfs_init();
 | 
				
			||||||
	if (retval)
 | 
						if (retval)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,7 @@ choice
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config USB_DWC2_HOST
 | 
					config USB_DWC2_HOST
 | 
				
			||||||
	bool "Host only mode"
 | 
						bool "Host only mode"
 | 
				
			||||||
	depends on USB
 | 
						depends on USB=y || (USB_DWC2=m && USB)
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  The Designware USB2.0 high-speed host controller
 | 
						  The Designware USB2.0 high-speed host controller
 | 
				
			||||||
	  integrated into many SoCs. Select this option if you want the
 | 
						  integrated into many SoCs. Select this option if you want the
 | 
				
			||||||
| 
						 | 
					@ -42,7 +42,7 @@ config USB_DWC2_PERIPHERAL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config USB_DWC2_DUAL_ROLE
 | 
					config USB_DWC2_DUAL_ROLE
 | 
				
			||||||
	bool "Dual Role mode"
 | 
						bool "Dual Role mode"
 | 
				
			||||||
	depends on (USB=y || USB=USB_DWC2) && (USB_GADGET=y || USB_GADGET=USB_DWC2)
 | 
						depends on (USB=y && USB_GADGET=y) || (USB_DWC2=m && USB && USB_GADGET)
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  Select this option if you want the driver to work in a dual-role
 | 
						  Select this option if you want the driver to work in a dual-role
 | 
				
			||||||
	  mode. In this mode both host and gadget features are enabled, and
 | 
						  mode. In this mode both host and gadget features are enabled, and
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -462,7 +462,7 @@ int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq)
 | 
				
			||||||
	dwc2_enable_common_interrupts(hsotg);
 | 
						dwc2_enable_common_interrupts(hsotg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Do device or host intialization based on mode during PCD and
 | 
						 * Do device or host initialization based on mode during PCD and
 | 
				
			||||||
	 * HCD initialization
 | 
						 * HCD initialization
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (dwc2_is_host_mode(hsotg)) {
 | 
						if (dwc2_is_host_mode(hsotg)) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -108,7 +108,7 @@ struct s3c_hsotg_req;
 | 
				
			||||||
 * @halted: Set if the endpoint has been halted.
 | 
					 * @halted: Set if the endpoint has been halted.
 | 
				
			||||||
 * @periodic: Set if this is a periodic ep, such as Interrupt
 | 
					 * @periodic: Set if this is a periodic ep, such as Interrupt
 | 
				
			||||||
 * @isochronous: Set if this is a isochronous ep
 | 
					 * @isochronous: Set if this is a isochronous ep
 | 
				
			||||||
 * @sent_zlp: Set if we've sent a zero-length packet.
 | 
					 * @send_zlp: Set if we need to send a zero-length packet.
 | 
				
			||||||
 * @total_data: The total number of data bytes done.
 | 
					 * @total_data: The total number of data bytes done.
 | 
				
			||||||
 * @fifo_size: The size of the FIFO (for periodic IN endpoints)
 | 
					 * @fifo_size: The size of the FIFO (for periodic IN endpoints)
 | 
				
			||||||
 * @fifo_load: The amount of data loaded into the FIFO (periodic IN)
 | 
					 * @fifo_load: The amount of data loaded into the FIFO (periodic IN)
 | 
				
			||||||
| 
						 | 
					@ -149,7 +149,7 @@ struct s3c_hsotg_ep {
 | 
				
			||||||
	unsigned int            halted:1;
 | 
						unsigned int            halted:1;
 | 
				
			||||||
	unsigned int            periodic:1;
 | 
						unsigned int            periodic:1;
 | 
				
			||||||
	unsigned int            isochronous:1;
 | 
						unsigned int            isochronous:1;
 | 
				
			||||||
	unsigned int            sent_zlp:1;
 | 
						unsigned int            send_zlp:1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char                    name[10];
 | 
						char                    name[10];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -158,14 +158,12 @@ struct s3c_hsotg_ep {
 | 
				
			||||||
 * struct s3c_hsotg_req - data transfer request
 | 
					 * struct s3c_hsotg_req - data transfer request
 | 
				
			||||||
 * @req: The USB gadget request
 | 
					 * @req: The USB gadget request
 | 
				
			||||||
 * @queue: The list of requests for the endpoint this is queued for.
 | 
					 * @queue: The list of requests for the endpoint this is queued for.
 | 
				
			||||||
 * @in_progress: Has already had size/packets written to core
 | 
					 * @saved_req_buf: variable to save req.buf when bounce buffers are used.
 | 
				
			||||||
 * @mapped: DMA buffer for this request has been mapped via dma_map_single().
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct s3c_hsotg_req {
 | 
					struct s3c_hsotg_req {
 | 
				
			||||||
	struct usb_request      req;
 | 
						struct usb_request      req;
 | 
				
			||||||
	struct list_head        queue;
 | 
						struct list_head        queue;
 | 
				
			||||||
	unsigned char           in_progress;
 | 
						void *saved_req_buf;
 | 
				
			||||||
	unsigned char           mapped;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
 | 
					#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
 | 
				
			||||||
| 
						 | 
					@ -193,6 +191,22 @@ enum dwc2_lx_state {
 | 
				
			||||||
	DWC2_L3,	/* Off state */
 | 
						DWC2_L3,	/* Off state */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Gadget periodic tx fifo sizes as used by legacy driver
 | 
				
			||||||
 | 
					 * EP0 is not included
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define DWC2_G_P_LEGACY_TX_FIFO_SIZE {256, 256, 256, 256, 768, 768, 768, \
 | 
				
			||||||
 | 
										   768, 0, 0, 0, 0, 0, 0, 0}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Gadget ep0 states */
 | 
				
			||||||
 | 
					enum dwc2_ep0_state {
 | 
				
			||||||
 | 
						DWC2_EP0_SETUP,
 | 
				
			||||||
 | 
						DWC2_EP0_DATA_IN,
 | 
				
			||||||
 | 
						DWC2_EP0_DATA_OUT,
 | 
				
			||||||
 | 
						DWC2_EP0_STATUS_IN,
 | 
				
			||||||
 | 
						DWC2_EP0_STATUS_OUT,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * struct dwc2_core_params - Parameters for configuring the core
 | 
					 * struct dwc2_core_params - Parameters for configuring the core
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -381,7 +395,7 @@ struct dwc2_core_params {
 | 
				
			||||||
 * @power_optimized     Are power optimizations enabled?
 | 
					 * @power_optimized     Are power optimizations enabled?
 | 
				
			||||||
 * @num_dev_ep          Number of device endpoints available
 | 
					 * @num_dev_ep          Number of device endpoints available
 | 
				
			||||||
 * @num_dev_perio_in_ep Number of device periodic IN endpoints
 | 
					 * @num_dev_perio_in_ep Number of device periodic IN endpoints
 | 
				
			||||||
 *                      avaialable
 | 
					 *                      available
 | 
				
			||||||
 * @dev_token_q_depth   Device Mode IN Token Sequence Learning Queue
 | 
					 * @dev_token_q_depth   Device Mode IN Token Sequence Learning Queue
 | 
				
			||||||
 *                      Depth
 | 
					 *                      Depth
 | 
				
			||||||
 *                       0 to 30
 | 
					 *                       0 to 30
 | 
				
			||||||
| 
						 | 
					@ -434,6 +448,9 @@ struct dwc2_hw_params {
 | 
				
			||||||
	u32 snpsid;
 | 
						u32 snpsid;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Size of control and EP0 buffers */
 | 
				
			||||||
 | 
					#define DWC2_CTRL_BUFF_SIZE 8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * struct dwc2_hsotg - Holds the state of the driver, including the non-periodic
 | 
					 * struct dwc2_hsotg - Holds the state of the driver, including the non-periodic
 | 
				
			||||||
 * and periodic schedules
 | 
					 * and periodic schedules
 | 
				
			||||||
| 
						 | 
					@ -552,14 +569,20 @@ struct dwc2_hw_params {
 | 
				
			||||||
 * @num_of_eps:         Number of available EPs (excluding EP0)
 | 
					 * @num_of_eps:         Number of available EPs (excluding EP0)
 | 
				
			||||||
 * @debug_root:         Root directrory for debugfs.
 | 
					 * @debug_root:         Root directrory for debugfs.
 | 
				
			||||||
 * @debug_file:         Main status file for debugfs.
 | 
					 * @debug_file:         Main status file for debugfs.
 | 
				
			||||||
 | 
					 * @debug_testmode:     Testmode status file for debugfs.
 | 
				
			||||||
 * @debug_fifo:         FIFO status file for debugfs.
 | 
					 * @debug_fifo:         FIFO status file for debugfs.
 | 
				
			||||||
 * @ep0_reply:          Request used for ep0 reply.
 | 
					 * @ep0_reply:          Request used for ep0 reply.
 | 
				
			||||||
 * @ep0_buff:           Buffer for EP0 reply data, if needed.
 | 
					 * @ep0_buff:           Buffer for EP0 reply data, if needed.
 | 
				
			||||||
 * @ctrl_buff:          Buffer for EP0 control requests.
 | 
					 * @ctrl_buff:          Buffer for EP0 control requests.
 | 
				
			||||||
 * @ctrl_req:           Request for EP0 control packets.
 | 
					 * @ctrl_req:           Request for EP0 control packets.
 | 
				
			||||||
 * @setup:              NAK management for EP0 SETUP
 | 
					 * @ep0_state:          EP0 control transfers state
 | 
				
			||||||
 | 
					 * @test_mode:          USB test mode requested by the host
 | 
				
			||||||
 * @last_rst:           Time of last reset
 | 
					 * @last_rst:           Time of last reset
 | 
				
			||||||
 * @eps:                The endpoints being supplied to the gadget framework
 | 
					 * @eps:                The endpoints being supplied to the gadget framework
 | 
				
			||||||
 | 
					 * @g_using_dma:          Indicate if dma usage is enabled
 | 
				
			||||||
 | 
					 * @g_rx_fifo_sz:         Contains rx fifo size value
 | 
				
			||||||
 | 
					 * @g_np_g_tx_fifo_sz:      Contains Non-Periodic tx fifo size value
 | 
				
			||||||
 | 
					 * @g_tx_fifo_sz:         Contains tx fifo size value per endpoints
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct dwc2_hsotg {
 | 
					struct dwc2_hsotg {
 | 
				
			||||||
	struct device *dev;
 | 
						struct device *dev;
 | 
				
			||||||
| 
						 | 
					@ -591,6 +614,7 @@ struct dwc2_hsotg {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct dentry *debug_root;
 | 
						struct dentry *debug_root;
 | 
				
			||||||
	struct dentry *debug_file;
 | 
						struct dentry *debug_file;
 | 
				
			||||||
 | 
						struct dentry *debug_testmode;
 | 
				
			||||||
	struct dentry *debug_fifo;
 | 
						struct dentry *debug_fifo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* DWC OTG HW Release versions */
 | 
						/* DWC OTG HW Release versions */
 | 
				
			||||||
| 
						 | 
					@ -684,15 +708,21 @@ struct dwc2_hsotg {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct usb_request *ep0_reply;
 | 
						struct usb_request *ep0_reply;
 | 
				
			||||||
	struct usb_request *ctrl_req;
 | 
						struct usb_request *ctrl_req;
 | 
				
			||||||
	u8 ep0_buff[8];
 | 
						void *ep0_buff;
 | 
				
			||||||
	u8 ctrl_buff[8];
 | 
						void *ctrl_buff;
 | 
				
			||||||
 | 
						enum dwc2_ep0_state ep0_state;
 | 
				
			||||||
 | 
						u8 test_mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct usb_gadget gadget;
 | 
						struct usb_gadget gadget;
 | 
				
			||||||
	unsigned int enabled:1;
 | 
						unsigned int enabled:1;
 | 
				
			||||||
	unsigned int connected:1;
 | 
						unsigned int connected:1;
 | 
				
			||||||
	unsigned int setup:1;
 | 
					 | 
				
			||||||
	unsigned long last_rst;
 | 
						unsigned long last_rst;
 | 
				
			||||||
	struct s3c_hsotg_ep *eps;
 | 
						struct s3c_hsotg_ep *eps_in[MAX_EPS_CHANNELS];
 | 
				
			||||||
 | 
						struct s3c_hsotg_ep *eps_out[MAX_EPS_CHANNELS];
 | 
				
			||||||
 | 
						u32 g_using_dma;
 | 
				
			||||||
 | 
						u32 g_rx_fifo_sz;
 | 
				
			||||||
 | 
						u32 g_np_g_tx_fifo_sz;
 | 
				
			||||||
 | 
						u32 g_tx_fifo_sz[MAX_EPS_CHANNELS];
 | 
				
			||||||
#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
 | 
					#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -969,7 +999,8 @@ extern int s3c_hsotg_remove(struct dwc2_hsotg *hsotg);
 | 
				
			||||||
extern int s3c_hsotg_suspend(struct dwc2_hsotg *dwc2);
 | 
					extern int s3c_hsotg_suspend(struct dwc2_hsotg *dwc2);
 | 
				
			||||||
extern int s3c_hsotg_resume(struct dwc2_hsotg *dwc2);
 | 
					extern int s3c_hsotg_resume(struct dwc2_hsotg *dwc2);
 | 
				
			||||||
extern int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq);
 | 
					extern int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq);
 | 
				
			||||||
extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2);
 | 
					extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
 | 
				
			||||||
 | 
							bool reset);
 | 
				
			||||||
extern void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg);
 | 
					extern void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg);
 | 
				
			||||||
extern void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2);
 | 
					extern void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
| 
						 | 
					@ -981,7 +1012,8 @@ static inline int s3c_hsotg_resume(struct dwc2_hsotg *dwc2)
 | 
				
			||||||
{ return 0; }
 | 
					{ return 0; }
 | 
				
			||||||
static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
 | 
					static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
 | 
				
			||||||
{ return 0; }
 | 
					{ return 0; }
 | 
				
			||||||
static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2) {}
 | 
					static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
 | 
				
			||||||
 | 
							bool reset) {}
 | 
				
			||||||
static inline void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) {}
 | 
					static inline void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) {}
 | 
				
			||||||
static inline void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2) {}
 | 
					static inline void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2) {}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -316,10 +316,12 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void dwc2_hcd_rem_wakeup(struct dwc2_hsotg *hsotg)
 | 
					static void dwc2_hcd_rem_wakeup(struct dwc2_hsotg *hsotg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (hsotg->lx_state == DWC2_L2)
 | 
						if (hsotg->lx_state == DWC2_L2) {
 | 
				
			||||||
		hsotg->flags.b.port_suspend_change = 1;
 | 
							hsotg->flags.b.port_suspend_change = 1;
 | 
				
			||||||
	else
 | 
							usb_hcd_resume_root_hub(hsotg->priv);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
		hsotg->flags.b.port_l1_change = 1;
 | 
							hsotg->flags.b.port_l1_change = 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -1371,7 +1373,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
 | 
				
			||||||
		hsotg->op_state = OTG_STATE_B_PERIPHERAL;
 | 
							hsotg->op_state = OTG_STATE_B_PERIPHERAL;
 | 
				
			||||||
		dwc2_core_init(hsotg, false, -1);
 | 
							dwc2_core_init(hsotg, false, -1);
 | 
				
			||||||
		dwc2_enable_global_interrupts(hsotg);
 | 
							dwc2_enable_global_interrupts(hsotg);
 | 
				
			||||||
		s3c_hsotg_core_init_disconnected(hsotg);
 | 
							s3c_hsotg_core_init_disconnected(hsotg, false);
 | 
				
			||||||
		s3c_hsotg_core_connect(hsotg);
 | 
							s3c_hsotg_core_connect(hsotg);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		/* A-Device connector (Host Mode) */
 | 
							/* A-Device connector (Host Mode) */
 | 
				
			||||||
| 
						 | 
					@ -1473,30 +1475,6 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void dwc2_port_resume(struct dwc2_hsotg *hsotg)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	u32 hprt0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* After clear the Stop PHY clock bit, we should wait for a moment
 | 
					 | 
				
			||||||
	 * for PLL work stable with clock output.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	writel(0, hsotg->regs + PCGCTL);
 | 
					 | 
				
			||||||
	usleep_range(2000, 4000);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	hprt0 = dwc2_read_hprt0(hsotg);
 | 
					 | 
				
			||||||
	hprt0 |= HPRT0_RES;
 | 
					 | 
				
			||||||
	writel(hprt0, hsotg->regs + HPRT0);
 | 
					 | 
				
			||||||
	hprt0 &= ~HPRT0_SUSP;
 | 
					 | 
				
			||||||
	/* according to USB2.0 Spec 7.1.7.7, the host must send the resume
 | 
					 | 
				
			||||||
	 * signal for at least 20ms
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	usleep_range(20000, 25000);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	hprt0 &= ~HPRT0_RES;
 | 
					 | 
				
			||||||
	writel(hprt0, hsotg->regs + HPRT0);
 | 
					 | 
				
			||||||
	hsotg->lx_state = DWC2_L0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Handles hub class-specific requests */
 | 
					/* Handles hub class-specific requests */
 | 
				
			||||||
static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
 | 
					static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
 | 
				
			||||||
				u16 wvalue, u16 windex, char *buf, u16 wlength)
 | 
									u16 wvalue, u16 windex, char *buf, u16 wlength)
 | 
				
			||||||
| 
						 | 
					@ -1542,7 +1520,17 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
 | 
				
			||||||
		case USB_PORT_FEAT_SUSPEND:
 | 
							case USB_PORT_FEAT_SUSPEND:
 | 
				
			||||||
			dev_dbg(hsotg->dev,
 | 
								dev_dbg(hsotg->dev,
 | 
				
			||||||
				"ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
 | 
									"ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
 | 
				
			||||||
			dwc2_port_resume(hsotg);
 | 
								writel(0, hsotg->regs + PCGCTL);
 | 
				
			||||||
 | 
								usleep_range(20000, 40000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								hprt0 = dwc2_read_hprt0(hsotg);
 | 
				
			||||||
 | 
								hprt0 |= HPRT0_RES;
 | 
				
			||||||
 | 
								writel(hprt0, hsotg->regs + HPRT0);
 | 
				
			||||||
 | 
								hprt0 &= ~HPRT0_SUSP;
 | 
				
			||||||
 | 
								usleep_range(100000, 150000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								hprt0 &= ~HPRT0_RES;
 | 
				
			||||||
 | 
								writel(hprt0, hsotg->regs + HPRT0);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case USB_PORT_FEAT_POWER:
 | 
							case USB_PORT_FEAT_POWER:
 | 
				
			||||||
| 
						 | 
					@ -1622,7 +1610,9 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
 | 
				
			||||||
		hub_desc->bDescLength = 9;
 | 
							hub_desc->bDescLength = 9;
 | 
				
			||||||
		hub_desc->bDescriptorType = 0x29;
 | 
							hub_desc->bDescriptorType = 0x29;
 | 
				
			||||||
		hub_desc->bNbrPorts = 1;
 | 
							hub_desc->bNbrPorts = 1;
 | 
				
			||||||
		hub_desc->wHubCharacteristics = cpu_to_le16(0x08);
 | 
							hub_desc->wHubCharacteristics =
 | 
				
			||||||
 | 
								cpu_to_le16(HUB_CHAR_COMMON_LPSM |
 | 
				
			||||||
 | 
									    HUB_CHAR_INDV_PORT_OCPM);
 | 
				
			||||||
		hub_desc->bPwrOn2PwrGood = 1;
 | 
							hub_desc->bPwrOn2PwrGood = 1;
 | 
				
			||||||
		hub_desc->bHubContrCurrent = 0;
 | 
							hub_desc->bHubContrCurrent = 0;
 | 
				
			||||||
		hub_desc->u.hs.DeviceRemovable[0] = 0;
 | 
							hub_desc->u.hs.DeviceRemovable[0] = 0;
 | 
				
			||||||
| 
						 | 
					@ -2315,55 +2305,6 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
 | 
				
			||||||
	usleep_range(1000, 3000);
 | 
						usleep_range(1000, 3000);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
 | 
					 | 
				
			||||||
	u32 hprt0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!((hsotg->op_state == OTG_STATE_B_HOST) ||
 | 
					 | 
				
			||||||
		(hsotg->op_state == OTG_STATE_A_HOST)))
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* TODO: We get into suspend from 'on' state, maybe we need to do
 | 
					 | 
				
			||||||
	 * something if we get here from DWC2_L1(LPM sleep) state one day.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (hsotg->lx_state != DWC2_L0)
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	hprt0 = dwc2_read_hprt0(hsotg);
 | 
					 | 
				
			||||||
	if (hprt0 & HPRT0_CONNSTS) {
 | 
					 | 
				
			||||||
		dwc2_port_suspend(hsotg, 1);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		u32 pcgctl = readl(hsotg->regs + PCGCTL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		pcgctl |= PCGCTL_STOPPCLK;
 | 
					 | 
				
			||||||
		writel(pcgctl, hsotg->regs + PCGCTL);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int _dwc2_hcd_resume(struct usb_hcd *hcd)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
 | 
					 | 
				
			||||||
	u32 hprt0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!((hsotg->op_state == OTG_STATE_B_HOST) ||
 | 
					 | 
				
			||||||
		(hsotg->op_state == OTG_STATE_A_HOST)))
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (hsotg->lx_state != DWC2_L2)
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	hprt0 = dwc2_read_hprt0(hsotg);
 | 
					 | 
				
			||||||
	if ((hprt0 & HPRT0_CONNSTS) && (hprt0 & HPRT0_SUSP))
 | 
					 | 
				
			||||||
		dwc2_port_resume(hsotg);
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		writel(0, hsotg->regs + PCGCTL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Returns the current frame number */
 | 
					/* Returns the current frame number */
 | 
				
			||||||
static int _dwc2_hcd_get_frame_number(struct usb_hcd *hcd)
 | 
					static int _dwc2_hcd_get_frame_number(struct usb_hcd *hcd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -2734,9 +2675,6 @@ static struct hc_driver dwc2_hc_driver = {
 | 
				
			||||||
	.hub_status_data = _dwc2_hcd_hub_status_data,
 | 
						.hub_status_data = _dwc2_hcd_hub_status_data,
 | 
				
			||||||
	.hub_control = _dwc2_hcd_hub_control,
 | 
						.hub_control = _dwc2_hcd_hub_control,
 | 
				
			||||||
	.clear_tt_buffer_complete = _dwc2_hcd_clear_tt_buffer_complete,
 | 
						.clear_tt_buffer_complete = _dwc2_hcd_clear_tt_buffer_complete,
 | 
				
			||||||
 | 
					 | 
				
			||||||
	.bus_suspend = _dwc2_hcd_suspend,
 | 
					 | 
				
			||||||
	.bus_resume = _dwc2_hcd_resume,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -294,6 +294,7 @@
 | 
				
			||||||
#define GHWCFG4_NUM_IN_EPS_MASK			(0xf << 26)
 | 
					#define GHWCFG4_NUM_IN_EPS_MASK			(0xf << 26)
 | 
				
			||||||
#define GHWCFG4_NUM_IN_EPS_SHIFT		26
 | 
					#define GHWCFG4_NUM_IN_EPS_SHIFT		26
 | 
				
			||||||
#define GHWCFG4_DED_FIFO_EN			(1 << 25)
 | 
					#define GHWCFG4_DED_FIFO_EN			(1 << 25)
 | 
				
			||||||
 | 
					#define GHWCFG4_DED_FIFO_SHIFT		25
 | 
				
			||||||
#define GHWCFG4_SESSION_END_FILT_EN		(1 << 24)
 | 
					#define GHWCFG4_SESSION_END_FILT_EN		(1 << 24)
 | 
				
			||||||
#define GHWCFG4_B_VALID_FILT_EN			(1 << 23)
 | 
					#define GHWCFG4_B_VALID_FILT_EN			(1 << 23)
 | 
				
			||||||
#define GHWCFG4_A_VALID_FILT_EN			(1 << 22)
 | 
					#define GHWCFG4_A_VALID_FILT_EN			(1 << 22)
 | 
				
			||||||
| 
						 | 
					@ -541,6 +542,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DIEPINT(_a)			HSOTG_REG(0x908 + ((_a) * 0x20))
 | 
					#define DIEPINT(_a)			HSOTG_REG(0x908 + ((_a) * 0x20))
 | 
				
			||||||
#define DOEPINT(_a)			HSOTG_REG(0xB08 + ((_a) * 0x20))
 | 
					#define DOEPINT(_a)			HSOTG_REG(0xB08 + ((_a) * 0x20))
 | 
				
			||||||
 | 
					#define DXEPINT_SETUP_RCVD		(1 << 15)
 | 
				
			||||||
#define DXEPINT_INEPNAKEFF		(1 << 6)
 | 
					#define DXEPINT_INEPNAKEFF		(1 << 6)
 | 
				
			||||||
#define DXEPINT_BACK2BACKSETUP		(1 << 6)
 | 
					#define DXEPINT_BACK2BACKSETUP		(1 << 6)
 | 
				
			||||||
#define DXEPINT_INTKNEPMIS		(1 << 5)
 | 
					#define DXEPINT_INTKNEPMIS		(1 << 5)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -155,6 +155,8 @@ static int dwc2_driver_probe(struct platform_device *dev)
 | 
				
			||||||
	struct dwc2_core_params defparams;
 | 
						struct dwc2_core_params defparams;
 | 
				
			||||||
	struct dwc2_hsotg *hsotg;
 | 
						struct dwc2_hsotg *hsotg;
 | 
				
			||||||
	struct resource *res;
 | 
						struct resource *res;
 | 
				
			||||||
 | 
						struct phy *phy;
 | 
				
			||||||
 | 
						struct usb_phy *uphy;
 | 
				
			||||||
	int retval;
 | 
						int retval;
 | 
				
			||||||
	int irq;
 | 
						int irq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -212,6 +214,24 @@ static int dwc2_driver_probe(struct platform_device *dev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hsotg->dr_mode = of_usb_get_dr_mode(dev->dev.of_node);
 | 
						hsotg->dr_mode = of_usb_get_dr_mode(dev->dev.of_node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Attempt to find a generic PHY, then look for an old style
 | 
				
			||||||
 | 
						 * USB PHY
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						phy = devm_phy_get(&dev->dev, "usb2-phy");
 | 
				
			||||||
 | 
						if (IS_ERR(phy)) {
 | 
				
			||||||
 | 
							hsotg->phy = NULL;
 | 
				
			||||||
 | 
							uphy = devm_usb_get_phy(&dev->dev, USB_PHY_TYPE_USB2);
 | 
				
			||||||
 | 
							if (IS_ERR(uphy))
 | 
				
			||||||
 | 
								hsotg->uphy = NULL;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								hsotg->uphy = uphy;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							hsotg->phy = phy;
 | 
				
			||||||
 | 
							phy_power_on(hsotg->phy);
 | 
				
			||||||
 | 
							phy_init(hsotg->phy);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock_init(&hsotg->lock);
 | 
						spin_lock_init(&hsotg->lock);
 | 
				
			||||||
	mutex_init(&hsotg->init_mutex);
 | 
						mutex_init(&hsotg->init_mutex);
 | 
				
			||||||
	retval = dwc2_gadget_init(hsotg, irq);
 | 
						retval = dwc2_gadget_init(hsotg, irq);
 | 
				
			||||||
| 
						 | 
					@ -231,8 +251,15 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
 | 
				
			||||||
	struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
 | 
						struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dwc2_is_device_mode(dwc2))
 | 
						if (dwc2_is_device_mode(dwc2)) {
 | 
				
			||||||
		ret = s3c_hsotg_suspend(dwc2);
 | 
							ret = s3c_hsotg_suspend(dwc2);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if (dwc2->lx_state == DWC2_L0)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							phy_exit(dwc2->phy);
 | 
				
			||||||
 | 
							phy_power_off(dwc2->phy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -241,8 +268,13 @@ static int __maybe_unused dwc2_resume(struct device *dev)
 | 
				
			||||||
	struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
 | 
						struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dwc2_is_device_mode(dwc2))
 | 
						if (dwc2_is_device_mode(dwc2)) {
 | 
				
			||||||
		ret = s3c_hsotg_resume(dwc2);
 | 
							ret = s3c_hsotg_resume(dwc2);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							phy_power_on(dwc2->phy);
 | 
				
			||||||
 | 
							phy_init(dwc2->phy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -104,12 +104,6 @@ config USB_DWC3_DEBUG
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  Say Y here to enable debugging messages on DWC3 Driver.
 | 
						  Say Y here to enable debugging messages on DWC3 Driver.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config USB_DWC3_VERBOSE
 | 
					 | 
				
			||||||
	bool "Enable Verbose Debugging Messages"
 | 
					 | 
				
			||||||
	depends on USB_DWC3_DEBUG
 | 
					 | 
				
			||||||
	help
 | 
					 | 
				
			||||||
	  Say Y here to enable verbose debugging messages on DWC3 Driver.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
config DWC3_HOST_USB3_LPM_ENABLE
 | 
					config DWC3_HOST_USB3_LPM_ENABLE
 | 
				
			||||||
	bool "Enable USB3 LPM Capability"
 | 
						bool "Enable USB3 LPM Capability"
 | 
				
			||||||
	depends on USB_DWC3_HOST=y || USB_DWC3_DUAL_ROLE=y
 | 
						depends on USB_DWC3_HOST=y || USB_DWC3_DUAL_ROLE=y
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,6 @@
 | 
				
			||||||
CFLAGS_trace.o				:= -I$(src)
 | 
					CFLAGS_trace.o				:= -I$(src)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ccflags-$(CONFIG_USB_DWC3_DEBUG)	:= -DDEBUG
 | 
					ccflags-$(CONFIG_USB_DWC3_DEBUG)	:= -DDEBUG
 | 
				
			||||||
ccflags-$(CONFIG_USB_DWC3_VERBOSE)	+= -DVERBOSE_DEBUG
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-$(CONFIG_USB_DWC3)			+= dwc3.o
 | 
					obj-$(CONFIG_USB_DWC3)			+= dwc3.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -345,7 +345,7 @@ static void dwc3_core_num_eps(struct dwc3 *dwc)
 | 
				
			||||||
	dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
 | 
						dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
 | 
				
			||||||
	dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
 | 
						dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n",
 | 
						dwc3_trace(trace_dwc3_core, "found %d IN and %d OUT endpoints",
 | 
				
			||||||
			dwc->num_in_eps, dwc->num_out_eps);
 | 
								dwc->num_in_eps, dwc->num_out_eps);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -431,7 +431,6 @@ struct dwc3_event_buffer {
 | 
				
			||||||
 * @dwc: pointer to DWC controller
 | 
					 * @dwc: pointer to DWC controller
 | 
				
			||||||
 * @saved_state: ep state saved during hibernation
 | 
					 * @saved_state: ep state saved during hibernation
 | 
				
			||||||
 * @flags: endpoint flags (wedged, stalled, ...)
 | 
					 * @flags: endpoint flags (wedged, stalled, ...)
 | 
				
			||||||
 * @current_trb: index of current used trb
 | 
					 | 
				
			||||||
 * @number: endpoint number (1 - 15)
 | 
					 * @number: endpoint number (1 - 15)
 | 
				
			||||||
 * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
 | 
					 * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
 | 
				
			||||||
 * @resource_index: Resource transfer index
 | 
					 * @resource_index: Resource transfer index
 | 
				
			||||||
| 
						 | 
					@ -464,8 +463,6 @@ struct dwc3_ep {
 | 
				
			||||||
	/* This last one is specific to EP0 */
 | 
						/* This last one is specific to EP0 */
 | 
				
			||||||
#define DWC3_EP0_DIR_IN		(1 << 31)
 | 
					#define DWC3_EP0_DIR_IN		(1 << 31)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned		current_trb;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	u8			number;
 | 
						u8			number;
 | 
				
			||||||
	u8			type;
 | 
						u8			type;
 | 
				
			||||||
	u8			resource_index;
 | 
						u8			resource_index;
 | 
				
			||||||
| 
						 | 
					@ -685,7 +682,6 @@ struct dwc3_scratchpad_array {
 | 
				
			||||||
 * @is_utmi_l1_suspend: the core asserts output signal
 | 
					 * @is_utmi_l1_suspend: the core asserts output signal
 | 
				
			||||||
 * 	0	- utmi_sleep_n
 | 
					 * 	0	- utmi_sleep_n
 | 
				
			||||||
 * 	1	- utmi_l1_suspend_n
 | 
					 * 	1	- utmi_l1_suspend_n
 | 
				
			||||||
 * @is_selfpowered: true when we are selfpowered
 | 
					 | 
				
			||||||
 * @is_fpga: true when we are using the FPGA board
 | 
					 * @is_fpga: true when we are using the FPGA board
 | 
				
			||||||
 * @needs_fifo_resize: not all users might want fifo resizing, flag it
 | 
					 * @needs_fifo_resize: not all users might want fifo resizing, flag it
 | 
				
			||||||
 * @pullups_connected: true when Run/Stop bit is set
 | 
					 * @pullups_connected: true when Run/Stop bit is set
 | 
				
			||||||
| 
						 | 
					@ -809,7 +805,6 @@ struct dwc3 {
 | 
				
			||||||
	unsigned		has_hibernation:1;
 | 
						unsigned		has_hibernation:1;
 | 
				
			||||||
	unsigned		has_lpm_erratum:1;
 | 
						unsigned		has_lpm_erratum:1;
 | 
				
			||||||
	unsigned		is_utmi_l1_suspend:1;
 | 
						unsigned		is_utmi_l1_suspend:1;
 | 
				
			||||||
	unsigned		is_selfpowered:1;
 | 
					 | 
				
			||||||
	unsigned		is_fpga:1;
 | 
						unsigned		is_fpga:1;
 | 
				
			||||||
	unsigned		needs_fifo_resize:1;
 | 
						unsigned		needs_fifo_resize:1;
 | 
				
			||||||
	unsigned		pullups_connected:1;
 | 
						unsigned		pullups_connected:1;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,9 +22,6 @@
 | 
				
			||||||
#include <linux/pci.h>
 | 
					#include <linux/pci.h>
 | 
				
			||||||
#include <linux/platform_device.h>
 | 
					#include <linux/platform_device.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/usb/otg.h>
 | 
					 | 
				
			||||||
#include <linux/usb/usb_phy_generic.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "platform_data.h"
 | 
					#include "platform_data.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* FIXME define these in <linux/pci_ids.h> */
 | 
					/* FIXME define these in <linux/pci_ids.h> */
 | 
				
			||||||
| 
						 | 
					@ -36,66 +33,41 @@
 | 
				
			||||||
#define PCI_DEVICE_ID_INTEL_SPTLP	0x9d30
 | 
					#define PCI_DEVICE_ID_INTEL_SPTLP	0x9d30
 | 
				
			||||||
#define PCI_DEVICE_ID_INTEL_SPTH	0xa130
 | 
					#define PCI_DEVICE_ID_INTEL_SPTH	0xa130
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct dwc3_pci {
 | 
					static int dwc3_pci_quirks(struct pci_dev *pdev)
 | 
				
			||||||
	struct device		*dev;
 | 
					 | 
				
			||||||
	struct platform_device	*dwc3;
 | 
					 | 
				
			||||||
	struct platform_device	*usb2_phy;
 | 
					 | 
				
			||||||
	struct platform_device	*usb3_phy;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int dwc3_pci_register_phys(struct dwc3_pci *glue)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct usb_phy_generic_platform_data pdata;
 | 
						if (pdev->vendor == PCI_VENDOR_ID_AMD &&
 | 
				
			||||||
	struct platform_device	*pdev;
 | 
						    pdev->device == PCI_DEVICE_ID_AMD_NL_USB) {
 | 
				
			||||||
	int			ret;
 | 
							struct dwc3_platform_data pdata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(&pdata, 0x00, sizeof(pdata));
 | 
							memset(&pdata, 0, sizeof(pdata));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pdev = platform_device_alloc("usb_phy_generic", 0);
 | 
							pdata.has_lpm_erratum = true;
 | 
				
			||||||
	if (!pdev)
 | 
							pdata.lpm_nyet_threshold = 0xf;
 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	glue->usb2_phy = pdev;
 | 
							pdata.u2exit_lfps_quirk = true;
 | 
				
			||||||
	pdata.type = USB_PHY_TYPE_USB2;
 | 
							pdata.u2ss_inp3_quirk = true;
 | 
				
			||||||
	pdata.gpio_reset = -1;
 | 
							pdata.req_p1p2p3_quirk = true;
 | 
				
			||||||
 | 
							pdata.del_p1p2p3_quirk = true;
 | 
				
			||||||
 | 
							pdata.del_phy_power_chg_quirk = true;
 | 
				
			||||||
 | 
							pdata.lfps_filter_quirk = true;
 | 
				
			||||||
 | 
							pdata.rx_detect_poll_quirk = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata));
 | 
							pdata.tx_de_emphasis_quirk = true;
 | 
				
			||||||
	if (ret)
 | 
							pdata.tx_de_emphasis = 1;
 | 
				
			||||||
		goto err1;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pdev = platform_device_alloc("usb_phy_generic", 1);
 | 
							/*
 | 
				
			||||||
	if (!pdev) {
 | 
							 * FIXME these quirks should be removed when AMD NL
 | 
				
			||||||
		ret = -ENOMEM;
 | 
							 * taps out
 | 
				
			||||||
		goto err1;
 | 
							 */
 | 
				
			||||||
 | 
							pdata.disable_scramble_quirk = true;
 | 
				
			||||||
 | 
							pdata.dis_u3_susphy_quirk = true;
 | 
				
			||||||
 | 
							pdata.dis_u2_susphy_quirk = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return platform_device_add_data(pci_get_drvdata(pdev), &pdata,
 | 
				
			||||||
 | 
											sizeof(pdata));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	glue->usb3_phy = pdev;
 | 
					 | 
				
			||||||
	pdata.type = USB_PHY_TYPE_USB3;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata));
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		goto err2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = platform_device_add(glue->usb2_phy);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		goto err2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = platform_device_add(glue->usb3_phy);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		goto err3;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
err3:
 | 
					 | 
				
			||||||
	platform_device_del(glue->usb2_phy);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
err2:
 | 
					 | 
				
			||||||
	platform_device_put(glue->usb3_phy);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
err1:
 | 
					 | 
				
			||||||
	platform_device_put(glue->usb2_phy);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int dwc3_pci_probe(struct pci_dev *pci,
 | 
					static int dwc3_pci_probe(struct pci_dev *pci,
 | 
				
			||||||
| 
						 | 
					@ -103,18 +75,8 @@ static int dwc3_pci_probe(struct pci_dev *pci,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct resource		res[2];
 | 
						struct resource		res[2];
 | 
				
			||||||
	struct platform_device	*dwc3;
 | 
						struct platform_device	*dwc3;
 | 
				
			||||||
	struct dwc3_pci		*glue;
 | 
					 | 
				
			||||||
	int			ret;
 | 
						int			ret;
 | 
				
			||||||
	struct device		*dev = &pci->dev;
 | 
						struct device		*dev = &pci->dev;
 | 
				
			||||||
	struct dwc3_platform_data dwc3_pdata;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	memset(&dwc3_pdata, 0x00, sizeof(dwc3_pdata));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
 | 
					 | 
				
			||||||
	if (!glue)
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	glue->dev = dev;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = pcim_enable_device(pci);
 | 
						ret = pcim_enable_device(pci);
 | 
				
			||||||
	if (ret) {
 | 
						if (ret) {
 | 
				
			||||||
| 
						 | 
					@ -124,12 +86,6 @@ static int dwc3_pci_probe(struct pci_dev *pci,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pci_set_master(pci);
 | 
						pci_set_master(pci);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = dwc3_pci_register_phys(glue);
 | 
					 | 
				
			||||||
	if (ret) {
 | 
					 | 
				
			||||||
		dev_err(dev, "couldn't register PHYs\n");
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
 | 
						dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
 | 
				
			||||||
	if (!dwc3) {
 | 
						if (!dwc3) {
 | 
				
			||||||
		dev_err(dev, "couldn't allocate dwc3 device\n");
 | 
							dev_err(dev, "couldn't allocate dwc3 device\n");
 | 
				
			||||||
| 
						 | 
					@ -147,70 +103,34 @@ static int dwc3_pci_probe(struct pci_dev *pci,
 | 
				
			||||||
	res[1].name	= "dwc_usb3";
 | 
						res[1].name	= "dwc_usb3";
 | 
				
			||||||
	res[1].flags	= IORESOURCE_IRQ;
 | 
						res[1].flags	= IORESOURCE_IRQ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pci->vendor == PCI_VENDOR_ID_AMD &&
 | 
					 | 
				
			||||||
			pci->device == PCI_DEVICE_ID_AMD_NL_USB) {
 | 
					 | 
				
			||||||
		dwc3_pdata.has_lpm_erratum = true;
 | 
					 | 
				
			||||||
		dwc3_pdata.lpm_nyet_threshold = 0xf;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		dwc3_pdata.u2exit_lfps_quirk = true;
 | 
					 | 
				
			||||||
		dwc3_pdata.u2ss_inp3_quirk = true;
 | 
					 | 
				
			||||||
		dwc3_pdata.req_p1p2p3_quirk = true;
 | 
					 | 
				
			||||||
		dwc3_pdata.del_p1p2p3_quirk = true;
 | 
					 | 
				
			||||||
		dwc3_pdata.del_phy_power_chg_quirk = true;
 | 
					 | 
				
			||||||
		dwc3_pdata.lfps_filter_quirk = true;
 | 
					 | 
				
			||||||
		dwc3_pdata.rx_detect_poll_quirk = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		dwc3_pdata.tx_de_emphasis_quirk = true;
 | 
					 | 
				
			||||||
		dwc3_pdata.tx_de_emphasis = 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * FIXME these quirks should be removed when AMD NL
 | 
					 | 
				
			||||||
		 * taps out
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		dwc3_pdata.disable_scramble_quirk = true;
 | 
					 | 
				
			||||||
		dwc3_pdata.dis_u3_susphy_quirk = true;
 | 
					 | 
				
			||||||
		dwc3_pdata.dis_u2_susphy_quirk = true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
 | 
						ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
 | 
				
			||||||
	if (ret) {
 | 
						if (ret) {
 | 
				
			||||||
		dev_err(dev, "couldn't add resources to dwc3 device\n");
 | 
							dev_err(dev, "couldn't add resources to dwc3 device\n");
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pci_set_drvdata(pci, glue);
 | 
						pci_set_drvdata(pci, dwc3);
 | 
				
			||||||
 | 
						ret = dwc3_pci_quirks(pci);
 | 
				
			||||||
	ret = platform_device_add_data(dwc3, &dwc3_pdata, sizeof(dwc3_pdata));
 | 
					 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		goto err3;
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	dwc3->dev.dma_mask = dev->dma_mask;
 | 
					 | 
				
			||||||
	dwc3->dev.dma_parms = dev->dma_parms;
 | 
					 | 
				
			||||||
	dwc3->dev.parent = dev;
 | 
						dwc3->dev.parent = dev;
 | 
				
			||||||
	glue->dwc3 = dwc3;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = platform_device_add(dwc3);
 | 
						ret = platform_device_add(dwc3);
 | 
				
			||||||
	if (ret) {
 | 
						if (ret) {
 | 
				
			||||||
		dev_err(dev, "failed to register dwc3 device\n");
 | 
							dev_err(dev, "failed to register dwc3 device\n");
 | 
				
			||||||
		goto err3;
 | 
							goto err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					err:
 | 
				
			||||||
err3:
 | 
					 | 
				
			||||||
	platform_device_put(dwc3);
 | 
						platform_device_put(dwc3);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void dwc3_pci_remove(struct pci_dev *pci)
 | 
					static void dwc3_pci_remove(struct pci_dev *pci)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dwc3_pci	*glue = pci_get_drvdata(pci);
 | 
						platform_device_unregister(pci_get_drvdata(pci));
 | 
				
			||||||
 | 
					 | 
				
			||||||
	platform_device_unregister(glue->dwc3);
 | 
					 | 
				
			||||||
	platform_device_unregister(glue->usb2_phy);
 | 
					 | 
				
			||||||
	platform_device_unregister(glue->usb3_phy);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct pci_device_id dwc3_pci_id_table[] = {
 | 
					static const struct pci_device_id dwc3_pci_id_table[] = {
 | 
				
			||||||
| 
						 | 
					@ -228,45 +148,11 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
 | 
					MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_PM_SLEEP
 | 
					 | 
				
			||||||
static int dwc3_pci_suspend(struct device *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct pci_dev	*pci = to_pci_dev(dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pci_disable_device(pci);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int dwc3_pci_resume(struct device *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct pci_dev	*pci = to_pci_dev(dev);
 | 
					 | 
				
			||||||
	int		ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = pci_enable_device(pci);
 | 
					 | 
				
			||||||
	if (ret) {
 | 
					 | 
				
			||||||
		dev_err(dev, "can't re-enable device --> %d\n", ret);
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pci_set_master(pci);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif /* CONFIG_PM_SLEEP */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
 | 
					 | 
				
			||||||
	SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct pci_driver dwc3_pci_driver = {
 | 
					static struct pci_driver dwc3_pci_driver = {
 | 
				
			||||||
	.name		= "dwc3-pci",
 | 
						.name		= "dwc3-pci",
 | 
				
			||||||
	.id_table	= dwc3_pci_id_table,
 | 
						.id_table	= dwc3_pci_id_table,
 | 
				
			||||||
	.probe		= dwc3_pci_probe,
 | 
						.probe		= dwc3_pci_probe,
 | 
				
			||||||
	.remove		= dwc3_pci_remove,
 | 
						.remove		= dwc3_pci_remove,
 | 
				
			||||||
	.driver		= {
 | 
					 | 
				
			||||||
		.pm	= &dwc3_pci_dev_pm_ops,
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
 | 
					MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -344,7 +344,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * LTM will be set once we know how to set this in HW.
 | 
							 * LTM will be set once we know how to set this in HW.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
 | 
							usb_status |= dwc->gadget.is_selfpowered;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (dwc->speed == DWC3_DSTS_SUPERSPEED) {
 | 
							if (dwc->speed == DWC3_DSTS_SUPERSPEED) {
 | 
				
			||||||
			reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 | 
								reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -139,7 +139,8 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
 | 
				
			||||||
		udelay(5);
 | 
							udelay(5);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_vdbg(dwc->dev, "link state change request timed out\n");
 | 
						dwc3_trace(trace_dwc3_gadget,
 | 
				
			||||||
 | 
								"link state change request timed out");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return -ETIMEDOUT;
 | 
						return -ETIMEDOUT;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -219,7 +220,7 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		fifo_size |= (last_fifo_depth << 16);
 | 
							fifo_size |= (last_fifo_depth << 16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n",
 | 
							dwc3_trace(trace_dwc3_gadget, "%s: Fifo Addr %04x Size %d",
 | 
				
			||||||
				dep->name, last_fifo_depth, fifo_size & 0xffff);
 | 
									dep->name, last_fifo_depth, fifo_size & 0xffff);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size);
 | 
							dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size);
 | 
				
			||||||
| 
						 | 
					@ -287,7 +288,8 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
 | 
				
			||||||
	do {
 | 
						do {
 | 
				
			||||||
		reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
 | 
							reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
 | 
				
			||||||
		if (!(reg & DWC3_DGCMD_CMDACT)) {
 | 
							if (!(reg & DWC3_DGCMD_CMDACT)) {
 | 
				
			||||||
			dev_vdbg(dwc->dev, "Command Complete --> %d\n",
 | 
								dwc3_trace(trace_dwc3_gadget,
 | 
				
			||||||
 | 
										"Command Complete --> %d",
 | 
				
			||||||
					DWC3_DGCMD_STATUS(reg));
 | 
										DWC3_DGCMD_STATUS(reg));
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -297,8 +299,11 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
 | 
				
			||||||
		 * interrupt context.
 | 
							 * interrupt context.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		timeout--;
 | 
							timeout--;
 | 
				
			||||||
		if (!timeout)
 | 
							if (!timeout) {
 | 
				
			||||||
 | 
								dwc3_trace(trace_dwc3_gadget,
 | 
				
			||||||
 | 
										"Command Timed Out");
 | 
				
			||||||
			return -ETIMEDOUT;
 | 
								return -ETIMEDOUT;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		udelay(1);
 | 
							udelay(1);
 | 
				
			||||||
	} while (1);
 | 
						} while (1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -320,7 +325,8 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
 | 
				
			||||||
	do {
 | 
						do {
 | 
				
			||||||
		reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep));
 | 
							reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep));
 | 
				
			||||||
		if (!(reg & DWC3_DEPCMD_CMDACT)) {
 | 
							if (!(reg & DWC3_DEPCMD_CMDACT)) {
 | 
				
			||||||
			dev_vdbg(dwc->dev, "Command Complete --> %d\n",
 | 
								dwc3_trace(trace_dwc3_gadget,
 | 
				
			||||||
 | 
										"Command Complete --> %d",
 | 
				
			||||||
					DWC3_DEPCMD_STATUS(reg));
 | 
										DWC3_DEPCMD_STATUS(reg));
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -330,8 +336,11 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
 | 
				
			||||||
		 * interrupt context.
 | 
							 * interrupt context.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		timeout--;
 | 
							timeout--;
 | 
				
			||||||
		if (!timeout)
 | 
							if (!timeout) {
 | 
				
			||||||
 | 
								dwc3_trace(trace_dwc3_gadget,
 | 
				
			||||||
 | 
										"Command Timed Out");
 | 
				
			||||||
			return -ETIMEDOUT;
 | 
								return -ETIMEDOUT;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		udelay(1);
 | 
							udelay(1);
 | 
				
			||||||
	} while (1);
 | 
						} while (1);
 | 
				
			||||||
| 
						 | 
					@ -352,9 +361,6 @@ static int dwc3_alloc_trb_pool(struct dwc3_ep *dep)
 | 
				
			||||||
	if (dep->trb_pool)
 | 
						if (dep->trb_pool)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dep->number == 0 || dep->number == 1)
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	dep->trb_pool = dma_alloc_coherent(dwc->dev,
 | 
						dep->trb_pool = dma_alloc_coherent(dwc->dev,
 | 
				
			||||||
			sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
 | 
								sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
 | 
				
			||||||
			&dep->trb_pool_dma, GFP_KERNEL);
 | 
								&dep->trb_pool_dma, GFP_KERNEL);
 | 
				
			||||||
| 
						 | 
					@ -492,7 +498,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
 | 
				
			||||||
	u32			reg;
 | 
						u32			reg;
 | 
				
			||||||
	int			ret;
 | 
						int			ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
 | 
						dwc3_trace(trace_dwc3_gadget, "Enabling %s", dep->name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(dep->flags & DWC3_EP_ENABLED)) {
 | 
						if (!(dep->flags & DWC3_EP_ENABLED)) {
 | 
				
			||||||
		ret = dwc3_gadget_start_config(dwc, dep);
 | 
							ret = dwc3_gadget_start_config(dwc, dep);
 | 
				
			||||||
| 
						 | 
					@ -729,10 +735,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
 | 
				
			||||||
		struct dwc3_request *req, dma_addr_t dma,
 | 
							struct dwc3_request *req, dma_addr_t dma,
 | 
				
			||||||
		unsigned length, unsigned last, unsigned chain, unsigned node)
 | 
							unsigned length, unsigned last, unsigned chain, unsigned node)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dwc3		*dwc = dep->dwc;
 | 
					 | 
				
			||||||
	struct dwc3_trb		*trb;
 | 
						struct dwc3_trb		*trb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
 | 
						dwc3_trace(trace_dwc3_gadget, "%s: req %p dma %08llx length %d%s%s",
 | 
				
			||||||
			dep->name, req, (unsigned long long) dma,
 | 
								dep->name, req, (unsigned long long) dma,
 | 
				
			||||||
			length, last ? " last" : "",
 | 
								length, last ? " last" : "",
 | 
				
			||||||
			chain ? " chain" : "");
 | 
								chain ? " chain" : "");
 | 
				
			||||||
| 
						 | 
					@ -934,7 +939,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
 | 
				
			||||||
	u32				cmd;
 | 
						u32				cmd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (start_new && (dep->flags & DWC3_EP_BUSY)) {
 | 
						if (start_new && (dep->flags & DWC3_EP_BUSY)) {
 | 
				
			||||||
		dev_vdbg(dwc->dev, "%s: endpoint busy\n", dep->name);
 | 
							dwc3_trace(trace_dwc3_gadget, "%s: endpoint busy", dep->name);
 | 
				
			||||||
		return -EBUSY;
 | 
							return -EBUSY;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	dep->flags &= ~DWC3_EP_PENDING_REQUEST;
 | 
						dep->flags &= ~DWC3_EP_PENDING_REQUEST;
 | 
				
			||||||
| 
						 | 
					@ -1005,8 +1010,9 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
 | 
				
			||||||
	u32 uf;
 | 
						u32 uf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (list_empty(&dep->request_list)) {
 | 
						if (list_empty(&dep->request_list)) {
 | 
				
			||||||
		dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
 | 
							dwc3_trace(trace_dwc3_gadget,
 | 
				
			||||||
			dep->name);
 | 
									"ISOC ep %s run out for requests",
 | 
				
			||||||
 | 
									dep->name);
 | 
				
			||||||
		dep->flags |= DWC3_EP_PENDING_REQUEST;
 | 
							dep->flags |= DWC3_EP_PENDING_REQUEST;
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1113,15 +1119,10 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 | 
				
			||||||
	 * handled.
 | 
						 * handled.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (dep->stream_capable) {
 | 
						if (dep->stream_capable) {
 | 
				
			||||||
		int	ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ret = __dwc3_gadget_kick_transfer(dep, 0, true);
 | 
							ret = __dwc3_gadget_kick_transfer(dep, 0, true);
 | 
				
			||||||
		if (ret && ret != -EBUSY) {
 | 
							if (ret && ret != -EBUSY)
 | 
				
			||||||
			struct dwc3	*dwc = dep->dwc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
 | 
								dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
 | 
				
			||||||
					dep->name);
 | 
										dep->name);
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -1152,8 +1153,6 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
 | 
					 | 
				
			||||||
			request, ep->name, request->length);
 | 
					 | 
				
			||||||
	trace_dwc3_ep_queue(req);
 | 
						trace_dwc3_ep_queue(req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = __dwc3_gadget_ep_queue(dep, req);
 | 
						ret = __dwc3_gadget_ep_queue(dep, req);
 | 
				
			||||||
| 
						 | 
					@ -1416,7 +1415,7 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
 | 
				
			||||||
	unsigned long		flags;
 | 
						unsigned long		flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock_irqsave(&dwc->lock, flags);
 | 
						spin_lock_irqsave(&dwc->lock, flags);
 | 
				
			||||||
	dwc->is_selfpowered = !!is_selfpowered;
 | 
						g->is_selfpowered = !!is_selfpowered;
 | 
				
			||||||
	spin_unlock_irqrestore(&dwc->lock, flags);
 | 
						spin_unlock_irqrestore(&dwc->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -1468,7 +1467,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
 | 
				
			||||||
		udelay(1);
 | 
							udelay(1);
 | 
				
			||||||
	} while (1);
 | 
						} while (1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_vdbg(dwc->dev, "gadget %s data soft-%s\n",
 | 
						dwc3_trace(trace_dwc3_gadget, "gadget %s data soft-%s",
 | 
				
			||||||
			dwc->gadget_driver
 | 
								dwc->gadget_driver
 | 
				
			||||||
			? dwc->gadget_driver->function : "no-function",
 | 
								? dwc->gadget_driver->function : "no-function",
 | 
				
			||||||
			is_on ? "connect" : "disconnect");
 | 
								is_on ? "connect" : "disconnect");
 | 
				
			||||||
| 
						 | 
					@ -1688,7 +1687,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dep->endpoint.name = dep->name;
 | 
							dep->endpoint.name = dep->name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dev_vdbg(dwc->dev, "initializing %s\n", dep->name);
 | 
							dwc3_trace(trace_dwc3_gadget, "initializing %s", dep->name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (epnum == 0 || epnum == 1) {
 | 
							if (epnum == 0 || epnum == 1) {
 | 
				
			||||||
			usb_ep_set_maxpacket_limit(&dep->endpoint, 512);
 | 
								usb_ep_set_maxpacket_limit(&dep->endpoint, 512);
 | 
				
			||||||
| 
						 | 
					@ -1725,13 +1724,15 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0);
 | 
						ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0);
 | 
				
			||||||
	if (ret < 0) {
 | 
						if (ret < 0) {
 | 
				
			||||||
		dev_vdbg(dwc->dev, "failed to allocate OUT endpoints\n");
 | 
							dwc3_trace(trace_dwc3_gadget,
 | 
				
			||||||
 | 
									"failed to allocate OUT endpoints");
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1);
 | 
						ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1);
 | 
				
			||||||
	if (ret < 0) {
 | 
						if (ret < 0) {
 | 
				
			||||||
		dev_vdbg(dwc->dev, "failed to allocate IN endpoints\n");
 | 
							dwc3_trace(trace_dwc3_gadget,
 | 
				
			||||||
 | 
									"failed to allocate IN endpoints");
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1977,7 +1978,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			int ret;
 | 
								int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			dev_vdbg(dwc->dev, "%s: reason %s\n",
 | 
								dwc3_trace(trace_dwc3_gadget, "%s: reason %s",
 | 
				
			||||||
					dep->name, event->status &
 | 
										dep->name, event->status &
 | 
				
			||||||
					DEPEVT_STATUS_TRANSFER_ACTIVE
 | 
										DEPEVT_STATUS_TRANSFER_ACTIVE
 | 
				
			||||||
					? "Transfer Active"
 | 
										? "Transfer Active"
 | 
				
			||||||
| 
						 | 
					@ -2001,7 +2002,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		switch (event->status) {
 | 
							switch (event->status) {
 | 
				
			||||||
		case DEPEVT_STREAMEVT_FOUND:
 | 
							case DEPEVT_STREAMEVT_FOUND:
 | 
				
			||||||
			dev_vdbg(dwc->dev, "Stream %d found and started\n",
 | 
								dwc3_trace(trace_dwc3_gadget,
 | 
				
			||||||
 | 
										"Stream %d found and started",
 | 
				
			||||||
					event->parameters);
 | 
										event->parameters);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
| 
						 | 
					@ -2015,7 +2017,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
 | 
				
			||||||
		dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name);
 | 
							dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case DWC3_DEPEVT_EPCMDCMPLT:
 | 
						case DWC3_DEPEVT_EPCMDCMPLT:
 | 
				
			||||||
		dev_vdbg(dwc->dev, "Endpoint Command Complete\n");
 | 
							dwc3_trace(trace_dwc3_gadget, "Endpoint Command Complete");
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2043,6 +2045,7 @@ static void dwc3_resume_gadget(struct dwc3 *dwc)
 | 
				
			||||||
	if (dwc->gadget_driver && dwc->gadget_driver->resume) {
 | 
						if (dwc->gadget_driver && dwc->gadget_driver->resume) {
 | 
				
			||||||
		spin_unlock(&dwc->lock);
 | 
							spin_unlock(&dwc->lock);
 | 
				
			||||||
		dwc->gadget_driver->resume(&dwc->gadget);
 | 
							dwc->gadget_driver->resume(&dwc->gadget);
 | 
				
			||||||
 | 
							spin_lock(&dwc->lock);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2079,7 +2082,7 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
 | 
				
			||||||
	 * We have discussed this with the IP Provider and it was
 | 
						 * We have discussed this with the IP Provider and it was
 | 
				
			||||||
	 * suggested to giveback all requests here, but give HW some
 | 
						 * suggested to giveback all requests here, but give HW some
 | 
				
			||||||
	 * extra time to synchronize with the interconnect. We're using
 | 
						 * extra time to synchronize with the interconnect. We're using
 | 
				
			||||||
	 * an arbitraty 100us delay for that.
 | 
						 * an arbitrary 100us delay for that.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * Note also that a similar handling was tested by Synopsys
 | 
						 * Note also that a similar handling was tested by Synopsys
 | 
				
			||||||
	 * (thanks a lot Paul) and nothing bad has come out of it.
 | 
						 * (thanks a lot Paul) and nothing bad has come out of it.
 | 
				
			||||||
| 
						 | 
					@ -2389,7 +2392,8 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
 | 
				
			||||||
			(pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) {
 | 
								(pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) {
 | 
				
			||||||
		if ((dwc->link_state == DWC3_LINK_STATE_U3) &&
 | 
							if ((dwc->link_state == DWC3_LINK_STATE_U3) &&
 | 
				
			||||||
				(next == DWC3_LINK_STATE_RESUME)) {
 | 
									(next == DWC3_LINK_STATE_RESUME)) {
 | 
				
			||||||
			dev_vdbg(dwc->dev, "ignoring transition U3 -> Resume\n");
 | 
								dwc3_trace(trace_dwc3_gadget,
 | 
				
			||||||
 | 
										"ignoring transition U3 -> Resume");
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -2511,22 +2515,22 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
 | 
				
			||||||
		dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
 | 
							dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case DWC3_DEVICE_EVENT_EOPF:
 | 
						case DWC3_DEVICE_EVENT_EOPF:
 | 
				
			||||||
		dev_vdbg(dwc->dev, "End of Periodic Frame\n");
 | 
							dwc3_trace(trace_dwc3_gadget, "End of Periodic Frame");
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case DWC3_DEVICE_EVENT_SOF:
 | 
						case DWC3_DEVICE_EVENT_SOF:
 | 
				
			||||||
		dev_vdbg(dwc->dev, "Start of Periodic Frame\n");
 | 
							dwc3_trace(trace_dwc3_gadget, "Start of Periodic Frame");
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
 | 
						case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
 | 
				
			||||||
		dev_vdbg(dwc->dev, "Erratic Error\n");
 | 
							dwc3_trace(trace_dwc3_gadget, "Erratic Error");
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case DWC3_DEVICE_EVENT_CMD_CMPL:
 | 
						case DWC3_DEVICE_EVENT_CMD_CMPL:
 | 
				
			||||||
		dev_vdbg(dwc->dev, "Command Complete\n");
 | 
							dwc3_trace(trace_dwc3_gadget, "Command Complete");
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case DWC3_DEVICE_EVENT_OVERFLOW:
 | 
						case DWC3_DEVICE_EVENT_OVERFLOW:
 | 
				
			||||||
		dev_vdbg(dwc->dev, "Overflow\n");
 | 
							dwc3_trace(trace_dwc3_gadget, "Overflow");
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
 | 
							dev_WARN(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,6 +47,16 @@ DEFINE_EVENT(dwc3_log_msg, dwc3_writel,
 | 
				
			||||||
	TP_ARGS(vaf)
 | 
						TP_ARGS(vaf)
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFINE_EVENT(dwc3_log_msg, dwc3_gadget,
 | 
				
			||||||
 | 
						TP_PROTO(struct va_format *vaf),
 | 
				
			||||||
 | 
						TP_ARGS(vaf)
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFINE_EVENT(dwc3_log_msg, dwc3_core,
 | 
				
			||||||
 | 
						TP_PROTO(struct va_format *vaf),
 | 
				
			||||||
 | 
						TP_ARGS(vaf)
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFINE_EVENT(dwc3_log_msg, dwc3_ep0,
 | 
					DEFINE_EVENT(dwc3_log_msg, dwc3_ep0,
 | 
				
			||||||
	TP_PROTO(struct va_format *vaf),
 | 
						TP_PROTO(struct va_format *vaf),
 | 
				
			||||||
	TP_ARGS(vaf)
 | 
						TP_ARGS(vaf)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -423,6 +423,17 @@ config USB_CONFIGFS_F_HID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  For more information, see Documentation/usb/gadget_hid.txt.
 | 
						  For more information, see Documentation/usb/gadget_hid.txt.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config USB_CONFIGFS_F_UVC
 | 
				
			||||||
 | 
						bool "USB Webcam function"
 | 
				
			||||||
 | 
						depends on USB_CONFIGFS
 | 
				
			||||||
 | 
						depends on VIDEO_DEV
 | 
				
			||||||
 | 
						select VIDEOBUF2_VMALLOC
 | 
				
			||||||
 | 
						select USB_F_UVC
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  The Webcam function acts as a composite USB Audio and Video Class
 | 
				
			||||||
 | 
						  device. It provides a userspace API to process UVC control requests
 | 
				
			||||||
 | 
						  and stream video data to the host.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
source "drivers/usb/gadget/legacy/Kconfig"
 | 
					source "drivers/usb/gadget/legacy/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
endchoice
 | 
					endchoice
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1655,7 +1655,7 @@ unknown:
 | 
				
			||||||
		 * OS descriptors handling
 | 
							 * OS descriptors handling
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		if (cdev->use_os_string && cdev->os_desc_config &&
 | 
							if (cdev->use_os_string && cdev->os_desc_config &&
 | 
				
			||||||
		    (ctrl->bRequest & USB_TYPE_VENDOR) &&
 | 
							    (ctrl->bRequestType & USB_TYPE_VENDOR) &&
 | 
				
			||||||
		    ctrl->bRequest == cdev->b_vendor_code) {
 | 
							    ctrl->bRequest == cdev->b_vendor_code) {
 | 
				
			||||||
			struct usb_request		*req;
 | 
								struct usb_request		*req;
 | 
				
			||||||
			struct usb_configuration	*os_desc_cfg;
 | 
								struct usb_configuration	*os_desc_cfg;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,7 +36,7 @@ usb_f_uac1-y			:= f_uac1.o u_uac1.o
 | 
				
			||||||
obj-$(CONFIG_USB_F_UAC1)	+= usb_f_uac1.o
 | 
					obj-$(CONFIG_USB_F_UAC1)	+= usb_f_uac1.o
 | 
				
			||||||
usb_f_uac2-y			:= f_uac2.o
 | 
					usb_f_uac2-y			:= f_uac2.o
 | 
				
			||||||
obj-$(CONFIG_USB_F_UAC2)	+= usb_f_uac2.o
 | 
					obj-$(CONFIG_USB_F_UAC2)	+= usb_f_uac2.o
 | 
				
			||||||
usb_f_uvc-y			:= f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o
 | 
					usb_f_uvc-y			:= f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_configfs.o
 | 
				
			||||||
obj-$(CONFIG_USB_F_UVC)		+= usb_f_uvc.o
 | 
					obj-$(CONFIG_USB_F_UVC)		+= usb_f_uvc.o
 | 
				
			||||||
usb_f_midi-y			:= f_midi.o
 | 
					usb_f_midi-y			:= f_midi.o
 | 
				
			||||||
obj-$(CONFIG_USB_F_MIDI)	+= usb_f_midi.o
 | 
					obj-$(CONFIG_USB_F_MIDI)	+= usb_f_midi.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,6 +31,7 @@
 | 
				
			||||||
#include <linux/aio.h>
 | 
					#include <linux/aio.h>
 | 
				
			||||||
#include <linux/mmu_context.h>
 | 
					#include <linux/mmu_context.h>
 | 
				
			||||||
#include <linux/poll.h>
 | 
					#include <linux/poll.h>
 | 
				
			||||||
 | 
					#include <linux/eventfd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "u_fs.h"
 | 
					#include "u_fs.h"
 | 
				
			||||||
#include "u_f.h"
 | 
					#include "u_f.h"
 | 
				
			||||||
| 
						 | 
					@ -153,6 +154,8 @@ struct ffs_io_data {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct usb_ep *ep;
 | 
						struct usb_ep *ep;
 | 
				
			||||||
	struct usb_request *req;
 | 
						struct usb_request *req;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct ffs_data *ffs;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ffs_desc_helper {
 | 
					struct ffs_desc_helper {
 | 
				
			||||||
| 
						 | 
					@ -390,17 +393,20 @@ done_spin:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Called with ffs->ev.waitq.lock and ffs->mutex held, both released on exit. */
 | 
				
			||||||
static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
 | 
					static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
 | 
				
			||||||
				     size_t n)
 | 
									     size_t n)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * We are holding ffs->ev.waitq.lock and ffs->mutex and we need
 | 
						 * n cannot be bigger than ffs->ev.count, which cannot be bigger than
 | 
				
			||||||
	 * to release them.
 | 
						 * size of ffs->ev.types array (which is four) so that's how much space
 | 
				
			||||||
 | 
						 * we reserve.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	struct usb_functionfs_event events[n];
 | 
						struct usb_functionfs_event events[ARRAY_SIZE(ffs->ev.types)];
 | 
				
			||||||
 | 
						const size_t size = n * sizeof *events;
 | 
				
			||||||
	unsigned i = 0;
 | 
						unsigned i = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(events, 0, sizeof events);
 | 
						memset(events, 0, size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	do {
 | 
						do {
 | 
				
			||||||
		events[i].type = ffs->ev.types[i];
 | 
							events[i].type = ffs->ev.types[i];
 | 
				
			||||||
| 
						 | 
					@ -410,19 +416,15 @@ static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} while (++i < n);
 | 
						} while (++i < n);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (n < ffs->ev.count) {
 | 
						ffs->ev.count -= n;
 | 
				
			||||||
		ffs->ev.count -= n;
 | 
						if (ffs->ev.count)
 | 
				
			||||||
		memmove(ffs->ev.types, ffs->ev.types + n,
 | 
							memmove(ffs->ev.types, ffs->ev.types + n,
 | 
				
			||||||
			ffs->ev.count * sizeof *ffs->ev.types);
 | 
								ffs->ev.count * sizeof *ffs->ev.types);
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		ffs->ev.count = 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_unlock_irq(&ffs->ev.waitq.lock);
 | 
						spin_unlock_irq(&ffs->ev.waitq.lock);
 | 
				
			||||||
	mutex_unlock(&ffs->mutex);
 | 
						mutex_unlock(&ffs->mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return unlikely(__copy_to_user(buf, events, sizeof events))
 | 
						return unlikely(__copy_to_user(buf, events, size)) ? -EFAULT : size;
 | 
				
			||||||
		? -EFAULT : sizeof events;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
 | 
					static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
 | 
				
			||||||
| 
						 | 
					@ -606,6 +608,8 @@ static unsigned int ffs_ep0_poll(struct file *file, poll_table *wait)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case FFS_CLOSING:
 | 
						case FFS_CLOSING:
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						case FFS_DEACTIVATED:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_unlock(&ffs->mutex);
 | 
						mutex_unlock(&ffs->mutex);
 | 
				
			||||||
| 
						 | 
					@ -673,6 +677,9 @@ static void ffs_user_copy_worker(struct work_struct *work)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	aio_complete(io_data->kiocb, ret, ret);
 | 
						aio_complete(io_data->kiocb, ret, ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (io_data->ffs->ffs_eventfd && !io_data->kiocb->ki_eventfd)
 | 
				
			||||||
 | 
							eventfd_signal(io_data->ffs->ffs_eventfd, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	usb_ep_free_request(io_data->ep, io_data->req);
 | 
						usb_ep_free_request(io_data->ep, io_data->req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	io_data->kiocb->private = NULL;
 | 
						io_data->kiocb->private = NULL;
 | 
				
			||||||
| 
						 | 
					@ -826,6 +833,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
 | 
				
			||||||
			io_data->buf = data;
 | 
								io_data->buf = data;
 | 
				
			||||||
			io_data->ep = ep->ep;
 | 
								io_data->ep = ep->ep;
 | 
				
			||||||
			io_data->req = req;
 | 
								io_data->req = req;
 | 
				
			||||||
 | 
								io_data->ffs = epfile->ffs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			req->context  = io_data;
 | 
								req->context  = io_data;
 | 
				
			||||||
			req->complete = ffs_epfile_async_io_complete;
 | 
								req->complete = ffs_epfile_async_io_complete;
 | 
				
			||||||
| 
						 | 
					@ -1180,6 +1188,7 @@ struct ffs_sb_fill_data {
 | 
				
			||||||
	struct ffs_file_perms perms;
 | 
						struct ffs_file_perms perms;
 | 
				
			||||||
	umode_t root_mode;
 | 
						umode_t root_mode;
 | 
				
			||||||
	const char *dev_name;
 | 
						const char *dev_name;
 | 
				
			||||||
 | 
						bool no_disconnect;
 | 
				
			||||||
	struct ffs_data *ffs_data;
 | 
						struct ffs_data *ffs_data;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1250,6 +1259,12 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Interpret option */
 | 
							/* Interpret option */
 | 
				
			||||||
		switch (eq - opts) {
 | 
							switch (eq - opts) {
 | 
				
			||||||
 | 
							case 13:
 | 
				
			||||||
 | 
								if (!memcmp(opts, "no_disconnect", 13))
 | 
				
			||||||
 | 
									data->no_disconnect = !!value;
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									goto invalid;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		case 5:
 | 
							case 5:
 | 
				
			||||||
			if (!memcmp(opts, "rmode", 5))
 | 
								if (!memcmp(opts, "rmode", 5))
 | 
				
			||||||
				data->root_mode  = (value & 0555) | S_IFDIR;
 | 
									data->root_mode  = (value & 0555) | S_IFDIR;
 | 
				
			||||||
| 
						 | 
					@ -1314,6 +1329,7 @@ ffs_fs_mount(struct file_system_type *t, int flags,
 | 
				
			||||||
			.gid = GLOBAL_ROOT_GID,
 | 
								.gid = GLOBAL_ROOT_GID,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		.root_mode = S_IFDIR | 0500,
 | 
							.root_mode = S_IFDIR | 0500,
 | 
				
			||||||
 | 
							.no_disconnect = false,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	struct dentry *rv;
 | 
						struct dentry *rv;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
| 
						 | 
					@ -1330,6 +1346,7 @@ ffs_fs_mount(struct file_system_type *t, int flags,
 | 
				
			||||||
	if (unlikely(!ffs))
 | 
						if (unlikely(!ffs))
 | 
				
			||||||
		return ERR_PTR(-ENOMEM);
 | 
							return ERR_PTR(-ENOMEM);
 | 
				
			||||||
	ffs->file_perms = data.perms;
 | 
						ffs->file_perms = data.perms;
 | 
				
			||||||
 | 
						ffs->no_disconnect = data.no_disconnect;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ffs->dev_name = kstrdup(dev_name, GFP_KERNEL);
 | 
						ffs->dev_name = kstrdup(dev_name, GFP_KERNEL);
 | 
				
			||||||
	if (unlikely(!ffs->dev_name)) {
 | 
						if (unlikely(!ffs->dev_name)) {
 | 
				
			||||||
| 
						 | 
					@ -1361,6 +1378,7 @@ ffs_fs_kill_sb(struct super_block *sb)
 | 
				
			||||||
	kill_litter_super(sb);
 | 
						kill_litter_super(sb);
 | 
				
			||||||
	if (sb->s_fs_info) {
 | 
						if (sb->s_fs_info) {
 | 
				
			||||||
		ffs_release_dev(sb->s_fs_info);
 | 
							ffs_release_dev(sb->s_fs_info);
 | 
				
			||||||
 | 
							ffs_data_closed(sb->s_fs_info);
 | 
				
			||||||
		ffs_data_put(sb->s_fs_info);
 | 
							ffs_data_put(sb->s_fs_info);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1417,7 +1435,11 @@ static void ffs_data_opened(struct ffs_data *ffs)
 | 
				
			||||||
	ENTER();
 | 
						ENTER();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	atomic_inc(&ffs->ref);
 | 
						atomic_inc(&ffs->ref);
 | 
				
			||||||
	atomic_inc(&ffs->opened);
 | 
						if (atomic_add_return(1, &ffs->opened) == 1 &&
 | 
				
			||||||
 | 
								ffs->state == FFS_DEACTIVATED) {
 | 
				
			||||||
 | 
							ffs->state = FFS_CLOSING;
 | 
				
			||||||
 | 
							ffs_data_reset(ffs);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void ffs_data_put(struct ffs_data *ffs)
 | 
					static void ffs_data_put(struct ffs_data *ffs)
 | 
				
			||||||
| 
						 | 
					@ -1439,6 +1461,21 @@ static void ffs_data_closed(struct ffs_data *ffs)
 | 
				
			||||||
	ENTER();
 | 
						ENTER();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (atomic_dec_and_test(&ffs->opened)) {
 | 
						if (atomic_dec_and_test(&ffs->opened)) {
 | 
				
			||||||
 | 
							if (ffs->no_disconnect) {
 | 
				
			||||||
 | 
								ffs->state = FFS_DEACTIVATED;
 | 
				
			||||||
 | 
								if (ffs->epfiles) {
 | 
				
			||||||
 | 
									ffs_epfiles_destroy(ffs->epfiles,
 | 
				
			||||||
 | 
											   ffs->eps_count);
 | 
				
			||||||
 | 
									ffs->epfiles = NULL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (ffs->setup_state == FFS_SETUP_PENDING)
 | 
				
			||||||
 | 
									__ffs_ep0_stall(ffs);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								ffs->state = FFS_CLOSING;
 | 
				
			||||||
 | 
								ffs_data_reset(ffs);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (atomic_read(&ffs->opened) < 0) {
 | 
				
			||||||
		ffs->state = FFS_CLOSING;
 | 
							ffs->state = FFS_CLOSING;
 | 
				
			||||||
		ffs_data_reset(ffs);
 | 
							ffs_data_reset(ffs);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1480,6 +1517,9 @@ static void ffs_data_clear(struct ffs_data *ffs)
 | 
				
			||||||
	if (ffs->epfiles)
 | 
						if (ffs->epfiles)
 | 
				
			||||||
		ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
 | 
							ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ffs->ffs_eventfd)
 | 
				
			||||||
 | 
							eventfd_ctx_put(ffs->ffs_eventfd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kfree(ffs->raw_descs_data);
 | 
						kfree(ffs->raw_descs_data);
 | 
				
			||||||
	kfree(ffs->raw_strings);
 | 
						kfree(ffs->raw_strings);
 | 
				
			||||||
	kfree(ffs->stringtabs);
 | 
						kfree(ffs->stringtabs);
 | 
				
			||||||
| 
						 | 
					@ -1581,10 +1621,10 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
 | 
				
			||||||
		mutex_init(&epfile->mutex);
 | 
							mutex_init(&epfile->mutex);
 | 
				
			||||||
		init_waitqueue_head(&epfile->wait);
 | 
							init_waitqueue_head(&epfile->wait);
 | 
				
			||||||
		if (ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
 | 
							if (ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
 | 
				
			||||||
			sprintf(epfiles->name, "ep%02x", ffs->eps_addrmap[i]);
 | 
								sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]);
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			sprintf(epfiles->name, "ep%u", i);
 | 
								sprintf(epfile->name, "ep%u", i);
 | 
				
			||||||
		epfile->dentry = ffs_sb_create_file(ffs->sb, epfiles->name,
 | 
							epfile->dentry = ffs_sb_create_file(ffs->sb, epfile->name,
 | 
				
			||||||
						 epfile,
 | 
											 epfile,
 | 
				
			||||||
						 &ffs_epfile_operations);
 | 
											 &ffs_epfile_operations);
 | 
				
			||||||
		if (unlikely(!epfile->dentry)) {
 | 
							if (unlikely(!epfile->dentry)) {
 | 
				
			||||||
| 
						 | 
					@ -1616,7 +1656,6 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
 | 
				
			||||||
	kfree(epfiles);
 | 
						kfree(epfiles);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
static void ffs_func_eps_disable(struct ffs_function *func)
 | 
					static void ffs_func_eps_disable(struct ffs_function *func)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ffs_ep *ep         = func->eps;
 | 
						struct ffs_ep *ep         = func->eps;
 | 
				
			||||||
| 
						 | 
					@ -1629,10 +1668,12 @@ static void ffs_func_eps_disable(struct ffs_function *func)
 | 
				
			||||||
		/* pending requests get nuked */
 | 
							/* pending requests get nuked */
 | 
				
			||||||
		if (likely(ep->ep))
 | 
							if (likely(ep->ep))
 | 
				
			||||||
			usb_ep_disable(ep->ep);
 | 
								usb_ep_disable(ep->ep);
 | 
				
			||||||
		epfile->ep = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		++ep;
 | 
							++ep;
 | 
				
			||||||
		++epfile;
 | 
					
 | 
				
			||||||
 | 
							if (epfile) {
 | 
				
			||||||
 | 
								epfile->ep = NULL;
 | 
				
			||||||
 | 
								++epfile;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	} while (--count);
 | 
						} while (--count);
 | 
				
			||||||
	spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
 | 
						spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2138,7 +2179,8 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
 | 
				
			||||||
			      FUNCTIONFS_HAS_HS_DESC |
 | 
								      FUNCTIONFS_HAS_HS_DESC |
 | 
				
			||||||
			      FUNCTIONFS_HAS_SS_DESC |
 | 
								      FUNCTIONFS_HAS_SS_DESC |
 | 
				
			||||||
			      FUNCTIONFS_HAS_MS_OS_DESC |
 | 
								      FUNCTIONFS_HAS_MS_OS_DESC |
 | 
				
			||||||
			      FUNCTIONFS_VIRTUAL_ADDR)) {
 | 
								      FUNCTIONFS_VIRTUAL_ADDR |
 | 
				
			||||||
 | 
								      FUNCTIONFS_EVENTFD)) {
 | 
				
			||||||
			ret = -ENOSYS;
 | 
								ret = -ENOSYS;
 | 
				
			||||||
			goto error;
 | 
								goto error;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -2149,6 +2191,20 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (flags & FUNCTIONFS_EVENTFD) {
 | 
				
			||||||
 | 
							if (len < 4)
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
							ffs->ffs_eventfd =
 | 
				
			||||||
 | 
								eventfd_ctx_fdget((int)get_unaligned_le32(data));
 | 
				
			||||||
 | 
							if (IS_ERR(ffs->ffs_eventfd)) {
 | 
				
			||||||
 | 
								ret = PTR_ERR(ffs->ffs_eventfd);
 | 
				
			||||||
 | 
								ffs->ffs_eventfd = NULL;
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							data += 4;
 | 
				
			||||||
 | 
							len  -= 4;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Read fs_count, hs_count and ss_count (if present) */
 | 
						/* Read fs_count, hs_count and ss_count (if present) */
 | 
				
			||||||
	for (i = 0; i < 3; ++i) {
 | 
						for (i = 0; i < 3; ++i) {
 | 
				
			||||||
		if (!(flags & (1 << i))) {
 | 
							if (!(flags & (1 << i))) {
 | 
				
			||||||
| 
						 | 
					@ -2377,6 +2433,13 @@ static void __ffs_event_add(struct ffs_data *ffs,
 | 
				
			||||||
	if (ffs->setup_state == FFS_SETUP_PENDING)
 | 
						if (ffs->setup_state == FFS_SETUP_PENDING)
 | 
				
			||||||
		ffs->setup_state = FFS_SETUP_CANCELLED;
 | 
							ffs->setup_state = FFS_SETUP_CANCELLED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Logic of this function guarantees that there are at most four pending
 | 
				
			||||||
 | 
						 * evens on ffs->ev.types queue.  This is important because the queue
 | 
				
			||||||
 | 
						 * has space for four elements only and __ffs_ep0_read_events function
 | 
				
			||||||
 | 
						 * depends on that limit as well.  If more event types are added, those
 | 
				
			||||||
 | 
						 * limits have to be revisited or guaranteed to still hold.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	switch (type) {
 | 
						switch (type) {
 | 
				
			||||||
	case FUNCTIONFS_RESUME:
 | 
						case FUNCTIONFS_RESUME:
 | 
				
			||||||
		rem_type2 = FUNCTIONFS_SUSPEND;
 | 
							rem_type2 = FUNCTIONFS_SUSPEND;
 | 
				
			||||||
| 
						 | 
					@ -2416,6 +2479,8 @@ static void __ffs_event_add(struct ffs_data *ffs,
 | 
				
			||||||
	pr_vdebug("adding event %d\n", type);
 | 
						pr_vdebug("adding event %d\n", type);
 | 
				
			||||||
	ffs->ev.types[ffs->ev.count++] = type;
 | 
						ffs->ev.types[ffs->ev.count++] = type;
 | 
				
			||||||
	wake_up_locked(&ffs->ev.waitq);
 | 
						wake_up_locked(&ffs->ev.waitq);
 | 
				
			||||||
 | 
						if (ffs->ffs_eventfd)
 | 
				
			||||||
 | 
							eventfd_signal(ffs->ffs_eventfd, 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void ffs_event_add(struct ffs_data *ffs,
 | 
					static void ffs_event_add(struct ffs_data *ffs,
 | 
				
			||||||
| 
						 | 
					@ -2888,6 +2953,13 @@ static int ffs_func_bind(struct usb_configuration *c,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Other USB function hooks *************************************************/
 | 
					/* Other USB function hooks *************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ffs_reset_work(struct work_struct *work)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ffs_data *ffs = container_of(work,
 | 
				
			||||||
 | 
							struct ffs_data, reset_work);
 | 
				
			||||||
 | 
						ffs_data_reset(ffs);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ffs_func_set_alt(struct usb_function *f,
 | 
					static int ffs_func_set_alt(struct usb_function *f,
 | 
				
			||||||
			    unsigned interface, unsigned alt)
 | 
								    unsigned interface, unsigned alt)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -2904,6 +2976,13 @@ static int ffs_func_set_alt(struct usb_function *f,
 | 
				
			||||||
	if (ffs->func)
 | 
						if (ffs->func)
 | 
				
			||||||
		ffs_func_eps_disable(ffs->func);
 | 
							ffs_func_eps_disable(ffs->func);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ffs->state == FFS_DEACTIVATED) {
 | 
				
			||||||
 | 
							ffs->state = FFS_CLOSING;
 | 
				
			||||||
 | 
							INIT_WORK(&ffs->reset_work, ffs_reset_work);
 | 
				
			||||||
 | 
							schedule_work(&ffs->reset_work);
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ffs->state != FFS_ACTIVE)
 | 
						if (ffs->state != FFS_ACTIVE)
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -759,7 +759,7 @@ static struct f_hid_opts_attribute f_hid_opts_##name =			\
 | 
				
			||||||
 | 
					
 | 
				
			||||||
F_HID_OPT(subclass, 8, 255);
 | 
					F_HID_OPT(subclass, 8, 255);
 | 
				
			||||||
F_HID_OPT(protocol, 8, 255);
 | 
					F_HID_OPT(protocol, 8, 255);
 | 
				
			||||||
F_HID_OPT(report_length, 16, 65536);
 | 
					F_HID_OPT(report_length, 16, 65535);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t f_hid_opts_report_desc_show(struct f_hid_opts *opts, char *page)
 | 
					static ssize_t f_hid_opts_report_desc_show(struct f_hid_opts *opts, char *page)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1214,7 +1214,7 @@ static ssize_t f_ss_opts_pattern_show(struct f_ss_opts *opts, char *page)
 | 
				
			||||||
	int result;
 | 
						int result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&opts->lock);
 | 
						mutex_lock(&opts->lock);
 | 
				
			||||||
	result = sprintf(page, "%d", opts->pattern);
 | 
						result = sprintf(page, "%u", opts->pattern);
 | 
				
			||||||
	mutex_unlock(&opts->lock);
 | 
						mutex_unlock(&opts->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
| 
						 | 
					@ -1258,7 +1258,7 @@ static ssize_t f_ss_opts_isoc_interval_show(struct f_ss_opts *opts, char *page)
 | 
				
			||||||
	int result;
 | 
						int result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&opts->lock);
 | 
						mutex_lock(&opts->lock);
 | 
				
			||||||
	result = sprintf(page, "%d", opts->isoc_interval);
 | 
						result = sprintf(page, "%u", opts->isoc_interval);
 | 
				
			||||||
	mutex_unlock(&opts->lock);
 | 
						mutex_unlock(&opts->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
| 
						 | 
					@ -1302,7 +1302,7 @@ static ssize_t f_ss_opts_isoc_maxpacket_show(struct f_ss_opts *opts, char *page)
 | 
				
			||||||
	int result;
 | 
						int result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&opts->lock);
 | 
						mutex_lock(&opts->lock);
 | 
				
			||||||
	result = sprintf(page, "%d", opts->isoc_maxpacket);
 | 
						result = sprintf(page, "%u", opts->isoc_maxpacket);
 | 
				
			||||||
	mutex_unlock(&opts->lock);
 | 
						mutex_unlock(&opts->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
| 
						 | 
					@ -1346,7 +1346,7 @@ static ssize_t f_ss_opts_isoc_mult_show(struct f_ss_opts *opts, char *page)
 | 
				
			||||||
	int result;
 | 
						int result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&opts->lock);
 | 
						mutex_lock(&opts->lock);
 | 
				
			||||||
	result = sprintf(page, "%d", opts->isoc_mult);
 | 
						result = sprintf(page, "%u", opts->isoc_mult);
 | 
				
			||||||
	mutex_unlock(&opts->lock);
 | 
						mutex_unlock(&opts->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
| 
						 | 
					@ -1390,7 +1390,7 @@ static ssize_t f_ss_opts_isoc_maxburst_show(struct f_ss_opts *opts, char *page)
 | 
				
			||||||
	int result;
 | 
						int result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&opts->lock);
 | 
						mutex_lock(&opts->lock);
 | 
				
			||||||
	result = sprintf(page, "%d", opts->isoc_maxburst);
 | 
						result = sprintf(page, "%u", opts->isoc_maxburst);
 | 
				
			||||||
	mutex_unlock(&opts->lock);
 | 
						mutex_unlock(&opts->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
| 
						 | 
					@ -1434,7 +1434,7 @@ static ssize_t f_ss_opts_bulk_buflen_show(struct f_ss_opts *opts, char *page)
 | 
				
			||||||
	int result;
 | 
						int result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&opts->lock);
 | 
						mutex_lock(&opts->lock);
 | 
				
			||||||
	result = sprintf(page, "%d", opts->bulk_buflen);
 | 
						result = sprintf(page, "%u", opts->bulk_buflen);
 | 
				
			||||||
	mutex_unlock(&opts->lock);
 | 
						mutex_unlock(&opts->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
| 
						 | 
					@ -1473,7 +1473,7 @@ static ssize_t f_ss_opts_int_interval_show(struct f_ss_opts *opts, char *page)
 | 
				
			||||||
	int result;
 | 
						int result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&opts->lock);
 | 
						mutex_lock(&opts->lock);
 | 
				
			||||||
	result = sprintf(page, "%d", opts->int_interval);
 | 
						result = sprintf(page, "%u", opts->int_interval);
 | 
				
			||||||
	mutex_unlock(&opts->lock);
 | 
						mutex_unlock(&opts->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
| 
						 | 
					@ -1517,7 +1517,7 @@ static ssize_t f_ss_opts_int_maxpacket_show(struct f_ss_opts *opts, char *page)
 | 
				
			||||||
	int result;
 | 
						int result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&opts->lock);
 | 
						mutex_lock(&opts->lock);
 | 
				
			||||||
	result = sprintf(page, "%d", opts->int_maxpacket);
 | 
						result = sprintf(page, "%u", opts->int_maxpacket);
 | 
				
			||||||
	mutex_unlock(&opts->lock);
 | 
						mutex_unlock(&opts->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
| 
						 | 
					@ -1561,7 +1561,7 @@ static ssize_t f_ss_opts_int_mult_show(struct f_ss_opts *opts, char *page)
 | 
				
			||||||
	int result;
 | 
						int result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&opts->lock);
 | 
						mutex_lock(&opts->lock);
 | 
				
			||||||
	result = sprintf(page, "%d", opts->int_mult);
 | 
						result = sprintf(page, "%u", opts->int_mult);
 | 
				
			||||||
	mutex_unlock(&opts->lock);
 | 
						mutex_unlock(&opts->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
| 
						 | 
					@ -1605,7 +1605,7 @@ static ssize_t f_ss_opts_int_maxburst_show(struct f_ss_opts *opts, char *page)
 | 
				
			||||||
	int result;
 | 
						int result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&opts->lock);
 | 
						mutex_lock(&opts->lock);
 | 
				
			||||||
	result = sprintf(page, "%d", opts->int_maxburst);
 | 
						result = sprintf(page, "%u", opts->int_maxburst);
 | 
				
			||||||
	mutex_unlock(&opts->lock);
 | 
						mutex_unlock(&opts->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,7 @@ static int generic_get_cmd(struct usb_audio_control *con, u8 cmd);
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define F_AUDIO_AC_INTERFACE	0
 | 
					#define F_AUDIO_AC_INTERFACE	0
 | 
				
			||||||
#define F_AUDIO_AS_INTERFACE	1
 | 
					#define F_AUDIO_AS_INTERFACE	1
 | 
				
			||||||
#define F_AUDIO_NUM_INTERFACES	2
 | 
					#define F_AUDIO_NUM_INTERFACES	1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* B.3.1  Standard AC Interface Descriptor */
 | 
					/* B.3.1  Standard AC Interface Descriptor */
 | 
				
			||||||
static struct usb_interface_descriptor ac_interface_desc = {
 | 
					static struct usb_interface_descriptor ac_interface_desc = {
 | 
				
			||||||
| 
						 | 
					@ -42,14 +42,18 @@ static struct usb_interface_descriptor ac_interface_desc = {
 | 
				
			||||||
	.bInterfaceSubClass =	USB_SUBCLASS_AUDIOCONTROL,
 | 
						.bInterfaceSubClass =	USB_SUBCLASS_AUDIOCONTROL,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
 | 
					/*
 | 
				
			||||||
 | 
					 * The number of AudioStreaming and MIDIStreaming interfaces
 | 
				
			||||||
 | 
					 * in the Audio Interface Collection
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define UAC_DT_AC_HEADER_LENGTH	UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
 | 
					#define UAC_DT_AC_HEADER_LENGTH	UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
 | 
				
			||||||
/* 1 input terminal, 1 output terminal and 1 feature unit */
 | 
					/* 1 input terminal, 1 output terminal and 1 feature unit */
 | 
				
			||||||
#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \
 | 
					#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \
 | 
				
			||||||
	+ UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0))
 | 
						+ UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0))
 | 
				
			||||||
/* B.3.2  Class-Specific AC Interface Descriptor */
 | 
					/* B.3.2  Class-Specific AC Interface Descriptor */
 | 
				
			||||||
static struct uac1_ac_header_descriptor_2 ac_header_desc = {
 | 
					static struct uac1_ac_header_descriptor_1 ac_header_desc = {
 | 
				
			||||||
	.bLength =		UAC_DT_AC_HEADER_LENGTH,
 | 
						.bLength =		UAC_DT_AC_HEADER_LENGTH,
 | 
				
			||||||
	.bDescriptorType =	USB_DT_CS_INTERFACE,
 | 
						.bDescriptorType =	USB_DT_CS_INTERFACE,
 | 
				
			||||||
	.bDescriptorSubtype =	UAC_HEADER,
 | 
						.bDescriptorSubtype =	UAC_HEADER,
 | 
				
			||||||
| 
						 | 
					@ -57,8 +61,8 @@ static struct uac1_ac_header_descriptor_2 ac_header_desc = {
 | 
				
			||||||
	.wTotalLength =		__constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH),
 | 
						.wTotalLength =		__constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH),
 | 
				
			||||||
	.bInCollection =	F_AUDIO_NUM_INTERFACES,
 | 
						.bInCollection =	F_AUDIO_NUM_INTERFACES,
 | 
				
			||||||
	.baInterfaceNr = {
 | 
						.baInterfaceNr = {
 | 
				
			||||||
		[0] =		F_AUDIO_AC_INTERFACE,
 | 
						/* Interface number of the first AudioStream interface */
 | 
				
			||||||
		[1] =		F_AUDIO_AS_INTERFACE,
 | 
							[0] =		1,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -584,6 +588,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (intf == 1) {
 | 
						if (intf == 1) {
 | 
				
			||||||
		if (alt == 1) {
 | 
							if (alt == 1) {
 | 
				
			||||||
 | 
								config_ep_by_speed(cdev->gadget, f, out_ep);
 | 
				
			||||||
			usb_ep_enable(out_ep);
 | 
								usb_ep_enable(out_ep);
 | 
				
			||||||
			out_ep->driver_data = audio;
 | 
								out_ep->driver_data = audio;
 | 
				
			||||||
			audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
 | 
								audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
 | 
				
			||||||
| 
						 | 
					@ -669,7 +674,6 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst);
 | 
						audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst);
 | 
				
			||||||
	audio->card.gadget = c->cdev->gadget;
 | 
						audio->card.gadget = c->cdev->gadget;
 | 
				
			||||||
	audio_opts->card = &audio->card;
 | 
					 | 
				
			||||||
	/* set up ASLA audio devices */
 | 
						/* set up ASLA audio devices */
 | 
				
			||||||
	if (!audio_opts->bound) {
 | 
						if (!audio_opts->bound) {
 | 
				
			||||||
		status = gaudio_setup(&audio->card);
 | 
							status = gaudio_setup(&audio->card);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,10 +27,11 @@
 | 
				
			||||||
#include <media/v4l2-dev.h>
 | 
					#include <media/v4l2-dev.h>
 | 
				
			||||||
#include <media/v4l2-event.h>
 | 
					#include <media/v4l2-event.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "u_uvc.h"
 | 
				
			||||||
#include "uvc.h"
 | 
					#include "uvc.h"
 | 
				
			||||||
 | 
					#include "uvc_configfs.h"
 | 
				
			||||||
#include "uvc_v4l2.h"
 | 
					#include "uvc_v4l2.h"
 | 
				
			||||||
#include "uvc_video.h"
 | 
					#include "uvc_video.h"
 | 
				
			||||||
#include "u_uvc.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
unsigned int uvc_gadget_trace_param;
 | 
					unsigned int uvc_gadget_trace_param;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -509,6 +510,9 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!uvc_control_desc || !uvc_streaming_cls)
 | 
				
			||||||
 | 
							return ERR_PTR(-ENODEV);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Descriptors layout
 | 
						/* Descriptors layout
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * uvc_iad
 | 
						 * uvc_iad
 | 
				
			||||||
| 
						 | 
					@ -605,7 +609,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	INFO(cdev, "uvc_function_bind\n");
 | 
						INFO(cdev, "uvc_function_bind\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	opts = to_f_uvc_opts(f->fi);
 | 
						opts = fi_to_f_uvc_opts(f->fi);
 | 
				
			||||||
	/* Sanity check the streaming endpoint module parameters.
 | 
						/* Sanity check the streaming endpoint module parameters.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U);
 | 
						opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U);
 | 
				
			||||||
| 
						 | 
					@ -700,10 +704,27 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Copy descriptors */
 | 
						/* Copy descriptors */
 | 
				
			||||||
	f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
 | 
						f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
 | 
				
			||||||
	if (gadget_is_dualspeed(cdev->gadget))
 | 
						if (IS_ERR(f->fs_descriptors)) {
 | 
				
			||||||
 | 
							ret = PTR_ERR(f->fs_descriptors);
 | 
				
			||||||
 | 
							f->fs_descriptors = NULL;
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (gadget_is_dualspeed(cdev->gadget)) {
 | 
				
			||||||
		f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
 | 
							f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
 | 
				
			||||||
	if (gadget_is_superspeed(c->cdev->gadget))
 | 
							if (IS_ERR(f->hs_descriptors)) {
 | 
				
			||||||
 | 
								ret = PTR_ERR(f->hs_descriptors);
 | 
				
			||||||
 | 
								f->hs_descriptors = NULL;
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (gadget_is_superspeed(c->cdev->gadget)) {
 | 
				
			||||||
		f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
 | 
							f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
 | 
				
			||||||
 | 
							if (IS_ERR(f->ss_descriptors)) {
 | 
				
			||||||
 | 
								ret = PTR_ERR(f->ss_descriptors);
 | 
				
			||||||
 | 
								f->ss_descriptors = NULL;
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Preallocate control endpoint request. */
 | 
						/* Preallocate control endpoint request. */
 | 
				
			||||||
	uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
 | 
						uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
 | 
				
			||||||
| 
						 | 
					@ -766,27 +787,106 @@ error:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void uvc_free_inst(struct usb_function_instance *f)
 | 
					static void uvc_free_inst(struct usb_function_instance *f)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct f_uvc_opts *opts = to_f_uvc_opts(f);
 | 
						struct f_uvc_opts *opts = fi_to_f_uvc_opts(f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_destroy(&opts->lock);
 | 
				
			||||||
	kfree(opts);
 | 
						kfree(opts);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct usb_function_instance *uvc_alloc_inst(void)
 | 
					static struct usb_function_instance *uvc_alloc_inst(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct f_uvc_opts *opts;
 | 
						struct f_uvc_opts *opts;
 | 
				
			||||||
 | 
						struct uvc_camera_terminal_descriptor *cd;
 | 
				
			||||||
 | 
						struct uvc_processing_unit_descriptor *pd;
 | 
				
			||||||
 | 
						struct uvc_output_terminal_descriptor *od;
 | 
				
			||||||
 | 
						struct uvc_color_matching_descriptor *md;
 | 
				
			||||||
 | 
						struct uvc_descriptor_header **ctl_cls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
 | 
						opts = kzalloc(sizeof(*opts), GFP_KERNEL);
 | 
				
			||||||
	if (!opts)
 | 
						if (!opts)
 | 
				
			||||||
		return ERR_PTR(-ENOMEM);
 | 
							return ERR_PTR(-ENOMEM);
 | 
				
			||||||
	opts->func_inst.free_func_inst = uvc_free_inst;
 | 
						opts->func_inst.free_func_inst = uvc_free_inst;
 | 
				
			||||||
 | 
						mutex_init(&opts->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cd = &opts->uvc_camera_terminal;
 | 
				
			||||||
 | 
						cd->bLength			= UVC_DT_CAMERA_TERMINAL_SIZE(3);
 | 
				
			||||||
 | 
						cd->bDescriptorType		= USB_DT_CS_INTERFACE;
 | 
				
			||||||
 | 
						cd->bDescriptorSubType		= UVC_VC_INPUT_TERMINAL;
 | 
				
			||||||
 | 
						cd->bTerminalID			= 1;
 | 
				
			||||||
 | 
						cd->wTerminalType		= cpu_to_le16(0x0201);
 | 
				
			||||||
 | 
						cd->bAssocTerminal		= 0;
 | 
				
			||||||
 | 
						cd->iTerminal			= 0;
 | 
				
			||||||
 | 
						cd->wObjectiveFocalLengthMin	= cpu_to_le16(0);
 | 
				
			||||||
 | 
						cd->wObjectiveFocalLengthMax	= cpu_to_le16(0);
 | 
				
			||||||
 | 
						cd->wOcularFocalLength		= cpu_to_le16(0);
 | 
				
			||||||
 | 
						cd->bControlSize		= 3;
 | 
				
			||||||
 | 
						cd->bmControls[0]		= 2;
 | 
				
			||||||
 | 
						cd->bmControls[1]		= 0;
 | 
				
			||||||
 | 
						cd->bmControls[2]		= 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pd = &opts->uvc_processing;
 | 
				
			||||||
 | 
						pd->bLength			= UVC_DT_PROCESSING_UNIT_SIZE(2);
 | 
				
			||||||
 | 
						pd->bDescriptorType		= USB_DT_CS_INTERFACE;
 | 
				
			||||||
 | 
						pd->bDescriptorSubType		= UVC_VC_PROCESSING_UNIT;
 | 
				
			||||||
 | 
						pd->bUnitID			= 2;
 | 
				
			||||||
 | 
						pd->bSourceID			= 1;
 | 
				
			||||||
 | 
						pd->wMaxMultiplier		= cpu_to_le16(16*1024);
 | 
				
			||||||
 | 
						pd->bControlSize		= 2;
 | 
				
			||||||
 | 
						pd->bmControls[0]		= 1;
 | 
				
			||||||
 | 
						pd->bmControls[1]		= 0;
 | 
				
			||||||
 | 
						pd->iProcessing			= 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						od = &opts->uvc_output_terminal;
 | 
				
			||||||
 | 
						od->bLength			= UVC_DT_OUTPUT_TERMINAL_SIZE;
 | 
				
			||||||
 | 
						od->bDescriptorType		= USB_DT_CS_INTERFACE;
 | 
				
			||||||
 | 
						od->bDescriptorSubType		= UVC_VC_OUTPUT_TERMINAL;
 | 
				
			||||||
 | 
						od->bTerminalID			= 3;
 | 
				
			||||||
 | 
						od->wTerminalType		= cpu_to_le16(0x0101);
 | 
				
			||||||
 | 
						od->bAssocTerminal		= 0;
 | 
				
			||||||
 | 
						od->bSourceID			= 2;
 | 
				
			||||||
 | 
						od->iTerminal			= 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						md = &opts->uvc_color_matching;
 | 
				
			||||||
 | 
						md->bLength			= UVC_DT_COLOR_MATCHING_SIZE;
 | 
				
			||||||
 | 
						md->bDescriptorType		= USB_DT_CS_INTERFACE;
 | 
				
			||||||
 | 
						md->bDescriptorSubType		= UVC_VS_COLORFORMAT;
 | 
				
			||||||
 | 
						md->bColorPrimaries		= 1;
 | 
				
			||||||
 | 
						md->bTransferCharacteristics	= 1;
 | 
				
			||||||
 | 
						md->bMatrixCoefficients		= 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Prepare fs control class descriptors for configfs-based gadgets */
 | 
				
			||||||
 | 
						ctl_cls = opts->uvc_fs_control_cls;
 | 
				
			||||||
 | 
						ctl_cls[0] = NULL;	/* assigned elsewhere by configfs */
 | 
				
			||||||
 | 
						ctl_cls[1] = (struct uvc_descriptor_header *)cd;
 | 
				
			||||||
 | 
						ctl_cls[2] = (struct uvc_descriptor_header *)pd;
 | 
				
			||||||
 | 
						ctl_cls[3] = (struct uvc_descriptor_header *)od;
 | 
				
			||||||
 | 
						ctl_cls[4] = NULL;	/* NULL-terminate */
 | 
				
			||||||
 | 
						opts->fs_control =
 | 
				
			||||||
 | 
							(const struct uvc_descriptor_header * const *)ctl_cls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Prepare hs control class descriptors for configfs-based gadgets */
 | 
				
			||||||
 | 
						ctl_cls = opts->uvc_ss_control_cls;
 | 
				
			||||||
 | 
						ctl_cls[0] = NULL;	/* assigned elsewhere by configfs */
 | 
				
			||||||
 | 
						ctl_cls[1] = (struct uvc_descriptor_header *)cd;
 | 
				
			||||||
 | 
						ctl_cls[2] = (struct uvc_descriptor_header *)pd;
 | 
				
			||||||
 | 
						ctl_cls[3] = (struct uvc_descriptor_header *)od;
 | 
				
			||||||
 | 
						ctl_cls[4] = NULL;	/* NULL-terminate */
 | 
				
			||||||
 | 
						opts->ss_control =
 | 
				
			||||||
 | 
							(const struct uvc_descriptor_header * const *)ctl_cls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						opts->streaming_interval = 1;
 | 
				
			||||||
 | 
						opts->streaming_maxpacket = 1024;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uvcg_attach_configfs(opts);
 | 
				
			||||||
	return &opts->func_inst;
 | 
						return &opts->func_inst;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void uvc_free(struct usb_function *f)
 | 
					static void uvc_free(struct usb_function *f)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct uvc_device *uvc = to_uvc(f);
 | 
						struct uvc_device *uvc = to_uvc(f);
 | 
				
			||||||
 | 
						struct f_uvc_opts *opts = container_of(f->fi, struct f_uvc_opts,
 | 
				
			||||||
 | 
										       func_inst);
 | 
				
			||||||
 | 
						--opts->refcnt;
 | 
				
			||||||
	kfree(uvc);
 | 
						kfree(uvc);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -812,19 +912,39 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct uvc_device *uvc;
 | 
						struct uvc_device *uvc;
 | 
				
			||||||
	struct f_uvc_opts *opts;
 | 
						struct f_uvc_opts *opts;
 | 
				
			||||||
 | 
						struct uvc_descriptor_header **strm_cls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uvc = kzalloc(sizeof(*uvc), GFP_KERNEL);
 | 
						uvc = kzalloc(sizeof(*uvc), GFP_KERNEL);
 | 
				
			||||||
	if (uvc == NULL)
 | 
						if (uvc == NULL)
 | 
				
			||||||
		return ERR_PTR(-ENOMEM);
 | 
							return ERR_PTR(-ENOMEM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uvc->state = UVC_STATE_DISCONNECTED;
 | 
						uvc->state = UVC_STATE_DISCONNECTED;
 | 
				
			||||||
	opts = to_f_uvc_opts(fi);
 | 
						opts = fi_to_f_uvc_opts(fi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&opts->lock);
 | 
				
			||||||
 | 
						if (opts->uvc_fs_streaming_cls) {
 | 
				
			||||||
 | 
							strm_cls = opts->uvc_fs_streaming_cls;
 | 
				
			||||||
 | 
							opts->fs_streaming =
 | 
				
			||||||
 | 
								(const struct uvc_descriptor_header * const *)strm_cls;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (opts->uvc_hs_streaming_cls) {
 | 
				
			||||||
 | 
							strm_cls = opts->uvc_hs_streaming_cls;
 | 
				
			||||||
 | 
							opts->hs_streaming =
 | 
				
			||||||
 | 
								(const struct uvc_descriptor_header * const *)strm_cls;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (opts->uvc_ss_streaming_cls) {
 | 
				
			||||||
 | 
							strm_cls = opts->uvc_ss_streaming_cls;
 | 
				
			||||||
 | 
							opts->ss_streaming =
 | 
				
			||||||
 | 
								(const struct uvc_descriptor_header * const *)strm_cls;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uvc->desc.fs_control = opts->fs_control;
 | 
						uvc->desc.fs_control = opts->fs_control;
 | 
				
			||||||
	uvc->desc.ss_control = opts->ss_control;
 | 
						uvc->desc.ss_control = opts->ss_control;
 | 
				
			||||||
	uvc->desc.fs_streaming = opts->fs_streaming;
 | 
						uvc->desc.fs_streaming = opts->fs_streaming;
 | 
				
			||||||
	uvc->desc.hs_streaming = opts->hs_streaming;
 | 
						uvc->desc.hs_streaming = opts->hs_streaming;
 | 
				
			||||||
	uvc->desc.ss_streaming = opts->ss_streaming;
 | 
						uvc->desc.ss_streaming = opts->ss_streaming;
 | 
				
			||||||
 | 
						++opts->refcnt;
 | 
				
			||||||
 | 
						mutex_unlock(&opts->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Register the function. */
 | 
						/* Register the function. */
 | 
				
			||||||
	uvc->func.name = "uvc";
 | 
						uvc->func.name = "uvc";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -729,9 +729,7 @@ static int get_ether_addr_str(u8 dev_addr[ETH_ALEN], char *str, int len)
 | 
				
			||||||
	if (len < 18)
 | 
						if (len < 18)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	snprintf(str, len, "%02x:%02x:%02x:%02x:%02x:%02x",
 | 
						snprintf(str, len, "%pM", dev_addr);
 | 
				
			||||||
		 dev_addr[0], dev_addr[1], dev_addr[2],
 | 
					 | 
				
			||||||
		 dev_addr[3], dev_addr[4], dev_addr[5]);
 | 
					 | 
				
			||||||
	return 18;
 | 
						return 18;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,7 @@
 | 
				
			||||||
#include <linux/usb/composite.h>
 | 
					#include <linux/usb/composite.h>
 | 
				
			||||||
#include <linux/list.h>
 | 
					#include <linux/list.h>
 | 
				
			||||||
#include <linux/mutex.h>
 | 
					#include <linux/mutex.h>
 | 
				
			||||||
 | 
					#include <linux/workqueue.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef VERBOSE_DEBUG
 | 
					#ifdef VERBOSE_DEBUG
 | 
				
			||||||
#ifndef pr_vdebug
 | 
					#ifndef pr_vdebug
 | 
				
			||||||
| 
						 | 
					@ -92,6 +93,26 @@ enum ffs_state {
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	FFS_ACTIVE,
 | 
						FFS_ACTIVE,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Function is visible to host, but it's not functional. All
 | 
				
			||||||
 | 
						 * setup requests are stalled and transfers on another endpoints
 | 
				
			||||||
 | 
						 * are refused. All epfiles, except ep0, are deleted so there
 | 
				
			||||||
 | 
						 * is no way to perform any operations on them.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * This state is set after closing all functionfs files, when
 | 
				
			||||||
 | 
						 * mount parameter "no_disconnect=1" has been set. Function will
 | 
				
			||||||
 | 
						 * remain in deactivated state until filesystem is umounted or
 | 
				
			||||||
 | 
						 * ep0 is opened again. In the second case functionfs state will
 | 
				
			||||||
 | 
						 * be reset, and it will be ready for descriptors and strings
 | 
				
			||||||
 | 
						 * writing.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * This is useful only when functionfs is composed to gadget
 | 
				
			||||||
 | 
						 * with another function which can perform some critical
 | 
				
			||||||
 | 
						 * operations, and it's strongly desired to have this operations
 | 
				
			||||||
 | 
						 * completed, even after functionfs files closure.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						FFS_DEACTIVATED,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * All endpoints have been closed.  This state is also set if
 | 
						 * All endpoints have been closed.  This state is also set if
 | 
				
			||||||
	 * we encounter an unrecoverable error.  The only
 | 
						 * we encounter an unrecoverable error.  The only
 | 
				
			||||||
| 
						 | 
					@ -251,6 +272,10 @@ struct ffs_data {
 | 
				
			||||||
		kgid_t				gid;
 | 
							kgid_t				gid;
 | 
				
			||||||
	}				file_perms;
 | 
						}				file_perms;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct eventfd_ctx *ffs_eventfd;
 | 
				
			||||||
 | 
						bool no_disconnect;
 | 
				
			||||||
 | 
						struct work_struct reset_work;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The endpoint files, filled by ffs_epfiles_create(),
 | 
						 * The endpoint files, filled by ffs_epfiles_create(),
 | 
				
			||||||
	 * destroyed by ffs_epfiles_destroy().
 | 
						 * destroyed by ffs_epfiles_destroy().
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -308,8 +308,7 @@ int gaudio_setup(struct gaudio *card)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void gaudio_cleanup(struct gaudio *the_card)
 | 
					void gaudio_cleanup(struct gaudio *the_card)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (the_card) {
 | 
						if (the_card)
 | 
				
			||||||
		gaudio_close_snd_dev(the_card);
 | 
							gaudio_close_snd_dev(the_card);
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,7 +70,6 @@ struct f_uac1_opts {
 | 
				
			||||||
	unsigned			fn_play_alloc:1;
 | 
						unsigned			fn_play_alloc:1;
 | 
				
			||||||
	unsigned			fn_cap_alloc:1;
 | 
						unsigned			fn_cap_alloc:1;
 | 
				
			||||||
	unsigned			fn_cntl_alloc:1;
 | 
						unsigned			fn_cntl_alloc:1;
 | 
				
			||||||
	struct gaudio			*card;
 | 
					 | 
				
			||||||
	struct mutex			lock;
 | 
						struct mutex			lock;
 | 
				
			||||||
	int				refcnt;
 | 
						int				refcnt;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,8 +17,9 @@
 | 
				
			||||||
#define U_UVC_H
 | 
					#define U_UVC_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/usb/composite.h>
 | 
					#include <linux/usb/composite.h>
 | 
				
			||||||
 | 
					#include <linux/usb/video.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define to_f_uvc_opts(f)	container_of(f, struct f_uvc_opts, func_inst)
 | 
					#define fi_to_f_uvc_opts(f)	container_of(f, struct f_uvc_opts, func_inst)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct f_uvc_opts {
 | 
					struct f_uvc_opts {
 | 
				
			||||||
	struct usb_function_instance			func_inst;
 | 
						struct usb_function_instance			func_inst;
 | 
				
			||||||
| 
						 | 
					@ -26,11 +27,60 @@ struct f_uvc_opts {
 | 
				
			||||||
	unsigned int					streaming_interval;
 | 
						unsigned int					streaming_interval;
 | 
				
			||||||
	unsigned int					streaming_maxpacket;
 | 
						unsigned int					streaming_maxpacket;
 | 
				
			||||||
	unsigned int					streaming_maxburst;
 | 
						unsigned int					streaming_maxburst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Control descriptors array pointers for full-/high-speed and
 | 
				
			||||||
 | 
						 * super-speed. They point by default to the uvc_fs_control_cls and
 | 
				
			||||||
 | 
						 * uvc_ss_control_cls arrays respectively. Legacy gadgets must
 | 
				
			||||||
 | 
						 * override them in their gadget bind callback.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	const struct uvc_descriptor_header * const	*fs_control;
 | 
						const struct uvc_descriptor_header * const	*fs_control;
 | 
				
			||||||
	const struct uvc_descriptor_header * const	*ss_control;
 | 
						const struct uvc_descriptor_header * const	*ss_control;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Streaming descriptors array pointers for full-speed, high-speed and
 | 
				
			||||||
 | 
						 * super-speed. They will point to the uvc_[fhs]s_streaming_cls arrays
 | 
				
			||||||
 | 
						 * for configfs-based gadgets. Legacy gadgets must initialize them in
 | 
				
			||||||
 | 
						 * their gadget bind callback.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	const struct uvc_descriptor_header * const	*fs_streaming;
 | 
						const struct uvc_descriptor_header * const	*fs_streaming;
 | 
				
			||||||
	const struct uvc_descriptor_header * const	*hs_streaming;
 | 
						const struct uvc_descriptor_header * const	*hs_streaming;
 | 
				
			||||||
	const struct uvc_descriptor_header * const	*ss_streaming;
 | 
						const struct uvc_descriptor_header * const	*ss_streaming;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Default control descriptors for configfs-based gadgets. */
 | 
				
			||||||
 | 
						struct uvc_camera_terminal_descriptor		uvc_camera_terminal;
 | 
				
			||||||
 | 
						struct uvc_processing_unit_descriptor		uvc_processing;
 | 
				
			||||||
 | 
						struct uvc_output_terminal_descriptor		uvc_output_terminal;
 | 
				
			||||||
 | 
						struct uvc_color_matching_descriptor		uvc_color_matching;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Control descriptors pointers arrays for full-/high-speed and
 | 
				
			||||||
 | 
						 * super-speed. The first element is a configurable control header
 | 
				
			||||||
 | 
						 * descriptor, the other elements point to the fixed default control
 | 
				
			||||||
 | 
						 * descriptors. Used by configfs only, must not be touched by legacy
 | 
				
			||||||
 | 
						 * gadgets.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct uvc_descriptor_header			*uvc_fs_control_cls[5];
 | 
				
			||||||
 | 
						struct uvc_descriptor_header			*uvc_ss_control_cls[5];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Streaming descriptors for full-speed, high-speed and super-speed.
 | 
				
			||||||
 | 
						 * Used by configfs only, must not be touched by legacy gadgets. The
 | 
				
			||||||
 | 
						 * arrays are allocated at runtime as the number of descriptors isn't
 | 
				
			||||||
 | 
						 * known in advance.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct uvc_descriptor_header			**uvc_fs_streaming_cls;
 | 
				
			||||||
 | 
						struct uvc_descriptor_header			**uvc_hs_streaming_cls;
 | 
				
			||||||
 | 
						struct uvc_descriptor_header			**uvc_ss_streaming_cls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Read/write access to configfs attributes is handled by configfs.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * This lock protects the descriptors from concurrent access by
 | 
				
			||||||
 | 
						 * read/write and symlink creation/removal.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct mutex			lock;
 | 
				
			||||||
 | 
						int				refcnt;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void uvc_set_trace_param(unsigned int trace);
 | 
					void uvc_set_trace_param(unsigned int trace);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2468
									
								
								drivers/usb/gadget/function/uvc_configfs.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2468
									
								
								drivers/usb/gadget/function/uvc_configfs.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										22
									
								
								drivers/usb/gadget/function/uvc_configfs.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								drivers/usb/gadget/function/uvc_configfs.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * uvc_configfs.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Configfs support for the uvc function.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
 | 
				
			||||||
 | 
					 *		http://www.samsung.com
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.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 UVC_CONFIGFS_H
 | 
				
			||||||
 | 
					#define UVC_CONFIGFS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct f_uvc_opts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int uvcg_attach_configfs(struct f_uvc_opts *opts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* UVC_CONFIGFS_H */
 | 
				
			||||||
| 
						 | 
					@ -176,7 +176,7 @@ static int proc_udc_show(struct seq_file *s, void *unused)
 | 
				
			||||||
		udc->enabled
 | 
							udc->enabled
 | 
				
			||||||
			? (udc->vbus ? "active" : "enabled")
 | 
								? (udc->vbus ? "active" : "enabled")
 | 
				
			||||||
			: "disabled",
 | 
								: "disabled",
 | 
				
			||||||
		udc->selfpowered ? "self" : "VBUS",
 | 
							udc->gadget.is_selfpowered ? "self" : "VBUS",
 | 
				
			||||||
		udc->suspended ? ", suspended" : "",
 | 
							udc->suspended ? ", suspended" : "",
 | 
				
			||||||
		udc->driver ? udc->driver->driver.name : "(none)");
 | 
							udc->driver ? udc->driver->driver.name : "(none)");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1000,7 +1000,7 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on)
 | 
				
			||||||
	unsigned long	flags;
 | 
						unsigned long	flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock_irqsave(&udc->lock, flags);
 | 
						spin_lock_irqsave(&udc->lock, flags);
 | 
				
			||||||
	udc->selfpowered = (is_on != 0);
 | 
						gadget->is_selfpowered = (is_on != 0);
 | 
				
			||||||
	spin_unlock_irqrestore(&udc->lock, flags);
 | 
						spin_unlock_irqrestore(&udc->lock, flags);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1149,7 +1149,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
 | 
						case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
 | 
				
			||||||
			| USB_REQ_GET_STATUS:
 | 
								| USB_REQ_GET_STATUS:
 | 
				
			||||||
		tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
 | 
							tmp = (udc->gadget.is_selfpowered << USB_DEVICE_SELF_POWERED);
 | 
				
			||||||
		if (at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
 | 
							if (at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
 | 
				
			||||||
			tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP);
 | 
								tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP);
 | 
				
			||||||
		PACKET("get device status\n");
 | 
							PACKET("get device status\n");
 | 
				
			||||||
| 
						 | 
					@ -1653,7 +1653,7 @@ static int at91_start(struct usb_gadget *gadget,
 | 
				
			||||||
	udc->driver = driver;
 | 
						udc->driver = driver;
 | 
				
			||||||
	udc->gadget.dev.of_node = udc->pdev->dev.of_node;
 | 
						udc->gadget.dev.of_node = udc->pdev->dev.of_node;
 | 
				
			||||||
	udc->enabled = 1;
 | 
						udc->enabled = 1;
 | 
				
			||||||
	udc->selfpowered = 1;
 | 
						udc->gadget.is_selfpowered = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -122,7 +122,6 @@ struct at91_udc {
 | 
				
			||||||
	unsigned			req_pending:1;
 | 
						unsigned			req_pending:1;
 | 
				
			||||||
	unsigned			wait_for_addr_ack:1;
 | 
						unsigned			wait_for_addr_ack:1;
 | 
				
			||||||
	unsigned			wait_for_config_ack:1;
 | 
						unsigned			wait_for_config_ack:1;
 | 
				
			||||||
	unsigned			selfpowered:1;
 | 
					 | 
				
			||||||
	unsigned			active_suspend:1;
 | 
						unsigned			active_suspend:1;
 | 
				
			||||||
	u8				addr;
 | 
						u8				addr;
 | 
				
			||||||
	struct at91_udc_data		board;
 | 
						struct at91_udc_data		board;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@
 | 
				
			||||||
 * published by the Free Software Foundation.
 | 
					 * published by the Free Software Foundation.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#include <linux/clk.h>
 | 
					#include <linux/clk.h>
 | 
				
			||||||
 | 
					#include <linux/clk/at91_pmc.h>
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
#include <linux/init.h>
 | 
					#include <linux/init.h>
 | 
				
			||||||
#include <linux/interrupt.h>
 | 
					#include <linux/interrupt.h>
 | 
				
			||||||
| 
						 | 
					@ -315,6 +316,17 @@ static inline void usba_cleanup_debugfs(struct usba_udc *udc)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline u32 usba_int_enb_get(struct usba_udc *udc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return udc->int_enb_cache;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void usba_int_enb_set(struct usba_udc *udc, u32 val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						usba_writel(udc, INT_ENB, val);
 | 
				
			||||||
 | 
						udc->int_enb_cache = val;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int vbus_is_present(struct usba_udc *udc)
 | 
					static int vbus_is_present(struct usba_udc *udc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (gpio_is_valid(udc->vbus_pin))
 | 
						if (gpio_is_valid(udc->vbus_pin))
 | 
				
			||||||
| 
						 | 
					@ -324,27 +336,22 @@ static int vbus_is_present(struct usba_udc *udc)
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(CONFIG_ARCH_AT91SAM9RL)
 | 
					static void toggle_bias(struct usba_udc *udc, int is_on)
 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <linux/clk/at91_pmc.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void toggle_bias(int is_on)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
 | 
						if (udc->errata && udc->errata->toggle_bias)
 | 
				
			||||||
 | 
							udc->errata->toggle_bias(udc, is_on);
 | 
				
			||||||
	if (is_on)
 | 
					 | 
				
			||||||
		at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else
 | 
					static void generate_bias_pulse(struct usba_udc *udc)
 | 
				
			||||||
 | 
					 | 
				
			||||||
static void toggle_bias(int is_on)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
}
 | 
						if (!udc->bias_pulse_needed)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* CONFIG_ARCH_AT91SAM9RL */
 | 
						if (udc->errata && udc->errata->pulse_bias)
 | 
				
			||||||
 | 
							udc->errata->pulse_bias(udc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						udc->bias_pulse_needed = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
 | 
					static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -601,16 +608,14 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 | 
				
			||||||
	if (ep->can_dma) {
 | 
						if (ep->can_dma) {
 | 
				
			||||||
		u32 ctrl;
 | 
							u32 ctrl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		usba_writel(udc, INT_ENB,
 | 
							usba_int_enb_set(udc, usba_int_enb_get(udc) |
 | 
				
			||||||
				(usba_readl(udc, INT_ENB)
 | 
									      USBA_BF(EPT_INT, 1 << ep->index) |
 | 
				
			||||||
					| USBA_BF(EPT_INT, 1 << ep->index)
 | 
									      USBA_BF(DMA_INT, 1 << ep->index));
 | 
				
			||||||
					| USBA_BF(DMA_INT, 1 << ep->index)));
 | 
					 | 
				
			||||||
		ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA;
 | 
							ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA;
 | 
				
			||||||
		usba_ep_writel(ep, CTL_ENB, ctrl);
 | 
							usba_ep_writel(ep, CTL_ENB, ctrl);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		usba_writel(udc, INT_ENB,
 | 
							usba_int_enb_set(udc, usba_int_enb_get(udc) |
 | 
				
			||||||
				(usba_readl(udc, INT_ENB)
 | 
									      USBA_BF(EPT_INT, 1 << ep->index));
 | 
				
			||||||
					| USBA_BF(EPT_INT, 1 << ep->index)));
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_unlock_irqrestore(&udc->lock, flags);
 | 
						spin_unlock_irqrestore(&udc->lock, flags);
 | 
				
			||||||
| 
						 | 
					@ -618,7 +623,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 | 
				
			||||||
	DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index,
 | 
						DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index,
 | 
				
			||||||
			(unsigned long)usba_ep_readl(ep, CFG));
 | 
								(unsigned long)usba_ep_readl(ep, CFG));
 | 
				
			||||||
	DBG(DBG_HW, "INT_ENB after init: %#08lx\n",
 | 
						DBG(DBG_HW, "INT_ENB after init: %#08lx\n",
 | 
				
			||||||
			(unsigned long)usba_readl(udc, INT_ENB));
 | 
								(unsigned long)usba_int_enb_get(udc));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -654,9 +659,8 @@ static int usba_ep_disable(struct usb_ep *_ep)
 | 
				
			||||||
		usba_dma_readl(ep, STATUS);
 | 
							usba_dma_readl(ep, STATUS);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE);
 | 
						usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE);
 | 
				
			||||||
	usba_writel(udc, INT_ENB,
 | 
						usba_int_enb_set(udc, usba_int_enb_get(udc) &
 | 
				
			||||||
			usba_readl(udc, INT_ENB)
 | 
								      ~USBA_BF(EPT_INT, 1 << ep->index));
 | 
				
			||||||
			& ~USBA_BF(EPT_INT, 1 << ep->index));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	request_complete_list(ep, &req_list, -ESHUTDOWN);
 | 
						request_complete_list(ep, &req_list, -ESHUTDOWN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -985,6 +989,7 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
 | 
				
			||||||
	struct usba_udc *udc = to_usba_udc(gadget);
 | 
						struct usba_udc *udc = to_usba_udc(gadget);
 | 
				
			||||||
	unsigned long flags;
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gadget->is_selfpowered = (is_selfpowered != 0);
 | 
				
			||||||
	spin_lock_irqsave(&udc->lock, flags);
 | 
						spin_lock_irqsave(&udc->lock, flags);
 | 
				
			||||||
	if (is_selfpowered)
 | 
						if (is_selfpowered)
 | 
				
			||||||
		udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
 | 
							udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
 | 
				
			||||||
| 
						 | 
					@ -1619,18 +1624,21 @@ static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep)
 | 
				
			||||||
static irqreturn_t usba_udc_irq(int irq, void *devid)
 | 
					static irqreturn_t usba_udc_irq(int irq, void *devid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct usba_udc *udc = devid;
 | 
						struct usba_udc *udc = devid;
 | 
				
			||||||
	u32 status;
 | 
						u32 status, int_enb;
 | 
				
			||||||
	u32 dma_status;
 | 
						u32 dma_status;
 | 
				
			||||||
	u32 ep_status;
 | 
						u32 ep_status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock(&udc->lock);
 | 
						spin_lock(&udc->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	status = usba_readl(udc, INT_STA);
 | 
						int_enb = usba_int_enb_get(udc);
 | 
				
			||||||
 | 
						status = usba_readl(udc, INT_STA) & int_enb;
 | 
				
			||||||
	DBG(DBG_INT, "irq, status=%#08x\n", status);
 | 
						DBG(DBG_INT, "irq, status=%#08x\n", status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (status & USBA_DET_SUSPEND) {
 | 
						if (status & USBA_DET_SUSPEND) {
 | 
				
			||||||
		toggle_bias(0);
 | 
							toggle_bias(udc, 0);
 | 
				
			||||||
		usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
 | 
							usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
 | 
				
			||||||
 | 
							usba_int_enb_set(udc, int_enb | USBA_WAKE_UP);
 | 
				
			||||||
 | 
							udc->bias_pulse_needed = true;
 | 
				
			||||||
		DBG(DBG_BUS, "Suspend detected\n");
 | 
							DBG(DBG_BUS, "Suspend detected\n");
 | 
				
			||||||
		if (udc->gadget.speed != USB_SPEED_UNKNOWN
 | 
							if (udc->gadget.speed != USB_SPEED_UNKNOWN
 | 
				
			||||||
				&& udc->driver && udc->driver->suspend) {
 | 
									&& udc->driver && udc->driver->suspend) {
 | 
				
			||||||
| 
						 | 
					@ -1641,13 +1649,15 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (status & USBA_WAKE_UP) {
 | 
						if (status & USBA_WAKE_UP) {
 | 
				
			||||||
		toggle_bias(1);
 | 
							toggle_bias(udc, 1);
 | 
				
			||||||
		usba_writel(udc, INT_CLR, USBA_WAKE_UP);
 | 
							usba_writel(udc, INT_CLR, USBA_WAKE_UP);
 | 
				
			||||||
 | 
							usba_int_enb_set(udc, int_enb & ~USBA_WAKE_UP);
 | 
				
			||||||
		DBG(DBG_BUS, "Wake Up CPU detected\n");
 | 
							DBG(DBG_BUS, "Wake Up CPU detected\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (status & USBA_END_OF_RESUME) {
 | 
						if (status & USBA_END_OF_RESUME) {
 | 
				
			||||||
		usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
 | 
							usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
 | 
				
			||||||
 | 
							generate_bias_pulse(udc);
 | 
				
			||||||
		DBG(DBG_BUS, "Resume detected\n");
 | 
							DBG(DBG_BUS, "Resume detected\n");
 | 
				
			||||||
		if (udc->gadget.speed != USB_SPEED_UNKNOWN
 | 
							if (udc->gadget.speed != USB_SPEED_UNKNOWN
 | 
				
			||||||
				&& udc->driver && udc->driver->resume) {
 | 
									&& udc->driver && udc->driver->resume) {
 | 
				
			||||||
| 
						 | 
					@ -1683,6 +1693,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
 | 
				
			||||||
		struct usba_ep *ep0;
 | 
							struct usba_ep *ep0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
 | 
							usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
 | 
				
			||||||
 | 
							generate_bias_pulse(udc);
 | 
				
			||||||
		reset_all_endpoints(udc);
 | 
							reset_all_endpoints(udc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (udc->gadget.speed != USB_SPEED_UNKNOWN && udc->driver) {
 | 
							if (udc->gadget.speed != USB_SPEED_UNKNOWN && udc->driver) {
 | 
				
			||||||
| 
						 | 
					@ -1708,11 +1719,8 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
 | 
				
			||||||
				| USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
 | 
									| USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
 | 
				
			||||||
		usba_ep_writel(ep0, CTL_ENB,
 | 
							usba_ep_writel(ep0, CTL_ENB,
 | 
				
			||||||
				USBA_EPT_ENABLE | USBA_RX_SETUP);
 | 
									USBA_EPT_ENABLE | USBA_RX_SETUP);
 | 
				
			||||||
		usba_writel(udc, INT_ENB,
 | 
							usba_int_enb_set(udc, int_enb | USBA_BF(EPT_INT, 1) |
 | 
				
			||||||
				(usba_readl(udc, INT_ENB)
 | 
									      USBA_DET_SUSPEND | USBA_END_OF_RESUME);
 | 
				
			||||||
				| USBA_BF(EPT_INT, 1)
 | 
					 | 
				
			||||||
				| USBA_DET_SUSPEND
 | 
					 | 
				
			||||||
				| USBA_END_OF_RESUME));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * Unclear why we hit this irregularly, e.g. in usbtest,
 | 
							 * Unclear why we hit this irregularly, e.g. in usbtest,
 | 
				
			||||||
| 
						 | 
					@ -1745,13 +1753,13 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
 | 
				
			||||||
	vbus = vbus_is_present(udc);
 | 
						vbus = vbus_is_present(udc);
 | 
				
			||||||
	if (vbus != udc->vbus_prev) {
 | 
						if (vbus != udc->vbus_prev) {
 | 
				
			||||||
		if (vbus) {
 | 
							if (vbus) {
 | 
				
			||||||
			toggle_bias(1);
 | 
								toggle_bias(udc, 1);
 | 
				
			||||||
			usba_writel(udc, CTRL, USBA_ENABLE_MASK);
 | 
								usba_writel(udc, CTRL, USBA_ENABLE_MASK);
 | 
				
			||||||
			usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
 | 
								usba_int_enb_set(udc, USBA_END_OF_RESET);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			udc->gadget.speed = USB_SPEED_UNKNOWN;
 | 
								udc->gadget.speed = USB_SPEED_UNKNOWN;
 | 
				
			||||||
			reset_all_endpoints(udc);
 | 
								reset_all_endpoints(udc);
 | 
				
			||||||
			toggle_bias(0);
 | 
								toggle_bias(udc, 0);
 | 
				
			||||||
			usba_writel(udc, CTRL, USBA_DISABLE_MASK);
 | 
								usba_writel(udc, CTRL, USBA_DISABLE_MASK);
 | 
				
			||||||
			if (udc->driver->disconnect) {
 | 
								if (udc->driver->disconnect) {
 | 
				
			||||||
				spin_unlock(&udc->lock);
 | 
									spin_unlock(&udc->lock);
 | 
				
			||||||
| 
						 | 
					@ -1797,9 +1805,9 @@ static int atmel_usba_start(struct usb_gadget *gadget,
 | 
				
			||||||
	/* If Vbus is present, enable the controller and wait for reset */
 | 
						/* If Vbus is present, enable the controller and wait for reset */
 | 
				
			||||||
	spin_lock_irqsave(&udc->lock, flags);
 | 
						spin_lock_irqsave(&udc->lock, flags);
 | 
				
			||||||
	if (vbus_is_present(udc) && udc->vbus_prev == 0) {
 | 
						if (vbus_is_present(udc) && udc->vbus_prev == 0) {
 | 
				
			||||||
		toggle_bias(1);
 | 
							toggle_bias(udc, 1);
 | 
				
			||||||
		usba_writel(udc, CTRL, USBA_ENABLE_MASK);
 | 
							usba_writel(udc, CTRL, USBA_ENABLE_MASK);
 | 
				
			||||||
		usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
 | 
							usba_int_enb_set(udc, USBA_END_OF_RESET);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	spin_unlock_irqrestore(&udc->lock, flags);
 | 
						spin_unlock_irqrestore(&udc->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1820,7 +1828,7 @@ static int atmel_usba_stop(struct usb_gadget *gadget)
 | 
				
			||||||
	spin_unlock_irqrestore(&udc->lock, flags);
 | 
						spin_unlock_irqrestore(&udc->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* This will also disable the DP pullup */
 | 
						/* This will also disable the DP pullup */
 | 
				
			||||||
	toggle_bias(0);
 | 
						toggle_bias(udc, 0);
 | 
				
			||||||
	usba_writel(udc, CTRL, USBA_DISABLE_MASK);
 | 
						usba_writel(udc, CTRL, USBA_DISABLE_MASK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	clk_disable_unprepare(udc->hclk);
 | 
						clk_disable_unprepare(udc->hclk);
 | 
				
			||||||
| 
						 | 
					@ -1832,6 +1840,41 @@ static int atmel_usba_stop(struct usb_gadget *gadget)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_OF
 | 
					#ifdef CONFIG_OF
 | 
				
			||||||
 | 
					static void at91sam9rl_toggle_bias(struct usba_udc *udc, int is_on)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (is_on)
 | 
				
			||||||
 | 
							at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void at91sam9g45_pulse_bias(struct usba_udc *udc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
 | 
				
			||||||
 | 
						at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct usba_udc_errata at91sam9rl_errata = {
 | 
				
			||||||
 | 
						.toggle_bias = at91sam9rl_toggle_bias,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct usba_udc_errata at91sam9g45_errata = {
 | 
				
			||||||
 | 
						.pulse_bias = at91sam9g45_pulse_bias,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct of_device_id atmel_udc_dt_ids[] = {
 | 
				
			||||||
 | 
						{ .compatible = "atmel,at91sam9rl-udc", .data = &at91sam9rl_errata },
 | 
				
			||||||
 | 
						{ .compatible = "atmel,at91sam9g45-udc", .data = &at91sam9g45_errata },
 | 
				
			||||||
 | 
						{ .compatible = "atmel,sama5d3-udc" },
 | 
				
			||||||
 | 
						{ /* sentinel */ }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MODULE_DEVICE_TABLE(of, atmel_udc_dt_ids);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
 | 
					static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
 | 
				
			||||||
						    struct usba_udc *udc)
 | 
											    struct usba_udc *udc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -1839,10 +1882,17 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
 | 
				
			||||||
	const char *name;
 | 
						const char *name;
 | 
				
			||||||
	enum of_gpio_flags flags;
 | 
						enum of_gpio_flags flags;
 | 
				
			||||||
	struct device_node *np = pdev->dev.of_node;
 | 
						struct device_node *np = pdev->dev.of_node;
 | 
				
			||||||
 | 
						const struct of_device_id *match;
 | 
				
			||||||
	struct device_node *pp;
 | 
						struct device_node *pp;
 | 
				
			||||||
	int i, ret;
 | 
						int i, ret;
 | 
				
			||||||
	struct usba_ep *eps, *ep;
 | 
						struct usba_ep *eps, *ep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						match = of_match_node(atmel_udc_dt_ids, np);
 | 
				
			||||||
 | 
						if (!match)
 | 
				
			||||||
 | 
							return ERR_PTR(-EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						udc->errata = match->data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	udc->num_ep = 0;
 | 
						udc->num_ep = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	udc->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0,
 | 
						udc->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0,
 | 
				
			||||||
| 
						 | 
					@ -2033,7 +2083,7 @@ static int usba_udc_probe(struct platform_device *pdev)
 | 
				
			||||||
		dev_err(&pdev->dev, "Unable to enable pclk, aborting.\n");
 | 
							dev_err(&pdev->dev, "Unable to enable pclk, aborting.\n");
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	toggle_bias(0);
 | 
					
 | 
				
			||||||
	usba_writel(udc, CTRL, USBA_DISABLE_MASK);
 | 
						usba_writel(udc, CTRL, USBA_DISABLE_MASK);
 | 
				
			||||||
	clk_disable_unprepare(pclk);
 | 
						clk_disable_unprepare(pclk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2042,6 +2092,8 @@ static int usba_udc_probe(struct platform_device *pdev)
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		udc->usba_ep = usba_udc_pdata(pdev, udc);
 | 
							udc->usba_ep = usba_udc_pdata(pdev, udc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						toggle_bias(udc, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (IS_ERR(udc->usba_ep))
 | 
						if (IS_ERR(udc->usba_ep))
 | 
				
			||||||
		return PTR_ERR(udc->usba_ep);
 | 
							return PTR_ERR(udc->usba_ep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2101,15 +2153,6 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(CONFIG_OF)
 | 
					 | 
				
			||||||
static const struct of_device_id atmel_udc_dt_ids[] = {
 | 
					 | 
				
			||||||
	{ .compatible = "atmel,at91sam9rl-udc" },
 | 
					 | 
				
			||||||
	{ /* sentinel */ }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
MODULE_DEVICE_TABLE(of, atmel_udc_dt_ids);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct platform_driver udc_driver = {
 | 
					static struct platform_driver udc_driver = {
 | 
				
			||||||
	.remove		= __exit_p(usba_udc_remove),
 | 
						.remove		= __exit_p(usba_udc_remove),
 | 
				
			||||||
	.driver		= {
 | 
						.driver		= {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -304,6 +304,11 @@ struct usba_request {
 | 
				
			||||||
	unsigned int				mapped:1;
 | 
						unsigned int				mapped:1;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usba_udc_errata {
 | 
				
			||||||
 | 
						void (*toggle_bias)(struct usba_udc *udc, int is_on);
 | 
				
			||||||
 | 
						void (*pulse_bias)(struct usba_udc *udc);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct usba_udc {
 | 
					struct usba_udc {
 | 
				
			||||||
	/* Protect hw registers from concurrent modifications */
 | 
						/* Protect hw registers from concurrent modifications */
 | 
				
			||||||
	spinlock_t lock;
 | 
						spinlock_t lock;
 | 
				
			||||||
| 
						 | 
					@ -314,6 +319,7 @@ struct usba_udc {
 | 
				
			||||||
	struct usb_gadget gadget;
 | 
						struct usb_gadget gadget;
 | 
				
			||||||
	struct usb_gadget_driver *driver;
 | 
						struct usb_gadget_driver *driver;
 | 
				
			||||||
	struct platform_device *pdev;
 | 
						struct platform_device *pdev;
 | 
				
			||||||
 | 
						const struct usba_udc_errata *errata;
 | 
				
			||||||
	int irq;
 | 
						int irq;
 | 
				
			||||||
	int vbus_pin;
 | 
						int vbus_pin;
 | 
				
			||||||
	int vbus_pin_inverted;
 | 
						int vbus_pin_inverted;
 | 
				
			||||||
| 
						 | 
					@ -321,12 +327,15 @@ struct usba_udc {
 | 
				
			||||||
	struct clk *pclk;
 | 
						struct clk *pclk;
 | 
				
			||||||
	struct clk *hclk;
 | 
						struct clk *hclk;
 | 
				
			||||||
	struct usba_ep *usba_ep;
 | 
						struct usba_ep *usba_ep;
 | 
				
			||||||
 | 
						bool bias_pulse_needed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u16 devstatus;
 | 
						u16 devstatus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u16 test_mode;
 | 
						u16 test_mode;
 | 
				
			||||||
	int vbus_prev;
 | 
						int vbus_prev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u32 int_enb_cache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_USB_GADGET_DEBUG_FS
 | 
					#ifdef CONFIG_USB_GADGET_DEBUG_FS
 | 
				
			||||||
	struct dentry *debugfs_root;
 | 
						struct dentry *debugfs_root;
 | 
				
			||||||
	struct dentry *debugfs_regs;
 | 
						struct dentry *debugfs_regs;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -521,7 +521,6 @@ static int bdc_remove(struct platform_device *pdev)
 | 
				
			||||||
static struct platform_driver bdc_driver = {
 | 
					static struct platform_driver bdc_driver = {
 | 
				
			||||||
	.driver		= {
 | 
						.driver		= {
 | 
				
			||||||
		.name	= BRCM_BDC_NAME,
 | 
							.name	= BRCM_BDC_NAME,
 | 
				
			||||||
		.owner	= THIS_MODULE
 | 
					 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	.probe		= bdc_probe,
 | 
						.probe		= bdc_probe,
 | 
				
			||||||
	.remove		= bdc_remove,
 | 
						.remove		= bdc_remove,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -718,7 +718,7 @@ static int ep_queue(struct bdc_ep *ep, struct bdc_req *req)
 | 
				
			||||||
	struct bdc *bdc;
 | 
						struct bdc *bdc;
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!req || !ep || !ep->usb_ep.desc)
 | 
						if (!req || !ep->usb_ep.desc)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bdc = ep->bdc;
 | 
						bdc = ep->bdc;
 | 
				
			||||||
| 
						 | 
					@ -882,8 +882,8 @@ static int ep_set_halt(struct bdc_ep *ep, u32 value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ret = bdc_ep_set_stall(bdc, ep->ep_num);
 | 
							ret = bdc_ep_set_stall(bdc, ep->ep_num);
 | 
				
			||||||
		if (ret)
 | 
							if (ret)
 | 
				
			||||||
			dev_err(bdc->dev, "failed to %s STALL on %s\n",
 | 
								dev_err(bdc->dev, "failed to set STALL on %s\n",
 | 
				
			||||||
				value ? "set" : "clear", ep->name);
 | 
									ep->name);
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			ep->flags |= BDC_EP_STALL;
 | 
								ep->flags |= BDC_EP_STALL;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					@ -891,8 +891,8 @@ static int ep_set_halt(struct bdc_ep *ep, u32 value)
 | 
				
			||||||
		dev_dbg(bdc->dev, "Before Clear\n");
 | 
							dev_dbg(bdc->dev, "Before Clear\n");
 | 
				
			||||||
		ret = bdc_ep_clear_stall(bdc, ep->ep_num);
 | 
							ret = bdc_ep_clear_stall(bdc, ep->ep_num);
 | 
				
			||||||
		if (ret)
 | 
							if (ret)
 | 
				
			||||||
			dev_err(bdc->dev, "failed to %s STALL on %s\n",
 | 
								dev_err(bdc->dev, "failed to clear STALL on %s\n",
 | 
				
			||||||
				value ? "set" : "clear", ep->name);
 | 
									ep->name);
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			ep->flags &= ~BDC_EP_STALL;
 | 
								ep->flags &= ~BDC_EP_STALL;
 | 
				
			||||||
		dev_dbg(bdc->dev, "After  Clear\n");
 | 
							dev_dbg(bdc->dev, "After  Clear\n");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -454,6 +454,7 @@ static int bdc_udc_set_selfpowered(struct usb_gadget *gadget,
 | 
				
			||||||
	unsigned long           flags;
 | 
						unsigned long           flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_dbg(bdc->dev, "%s()\n", __func__);
 | 
						dev_dbg(bdc->dev, "%s()\n", __func__);
 | 
				
			||||||
 | 
						gadget->is_selfpowered = (is_self != 0);
 | 
				
			||||||
	spin_lock_irqsave(&bdc->lock, flags);
 | 
						spin_lock_irqsave(&bdc->lock, flags);
 | 
				
			||||||
	if (!is_self)
 | 
						if (!is_self)
 | 
				
			||||||
		bdc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
 | 
							bdc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -802,6 +802,7 @@ static int dummy_set_selfpowered(struct usb_gadget *_gadget, int value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dummy	*dum;
 | 
						struct dummy	*dum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_gadget->is_selfpowered = (value != 0);
 | 
				
			||||||
	dum = gadget_to_dummy_hcd(_gadget)->dum;
 | 
						dum = gadget_to_dummy_hcd(_gadget)->dum;
 | 
				
			||||||
	if (value)
 | 
						if (value)
 | 
				
			||||||
		dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
 | 
							dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
 | 
				
			||||||
| 
						 | 
					@ -1924,7 +1925,9 @@ ss_hub_descriptor(struct usb_hub_descriptor *desc)
 | 
				
			||||||
	memset(desc, 0, sizeof *desc);
 | 
						memset(desc, 0, sizeof *desc);
 | 
				
			||||||
	desc->bDescriptorType = 0x2a;
 | 
						desc->bDescriptorType = 0x2a;
 | 
				
			||||||
	desc->bDescLength = 12;
 | 
						desc->bDescLength = 12;
 | 
				
			||||||
	desc->wHubCharacteristics = cpu_to_le16(0x0001);
 | 
						desc->wHubCharacteristics = cpu_to_le16(
 | 
				
			||||||
 | 
								HUB_CHAR_INDV_PORT_LPSM |
 | 
				
			||||||
 | 
								HUB_CHAR_COMMON_OCPM);
 | 
				
			||||||
	desc->bNbrPorts = 1;
 | 
						desc->bNbrPorts = 1;
 | 
				
			||||||
	desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
 | 
						desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
 | 
				
			||||||
	desc->u.ss.DeviceRemovable = 0xffff;
 | 
						desc->u.ss.DeviceRemovable = 0xffff;
 | 
				
			||||||
| 
						 | 
					@ -1935,7 +1938,9 @@ static inline void hub_descriptor(struct usb_hub_descriptor *desc)
 | 
				
			||||||
	memset(desc, 0, sizeof *desc);
 | 
						memset(desc, 0, sizeof *desc);
 | 
				
			||||||
	desc->bDescriptorType = 0x29;
 | 
						desc->bDescriptorType = 0x29;
 | 
				
			||||||
	desc->bDescLength = 9;
 | 
						desc->bDescLength = 9;
 | 
				
			||||||
	desc->wHubCharacteristics = cpu_to_le16(0x0001);
 | 
						desc->wHubCharacteristics = cpu_to_le16(
 | 
				
			||||||
 | 
								HUB_CHAR_INDV_PORT_LPSM |
 | 
				
			||||||
 | 
								HUB_CHAR_COMMON_OCPM);
 | 
				
			||||||
	desc->bNbrPorts = 1;
 | 
						desc->bNbrPorts = 1;
 | 
				
			||||||
	desc->u.hs.DeviceRemovable[0] = 0xff;
 | 
						desc->u.hs.DeviceRemovable[0] = 0xff;
 | 
				
			||||||
	desc->u.hs.DeviceRemovable[1] = 0xff;
 | 
						desc->u.hs.DeviceRemovable[1] = 0xff;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2630,7 +2630,7 @@ static int qe_udc_remove(struct platform_device *ofdev)
 | 
				
			||||||
	struct qe_udc *udc = platform_get_drvdata(ofdev);
 | 
						struct qe_udc *udc = platform_get_drvdata(ofdev);
 | 
				
			||||||
	struct qe_ep *ep;
 | 
						struct qe_ep *ep;
 | 
				
			||||||
	unsigned int size;
 | 
						unsigned int size;
 | 
				
			||||||
	DECLARE_COMPLETION(done);
 | 
						DECLARE_COMPLETION_ONSTACK(done);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	usb_del_gadget_udc(&udc->gadget);
 | 
						usb_del_gadget_udc(&udc->gadget);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1337,7 +1337,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
 | 
						if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
 | 
				
			||||||
		/* Get device status */
 | 
							/* Get device status */
 | 
				
			||||||
		tmp = 1 << USB_DEVICE_SELF_POWERED;
 | 
							tmp = udc->gadget.is_selfpowered;
 | 
				
			||||||
		tmp |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP;
 | 
							tmp |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP;
 | 
				
			||||||
	} else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
 | 
						} else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
 | 
				
			||||||
		/* Get interface status */
 | 
							/* Get interface status */
 | 
				
			||||||
| 
						 | 
					@ -1948,6 +1948,7 @@ static int fsl_udc_start(struct usb_gadget *g,
 | 
				
			||||||
	/* hook up the driver */
 | 
						/* hook up the driver */
 | 
				
			||||||
	udc_controller->driver = driver;
 | 
						udc_controller->driver = driver;
 | 
				
			||||||
	spin_unlock_irqrestore(&udc_controller->lock, flags);
 | 
						spin_unlock_irqrestore(&udc_controller->lock, flags);
 | 
				
			||||||
 | 
						g->is_selfpowered = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
 | 
						if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
 | 
				
			||||||
		/* Suspend the controller until OTG enable it */
 | 
							/* Suspend the controller until OTG enable it */
 | 
				
			||||||
| 
						 | 
					@ -2529,7 +2530,7 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
 | 
				
			||||||
	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
						struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
				
			||||||
	struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
 | 
						struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	DECLARE_COMPLETION(done);
 | 
						DECLARE_COMPLETION_ONSTACK(done);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!udc_controller)
 | 
						if (!udc_controller)
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -191,7 +191,6 @@ struct lpc32xx_udc {
 | 
				
			||||||
	bool			enabled;
 | 
						bool			enabled;
 | 
				
			||||||
	bool			clocked;
 | 
						bool			clocked;
 | 
				
			||||||
	bool			suspended;
 | 
						bool			suspended;
 | 
				
			||||||
	bool			selfpowered;
 | 
					 | 
				
			||||||
	int                     ep0state;
 | 
						int                     ep0state;
 | 
				
			||||||
	atomic_t                enabled_ep_cnt;
 | 
						atomic_t                enabled_ep_cnt;
 | 
				
			||||||
	wait_queue_head_t       ep_disable_wait_queue;
 | 
						wait_queue_head_t       ep_disable_wait_queue;
 | 
				
			||||||
| 
						 | 
					@ -547,7 +546,7 @@ static int proc_udc_show(struct seq_file *s, void *unused)
 | 
				
			||||||
		   udc->vbus ? "present" : "off",
 | 
							   udc->vbus ? "present" : "off",
 | 
				
			||||||
		   udc->enabled ? (udc->vbus ? "active" : "enabled") :
 | 
							   udc->enabled ? (udc->vbus ? "active" : "enabled") :
 | 
				
			||||||
		   "disabled",
 | 
							   "disabled",
 | 
				
			||||||
		   udc->selfpowered ? "self" : "VBUS",
 | 
							   udc->gadget.is_selfpowered ? "self" : "VBUS",
 | 
				
			||||||
		   udc->suspended ? ", suspended" : "",
 | 
							   udc->suspended ? ", suspended" : "",
 | 
				
			||||||
		   udc->driver ? udc->driver->driver.name : "(none)");
 | 
							   udc->driver ? udc->driver->driver.name : "(none)");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2212,7 +2211,7 @@ static int udc_get_status(struct lpc32xx_udc *udc, u16 reqtype, u16 wIndex)
 | 
				
			||||||
		break; /* Not supported */
 | 
							break; /* Not supported */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case USB_RECIP_DEVICE:
 | 
						case USB_RECIP_DEVICE:
 | 
				
			||||||
		ep0buff = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
 | 
							ep0buff = udc->gadget.is_selfpowered;
 | 
				
			||||||
		if (udc->dev_status & (1 << USB_DEVICE_REMOTE_WAKEUP))
 | 
							if (udc->dev_status & (1 << USB_DEVICE_REMOTE_WAKEUP))
 | 
				
			||||||
			ep0buff |= (1 << USB_DEVICE_REMOTE_WAKEUP);
 | 
								ep0buff |= (1 << USB_DEVICE_REMOTE_WAKEUP);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
| 
						 | 
					@ -2498,10 +2497,7 @@ static int lpc32xx_wakeup(struct usb_gadget *gadget)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int lpc32xx_set_selfpowered(struct usb_gadget *gadget, int is_on)
 | 
					static int lpc32xx_set_selfpowered(struct usb_gadget *gadget, int is_on)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct lpc32xx_udc *udc = to_udc(gadget);
 | 
						gadget->is_selfpowered = (is_on != 0);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Always self-powered */
 | 
					 | 
				
			||||||
	udc->selfpowered = (is_on != 0);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2946,7 +2942,7 @@ static int lpc32xx_start(struct usb_gadget *gadget,
 | 
				
			||||||
	udc->driver = driver;
 | 
						udc->driver = driver;
 | 
				
			||||||
	udc->gadget.dev.of_node = udc->dev->of_node;
 | 
						udc->gadget.dev.of_node = udc->dev->of_node;
 | 
				
			||||||
	udc->enabled = 1;
 | 
						udc->enabled = 1;
 | 
				
			||||||
	udc->selfpowered = 1;
 | 
						udc->gadget.is_selfpowered = 1;
 | 
				
			||||||
	udc->vbus = 0;
 | 
						udc->vbus = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Force VBUS process once to check for cable insertion */
 | 
						/* Force VBUS process once to check for cable insertion */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1378,9 +1378,6 @@ static int mv_udc_start(struct usb_gadget *gadget,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* pullup is always on */
 | 
					 | 
				
			||||||
	mv_udc_pullup(&udc->gadget, 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* When boot with cable attached, there will be no vbus irq occurred */
 | 
						/* When boot with cable attached, there will be no vbus irq occurred */
 | 
				
			||||||
	if (udc->qwork)
 | 
						if (udc->qwork)
 | 
				
			||||||
		queue_work(udc->qwork, &udc->vbus_work);
 | 
							queue_work(udc->qwork, &udc->vbus_work);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1132,13 +1132,10 @@ net2272_wakeup(struct usb_gadget *_gadget)
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
net2272_set_selfpowered(struct usb_gadget *_gadget, int value)
 | 
					net2272_set_selfpowered(struct usb_gadget *_gadget, int value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct net2272 *dev;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!_gadget)
 | 
						if (!_gadget)
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
	dev = container_of(_gadget, struct net2272, gadget);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev->is_selfpowered = value;
 | 
						_gadget->is_selfpowered = (value != 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1844,7 +1841,7 @@ net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat)
 | 
				
			||||||
			case USB_RECIP_DEVICE:
 | 
								case USB_RECIP_DEVICE:
 | 
				
			||||||
				if (u.r.wLength > 2)
 | 
									if (u.r.wLength > 2)
 | 
				
			||||||
					goto do_stall;
 | 
										goto do_stall;
 | 
				
			||||||
				if (dev->is_selfpowered)
 | 
									if (dev->gadget.is_selfpowered)
 | 
				
			||||||
					status = (1 << USB_DEVICE_SELF_POWERED);
 | 
										status = (1 << USB_DEVICE_SELF_POWERED);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				/* don't bother with a request object! */
 | 
									/* don't bother with a request object! */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -458,7 +458,6 @@ struct net2272 {
 | 
				
			||||||
	struct usb_gadget_driver *driver;
 | 
						struct usb_gadget_driver *driver;
 | 
				
			||||||
	unsigned protocol_stall:1,
 | 
						unsigned protocol_stall:1,
 | 
				
			||||||
	         softconnect:1,
 | 
						         softconnect:1,
 | 
				
			||||||
	         is_selfpowered:1,
 | 
					 | 
				
			||||||
	         wakeup:1,
 | 
						         wakeup:1,
 | 
				
			||||||
	         dma_eot_polarity:1,
 | 
						         dma_eot_polarity:1,
 | 
				
			||||||
	         dma_dack_polarity:1,
 | 
						         dma_dack_polarity:1,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,11 +12,7 @@
 | 
				
			||||||
 * the Mass Storage, Serial, and Ethernet/RNDIS gadget drivers
 | 
					 * the Mass Storage, Serial, and Ethernet/RNDIS gadget drivers
 | 
				
			||||||
 * as well as Gadget Zero and Gadgetfs.
 | 
					 * as well as Gadget Zero and Gadgetfs.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * DMA is enabled by default.  Drivers using transfer queues might use
 | 
					 * DMA is enabled by default.
 | 
				
			||||||
 * DMA chaining to remove IRQ latencies between transfers.  (Except when
 | 
					 | 
				
			||||||
 * short OUT transfers happen.)  Drivers can use the req->no_interrupt
 | 
					 | 
				
			||||||
 * hint to completely eliminate some IRQs, if a later IRQ is guaranteed
 | 
					 | 
				
			||||||
 * and DMA chaining is enabled.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * MSI is enabled by default.  The legacy IRQ is used if MSI couldn't
 | 
					 * MSI is enabled by default.  The legacy IRQ is used if MSI couldn't
 | 
				
			||||||
 * be enabled.
 | 
					 * be enabled.
 | 
				
			||||||
| 
						 | 
					@ -84,23 +80,6 @@ static const char *const ep_name[] = {
 | 
				
			||||||
	"ep-e", "ep-f", "ep-g", "ep-h",
 | 
						"ep-e", "ep-f", "ep-g", "ep-h",
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* use_dma -- general goodness, fewer interrupts, less cpu load (vs PIO)
 | 
					 | 
				
			||||||
 * use_dma_chaining -- dma descriptor queueing gives even more irq reduction
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The net2280 DMA engines are not tightly integrated with their FIFOs;
 | 
					 | 
				
			||||||
 * not all cases are (yet) handled well in this driver or the silicon.
 | 
					 | 
				
			||||||
 * Some gadget drivers work better with the dma support here than others.
 | 
					 | 
				
			||||||
 * These two parameters let you use PIO or more aggressive DMA.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static bool use_dma = true;
 | 
					 | 
				
			||||||
static bool use_dma_chaining;
 | 
					 | 
				
			||||||
static bool use_msi = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* "modprobe net2280 use_dma=n" etc */
 | 
					 | 
				
			||||||
module_param(use_dma, bool, 0444);
 | 
					 | 
				
			||||||
module_param(use_dma_chaining, bool, 0444);
 | 
					 | 
				
			||||||
module_param(use_msi, bool, 0444);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* mode 0 == ep-{a,b,c,d} 1K fifo each
 | 
					/* mode 0 == ep-{a,b,c,d} 1K fifo each
 | 
				
			||||||
 * mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable
 | 
					 * mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable
 | 
				
			||||||
 * mode 2 == ep-a 2K fifo, ep-{b,c} 1K each, ep-d unavailable
 | 
					 * mode 2 == ep-a 2K fifo, ep-{b,c} 1K each, ep-d unavailable
 | 
				
			||||||
| 
						 | 
					@ -120,11 +99,6 @@ static bool enable_suspend;
 | 
				
			||||||
/* "modprobe net2280 enable_suspend=1" etc */
 | 
					/* "modprobe net2280 enable_suspend=1" etc */
 | 
				
			||||||
module_param(enable_suspend, bool, 0444);
 | 
					module_param(enable_suspend, bool, 0444);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* force full-speed operation */
 | 
					 | 
				
			||||||
static bool full_speed;
 | 
					 | 
				
			||||||
module_param(full_speed, bool, 0444);
 | 
					 | 
				
			||||||
MODULE_PARM_DESC(full_speed, "force full-speed mode -- for testing only!");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define	DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
 | 
					#define	DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char *type_string(u8 bmAttributes)
 | 
					static char *type_string(u8 bmAttributes)
 | 
				
			||||||
| 
						 | 
					@ -202,15 +176,6 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 | 
				
			||||||
	/* set speed-dependent max packet; may kick in high bandwidth */
 | 
						/* set speed-dependent max packet; may kick in high bandwidth */
 | 
				
			||||||
	set_max_speed(ep, max);
 | 
						set_max_speed(ep, max);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* FIFO lines can't go to different packets.  PIO is ok, so
 | 
					 | 
				
			||||||
	 * use it instead of troublesome (non-bulk) multi-packet DMA.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (ep->dma && (max % 4) != 0 && use_dma_chaining) {
 | 
					 | 
				
			||||||
		ep_dbg(ep->dev, "%s, no dma for maxpacket %d\n",
 | 
					 | 
				
			||||||
			ep->ep.name, ep->ep.maxpacket);
 | 
					 | 
				
			||||||
		ep->dma = NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* set type, direction, address; reset fifo counters */
 | 
						/* set type, direction, address; reset fifo counters */
 | 
				
			||||||
	writel(BIT(FIFO_FLUSH), &ep->regs->ep_stat);
 | 
						writel(BIT(FIFO_FLUSH), &ep->regs->ep_stat);
 | 
				
			||||||
	tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
 | 
						tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
 | 
				
			||||||
| 
						 | 
					@ -478,7 +443,7 @@ static int net2280_disable(struct usb_ep *_ep)
 | 
				
			||||||
	/* synch memory views with the device */
 | 
						/* synch memory views with the device */
 | 
				
			||||||
	(void)readl(&ep->cfg->ep_cfg);
 | 
						(void)readl(&ep->cfg->ep_cfg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (use_dma && !ep->dma && ep->num >= 1 && ep->num <= 4)
 | 
						if (!ep->dma && ep->num >= 1 && ep->num <= 4)
 | 
				
			||||||
		ep->dma = &ep->dev->dma[ep->num - 1];
 | 
							ep->dma = &ep->dev->dma[ep->num - 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_unlock_irqrestore(&ep->dev->lock, flags);
 | 
						spin_unlock_irqrestore(&ep->dev->lock, flags);
 | 
				
			||||||
| 
						 | 
					@ -610,9 +575,15 @@ static void out_flush(struct net2280_ep *ep)
 | 
				
			||||||
	u32	__iomem *statp;
 | 
						u32	__iomem *statp;
 | 
				
			||||||
	u32	tmp;
 | 
						u32	tmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ASSERT_OUT_NAKING(ep);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	statp = &ep->regs->ep_stat;
 | 
						statp = &ep->regs->ep_stat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tmp = readl(statp);
 | 
				
			||||||
 | 
						if (tmp & BIT(NAK_OUT_PACKETS)) {
 | 
				
			||||||
 | 
							ep_dbg(ep->dev, "%s %s %08x !NAK\n",
 | 
				
			||||||
 | 
								ep->ep.name, __func__, tmp);
 | 
				
			||||||
 | 
							writel(BIT(SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	writel(BIT(DATA_OUT_PING_TOKEN_INTERRUPT) |
 | 
						writel(BIT(DATA_OUT_PING_TOKEN_INTERRUPT) |
 | 
				
			||||||
		BIT(DATA_PACKET_RECEIVED_INTERRUPT),
 | 
							BIT(DATA_PACKET_RECEIVED_INTERRUPT),
 | 
				
			||||||
		statp);
 | 
							statp);
 | 
				
			||||||
| 
						 | 
					@ -747,8 +718,7 @@ static void fill_dma_desc(struct net2280_ep *ep,
 | 
				
			||||||
	req->valid = valid;
 | 
						req->valid = valid;
 | 
				
			||||||
	if (valid)
 | 
						if (valid)
 | 
				
			||||||
		dmacount |= BIT(VALID_BIT);
 | 
							dmacount |= BIT(VALID_BIT);
 | 
				
			||||||
	if (likely(!req->req.no_interrupt || !use_dma_chaining))
 | 
						dmacount |= BIT(DMA_DONE_INTERRUPT_ENABLE);
 | 
				
			||||||
		dmacount |= BIT(DMA_DONE_INTERRUPT_ENABLE);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* td->dmadesc = previously set by caller */
 | 
						/* td->dmadesc = previously set by caller */
 | 
				
			||||||
	td->dmaaddr = cpu_to_le32 (req->req.dma);
 | 
						td->dmaaddr = cpu_to_le32 (req->req.dma);
 | 
				
			||||||
| 
						 | 
					@ -862,27 +832,11 @@ static void start_dma(struct net2280_ep *ep, struct net2280_request *req)
 | 
				
			||||||
	req->td->dmadesc = cpu_to_le32 (ep->td_dma);
 | 
						req->td->dmadesc = cpu_to_le32 (ep->td_dma);
 | 
				
			||||||
	fill_dma_desc(ep, req, 1);
 | 
						fill_dma_desc(ep, req, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!use_dma_chaining)
 | 
						req->td->dmacount |= cpu_to_le32(BIT(END_OF_CHAIN));
 | 
				
			||||||
		req->td->dmacount |= cpu_to_le32(BIT(END_OF_CHAIN));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	start_queue(ep, tmp, req->td_dma);
 | 
						start_queue(ep, tmp, req->td_dma);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void resume_dma(struct net2280_ep *ep)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	writel(readl(&ep->dma->dmactl) | BIT(DMA_ENABLE), &ep->dma->dmactl);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ep->dma_started = true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline void ep_stop_dma(struct net2280_ep *ep)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	writel(readl(&ep->dma->dmactl) & ~BIT(DMA_ENABLE), &ep->dma->dmactl);
 | 
					 | 
				
			||||||
	spin_stop_dma(ep->dma);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ep->dma_started = false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline void
 | 
					static inline void
 | 
				
			||||||
queue_dma(struct net2280_ep *ep, struct net2280_request *req, int valid)
 | 
					queue_dma(struct net2280_ep *ep, struct net2280_request *req, int valid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -973,10 +927,8 @@ net2280_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 | 
				
			||||||
			return ret;
 | 
								return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if 0
 | 
					 | 
				
			||||||
	ep_vdbg(dev, "%s queue req %p, len %d buf %p\n",
 | 
						ep_vdbg(dev, "%s queue req %p, len %d buf %p\n",
 | 
				
			||||||
			_ep->name, _req, _req->length, _req->buf);
 | 
								_ep->name, _req, _req->length, _req->buf);
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock_irqsave(&dev->lock, flags);
 | 
						spin_lock_irqsave(&dev->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -984,24 +936,12 @@ net2280_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 | 
				
			||||||
	_req->actual = 0;
 | 
						_req->actual = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* kickstart this i/o queue? */
 | 
						/* kickstart this i/o queue? */
 | 
				
			||||||
	if (list_empty(&ep->queue) && !ep->stopped) {
 | 
						if  (list_empty(&ep->queue) && !ep->stopped &&
 | 
				
			||||||
		/* DMA request while EP halted */
 | 
							!((dev->quirks & PLX_SUPERSPEED) && ep->dma &&
 | 
				
			||||||
		if (ep->dma &&
 | 
							  (readl(&ep->regs->ep_rsp) & BIT(CLEAR_ENDPOINT_HALT)))) {
 | 
				
			||||||
		    (readl(&ep->regs->ep_rsp) & BIT(CLEAR_ENDPOINT_HALT)) &&
 | 
					
 | 
				
			||||||
			(dev->quirks & PLX_SUPERSPEED)) {
 | 
					 | 
				
			||||||
			int valid = 1;
 | 
					 | 
				
			||||||
			if (ep->is_in) {
 | 
					 | 
				
			||||||
				int expect;
 | 
					 | 
				
			||||||
				expect = likely(req->req.zero ||
 | 
					 | 
				
			||||||
						((req->req.length %
 | 
					 | 
				
			||||||
						  ep->ep.maxpacket) != 0));
 | 
					 | 
				
			||||||
				if (expect != ep->in_fifo_validate)
 | 
					 | 
				
			||||||
					valid = 0;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			queue_dma(ep, req, valid);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		/* use DMA if the endpoint supports it, else pio */
 | 
							/* use DMA if the endpoint supports it, else pio */
 | 
				
			||||||
		else if (ep->dma)
 | 
							if (ep->dma)
 | 
				
			||||||
			start_dma(ep, req);
 | 
								start_dma(ep, req);
 | 
				
			||||||
		else {
 | 
							else {
 | 
				
			||||||
			/* maybe there's no control data, just status ack */
 | 
								/* maybe there's no control data, just status ack */
 | 
				
			||||||
| 
						 | 
					@ -1084,8 +1024,6 @@ dma_done(struct net2280_ep *ep,	struct net2280_request *req, u32 dmacount,
 | 
				
			||||||
	done(ep, req, status);
 | 
						done(ep, req, status);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void restart_dma(struct net2280_ep *ep);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void scan_dma_completions(struct net2280_ep *ep)
 | 
					static void scan_dma_completions(struct net2280_ep *ep)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* only look at descriptors that were "naturally" retired,
 | 
						/* only look at descriptors that were "naturally" retired,
 | 
				
			||||||
| 
						 | 
					@ -1117,9 +1055,8 @@ static void scan_dma_completions(struct net2280_ep *ep)
 | 
				
			||||||
			dma_done(ep, req, tmp, 0);
 | 
								dma_done(ep, req, tmp, 0);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		} else if (!ep->is_in &&
 | 
							} else if (!ep->is_in &&
 | 
				
			||||||
				(req->req.length % ep->ep.maxpacket) != 0) {
 | 
								   (req->req.length % ep->ep.maxpacket) &&
 | 
				
			||||||
			if (ep->dev->quirks & PLX_SUPERSPEED)
 | 
								   !(ep->dev->quirks & PLX_SUPERSPEED)) {
 | 
				
			||||||
				return dma_done(ep, req, tmp, 0);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			tmp = readl(&ep->regs->ep_stat);
 | 
								tmp = readl(&ep->regs->ep_stat);
 | 
				
			||||||
			/* AVOID TROUBLE HERE by not issuing short reads from
 | 
								/* AVOID TROUBLE HERE by not issuing short reads from
 | 
				
			||||||
| 
						 | 
					@ -1150,67 +1087,15 @@ static void scan_dma_completions(struct net2280_ep *ep)
 | 
				
			||||||
static void restart_dma(struct net2280_ep *ep)
 | 
					static void restart_dma(struct net2280_ep *ep)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct net2280_request	*req;
 | 
						struct net2280_request	*req;
 | 
				
			||||||
	u32			dmactl = dmactl_default;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ep->stopped)
 | 
						if (ep->stopped)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	req = list_entry(ep->queue.next, struct net2280_request, queue);
 | 
						req = list_entry(ep->queue.next, struct net2280_request, queue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!use_dma_chaining) {
 | 
						start_dma(ep, req);
 | 
				
			||||||
		start_dma(ep, req);
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* the 2280 will be processing the queue unless queue hiccups after
 | 
					 | 
				
			||||||
	 * the previous transfer:
 | 
					 | 
				
			||||||
	 *  IN:   wanted automagic zlp, head doesn't (or vice versa)
 | 
					 | 
				
			||||||
	 *        DMA_FIFO_VALIDATE doesn't init from dma descriptors.
 | 
					 | 
				
			||||||
	 *  OUT:  was "usb-short", we must restart.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (ep->is_in && !req->valid) {
 | 
					 | 
				
			||||||
		struct net2280_request	*entry, *prev = NULL;
 | 
					 | 
				
			||||||
		int			reqmode, done = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ep_dbg(ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td);
 | 
					 | 
				
			||||||
		ep->in_fifo_validate = likely(req->req.zero ||
 | 
					 | 
				
			||||||
				(req->req.length % ep->ep.maxpacket) != 0);
 | 
					 | 
				
			||||||
		if (ep->in_fifo_validate)
 | 
					 | 
				
			||||||
			dmactl |= BIT(DMA_FIFO_VALIDATE);
 | 
					 | 
				
			||||||
		list_for_each_entry(entry, &ep->queue, queue) {
 | 
					 | 
				
			||||||
			__le32		dmacount;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (entry == req)
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			dmacount = entry->td->dmacount;
 | 
					 | 
				
			||||||
			if (!done) {
 | 
					 | 
				
			||||||
				reqmode = likely(entry->req.zero ||
 | 
					 | 
				
			||||||
				   (entry->req.length % ep->ep.maxpacket));
 | 
					 | 
				
			||||||
				if (reqmode == ep->in_fifo_validate) {
 | 
					 | 
				
			||||||
					entry->valid = 1;
 | 
					 | 
				
			||||||
					dmacount |= valid_bit;
 | 
					 | 
				
			||||||
					entry->td->dmacount = dmacount;
 | 
					 | 
				
			||||||
					prev = entry;
 | 
					 | 
				
			||||||
					continue;
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					/* force a hiccup */
 | 
					 | 
				
			||||||
					prev->td->dmacount |= dma_done_ie;
 | 
					 | 
				
			||||||
					done = 1;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			/* walk the rest of the queue so unlinks behave */
 | 
					 | 
				
			||||||
			entry->valid = 0;
 | 
					 | 
				
			||||||
			dmacount &= ~valid_bit;
 | 
					 | 
				
			||||||
			entry->td->dmacount = dmacount;
 | 
					 | 
				
			||||||
			prev = entry;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	writel(0, &ep->dma->dmactl);
 | 
					 | 
				
			||||||
	start_queue(ep, dmactl, req->td_dma);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void abort_dma_228x(struct net2280_ep *ep)
 | 
					static void abort_dma(struct net2280_ep *ep)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* abort the current transfer */
 | 
						/* abort the current transfer */
 | 
				
			||||||
	if (likely(!list_empty(&ep->queue))) {
 | 
						if (likely(!list_empty(&ep->queue))) {
 | 
				
			||||||
| 
						 | 
					@ -1222,19 +1107,6 @@ static void abort_dma_228x(struct net2280_ep *ep)
 | 
				
			||||||
	scan_dma_completions(ep);
 | 
						scan_dma_completions(ep);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void abort_dma_338x(struct net2280_ep *ep)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	writel(BIT(DMA_ABORT), &ep->dma->dmastat);
 | 
					 | 
				
			||||||
	spin_stop_dma(ep->dma);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void abort_dma(struct net2280_ep *ep)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (ep->dev->quirks & PLX_LEGACY)
 | 
					 | 
				
			||||||
		return abort_dma_228x(ep);
 | 
					 | 
				
			||||||
	return abort_dma_338x(ep);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* dequeue ALL requests */
 | 
					/* dequeue ALL requests */
 | 
				
			||||||
static void nuke(struct net2280_ep *ep)
 | 
					static void nuke(struct net2280_ep *ep)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -1306,25 +1178,6 @@ static int net2280_dequeue(struct usb_ep *_ep, struct usb_request *_req)
 | 
				
			||||||
			done(ep, req, -ECONNRESET);
 | 
								done(ep, req, -ECONNRESET);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		req = NULL;
 | 
							req = NULL;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* patch up hardware chaining data */
 | 
					 | 
				
			||||||
	} else if (ep->dma && use_dma_chaining) {
 | 
					 | 
				
			||||||
		if (req->queue.prev == ep->queue.next) {
 | 
					 | 
				
			||||||
			writel(le32_to_cpu(req->td->dmadesc),
 | 
					 | 
				
			||||||
				&ep->dma->dmadesc);
 | 
					 | 
				
			||||||
			if (req->td->dmacount & dma_done_ie)
 | 
					 | 
				
			||||||
				writel(readl(&ep->dma->dmacount) |
 | 
					 | 
				
			||||||
						le32_to_cpu(dma_done_ie),
 | 
					 | 
				
			||||||
					&ep->dma->dmacount);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			struct net2280_request	*prev;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			prev = list_entry(req->queue.prev,
 | 
					 | 
				
			||||||
				struct net2280_request, queue);
 | 
					 | 
				
			||||||
			prev->td->dmadesc = req->td->dmadesc;
 | 
					 | 
				
			||||||
			if (req->td->dmacount & dma_done_ie)
 | 
					 | 
				
			||||||
				prev->td->dmacount |= dma_done_ie;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (req)
 | 
						if (req)
 | 
				
			||||||
| 
						 | 
					@ -1512,10 +1365,10 @@ static int net2280_set_selfpowered(struct usb_gadget *_gadget, int value)
 | 
				
			||||||
	tmp = readl(&dev->usb->usbctl);
 | 
						tmp = readl(&dev->usb->usbctl);
 | 
				
			||||||
	if (value) {
 | 
						if (value) {
 | 
				
			||||||
		tmp |= BIT(SELF_POWERED_STATUS);
 | 
							tmp |= BIT(SELF_POWERED_STATUS);
 | 
				
			||||||
		dev->selfpowered = 1;
 | 
							_gadget->is_selfpowered = 1;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		tmp &= ~BIT(SELF_POWERED_STATUS);
 | 
							tmp &= ~BIT(SELF_POWERED_STATUS);
 | 
				
			||||||
		dev->selfpowered = 0;
 | 
							_gadget->is_selfpowered = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	writel(tmp, &dev->usb->usbctl);
 | 
						writel(tmp, &dev->usb->usbctl);
 | 
				
			||||||
	spin_unlock_irqrestore(&dev->lock, flags);
 | 
						spin_unlock_irqrestore(&dev->lock, flags);
 | 
				
			||||||
| 
						 | 
					@ -1604,14 +1457,11 @@ static ssize_t registers_show(struct device *_dev,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Main Control Registers */
 | 
						/* Main Control Registers */
 | 
				
			||||||
	t = scnprintf(next, size, "%s version " DRIVER_VERSION
 | 
						t = scnprintf(next, size, "%s version " DRIVER_VERSION
 | 
				
			||||||
			", chiprev %04x, dma %s\n\n"
 | 
								", chiprev %04x\n\n"
 | 
				
			||||||
			"devinit %03x fifoctl %08x gadget '%s'\n"
 | 
								"devinit %03x fifoctl %08x gadget '%s'\n"
 | 
				
			||||||
			"pci irqenb0 %02x irqenb1 %08x "
 | 
								"pci irqenb0 %02x irqenb1 %08x "
 | 
				
			||||||
			"irqstat0 %04x irqstat1 %08x\n",
 | 
								"irqstat0 %04x irqstat1 %08x\n",
 | 
				
			||||||
			driver_name, dev->chiprev,
 | 
								driver_name, dev->chiprev,
 | 
				
			||||||
			use_dma
 | 
					 | 
				
			||||||
				? (use_dma_chaining ? "chaining" : "enabled")
 | 
					 | 
				
			||||||
				: "disabled",
 | 
					 | 
				
			||||||
			readl(&dev->regs->devinit),
 | 
								readl(&dev->regs->devinit),
 | 
				
			||||||
			readl(&dev->regs->fifoctl),
 | 
								readl(&dev->regs->fifoctl),
 | 
				
			||||||
			s,
 | 
								s,
 | 
				
			||||||
| 
						 | 
					@ -1913,76 +1763,73 @@ static void defect7374_disable_data_eps(struct net2280 *dev)
 | 
				
			||||||
static void defect7374_enable_data_eps_zero(struct net2280 *dev)
 | 
					static void defect7374_enable_data_eps_zero(struct net2280 *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32 tmp = 0, tmp_reg;
 | 
						u32 tmp = 0, tmp_reg;
 | 
				
			||||||
	u32 fsmvalue, scratch;
 | 
						u32 scratch;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	unsigned char ep_sel;
 | 
						unsigned char ep_sel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	scratch = get_idx_reg(dev->regs, SCRATCH);
 | 
						scratch = get_idx_reg(dev->regs, SCRATCH);
 | 
				
			||||||
	fsmvalue = scratch & (0xf << DEFECT7374_FSM_FIELD);
 | 
					
 | 
				
			||||||
 | 
						WARN_ON((scratch & (0xf << DEFECT7374_FSM_FIELD))
 | 
				
			||||||
 | 
							== DEFECT7374_FSM_SS_CONTROL_READ);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	scratch &= ~(0xf << DEFECT7374_FSM_FIELD);
 | 
						scratch &= ~(0xf << DEFECT7374_FSM_FIELD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*See if firmware needs to set up for workaround*/
 | 
						ep_warn(dev, "Operate Defect 7374 workaround soft this time");
 | 
				
			||||||
	if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) {
 | 
						ep_warn(dev, "It will operate on cold-reboot and SS connect");
 | 
				
			||||||
		ep_warn(dev, "Operate Defect 7374 workaround soft this time");
 | 
					 | 
				
			||||||
		ep_warn(dev, "It will operate on cold-reboot and SS connect");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*GPEPs:*/
 | 
						/*GPEPs:*/
 | 
				
			||||||
		tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_DIRECTION) |
 | 
						tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_DIRECTION) |
 | 
				
			||||||
		       (2 << OUT_ENDPOINT_TYPE) | (2 << IN_ENDPOINT_TYPE) |
 | 
								(2 << OUT_ENDPOINT_TYPE) | (2 << IN_ENDPOINT_TYPE) |
 | 
				
			||||||
		       ((dev->enhanced_mode) ?
 | 
								((dev->enhanced_mode) ?
 | 
				
			||||||
		       BIT(OUT_ENDPOINT_ENABLE) : BIT(ENDPOINT_ENABLE)) |
 | 
								 BIT(OUT_ENDPOINT_ENABLE) : BIT(ENDPOINT_ENABLE)) |
 | 
				
			||||||
		       BIT(IN_ENDPOINT_ENABLE));
 | 
								BIT(IN_ENDPOINT_ENABLE));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (i = 1; i < 5; i++)
 | 
						for (i = 1; i < 5; i++)
 | 
				
			||||||
			writel(tmp, &dev->ep[i].cfg->ep_cfg);
 | 
							writel(tmp, &dev->ep[i].cfg->ep_cfg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* CSRIN, PCIIN, STATIN, RCIN*/
 | 
						/* CSRIN, PCIIN, STATIN, RCIN*/
 | 
				
			||||||
		tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_ENABLE));
 | 
						tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_ENABLE));
 | 
				
			||||||
		writel(tmp, &dev->dep[1].dep_cfg);
 | 
						writel(tmp, &dev->dep[1].dep_cfg);
 | 
				
			||||||
		writel(tmp, &dev->dep[3].dep_cfg);
 | 
						writel(tmp, &dev->dep[3].dep_cfg);
 | 
				
			||||||
		writel(tmp, &dev->dep[4].dep_cfg);
 | 
						writel(tmp, &dev->dep[4].dep_cfg);
 | 
				
			||||||
		writel(tmp, &dev->dep[5].dep_cfg);
 | 
						writel(tmp, &dev->dep[5].dep_cfg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*Implemented for development and debug.
 | 
						/*Implemented for development and debug.
 | 
				
			||||||
		 * Can be refined/tuned later.*/
 | 
						 * Can be refined/tuned later.*/
 | 
				
			||||||
		for (ep_sel = 0; ep_sel <= 21; ep_sel++) {
 | 
						for (ep_sel = 0; ep_sel <= 21; ep_sel++) {
 | 
				
			||||||
			/* Select an endpoint for subsequent operations: */
 | 
							/* Select an endpoint for subsequent operations: */
 | 
				
			||||||
			tmp_reg = readl(&dev->plregs->pl_ep_ctrl);
 | 
							tmp_reg = readl(&dev->plregs->pl_ep_ctrl);
 | 
				
			||||||
			writel(((tmp_reg & ~0x1f) | ep_sel),
 | 
							writel(((tmp_reg & ~0x1f) | ep_sel),
 | 
				
			||||||
			       &dev->plregs->pl_ep_ctrl);
 | 
									&dev->plregs->pl_ep_ctrl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (ep_sel == 1) {
 | 
							if (ep_sel == 1) {
 | 
				
			||||||
				tmp =
 | 
								tmp =
 | 
				
			||||||
				    (readl(&dev->plregs->pl_ep_ctrl) |
 | 
									(readl(&dev->plregs->pl_ep_ctrl) |
 | 
				
			||||||
				     BIT(CLEAR_ACK_ERROR_CODE) | 0);
 | 
									 BIT(CLEAR_ACK_ERROR_CODE) | 0);
 | 
				
			||||||
				writel(tmp, &dev->plregs->pl_ep_ctrl);
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (ep_sel == 0 || (ep_sel > 9 && ep_sel < 14) ||
 | 
					 | 
				
			||||||
					ep_sel == 18  || ep_sel == 20)
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			tmp = (readl(&dev->plregs->pl_ep_cfg_4) |
 | 
					 | 
				
			||||||
				 BIT(NON_CTRL_IN_TOLERATE_BAD_DIR) | 0);
 | 
					 | 
				
			||||||
			writel(tmp, &dev->plregs->pl_ep_cfg_4);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			tmp = readl(&dev->plregs->pl_ep_ctrl) &
 | 
					 | 
				
			||||||
				~BIT(EP_INITIALIZED);
 | 
					 | 
				
			||||||
			writel(tmp, &dev->plregs->pl_ep_ctrl);
 | 
								writel(tmp, &dev->plregs->pl_ep_ctrl);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Set FSM to focus on the first Control Read:
 | 
							if (ep_sel == 0 || (ep_sel > 9 && ep_sel < 14) ||
 | 
				
			||||||
		 * - Tip: Connection speed is known upon the first
 | 
									ep_sel == 18  || ep_sel == 20)
 | 
				
			||||||
		 * setup request.*/
 | 
								continue;
 | 
				
			||||||
		scratch |= DEFECT7374_FSM_WAITING_FOR_CONTROL_READ;
 | 
					
 | 
				
			||||||
		set_idx_reg(dev->regs, SCRATCH, scratch);
 | 
							tmp = (readl(&dev->plregs->pl_ep_cfg_4) |
 | 
				
			||||||
 | 
									BIT(NON_CTRL_IN_TOLERATE_BAD_DIR) | 0);
 | 
				
			||||||
 | 
							writel(tmp, &dev->plregs->pl_ep_cfg_4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							tmp = readl(&dev->plregs->pl_ep_ctrl) &
 | 
				
			||||||
 | 
								~BIT(EP_INITIALIZED);
 | 
				
			||||||
 | 
							writel(tmp, &dev->plregs->pl_ep_ctrl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	} else{
 | 
					 | 
				
			||||||
		ep_warn(dev, "Defect 7374 workaround soft will NOT operate");
 | 
					 | 
				
			||||||
		ep_warn(dev, "It will operate on cold-reboot and SS connect");
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Set FSM to focus on the first Control Read:
 | 
				
			||||||
 | 
						 * - Tip: Connection speed is known upon the first
 | 
				
			||||||
 | 
						 * setup request.*/
 | 
				
			||||||
 | 
						scratch |= DEFECT7374_FSM_WAITING_FOR_CONTROL_READ;
 | 
				
			||||||
 | 
						set_idx_reg(dev->regs, SCRATCH, scratch);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* keeping it simple:
 | 
					/* keeping it simple:
 | 
				
			||||||
| 
						 | 
					@ -2033,21 +1880,13 @@ static void usb_reset_228x(struct net2280 *dev)
 | 
				
			||||||
static void usb_reset_338x(struct net2280 *dev)
 | 
					static void usb_reset_338x(struct net2280 *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32 tmp;
 | 
						u32 tmp;
 | 
				
			||||||
	u32 fsmvalue;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev->gadget.speed = USB_SPEED_UNKNOWN;
 | 
						dev->gadget.speed = USB_SPEED_UNKNOWN;
 | 
				
			||||||
	(void)readl(&dev->usb->usbctl);
 | 
						(void)readl(&dev->usb->usbctl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	net2280_led_init(dev);
 | 
						net2280_led_init(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
 | 
						if (dev->bug7734_patched) {
 | 
				
			||||||
			(0xf << DEFECT7374_FSM_FIELD);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* See if firmware needs to set up for workaround: */
 | 
					 | 
				
			||||||
	if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) {
 | 
					 | 
				
			||||||
		ep_info(dev, "%s: Defect 7374 FsmValue 0x%08x\n", __func__,
 | 
					 | 
				
			||||||
		     fsmvalue);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		/* disable automatic responses, and irqs */
 | 
							/* disable automatic responses, and irqs */
 | 
				
			||||||
		writel(0, &dev->usb->stdrsp);
 | 
							writel(0, &dev->usb->stdrsp);
 | 
				
			||||||
		writel(0, &dev->regs->pciirqenb0);
 | 
							writel(0, &dev->regs->pciirqenb0);
 | 
				
			||||||
| 
						 | 
					@ -2064,7 +1903,7 @@ static void usb_reset_338x(struct net2280 *dev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	writel(~0, &dev->regs->irqstat0), writel(~0, &dev->regs->irqstat1);
 | 
						writel(~0, &dev->regs->irqstat0), writel(~0, &dev->regs->irqstat1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ) {
 | 
						if (dev->bug7734_patched) {
 | 
				
			||||||
		/* reset, and enable pci */
 | 
							/* reset, and enable pci */
 | 
				
			||||||
		tmp = readl(&dev->regs->devinit) |
 | 
							tmp = readl(&dev->regs->devinit) |
 | 
				
			||||||
		    BIT(PCI_ENABLE) |
 | 
							    BIT(PCI_ENABLE) |
 | 
				
			||||||
| 
						 | 
					@ -2093,10 +1932,6 @@ static void usb_reset(struct net2280 *dev)
 | 
				
			||||||
static void usb_reinit_228x(struct net2280 *dev)
 | 
					static void usb_reinit_228x(struct net2280 *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32	tmp;
 | 
						u32	tmp;
 | 
				
			||||||
	int	init_dma;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* use_dma changes are ignored till next device re-init */
 | 
					 | 
				
			||||||
	init_dma = use_dma;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* basic endpoint init */
 | 
						/* basic endpoint init */
 | 
				
			||||||
	for (tmp = 0; tmp < 7; tmp++) {
 | 
						for (tmp = 0; tmp < 7; tmp++) {
 | 
				
			||||||
| 
						 | 
					@ -2108,8 +1943,7 @@ static void usb_reinit_228x(struct net2280 *dev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (tmp > 0 && tmp <= 4) {
 | 
							if (tmp > 0 && tmp <= 4) {
 | 
				
			||||||
			ep->fifo_size = 1024;
 | 
								ep->fifo_size = 1024;
 | 
				
			||||||
			if (init_dma)
 | 
								ep->dma = &dev->dma[tmp - 1];
 | 
				
			||||||
				ep->dma = &dev->dma[tmp - 1];
 | 
					 | 
				
			||||||
		} else
 | 
							} else
 | 
				
			||||||
			ep->fifo_size = 64;
 | 
								ep->fifo_size = 64;
 | 
				
			||||||
		ep->regs = &dev->epregs[tmp];
 | 
							ep->regs = &dev->epregs[tmp];
 | 
				
			||||||
| 
						 | 
					@ -2133,17 +1967,12 @@ static void usb_reinit_228x(struct net2280 *dev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void usb_reinit_338x(struct net2280 *dev)
 | 
					static void usb_reinit_338x(struct net2280 *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int init_dma;
 | 
					 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	u32 tmp, val;
 | 
						u32 tmp, val;
 | 
				
			||||||
	u32 fsmvalue;
 | 
					 | 
				
			||||||
	static const u32 ne[9] = { 0, 1, 2, 3, 4, 1, 2, 3, 4 };
 | 
						static const u32 ne[9] = { 0, 1, 2, 3, 4, 1, 2, 3, 4 };
 | 
				
			||||||
	static const u32 ep_reg_addr[9] = { 0x00, 0xC0, 0x00, 0xC0, 0x00,
 | 
						static const u32 ep_reg_addr[9] = { 0x00, 0xC0, 0x00, 0xC0, 0x00,
 | 
				
			||||||
						0x00, 0xC0, 0x00, 0xC0 };
 | 
											0x00, 0xC0, 0x00, 0xC0 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* use_dma changes are ignored till next device re-init */
 | 
					 | 
				
			||||||
	init_dma = use_dma;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* basic endpoint init */
 | 
						/* basic endpoint init */
 | 
				
			||||||
	for (i = 0; i < dev->n_ep; i++) {
 | 
						for (i = 0; i < dev->n_ep; i++) {
 | 
				
			||||||
		struct net2280_ep *ep = &dev->ep[i];
 | 
							struct net2280_ep *ep = &dev->ep[i];
 | 
				
			||||||
| 
						 | 
					@ -2152,7 +1981,7 @@ static void usb_reinit_338x(struct net2280 *dev)
 | 
				
			||||||
		ep->dev = dev;
 | 
							ep->dev = dev;
 | 
				
			||||||
		ep->num = i;
 | 
							ep->num = i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (i > 0 && i <= 4 && init_dma)
 | 
							if (i > 0 && i <= 4)
 | 
				
			||||||
			ep->dma = &dev->dma[i - 1];
 | 
								ep->dma = &dev->dma[i - 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (dev->enhanced_mode) {
 | 
							if (dev->enhanced_mode) {
 | 
				
			||||||
| 
						 | 
					@ -2177,14 +2006,7 @@ static void usb_reinit_338x(struct net2280 *dev)
 | 
				
			||||||
	dev->ep[0].stopped = 0;
 | 
						dev->ep[0].stopped = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Link layer set up */
 | 
						/* Link layer set up */
 | 
				
			||||||
	fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
 | 
						if (dev->bug7734_patched) {
 | 
				
			||||||
				(0xf << DEFECT7374_FSM_FIELD);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* See if driver needs to set up for workaround: */
 | 
					 | 
				
			||||||
	if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ)
 | 
					 | 
				
			||||||
		ep_info(dev, "%s: Defect 7374 FsmValue %08x\n",
 | 
					 | 
				
			||||||
						__func__, fsmvalue);
 | 
					 | 
				
			||||||
	else {
 | 
					 | 
				
			||||||
		tmp = readl(&dev->usb_ext->usbctl2) &
 | 
							tmp = readl(&dev->usb_ext->usbctl2) &
 | 
				
			||||||
		    ~(BIT(U1_ENABLE) | BIT(U2_ENABLE) | BIT(LTM_ENABLE));
 | 
							    ~(BIT(U1_ENABLE) | BIT(U2_ENABLE) | BIT(LTM_ENABLE));
 | 
				
			||||||
		writel(tmp, &dev->usb_ext->usbctl2);
 | 
							writel(tmp, &dev->usb_ext->usbctl2);
 | 
				
			||||||
| 
						 | 
					@ -2291,15 +2113,8 @@ static void ep0_start_228x(struct net2280 *dev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void ep0_start_338x(struct net2280 *dev)
 | 
					static void ep0_start_338x(struct net2280 *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32 fsmvalue;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
 | 
						if (dev->bug7734_patched)
 | 
				
			||||||
			(0xf << DEFECT7374_FSM_FIELD);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ)
 | 
					 | 
				
			||||||
		ep_info(dev, "%s: Defect 7374 FsmValue %08x\n", __func__,
 | 
					 | 
				
			||||||
		     fsmvalue);
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		writel(BIT(CLEAR_NAK_OUT_PACKETS_MODE) |
 | 
							writel(BIT(CLEAR_NAK_OUT_PACKETS_MODE) |
 | 
				
			||||||
		       BIT(SET_EP_HIDE_STATUS_PHASE),
 | 
							       BIT(SET_EP_HIDE_STATUS_PHASE),
 | 
				
			||||||
		       &dev->epregs[0].ep_rsp);
 | 
							       &dev->epregs[0].ep_rsp);
 | 
				
			||||||
| 
						 | 
					@ -2382,16 +2197,12 @@ static int net2280_start(struct usb_gadget *_gadget,
 | 
				
			||||||
	if (retval)
 | 
						if (retval)
 | 
				
			||||||
		goto err_func;
 | 
							goto err_func;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Enable force-full-speed testing mode, if desired */
 | 
						/* enable host detection and ep0; and we're ready
 | 
				
			||||||
	if (full_speed && (dev->quirks & PLX_LEGACY))
 | 
					 | 
				
			||||||
		writel(BIT(FORCE_FULL_SPEED_MODE), &dev->usb->xcvrdiag);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* ... then enable host detection and ep0; and we're ready
 | 
					 | 
				
			||||||
	 * for set_configuration as well as eventual disconnect.
 | 
						 * for set_configuration as well as eventual disconnect.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	net2280_led_active(dev, 1);
 | 
						net2280_led_active(dev, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dev->quirks & PLX_SUPERSPEED)
 | 
						if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched)
 | 
				
			||||||
		defect7374_enable_data_eps_zero(dev);
 | 
							defect7374_enable_data_eps_zero(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ep0_start(dev);
 | 
						ep0_start(dev);
 | 
				
			||||||
| 
						 | 
					@ -2444,10 +2255,6 @@ static int net2280_stop(struct usb_gadget *_gadget)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	net2280_led_active(dev, 0);
 | 
						net2280_led_active(dev, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Disable full-speed test mode */
 | 
					 | 
				
			||||||
	if (dev->quirks & PLX_LEGACY)
 | 
					 | 
				
			||||||
		writel(0, &dev->usb->xcvrdiag);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	device_remove_file(&dev->pdev->dev, &dev_attr_function);
 | 
						device_remove_file(&dev->pdev->dev, &dev_attr_function);
 | 
				
			||||||
	device_remove_file(&dev->pdev->dev, &dev_attr_queues);
 | 
						device_remove_file(&dev->pdev->dev, &dev_attr_queues);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2478,10 +2285,10 @@ static void handle_ep_small(struct net2280_ep *ep)
 | 
				
			||||||
	/* ack all, and handle what we care about */
 | 
						/* ack all, and handle what we care about */
 | 
				
			||||||
	t = readl(&ep->regs->ep_stat);
 | 
						t = readl(&ep->regs->ep_stat);
 | 
				
			||||||
	ep->irqs++;
 | 
						ep->irqs++;
 | 
				
			||||||
#if 0
 | 
					
 | 
				
			||||||
	ep_vdbg(ep->dev, "%s ack ep_stat %08x, req %p\n",
 | 
						ep_vdbg(ep->dev, "%s ack ep_stat %08x, req %p\n",
 | 
				
			||||||
			ep->ep.name, t, req ? &req->req : 0);
 | 
								ep->ep.name, t, req ? &req->req : NULL);
 | 
				
			||||||
#endif
 | 
					
 | 
				
			||||||
	if (!ep->is_in || (ep->dev->quirks & PLX_2280))
 | 
						if (!ep->is_in || (ep->dev->quirks & PLX_2280))
 | 
				
			||||||
		writel(t & ~BIT(NAK_OUT_PACKETS), &ep->regs->ep_stat);
 | 
							writel(t & ~BIT(NAK_OUT_PACKETS), &ep->regs->ep_stat);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
| 
						 | 
					@ -2717,6 +2524,7 @@ static void defect7374_workaround(struct net2280 *dev, struct usb_ctrlrequest r)
 | 
				
			||||||
		 * run after the next USB connection.
 | 
							 * run after the next USB connection.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		scratch |= DEFECT7374_FSM_NON_SS_CONTROL_READ;
 | 
							scratch |= DEFECT7374_FSM_NON_SS_CONTROL_READ;
 | 
				
			||||||
 | 
							dev->bug7734_patched = 1;
 | 
				
			||||||
		goto restore_data_eps;
 | 
							goto restore_data_eps;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2730,6 +2538,7 @@ static void defect7374_workaround(struct net2280 *dev, struct usb_ctrlrequest r)
 | 
				
			||||||
		if ((state >= (ACK_GOOD_NORMAL << STATE)) &&
 | 
							if ((state >= (ACK_GOOD_NORMAL << STATE)) &&
 | 
				
			||||||
			(state <= (ACK_GOOD_MORE_ACKS_TO_COME << STATE))) {
 | 
								(state <= (ACK_GOOD_MORE_ACKS_TO_COME << STATE))) {
 | 
				
			||||||
			scratch |= DEFECT7374_FSM_SS_CONTROL_READ;
 | 
								scratch |= DEFECT7374_FSM_SS_CONTROL_READ;
 | 
				
			||||||
 | 
								dev->bug7734_patched = 1;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2766,80 +2575,19 @@ restore_data_eps:
 | 
				
			||||||
	return;
 | 
						return;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void ep_stall(struct net2280_ep *ep, int stall)
 | 
					static void ep_clear_seqnum(struct net2280_ep *ep)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct net2280 *dev = ep->dev;
 | 
						struct net2280 *dev = ep->dev;
 | 
				
			||||||
	u32 val;
 | 
						u32 val;
 | 
				
			||||||
	static const u32 ep_pl[9] = { 0, 3, 4, 7, 8, 2, 5, 6, 9 };
 | 
						static const u32 ep_pl[9] = { 0, 3, 4, 7, 8, 2, 5, 6, 9 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (stall) {
 | 
						val = readl(&dev->plregs->pl_ep_ctrl) & ~0x1f;
 | 
				
			||||||
		writel(BIT(SET_ENDPOINT_HALT) |
 | 
						val |= ep_pl[ep->num];
 | 
				
			||||||
		       /* BIT(SET_NAK_PACKETS) | */
 | 
						writel(val, &dev->plregs->pl_ep_ctrl);
 | 
				
			||||||
		       BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE),
 | 
						val |= BIT(SEQUENCE_NUMBER_RESET);
 | 
				
			||||||
		       &ep->regs->ep_rsp);
 | 
						writel(val, &dev->plregs->pl_ep_ctrl);
 | 
				
			||||||
		ep->is_halt = 1;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		if (dev->gadget.speed == USB_SPEED_SUPER) {
 | 
					 | 
				
			||||||
			/*
 | 
					 | 
				
			||||||
			 * Workaround for SS SeqNum not cleared via
 | 
					 | 
				
			||||||
			 * Endpoint Halt (Clear) bit. select endpoint
 | 
					 | 
				
			||||||
			 */
 | 
					 | 
				
			||||||
			val = readl(&dev->plregs->pl_ep_ctrl);
 | 
					 | 
				
			||||||
			val = (val & ~0x1f) | ep_pl[ep->num];
 | 
					 | 
				
			||||||
			writel(val, &dev->plregs->pl_ep_ctrl);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			val |= BIT(SEQUENCE_NUMBER_RESET);
 | 
						return;
 | 
				
			||||||
			writel(val, &dev->plregs->pl_ep_ctrl);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		val = readl(&ep->regs->ep_rsp);
 | 
					 | 
				
			||||||
		val |= BIT(CLEAR_ENDPOINT_HALT) |
 | 
					 | 
				
			||||||
			BIT(CLEAR_ENDPOINT_TOGGLE);
 | 
					 | 
				
			||||||
		writel(val,
 | 
					 | 
				
			||||||
		       /* | BIT(CLEAR_NAK_PACKETS),*/
 | 
					 | 
				
			||||||
		       &ep->regs->ep_rsp);
 | 
					 | 
				
			||||||
		ep->is_halt = 0;
 | 
					 | 
				
			||||||
		val = readl(&ep->regs->ep_rsp);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void ep_stdrsp(struct net2280_ep *ep, int value, int wedged)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	/* set/clear, then synch memory views with the device */
 | 
					 | 
				
			||||||
	if (value) {
 | 
					 | 
				
			||||||
		ep->stopped = 1;
 | 
					 | 
				
			||||||
		if (ep->num == 0)
 | 
					 | 
				
			||||||
			ep->dev->protocol_stall = 1;
 | 
					 | 
				
			||||||
		else {
 | 
					 | 
				
			||||||
			if (ep->dma)
 | 
					 | 
				
			||||||
				ep_stop_dma(ep);
 | 
					 | 
				
			||||||
			ep_stall(ep, true);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (wedged)
 | 
					 | 
				
			||||||
			ep->wedged = 1;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		ep->stopped = 0;
 | 
					 | 
				
			||||||
		ep->wedged = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ep_stall(ep, false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Flush the queue */
 | 
					 | 
				
			||||||
		if (!list_empty(&ep->queue)) {
 | 
					 | 
				
			||||||
			struct net2280_request *req =
 | 
					 | 
				
			||||||
			    list_entry(ep->queue.next, struct net2280_request,
 | 
					 | 
				
			||||||
				       queue);
 | 
					 | 
				
			||||||
			if (ep->dma)
 | 
					 | 
				
			||||||
				resume_dma(ep);
 | 
					 | 
				
			||||||
			else {
 | 
					 | 
				
			||||||
				if (ep->is_in)
 | 
					 | 
				
			||||||
					write_fifo(ep, &req->req);
 | 
					 | 
				
			||||||
				else {
 | 
					 | 
				
			||||||
					if (read_fifo(ep, req))
 | 
					 | 
				
			||||||
						done(ep, req, 0);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_stat0_irqs_superspeed(struct net2280 *dev,
 | 
					static void handle_stat0_irqs_superspeed(struct net2280 *dev,
 | 
				
			||||||
| 
						 | 
					@ -2863,7 +2611,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev,
 | 
				
			||||||
		switch (r.bRequestType) {
 | 
							switch (r.bRequestType) {
 | 
				
			||||||
		case (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE):
 | 
							case (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE):
 | 
				
			||||||
			status = dev->wakeup_enable ? 0x02 : 0x00;
 | 
								status = dev->wakeup_enable ? 0x02 : 0x00;
 | 
				
			||||||
			if (dev->selfpowered)
 | 
								if (dev->gadget.is_selfpowered)
 | 
				
			||||||
				status |= BIT(0);
 | 
									status |= BIT(0);
 | 
				
			||||||
			status |= (dev->u1_enable << 2 | dev->u2_enable << 3 |
 | 
								status |= (dev->u1_enable << 2 | dev->u2_enable << 3 |
 | 
				
			||||||
							dev->ltm_enable << 4);
 | 
												dev->ltm_enable << 4);
 | 
				
			||||||
| 
						 | 
					@ -2940,7 +2688,12 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev,
 | 
				
			||||||
			if (w_value != USB_ENDPOINT_HALT)
 | 
								if (w_value != USB_ENDPOINT_HALT)
 | 
				
			||||||
				goto do_stall3;
 | 
									goto do_stall3;
 | 
				
			||||||
			ep_vdbg(dev, "%s clear halt\n", e->ep.name);
 | 
								ep_vdbg(dev, "%s clear halt\n", e->ep.name);
 | 
				
			||||||
			ep_stall(e, false);
 | 
								/*
 | 
				
			||||||
 | 
								 * Workaround for SS SeqNum not cleared via
 | 
				
			||||||
 | 
								 * Endpoint Halt (Clear) bit. select endpoint
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								ep_clear_seqnum(e);
 | 
				
			||||||
 | 
								clear_halt(e);
 | 
				
			||||||
			if (!list_empty(&e->queue) && e->td_dma)
 | 
								if (!list_empty(&e->queue) && e->td_dma)
 | 
				
			||||||
				restart_dma(e);
 | 
									restart_dma(e);
 | 
				
			||||||
			allow_status(ep);
 | 
								allow_status(ep);
 | 
				
			||||||
| 
						 | 
					@ -2998,7 +2751,14 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev,
 | 
				
			||||||
			e = get_ep_by_addr(dev,	w_index);
 | 
								e = get_ep_by_addr(dev,	w_index);
 | 
				
			||||||
			if (!e || (w_value != USB_ENDPOINT_HALT))
 | 
								if (!e || (w_value != USB_ENDPOINT_HALT))
 | 
				
			||||||
				goto do_stall3;
 | 
									goto do_stall3;
 | 
				
			||||||
			ep_stdrsp(e, true, false);
 | 
								ep->stopped = 1;
 | 
				
			||||||
 | 
								if (ep->num == 0)
 | 
				
			||||||
 | 
									ep->dev->protocol_stall = 1;
 | 
				
			||||||
 | 
								else {
 | 
				
			||||||
 | 
									if (ep->dma)
 | 
				
			||||||
 | 
										abort_dma(ep);
 | 
				
			||||||
 | 
									set_halt(ep);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			allow_status_338x(ep);
 | 
								allow_status_338x(ep);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3026,7 +2786,7 @@ do_stall3:
 | 
				
			||||||
				r.bRequestType, r.bRequest, tmp);
 | 
									r.bRequestType, r.bRequest, tmp);
 | 
				
			||||||
		dev->protocol_stall = 1;
 | 
							dev->protocol_stall = 1;
 | 
				
			||||||
		/* TD 9.9 Halt Endpoint test. TD 9.22 Set feature test */
 | 
							/* TD 9.9 Halt Endpoint test. TD 9.22 Set feature test */
 | 
				
			||||||
		ep_stall(ep, true);
 | 
							set_halt(ep);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
next_endpoints3:
 | 
					next_endpoints3:
 | 
				
			||||||
| 
						 | 
					@ -3091,9 +2851,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ep->stopped = 0;
 | 
							ep->stopped = 0;
 | 
				
			||||||
		dev->protocol_stall = 0;
 | 
							dev->protocol_stall = 0;
 | 
				
			||||||
		if (dev->quirks & PLX_SUPERSPEED)
 | 
							if (!(dev->quirks & PLX_SUPERSPEED)) {
 | 
				
			||||||
			ep->is_halt = 0;
 | 
					 | 
				
			||||||
		else{
 | 
					 | 
				
			||||||
			if (ep->dev->quirks & PLX_2280)
 | 
								if (ep->dev->quirks & PLX_2280)
 | 
				
			||||||
				tmp = BIT(FIFO_OVERFLOW) |
 | 
									tmp = BIT(FIFO_OVERFLOW) |
 | 
				
			||||||
				    BIT(FIFO_UNDERFLOW);
 | 
									    BIT(FIFO_UNDERFLOW);
 | 
				
			||||||
| 
						 | 
					@ -3120,7 +2878,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
 | 
				
			||||||
		cpu_to_le32s(&u.raw[0]);
 | 
							cpu_to_le32s(&u.raw[0]);
 | 
				
			||||||
		cpu_to_le32s(&u.raw[1]);
 | 
							cpu_to_le32s(&u.raw[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (dev->quirks & PLX_SUPERSPEED)
 | 
							if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched)
 | 
				
			||||||
			defect7374_workaround(dev, u.r);
 | 
								defect7374_workaround(dev, u.r);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		tmp = 0;
 | 
							tmp = 0;
 | 
				
			||||||
| 
						 | 
					@ -3423,17 +3181,12 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat)
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* chaining should stop on abort, short OUT from fifo,
 | 
							if (!(tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT))) {
 | 
				
			||||||
		 * or (stat0 codepath) short OUT transfer.
 | 
								ep_dbg(ep->dev, "%s no xact done? %08x\n",
 | 
				
			||||||
		 */
 | 
									ep->ep.name, tmp);
 | 
				
			||||||
		if (!use_dma_chaining) {
 | 
								continue;
 | 
				
			||||||
			if (!(tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT))) {
 | 
					 | 
				
			||||||
				ep_dbg(ep->dev, "%s no xact done? %08x\n",
 | 
					 | 
				
			||||||
					ep->ep.name, tmp);
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			stop_dma(ep->dma);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							stop_dma(ep->dma);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* OUT transfers terminate when the data from the
 | 
							/* OUT transfers terminate when the data from the
 | 
				
			||||||
		 * host is in our memory.  Process whatever's done.
 | 
							 * host is in our memory.  Process whatever's done.
 | 
				
			||||||
| 
						 | 
					@ -3448,30 +3201,9 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat)
 | 
				
			||||||
		scan_dma_completions(ep);
 | 
							scan_dma_completions(ep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* disable dma on inactive queues; else maybe restart */
 | 
							/* disable dma on inactive queues; else maybe restart */
 | 
				
			||||||
		if (list_empty(&ep->queue)) {
 | 
							if (!list_empty(&ep->queue)) {
 | 
				
			||||||
			if (use_dma_chaining)
 | 
					 | 
				
			||||||
				stop_dma(ep->dma);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			tmp = readl(&dma->dmactl);
 | 
								tmp = readl(&dma->dmactl);
 | 
				
			||||||
			if (!use_dma_chaining || (tmp & BIT(DMA_ENABLE)) == 0)
 | 
								restart_dma(ep);
 | 
				
			||||||
				restart_dma(ep);
 | 
					 | 
				
			||||||
			else if (ep->is_in && use_dma_chaining) {
 | 
					 | 
				
			||||||
				struct net2280_request	*req;
 | 
					 | 
				
			||||||
				__le32			dmacount;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				/* the descriptor at the head of the chain
 | 
					 | 
				
			||||||
				 * may still have VALID_BIT clear; that's
 | 
					 | 
				
			||||||
				 * used to trigger changing DMA_FIFO_VALIDATE
 | 
					 | 
				
			||||||
				 * (affects automagic zlp writes).
 | 
					 | 
				
			||||||
				 */
 | 
					 | 
				
			||||||
				req = list_entry(ep->queue.next,
 | 
					 | 
				
			||||||
						struct net2280_request, queue);
 | 
					 | 
				
			||||||
				dmacount = req->td->dmacount;
 | 
					 | 
				
			||||||
				dmacount &= cpu_to_le32(BIT(VALID_BIT) |
 | 
					 | 
				
			||||||
						DMA_BYTE_COUNT_MASK);
 | 
					 | 
				
			||||||
				if (dmacount && (dmacount & valid_bit) == 0)
 | 
					 | 
				
			||||||
					restart_dma(ep);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ep->irqs++;
 | 
							ep->irqs++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -3556,7 +3288,7 @@ static void net2280_remove(struct pci_dev *pdev)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (dev->got_irq)
 | 
						if (dev->got_irq)
 | 
				
			||||||
		free_irq(pdev->irq, dev);
 | 
							free_irq(pdev->irq, dev);
 | 
				
			||||||
	if (use_msi && dev->quirks & PLX_SUPERSPEED)
 | 
						if (dev->quirks & PLX_SUPERSPEED)
 | 
				
			||||||
		pci_disable_msi(pdev);
 | 
							pci_disable_msi(pdev);
 | 
				
			||||||
	if (dev->regs)
 | 
						if (dev->regs)
 | 
				
			||||||
		iounmap(dev->regs);
 | 
							iounmap(dev->regs);
 | 
				
			||||||
| 
						 | 
					@ -3581,9 +3313,6 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 | 
				
			||||||
	void			__iomem *base = NULL;
 | 
						void			__iomem *base = NULL;
 | 
				
			||||||
	int			retval, i;
 | 
						int			retval, i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!use_dma)
 | 
					 | 
				
			||||||
		use_dma_chaining = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* alloc, and start init */
 | 
						/* alloc, and start init */
 | 
				
			||||||
	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 | 
						dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 | 
				
			||||||
	if (dev == NULL) {
 | 
						if (dev == NULL) {
 | 
				
			||||||
| 
						 | 
					@ -3663,9 +3392,12 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 | 
				
			||||||
		fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
 | 
							fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
 | 
				
			||||||
					(0xf << DEFECT7374_FSM_FIELD);
 | 
										(0xf << DEFECT7374_FSM_FIELD);
 | 
				
			||||||
		/* See if firmware needs to set up for workaround: */
 | 
							/* See if firmware needs to set up for workaround: */
 | 
				
			||||||
		if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ)
 | 
							if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ) {
 | 
				
			||||||
 | 
								dev->bug7734_patched = 1;
 | 
				
			||||||
			writel(0, &dev->usb->usbctl);
 | 
								writel(0, &dev->usb->usbctl);
 | 
				
			||||||
	} else{
 | 
							} else
 | 
				
			||||||
 | 
								dev->bug7734_patched = 0;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
		dev->enhanced_mode = 0;
 | 
							dev->enhanced_mode = 0;
 | 
				
			||||||
		dev->n_ep = 7;
 | 
							dev->n_ep = 7;
 | 
				
			||||||
		/* put into initial config, link up all endpoints */
 | 
							/* put into initial config, link up all endpoints */
 | 
				
			||||||
| 
						 | 
					@ -3682,7 +3414,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 | 
				
			||||||
		goto done;
 | 
							goto done;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (use_msi && (dev->quirks & PLX_SUPERSPEED))
 | 
						if (dev->quirks & PLX_SUPERSPEED)
 | 
				
			||||||
		if (pci_enable_msi(pdev))
 | 
							if (pci_enable_msi(pdev))
 | 
				
			||||||
			ep_err(dev, "Failed to enable MSI mode\n");
 | 
								ep_err(dev, "Failed to enable MSI mode\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3741,9 +3473,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 | 
				
			||||||
	ep_info(dev, "%s\n", driver_desc);
 | 
						ep_info(dev, "%s\n", driver_desc);
 | 
				
			||||||
	ep_info(dev, "irq %d, pci mem %p, chip rev %04x\n",
 | 
						ep_info(dev, "irq %d, pci mem %p, chip rev %04x\n",
 | 
				
			||||||
			pdev->irq, base, dev->chiprev);
 | 
								pdev->irq, base, dev->chiprev);
 | 
				
			||||||
	ep_info(dev, "version: " DRIVER_VERSION "; dma %s %s\n",
 | 
						ep_info(dev, "version: " DRIVER_VERSION "; %s\n",
 | 
				
			||||||
		use_dma	? (use_dma_chaining ? "chaining" : "enabled")
 | 
					 | 
				
			||||||
			: "disabled",
 | 
					 | 
				
			||||||
		dev->enhanced_mode ? "enhanced mode" : "legacy mode");
 | 
							dev->enhanced_mode ? "enhanced mode" : "legacy mode");
 | 
				
			||||||
	retval = device_create_file(&pdev->dev, &dev_attr_registers);
 | 
						retval = device_create_file(&pdev->dev, &dev_attr_registers);
 | 
				
			||||||
	if (retval)
 | 
						if (retval)
 | 
				
			||||||
| 
						 | 
					@ -3776,9 +3506,6 @@ static void net2280_shutdown(struct pci_dev *pdev)
 | 
				
			||||||
	/* disable the pullup so the host will think we're gone */
 | 
						/* disable the pullup so the host will think we're gone */
 | 
				
			||||||
	writel(0, &dev->usb->usbctl);
 | 
						writel(0, &dev->usb->usbctl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Disable full-speed test mode */
 | 
					 | 
				
			||||||
	if (dev->quirks & PLX_LEGACY)
 | 
					 | 
				
			||||||
		writel(0, &dev->usb->xcvrdiag);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -100,7 +100,6 @@ struct net2280_ep {
 | 
				
			||||||
	dma_addr_t				td_dma;	/* of dummy */
 | 
						dma_addr_t				td_dma;	/* of dummy */
 | 
				
			||||||
	struct net2280				*dev;
 | 
						struct net2280				*dev;
 | 
				
			||||||
	unsigned long				irqs;
 | 
						unsigned long				irqs;
 | 
				
			||||||
	unsigned is_halt:1, dma_started:1;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* analogous to a host-side qh */
 | 
						/* analogous to a host-side qh */
 | 
				
			||||||
	struct list_head			queue;
 | 
						struct list_head			queue;
 | 
				
			||||||
| 
						 | 
					@ -126,7 +125,7 @@ static inline void allow_status(struct net2280_ep *ep)
 | 
				
			||||||
	ep->stopped = 1;
 | 
						ep->stopped = 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void allow_status_338x(struct net2280_ep *ep)
 | 
					static inline void allow_status_338x(struct net2280_ep *ep)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Control Status Phase Handshake was set by the chip when the setup
 | 
						 * Control Status Phase Handshake was set by the chip when the setup
 | 
				
			||||||
| 
						 | 
					@ -165,8 +164,8 @@ struct net2280 {
 | 
				
			||||||
					u2_enable:1,
 | 
										u2_enable:1,
 | 
				
			||||||
					ltm_enable:1,
 | 
										ltm_enable:1,
 | 
				
			||||||
					wakeup_enable:1,
 | 
										wakeup_enable:1,
 | 
				
			||||||
					selfpowered:1,
 | 
										addressed_state:1,
 | 
				
			||||||
					addressed_state:1;
 | 
										bug7734_patched:1;
 | 
				
			||||||
	u16				chiprev;
 | 
						u16				chiprev;
 | 
				
			||||||
	int enhanced_mode;
 | 
						int enhanced_mode;
 | 
				
			||||||
	int n_ep;
 | 
						int n_ep;
 | 
				
			||||||
| 
						 | 
					@ -356,23 +355,6 @@ static inline void start_out_naking(struct net2280_ep *ep)
 | 
				
			||||||
	readl(&ep->regs->ep_rsp);
 | 
						readl(&ep->regs->ep_rsp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef DEBUG
 | 
					 | 
				
			||||||
static inline void assert_out_naking(struct net2280_ep *ep, const char *where)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	u32	tmp = readl(&ep->regs->ep_stat);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((tmp & BIT(NAK_OUT_PACKETS)) == 0) {
 | 
					 | 
				
			||||||
		ep_dbg(ep->dev, "%s %s %08x !NAK\n",
 | 
					 | 
				
			||||||
				ep->ep.name, where, tmp);
 | 
					 | 
				
			||||||
		writel(BIT(SET_NAK_OUT_PACKETS),
 | 
					 | 
				
			||||||
			&ep->regs->ep_rsp);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep, __func__)
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
#define ASSERT_OUT_NAKING(ep) do {} while (0)
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline void stop_out_naking(struct net2280_ep *ep)
 | 
					static inline void stop_out_naking(struct net2280_ep *ep)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32	tmp;
 | 
						u32	tmp;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1171,6 +1171,7 @@ omap_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
 | 
				
			||||||
	unsigned long	flags;
 | 
						unsigned long	flags;
 | 
				
			||||||
	u16		syscon1;
 | 
						u16		syscon1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gadget->is_selfpowered = (is_selfpowered != 0);
 | 
				
			||||||
	udc = container_of(gadget, struct omap_udc, gadget);
 | 
						udc = container_of(gadget, struct omap_udc, gadget);
 | 
				
			||||||
	spin_lock_irqsave(&udc->lock, flags);
 | 
						spin_lock_irqsave(&udc->lock, flags);
 | 
				
			||||||
	syscon1 = omap_readw(UDC_SYSCON1);
 | 
						syscon1 = omap_readw(UDC_SYSCON1);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1161,6 +1161,7 @@ static int pch_udc_pcd_selfpowered(struct usb_gadget *gadget, int value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!gadget)
 | 
						if (!gadget)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						gadget->is_selfpowered = (value != 0);
 | 
				
			||||||
	dev = container_of(gadget, struct pch_udc_dev, gadget);
 | 
						dev = container_of(gadget, struct pch_udc_dev, gadget);
 | 
				
			||||||
	if (value)
 | 
						if (value)
 | 
				
			||||||
		pch_udc_set_selfpowered(dev);
 | 
							pch_udc_set_selfpowered(dev);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1272,7 +1272,6 @@ static int pxa25x_udc_start(struct usb_gadget *g,
 | 
				
			||||||
			goto bind_fail;
 | 
								goto bind_fail;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pullup(dev);
 | 
					 | 
				
			||||||
	dump_state(dev);
 | 
						dump_state(dev);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
bind_fail:
 | 
					bind_fail:
 | 
				
			||||||
| 
						 | 
					@ -1339,7 +1338,6 @@ static int pxa25x_udc_stop(struct usb_gadget*g)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local_irq_disable();
 | 
						local_irq_disable();
 | 
				
			||||||
	dev->pullup = 0;
 | 
						dev->pullup = 0;
 | 
				
			||||||
	pullup(dev);
 | 
					 | 
				
			||||||
	stop_activity(dev, NULL);
 | 
						stop_activity(dev, NULL);
 | 
				
			||||||
	local_irq_enable();
 | 
						local_irq_enable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1809,7 +1809,6 @@ static int pxa27x_udc_start(struct usb_gadget *g,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* first hook up the driver ... */
 | 
						/* first hook up the driver ... */
 | 
				
			||||||
	udc->driver = driver;
 | 
						udc->driver = driver;
 | 
				
			||||||
	dplus_pullup(udc, 1);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!IS_ERR_OR_NULL(udc->transceiver)) {
 | 
						if (!IS_ERR_OR_NULL(udc->transceiver)) {
 | 
				
			||||||
		retval = otg_set_peripheral(udc->transceiver->otg,
 | 
							retval = otg_set_peripheral(udc->transceiver->otg,
 | 
				
			||||||
| 
						 | 
					@ -1862,7 +1861,6 @@ static int pxa27x_udc_stop(struct usb_gadget *g)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stop_activity(udc, NULL);
 | 
						stop_activity(udc, NULL);
 | 
				
			||||||
	udc_disable(udc);
 | 
						udc_disable(udc);
 | 
				
			||||||
	dplus_pullup(udc, 0);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	udc->driver = NULL;
 | 
						udc->driver = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1803,6 +1803,7 @@ static int r8a66597_set_selfpowered(struct usb_gadget *gadget, int is_self)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget);
 | 
						struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gadget->is_selfpowered = (is_self != 0);
 | 
				
			||||||
	if (is_self)
 | 
						if (is_self)
 | 
				
			||||||
		r8a66597->device_status |= 1 << USB_DEVICE_SELF_POWERED;
 | 
							r8a66597->device_status |= 1 << USB_DEVICE_SELF_POWERED;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -238,14 +238,6 @@ static inline void s3c2410_udc_set_ep0_de_out(void __iomem *base)
 | 
				
			||||||
			S3C2410_UDC_EP0_CSR_REG);
 | 
								S3C2410_UDC_EP0_CSR_REG);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void s3c2410_udc_set_ep0_sse_out(void __iomem *base)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
 | 
					 | 
				
			||||||
	udc_writeb(base, (S3C2410_UDC_EP0_CSR_SOPKTRDY
 | 
					 | 
				
			||||||
				| S3C2410_UDC_EP0_CSR_SSE),
 | 
					 | 
				
			||||||
			S3C2410_UDC_EP0_CSR_REG);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline void s3c2410_udc_set_ep0_de_in(void __iomem *base)
 | 
					static inline void s3c2410_udc_set_ep0_de_in(void __iomem *base)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
 | 
						udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
 | 
				
			||||||
| 
						 | 
					@ -291,18 +283,6 @@ static void s3c2410_udc_nuke(struct s3c2410_udc *udc,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void s3c2410_udc_clear_ep_state(struct s3c2410_udc *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint
 | 
					 | 
				
			||||||
	 * fifos, and pending transactions mustn't be continued in any case.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 1; i < S3C2410_ENDPOINTS; i++)
 | 
					 | 
				
			||||||
		s3c2410_udc_nuke(dev, &dev->ep[i], -ECONNABORTED);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline int s3c2410_udc_fifo_count_out(void)
 | 
					static inline int s3c2410_udc_fifo_count_out(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int tmp;
 | 
						int tmp;
 | 
				
			||||||
| 
						 | 
					@ -1454,6 +1434,7 @@ static int s3c2410_udc_set_selfpowered(struct usb_gadget *gadget, int value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dprintk(DEBUG_NORMAL, "%s()\n", __func__);
 | 
						dprintk(DEBUG_NORMAL, "%s()\n", __func__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gadget->is_selfpowered = (value != 0);
 | 
				
			||||||
	if (value)
 | 
						if (value)
 | 
				
			||||||
		udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
 | 
							udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -564,6 +564,7 @@ static USB_UDC_ATTR(is_a_peripheral);
 | 
				
			||||||
static USB_UDC_ATTR(b_hnp_enable);
 | 
					static USB_UDC_ATTR(b_hnp_enable);
 | 
				
			||||||
static USB_UDC_ATTR(a_hnp_support);
 | 
					static USB_UDC_ATTR(a_hnp_support);
 | 
				
			||||||
static USB_UDC_ATTR(a_alt_hnp_support);
 | 
					static USB_UDC_ATTR(a_alt_hnp_support);
 | 
				
			||||||
 | 
					static USB_UDC_ATTR(is_selfpowered);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct attribute *usb_udc_attrs[] = {
 | 
					static struct attribute *usb_udc_attrs[] = {
 | 
				
			||||||
	&dev_attr_srp.attr,
 | 
						&dev_attr_srp.attr,
 | 
				
			||||||
| 
						 | 
					@ -577,6 +578,7 @@ static struct attribute *usb_udc_attrs[] = {
 | 
				
			||||||
	&dev_attr_b_hnp_enable.attr,
 | 
						&dev_attr_b_hnp_enable.attr,
 | 
				
			||||||
	&dev_attr_a_hnp_support.attr,
 | 
						&dev_attr_a_hnp_support.attr,
 | 
				
			||||||
	&dev_attr_a_alt_hnp_support.attr,
 | 
						&dev_attr_a_alt_hnp_support.attr,
 | 
				
			||||||
 | 
						&dev_attr_is_selfpowered.attr,
 | 
				
			||||||
	NULL,
 | 
						NULL,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -219,7 +219,7 @@ config USB_EHCI_TEGRA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config USB_EHCI_HCD_PPC_OF
 | 
					config USB_EHCI_HCD_PPC_OF
 | 
				
			||||||
	bool "EHCI support for PPC USB controller on OF platform bus"
 | 
						bool "EHCI support for PPC USB controller on OF platform bus"
 | 
				
			||||||
	depends on PPC_OF
 | 
						depends on PPC
 | 
				
			||||||
	default y
 | 
						default y
 | 
				
			||||||
	---help---
 | 
						---help---
 | 
				
			||||||
	  Enables support for the USB controller present on the PowerPC
 | 
						  Enables support for the USB controller present on the PowerPC
 | 
				
			||||||
| 
						 | 
					@ -331,20 +331,6 @@ config USB_ISP116X_HCD
 | 
				
			||||||
	  To compile this driver as a module, choose M here: the
 | 
						  To compile this driver as a module, choose M here: the
 | 
				
			||||||
	  module will be called isp116x-hcd.
 | 
						  module will be called isp116x-hcd.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config USB_ISP1760_HCD
 | 
					 | 
				
			||||||
	tristate "ISP 1760 HCD support"
 | 
					 | 
				
			||||||
	---help---
 | 
					 | 
				
			||||||
	  The ISP1760 chip is a USB 2.0 host controller.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	  This driver does not support isochronous transfers or OTG.
 | 
					 | 
				
			||||||
	  This USB controller is usually attached to a non-DMA-Master
 | 
					 | 
				
			||||||
	  capable bus. NXP's eval kit brings this chip on PCI card
 | 
					 | 
				
			||||||
	  where the chip itself is behind a PLB to simulate such
 | 
					 | 
				
			||||||
	  a bus.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	  To compile this driver as a module, choose M here: the
 | 
					 | 
				
			||||||
	  module will be called isp1760.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
config USB_ISP1362_HCD
 | 
					config USB_ISP1362_HCD
 | 
				
			||||||
	tristate "ISP1362 HCD support"
 | 
						tristate "ISP1362 HCD support"
 | 
				
			||||||
	---help---
 | 
						---help---
 | 
				
			||||||
| 
						 | 
					@ -494,7 +480,7 @@ config USB_OHCI_ATH79
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config USB_OHCI_HCD_PPC_OF_BE
 | 
					config USB_OHCI_HCD_PPC_OF_BE
 | 
				
			||||||
	bool "OHCI support for OF platform bus (big endian)"
 | 
						bool "OHCI support for OF platform bus (big endian)"
 | 
				
			||||||
	depends on PPC_OF
 | 
						depends on PPC
 | 
				
			||||||
	select USB_OHCI_BIG_ENDIAN_DESC
 | 
						select USB_OHCI_BIG_ENDIAN_DESC
 | 
				
			||||||
	select USB_OHCI_BIG_ENDIAN_MMIO
 | 
						select USB_OHCI_BIG_ENDIAN_MMIO
 | 
				
			||||||
	---help---
 | 
						---help---
 | 
				
			||||||
| 
						 | 
					@ -503,7 +489,7 @@ config USB_OHCI_HCD_PPC_OF_BE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config USB_OHCI_HCD_PPC_OF_LE
 | 
					config USB_OHCI_HCD_PPC_OF_LE
 | 
				
			||||||
	bool "OHCI support for OF platform bus (little endian)"
 | 
						bool "OHCI support for OF platform bus (little endian)"
 | 
				
			||||||
	depends on PPC_OF
 | 
						depends on PPC
 | 
				
			||||||
	select USB_OHCI_LITTLE_ENDIAN
 | 
						select USB_OHCI_LITTLE_ENDIAN
 | 
				
			||||||
	---help---
 | 
						---help---
 | 
				
			||||||
	  Enables support for little-endian USB controllers present on the
 | 
						  Enables support for little-endian USB controllers present on the
 | 
				
			||||||
| 
						 | 
					@ -511,7 +497,7 @@ config USB_OHCI_HCD_PPC_OF_LE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config USB_OHCI_HCD_PPC_OF
 | 
					config USB_OHCI_HCD_PPC_OF
 | 
				
			||||||
	bool
 | 
						bool
 | 
				
			||||||
	depends on PPC_OF
 | 
						depends on PPC
 | 
				
			||||||
	default USB_OHCI_HCD_PPC_OF_BE || USB_OHCI_HCD_PPC_OF_LE
 | 
						default USB_OHCI_HCD_PPC_OF_BE || USB_OHCI_HCD_PPC_OF_LE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config USB_OHCI_HCD_PCI
 | 
					config USB_OHCI_HCD_PCI
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,8 +5,6 @@
 | 
				
			||||||
# tell define_trace.h where to find the xhci trace header
 | 
					# tell define_trace.h where to find the xhci trace header
 | 
				
			||||||
CFLAGS_xhci-trace.o := -I$(src)
 | 
					CFLAGS_xhci-trace.o := -I$(src)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
isp1760-y := isp1760-hcd.o isp1760-if.o
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fhci-y := fhci-hcd.o fhci-hub.o fhci-q.o
 | 
					fhci-y := fhci-hcd.o fhci-hub.o fhci-q.o
 | 
				
			||||||
fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o
 | 
					fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,7 +67,6 @@ obj-$(CONFIG_USB_SL811_HCD)	+= sl811-hcd.o
 | 
				
			||||||
obj-$(CONFIG_USB_SL811_CS)	+= sl811_cs.o
 | 
					obj-$(CONFIG_USB_SL811_CS)	+= sl811_cs.o
 | 
				
			||||||
obj-$(CONFIG_USB_U132_HCD)	+= u132-hcd.o
 | 
					obj-$(CONFIG_USB_U132_HCD)	+= u132-hcd.o
 | 
				
			||||||
obj-$(CONFIG_USB_R8A66597_HCD)	+= r8a66597-hcd.o
 | 
					obj-$(CONFIG_USB_R8A66597_HCD)	+= r8a66597-hcd.o
 | 
				
			||||||
obj-$(CONFIG_USB_ISP1760_HCD)	+= isp1760.o
 | 
					 | 
				
			||||||
obj-$(CONFIG_USB_HWA_HCD)	+= hwa-hc.o
 | 
					obj-$(CONFIG_USB_HWA_HCD)	+= hwa-hc.o
 | 
				
			||||||
obj-$(CONFIG_USB_IMX21_HCD)	+= imx21-hcd.o
 | 
					obj-$(CONFIG_USB_IMX21_HCD)	+= imx21-hcd.o
 | 
				
			||||||
obj-$(CONFIG_USB_FSL_MPH_DR_OF)	+= fsl-mph-dr-of.o
 | 
					obj-$(CONFIG_USB_FSL_MPH_DR_OF)	+= fsl-mph-dr-of.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,44 +27,66 @@
 | 
				
			||||||
#define DRIVER_DESC "EHCI Atmel driver"
 | 
					#define DRIVER_DESC "EHCI Atmel driver"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char hcd_name[] = "ehci-atmel";
 | 
					static const char hcd_name[] = "ehci-atmel";
 | 
				
			||||||
static struct hc_driver __read_mostly ehci_atmel_hc_driver;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* interface and function clocks */
 | 
					/* interface and function clocks */
 | 
				
			||||||
static struct clk *iclk, *fclk, *uclk;
 | 
					#define hcd_to_atmel_ehci_priv(h) \
 | 
				
			||||||
static int clocked;
 | 
						((struct atmel_ehci_priv *)hcd_to_ehci(h)->priv)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct atmel_ehci_priv {
 | 
				
			||||||
 | 
						struct clk *iclk;
 | 
				
			||||||
 | 
						struct clk *fclk;
 | 
				
			||||||
 | 
						struct clk *uclk;
 | 
				
			||||||
 | 
						bool clocked;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct hc_driver __read_mostly ehci_atmel_hc_driver;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct ehci_driver_overrides ehci_atmel_drv_overrides __initconst = {
 | 
				
			||||||
 | 
						.extra_priv_size = sizeof(struct atmel_ehci_priv),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*-------------------------------------------------------------------------*/
 | 
					/*-------------------------------------------------------------------------*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void atmel_start_clock(void)
 | 
					static void atmel_start_clock(struct atmel_ehci_priv *atmel_ehci)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						if (atmel_ehci->clocked)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
	if (IS_ENABLED(CONFIG_COMMON_CLK)) {
 | 
						if (IS_ENABLED(CONFIG_COMMON_CLK)) {
 | 
				
			||||||
		clk_set_rate(uclk, 48000000);
 | 
							clk_set_rate(atmel_ehci->uclk, 48000000);
 | 
				
			||||||
		clk_prepare_enable(uclk);
 | 
							clk_prepare_enable(atmel_ehci->uclk);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	clk_prepare_enable(iclk);
 | 
						clk_prepare_enable(atmel_ehci->iclk);
 | 
				
			||||||
	clk_prepare_enable(fclk);
 | 
						clk_prepare_enable(atmel_ehci->fclk);
 | 
				
			||||||
	clocked = 1;
 | 
						atmel_ehci->clocked = true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void atmel_stop_clock(void)
 | 
					static void atmel_stop_clock(struct atmel_ehci_priv *atmel_ehci)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	clk_disable_unprepare(fclk);
 | 
						if (!atmel_ehci->clocked)
 | 
				
			||||||
	clk_disable_unprepare(iclk);
 | 
							return;
 | 
				
			||||||
 | 
						clk_disable_unprepare(atmel_ehci->fclk);
 | 
				
			||||||
 | 
						clk_disable_unprepare(atmel_ehci->iclk);
 | 
				
			||||||
	if (IS_ENABLED(CONFIG_COMMON_CLK))
 | 
						if (IS_ENABLED(CONFIG_COMMON_CLK))
 | 
				
			||||||
		clk_disable_unprepare(uclk);
 | 
							clk_disable_unprepare(atmel_ehci->uclk);
 | 
				
			||||||
	clocked = 0;
 | 
						atmel_ehci->clocked = false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void atmel_start_ehci(struct platform_device *pdev)
 | 
					static void atmel_start_ehci(struct platform_device *pdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct usb_hcd *hcd = platform_get_drvdata(pdev);
 | 
				
			||||||
 | 
						struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_dbg(&pdev->dev, "start\n");
 | 
						dev_dbg(&pdev->dev, "start\n");
 | 
				
			||||||
	atmel_start_clock();
 | 
						atmel_start_clock(atmel_ehci);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void atmel_stop_ehci(struct platform_device *pdev)
 | 
					static void atmel_stop_ehci(struct platform_device *pdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct usb_hcd *hcd = platform_get_drvdata(pdev);
 | 
				
			||||||
 | 
						struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_dbg(&pdev->dev, "stop\n");
 | 
						dev_dbg(&pdev->dev, "stop\n");
 | 
				
			||||||
	atmel_stop_clock();
 | 
						atmel_stop_clock(atmel_ehci);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*-------------------------------------------------------------------------*/
 | 
					/*-------------------------------------------------------------------------*/
 | 
				
			||||||
| 
						 | 
					@ -75,6 +97,7 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
 | 
				
			||||||
	const struct hc_driver *driver = &ehci_atmel_hc_driver;
 | 
						const struct hc_driver *driver = &ehci_atmel_hc_driver;
 | 
				
			||||||
	struct resource *res;
 | 
						struct resource *res;
 | 
				
			||||||
	struct ehci_hcd *ehci;
 | 
						struct ehci_hcd *ehci;
 | 
				
			||||||
 | 
						struct atmel_ehci_priv *atmel_ehci;
 | 
				
			||||||
	int irq;
 | 
						int irq;
 | 
				
			||||||
	int retval;
 | 
						int retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -105,6 +128,7 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
 | 
				
			||||||
		retval = -ENOMEM;
 | 
							retval = -ENOMEM;
 | 
				
			||||||
		goto fail_create_hcd;
 | 
							goto fail_create_hcd;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
						res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
				
			||||||
	hcd->regs = devm_ioremap_resource(&pdev->dev, res);
 | 
						hcd->regs = devm_ioremap_resource(&pdev->dev, res);
 | 
				
			||||||
| 
						 | 
					@ -116,23 +140,23 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
 | 
				
			||||||
	hcd->rsrc_start = res->start;
 | 
						hcd->rsrc_start = res->start;
 | 
				
			||||||
	hcd->rsrc_len = resource_size(res);
 | 
						hcd->rsrc_len = resource_size(res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iclk = devm_clk_get(&pdev->dev, "ehci_clk");
 | 
						atmel_ehci->iclk = devm_clk_get(&pdev->dev, "ehci_clk");
 | 
				
			||||||
	if (IS_ERR(iclk)) {
 | 
						if (IS_ERR(atmel_ehci->iclk)) {
 | 
				
			||||||
		dev_err(&pdev->dev, "Error getting interface clock\n");
 | 
							dev_err(&pdev->dev, "Error getting interface clock\n");
 | 
				
			||||||
		retval = -ENOENT;
 | 
							retval = -ENOENT;
 | 
				
			||||||
		goto fail_request_resource;
 | 
							goto fail_request_resource;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	fclk = devm_clk_get(&pdev->dev, "uhpck");
 | 
						atmel_ehci->fclk = devm_clk_get(&pdev->dev, "uhpck");
 | 
				
			||||||
	if (IS_ERR(fclk)) {
 | 
						if (IS_ERR(atmel_ehci->fclk)) {
 | 
				
			||||||
		dev_err(&pdev->dev, "Error getting function clock\n");
 | 
							dev_err(&pdev->dev, "Error getting function clock\n");
 | 
				
			||||||
		retval = -ENOENT;
 | 
							retval = -ENOENT;
 | 
				
			||||||
		goto fail_request_resource;
 | 
							goto fail_request_resource;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (IS_ENABLED(CONFIG_COMMON_CLK)) {
 | 
						if (IS_ENABLED(CONFIG_COMMON_CLK)) {
 | 
				
			||||||
		uclk = devm_clk_get(&pdev->dev, "usb_clk");
 | 
							atmel_ehci->uclk = devm_clk_get(&pdev->dev, "usb_clk");
 | 
				
			||||||
		if (IS_ERR(uclk)) {
 | 
							if (IS_ERR(atmel_ehci->uclk)) {
 | 
				
			||||||
			dev_err(&pdev->dev, "failed to get uclk\n");
 | 
								dev_err(&pdev->dev, "failed to get uclk\n");
 | 
				
			||||||
			retval = PTR_ERR(uclk);
 | 
								retval = PTR_ERR(atmel_ehci->uclk);
 | 
				
			||||||
			goto fail_request_resource;
 | 
								goto fail_request_resource;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -169,11 +193,35 @@ static int ehci_atmel_drv_remove(struct platform_device *pdev)
 | 
				
			||||||
	usb_put_hcd(hcd);
 | 
						usb_put_hcd(hcd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	atmel_stop_ehci(pdev);
 | 
						atmel_stop_ehci(pdev);
 | 
				
			||||||
	fclk = iclk = NULL;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_PM
 | 
				
			||||||
 | 
					static int ehci_atmel_drv_suspend(struct device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usb_hcd *hcd = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
						struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = ehci_suspend(hcd, false);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						atmel_stop_clock(atmel_ehci);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ehci_atmel_drv_resume(struct device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usb_hcd *hcd = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
						struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						atmel_start_clock(atmel_ehci);
 | 
				
			||||||
 | 
						return ehci_resume(hcd, false);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_OF
 | 
					#ifdef CONFIG_OF
 | 
				
			||||||
static const struct of_device_id atmel_ehci_dt_ids[] = {
 | 
					static const struct of_device_id atmel_ehci_dt_ids[] = {
 | 
				
			||||||
	{ .compatible = "atmel,at91sam9g45-ehci" },
 | 
						{ .compatible = "atmel,at91sam9g45-ehci" },
 | 
				
			||||||
| 
						 | 
					@ -183,12 +231,16 @@ static const struct of_device_id atmel_ehci_dt_ids[] = {
 | 
				
			||||||
MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids);
 | 
					MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static SIMPLE_DEV_PM_OPS(ehci_atmel_pm_ops, ehci_atmel_drv_suspend,
 | 
				
			||||||
 | 
										ehci_atmel_drv_resume);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct platform_driver ehci_atmel_driver = {
 | 
					static struct platform_driver ehci_atmel_driver = {
 | 
				
			||||||
	.probe		= ehci_atmel_drv_probe,
 | 
						.probe		= ehci_atmel_drv_probe,
 | 
				
			||||||
	.remove		= ehci_atmel_drv_remove,
 | 
						.remove		= ehci_atmel_drv_remove,
 | 
				
			||||||
	.shutdown	= usb_hcd_platform_shutdown,
 | 
						.shutdown	= usb_hcd_platform_shutdown,
 | 
				
			||||||
	.driver		= {
 | 
						.driver		= {
 | 
				
			||||||
		.name	= "atmel-ehci",
 | 
							.name	= "atmel-ehci",
 | 
				
			||||||
 | 
							.pm	= &ehci_atmel_pm_ops,
 | 
				
			||||||
		.of_match_table	= of_match_ptr(atmel_ehci_dt_ids),
 | 
							.of_match_table	= of_match_ptr(atmel_ehci_dt_ids),
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -199,7 +251,7 @@ static int __init ehci_atmel_init(void)
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pr_info("%s: " DRIVER_DESC "\n", hcd_name);
 | 
						pr_info("%s: " DRIVER_DESC "\n", hcd_name);
 | 
				
			||||||
	ehci_init_driver(&ehci_atmel_hc_driver, NULL);
 | 
						ehci_init_driver(&ehci_atmel_hc_driver, &ehci_atmel_drv_overrides);
 | 
				
			||||||
	return platform_driver_register(&ehci_atmel_driver);
 | 
						return platform_driver_register(&ehci_atmel_driver);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
module_init(ehci_atmel_init);
 | 
					module_init(ehci_atmel_init);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -709,7 +709,6 @@ static struct platform_driver ehci_fsl_driver = {
 | 
				
			||||||
	.shutdown = usb_hcd_platform_shutdown,
 | 
						.shutdown = usb_hcd_platform_shutdown,
 | 
				
			||||||
	.driver = {
 | 
						.driver = {
 | 
				
			||||||
		.name = "fsl-ehci",
 | 
							.name = "fsl-ehci",
 | 
				
			||||||
		.owner	= THIS_MODULE,
 | 
					 | 
				
			||||||
		.pm = EHCI_FSL_PM_OPS,
 | 
							.pm = EHCI_FSL_PM_OPS,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -187,7 +187,6 @@ static struct platform_driver ehci_grlib_driver = {
 | 
				
			||||||
	.shutdown	= usb_hcd_platform_shutdown,
 | 
						.shutdown	= usb_hcd_platform_shutdown,
 | 
				
			||||||
	.driver = {
 | 
						.driver = {
 | 
				
			||||||
		.name = "grlib-ehci",
 | 
							.name = "grlib-ehci",
 | 
				
			||||||
		.owner = THIS_MODULE,
 | 
					 | 
				
			||||||
		.of_match_table = ehci_hcd_grlib_of_match,
 | 
							.of_match_table = ehci_hcd_grlib_of_match,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1110,7 +1110,7 @@ int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup)
 | 
				
			||||||
EXPORT_SYMBOL_GPL(ehci_suspend);
 | 
					EXPORT_SYMBOL_GPL(ehci_suspend);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Returns 0 if power was preserved, 1 if power was lost */
 | 
					/* Returns 0 if power was preserved, 1 if power was lost */
 | 
				
			||||||
int ehci_resume(struct usb_hcd *hcd, bool hibernated)
 | 
					int ehci_resume(struct usb_hcd *hcd, bool force_reset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
 | 
						struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1124,12 +1124,12 @@ int ehci_resume(struct usb_hcd *hcd, bool hibernated)
 | 
				
			||||||
		return 0;		/* Controller is dead */
 | 
							return 0;		/* Controller is dead */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * If CF is still set and we aren't resuming from hibernation
 | 
						 * If CF is still set and reset isn't forced
 | 
				
			||||||
	 * then we maintained suspend power.
 | 
						 * then we maintained suspend power.
 | 
				
			||||||
	 * Just undo the effect of ehci_suspend().
 | 
						 * Just undo the effect of ehci_suspend().
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
 | 
						if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
 | 
				
			||||||
			!hibernated) {
 | 
								!force_reset) {
 | 
				
			||||||
		int	mask = INTR_MASK;
 | 
							int	mask = INTR_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ehci_prepare_ports_for_controller_resume(ehci);
 | 
							ehci_prepare_ports_for_controller_resume(ehci);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -700,15 +700,15 @@ ehci_hub_descriptor (
 | 
				
			||||||
	memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
 | 
						memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
 | 
				
			||||||
	memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
 | 
						memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	temp = 0x0008;			/* per-port overcurrent reporting */
 | 
						temp = HUB_CHAR_INDV_PORT_OCPM;	/* per-port overcurrent reporting */
 | 
				
			||||||
	if (HCS_PPC (ehci->hcs_params))
 | 
						if (HCS_PPC (ehci->hcs_params))
 | 
				
			||||||
		temp |= 0x0001;		/* per-port power control */
 | 
							temp |= HUB_CHAR_INDV_PORT_LPSM; /* per-port power control */
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		temp |= 0x0002;		/* no power switching */
 | 
							temp |= HUB_CHAR_NO_LPSM; /* no power switching */
 | 
				
			||||||
#if 0
 | 
					#if 0
 | 
				
			||||||
// re-enable when we support USB_PORT_FEAT_INDICATOR below.
 | 
					// re-enable when we support USB_PORT_FEAT_INDICATOR below.
 | 
				
			||||||
	if (HCS_INDICATOR (ehci->hcs_params))
 | 
						if (HCS_INDICATOR (ehci->hcs_params))
 | 
				
			||||||
		temp |= 0x0080;		/* per-port indicators (LEDs) */
 | 
							temp |= HUB_CHAR_PORTIND; /* per-port indicators (LEDs) */
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	desc->wHubCharacteristics = cpu_to_le16(temp);
 | 
						desc->wHubCharacteristics = cpu_to_le16(temp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,6 +42,24 @@ static inline bool is_intel_quark_x1000(struct pci_dev *pdev)
 | 
				
			||||||
		pdev->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_SOC;
 | 
							pdev->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_SOC;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This is the list of PCI IDs for the devices that have EHCI USB class and
 | 
				
			||||||
 | 
					 * specific drivers for that. One of the example is a ChipIdea device installed
 | 
				
			||||||
 | 
					 * on some Intel MID platforms.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static const struct pci_device_id bypass_pci_id_table[] = {
 | 
				
			||||||
 | 
						/* ChipIdea on Intel MID platform */
 | 
				
			||||||
 | 
						{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0811), },
 | 
				
			||||||
 | 
						{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829), },
 | 
				
			||||||
 | 
						{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe006), },
 | 
				
			||||||
 | 
						{}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline bool is_bypassed_id(struct pci_dev *pdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return !!pci_match_id(bypass_pci_id_table, pdev);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * 0x84 is the offset of in/out threshold register,
 | 
					 * 0x84 is the offset of in/out threshold register,
 | 
				
			||||||
 * and it is the same offset as the register of 'hostpc'.
 | 
					 * and it is the same offset as the register of 'hostpc'.
 | 
				
			||||||
| 
						 | 
					@ -352,6 +370,13 @@ static const struct ehci_driver_overrides pci_overrides __initconst = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*-------------------------------------------------------------------------*/
 | 
					/*-------------------------------------------------------------------------*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ehci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (is_bypassed_id(pdev))
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
						return usb_hcd_pci_probe(pdev, id);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* PCI driver selection metadata; PCI hotplugging uses this */
 | 
					/* PCI driver selection metadata; PCI hotplugging uses this */
 | 
				
			||||||
static const struct pci_device_id pci_ids [] = { {
 | 
					static const struct pci_device_id pci_ids [] = { {
 | 
				
			||||||
	/* handle any USB 2.0 EHCI controller */
 | 
						/* handle any USB 2.0 EHCI controller */
 | 
				
			||||||
| 
						 | 
					@ -370,7 +395,7 @@ static struct pci_driver ehci_pci_driver = {
 | 
				
			||||||
	.name =		(char *) hcd_name,
 | 
						.name =		(char *) hcd_name,
 | 
				
			||||||
	.id_table =	pci_ids,
 | 
						.id_table =	pci_ids,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	.probe =	usb_hcd_pci_probe,
 | 
						.probe =	ehci_pci_probe,
 | 
				
			||||||
	.remove =	usb_hcd_pci_remove,
 | 
						.remove =	usb_hcd_pci_remove,
 | 
				
			||||||
	.shutdown = 	usb_hcd_pci_shutdown,
 | 
						.shutdown = 	usb_hcd_pci_shutdown,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,7 +43,8 @@
 | 
				
			||||||
struct ehci_platform_priv {
 | 
					struct ehci_platform_priv {
 | 
				
			||||||
	struct clk *clks[EHCI_MAX_CLKS];
 | 
						struct clk *clks[EHCI_MAX_CLKS];
 | 
				
			||||||
	struct reset_control *rst;
 | 
						struct reset_control *rst;
 | 
				
			||||||
	struct phy *phy;
 | 
						struct phy **phys;
 | 
				
			||||||
 | 
						int num_phys;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char hcd_name[] = "ehci-platform";
 | 
					static const char hcd_name[] = "ehci-platform";
 | 
				
			||||||
| 
						 | 
					@ -78,7 +79,7 @@ static int ehci_platform_power_on(struct platform_device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct usb_hcd *hcd = platform_get_drvdata(dev);
 | 
						struct usb_hcd *hcd = platform_get_drvdata(dev);
 | 
				
			||||||
	struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
 | 
						struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
 | 
				
			||||||
	int clk, ret;
 | 
						int clk, ret, phy_num;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) {
 | 
						for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) {
 | 
				
			||||||
		ret = clk_prepare_enable(priv->clks[clk]);
 | 
							ret = clk_prepare_enable(priv->clks[clk]);
 | 
				
			||||||
| 
						 | 
					@ -86,20 +87,28 @@ static int ehci_platform_power_on(struct platform_device *dev)
 | 
				
			||||||
			goto err_disable_clks;
 | 
								goto err_disable_clks;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (priv->phy) {
 | 
						for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
 | 
				
			||||||
		ret = phy_init(priv->phy);
 | 
							if (priv->phys[phy_num]) {
 | 
				
			||||||
		if (ret)
 | 
								ret = phy_init(priv->phys[phy_num]);
 | 
				
			||||||
			goto err_disable_clks;
 | 
								if (ret)
 | 
				
			||||||
 | 
									goto err_exit_phy;
 | 
				
			||||||
		ret = phy_power_on(priv->phy);
 | 
								ret = phy_power_on(priv->phys[phy_num]);
 | 
				
			||||||
		if (ret)
 | 
								if (ret) {
 | 
				
			||||||
			goto err_exit_phy;
 | 
									phy_exit(priv->phys[phy_num]);
 | 
				
			||||||
 | 
									goto err_exit_phy;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_exit_phy:
 | 
					err_exit_phy:
 | 
				
			||||||
	phy_exit(priv->phy);
 | 
						while (--phy_num >= 0) {
 | 
				
			||||||
 | 
							if (priv->phys[phy_num]) {
 | 
				
			||||||
 | 
								phy_power_off(priv->phys[phy_num]);
 | 
				
			||||||
 | 
								phy_exit(priv->phys[phy_num]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
err_disable_clks:
 | 
					err_disable_clks:
 | 
				
			||||||
	while (--clk >= 0)
 | 
						while (--clk >= 0)
 | 
				
			||||||
		clk_disable_unprepare(priv->clks[clk]);
 | 
							clk_disable_unprepare(priv->clks[clk]);
 | 
				
			||||||
| 
						 | 
					@ -111,11 +120,13 @@ static void ehci_platform_power_off(struct platform_device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct usb_hcd *hcd = platform_get_drvdata(dev);
 | 
						struct usb_hcd *hcd = platform_get_drvdata(dev);
 | 
				
			||||||
	struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
 | 
						struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
 | 
				
			||||||
	int clk;
 | 
						int clk, phy_num;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (priv->phy) {
 | 
						for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
 | 
				
			||||||
		phy_power_off(priv->phy);
 | 
							if (priv->phys[phy_num]) {
 | 
				
			||||||
		phy_exit(priv->phy);
 | 
								phy_power_off(priv->phys[phy_num]);
 | 
				
			||||||
 | 
								phy_exit(priv->phys[phy_num]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--)
 | 
						for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--)
 | 
				
			||||||
| 
						 | 
					@ -143,7 +154,8 @@ static int ehci_platform_probe(struct platform_device *dev)
 | 
				
			||||||
	struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
 | 
						struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
 | 
				
			||||||
	struct ehci_platform_priv *priv;
 | 
						struct ehci_platform_priv *priv;
 | 
				
			||||||
	struct ehci_hcd *ehci;
 | 
						struct ehci_hcd *ehci;
 | 
				
			||||||
	int err, irq, clk = 0;
 | 
						const char *phy_name;
 | 
				
			||||||
 | 
						int err, irq, phy_num, clk = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (usb_disabled())
 | 
						if (usb_disabled())
 | 
				
			||||||
		return -ENODEV;
 | 
							return -ENODEV;
 | 
				
			||||||
| 
						 | 
					@ -155,7 +167,8 @@ static int ehci_platform_probe(struct platform_device *dev)
 | 
				
			||||||
	if (!pdata)
 | 
						if (!pdata)
 | 
				
			||||||
		pdata = &ehci_platform_defaults;
 | 
							pdata = &ehci_platform_defaults;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = dma_coerce_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
 | 
						err = dma_coerce_mask_and_coherent(&dev->dev,
 | 
				
			||||||
 | 
							pdata->dma_mask_64 ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -185,12 +198,42 @@ static int ehci_platform_probe(struct platform_device *dev)
 | 
				
			||||||
		if (of_property_read_bool(dev->dev.of_node, "big-endian"))
 | 
							if (of_property_read_bool(dev->dev.of_node, "big-endian"))
 | 
				
			||||||
			ehci->big_endian_mmio = ehci->big_endian_desc = 1;
 | 
								ehci->big_endian_mmio = ehci->big_endian_desc = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		priv->phy = devm_phy_get(&dev->dev, "usb");
 | 
							if (of_property_read_bool(dev->dev.of_node,
 | 
				
			||||||
		if (IS_ERR(priv->phy)) {
 | 
										  "needs-reset-on-resume"))
 | 
				
			||||||
			err = PTR_ERR(priv->phy);
 | 
								pdata->reset_on_resume = 1;
 | 
				
			||||||
			if (err == -EPROBE_DEFER)
 | 
					
 | 
				
			||||||
				goto err_put_hcd;
 | 
							priv->num_phys = of_count_phandle_with_args(dev->dev.of_node,
 | 
				
			||||||
			priv->phy = NULL;
 | 
									"phys", "#phy-cells");
 | 
				
			||||||
 | 
							priv->num_phys = priv->num_phys > 0 ? priv->num_phys : 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
 | 
				
			||||||
 | 
									sizeof(struct phy *), GFP_KERNEL);
 | 
				
			||||||
 | 
							if (!priv->phys)
 | 
				
			||||||
 | 
								return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
 | 
				
			||||||
 | 
									err = of_property_read_string_index(
 | 
				
			||||||
 | 
											dev->dev.of_node,
 | 
				
			||||||
 | 
											"phy-names", phy_num,
 | 
				
			||||||
 | 
											&phy_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (err < 0) {
 | 
				
			||||||
 | 
										if (priv->num_phys > 1) {
 | 
				
			||||||
 | 
											dev_err(&dev->dev, "phy-names not provided");
 | 
				
			||||||
 | 
											goto err_put_hcd;
 | 
				
			||||||
 | 
										} else
 | 
				
			||||||
 | 
											phy_name = "usb";
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									priv->phys[phy_num] = devm_phy_get(&dev->dev,
 | 
				
			||||||
 | 
											phy_name);
 | 
				
			||||||
 | 
									if (IS_ERR(priv->phys[phy_num])) {
 | 
				
			||||||
 | 
										err = PTR_ERR(priv->phys[phy_num]);
 | 
				
			||||||
 | 
										if ((priv->num_phys > 1) ||
 | 
				
			||||||
 | 
										    (err == -EPROBE_DEFER))
 | 
				
			||||||
 | 
											goto err_put_hcd;
 | 
				
			||||||
 | 
										priv->phys[phy_num] = NULL;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (clk = 0; clk < EHCI_MAX_CLKS; clk++) {
 | 
							for (clk = 0; clk < EHCI_MAX_CLKS; clk++) {
 | 
				
			||||||
| 
						 | 
					@ -340,7 +383,7 @@ static int ehci_platform_resume(struct device *dev)
 | 
				
			||||||
			return err;
 | 
								return err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ehci_resume(hcd, false);
 | 
						ehci_resume(hcd, pdata->reset_on_resume);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif /* CONFIG_PM_SLEEP */
 | 
					#endif /* CONFIG_PM_SLEEP */
 | 
				
			||||||
| 
						 | 
					@ -349,6 +392,7 @@ static const struct of_device_id vt8500_ehci_ids[] = {
 | 
				
			||||||
	{ .compatible = "via,vt8500-ehci", },
 | 
						{ .compatible = "via,vt8500-ehci", },
 | 
				
			||||||
	{ .compatible = "wm,prizm-ehci", },
 | 
						{ .compatible = "wm,prizm-ehci", },
 | 
				
			||||||
	{ .compatible = "generic-ehci", },
 | 
						{ .compatible = "generic-ehci", },
 | 
				
			||||||
 | 
						{ .compatible = "cavium,octeon-6335-ehci", },
 | 
				
			||||||
	{}
 | 
						{}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
MODULE_DEVICE_TABLE(of, vt8500_ehci_ids);
 | 
					MODULE_DEVICE_TABLE(of, vt8500_ehci_ids);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -325,6 +325,5 @@ static struct platform_driver ehci_hcd_msp_driver = {
 | 
				
			||||||
	.remove		= ehci_hcd_msp_drv_remove,
 | 
						.remove		= ehci_hcd_msp_drv_remove,
 | 
				
			||||||
	.driver		= {
 | 
						.driver		= {
 | 
				
			||||||
		.name	= "pmcmsp-ehci",
 | 
							.name	= "pmcmsp-ehci",
 | 
				
			||||||
		.owner	= THIS_MODULE,
 | 
					 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -234,7 +234,6 @@ static struct platform_driver ehci_hcd_ppc_of_driver = {
 | 
				
			||||||
	.shutdown	= usb_hcd_platform_shutdown,
 | 
						.shutdown	= usb_hcd_platform_shutdown,
 | 
				
			||||||
	.driver = {
 | 
						.driver = {
 | 
				
			||||||
		.name = "ppc-of-ehci",
 | 
							.name = "ppc-of-ehci",
 | 
				
			||||||
		.owner = THIS_MODULE,
 | 
					 | 
				
			||||||
		.of_match_table = ehci_hcd_ppc_of_match,
 | 
							.of_match_table = ehci_hcd_ppc_of_match,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -178,7 +178,6 @@ static struct platform_driver ehci_hcd_sead3_driver = {
 | 
				
			||||||
	.shutdown	= usb_hcd_platform_shutdown,
 | 
						.shutdown	= usb_hcd_platform_shutdown,
 | 
				
			||||||
	.driver = {
 | 
						.driver = {
 | 
				
			||||||
		.name	= "sead3-ehci",
 | 
							.name	= "sead3-ehci",
 | 
				
			||||||
		.owner	= THIS_MODULE,
 | 
					 | 
				
			||||||
		.pm	= SEAD3_EHCI_PMOPS,
 | 
							.pm	= SEAD3_EHCI_PMOPS,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue