Преглед изворни кода

Merge tag 'usb-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB patches from Greg Kroah-Hartman:
 "Here's the big USB patch set for the 3.6-rc1 merge window.

  Lots of little changes in here, primarily for gadget controllers and
  drivers.  There's some scsi changes that I think also went in through
  the scsi tree, but they merge just fine.  All of these patches have
  been in the linux-next tree for a while now.

  Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>"

Fix up trivial conflicts in include/scsi/scsi_device.h (same libata
conflict that Jeff had already encountered)

* tag 'usb-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (207 commits)
  usb: Add USB_QUIRK_RESET_RESUME for all Logitech UVC webcams
  usb: Add quirk detection based on interface information
  usb: s3c-hsotg: Add header file protection macros in s3c-hsotg.h
  USB: ehci-s5p: Add vbus setup function to the s5p ehci glue layer
  USB: add USB_VENDOR_AND_INTERFACE_INFO() macro
  USB: notify phy when root hub port connect change
  USB: remove 8 bytes of padding from usb_host_interface on 64 bit builds
  USB: option: add ZTE MF821D
  USB: sierra: QMI mode MC7710 moved to qcserial
  USB: qcserial: adding Sierra Wireless devices
  USB: qcserial: support generic Qualcomm serial ports
  USB: qcserial: make probe more flexible
  USB: qcserial: centralize probe exit path
  USB: qcserial: consolidate usb_set_interface calls
  USB: ehci-s5p: Add support for device tree
  USB: ohci-exynos: Add support for device tree
  USB: ehci-omap: fix compile failure(v1)
  usb: host: tegra: pass correct pointer in ehci_setup()
  USB: ehci-fsl: Update ifdef check to work on 64-bit ppc
  USB: serial: keyspan: Removed unrequired parentheses.
  ...
Linus Torvalds пре 12 година
родитељ
комит
9fc377799b
100 измењених фајлова са 6506 додато и 3318 уклоњено
  1. 12 0
      Documentation/ABI/testing/sysfs-bus-usb
  2. 18 0
      Documentation/devicetree/bindings/usb/ci13xxx-imx.txt
  3. 13 0
      Documentation/devicetree/bindings/usb/mxs-phy.txt
  4. 226 0
      Documentation/usb/mass-storage.txt
  5. 7 7
      arch/arm/mach-omap2/clock3xxx_data.c
  6. 4 4
      drivers/power/ab8500_charger.c
  7. 4 4
      drivers/power/isp1704_charger.c
  8. 11 11
      drivers/power/pda_power.c
  9. 7 6
      drivers/power/twl4030_charger.c
  10. 1 0
      drivers/usb/chipidea/Kconfig
  11. 7 2
      drivers/usb/chipidea/Makefile
  12. 17 15
      drivers/usb/chipidea/ci.h
  13. 198 0
      drivers/usb/chipidea/ci13xxx_imx.c
  14. 26 37
      drivers/usb/chipidea/ci13xxx_msm.c
  15. 15 37
      drivers/usb/chipidea/ci13xxx_pci.c
  16. 64 6
      drivers/usb/chipidea/core.c
  17. 73 73
      drivers/usb/chipidea/debug.c
  18. 2 1
      drivers/usb/chipidea/host.c
  19. 201 200
      drivers/usb/chipidea/udc.c
  20. 1 1
      drivers/usb/class/cdc-acm.c
  21. 0 25
      drivers/usb/class/cdc-wdm.c
  22. 140 29
      drivers/usb/core/devio.c
  23. 31 17
      drivers/usb/core/driver.c
  24. 1 1
      drivers/usb/core/file.c
  25. 9 1
      drivers/usb/core/hcd.c
  26. 110 29
      drivers/usb/core/hub.c
  27. 11 5
      drivers/usb/core/message.c
  28. 88 63
      drivers/usb/core/quirks.c
  29. 13 2
      drivers/usb/core/sysfs.c
  30. 1 0
      drivers/usb/core/usb.c
  31. 10 3
      drivers/usb/core/usb.h
  32. 10 3
      drivers/usb/dwc3/core.c
  33. 83 24
      drivers/usb/dwc3/core.h
  34. 0 1
      drivers/usb/dwc3/dwc3-exynos.c
  35. 92 54
      drivers/usb/dwc3/ep0.c
  36. 217 148
      drivers/usb/dwc3/gadget.c
  37. 6 0
      drivers/usb/dwc3/gadget.h
  38. 1 1
      drivers/usb/early/ehci-dbgp.c
  39. 9 0
      drivers/usb/gadget/Kconfig
  40. 1 0
      drivers/usb/gadget/Makefile
  41. 1 0
      drivers/usb/gadget/acm_ms.c
  42. 1 0
      drivers/usb/gadget/at91_udc.c
  43. 5 2
      drivers/usb/gadget/composite.c
  44. 7 0
      drivers/usb/gadget/f_fs.c
  45. 165 43
      drivers/usb/gadget/f_hid.c
  46. 31 102
      drivers/usb/gadget/f_mass_storage.c
  47. 241 46
      drivers/usb/gadget/f_uvc.c
  48. 5 3
      drivers/usb/gadget/f_uvc.h
  49. 31 43
      drivers/usb/gadget/fsl_mxc_udc.c
  50. 10 8
      drivers/usb/gadget/fsl_udc_core.c
  51. 3 3
      drivers/usb/gadget/imx_udc.c
  52. 25 60
      drivers/usb/gadget/lpc32xx_udc.c
  53. 320 0
      drivers/usb/gadget/mv_u3d.h
  54. 2098 0
      drivers/usb/gadget/mv_u3d_core.c
  55. 8 7
      drivers/usb/gadget/mv_udc_core.c
  56. 181 253
      drivers/usb/gadget/omap_udc.c
  57. 1 1
      drivers/usb/gadget/pch_udc.c
  58. 9 8
      drivers/usb/gadget/pxa25x_udc.c
  59. 8 7
      drivers/usb/gadget/pxa27x_udc.c
  60. 110 105
      drivers/usb/gadget/s3c-hsotg.c
  61. 7 6
      drivers/usb/gadget/s3c-hsudc.c
  62. 29 34
      drivers/usb/gadget/storage_common.c
  63. 6 6
      drivers/usb/gadget/u_ether.c
  64. 3 1
      drivers/usb/gadget/uvc.h
  65. 25 4
      drivers/usb/gadget/webcam.c
  66. 2 2
      drivers/usb/host/Kconfig
  67. 2 17
      drivers/usb/host/ehci-atmel.c
  68. 8 79
      drivers/usb/host/ehci-au1xxx.c
  69. 1 5
      drivers/usb/host/ehci-cns3xxx.c
  70. 14 10
      drivers/usb/host/ehci-dbg.c
  71. 13 29
      drivers/usb/host/ehci-fsl.c
  72. 2 13
      drivers/usb/host/ehci-grlib.c
  73. 226 286
      drivers/usb/host/ehci-hcd.c
  74. 71 58
      drivers/usb/host/ehci-hub.c
  75. 1 5
      drivers/usb/host/ehci-ixp4xx.c
  76. 3 22
      drivers/usb/host/ehci-mem.c
  77. 7 20
      drivers/usb/host/ehci-msm.c
  78. 11 25
      drivers/usb/host/ehci-mv.c
  79. 1 16
      drivers/usb/host/ehci-mxc.c
  80. 1 7
      drivers/usb/host/ehci-octeon.c
  81. 59 55
      drivers/usb/host/ehci-omap.c
  82. 1 16
      drivers/usb/host/ehci-orion.c
  83. 82 156
      drivers/usb/host/ehci-pci.c
  84. 3 4
      drivers/usb/host/ehci-platform.c
  85. 2 15
      drivers/usb/host/ehci-pmcmsp.c
  86. 1 24
      drivers/usb/host/ehci-ppc-of.c
  87. 1 17
      drivers/usb/host/ehci-ps3.c
  88. 177 134
      drivers/usb/host/ehci-q.c
  89. 54 81
      drivers/usb/host/ehci-s5p.c
  90. 195 357
      drivers/usb/host/ehci-sched.c
  91. 3 71
      drivers/usb/host/ehci-sead3.c
  92. 1 15
      drivers/usb/host/ehci-sh.c
  93. 4 67
      drivers/usb/host/ehci-spear.c
  94. 10 26
      drivers/usb/host/ehci-tegra.c
  95. 401 0
      drivers/usb/host/ehci-timer.c
  96. 1 13
      drivers/usb/host/ehci-vt8500.c
  97. 1 8
      drivers/usb/host/ehci-w90x900.c
  98. 1 30
      drivers/usb/host/ehci-xilinx-of.c
  99. 1 20
      drivers/usb/host/ehci-xls.c
  100. 75 63
      drivers/usb/host/ehci.h

+ 12 - 0
Documentation/ABI/testing/sysfs-bus-usb

@@ -208,3 +208,15 @@ Description:
 		such as ACPI. This file will read either "removable" or
 		such as ACPI. This file will read either "removable" or
 		"fixed" if the information is available, and "unknown"
 		"fixed" if the information is available, and "unknown"
 		otherwise.
 		otherwise.
+
+What:		/sys/bus/usb/devices/.../ltm_capable
+Date:		July 2012
+Contact:	Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Description:
+		USB 3.0 devices may optionally support Latency Tolerance
+		Messaging (LTM).  They indicate their support by setting a bit
+		in the bmAttributes field of their SuperSpeed BOS descriptors.
+		If that bit is set for the device, ltm_capable will read "yes".
+		If the device doesn't support LTM, the file will read "no".
+		The file will be present for all speeds of USB devices, and will
+		always read "no" for USB 1.1 and USB 2.0 devices.

+ 18 - 0
Documentation/devicetree/bindings/usb/ci13xxx-imx.txt

@@ -0,0 +1,18 @@
+* Freescale i.MX ci13xxx usb controllers
+
+Required properties:
+- compatible: Should be "fsl,imx27-usb"
+- reg: Should contain registers location and length
+- interrupts: Should contain controller interrupt
+
+Optional properties:
+- fsl,usbphy: phandler of usb phy that connects to the only one port
+- vbus-supply: regulator for vbus
+
+Examples:
+usb@02184000 { /* USB OTG */
+	compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
+	reg = <0x02184000 0x200>;
+	interrupts = <0 43 0x04>;
+	fsl,usbphy = <&usbphy1>;
+};

+ 13 - 0
Documentation/devicetree/bindings/usb/mxs-phy.txt

@@ -0,0 +1,13 @@
+* Freescale MXS USB Phy Device
+
+Required properties:
+- compatible: Should be "fsl,imx23-usbphy"
+- reg: Should contain registers location and length
+- interrupts: Should contain phy interrupt
+
+Example:
+usbphy1: usbphy@020c9000 {
+	compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy";
+	reg = <0x020c9000 0x1000>;
+	interrupts = <0 44 0x04>;
+};

+ 226 - 0
Documentation/usb/mass-storage.txt

@@ -0,0 +1,226 @@
+* Overview
+
+  Mass Storage Gadget (or MSG) acts as a USB Mass Storage device,
+  appearing to the host as a disk or a CD-ROM drive.  It supports
+  multiple logical units (LUNs).  Backing storage for each LUN is
+  provided by a regular file or a block device, access can be limited
+  to read-only, and gadget can indicate that it is removable and/or
+  CD-ROM (the latter implies read-only access).
+
+  Its requirements are modest; only a bulk-in and a bulk-out endpoint
+  are needed.  The memory requirement amounts to two 16K buffers.
+  Support is included for full-speed, high-speed and SuperSpeed
+  operation.
+
+  Note that the driver is slightly non-portable in that it assumes
+  a single memory/DMA buffer will be useable for bulk-in and bulk-out
+  endpoints.  With most device controllers this is not an issue, but
+  there may be some with hardware restrictions that prevent a buffer
+  from being used by more than one endpoint.
+
+  This document describes how to use the gadget from user space, its
+  relation to mass storage function (or MSF) and different gadgets
+  using it, and how it differs from File Storage Gadget (or FSG).  It
+  will talk only briefly about how to use MSF within composite
+  gadgets.
+
+* Module parameters
+
+  The mass storage gadget accepts the following mass storage specific
+  module parameters:
+
+  - file=filename[,filename...]
+
+    This parameter lists paths to files or block devices used for
+    backing storage for each logical unit.  There may be at most
+    FSG_MAX_LUNS (8) LUNs set.  If more files are specified, they will
+    be silently ignored.  See also “luns” parameter.
+
+    *BEWARE* that if a file is used as a backing storage, it may not
+    be modified by any other process.  This is because the host
+    assumes the data does not change without its knowledge.  It may be
+    read, but (if the logical unit is writable) due to buffering on
+    the host side, the contents are not well defined.
+
+    The size of the logical unit will be rounded down to a full
+    logical block.  The logical block size is 2048 bytes for LUNs
+    simulating CD-ROM, block size of the device if the backing file is
+    a block device, or 512 bytes otherwise.
+
+  - removable=b[,b...]
+
+    This parameter specifies whether each logical unit should be
+    removable.  “b” here is either “y”, “Y” or “1” for true or “n”,
+    “N” or “0” for false.
+
+    If this option is set for a logical unit, gadget will accept an
+    “eject” SCSI request (Start/Stop Unit).  When it is sent, the
+    backing file will be closed to simulate ejection and the logical
+    unit will not be mountable by the host until a new backing file is
+    specified by userspace on the device (see “sysfs entries”
+    section).
+
+    If a logical unit is not removable (the default), a backing file
+    must be specified for it with the “file” parameter as the module
+    is loaded.  The same applies if the module is built in, no
+    exceptions.
+
+    The default value of the flag is false, *HOWEVER* it used to be
+    true.  This has been changed to better match File Storage Gadget
+    and because it seems like a saner default after all.  Thus to
+    maintain compatibility with older kernels, it's best to specify
+    the default values.  Also, if one relied on old default, explicit
+    “n” needs to be specified now.
+
+    Note that “removable” means the logical unit's media can be
+    ejected or removed (as is true for a CD-ROM drive or a card
+    reader).  It does *not* mean that the entire gadget can be
+    unplugged from the host; the proper term for that is
+    “hot-unpluggable”.
+
+  - cdrom=b[,b...]
+
+    This parameter specifies whether each logical unit should simulate
+    CD-ROM.  The default is false.
+
+  - ro=b[,b...]
+
+    This parameter specifies whether each logical unit should be
+    reported as read only.  This will prevent host from modifying the
+    backing files.
+
+    Note that if this flag for given logical unit is false but the
+    backing file could not be opened in read/write mode, the gadget
+    will fall back to read only mode anyway.
+
+    The default value for non-CD-ROM logical units is false; for
+    logical units simulating CD-ROM it is forced to true.
+
+  - nofua=b[,b...]
+
+    This parameter specifies whether FUA flag should be ignored in SCSI
+    Write10 and Write12 commands sent to given logical units.
+
+    MS Windows mounts removable storage in “Removal optimised mode” by
+    default.  All the writes to the media are synchronous, which is
+    achieved by setting the FUA (Force Unit Access) bit in SCSI
+    Write(10,12) commands.  This forces each write to wait until the
+    data has actually been written out and prevents I/O requests
+    aggregation in block layer dramatically decreasing performance.
+
+    Note that this may mean that if the device is powered from USB and
+    the user unplugs the device without unmounting it first (which at
+    least some Windows users do), the data may be lost.
+
+    The default value is false.
+
+  - luns=N
+
+    This parameter specifies number of logical units the gadget will
+    have.  It is limited by FSG_MAX_LUNS (8) and higher value will be
+    capped.
+
+    If this parameter is provided, and the number of files specified
+    in “file” argument is greater then the value of “luns”, all excess
+    files will be ignored.
+
+    If this parameter is not present, the number of logical units will
+    be deduced from the number of files specified in the “file”
+    parameter.  If the file parameter is missing as well, one is
+    assumed.
+
+  - stall=b
+
+    Specifies whether the gadget is allowed to halt bulk endpoints.
+    The default is determined according to the type of USB device
+    controller, but usually true.
+
+  In addition to the above, the gadget also accepts the following
+  parameters defined by the composite framework (they are common to
+  all composite gadgets so just a quick listing):
+
+  - idVendor      -- USB Vendor ID (16 bit integer)
+  - idProduct     -- USB Product ID (16 bit integer)
+  - bcdDevice     -- USB Device version (BCD) (16 bit integer)
+  - iManufacturer -- USB Manufacturer string (string)
+  - iProduct      -- USB Product string (string)
+  - iSerialNumber -- SerialNumber string (sting)
+
+* sysfs entries
+
+  For each logical unit, the gadget creates a directory in the sysfs
+  hierarchy.  Inside of it the following three files are created:
+
+  - file
+
+    When read it returns the path to the backing file for the given
+    logical unit.  If there is no backing file (possible only if the
+    logical unit is removable), the content is empty.
+
+    When written into, it changes the backing file for given logical
+    unit.  This change can be performed even if given logical unit is
+    not specified as removable (but that may look strange to the
+    host).  It may fail, however, if host disallowed medium removal
+    with the Prevent-Allow Medium Removal SCSI command.
+
+  - ro
+
+    Reflects the state of ro flag for the given logical unit.  It can
+    be read any time, and written to when there is no backing file
+    open for given logical unit.
+
+  - nofua
+
+    Reflects the state of nofua flag for given logical unit.  It can
+    be read and written.
+
+  Other then those, as usual, the values of module parameters can be
+  read from /sys/module/g_mass_storage/parameters/* files.
+
+* Other gadgets using mass storage function
+
+  The Mass Storage Gadget uses the Mass Storage Function to handle
+  mass storage protocol.  As a composite function, MSF may be used by
+  other gadgets as well (eg. g_multi and acm_ms).
+
+  All of the information in previous sections are valid for other
+  gadgets using MSF, except that support for mass storage related
+  module parameters may be missing, or the parameters may have
+  a prefix.  To figure out whether any of this is true one needs to
+  consult the gadget's documentation or its source code.
+
+  For examples of how to include mass storage function in gadgets, one
+  may take a look at mass_storage.c, acm_ms.c and multi.c (sorted by
+  complexity).
+
+* Relation to file storage gadget
+
+  The Mass Storage Function and thus the Mass Storage Gadget has been
+  based on the File Storage Gadget.  The difference between the two is
+  that MSG is a composite gadget (ie. uses the composite framework)
+  while file storage gadget is a traditional gadget.  From userspace
+  point of view this distinction does not really matter, but from
+  kernel hacker's point of view, this means that (i) MSG does not
+  duplicate code needed for handling basic USB protocol commands and
+  (ii) MSF can be used in any other composite gadget.
+
+  Because of that, File Storage Gadget has been deprecated and
+  scheduled to be removed in Linux 3.8.  All users need to transition
+  to the Mass Storage Gadget by that time.  The two gadgets behave
+  mostly the same from the outside except:
+
+  1. In FSG the “removable” and “cdrom” module parameters set the flag
+     for all logical units whereas in MSG they accept a list of y/n
+     values for each logical unit.  If one uses only a single logical
+     unit this does not matter, but if there are more, the y/n value
+     needs to be repeated for each logical unit.
+
+  2. FSG's “serial”, “vendor”, “product” and “release” module
+     parameters are handled in MSG by the composite layer's parameters
+     named respectively: “iSerialnumber”, “idVendor”, “idProduct” and
+     “bcdDevice”.
+
+  3. MSG does not support FSG's test mode, thus “transport”,
+     “protocol” and “buflen” FSG's module parameters are not
+     supported.  MSG always uses SCSI protocol with bulk only
+     transport mode and 16 KiB buffers.

+ 7 - 7
arch/arm/mach-omap2/clock3xxx_data.c

@@ -3376,15 +3376,15 @@ static struct omap_clk omap3xxx_clks[] = {
 	CLK(NULL,	"usbhost_48m_fck", &usbhost_48m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
 	CLK(NULL,	"usbhost_48m_fck", &usbhost_48m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
 	CLK(NULL,	"usbhost_ick",	&usbhost_ick,	CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
 	CLK(NULL,	"usbhost_ick",	&usbhost_ick,	CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
 	CLK("usbhs_omap",	"usbhost_ick",	&usbhost_ick,	CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
 	CLK("usbhs_omap",	"usbhost_ick",	&usbhost_ick,	CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
-	CLK("usbhs_omap",	"utmi_p1_gfclk",	&dummy_ck,	CK_3XXX),
-	CLK("usbhs_omap",	"utmi_p2_gfclk",	&dummy_ck,	CK_3XXX),
-	CLK("usbhs_omap",	"xclk60mhsp1_ck",	&dummy_ck,	CK_3XXX),
-	CLK("usbhs_omap",	"xclk60mhsp2_ck",	&dummy_ck,	CK_3XXX),
-	CLK("usbhs_omap",	"usb_host_hs_utmi_p1_clk",	&dummy_ck,	CK_3XXX),
-	CLK("usbhs_omap",	"usb_host_hs_utmi_p2_clk",	&dummy_ck,	CK_3XXX),
+	CLK(NULL,	"utmi_p1_gfclk",	&dummy_ck,	CK_3XXX),
+	CLK(NULL,	"utmi_p2_gfclk",	&dummy_ck,	CK_3XXX),
+	CLK(NULL,	"xclk60mhsp1_ck",	&dummy_ck,	CK_3XXX),
+	CLK(NULL,	"xclk60mhsp2_ck",	&dummy_ck,	CK_3XXX),
+	CLK(NULL,	"usb_host_hs_utmi_p1_clk",	&dummy_ck,	CK_3XXX),
+	CLK(NULL,	"usb_host_hs_utmi_p2_clk",	&dummy_ck,	CK_3XXX),
 	CLK("usbhs_omap",	"usb_tll_hs_usb_ch0_clk",	&dummy_ck,	CK_3XXX),
 	CLK("usbhs_omap",	"usb_tll_hs_usb_ch0_clk",	&dummy_ck,	CK_3XXX),
 	CLK("usbhs_omap",	"usb_tll_hs_usb_ch1_clk",	&dummy_ck,	CK_3XXX),
 	CLK("usbhs_omap",	"usb_tll_hs_usb_ch1_clk",	&dummy_ck,	CK_3XXX),
-	CLK("usbhs_omap",	"init_60m_fclk",	&dummy_ck,	CK_3XXX),
+	CLK(NULL,	"init_60m_fclk",	&dummy_ck,	CK_3XXX),
 	CLK(NULL,	"usim_fck",	&usim_fck,	CK_3430ES2PLUS | CK_36XX),
 	CLK(NULL,	"usim_fck",	&usim_fck,	CK_3430ES2PLUS | CK_36XX),
 	CLK(NULL,	"gpt1_fck",	&gpt1_fck,	CK_3XXX),
 	CLK(NULL,	"gpt1_fck",	&gpt1_fck,	CK_3XXX),
 	CLK(NULL,	"wkup_32k_fck",	&wkup_32k_fck,	CK_3XXX),
 	CLK(NULL,	"wkup_32k_fck",	&wkup_32k_fck,	CK_3XXX),

+ 4 - 4
drivers/power/ab8500_charger.c

@@ -2517,7 +2517,7 @@ static int __devexit ab8500_charger_remove(struct platform_device *pdev)
 		dev_err(di->dev, "%s mask and set failed\n", __func__);
 		dev_err(di->dev, "%s mask and set failed\n", __func__);
 
 
 	usb_unregister_notifier(di->usb_phy, &di->nb);
 	usb_unregister_notifier(di->usb_phy, &di->nb);
-	usb_put_transceiver(di->usb_phy);
+	usb_put_phy(di->usb_phy);
 
 
 	/* Delete the work queue */
 	/* Delete the work queue */
 	destroy_workqueue(di->charger_wq);
 	destroy_workqueue(di->charger_wq);
@@ -2688,8 +2688,8 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev)
 		goto free_ac;
 		goto free_ac;
 	}
 	}
 
 
-	di->usb_phy = usb_get_transceiver();
-	if (!di->usb_phy) {
+	di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (IS_ERR_OR_NULL(di->usb_phy)) {
 		dev_err(di->dev, "failed to get usb transceiver\n");
 		dev_err(di->dev, "failed to get usb transceiver\n");
 		ret = -EINVAL;
 		ret = -EINVAL;
 		goto free_usb;
 		goto free_usb;
@@ -2747,7 +2747,7 @@ free_irq:
 		free_irq(irq, di);
 		free_irq(irq, di);
 	}
 	}
 put_usb_phy:
 put_usb_phy:
-	usb_put_transceiver(di->usb_phy);
+	usb_put_phy(di->usb_phy);
 free_usb:
 free_usb:
 	power_supply_unregister(&di->usb_chg.psy);
 	power_supply_unregister(&di->usb_chg.psy);
 free_ac:
 free_ac:

+ 4 - 4
drivers/power/isp1704_charger.c

@@ -415,8 +415,8 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
 	if (!isp)
 	if (!isp)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	isp->phy = usb_get_transceiver();
-	if (!isp->phy)
+	isp->phy = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (IS_ERR_OR_NULL(isp->phy))
 		goto fail0;
 		goto fail0;
 
 
 	isp->dev = &pdev->dev;
 	isp->dev = &pdev->dev;
@@ -475,7 +475,7 @@ fail2:
 	power_supply_unregister(&isp->psy);
 	power_supply_unregister(&isp->psy);
 fail1:
 fail1:
 	isp1704_charger_set_power(isp, 0);
 	isp1704_charger_set_power(isp, 0);
-	usb_put_transceiver(isp->phy);
+	usb_put_phy(isp->phy);
 fail0:
 fail0:
 	kfree(isp);
 	kfree(isp);
 
 
@@ -490,7 +490,7 @@ static int __devexit isp1704_charger_remove(struct platform_device *pdev)
 
 
 	usb_unregister_notifier(isp->phy, &isp->nb);
 	usb_unregister_notifier(isp->phy, &isp->nb);
 	power_supply_unregister(&isp->psy);
 	power_supply_unregister(&isp->psy);
-	usb_put_transceiver(isp->phy);
+	usb_put_phy(isp->phy);
 	isp1704_charger_set_power(isp, 0);
 	isp1704_charger_set_power(isp, 0);
 	kfree(isp);
 	kfree(isp);
 
 

+ 11 - 11
drivers/power/pda_power.c

@@ -321,12 +321,12 @@ static int pda_power_probe(struct platform_device *pdev)
 	}
 	}
 
 
 #ifdef CONFIG_USB_OTG_UTILS
 #ifdef CONFIG_USB_OTG_UTILS
-	transceiver = usb_get_transceiver();
-	if (transceiver && !pdata->is_usb_online) {
-		pdata->is_usb_online = otg_is_usb_online;
-	}
-	if (transceiver && !pdata->is_ac_online) {
-		pdata->is_ac_online = otg_is_ac_online;
+	transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (!IS_ERR_OR_NULL(transceiver)) {
+		if (!pdata->is_usb_online)
+			pdata->is_usb_online = otg_is_usb_online;
+		if (!pdata->is_ac_online)
+			pdata->is_ac_online = otg_is_ac_online;
 	}
 	}
 #endif
 #endif
 
 
@@ -373,7 +373,7 @@ static int pda_power_probe(struct platform_device *pdev)
 	}
 	}
 
 
 #ifdef CONFIG_USB_OTG_UTILS
 #ifdef CONFIG_USB_OTG_UTILS
-	if (transceiver && pdata->use_otg_notifier) {
+	if (!IS_ERR_OR_NULL(transceiver) && pdata->use_otg_notifier) {
 		otg_nb.notifier_call = otg_handle_notification;
 		otg_nb.notifier_call = otg_handle_notification;
 		ret = usb_register_notifier(transceiver, &otg_nb);
 		ret = usb_register_notifier(transceiver, &otg_nb);
 		if (ret) {
 		if (ret) {
@@ -408,8 +408,8 @@ usb_supply_failed:
 	if (pdata->is_ac_online && ac_irq)
 	if (pdata->is_ac_online && ac_irq)
 		free_irq(ac_irq->start, &pda_psy_ac);
 		free_irq(ac_irq->start, &pda_psy_ac);
 #ifdef CONFIG_USB_OTG_UTILS
 #ifdef CONFIG_USB_OTG_UTILS
-	if (transceiver)
-		usb_put_transceiver(transceiver);
+	if (!IS_ERR_OR_NULL(transceiver))
+		usb_put_phy(transceiver);
 #endif
 #endif
 ac_irq_failed:
 ac_irq_failed:
 	if (pdata->is_ac_online)
 	if (pdata->is_ac_online)
@@ -443,8 +443,8 @@ static int pda_power_remove(struct platform_device *pdev)
 	if (pdata->is_ac_online)
 	if (pdata->is_ac_online)
 		power_supply_unregister(&pda_psy_ac);
 		power_supply_unregister(&pda_psy_ac);
 #ifdef CONFIG_USB_OTG_UTILS
 #ifdef CONFIG_USB_OTG_UTILS
-	if (transceiver)
-		usb_put_transceiver(transceiver);
+	if (!IS_ERR_OR_NULL(transceiver))
+		usb_put_phy(transceiver);
 #endif
 #endif
 	if (ac_draw) {
 	if (ac_draw) {
 		regulator_put(ac_draw);
 		regulator_put(ac_draw);

+ 7 - 6
drivers/power/twl4030_charger.c

@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
+#include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/i2c/twl.h>
 #include <linux/i2c/twl.h>
@@ -479,8 +480,8 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
 
 
 	INIT_WORK(&bci->work, twl4030_bci_usb_work);
 	INIT_WORK(&bci->work, twl4030_bci_usb_work);
 
 
-	bci->transceiver = usb_get_transceiver();
-	if (bci->transceiver != NULL) {
+	bci->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (!IS_ERR_OR_NULL(bci->transceiver)) {
 		bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
 		bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
 		usb_register_notifier(bci->transceiver, &bci->usb_nb);
 		usb_register_notifier(bci->transceiver, &bci->usb_nb);
 	}
 	}
@@ -507,9 +508,9 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
 	return 0;
 	return 0;
 
 
 fail_unmask_interrupts:
 fail_unmask_interrupts:
-	if (bci->transceiver != NULL) {
+	if (!IS_ERR_OR_NULL(bci->transceiver)) {
 		usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
 		usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
-		usb_put_transceiver(bci->transceiver);
+		usb_put_phy(bci->transceiver);
 	}
 	}
 	free_irq(bci->irq_bci, bci);
 	free_irq(bci->irq_bci, bci);
 fail_bci_irq:
 fail_bci_irq:
@@ -538,9 +539,9 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev)
 	twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
 	twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
 			 TWL4030_INTERRUPTS_BCIIMR2A);
 			 TWL4030_INTERRUPTS_BCIIMR2A);
 
 
-	if (bci->transceiver != NULL) {
+	if (!IS_ERR_OR_NULL(bci->transceiver)) {
 		usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
 		usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
-		usb_put_transceiver(bci->transceiver);
+		usb_put_phy(bci->transceiver);
 	}
 	}
 	free_irq(bci->irq_bci, bci);
 	free_irq(bci->irq_bci, bci);
 	free_irq(bci->irq_chg, bci);
 	free_irq(bci->irq_chg, bci);

+ 1 - 0
drivers/usb/chipidea/Kconfig

@@ -20,6 +20,7 @@ config USB_CHIPIDEA_UDC
 
 
 config USB_CHIPIDEA_HOST
 config USB_CHIPIDEA_HOST
 	bool "ChipIdea host controller"
 	bool "ChipIdea host controller"
+	select USB_EHCI_ROOT_HUB_TT
 	help
 	help
 	  Say Y here to enable host controller functionality of the
 	  Say Y here to enable host controller functionality of the
 	  ChipIdea driver.
 	  ChipIdea driver.

+ 7 - 2
drivers/usb/chipidea/Makefile

@@ -5,10 +5,15 @@ ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC)	+= udc.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST)	+= host.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST)	+= host.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG)	+= debug.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG)	+= debug.o
 
 
+# Glue/Bridge layers go here
+
+obj-$(CONFIG_USB_CHIPIDEA)	+= ci13xxx_msm.o
+
+# PCI doesn't provide stubs, need to check
 ifneq ($(CONFIG_PCI),)
 ifneq ($(CONFIG_PCI),)
 	obj-$(CONFIG_USB_CHIPIDEA)	+= ci13xxx_pci.o
 	obj-$(CONFIG_USB_CHIPIDEA)	+= ci13xxx_pci.o
 endif
 endif
 
 
-ifneq ($(CONFIG_ARCH_MSM),)
-	obj-$(CONFIG_USB_CHIPIDEA)	+= ci13xxx_msm.o
+ifneq ($(CONFIG_OF_DEVICE),)
+	obj-$(CONFIG_USB_CHIPIDEA)	+= ci13xxx_imx.o
 endif
 endif

+ 17 - 15
drivers/usb/chipidea/ci.h

@@ -36,7 +36,7 @@
  * @name: string description of the endpoint
  * @name: string description of the endpoint
  * @qh: queue head for this endpoint
  * @qh: queue head for this endpoint
  * @wedge: is the endpoint wedged
  * @wedge: is the endpoint wedged
- * @udc: pointer to the controller
+ * @ci: pointer to the controller
  * @lock: pointer to controller's spinlock
  * @lock: pointer to controller's spinlock
  * @td_pool: pointer to controller's TD pool
  * @td_pool: pointer to controller's TD pool
  */
  */
@@ -54,7 +54,7 @@ struct ci13xxx_ep {
 	int					wedge;
 	int					wedge;
 
 
 	/* global resources */
 	/* global resources */
-	struct ci13xxx				*udc;
+	struct ci13xxx				*ci;
 	spinlock_t				*lock;
 	spinlock_t				*lock;
 	struct dma_pool				*td_pool;
 	struct dma_pool				*td_pool;
 };
 };
@@ -125,7 +125,7 @@ struct hw_bank {
  * @remote_wakeup: host-enabled remote wakeup
  * @remote_wakeup: host-enabled remote wakeup
  * @suspended: suspended by host
  * @suspended: suspended by host
  * @test_mode: the selected test mode
  * @test_mode: the selected test mode
- * @udc_driver: platform specific information supplied by parent device
+ * @platdata: platform specific information supplied by parent device
  * @vbus_active: is VBUS active
  * @vbus_active: is VBUS active
  * @transceiver: pointer to USB PHY, if any
  * @transceiver: pointer to USB PHY, if any
  * @hcd: pointer to usb_hcd for ehci host driver
  * @hcd: pointer to usb_hcd for ehci host driver
@@ -158,8 +158,10 @@ struct ci13xxx {
 	u8				suspended;
 	u8				suspended;
 	u8				test_mode;
 	u8				test_mode;
 
 
-	struct ci13xxx_udc_driver	*udc_driver;
+	struct ci13xxx_platform_data	*platdata;
 	int				vbus_active;
 	int				vbus_active;
+	/* FIXME: some day, we'll not use global phy */
+	bool				global_phy;
 	struct usb_phy			*transceiver;
 	struct usb_phy			*transceiver;
 	struct usb_hcd			*hcd;
 	struct usb_hcd			*hcd;
 };
 };
@@ -250,9 +252,9 @@ static inline int ffs_nr(u32 x)
  *
  *
  * This function returns register contents
  * This function returns register contents
  */
  */
-static inline u32 hw_read(struct ci13xxx *udc, enum ci13xxx_regs reg, u32 mask)
+static inline u32 hw_read(struct ci13xxx *ci, enum ci13xxx_regs reg, u32 mask)
 {
 {
-	return ioread32(udc->hw_bank.regmap[reg]) & mask;
+	return ioread32(ci->hw_bank.regmap[reg]) & mask;
 }
 }
 
 
 /**
 /**
@@ -261,14 +263,14 @@ static inline u32 hw_read(struct ci13xxx *udc, enum ci13xxx_regs reg, u32 mask)
  * @mask: bitfield mask
  * @mask: bitfield mask
  * @data: new value
  * @data: new value
  */
  */
-static inline void hw_write(struct ci13xxx *udc, enum ci13xxx_regs reg,
+static inline void hw_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
 			    u32 mask, u32 data)
 			    u32 mask, u32 data)
 {
 {
 	if (~mask)
 	if (~mask)
-		data = (ioread32(udc->hw_bank.regmap[reg]) & ~mask)
+		data = (ioread32(ci->hw_bank.regmap[reg]) & ~mask)
 			| (data & mask);
 			| (data & mask);
 
 
-	iowrite32(data, udc->hw_bank.regmap[reg]);
+	iowrite32(data, ci->hw_bank.regmap[reg]);
 }
 }
 
 
 /**
 /**
@@ -278,12 +280,12 @@ static inline void hw_write(struct ci13xxx *udc, enum ci13xxx_regs reg,
  *
  *
  * This function returns register contents
  * This function returns register contents
  */
  */
-static inline u32 hw_test_and_clear(struct ci13xxx *udc, enum ci13xxx_regs reg,
+static inline u32 hw_test_and_clear(struct ci13xxx *ci, enum ci13xxx_regs reg,
 				    u32 mask)
 				    u32 mask)
 {
 {
-	u32 val = ioread32(udc->hw_bank.regmap[reg]) & mask;
+	u32 val = ioread32(ci->hw_bank.regmap[reg]) & mask;
 
 
-	iowrite32(val, udc->hw_bank.regmap[reg]);
+	iowrite32(val, ci->hw_bank.regmap[reg]);
 	return val;
 	return val;
 }
 }
 
 
@@ -295,12 +297,12 @@ static inline u32 hw_test_and_clear(struct ci13xxx *udc, enum ci13xxx_regs reg,
  *
  *
  * This function returns register contents
  * This function returns register contents
  */
  */
-static inline u32 hw_test_and_write(struct ci13xxx *udc, enum ci13xxx_regs reg,
+static inline u32 hw_test_and_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
 				    u32 mask, u32 data)
 				    u32 mask, u32 data)
 {
 {
-	u32 val = hw_read(udc, reg, ~0);
+	u32 val = hw_read(ci, reg, ~0);
 
 
-	hw_write(udc, reg, mask, data);
+	hw_write(ci, reg, mask, data);
 	return (val & mask) >> ffs_nr(mask);
 	return (val & mask) >> ffs_nr(mask);
 }
 }
 
 

+ 198 - 0
drivers/usb/chipidea/ci13xxx_imx.c

@@ -0,0 +1,198 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright (C) 2012 Marek Vasut <marex@denx.de>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/dma-mapping.h>
+#include <linux/usb/chipidea.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+
+#include "ci.h"
+
+#define pdev_to_phy(pdev) \
+	((struct usb_phy *)platform_get_drvdata(pdev))
+
+struct ci13xxx_imx_data {
+	struct device_node *phy_np;
+	struct usb_phy *phy;
+	struct platform_device *ci_pdev;
+	struct clk *clk;
+	struct regulator *reg_vbus;
+};
+
+static struct ci13xxx_platform_data ci13xxx_imx_platdata __devinitdata  = {
+	.name			= "ci13xxx_imx",
+	.flags			= CI13XXX_REQUIRE_TRANSCEIVER |
+				  CI13XXX_PULLUP_ON_VBUS |
+				  CI13XXX_DISABLE_STREAMING,
+	.capoffset		= DEF_CAPOFFSET,
+};
+
+static int __devinit ci13xxx_imx_probe(struct platform_device *pdev)
+{
+	struct ci13xxx_imx_data *data;
+	struct platform_device *plat_ci, *phy_pdev;
+	struct device_node *phy_np;
+	struct resource *res;
+	struct regulator *reg_vbus;
+	int ret;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		dev_err(&pdev->dev, "Failed to allocate CI13xxx-IMX data!\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Can't get device resources!\n");
+		return -ENOENT;
+	}
+
+	data->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(data->clk)) {
+		dev_err(&pdev->dev,
+			"Failed to get clock, err=%ld\n", PTR_ERR(data->clk));
+		return PTR_ERR(data->clk);
+	}
+
+	ret = clk_prepare_enable(data->clk);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"Failed to prepare or enable clock, err=%d\n", ret);
+		return ret;
+	}
+
+	phy_np = of_parse_phandle(pdev->dev.of_node, "fsl,usbphy", 0);
+	if (phy_np) {
+		data->phy_np = phy_np;
+		phy_pdev = of_find_device_by_node(phy_np);
+		if (phy_pdev) {
+			struct usb_phy *phy;
+			phy = pdev_to_phy(phy_pdev);
+			if (phy &&
+			    try_module_get(phy_pdev->dev.driver->owner)) {
+				usb_phy_init(phy);
+				data->phy = phy;
+			}
+		}
+	}
+
+	/* we only support host now, so enable vbus here */
+	reg_vbus = devm_regulator_get(&pdev->dev, "vbus");
+	if (!IS_ERR(reg_vbus)) {
+		ret = regulator_enable(reg_vbus);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"Failed to enable vbus regulator, err=%d\n",
+				ret);
+			goto put_np;
+		}
+		data->reg_vbus = reg_vbus;
+	} else {
+		reg_vbus = NULL;
+	}
+
+	ci13xxx_imx_platdata.phy = data->phy;
+
+	if (!pdev->dev.dma_mask) {
+		pdev->dev.dma_mask = devm_kzalloc(&pdev->dev,
+				      sizeof(*pdev->dev.dma_mask), GFP_KERNEL);
+		if (!pdev->dev.dma_mask) {
+			ret = -ENOMEM;
+			dev_err(&pdev->dev, "Failed to alloc dma_mask!\n");
+			goto err;
+		}
+		*pdev->dev.dma_mask = DMA_BIT_MASK(32);
+		dma_set_coherent_mask(&pdev->dev, *pdev->dev.dma_mask);
+	}
+	plat_ci = ci13xxx_add_device(&pdev->dev,
+				pdev->resource, pdev->num_resources,
+				&ci13xxx_imx_platdata);
+	if (IS_ERR(plat_ci)) {
+		ret = PTR_ERR(plat_ci);
+		dev_err(&pdev->dev,
+			"Can't register ci_hdrc platform device, err=%d\n",
+			ret);
+		goto err;
+	}
+
+	data->ci_pdev = plat_ci;
+	platform_set_drvdata(pdev, data);
+
+	pm_runtime_no_callbacks(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	return 0;
+
+err:
+	if (reg_vbus)
+		regulator_disable(reg_vbus);
+put_np:
+	if (phy_np)
+		of_node_put(phy_np);
+	clk_disable_unprepare(data->clk);
+	return ret;
+}
+
+static int __devexit ci13xxx_imx_remove(struct platform_device *pdev)
+{
+	struct ci13xxx_imx_data *data = platform_get_drvdata(pdev);
+
+	pm_runtime_disable(&pdev->dev);
+	ci13xxx_remove_device(data->ci_pdev);
+
+	if (data->reg_vbus)
+		regulator_disable(data->reg_vbus);
+
+	if (data->phy) {
+		usb_phy_shutdown(data->phy);
+		module_put(data->phy->dev->driver->owner);
+	}
+
+	of_node_put(data->phy_np);
+
+	clk_disable_unprepare(data->clk);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id ci13xxx_imx_dt_ids[] = {
+	{ .compatible = "fsl,imx27-usb", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ci13xxx_imx_dt_ids);
+
+static struct platform_driver ci13xxx_imx_driver = {
+	.probe = ci13xxx_imx_probe,
+	.remove = __devexit_p(ci13xxx_imx_remove),
+	.driver = {
+		.name = "imx_usb",
+		.owner = THIS_MODULE,
+		.of_match_table = ci13xxx_imx_dt_ids,
+	 },
+};
+
+module_platform_driver(ci13xxx_imx_driver);
+
+MODULE_ALIAS("platform:imx-usb");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CI13xxx i.MX USB binding");
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");

+ 26 - 37
drivers/usb/chipidea/ci13xxx_msm.c

@@ -15,11 +15,11 @@
 
 
 #include "ci.h"
 #include "ci.h"
 
 
-#define MSM_USB_BASE	(udc->hw_bank.abs)
+#define MSM_USB_BASE	(ci->hw_bank.abs)
 
 
-static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
+static void ci13xxx_msm_notify_event(struct ci13xxx *ci, unsigned event)
 {
 {
-	struct device *dev = udc->gadget.dev.parent;
+	struct device *dev = ci->gadget.dev.parent;
 	int val;
 	int val;
 
 
 	switch (event) {
 	switch (event) {
@@ -34,18 +34,18 @@ static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
 		 * Put the transceiver in non-driving mode. Otherwise host
 		 * Put the transceiver in non-driving mode. Otherwise host
 		 * may not detect soft-disconnection.
 		 * may not detect soft-disconnection.
 		 */
 		 */
-		val = usb_phy_io_read(udc->transceiver, ULPI_FUNC_CTRL);
+		val = usb_phy_io_read(ci->transceiver, ULPI_FUNC_CTRL);
 		val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
 		val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
 		val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
 		val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
-		usb_phy_io_write(udc->transceiver, val, ULPI_FUNC_CTRL);
+		usb_phy_io_write(ci->transceiver, val, ULPI_FUNC_CTRL);
 		break;
 		break;
 	default:
 	default:
-		dev_dbg(dev, "unknown ci13xxx_udc event\n");
+		dev_dbg(dev, "unknown ci13xxx event\n");
 		break;
 		break;
 	}
 	}
 }
 }
 
 
-static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = {
+static struct ci13xxx_platform_data ci13xxx_msm_platdata = {
 	.name			= "ci13xxx_msm",
 	.name			= "ci13xxx_msm",
 	.flags			= CI13XXX_REGS_SHARED |
 	.flags			= CI13XXX_REGS_SHARED |
 				  CI13XXX_REQUIRE_TRANSCEIVER |
 				  CI13XXX_REQUIRE_TRANSCEIVER |
@@ -55,56 +55,45 @@ static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = {
 	.notify_event		= ci13xxx_msm_notify_event,
 	.notify_event		= ci13xxx_msm_notify_event,
 };
 };
 
 
-static int ci13xxx_msm_probe(struct platform_device *pdev)
+static int __devinit ci13xxx_msm_probe(struct platform_device *pdev)
 {
 {
 	struct platform_device *plat_ci;
 	struct platform_device *plat_ci;
-	int ret;
 
 
 	dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
 	dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
 
 
-	plat_ci = platform_device_alloc("ci_hdrc", -1);
-	if (!plat_ci) {
-		dev_err(&pdev->dev, "can't allocate ci_hdrc platform device\n");
-		return -ENOMEM;
+	plat_ci = ci13xxx_add_device(&pdev->dev,
+				pdev->resource, pdev->num_resources,
+				&ci13xxx_msm_platdata);
+	if (IS_ERR(plat_ci)) {
+		dev_err(&pdev->dev, "ci13xxx_add_device failed!\n");
+		return PTR_ERR(plat_ci);
 	}
 	}
 
 
-	ret = platform_device_add_resources(plat_ci, pdev->resource,
-					    pdev->num_resources);
-	if (ret) {
-		dev_err(&pdev->dev, "can't add resources to platform device\n");
-		goto put_platform;
-	}
-
-	ret = platform_device_add_data(plat_ci, &ci13xxx_msm_udc_driver,
-				       sizeof(ci13xxx_msm_udc_driver));
-	if (ret)
-		goto put_platform;
-
-	ret = platform_device_add(plat_ci);
-	if (ret)
-		goto put_platform;
+	platform_set_drvdata(pdev, plat_ci);
 
 
 	pm_runtime_no_callbacks(&pdev->dev);
 	pm_runtime_no_callbacks(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 
 
 	return 0;
 	return 0;
+}
+
+static int __devexit ci13xxx_msm_remove(struct platform_device *pdev)
+{
+	struct platform_device *plat_ci = platform_get_drvdata(pdev);
 
 
-put_platform:
-	platform_device_put(plat_ci);
+	pm_runtime_disable(&pdev->dev);
+	ci13xxx_remove_device(plat_ci);
 
 
-	return ret;
+	return 0;
 }
 }
 
 
 static struct platform_driver ci13xxx_msm_driver = {
 static struct platform_driver ci13xxx_msm_driver = {
 	.probe = ci13xxx_msm_probe,
 	.probe = ci13xxx_msm_probe,
+	.remove = __devexit_p(ci13xxx_msm_remove),
 	.driver = { .name = "msm_hsusb", },
 	.driver = { .name = "msm_hsusb", },
 };
 };
-MODULE_ALIAS("platform:msm_hsusb");
 
 
-static int __init ci13xxx_msm_init(void)
-{
-	return platform_driver_register(&ci13xxx_msm_driver);
-}
-module_init(ci13xxx_msm_init);
+module_platform_driver(ci13xxx_msm_driver);
 
 
+MODULE_ALIAS("platform:msm_hsusb");
 MODULE_LICENSE("GPL v2");
 MODULE_LICENSE("GPL v2");

+ 15 - 37
drivers/usb/chipidea/ci13xxx_pci.c

@@ -23,17 +23,17 @@
 /******************************************************************************
 /******************************************************************************
  * PCI block
  * PCI block
  *****************************************************************************/
  *****************************************************************************/
-struct ci13xxx_udc_driver pci_driver = {
+struct ci13xxx_platform_data pci_platdata = {
 	.name		= UDC_DRIVER_NAME,
 	.name		= UDC_DRIVER_NAME,
 	.capoffset	= DEF_CAPOFFSET,
 	.capoffset	= DEF_CAPOFFSET,
 };
 };
 
 
-struct ci13xxx_udc_driver langwell_pci_driver = {
+struct ci13xxx_platform_data langwell_pci_platdata = {
 	.name		= UDC_DRIVER_NAME,
 	.name		= UDC_DRIVER_NAME,
 	.capoffset	= 0,
 	.capoffset	= 0,
 };
 };
 
 
-struct ci13xxx_udc_driver penwell_pci_driver = {
+struct ci13xxx_platform_data penwell_pci_platdata = {
 	.name		= UDC_DRIVER_NAME,
 	.name		= UDC_DRIVER_NAME,
 	.capoffset	= 0,
 	.capoffset	= 0,
 	.power_budget	= 200,
 	.power_budget	= 200,
@@ -51,12 +51,12 @@ struct ci13xxx_udc_driver penwell_pci_driver = {
 static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
 static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
 				       const struct pci_device_id *id)
 				       const struct pci_device_id *id)
 {
 {
-	struct ci13xxx_udc_driver *driver = (void *)id->driver_data;
+	struct ci13xxx_platform_data *platdata = (void *)id->driver_data;
 	struct platform_device *plat_ci;
 	struct platform_device *plat_ci;
 	struct resource res[3];
 	struct resource res[3];
 	int retval = 0, nres = 2;
 	int retval = 0, nres = 2;
 
 
-	if (!driver) {
+	if (!platdata) {
 		dev_err(&pdev->dev, "device doesn't provide driver data\n");
 		dev_err(&pdev->dev, "device doesn't provide driver data\n");
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
@@ -75,13 +75,6 @@ static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
 	pci_set_master(pdev);
 	pci_set_master(pdev);
 	pci_try_set_mwi(pdev);
 	pci_try_set_mwi(pdev);
 
 
-	plat_ci = platform_device_alloc("ci_hdrc", -1);
-	if (!plat_ci) {
-		dev_err(&pdev->dev, "can't allocate ci_hdrc platform device\n");
-		retval = -ENOMEM;
-		goto disable_device;
-	}
-
 	memset(res, 0, sizeof(res));
 	memset(res, 0, sizeof(res));
 	res[0].start	= pci_resource_start(pdev, 0);
 	res[0].start	= pci_resource_start(pdev, 0);
 	res[0].end	= pci_resource_end(pdev, 0);
 	res[0].end	= pci_resource_end(pdev, 0);
@@ -89,32 +82,17 @@ static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
 	res[1].start	= pdev->irq;
 	res[1].start	= pdev->irq;
 	res[1].flags	= IORESOURCE_IRQ;
 	res[1].flags	= IORESOURCE_IRQ;
 
 
-	retval = platform_device_add_resources(plat_ci, res, nres);
-	if (retval) {
-		dev_err(&pdev->dev, "can't add resources to platform device\n");
-		goto put_platform;
+	plat_ci = ci13xxx_add_device(&pdev->dev, res, nres, platdata);
+	if (IS_ERR(plat_ci)) {
+		dev_err(&pdev->dev, "ci13xxx_add_device failed!\n");
+		retval = PTR_ERR(plat_ci);
+		goto disable_device;
 	}
 	}
 
 
-	retval = platform_device_add_data(plat_ci, driver, sizeof(*driver));
-	if (retval)
-		goto put_platform;
-
-	dma_set_coherent_mask(&plat_ci->dev, pdev->dev.coherent_dma_mask);
-	plat_ci->dev.dma_mask = pdev->dev.dma_mask;
-	plat_ci->dev.dma_parms = pdev->dev.dma_parms;
-	plat_ci->dev.parent = &pdev->dev;
-
 	pci_set_drvdata(pdev, plat_ci);
 	pci_set_drvdata(pdev, plat_ci);
 
 
-	retval = platform_device_add(plat_ci);
-	if (retval)
-		goto put_platform;
-
 	return 0;
 	return 0;
 
 
- put_platform:
-	pci_set_drvdata(pdev, NULL);
-	platform_device_put(plat_ci);
  disable_device:
  disable_device:
 	pci_disable_device(pdev);
 	pci_disable_device(pdev);
  done:
  done:
@@ -133,7 +111,7 @@ static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev)
 {
 {
 	struct platform_device *plat_ci = pci_get_drvdata(pdev);
 	struct platform_device *plat_ci = pci_get_drvdata(pdev);
 
 
-	platform_device_unregister(plat_ci);
+	ci13xxx_remove_device(plat_ci);
 	pci_set_drvdata(pdev, NULL);
 	pci_set_drvdata(pdev, NULL);
 	pci_disable_device(pdev);
 	pci_disable_device(pdev);
 }
 }
@@ -147,19 +125,19 @@ static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev)
 static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = {
 static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = {
 	{
 	{
 		PCI_DEVICE(0x153F, 0x1004),
 		PCI_DEVICE(0x153F, 0x1004),
-		.driver_data = (kernel_ulong_t)&pci_driver,
+		.driver_data = (kernel_ulong_t)&pci_platdata,
 	},
 	},
 	{
 	{
 		PCI_DEVICE(0x153F, 0x1006),
 		PCI_DEVICE(0x153F, 0x1006),
-		.driver_data = (kernel_ulong_t)&pci_driver,
+		.driver_data = (kernel_ulong_t)&pci_platdata,
 	},
 	},
 	{
 	{
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0811),
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0811),
-		.driver_data = (kernel_ulong_t)&langwell_pci_driver,
+		.driver_data = (kernel_ulong_t)&langwell_pci_platdata,
 	},
 	},
 	{
 	{
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829),
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829),
-		.driver_data = (kernel_ulong_t)&penwell_pci_driver,
+		.driver_data = (kernel_ulong_t)&penwell_pci_platdata,
 	},
 	},
 	{ 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ }
 	{ 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ }
 };
 };

+ 64 - 6
drivers/usb/chipidea/core.c

@@ -56,6 +56,7 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/module.h>
 #include <linux/module.h>
+#include <linux/idr.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/irq.h>
@@ -179,7 +180,7 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
 	ci->hw_bank.abs = base;
 	ci->hw_bank.abs = base;
 
 
 	ci->hw_bank.cap = ci->hw_bank.abs;
 	ci->hw_bank.cap = ci->hw_bank.abs;
-	ci->hw_bank.cap += ci->udc_driver->capoffset;
+	ci->hw_bank.cap += ci->platdata->capoffset;
 	ci->hw_bank.op = ci->hw_bank.cap + ioread8(ci->hw_bank.cap);
 	ci->hw_bank.op = ci->hw_bank.cap + ioread8(ci->hw_bank.cap);
 
 
 	hw_alloc_regmap(ci, false);
 	hw_alloc_regmap(ci, false);
@@ -227,11 +228,11 @@ int hw_device_reset(struct ci13xxx *ci, u32 mode)
 		udelay(10);		/* not RTOS friendly */
 		udelay(10);		/* not RTOS friendly */
 
 
 
 
-	if (ci->udc_driver->notify_event)
-		ci->udc_driver->notify_event(ci,
+	if (ci->platdata->notify_event)
+		ci->platdata->notify_event(ci,
 			CI13XXX_CONTROLLER_RESET_EVENT);
 			CI13XXX_CONTROLLER_RESET_EVENT);
 
 
-	if (ci->udc_driver->flags & CI13XXX_DISABLE_STREAMING)
+	if (ci->platdata->flags & CI13XXX_DISABLE_STREAMING)
 		hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
 		hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
 
 
 	/* USBMODE should be configured step by step */
 	/* USBMODE should be configured step by step */
@@ -332,6 +333,59 @@ static irqreturn_t ci_irq(int irq, void *data)
 	return ci->role == CI_ROLE_END ? ret : ci_role(ci)->irq(ci);
 	return ci->role == CI_ROLE_END ? ret : ci_role(ci)->irq(ci);
 }
 }
 
 
+static DEFINE_IDA(ci_ida);
+
+struct platform_device *ci13xxx_add_device(struct device *dev,
+			struct resource *res, int nres,
+			struct ci13xxx_platform_data *platdata)
+{
+	struct platform_device *pdev;
+	int id, ret;
+
+	id = ida_simple_get(&ci_ida, 0, 0, GFP_KERNEL);
+	if (id < 0)
+		return ERR_PTR(id);
+
+	pdev = platform_device_alloc("ci_hdrc", id);
+	if (!pdev) {
+		ret = -ENOMEM;
+		goto put_id;
+	}
+
+	pdev->dev.parent = dev;
+	pdev->dev.dma_mask = dev->dma_mask;
+	pdev->dev.dma_parms = dev->dma_parms;
+	dma_set_coherent_mask(&pdev->dev, dev->coherent_dma_mask);
+
+	ret = platform_device_add_resources(pdev, res, nres);
+	if (ret)
+		goto err;
+
+	ret = platform_device_add_data(pdev, platdata, sizeof(*platdata));
+	if (ret)
+		goto err;
+
+	ret = platform_device_add(pdev);
+	if (ret)
+		goto err;
+
+	return pdev;
+
+err:
+	platform_device_put(pdev);
+put_id:
+	ida_simple_remove(&ci_ida, id);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(ci13xxx_add_device);
+
+void ci13xxx_remove_device(struct platform_device *pdev)
+{
+	platform_device_unregister(pdev);
+	ida_simple_remove(&ci_ida, pdev->id);
+}
+EXPORT_SYMBOL_GPL(ci13xxx_remove_device);
+
 static int __devinit ci_hdrc_probe(struct platform_device *pdev)
 static int __devinit ci_hdrc_probe(struct platform_device *pdev)
 {
 {
 	struct device	*dev = &pdev->dev;
 	struct device	*dev = &pdev->dev;
@@ -364,7 +418,11 @@ static int __devinit ci_hdrc_probe(struct platform_device *pdev)
 	}
 	}
 
 
 	ci->dev = dev;
 	ci->dev = dev;
-	ci->udc_driver = dev->platform_data;
+	ci->platdata = dev->platform_data;
+	if (ci->platdata->phy)
+		ci->transceiver = ci->platdata->phy;
+	else
+		ci->global_phy = true;
 
 
 	ret = hw_device_init(ci, base);
 	ret = hw_device_init(ci, base);
 	if (ret < 0) {
 	if (ret < 0) {
@@ -419,7 +477,7 @@ static int __devinit ci_hdrc_probe(struct platform_device *pdev)
 	}
 	}
 
 
 	platform_set_drvdata(pdev, ci);
 	platform_set_drvdata(pdev, ci);
-	ret = request_irq(ci->irq, ci_irq, IRQF_SHARED, ci->udc_driver->name,
+	ret = request_irq(ci->irq, ci_irq, IRQF_SHARED, ci->platdata->name,
 			  ci);
 			  ci);
 	if (ret)
 	if (ret)
 		goto stop;
 		goto stop;

+ 73 - 73
drivers/usb/chipidea/debug.c

@@ -68,15 +68,15 @@ void dbg_interrupt(u32 intmask)
  *
  *
  * This function returns number of registers read
  * This function returns number of registers read
  */
  */
-static size_t hw_register_read(struct ci13xxx *udc, u32 *buf, size_t size)
+static size_t hw_register_read(struct ci13xxx *ci, u32 *buf, size_t size)
 {
 {
 	unsigned i;
 	unsigned i;
 
 
-	if (size > udc->hw_bank.size)
-		size = udc->hw_bank.size;
+	if (size > ci->hw_bank.size)
+		size = ci->hw_bank.size;
 
 
 	for (i = 0; i < size; i++)
 	for (i = 0; i < size; i++)
-		buf[i] = hw_read(udc, i * sizeof(u32), ~0);
+		buf[i] = hw_read(ci, i * sizeof(u32), ~0);
 
 
 	return size;
 	return size;
 }
 }
@@ -88,18 +88,18 @@ static size_t hw_register_read(struct ci13xxx *udc, u32 *buf, size_t size)
  *
  *
  * This function returns an error code
  * This function returns an error code
  */
  */
-static int hw_register_write(struct ci13xxx *udc, u16 addr, u32 data)
+static int hw_register_write(struct ci13xxx *ci, u16 addr, u32 data)
 {
 {
 	/* align */
 	/* align */
 	addr /= sizeof(u32);
 	addr /= sizeof(u32);
 
 
-	if (addr >= udc->hw_bank.size)
+	if (addr >= ci->hw_bank.size)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	/* align */
 	/* align */
 	addr *= sizeof(u32);
 	addr *= sizeof(u32);
 
 
-	hw_write(udc, addr, ~0, data);
+	hw_write(ci, addr, ~0, data);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -110,13 +110,13 @@ static int hw_register_write(struct ci13xxx *udc, u16 addr, u32 data)
  *
  *
  * This function returns an error code
  * This function returns an error code
  */
  */
-static int hw_intr_clear(struct ci13xxx *udc, int n)
+static int hw_intr_clear(struct ci13xxx *ci, int n)
 {
 {
 	if (n >= REG_BITS)
 	if (n >= REG_BITS)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	hw_write(udc, OP_USBINTR, BIT(n), 0);
-	hw_write(udc, OP_USBSTS,  BIT(n), BIT(n));
+	hw_write(ci, OP_USBINTR, BIT(n), 0);
+	hw_write(ci, OP_USBSTS,  BIT(n), BIT(n));
 	return 0;
 	return 0;
 }
 }
 
 
@@ -127,15 +127,15 @@ static int hw_intr_clear(struct ci13xxx *udc, int n)
  *
  *
  * This function returns an error code
  * This function returns an error code
  */
  */
-static int hw_intr_force(struct ci13xxx *udc, int n)
+static int hw_intr_force(struct ci13xxx *ci, int n)
 {
 {
 	if (n >= REG_BITS)
 	if (n >= REG_BITS)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	hw_write(udc, CAP_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
-	hw_write(udc, OP_USBINTR,  BIT(n), BIT(n));
-	hw_write(udc, OP_USBSTS,   BIT(n), BIT(n));
-	hw_write(udc, CAP_TESTMODE, TESTMODE_FORCE, 0);
+	hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
+	hw_write(ci, OP_USBINTR,  BIT(n), BIT(n));
+	hw_write(ci, OP_USBSTS,   BIT(n), BIT(n));
+	hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, 0);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -147,12 +147,12 @@ static int hw_intr_force(struct ci13xxx *udc, int n)
 static ssize_t show_device(struct device *dev, struct device_attribute *attr,
 static ssize_t show_device(struct device *dev, struct device_attribute *attr,
 			   char *buf)
 			   char *buf)
 {
 {
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
-	struct usb_gadget *gadget = &udc->gadget;
+	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+	struct usb_gadget *gadget = &ci->gadget;
 	int n = 0;
 	int n = 0;
 
 
 	if (attr == NULL || buf == NULL) {
 	if (attr == NULL || buf == NULL) {
-		dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+		dev_err(ci->dev, "[%s] EINVAL\n", __func__);
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -188,8 +188,8 @@ static DEVICE_ATTR(device, S_IRUSR, show_device, NULL);
 static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
 static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
 			   char *buf)
 			   char *buf)
 {
 {
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
-	struct usb_gadget_driver *driver = udc->driver;
+	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+	struct usb_gadget_driver *driver = ci->driver;
 	int n = 0;
 	int n = 0;
 
 
 	if (attr == NULL || buf == NULL) {
 	if (attr == NULL || buf == NULL) {
@@ -412,22 +412,22 @@ static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events);
 static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
 static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
 			   char *buf)
 			   char *buf)
 {
 {
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
 	unsigned long flags;
 	unsigned long flags;
 	u32 intr;
 	u32 intr;
 	unsigned i, j, n = 0;
 	unsigned i, j, n = 0;
 
 
 	if (attr == NULL || buf == NULL) {
 	if (attr == NULL || buf == NULL) {
-		dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+		dev_err(ci->dev, "[%s] EINVAL\n", __func__);
 		return 0;
 		return 0;
 	}
 	}
 
 
-	spin_lock_irqsave(&udc->lock, flags);
+	spin_lock_irqsave(&ci->lock, flags);
 
 
 	/*n += scnprintf(buf + n, PAGE_SIZE - n,
 	/*n += scnprintf(buf + n, PAGE_SIZE - n,
-		       "status = %08x\n", hw_read_intr_status(udc));
+		       "status = %08x\n", hw_read_intr_status(ci));
 	n += scnprintf(buf + n, PAGE_SIZE - n,
 	n += scnprintf(buf + n, PAGE_SIZE - n,
-	"enable = %08x\n", hw_read_intr_enable(udc));*/
+	"enable = %08x\n", hw_read_intr_enable(ci));*/
 
 
 	n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
 	n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
 		       isr_statistics.test);
 		       isr_statistics.test);
@@ -471,7 +471,7 @@ static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
 			n += scnprintf(buf + n, PAGE_SIZE - n, "\n");
 			n += scnprintf(buf + n, PAGE_SIZE - n, "\n");
 	}
 	}
 
 
-	spin_unlock_irqrestore(&udc->lock, flags);
+	spin_unlock_irqrestore(&ci->lock, flags);
 
 
 	return n;
 	return n;
 }
 }
@@ -485,31 +485,31 @@ static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
 static ssize_t store_inters(struct device *dev, struct device_attribute *attr,
 static ssize_t store_inters(struct device *dev, struct device_attribute *attr,
 			    const char *buf, size_t count)
 			    const char *buf, size_t count)
 {
 {
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
 	unsigned long flags;
 	unsigned long flags;
 	unsigned en, bit;
 	unsigned en, bit;
 
 
 	if (attr == NULL || buf == NULL) {
 	if (attr == NULL || buf == NULL) {
-		dev_err(udc->dev, "EINVAL\n");
+		dev_err(ci->dev, "EINVAL\n");
 		goto done;
 		goto done;
 	}
 	}
 
 
 	if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) {
 	if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) {
-		dev_err(udc->dev, "<1|0> <bit>: enable|disable interrupt\n");
+		dev_err(ci->dev, "<1|0> <bit>: enable|disable interrupt\n");
 		goto done;
 		goto done;
 	}
 	}
 
 
-	spin_lock_irqsave(&udc->lock, flags);
+	spin_lock_irqsave(&ci->lock, flags);
 	if (en) {
 	if (en) {
-		if (hw_intr_force(udc, bit))
+		if (hw_intr_force(ci, bit))
 			dev_err(dev, "invalid bit number\n");
 			dev_err(dev, "invalid bit number\n");
 		else
 		else
 			isr_statistics.test++;
 			isr_statistics.test++;
 	} else {
 	} else {
-		if (hw_intr_clear(udc, bit))
+		if (hw_intr_clear(ci, bit))
 			dev_err(dev, "invalid bit number\n");
 			dev_err(dev, "invalid bit number\n");
 	}
 	}
-	spin_unlock_irqrestore(&udc->lock, flags);
+	spin_unlock_irqrestore(&ci->lock, flags);
 
 
  done:
  done:
 	return count;
 	return count;
@@ -524,18 +524,18 @@ static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters);
 static ssize_t show_port_test(struct device *dev,
 static ssize_t show_port_test(struct device *dev,
 			      struct device_attribute *attr, char *buf)
 			      struct device_attribute *attr, char *buf)
 {
 {
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
 	unsigned long flags;
 	unsigned long flags;
 	unsigned mode;
 	unsigned mode;
 
 
 	if (attr == NULL || buf == NULL) {
 	if (attr == NULL || buf == NULL) {
-		dev_err(udc->dev, "EINVAL\n");
+		dev_err(ci->dev, "EINVAL\n");
 		return 0;
 		return 0;
 	}
 	}
 
 
-	spin_lock_irqsave(&udc->lock, flags);
-	mode = hw_port_test_get(udc);
-	spin_unlock_irqrestore(&udc->lock, flags);
+	spin_lock_irqsave(&ci->lock, flags);
+	mode = hw_port_test_get(ci);
+	spin_unlock_irqrestore(&ci->lock, flags);
 
 
 	return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode);
 	return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode);
 }
 }
@@ -549,24 +549,24 @@ static ssize_t store_port_test(struct device *dev,
 			       struct device_attribute *attr,
 			       struct device_attribute *attr,
 			       const char *buf, size_t count)
 			       const char *buf, size_t count)
 {
 {
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
 	unsigned long flags;
 	unsigned long flags;
 	unsigned mode;
 	unsigned mode;
 
 
 	if (attr == NULL || buf == NULL) {
 	if (attr == NULL || buf == NULL) {
-		dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+		dev_err(ci->dev, "[%s] EINVAL\n", __func__);
 		goto done;
 		goto done;
 	}
 	}
 
 
 	if (sscanf(buf, "%u", &mode) != 1) {
 	if (sscanf(buf, "%u", &mode) != 1) {
-		dev_err(udc->dev, "<mode>: set port test mode");
+		dev_err(ci->dev, "<mode>: set port test mode");
 		goto done;
 		goto done;
 	}
 	}
 
 
-	spin_lock_irqsave(&udc->lock, flags);
-	if (hw_port_test_set(udc, mode))
-		dev_err(udc->dev, "invalid mode\n");
-	spin_unlock_irqrestore(&udc->lock, flags);
+	spin_lock_irqsave(&ci->lock, flags);
+	if (hw_port_test_set(ci, mode))
+		dev_err(ci->dev, "invalid mode\n");
+	spin_unlock_irqrestore(&ci->lock, flags);
 
 
  done:
  done:
 	return count;
 	return count;
@@ -582,20 +582,20 @@ static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR,
 static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
 static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
 			   char *buf)
 			   char *buf)
 {
 {
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
 	unsigned long flags;
 	unsigned long flags;
 	unsigned i, j, n = 0;
 	unsigned i, j, n = 0;
 
 
 	if (attr == NULL || buf == NULL) {
 	if (attr == NULL || buf == NULL) {
-		dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+		dev_err(ci->dev, "[%s] EINVAL\n", __func__);
 		return 0;
 		return 0;
 	}
 	}
 
 
-	spin_lock_irqsave(&udc->lock, flags);
-	for (i = 0; i < udc->hw_ep_max/2; i++) {
-		struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i];
+	spin_lock_irqsave(&ci->lock, flags);
+	for (i = 0; i < ci->hw_ep_max/2; i++) {
+		struct ci13xxx_ep *mEpRx = &ci->ci13xxx_ep[i];
 		struct ci13xxx_ep *mEpTx =
 		struct ci13xxx_ep *mEpTx =
-			&udc->ci13xxx_ep[i + udc->hw_ep_max/2];
+			&ci->ci13xxx_ep[i + ci->hw_ep_max/2];
 		n += scnprintf(buf + n, PAGE_SIZE - n,
 		n += scnprintf(buf + n, PAGE_SIZE - n,
 			       "EP=%02i: RX=%08X TX=%08X\n",
 			       "EP=%02i: RX=%08X TX=%08X\n",
 			       i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
 			       i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
@@ -606,7 +606,7 @@ static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
 				       *((u32 *)mEpTx->qh.ptr + j));
 				       *((u32 *)mEpTx->qh.ptr + j));
 		}
 		}
 	}
 	}
-	spin_unlock_irqrestore(&udc->lock, flags);
+	spin_unlock_irqrestore(&ci->lock, flags);
 
 
 	return n;
 	return n;
 }
 }
@@ -621,25 +621,25 @@ static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
 static ssize_t show_registers(struct device *dev,
 static ssize_t show_registers(struct device *dev,
 			      struct device_attribute *attr, char *buf)
 			      struct device_attribute *attr, char *buf)
 {
 {
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
 	unsigned long flags;
 	unsigned long flags;
 	u32 *dump;
 	u32 *dump;
 	unsigned i, k, n = 0;
 	unsigned i, k, n = 0;
 
 
 	if (attr == NULL || buf == NULL) {
 	if (attr == NULL || buf == NULL) {
-		dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+		dev_err(ci->dev, "[%s] EINVAL\n", __func__);
 		return 0;
 		return 0;
 	}
 	}
 
 
 	dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
 	dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
 	if (!dump) {
 	if (!dump) {
-		dev_err(udc->dev, "%s: out of memory\n", __func__);
+		dev_err(ci->dev, "%s: out of memory\n", __func__);
 		return 0;
 		return 0;
 	}
 	}
 
 
-	spin_lock_irqsave(&udc->lock, flags);
-	k = hw_register_read(udc, dump, DUMP_ENTRIES);
-	spin_unlock_irqrestore(&udc->lock, flags);
+	spin_lock_irqsave(&ci->lock, flags);
+	k = hw_register_read(ci, dump, DUMP_ENTRIES);
+	spin_unlock_irqrestore(&ci->lock, flags);
 
 
 	for (i = 0; i < k; i++) {
 	for (i = 0; i < k; i++) {
 		n += scnprintf(buf + n, PAGE_SIZE - n,
 		n += scnprintf(buf + n, PAGE_SIZE - n,
@@ -660,24 +660,24 @@ static ssize_t store_registers(struct device *dev,
 			       struct device_attribute *attr,
 			       struct device_attribute *attr,
 			       const char *buf, size_t count)
 			       const char *buf, size_t count)
 {
 {
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
 	unsigned long addr, data, flags;
 	unsigned long addr, data, flags;
 
 
 	if (attr == NULL || buf == NULL) {
 	if (attr == NULL || buf == NULL) {
-		dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+		dev_err(ci->dev, "[%s] EINVAL\n", __func__);
 		goto done;
 		goto done;
 	}
 	}
 
 
 	if (sscanf(buf, "%li %li", &addr, &data) != 2) {
 	if (sscanf(buf, "%li %li", &addr, &data) != 2) {
-		dev_err(udc->dev,
+		dev_err(ci->dev,
 			"<addr> <data>: write data to register address\n");
 			"<addr> <data>: write data to register address\n");
 		goto done;
 		goto done;
 	}
 	}
 
 
-	spin_lock_irqsave(&udc->lock, flags);
-	if (hw_register_write(udc, addr, data))
-		dev_err(udc->dev, "invalid address range\n");
-	spin_unlock_irqrestore(&udc->lock, flags);
+	spin_lock_irqsave(&ci->lock, flags);
+	if (hw_register_write(ci, addr, data))
+		dev_err(ci->dev, "invalid address range\n");
+	spin_unlock_irqrestore(&ci->lock, flags);
 
 
  done:
  done:
 	return count;
 	return count;
@@ -693,34 +693,34 @@ static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR,
 static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
 static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
 			     char *buf)
 			     char *buf)
 {
 {
-	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
 	unsigned long flags;
 	unsigned long flags;
 	struct list_head   *ptr = NULL;
 	struct list_head   *ptr = NULL;
 	struct ci13xxx_req *req = NULL;
 	struct ci13xxx_req *req = NULL;
 	unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
 	unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
 
 
 	if (attr == NULL || buf == NULL) {
 	if (attr == NULL || buf == NULL) {
-		dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+		dev_err(ci->dev, "[%s] EINVAL\n", __func__);
 		return 0;
 		return 0;
 	}
 	}
 
 
-	spin_lock_irqsave(&udc->lock, flags);
-	for (i = 0; i < udc->hw_ep_max; i++)
-		list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue)
+	spin_lock_irqsave(&ci->lock, flags);
+	for (i = 0; i < ci->hw_ep_max; i++)
+		list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue)
 		{
 		{
 			req = list_entry(ptr, struct ci13xxx_req, queue);
 			req = list_entry(ptr, struct ci13xxx_req, queue);
 
 
 			n += scnprintf(buf + n, PAGE_SIZE - n,
 			n += scnprintf(buf + n, PAGE_SIZE - n,
 					"EP=%02i: TD=%08X %s\n",
 					"EP=%02i: TD=%08X %s\n",
-					i % udc->hw_ep_max/2, (u32)req->dma,
-					((i < udc->hw_ep_max/2) ? "RX" : "TX"));
+					i % ci->hw_ep_max/2, (u32)req->dma,
+					((i < ci->hw_ep_max/2) ? "RX" : "TX"));
 
 
 			for (j = 0; j < qSize; j++)
 			for (j = 0; j < qSize; j++)
 				n += scnprintf(buf + n, PAGE_SIZE - n,
 				n += scnprintf(buf + n, PAGE_SIZE - n,
 						" %04X:    %08X\n", j,
 						" %04X:    %08X\n", j,
 						*((u32 *)req->ptr + j));
 						*((u32 *)req->ptr + j));
 		}
 		}
-	spin_unlock_irqrestore(&udc->lock, flags);
+	spin_unlock_irqrestore(&ci->lock, flags);
 
 
 	return n;
 	return n;
 }
 }

+ 2 - 1
drivers/usb/chipidea/host.c

@@ -116,7 +116,8 @@ static int host_start(struct ci13xxx *ci)
 	hcd->regs = ci->hw_bank.abs;
 	hcd->regs = ci->hw_bank.abs;
 	hcd->has_tt = 1;
 	hcd->has_tt = 1;
 
 
-	hcd->power_budget = ci->udc_driver->power_budget;
+	hcd->power_budget = ci->platdata->power_budget;
+	hcd->phy = ci->transceiver;
 
 
 	ehci = hcd_to_ehci(hcd);
 	ehci = hcd_to_ehci(hcd);
 	ehci->caps = ci->hw_bank.cap;
 	ehci->caps = ci->hw_bank.cap;

Разлика између датотеке није приказан због своје велике величине
+ 201 - 200
drivers/usb/chipidea/udc.c


+ 1 - 1
drivers/usb/class/cdc-acm.c

@@ -996,7 +996,7 @@ static int acm_probe(struct usb_interface *intf,
 		case USB_CDC_CALL_MANAGEMENT_TYPE:
 		case USB_CDC_CALL_MANAGEMENT_TYPE:
 			call_management_function = buffer[3];
 			call_management_function = buffer[3];
 			call_interface_num = buffer[4];
 			call_interface_num = buffer[4];
-			if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3)
+			if ((quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3)
 				dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
 				dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
 			break;
 			break;
 		default:
 		default:

+ 0 - 25
drivers/usb/class/cdc-wdm.c

@@ -32,8 +32,6 @@
 #define DRIVER_AUTHOR "Oliver Neukum"
 #define DRIVER_AUTHOR "Oliver Neukum"
 #define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management"
 #define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management"
 
 
-#define HUAWEI_VENDOR_ID	0x12D1
-
 static const struct usb_device_id wdm_ids[] = {
 static const struct usb_device_id wdm_ids[] = {
 	{
 	{
 		.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
 		.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
@@ -41,29 +39,6 @@ static const struct usb_device_id wdm_ids[] = {
 		.bInterfaceClass = USB_CLASS_COMM,
 		.bInterfaceClass = USB_CLASS_COMM,
 		.bInterfaceSubClass = USB_CDC_SUBCLASS_DMM
 		.bInterfaceSubClass = USB_CDC_SUBCLASS_DMM
 	},
 	},
-	{
-		/* 
-		 * Huawei E392, E398 and possibly other Qualcomm based modems
-		 * embed the Qualcomm QMI protocol inside CDC on CDC ECM like
-		 * control interfaces.  Userspace access to this is required
-		 * to configure the accompanying data interface
-		 */
-		.match_flags        = USB_DEVICE_ID_MATCH_VENDOR |
-					USB_DEVICE_ID_MATCH_INT_INFO,
-		.idVendor           = HUAWEI_VENDOR_ID,
-		.bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
-		.bInterfaceSubClass = 1,
-		.bInterfaceProtocol = 9, /* NOTE: CDC ECM control interface! */
-	},
-	{
-		 /* Vodafone/Huawei K5005 (12d1:14c8) and similar modems */
-		.match_flags        = USB_DEVICE_ID_MATCH_VENDOR |
-				      USB_DEVICE_ID_MATCH_INT_INFO,
-		.idVendor           = HUAWEI_VENDOR_ID,
-		.bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
-		.bInterfaceSubClass = 1,
-		.bInterfaceProtocol = 57, /* NOTE: CDC ECM control interface! */
-	},
 	{ }
 	{ }
 };
 };
 
 

+ 140 - 29
drivers/usb/core/devio.c

@@ -47,6 +47,7 @@
 #include <linux/notifier.h>
 #include <linux/notifier.h>
 #include <linux/security.h>
 #include <linux/security.h>
 #include <linux/user_namespace.h>
 #include <linux/user_namespace.h>
+#include <linux/scatterlist.h>
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 #include <asm/byteorder.h>
 #include <linux/moduleparam.h>
 #include <linux/moduleparam.h>
@@ -55,6 +56,7 @@
 
 
 #define USB_MAXBUS			64
 #define USB_MAXBUS			64
 #define USB_DEVICE_MAX			USB_MAXBUS * 128
 #define USB_DEVICE_MAX			USB_MAXBUS * 128
+#define USB_SG_SIZE			16384 /* split-size for large txs */
 
 
 /* Mutual exclusion for removal, open, and release */
 /* Mutual exclusion for removal, open, and release */
 DEFINE_MUTEX(usbfs_mutex);
 DEFINE_MUTEX(usbfs_mutex);
@@ -285,9 +287,16 @@ static struct async *alloc_async(unsigned int numisoframes)
 
 
 static void free_async(struct async *as)
 static void free_async(struct async *as)
 {
 {
+	int i;
+
 	put_pid(as->pid);
 	put_pid(as->pid);
 	if (as->cred)
 	if (as->cred)
 		put_cred(as->cred);
 		put_cred(as->cred);
+	for (i = 0; i < as->urb->num_sgs; i++) {
+		if (sg_page(&as->urb->sg[i]))
+			kfree(sg_virt(&as->urb->sg[i]));
+	}
+	kfree(as->urb->sg);
 	kfree(as->urb->transfer_buffer);
 	kfree(as->urb->transfer_buffer);
 	kfree(as->urb->setup_packet);
 	kfree(as->urb->setup_packet);
 	usb_free_urb(as->urb);
 	usb_free_urb(as->urb);
@@ -388,6 +397,53 @@ static void snoop_urb(struct usb_device *udev,
 	}
 	}
 }
 }
 
 
+static void snoop_urb_data(struct urb *urb, unsigned len)
+{
+	int i, size;
+
+	if (!usbfs_snoop)
+		return;
+
+	if (urb->num_sgs == 0) {
+		print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
+			urb->transfer_buffer, len, 1);
+		return;
+	}
+
+	for (i = 0; i < urb->num_sgs && len; i++) {
+		size = (len > USB_SG_SIZE) ? USB_SG_SIZE : len;
+		print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
+			sg_virt(&urb->sg[i]), size, 1);
+		len -= size;
+	}
+}
+
+static int copy_urb_data_to_user(u8 __user *userbuffer, struct urb *urb)
+{
+	unsigned i, len, size;
+
+	if (urb->number_of_packets > 0)		/* Isochronous */
+		len = urb->transfer_buffer_length;
+	else					/* Non-Isoc */
+		len = urb->actual_length;
+
+	if (urb->num_sgs == 0) {
+		if (copy_to_user(userbuffer, urb->transfer_buffer, len))
+			return -EFAULT;
+		return 0;
+	}
+
+	for (i = 0; i < urb->num_sgs && len; i++) {
+		size = (len > USB_SG_SIZE) ? USB_SG_SIZE : len;
+		if (copy_to_user(userbuffer, sg_virt(&urb->sg[i]), size))
+			return -EFAULT;
+		userbuffer += size;
+		len -= size;
+	}
+
+	return 0;
+}
+
 #define AS_CONTINUATION	1
 #define AS_CONTINUATION	1
 #define AS_UNLINK	2
 #define AS_UNLINK	2
 
 
@@ -454,9 +510,10 @@ static void async_completed(struct urb *urb)
 	}
 	}
 	snoop(&urb->dev->dev, "urb complete\n");
 	snoop(&urb->dev->dev, "urb complete\n");
 	snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
 	snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
-			as->status, COMPLETE,
-			((urb->transfer_flags & URB_DIR_MASK) == USB_DIR_OUT) ?
-				NULL : urb->transfer_buffer, urb->actual_length);
+			as->status, COMPLETE, NULL, 0);
+	if ((urb->transfer_flags & URB_DIR_MASK) == USB_DIR_IN)
+		snoop_urb_data(urb, urb->actual_length);
+
 	if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
 	if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
 			as->status != -ENOENT)
 			as->status != -ENOENT)
 		cancel_bulk_urbs(ps, as->bulk_addr);
 		cancel_bulk_urbs(ps, as->bulk_addr);
@@ -1114,8 +1171,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 	struct async *as = NULL;
 	struct async *as = NULL;
 	struct usb_ctrlrequest *dr = NULL;
 	struct usb_ctrlrequest *dr = NULL;
 	unsigned int u, totlen, isofrmlen;
 	unsigned int u, totlen, isofrmlen;
-	int ret, ifnum = -1;
-	int is_in;
+	int i, ret, is_in, num_sgs = 0, ifnum = -1;
+	void *buf;
 
 
 	if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP |
 	if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP |
 				USBDEVFS_URB_SHORT_NOT_OK |
 				USBDEVFS_URB_SHORT_NOT_OK |
@@ -1199,6 +1256,9 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 			goto interrupt_urb;
 			goto interrupt_urb;
 		}
 		}
 		uurb->number_of_packets = 0;
 		uurb->number_of_packets = 0;
+		num_sgs = DIV_ROUND_UP(uurb->buffer_length, USB_SG_SIZE);
+		if (num_sgs == 1 || num_sgs > ps->dev->bus->sg_tablesize)
+			num_sgs = 0;
 		break;
 		break;
 
 
 	case USBDEVFS_URB_TYPE_INTERRUPT:
 	case USBDEVFS_URB_TYPE_INTERRUPT:
@@ -1255,26 +1315,67 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 		ret = -ENOMEM;
 		ret = -ENOMEM;
 		goto error;
 		goto error;
 	}
 	}
-	u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length;
+
+	u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length +
+	     num_sgs * sizeof(struct scatterlist);
 	ret = usbfs_increase_memory_usage(u);
 	ret = usbfs_increase_memory_usage(u);
 	if (ret)
 	if (ret)
 		goto error;
 		goto error;
 	as->mem_usage = u;
 	as->mem_usage = u;
 
 
-	if (uurb->buffer_length > 0) {
+	if (num_sgs) {
+		as->urb->sg = kmalloc(num_sgs * sizeof(struct scatterlist),
+				      GFP_KERNEL);
+		if (!as->urb->sg) {
+			ret = -ENOMEM;
+			goto error;
+		}
+		as->urb->num_sgs = num_sgs;
+		sg_init_table(as->urb->sg, as->urb->num_sgs);
+
+		totlen = uurb->buffer_length;
+		for (i = 0; i < as->urb->num_sgs; i++) {
+			u = (totlen > USB_SG_SIZE) ? USB_SG_SIZE : totlen;
+			buf = kmalloc(u, GFP_KERNEL);
+			if (!buf) {
+				ret = -ENOMEM;
+				goto error;
+			}
+			sg_set_buf(&as->urb->sg[i], buf, u);
+
+			if (!is_in) {
+				if (copy_from_user(buf, uurb->buffer, u)) {
+					ret = -EFAULT;
+					goto error;
+				}
+			}
+			totlen -= u;
+		}
+	} else if (uurb->buffer_length > 0) {
 		as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
 		as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
 				GFP_KERNEL);
 				GFP_KERNEL);
 		if (!as->urb->transfer_buffer) {
 		if (!as->urb->transfer_buffer) {
 			ret = -ENOMEM;
 			ret = -ENOMEM;
 			goto error;
 			goto error;
 		}
 		}
-		/* Isochronous input data may end up being discontiguous
-		 * if some of the packets are short.  Clear the buffer so
-		 * that the gaps don't leak kernel data to userspace.
-		 */
-		if (is_in && uurb->type == USBDEVFS_URB_TYPE_ISO)
+
+		if (!is_in) {
+			if (copy_from_user(as->urb->transfer_buffer,
+					   uurb->buffer,
+					   uurb->buffer_length)) {
+				ret = -EFAULT;
+				goto error;
+			}
+		} else if (uurb->type == USBDEVFS_URB_TYPE_ISO) {
+			/*
+			 * Isochronous input data may end up being
+			 * discontiguous if some of the packets are short.
+			 * Clear the buffer so that the gaps don't leak
+			 * kernel data to userspace.
+			 */
 			memset(as->urb->transfer_buffer, 0,
 			memset(as->urb->transfer_buffer, 0,
 					uurb->buffer_length);
 					uurb->buffer_length);
+		}
 	}
 	}
 	as->urb->dev = ps->dev;
 	as->urb->dev = ps->dev;
 	as->urb->pipe = (uurb->type << 30) |
 	as->urb->pipe = (uurb->type << 30) |
@@ -1328,17 +1429,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 	as->pid = get_pid(task_pid(current));
 	as->pid = get_pid(task_pid(current));
 	as->cred = get_current_cred();
 	as->cred = get_current_cred();
 	security_task_getsecid(current, &as->secid);
 	security_task_getsecid(current, &as->secid);
-	if (!is_in && uurb->buffer_length > 0) {
-		if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
-				uurb->buffer_length)) {
-			ret = -EFAULT;
-			goto error;
-		}
-	}
 	snoop_urb(ps->dev, as->userurb, as->urb->pipe,
 	snoop_urb(ps->dev, as->userurb, as->urb->pipe,
 			as->urb->transfer_buffer_length, 0, SUBMIT,
 			as->urb->transfer_buffer_length, 0, SUBMIT,
-			is_in ? NULL : as->urb->transfer_buffer,
-				uurb->buffer_length);
+			NULL, 0);
+	if (!is_in)
+		snoop_urb_data(as->urb, as->urb->transfer_buffer_length);
+
 	async_newpending(as);
 	async_newpending(as);
 
 
 	if (usb_endpoint_xfer_bulk(&ep->desc)) {
 	if (usb_endpoint_xfer_bulk(&ep->desc)) {
@@ -1433,11 +1529,7 @@ static int processcompl(struct async *as, void __user * __user *arg)
 	unsigned int i;
 	unsigned int i;
 
 
 	if (as->userbuffer && urb->actual_length) {
 	if (as->userbuffer && urb->actual_length) {
-		if (urb->number_of_packets > 0)		/* Isochronous */
-			i = urb->transfer_buffer_length;
-		else					/* Non-Isoc */
-			i = urb->actual_length;
-		if (copy_to_user(as->userbuffer, urb->transfer_buffer, i))
+		if (copy_urb_data_to_user(as->userbuffer, urb))
 			goto err_out;
 			goto err_out;
 	}
 	}
 	if (put_user(as->status, &userurb->status))
 	if (put_user(as->status, &userurb->status))
@@ -1604,10 +1696,10 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
 	void __user *addr = as->userurb;
 	void __user *addr = as->userurb;
 	unsigned int i;
 	unsigned int i;
 
 
-	if (as->userbuffer && urb->actual_length)
-		if (copy_to_user(as->userbuffer, urb->transfer_buffer,
-				 urb->actual_length))
+	if (as->userbuffer && urb->actual_length) {
+		if (copy_urb_data_to_user(as->userbuffer, urb))
 			return -EFAULT;
 			return -EFAULT;
+	}
 	if (put_user(as->status, &userurb->status))
 	if (put_user(as->status, &userurb->status))
 		return -EFAULT;
 		return -EFAULT;
 	if (put_user(urb->actual_length, &userurb->actual_length))
 	if (put_user(urb->actual_length, &userurb->actual_length))
@@ -1820,6 +1912,22 @@ static int proc_release_port(struct dev_state *ps, void __user *arg)
 	return usb_hub_release_port(ps->dev, portnum, ps);
 	return usb_hub_release_port(ps->dev, portnum, ps);
 }
 }
 
 
+static int proc_get_capabilities(struct dev_state *ps, void __user *arg)
+{
+	__u32 caps;
+
+	caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM;
+	if (!ps->dev->bus->no_stop_on_short)
+		caps |= USBDEVFS_CAP_BULK_CONTINUATION;
+	if (ps->dev->bus->sg_tablesize)
+		caps |= USBDEVFS_CAP_BULK_SCATTER_GATHER;
+
+	if (put_user(caps, (__u32 __user *)arg))
+		return -EFAULT;
+
+	return 0;
+}
+
 /*
 /*
  * NOTE:  All requests here that have interface numbers as parameters
  * NOTE:  All requests here that have interface numbers as parameters
  * are assuming that somehow the configuration has been prevented from
  * are assuming that somehow the configuration has been prevented from
@@ -1990,6 +2098,9 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
 		snoop(&dev->dev, "%s: RELEASE_PORT\n", __func__);
 		snoop(&dev->dev, "%s: RELEASE_PORT\n", __func__);
 		ret = proc_release_port(ps, p);
 		ret = proc_release_port(ps, p);
 		break;
 		break;
+	case USBDEVFS_GET_CAPABILITIES:
+		ret = proc_get_capabilities(ps, p);
+		break;
 	}
 	}
 	usb_unlock_device(dev);
 	usb_unlock_device(dev);
 	if (ret >= 0)
 	if (ret >= 0)

+ 31 - 17
drivers/usb/core/driver.c

@@ -367,6 +367,7 @@ static int usb_probe_interface(struct device *dev)
 	return error;
 	return error;
 
 
  err:
  err:
+	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);
 	usb_cancel_queued_reset(intf);
@@ -606,30 +607,19 @@ int usb_match_device(struct usb_device *dev, const struct usb_device_id *id)
 }
 }
 
 
 /* returns 0 if no match, 1 if match */
 /* returns 0 if no match, 1 if match */
-int usb_match_one_id(struct usb_interface *interface,
-		     const struct usb_device_id *id)
+int usb_match_one_id_intf(struct usb_device *dev,
+			  struct usb_host_interface *intf,
+			  const struct usb_device_id *id)
 {
 {
-	struct usb_host_interface *intf;
-	struct usb_device *dev;
-
-	/* proc_connectinfo in devio.c may call us with id == NULL. */
-	if (id == NULL)
-		return 0;
-
-	intf = interface->cur_altsetting;
-	dev = interface_to_usbdev(interface);
-
-	if (!usb_match_device(dev, id))
-		return 0;
-
-	/* The interface class, subclass, and protocol should never be
+	/* The interface class, subclass, protocol and number should never be
 	 * checked for a match if the device class is Vendor Specific,
 	 * checked for a match if the device class is Vendor Specific,
 	 * unless the match record specifies the Vendor ID. */
 	 * unless the match record specifies the Vendor ID. */
 	if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC &&
 	if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC &&
 			!(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
 			!(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
 			(id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |
 			(id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |
 				USB_DEVICE_ID_MATCH_INT_SUBCLASS |
 				USB_DEVICE_ID_MATCH_INT_SUBCLASS |
-				USB_DEVICE_ID_MATCH_INT_PROTOCOL)))
+				USB_DEVICE_ID_MATCH_INT_PROTOCOL |
+				USB_DEVICE_ID_MATCH_INT_NUMBER)))
 		return 0;
 		return 0;
 
 
 	if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
 	if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
@@ -644,8 +634,32 @@ int usb_match_one_id(struct usb_interface *interface,
 	    (id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
 	    (id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
 		return 0;
 		return 0;
 
 
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) &&
+	    (id->bInterfaceNumber != intf->desc.bInterfaceNumber))
+		return 0;
+
 	return 1;
 	return 1;
 }
 }
+
+/* returns 0 if no match, 1 if match */
+int usb_match_one_id(struct usb_interface *interface,
+		     const struct usb_device_id *id)
+{
+	struct usb_host_interface *intf;
+	struct usb_device *dev;
+
+	/* proc_connectinfo in devio.c may call us with id == NULL. */
+	if (id == NULL)
+		return 0;
+
+	intf = interface->cur_altsetting;
+	dev = interface_to_usbdev(interface);
+
+	if (!usb_match_device(dev, id))
+		return 0;
+
+	return usb_match_one_id_intf(dev, intf, id);
+}
 EXPORT_SYMBOL_GPL(usb_match_one_id);
 EXPORT_SYMBOL_GPL(usb_match_one_id);
 
 
 /**
 /**

+ 1 - 1
drivers/usb/core/file.c

@@ -92,7 +92,7 @@ static int init_usb_class(void)
 	}
 	}
 
 
 	kref_init(&usb_class->kref);
 	kref_init(&usb_class->kref);
-	usb_class->class = class_create(THIS_MODULE, "usb");
+	usb_class->class = class_create(THIS_MODULE, "usbmisc");
 	if (IS_ERR(usb_class->class)) {
 	if (IS_ERR(usb_class->class)) {
 		result = IS_ERR(usb_class->class);
 		result = IS_ERR(usb_class->class);
 		printk(KERN_ERR "class_create failed for usb devices\n");
 		printk(KERN_ERR "class_create failed for usb devices\n");

+ 9 - 1
drivers/usb/core/hcd.c

@@ -1398,7 +1398,15 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
 	    && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
 	    && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
 		if (hcd->self.uses_dma) {
 		if (hcd->self.uses_dma) {
 			if (urb->num_sgs) {
 			if (urb->num_sgs) {
-				int n = dma_map_sg(
+				int n;
+
+				/* We don't support sg for isoc transfers ! */
+				if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
+					WARN_ON(1);
+					return -EINVAL;
+				}
+
+				n = dma_map_sg(
 						hcd->self.controller,
 						hcd->self.controller,
 						urb->sg,
 						urb->sg,
 						urb->num_sgs,
 						urb->num_sgs,

+ 110 - 29
drivers/usb/core/hub.c

@@ -20,6 +20,7 @@
 #include <linux/usb.h>
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/usb/hcd.h>
 #include <linux/usb/hcd.h>
+#include <linux/usb/otg.h>
 #include <linux/usb/quirks.h>
 #include <linux/usb/quirks.h>
 #include <linux/kthread.h>
 #include <linux/kthread.h>
 #include <linux/mutex.h>
 #include <linux/mutex.h>
@@ -81,7 +82,7 @@ struct usb_hub {
 	u8			indicator[USB_MAXCHILDREN];
 	u8			indicator[USB_MAXCHILDREN];
 	struct delayed_work	leds;
 	struct delayed_work	leds;
 	struct delayed_work	init_work;
 	struct delayed_work	init_work;
-	void			**port_owners;
+	struct dev_state	**port_owners;
 };
 };
 
 
 static inline int hub_is_superspeed(struct usb_device *hdev)
 static inline int hub_is_superspeed(struct usb_device *hdev)
@@ -1271,7 +1272,8 @@ static int hub_configure(struct usb_hub *hub,
 
 
 	hdev->children = kzalloc(hdev->maxchild *
 	hdev->children = kzalloc(hdev->maxchild *
 				sizeof(struct usb_device *), GFP_KERNEL);
 				sizeof(struct usb_device *), GFP_KERNEL);
-	hub->port_owners = kzalloc(hdev->maxchild * sizeof(void *), GFP_KERNEL);
+	hub->port_owners = kzalloc(hdev->maxchild * sizeof(struct dev_state *),
+				GFP_KERNEL);
 	if (!hdev->children || !hub->port_owners) {
 	if (!hdev->children || !hub->port_owners) {
 		ret = -ENOMEM;
 		ret = -ENOMEM;
 		goto fail;
 		goto fail;
@@ -1649,7 +1651,7 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
  * to one of these "claimed" ports, the program will "own" the device.
  * to one of these "claimed" ports, the program will "own" the device.
  */
  */
 static int find_port_owner(struct usb_device *hdev, unsigned port1,
 static int find_port_owner(struct usb_device *hdev, unsigned port1,
-		void ***ppowner)
+		struct dev_state ***ppowner)
 {
 {
 	if (hdev->state == USB_STATE_NOTATTACHED)
 	if (hdev->state == USB_STATE_NOTATTACHED)
 		return -ENODEV;
 		return -ENODEV;
@@ -1664,10 +1666,11 @@ static int find_port_owner(struct usb_device *hdev, unsigned port1,
 }
 }
 
 
 /* In the following three functions, the caller must hold hdev's lock */
 /* In the following three functions, the caller must hold hdev's lock */
-int usb_hub_claim_port(struct usb_device *hdev, unsigned port1, void *owner)
+int usb_hub_claim_port(struct usb_device *hdev, unsigned port1,
+		       struct dev_state *owner)
 {
 {
 	int rc;
 	int rc;
-	void **powner;
+	struct dev_state **powner;
 
 
 	rc = find_port_owner(hdev, port1, &powner);
 	rc = find_port_owner(hdev, port1, &powner);
 	if (rc)
 	if (rc)
@@ -1678,10 +1681,11 @@ int usb_hub_claim_port(struct usb_device *hdev, unsigned port1, void *owner)
 	return rc;
 	return rc;
 }
 }
 
 
-int usb_hub_release_port(struct usb_device *hdev, unsigned port1, void *owner)
+int usb_hub_release_port(struct usb_device *hdev, unsigned port1,
+			 struct dev_state *owner)
 {
 {
 	int rc;
 	int rc;
-	void **powner;
+	struct dev_state **powner;
 
 
 	rc = find_port_owner(hdev, port1, &powner);
 	rc = find_port_owner(hdev, port1, &powner);
 	if (rc)
 	if (rc)
@@ -1692,10 +1696,10 @@ int usb_hub_release_port(struct usb_device *hdev, unsigned port1, void *owner)
 	return rc;
 	return rc;
 }
 }
 
 
-void usb_hub_release_all_ports(struct usb_device *hdev, void *owner)
+void usb_hub_release_all_ports(struct usb_device *hdev, struct dev_state *owner)
 {
 {
 	int n;
 	int n;
-	void **powner;
+	struct dev_state **powner;
 
 
 	n = find_port_owner(hdev, 1, &powner);
 	n = find_port_owner(hdev, 1, &powner);
 	if (n == 0) {
 	if (n == 0) {
@@ -2065,7 +2069,7 @@ static int usb_enumerate_device(struct usb_device *udev)
 		if (err < 0) {
 		if (err < 0) {
 			dev_err(&udev->dev, "can't read configurations, error %d\n",
 			dev_err(&udev->dev, "can't read configurations, error %d\n",
 				err);
 				err);
-			goto fail;
+			return err;
 		}
 		}
 	}
 	}
 	if (udev->wusb == 1 && udev->authorized == 0) {
 	if (udev->wusb == 1 && udev->authorized == 0) {
@@ -2081,8 +2085,12 @@ static int usb_enumerate_device(struct usb_device *udev)
 		udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
 		udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
 	}
 	}
 	err = usb_enumerate_device_otg(udev);
 	err = usb_enumerate_device_otg(udev);
-fail:
-	return err;
+	if (err < 0)
+		return err;
+
+	usb_detect_interface_quirks(udev);
+
+	return 0;
 }
 }
 
 
 static void set_usb_port_removable(struct usb_device *udev)
 static void set_usb_port_removable(struct usb_device *udev)
@@ -2611,6 +2619,50 @@ static int check_port_resume_type(struct usb_device *udev,
 	return status;
 	return status;
 }
 }
 
 
+int usb_disable_ltm(struct usb_device *udev)
+{
+	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+	/* Check if the roothub and device supports LTM. */
+	if (!usb_device_supports_ltm(hcd->self.root_hub) ||
+			!usb_device_supports_ltm(udev))
+		return 0;
+
+	/* Clear Feature LTM Enable can only be sent if the device is
+	 * configured.
+	 */
+	if (!udev->actconfig)
+		return 0;
+
+	return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE,
+			USB_DEVICE_LTM_ENABLE, 0, NULL, 0,
+			USB_CTRL_SET_TIMEOUT);
+}
+EXPORT_SYMBOL_GPL(usb_disable_ltm);
+
+void usb_enable_ltm(struct usb_device *udev)
+{
+	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+	/* Check if the roothub and device supports LTM. */
+	if (!usb_device_supports_ltm(hcd->self.root_hub) ||
+			!usb_device_supports_ltm(udev))
+		return;
+
+	/* Set Feature LTM Enable can only be sent if the device is
+	 * configured.
+	 */
+	if (!udev->actconfig)
+		return;
+
+	usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
+			USB_DEVICE_LTM_ENABLE, 0, NULL, 0,
+			USB_CTRL_SET_TIMEOUT);
+}
+EXPORT_SYMBOL_GPL(usb_enable_ltm);
+
 #ifdef	CONFIG_USB_SUSPEND
 #ifdef	CONFIG_USB_SUSPEND
 
 
 /*
 /*
@@ -2706,6 +2758,11 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
 	if (udev->usb2_hw_lpm_enabled == 1)
 	if (udev->usb2_hw_lpm_enabled == 1)
 		usb_set_usb2_hardware_lpm(udev, 0);
 		usb_set_usb2_hardware_lpm(udev, 0);
 
 
+	if (usb_disable_ltm(udev)) {
+		dev_err(&udev->dev, "%s Failed to disable LTM before suspend\n.",
+				__func__);
+		return -ENOMEM;
+	}
 	if (usb_unlocked_disable_lpm(udev)) {
 	if (usb_unlocked_disable_lpm(udev)) {
 		dev_err(&udev->dev, "%s Failed to disable LPM before suspend\n.",
 		dev_err(&udev->dev, "%s Failed to disable LPM before suspend\n.",
 				__func__);
 				__func__);
@@ -2735,7 +2792,8 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
 		if (udev->usb2_hw_lpm_capable == 1)
 		if (udev->usb2_hw_lpm_capable == 1)
 			usb_set_usb2_hardware_lpm(udev, 1);
 			usb_set_usb2_hardware_lpm(udev, 1);
 
 
-		/* Try to enable USB3 LPM again */
+		/* Try to enable USB3 LTM and LPM again */
+		usb_enable_ltm(udev);
 		usb_unlocked_enable_lpm(udev);
 		usb_unlocked_enable_lpm(udev);
 
 
 		/* System sleep transitions should never fail */
 		/* System sleep transitions should never fail */
@@ -2936,7 +2994,8 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
 		if (udev->usb2_hw_lpm_capable == 1)
 		if (udev->usb2_hw_lpm_capable == 1)
 			usb_set_usb2_hardware_lpm(udev, 1);
 			usb_set_usb2_hardware_lpm(udev, 1);
 
 
-		/* Try to enable USB3 LPM */
+		/* Try to enable USB3 LTM and LPM */
+		usb_enable_ltm(udev);
 		usb_unlocked_enable_lpm(udev);
 		usb_unlocked_enable_lpm(udev);
 	}
 	}
 
 
@@ -3489,6 +3548,15 @@ EXPORT_SYMBOL_GPL(usb_unlocked_disable_lpm);
 
 
 void usb_unlocked_enable_lpm(struct usb_device *udev) { }
 void usb_unlocked_enable_lpm(struct usb_device *udev) { }
 EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm);
 EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm);
+
+int usb_disable_ltm(struct usb_device *udev)
+{
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_disable_ltm);
+
+void usb_enable_ltm(struct usb_device *udev) { }
+EXPORT_SYMBOL_GPL(usb_enable_ltm);
 #endif
 #endif
 
 
 
 
@@ -4038,6 +4106,13 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
 		}
 		}
 	}
 	}
 
 
+	if (hcd->phy && !hdev->parent) {
+		if (portstatus & USB_PORT_STAT_CONNECTION)
+			usb_phy_notify_connect(hcd->phy, port1);
+		else
+			usb_phy_notify_disconnect(hcd->phy, port1);
+	}
+
 	/* Return now if debouncing failed or nothing is connected or
 	/* Return now if debouncing failed or nothing is connected or
 	 * the device was "removed".
 	 * the device was "removed".
 	 */
 	 */
@@ -4672,6 +4747,23 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
 	}
 	}
 	parent_hub = hdev_to_hub(parent_hdev);
 	parent_hub = hdev_to_hub(parent_hdev);
 
 
+	/* Disable LPM and LTM while we reset the device and reinstall the alt
+	 * settings.  Device-initiated LPM settings, and system exit latency
+	 * settings are cleared when the device is reset, so we have to set
+	 * them up again.
+	 */
+	ret = usb_unlocked_disable_lpm(udev);
+	if (ret) {
+		dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__);
+		goto re_enumerate;
+	}
+	ret = usb_disable_ltm(udev);
+	if (ret) {
+		dev_err(&udev->dev, "%s Failed to disable LTM\n.",
+				__func__);
+		goto re_enumerate;
+	}
+
 	set_bit(port1, parent_hub->busy_bits);
 	set_bit(port1, parent_hub->busy_bits);
 	for (i = 0; i < SET_CONFIG_TRIES; ++i) {
 	for (i = 0; i < SET_CONFIG_TRIES; ++i) {
 
 
@@ -4699,22 +4791,11 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
 		goto done;
 		goto done;
 
 
 	mutex_lock(hcd->bandwidth_mutex);
 	mutex_lock(hcd->bandwidth_mutex);
-	/* Disable LPM while we reset the device and reinstall the alt settings.
-	 * Device-initiated LPM settings, and system exit latency settings are
-	 * cleared when the device is reset, so we have to set them up again.
-	 */
-	ret = usb_disable_lpm(udev);
-	if (ret) {
-		dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__);
-		mutex_unlock(hcd->bandwidth_mutex);
-		goto done;
-	}
 	ret = usb_hcd_alloc_bandwidth(udev, udev->actconfig, NULL, NULL);
 	ret = usb_hcd_alloc_bandwidth(udev, udev->actconfig, NULL, NULL);
 	if (ret < 0) {
 	if (ret < 0) {
 		dev_warn(&udev->dev,
 		dev_warn(&udev->dev,
 				"Busted HC?  Not enough HCD resources for "
 				"Busted HC?  Not enough HCD resources for "
 				"old configuration.\n");
 				"old configuration.\n");
-		usb_enable_lpm(udev);
 		mutex_unlock(hcd->bandwidth_mutex);
 		mutex_unlock(hcd->bandwidth_mutex);
 		goto re_enumerate;
 		goto re_enumerate;
 	}
 	}
@@ -4726,7 +4807,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
 		dev_err(&udev->dev,
 		dev_err(&udev->dev,
 			"can't restore configuration #%d (error=%d)\n",
 			"can't restore configuration #%d (error=%d)\n",
 			udev->actconfig->desc.bConfigurationValue, ret);
 			udev->actconfig->desc.bConfigurationValue, ret);
-		usb_enable_lpm(udev);
 		mutex_unlock(hcd->bandwidth_mutex);
 		mutex_unlock(hcd->bandwidth_mutex);
 		goto re_enumerate;
 		goto re_enumerate;
   	}
   	}
@@ -4765,17 +4845,18 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
 				desc->bInterfaceNumber,
 				desc->bInterfaceNumber,
 				desc->bAlternateSetting,
 				desc->bAlternateSetting,
 				ret);
 				ret);
-			usb_unlocked_enable_lpm(udev);
 			goto re_enumerate;
 			goto re_enumerate;
 		}
 		}
 	}
 	}
 
 
-	/* Now that the alt settings are re-installed, enable LPM. */
-	usb_unlocked_enable_lpm(udev);
 done:
 done:
+	/* Now that the alt settings are re-installed, enable LTM and LPM. */
+	usb_unlocked_enable_lpm(udev);
+	usb_enable_ltm(udev);
 	return 0;
 	return 0;
  
  
 re_enumerate:
 re_enumerate:
+	/* LPM state doesn't matter when we're about to destroy the device. */
 	hub_port_logical_disconnect(parent_hub, port1);
 	hub_port_logical_disconnect(parent_hub, port1);
 	return -ENODEV;
 	return -ENODEV;
 }
 }

+ 11 - 5
drivers/usb/core/message.c

@@ -1174,6 +1174,8 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
 			put_device(&dev->actconfig->interface[i]->dev);
 			put_device(&dev->actconfig->interface[i]->dev);
 			dev->actconfig->interface[i] = NULL;
 			dev->actconfig->interface[i] = NULL;
 		}
 		}
+		usb_unlocked_disable_lpm(dev);
+		usb_disable_ltm(dev);
 		dev->actconfig = NULL;
 		dev->actconfig = NULL;
 		if (dev->state == USB_STATE_CONFIGURED)
 		if (dev->state == USB_STATE_CONFIGURED)
 			usb_set_device_state(dev, USB_STATE_ADDRESS);
 			usb_set_device_state(dev, USB_STATE_ADDRESS);
@@ -1559,7 +1561,7 @@ static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
 
 
 	if (add_uevent_var(env,
 	if (add_uevent_var(env,
 		   "MODALIAS=usb:"
 		   "MODALIAS=usb:"
-		   "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
+		   "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02Xin%02X",
 		   le16_to_cpu(usb_dev->descriptor.idVendor),
 		   le16_to_cpu(usb_dev->descriptor.idVendor),
 		   le16_to_cpu(usb_dev->descriptor.idProduct),
 		   le16_to_cpu(usb_dev->descriptor.idProduct),
 		   le16_to_cpu(usb_dev->descriptor.bcdDevice),
 		   le16_to_cpu(usb_dev->descriptor.bcdDevice),
@@ -1568,7 +1570,8 @@ static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
 		   usb_dev->descriptor.bDeviceProtocol,
 		   usb_dev->descriptor.bDeviceProtocol,
 		   alt->desc.bInterfaceClass,
 		   alt->desc.bInterfaceClass,
 		   alt->desc.bInterfaceSubClass,
 		   alt->desc.bInterfaceSubClass,
-		   alt->desc.bInterfaceProtocol))
+		   alt->desc.bInterfaceProtocol,
+		   alt->desc.bInterfaceNumber))
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	return 0;
 	return 0;
@@ -1791,14 +1794,15 @@ free_interfaces:
 	 * installed, so that the xHCI driver can recalculate the U1/U2
 	 * installed, so that the xHCI driver can recalculate the U1/U2
 	 * timeouts.
 	 * timeouts.
 	 */
 	 */
-	if (usb_disable_lpm(dev)) {
+	if (dev->actconfig && usb_disable_lpm(dev)) {
 		dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__);
 		dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__);
 		mutex_unlock(hcd->bandwidth_mutex);
 		mutex_unlock(hcd->bandwidth_mutex);
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 	ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
 	ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
 	if (ret < 0) {
 	if (ret < 0) {
-		usb_enable_lpm(dev);
+		if (dev->actconfig)
+			usb_enable_lpm(dev);
 		mutex_unlock(hcd->bandwidth_mutex);
 		mutex_unlock(hcd->bandwidth_mutex);
 		usb_autosuspend_device(dev);
 		usb_autosuspend_device(dev);
 		goto free_interfaces;
 		goto free_interfaces;
@@ -1818,7 +1822,7 @@ free_interfaces:
 	if (!cp) {
 	if (!cp) {
 		usb_set_device_state(dev, USB_STATE_ADDRESS);
 		usb_set_device_state(dev, USB_STATE_ADDRESS);
 		usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
 		usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
-		usb_enable_lpm(dev);
+		/* Leave LPM disabled while the device is unconfigured. */
 		mutex_unlock(hcd->bandwidth_mutex);
 		mutex_unlock(hcd->bandwidth_mutex);
 		usb_autosuspend_device(dev);
 		usb_autosuspend_device(dev);
 		goto free_interfaces;
 		goto free_interfaces;
@@ -1876,6 +1880,8 @@ free_interfaces:
 
 
 	/* Now that the interfaces are installed, re-enable LPM. */
 	/* Now that the interfaces are installed, re-enable LPM. */
 	usb_unlocked_enable_lpm(dev);
 	usb_unlocked_enable_lpm(dev);
+	/* Enable LTM if it was turned off by usb_disable_device. */
+	usb_enable_ltm(dev);
 
 
 	/* Now that all the interfaces are set up, register them
 	/* Now that all the interfaces are set up, register them
 	 * to trigger binding of drivers to interfaces.  probe()
 	 * to trigger binding of drivers to interfaces.  probe()

+ 88 - 63
drivers/usb/core/quirks.c

@@ -15,17 +15,22 @@
 #include <linux/usb/quirks.h>
 #include <linux/usb/quirks.h>
 #include "usb.h"
 #include "usb.h"
 
 
-/* List of quirky USB devices.  Please keep this list ordered by:
+/* Lists of quirky USB devices, split in device quirks and interface quirks.
+ * Device quirks are applied at the very beginning of the enumeration process,
+ * right after reading the device descriptor. They can thus only match on device
+ * information.
+ *
+ * Interface quirks are applied after reading all the configuration descriptors.
+ * They can match on both device and interface information.
+ *
+ * Note that the DELAY_INIT and HONOR_BNUMINTERFACES quirks do not make sense as
+ * interface quirks, as they only influence the enumeration process which is run
+ * before processing the interface quirks.
+ *
+ * Please keep the lists ordered by:
  * 	1) Vendor ID
  * 	1) Vendor ID
  * 	2) Product ID
  * 	2) Product ID
  * 	3) Class ID
  * 	3) Class ID
- *
- * as we want specific devices to be overridden first, and only after that, any
- * class specific quirks.
- *
- * Right now the logic aborts if it finds a valid device in the table, we might
- * want to change that in the future if it turns out that a whole class of
- * devices is broken...
  */
  */
 static const struct usb_device_id usb_quirk_list[] = {
 static const struct usb_device_id usb_quirk_list[] = {
 	/* CBM - Flash disk */
 	/* CBM - Flash disk */
@@ -38,53 +43,23 @@ static const struct usb_device_id usb_quirk_list[] = {
 	/* Creative SB Audigy 2 NX */
 	/* Creative SB Audigy 2 NX */
 	{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
 	{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
 
 
-	/* Logitech Webcam C200 */
-	{ USB_DEVICE(0x046d, 0x0802), .driver_info = USB_QUIRK_RESET_RESUME },
-
-	/* Logitech Webcam C250 */
-	{ USB_DEVICE(0x046d, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME },
-
-	/* Logitech Webcam C300 */
-	{ USB_DEVICE(0x046d, 0x0805), .driver_info = USB_QUIRK_RESET_RESUME },
-
-	/* Logitech Webcam B/C500 */
-	{ USB_DEVICE(0x046d, 0x0807), .driver_info = USB_QUIRK_RESET_RESUME },
-
-	/* Logitech Webcam C600 */
-	{ USB_DEVICE(0x046d, 0x0808), .driver_info = USB_QUIRK_RESET_RESUME },
-
-	/* Logitech Webcam Pro 9000 */
-	{ USB_DEVICE(0x046d, 0x0809), .driver_info = USB_QUIRK_RESET_RESUME },
+	/* Logitech Quickcam Fusion */
+	{ USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME },
 
 
-	/* Logitech Webcam C905 */
-	{ USB_DEVICE(0x046d, 0x080a), .driver_info = USB_QUIRK_RESET_RESUME },
+	/* Logitech Quickcam Orbit MP */
+	{ USB_DEVICE(0x046d, 0x08c2), .driver_info = USB_QUIRK_RESET_RESUME },
 
 
-	/* Logitech Webcam C210 */
-	{ USB_DEVICE(0x046d, 0x0819), .driver_info = USB_QUIRK_RESET_RESUME },
+	/* Logitech Quickcam Pro for Notebook */
+	{ USB_DEVICE(0x046d, 0x08c3), .driver_info = USB_QUIRK_RESET_RESUME },
 
 
-	/* Logitech Webcam C260 */
-	{ USB_DEVICE(0x046d, 0x081a), .driver_info = USB_QUIRK_RESET_RESUME },
+	/* Logitech Quickcam Pro 5000 */
+	{ USB_DEVICE(0x046d, 0x08c5), .driver_info = USB_QUIRK_RESET_RESUME },
 
 
-	/* Logitech Webcam C310 */
-	{ USB_DEVICE(0x046d, 0x081b), .driver_info = USB_QUIRK_RESET_RESUME },
+	/* Logitech Quickcam OEM Dell Notebook */
+	{ USB_DEVICE(0x046d, 0x08c6), .driver_info = USB_QUIRK_RESET_RESUME },
 
 
-	/* Logitech Webcam C910 */
-	{ USB_DEVICE(0x046d, 0x0821), .driver_info = USB_QUIRK_RESET_RESUME },
-
-	/* Logitech Webcam C160 */
-	{ USB_DEVICE(0x046d, 0x0824), .driver_info = USB_QUIRK_RESET_RESUME },
-
-	/* Logitech Webcam C270 */
-	{ USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME },
-
-	/* Logitech Quickcam Pro 9000 */
-	{ USB_DEVICE(0x046d, 0x0990), .driver_info = USB_QUIRK_RESET_RESUME },
-
-	/* Logitech Quickcam E3500 */
-	{ USB_DEVICE(0x046d, 0x09a4), .driver_info = USB_QUIRK_RESET_RESUME },
-
-	/* Logitech Quickcam Vision Pro */
-	{ USB_DEVICE(0x046d, 0x09a6), .driver_info = USB_QUIRK_RESET_RESUME },
+	/* Logitech Quickcam OEM Cisco VT Camera II */
+	{ USB_DEVICE(0x046d, 0x08c7), .driver_info = USB_QUIRK_RESET_RESUME },
 
 
 	/* Logitech Harmony 700-series */
 	/* Logitech Harmony 700-series */
 	{ USB_DEVICE(0x046d, 0xc122), .driver_info = USB_QUIRK_DELAY_INIT },
 	{ USB_DEVICE(0x046d, 0xc122), .driver_info = USB_QUIRK_DELAY_INIT },
@@ -156,16 +131,57 @@ static const struct usb_device_id usb_quirk_list[] = {
 	{ }  /* terminating entry must be last */
 	{ }  /* terminating entry must be last */
 };
 };
 
 
-static const struct usb_device_id *find_id(struct usb_device *udev)
+static const struct usb_device_id usb_interface_quirk_list[] = {
+	/* Logitech UVC Cameras */
+	{ USB_VENDOR_AND_INTERFACE_INFO(0x046d, USB_CLASS_VIDEO, 1, 0),
+	  .driver_info = USB_QUIRK_RESET_RESUME },
+
+	{ }  /* terminating entry must be last */
+};
+
+static bool usb_match_any_interface(struct usb_device *udev,
+				    const struct usb_device_id *id)
 {
 {
-	const struct usb_device_id *id = usb_quirk_list;
+	unsigned int i;
 
 
-	for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
-			id->driver_info; id++) {
-		if (usb_match_device(udev, id))
-			return id;
+	for (i = 0; i < udev->descriptor.bNumConfigurations; ++i) {
+		struct usb_host_config *cfg = &udev->config[i];
+		unsigned int j;
+
+		for (j = 0; j < cfg->desc.bNumInterfaces; ++j) {
+			struct usb_interface_cache *cache;
+			struct usb_host_interface *intf;
+
+			cache = cfg->intf_cache[j];
+			if (cache->num_altsetting == 0)
+				continue;
+
+			intf = &cache->altsetting[0];
+			if (usb_match_one_id_intf(udev, intf, id))
+				return true;
+		}
+	}
+
+	return false;
+}
+
+static u32 __usb_detect_quirks(struct usb_device *udev,
+			       const struct usb_device_id *id)
+{
+	u32 quirks = 0;
+
+	for (; id->match_flags; id++) {
+		if (!usb_match_device(udev, id))
+			continue;
+
+		if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_INFO) &&
+		    !usb_match_any_interface(udev, id))
+			continue;
+
+		quirks |= (u32)(id->driver_info);
 	}
 	}
-	return NULL;
+
+	return quirks;
 }
 }
 
 
 /*
 /*
@@ -173,14 +189,10 @@ static const struct usb_device_id *find_id(struct usb_device *udev)
  */
  */
 void usb_detect_quirks(struct usb_device *udev)
 void usb_detect_quirks(struct usb_device *udev)
 {
 {
-	const struct usb_device_id *id = usb_quirk_list;
-
-	id = find_id(udev);
-	if (id)
-		udev->quirks = (u32)(id->driver_info);
+	udev->quirks = __usb_detect_quirks(udev, usb_quirk_list);
 	if (udev->quirks)
 	if (udev->quirks)
 		dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
 		dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
-				udev->quirks);
+			udev->quirks);
 
 
 	/* For the present, all devices default to USB-PERSIST enabled */
 	/* For the present, all devices default to USB-PERSIST enabled */
 #if 0		/* was: #ifdef CONFIG_PM */
 #if 0		/* was: #ifdef CONFIG_PM */
@@ -197,3 +209,16 @@ void usb_detect_quirks(struct usb_device *udev)
 		udev->persist_enabled = 1;
 		udev->persist_enabled = 1;
 #endif	/* CONFIG_PM */
 #endif	/* CONFIG_PM */
 }
 }
+
+void usb_detect_interface_quirks(struct usb_device *udev)
+{
+	u32 quirks;
+
+	quirks = __usb_detect_quirks(udev, usb_interface_quirk_list);
+	if (quirks == 0)
+		return;
+
+	dev_dbg(&udev->dev, "USB interface quirks for this device: %x\n",
+		quirks);
+	udev->quirks |= quirks;
+}

+ 13 - 2
drivers/usb/core/sysfs.c

@@ -253,6 +253,15 @@ show_removable(struct device *dev, struct device_attribute *attr, char *buf)
 }
 }
 static DEVICE_ATTR(removable, S_IRUGO, show_removable, NULL);
 static DEVICE_ATTR(removable, S_IRUGO, show_removable, NULL);
 
 
+static ssize_t
+show_ltm_capable(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	if (usb_device_supports_ltm(to_usb_device(dev)))
+		return sprintf(buf, "%s\n", "yes");
+	return sprintf(buf, "%s\n", "no");
+}
+static DEVICE_ATTR(ltm_capable, S_IRUGO, show_ltm_capable, NULL);
+
 #ifdef	CONFIG_PM
 #ifdef	CONFIG_PM
 
 
 static ssize_t
 static ssize_t
@@ -649,6 +658,7 @@ static struct attribute *dev_attrs[] = {
 	&dev_attr_authorized.attr,
 	&dev_attr_authorized.attr,
 	&dev_attr_remove.attr,
 	&dev_attr_remove.attr,
 	&dev_attr_removable.attr,
 	&dev_attr_removable.attr,
+	&dev_attr_ltm_capable.attr,
 	NULL,
 	NULL,
 };
 };
 static struct attribute_group dev_attr_grp = {
 static struct attribute_group dev_attr_grp = {
@@ -840,7 +850,7 @@ static ssize_t show_modalias(struct device *dev,
 	alt = intf->cur_altsetting;
 	alt = intf->cur_altsetting;
 
 
 	return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"
 	return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"
-			"ic%02Xisc%02Xip%02X\n",
+			"ic%02Xisc%02Xip%02Xin%02X\n",
 			le16_to_cpu(udev->descriptor.idVendor),
 			le16_to_cpu(udev->descriptor.idVendor),
 			le16_to_cpu(udev->descriptor.idProduct),
 			le16_to_cpu(udev->descriptor.idProduct),
 			le16_to_cpu(udev->descriptor.bcdDevice),
 			le16_to_cpu(udev->descriptor.bcdDevice),
@@ -849,7 +859,8 @@ static ssize_t show_modalias(struct device *dev,
 			udev->descriptor.bDeviceProtocol,
 			udev->descriptor.bDeviceProtocol,
 			alt->desc.bInterfaceClass,
 			alt->desc.bInterfaceClass,
 			alt->desc.bInterfaceSubClass,
 			alt->desc.bInterfaceSubClass,
-			alt->desc.bInterfaceProtocol);
+			alt->desc.bInterfaceProtocol,
+			alt->desc.bInterfaceNumber);
 }
 }
 static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
 static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
 
 

+ 1 - 0
drivers/usb/core/usb.c

@@ -396,6 +396,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
 	dev->dev.dma_mask = bus->controller->dma_mask;
 	dev->dev.dma_mask = bus->controller->dma_mask;
 	set_dev_node(&dev->dev, dev_to_node(bus->controller));
 	set_dev_node(&dev->dev, dev_to_node(bus->controller));
 	dev->state = USB_STATE_ATTACHED;
 	dev->state = USB_STATE_ATTACHED;
+	dev->lpm_disable_count = 1;
 	atomic_set(&dev->urbnum, 0);
 	atomic_set(&dev->urbnum, 0);
 
 
 	INIT_LIST_HEAD(&dev->ep0.urb_list);
 	INIT_LIST_HEAD(&dev->ep0.urb_list);

+ 10 - 3
drivers/usb/core/usb.h

@@ -1,5 +1,7 @@
 #include <linux/pm.h>
 #include <linux/pm.h>
 
 
+struct dev_state;
+
 /* Functions local to drivers/usb/core/ */
 /* Functions local to drivers/usb/core/ */
 
 
 extern int usb_create_sysfs_dev_files(struct usb_device *dev);
 extern int usb_create_sysfs_dev_files(struct usb_device *dev);
@@ -24,6 +26,7 @@ extern void usb_disable_device(struct usb_device *dev, int skip_ep0);
 extern int usb_deauthorize_device(struct usb_device *);
 extern int usb_deauthorize_device(struct usb_device *);
 extern int usb_authorize_device(struct usb_device *);
 extern int usb_authorize_device(struct usb_device *);
 extern void usb_detect_quirks(struct usb_device *udev);
 extern void usb_detect_quirks(struct usb_device *udev);
+extern void usb_detect_interface_quirks(struct usb_device *udev);
 extern int usb_remove_device(struct usb_device *udev);
 extern int usb_remove_device(struct usb_device *udev);
 
 
 extern int usb_get_device_descriptor(struct usb_device *dev,
 extern int usb_get_device_descriptor(struct usb_device *dev,
@@ -35,16 +38,20 @@ extern int usb_set_configuration(struct usb_device *dev, int configuration);
 extern int usb_choose_configuration(struct usb_device *udev);
 extern int usb_choose_configuration(struct usb_device *udev);
 
 
 extern void usb_kick_khubd(struct usb_device *dev);
 extern void usb_kick_khubd(struct usb_device *dev);
+extern int usb_match_one_id_intf(struct usb_device *dev,
+				 struct usb_host_interface *intf,
+				 const struct usb_device_id *id);
 extern int usb_match_device(struct usb_device *dev,
 extern int usb_match_device(struct usb_device *dev,
 			    const struct usb_device_id *id);
 			    const struct usb_device_id *id);
 extern void usb_forced_unbind_intf(struct usb_interface *intf);
 extern void usb_forced_unbind_intf(struct usb_interface *intf);
 extern void usb_rebind_intf(struct usb_interface *intf);
 extern void usb_rebind_intf(struct usb_interface *intf);
 
 
 extern int usb_hub_claim_port(struct usb_device *hdev, unsigned port,
 extern int usb_hub_claim_port(struct usb_device *hdev, unsigned port,
-		void *owner);
+		struct dev_state *owner);
 extern int usb_hub_release_port(struct usb_device *hdev, unsigned port,
 extern int usb_hub_release_port(struct usb_device *hdev, unsigned port,
-		void *owner);
-extern void usb_hub_release_all_ports(struct usb_device *hdev, void *owner);
+		struct dev_state *owner);
+extern void usb_hub_release_all_ports(struct usb_device *hdev,
+		struct dev_state *owner);
 extern bool usb_device_is_owned(struct usb_device *udev);
 extern bool usb_device_is_owned(struct usb_device *udev);
 
 
 extern int  usb_hub_init(void);
 extern int  usb_hub_init(void);

+ 10 - 3
drivers/usb/dwc3/core.c

@@ -148,6 +148,8 @@ static void dwc3_core_soft_reset(struct dwc3 *dwc)
 	reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
 	reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 
 
+	mdelay(100);
+
 	/* After PHYs are stable we can take Core out of reset state */
 	/* After PHYs are stable we can take Core out of reset state */
 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
 	reg &= ~DWC3_GCTL_CORESOFTRESET;
 	reg &= ~DWC3_GCTL_CORESOFTRESET;
@@ -255,7 +257,7 @@ static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
  *
  *
  * Returns 0 on success otherwise negative errno.
  * Returns 0 on success otherwise negative errno.
  */
  */
-static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)
+static int dwc3_event_buffers_setup(struct dwc3 *dwc)
 {
 {
 	struct dwc3_event_buffer	*evt;
 	struct dwc3_event_buffer	*evt;
 	int				n;
 	int				n;
@@ -266,6 +268,8 @@ static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)
 				evt->buf, (unsigned long long) evt->dma,
 				evt->buf, (unsigned long long) evt->dma,
 				evt->length);
 				evt->length);
 
 
+		evt->lpos = 0;
+
 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
 				lower_32_bits(evt->dma));
 				lower_32_bits(evt->dma));
 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
@@ -285,6 +289,9 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
 
 
 	for (n = 0; n < dwc->num_event_buffers; n++) {
 	for (n = 0; n < dwc->num_event_buffers; n++) {
 		evt = dwc->ev_buffs[n];
 		evt = dwc->ev_buffs[n];
+
+		evt->lpos = 0;
+
 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
@@ -328,8 +335,6 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
 	}
 	}
 	dwc->revision = reg;
 	dwc->revision = reg;
 
 
-	dwc3_core_soft_reset(dwc);
-
 	/* issue device SoftReset too */
 	/* issue device SoftReset too */
 	timeout = jiffies + msecs_to_jiffies(500);
 	timeout = jiffies + msecs_to_jiffies(500);
 	dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
 	dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
@@ -347,6 +352,8 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
 		cpu_relax();
 		cpu_relax();
 	} while (true);
 	} while (true);
 
 
+	dwc3_core_soft_reset(dwc);
+
 	dwc3_cache_hwparams(dwc);
 	dwc3_cache_hwparams(dwc);
 
 
 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);

+ 83 - 24
drivers/usb/dwc3/core.h

@@ -67,6 +67,7 @@
 #define DWC3_DEVICE_EVENT_CONNECT_DONE		2
 #define DWC3_DEVICE_EVENT_CONNECT_DONE		2
 #define DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE	3
 #define DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE	3
 #define DWC3_DEVICE_EVENT_WAKEUP		4
 #define DWC3_DEVICE_EVENT_WAKEUP		4
+#define DWC3_DEVICE_EVENT_HIBER_REQ		5
 #define DWC3_DEVICE_EVENT_EOPF			6
 #define DWC3_DEVICE_EVENT_EOPF			6
 #define DWC3_DEVICE_EVENT_SOF			7
 #define DWC3_DEVICE_EVENT_SOF			7
 #define DWC3_DEVICE_EVENT_ERRATIC_ERROR		9
 #define DWC3_DEVICE_EVENT_ERRATIC_ERROR		9
@@ -171,28 +172,36 @@
 #define DWC3_GCTL_PRTCAP_DEVICE	2
 #define DWC3_GCTL_PRTCAP_DEVICE	2
 #define DWC3_GCTL_PRTCAP_OTG	3
 #define DWC3_GCTL_PRTCAP_OTG	3
 
 
-#define DWC3_GCTL_CORESOFTRESET	(1 << 11)
-#define DWC3_GCTL_SCALEDOWN(n)	((n) << 4)
-#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3)
-#define DWC3_GCTL_DISSCRAMBLE	(1 << 3)
-#define DWC3_GCTL_DSBLCLKGTNG	(1 << 0)
+#define DWC3_GCTL_CORESOFTRESET		(1 << 11)
+#define DWC3_GCTL_SCALEDOWN(n)		((n) << 4)
+#define DWC3_GCTL_SCALEDOWN_MASK	DWC3_GCTL_SCALEDOWN(3)
+#define DWC3_GCTL_DISSCRAMBLE		(1 << 3)
+#define DWC3_GCTL_GBLHIBERNATIONEN	(1 << 1)
+#define DWC3_GCTL_DSBLCLKGTNG		(1 << 0)
 
 
 /* Global USB2 PHY Configuration Register */
 /* Global USB2 PHY Configuration Register */
-#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
-#define DWC3_GUSB2PHYCFG_SUSPHY	(1 << 6)
+#define DWC3_GUSB2PHYCFG_PHYSOFTRST	(1 << 31)
+#define DWC3_GUSB2PHYCFG_SUSPHY		(1 << 6)
 
 
 /* Global USB3 PIPE Control Register */
 /* Global USB3 PIPE Control Register */
-#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
-#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
+#define DWC3_GUSB3PIPECTL_PHYSOFTRST	(1 << 31)
+#define DWC3_GUSB3PIPECTL_SUSPHY	(1 << 17)
 
 
 /* Global TX Fifo Size Register */
 /* Global TX Fifo Size Register */
-#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
-#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000)
+#define DWC3_GTXFIFOSIZ_TXFDEF(n)	((n) & 0xffff)
+#define DWC3_GTXFIFOSIZ_TXFSTADDR(n)	((n) & 0xffff0000)
 
 
 /* Global HWPARAMS1 Register */
 /* Global HWPARAMS1 Register */
 #define DWC3_GHWPARAMS1_EN_PWROPT(n)	(((n) & (3 << 24)) >> 24)
 #define DWC3_GHWPARAMS1_EN_PWROPT(n)	(((n) & (3 << 24)) >> 24)
 #define DWC3_GHWPARAMS1_EN_PWROPT_NO	0
 #define DWC3_GHWPARAMS1_EN_PWROPT_NO	0
 #define DWC3_GHWPARAMS1_EN_PWROPT_CLK	1
 #define DWC3_GHWPARAMS1_EN_PWROPT_CLK	1
+#define DWC3_GHWPARAMS1_EN_PWROPT_HIB	2
+#define DWC3_GHWPARAMS1_PWROPT(n)	((n) << 24)
+#define DWC3_GHWPARAMS1_PWROPT_MASK	DWC3_GHWPARAMS1_PWROPT(3)
+
+/* Global HWPARAMS4 Register */
+#define DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(n)	(((n) & (0x0f << 13)) >> 13)
+#define DWC3_MAX_HIBER_SCRATCHBUFS		15
 
 
 /* Device Configuration Register */
 /* Device Configuration Register */
 #define DWC3_DCFG_LPM_CAP	(1 << 22)
 #define DWC3_DCFG_LPM_CAP	(1 << 22)
@@ -206,24 +215,32 @@
 #define DWC3_DCFG_LOWSPEED	(2 << 0)
 #define DWC3_DCFG_LOWSPEED	(2 << 0)
 #define DWC3_DCFG_FULLSPEED1	(3 << 0)
 #define DWC3_DCFG_FULLSPEED1	(3 << 0)
 
 
+#define DWC3_DCFG_LPM_CAP	(1 << 22)
+
 /* Device Control Register */
 /* Device Control Register */
 #define DWC3_DCTL_RUN_STOP	(1 << 31)
 #define DWC3_DCTL_RUN_STOP	(1 << 31)
 #define DWC3_DCTL_CSFTRST	(1 << 30)
 #define DWC3_DCTL_CSFTRST	(1 << 30)
 #define DWC3_DCTL_LSFTRST	(1 << 29)
 #define DWC3_DCTL_LSFTRST	(1 << 29)
 
 
 #define DWC3_DCTL_HIRD_THRES_MASK	(0x1f << 24)
 #define DWC3_DCTL_HIRD_THRES_MASK	(0x1f << 24)
-#define DWC3_DCTL_HIRD_THRES(n)	(((n) & DWC3_DCTL_HIRD_THRES_MASK) >> 24)
+#define DWC3_DCTL_HIRD_THRES(n)	((n) << 24)
 
 
 #define DWC3_DCTL_APPL1RES	(1 << 23)
 #define DWC3_DCTL_APPL1RES	(1 << 23)
 
 
-#define DWC3_DCTL_TRGTULST_MASK	(0x0f << 17)
-#define DWC3_DCTL_TRGTULST(n)	((n) << 17)
-
-#define DWC3_DCTL_TRGTULST_U2	(DWC3_DCTL_TRGTULST(2))
-#define DWC3_DCTL_TRGTULST_U3	(DWC3_DCTL_TRGTULST(3))
-#define DWC3_DCTL_TRGTULST_SS_DIS (DWC3_DCTL_TRGTULST(4))
-#define DWC3_DCTL_TRGTULST_RX_DET (DWC3_DCTL_TRGTULST(5))
-#define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6))
+/* These apply for core versions 1.87a and earlier */
+#define DWC3_DCTL_TRGTULST_MASK		(0x0f << 17)
+#define DWC3_DCTL_TRGTULST(n)		((n) << 17)
+#define DWC3_DCTL_TRGTULST_U2		(DWC3_DCTL_TRGTULST(2))
+#define DWC3_DCTL_TRGTULST_U3		(DWC3_DCTL_TRGTULST(3))
+#define DWC3_DCTL_TRGTULST_SS_DIS	(DWC3_DCTL_TRGTULST(4))
+#define DWC3_DCTL_TRGTULST_RX_DET	(DWC3_DCTL_TRGTULST(5))
+#define DWC3_DCTL_TRGTULST_SS_INACT	(DWC3_DCTL_TRGTULST(6))
+
+/* These apply for core versions 1.94a and later */
+#define DWC3_DCTL_KEEP_CONNECT	(1 << 19)
+#define DWC3_DCTL_L1_HIBER_EN	(1 << 18)
+#define DWC3_DCTL_CRS		(1 << 17)
+#define DWC3_DCTL_CSS		(1 << 16)
 
 
 #define DWC3_DCTL_INITU2ENA	(1 << 12)
 #define DWC3_DCTL_INITU2ENA	(1 << 12)
 #define DWC3_DCTL_ACCEPTU2ENA	(1 << 11)
 #define DWC3_DCTL_ACCEPTU2ENA	(1 << 11)
@@ -249,6 +266,7 @@
 #define DWC3_DEVTEN_ERRTICERREN		(1 << 9)
 #define DWC3_DEVTEN_ERRTICERREN		(1 << 9)
 #define DWC3_DEVTEN_SOFEN		(1 << 7)
 #define DWC3_DEVTEN_SOFEN		(1 << 7)
 #define DWC3_DEVTEN_EOPFEN		(1 << 6)
 #define DWC3_DEVTEN_EOPFEN		(1 << 6)
+#define DWC3_DEVTEN_HIBERNATIONREQEVTEN	(1 << 5)
 #define DWC3_DEVTEN_WKUPEVTEN		(1 << 4)
 #define DWC3_DEVTEN_WKUPEVTEN		(1 << 4)
 #define DWC3_DEVTEN_ULSTCNGEN		(1 << 3)
 #define DWC3_DEVTEN_ULSTCNGEN		(1 << 3)
 #define DWC3_DEVTEN_CONNECTDONEEN	(1 << 2)
 #define DWC3_DEVTEN_CONNECTDONEEN	(1 << 2)
@@ -256,7 +274,15 @@
 #define DWC3_DEVTEN_DISCONNEVTEN	(1 << 0)
 #define DWC3_DEVTEN_DISCONNEVTEN	(1 << 0)
 
 
 /* Device Status Register */
 /* Device Status Register */
+#define DWC3_DSTS_DCNRD			(1 << 29)
+
+/* This applies for core versions 1.87a and earlier */
 #define DWC3_DSTS_PWRUPREQ		(1 << 24)
 #define DWC3_DSTS_PWRUPREQ		(1 << 24)
+
+/* These apply for core versions 1.94a and later */
+#define DWC3_DSTS_RSS			(1 << 25)
+#define DWC3_DSTS_SSS			(1 << 24)
+
 #define DWC3_DSTS_COREIDLE		(1 << 23)
 #define DWC3_DSTS_COREIDLE		(1 << 23)
 #define DWC3_DSTS_DEVCTRLHLT		(1 << 22)
 #define DWC3_DSTS_DEVCTRLHLT		(1 << 22)
 
 
@@ -265,7 +291,7 @@
 
 
 #define DWC3_DSTS_RXFIFOEMPTY		(1 << 17)
 #define DWC3_DSTS_RXFIFOEMPTY		(1 << 17)
 
 
-#define DWC3_DSTS_SOFFN_MASK		(0x3ff << 3)
+#define DWC3_DSTS_SOFFN_MASK		(0x3fff << 3)
 #define DWC3_DSTS_SOFFN(n)		(((n) & DWC3_DSTS_SOFFN_MASK) >> 3)
 #define DWC3_DSTS_SOFFN(n)		(((n) & DWC3_DSTS_SOFFN_MASK) >> 3)
 
 
 #define DWC3_DSTS_CONNECTSPD		(7 << 0)
 #define DWC3_DSTS_CONNECTSPD		(7 << 0)
@@ -280,6 +306,11 @@
 #define DWC3_DGCMD_SET_LMP		0x01
 #define DWC3_DGCMD_SET_LMP		0x01
 #define DWC3_DGCMD_SET_PERIODIC_PAR	0x02
 #define DWC3_DGCMD_SET_PERIODIC_PAR	0x02
 #define DWC3_DGCMD_XMIT_FUNCTION	0x03
 #define DWC3_DGCMD_XMIT_FUNCTION	0x03
+
+/* These apply for core versions 1.94a and later */
+#define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO	0x04
+#define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI	0x05
+
 #define DWC3_DGCMD_SELECTED_FIFO_FLUSH	0x09
 #define DWC3_DGCMD_SELECTED_FIFO_FLUSH	0x09
 #define DWC3_DGCMD_ALL_FIFO_FLUSH	0x0a
 #define DWC3_DGCMD_ALL_FIFO_FLUSH	0x0a
 #define DWC3_DGCMD_SET_ENDPOINT_NRDY	0x0c
 #define DWC3_DGCMD_SET_ENDPOINT_NRDY	0x0c
@@ -287,6 +318,15 @@
 
 
 #define DWC3_DGCMD_STATUS(n)		(((n) >> 15) & 1)
 #define DWC3_DGCMD_STATUS(n)		(((n) >> 15) & 1)
 #define DWC3_DGCMD_CMDACT		(1 << 10)
 #define DWC3_DGCMD_CMDACT		(1 << 10)
+#define DWC3_DGCMD_CMDIOC		(1 << 8)
+
+/* Device Generic Command Parameter Register */
+#define DWC3_DGCMDPAR_FORCE_LINKPM_ACCEPT	(1 << 0)
+#define DWC3_DGCMDPAR_FIFO_NUM(n)		((n) << 0)
+#define DWC3_DGCMDPAR_RX_FIFO			(0 << 5)
+#define DWC3_DGCMDPAR_TX_FIFO			(1 << 5)
+#define DWC3_DGCMDPAR_LOOPBACK_DIS		(0 << 0)
+#define DWC3_DGCMDPAR_LOOPBACK_ENA		(1 << 0)
 
 
 /* Device Endpoint Command Register */
 /* Device Endpoint Command Register */
 #define DWC3_DEPCMD_PARAM_SHIFT		16
 #define DWC3_DEPCMD_PARAM_SHIFT		16
@@ -303,7 +343,10 @@
 #define DWC3_DEPCMD_STARTTRANSFER	(0x06 << 0)
 #define DWC3_DEPCMD_STARTTRANSFER	(0x06 << 0)
 #define DWC3_DEPCMD_CLEARSTALL		(0x05 << 0)
 #define DWC3_DEPCMD_CLEARSTALL		(0x05 << 0)
 #define DWC3_DEPCMD_SETSTALL		(0x04 << 0)
 #define DWC3_DEPCMD_SETSTALL		(0x04 << 0)
+/* This applies for core versions 1.90a and earlier */
 #define DWC3_DEPCMD_GETSEQNUMBER	(0x03 << 0)
 #define DWC3_DEPCMD_GETSEQNUMBER	(0x03 << 0)
+/* This applies for core versions 1.94a and later */
+#define DWC3_DEPCMD_GETEPSTATE		(0x03 << 0)
 #define DWC3_DEPCMD_SETTRANSFRESOURCE	(0x02 << 0)
 #define DWC3_DEPCMD_SETTRANSFRESOURCE	(0x02 << 0)
 #define DWC3_DEPCMD_SETEPCONFIG		(0x01 << 0)
 #define DWC3_DEPCMD_SETEPCONFIG		(0x01 << 0)
 
 
@@ -361,7 +404,8 @@ struct dwc3_event_buffer {
  * @current_trb: index of current used trb
  * @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
- * @res_trans_idx: Resource transfer index
+ * @resource_index: Resource transfer index
+ * @current_uf: Current uf received through last event parameter
  * @interval: the intervall on which the ISOC transfer is started
  * @interval: the intervall on which the ISOC transfer is started
  * @name: a human readable name e.g. ep1out-bulk
  * @name: a human readable name e.g. ep1out-bulk
  * @direction: true for TX, false for RX
  * @direction: true for TX, false for RX
@@ -385,6 +429,7 @@ struct dwc3_ep {
 #define DWC3_EP_WEDGE		(1 << 2)
 #define DWC3_EP_WEDGE		(1 << 2)
 #define DWC3_EP_BUSY		(1 << 4)
 #define DWC3_EP_BUSY		(1 << 4)
 #define DWC3_EP_PENDING_REQUEST	(1 << 5)
 #define DWC3_EP_PENDING_REQUEST	(1 << 5)
+#define DWC3_EP_MISSED_ISOC	(1 << 6)
 
 
 	/* 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)
@@ -393,7 +438,8 @@ struct dwc3_ep {
 
 
 	u8			number;
 	u8			number;
 	u8			type;
 	u8			type;
-	u8			res_trans_idx;
+	u8			resource_index;
+	u16			current_uf;
 	u32			interval;
 	u32			interval;
 
 
 	char			name[20];
 	char			name[20];
@@ -437,6 +483,8 @@ enum dwc3_link_state {
 	DWC3_LINK_STATE_HRESET		= 0x09,
 	DWC3_LINK_STATE_HRESET		= 0x09,
 	DWC3_LINK_STATE_CMPLY		= 0x0a,
 	DWC3_LINK_STATE_CMPLY		= 0x0a,
 	DWC3_LINK_STATE_LPBK		= 0x0b,
 	DWC3_LINK_STATE_LPBK		= 0x0b,
+	DWC3_LINK_STATE_RESET		= 0x0e,
+	DWC3_LINK_STATE_RESUME		= 0x0f,
 	DWC3_LINK_STATE_MASK		= 0x0f,
 	DWC3_LINK_STATE_MASK		= 0x0f,
 };
 };
 
 
@@ -450,11 +498,12 @@ enum dwc3_device_state {
 #define DWC3_TRB_SIZE_MASK	(0x00ffffff)
 #define DWC3_TRB_SIZE_MASK	(0x00ffffff)
 #define DWC3_TRB_SIZE_LENGTH(n)	((n) & DWC3_TRB_SIZE_MASK)
 #define DWC3_TRB_SIZE_LENGTH(n)	((n) & DWC3_TRB_SIZE_MASK)
 #define DWC3_TRB_SIZE_PCM1(n)	(((n) & 0x03) << 24)
 #define DWC3_TRB_SIZE_PCM1(n)	(((n) & 0x03) << 24)
-#define DWC3_TRB_SIZE_TRBSTS(n)	(((n) & (0x0f << 28) >> 28))
+#define DWC3_TRB_SIZE_TRBSTS(n)	(((n) & (0x0f << 28)) >> 28)
 
 
 #define DWC3_TRBSTS_OK			0
 #define DWC3_TRBSTS_OK			0
 #define DWC3_TRBSTS_MISSED_ISOC		1
 #define DWC3_TRBSTS_MISSED_ISOC		1
 #define DWC3_TRBSTS_SETUP_PENDING	2
 #define DWC3_TRBSTS_SETUP_PENDING	2
+#define DWC3_TRB_STS_XFER_IN_PROG	4
 
 
 /* TRB Control */
 /* TRB Control */
 #define DWC3_TRB_CTRL_HWO		(1 << 0)
 #define DWC3_TRB_CTRL_HWO		(1 << 0)
@@ -543,6 +592,14 @@ struct dwc3_request {
 	unsigned		queued:1;
 	unsigned		queued:1;
 };
 };
 
 
+/*
+ * struct dwc3_scratchpad_array - hibernation scratchpad array
+ * (format defined by hw)
+ */
+struct dwc3_scratchpad_array {
+	__le64	dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS];
+};
+
 /**
 /**
  * struct dwc3 - representation of our controller
  * struct dwc3 - representation of our controller
  * @ctrl_req: usb control request which is used for ep0
  * @ctrl_req: usb control request which is used for ep0
@@ -624,8 +681,10 @@ struct dwc3 {
 #define DWC3_REVISION_180A	0x5533180a
 #define DWC3_REVISION_180A	0x5533180a
 #define DWC3_REVISION_183A	0x5533183a
 #define DWC3_REVISION_183A	0x5533183a
 #define DWC3_REVISION_185A	0x5533185a
 #define DWC3_REVISION_185A	0x5533185a
+#define DWC3_REVISION_187A	0x5533187a
 #define DWC3_REVISION_188A	0x5533188a
 #define DWC3_REVISION_188A	0x5533188a
 #define DWC3_REVISION_190A	0x5533190a
 #define DWC3_REVISION_190A	0x5533190a
+#define DWC3_REVISION_194A	0x5533194a
 #define DWC3_REVISION_200A	0x5533200a
 #define DWC3_REVISION_200A	0x5533200a
 #define DWC3_REVISION_202A	0x5533202a
 #define DWC3_REVISION_202A	0x5533202a
 #define DWC3_REVISION_210A	0x5533210a
 #define DWC3_REVISION_210A	0x5533210a

+ 0 - 1
drivers/usb/dwc3/dwc3-exynos.c

@@ -18,7 +18,6 @@
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/platform_data/dwc3-exynos.h>
 #include <linux/platform_data/dwc3-exynos.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
-#include <linux/module.h>
 #include <linux/clk.h>
 #include <linux/clk.h>
 
 
 #include "core.h"
 #include "core.h"

+ 92 - 54
drivers/usb/dwc3/ep0.c

@@ -54,7 +54,9 @@
 #include "gadget.h"
 #include "gadget.h"
 #include "io.h"
 #include "io.h"
 
 
-static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum);
+static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep);
+static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
+		struct dwc3_ep *dep, struct dwc3_request *req);
 
 
 static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
 static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
 {
 {
@@ -111,7 +113,7 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
 	}
 	}
 
 
 	dep->flags |= DWC3_EP_BUSY;
 	dep->flags |= DWC3_EP_BUSY;
-	dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
+	dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc,
 			dep->number);
 			dep->number);
 
 
 	dwc->ep0_next_event = DWC3_EP0_COMPLETE;
 	dwc->ep0_next_event = DWC3_EP0_COMPLETE;
@@ -150,16 +152,15 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
 			return 0;
 			return 0;
 		}
 		}
 
 
-		ret = dwc3_ep0_start_trans(dwc, direction,
-				req->request.dma, req->request.length,
-				DWC3_TRBCTL_CONTROL_DATA);
+		__dwc3_ep0_do_control_data(dwc, dwc->eps[direction], req);
+
 		dep->flags &= ~(DWC3_EP_PENDING_REQUEST |
 		dep->flags &= ~(DWC3_EP_PENDING_REQUEST |
 				DWC3_EP0_DIR_IN);
 				DWC3_EP0_DIR_IN);
 	} else if (dwc->delayed_status) {
 	} else if (dwc->delayed_status) {
 		dwc->delayed_status = false;
 		dwc->delayed_status = false;
 
 
 		if (dwc->ep0state == EP0_STATUS_PHASE)
 		if (dwc->ep0state == EP0_STATUS_PHASE)
-			dwc3_ep0_do_control_status(dwc, 1);
+			__dwc3_ep0_do_control_status(dwc, dwc->eps[1]);
 		else
 		else
 			dev_dbg(dwc->dev, "too early for delayed status\n");
 			dev_dbg(dwc->dev, "too early for delayed status\n");
 	}
 	}
@@ -224,6 +225,16 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
 	dwc3_ep0_out_start(dwc);
 	dwc3_ep0_out_start(dwc);
 }
 }
 
 
+int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
+{
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+	struct dwc3			*dwc = dep->dwc;
+
+	dwc3_ep0_stall_and_restart(dwc);
+
+	return 0;
+}
+
 void dwc3_ep0_out_start(struct dwc3 *dwc)
 void dwc3_ep0_out_start(struct dwc3 *dwc)
 {
 {
 	int				ret;
 	int				ret;
@@ -463,6 +474,7 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 {
 {
 	u32 cfg;
 	u32 cfg;
 	int ret;
 	int ret;
+	u32 reg;
 
 
 	dwc->start_config_issued = false;
 	dwc->start_config_issued = false;
 	cfg = le16_to_cpu(ctrl->wValue);
 	cfg = le16_to_cpu(ctrl->wValue);
@@ -477,6 +489,14 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 		/* if the cfg matches and the cfg is non zero */
 		/* if the cfg matches and the cfg is non zero */
 		if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
 		if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
 			dwc->dev_state = DWC3_CONFIGURED_STATE;
 			dwc->dev_state = DWC3_CONFIGURED_STATE;
+			/*
+			 * Enable transition to U1/U2 state when
+			 * nothing is pending from application.
+			 */
+			reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+			reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA);
+			dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
 			dwc->resize_fifos = true;
 			dwc->resize_fifos = true;
 			dev_dbg(dwc->dev, "resize fifos flag SET\n");
 			dev_dbg(dwc->dev, "resize fifos flag SET\n");
 		}
 		}
@@ -514,8 +534,8 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
 
 
 	dwc->u1sel = timing.u1sel;
 	dwc->u1sel = timing.u1sel;
 	dwc->u1pel = timing.u1pel;
 	dwc->u1pel = timing.u1pel;
-	dwc->u2sel = timing.u2sel;
-	dwc->u2pel = timing.u2pel;
+	dwc->u2sel = le16_to_cpu(timing.u2sel);
+	dwc->u2pel = le16_to_cpu(timing.u2pel);
 
 
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 	if (reg & DWC3_DCTL_INITU2ENA)
 	if (reg & DWC3_DCTL_INITU2ENA)
@@ -640,11 +660,11 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
 		const struct dwc3_event_depevt *event)
 		const struct dwc3_event_depevt *event)
 {
 {
 	struct usb_ctrlrequest *ctrl = dwc->ctrl_req;
 	struct usb_ctrlrequest *ctrl = dwc->ctrl_req;
-	int ret;
+	int ret = -EINVAL;
 	u32 len;
 	u32 len;
 
 
 	if (!dwc->gadget_driver)
 	if (!dwc->gadget_driver)
-		goto err;
+		goto out;
 
 
 	len = le16_to_cpu(ctrl->wLength);
 	len = le16_to_cpu(ctrl->wLength);
 	if (!len) {
 	if (!len) {
@@ -665,11 +685,9 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
 	if (ret == USB_GADGET_DELAYED_STATUS)
 	if (ret == USB_GADGET_DELAYED_STATUS)
 		dwc->delayed_status = true;
 		dwc->delayed_status = true;
 
 
-	if (ret >= 0)
-		return;
-
-err:
-	dwc3_ep0_stall_and_restart(dwc);
+out:
+	if (ret < 0)
+		dwc3_ep0_stall_and_restart(dwc);
 }
 }
 
 
 static void dwc3_ep0_complete_data(struct dwc3 *dwc,
 static void dwc3_ep0_complete_data(struct dwc3 *dwc,
@@ -723,7 +741,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
 	}
 	}
 }
 }
 
 
-static void dwc3_ep0_complete_req(struct dwc3 *dwc,
+static void dwc3_ep0_complete_status(struct dwc3 *dwc,
 		const struct dwc3_event_depevt *event)
 		const struct dwc3_event_depevt *event)
 {
 {
 	struct dwc3_request	*r;
 	struct dwc3_request	*r;
@@ -745,6 +763,7 @@ static void dwc3_ep0_complete_req(struct dwc3 *dwc,
 			dev_dbg(dwc->dev, "Invalid Test #%d\n",
 			dev_dbg(dwc->dev, "Invalid Test #%d\n",
 					dwc->test_mode_nr);
 					dwc->test_mode_nr);
 			dwc3_ep0_stall_and_restart(dwc);
 			dwc3_ep0_stall_and_restart(dwc);
+			return;
 		}
 		}
 	}
 	}
 
 
@@ -758,7 +777,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
 	struct dwc3_ep		*dep = dwc->eps[event->endpoint_number];
 	struct dwc3_ep		*dep = dwc->eps[event->endpoint_number];
 
 
 	dep->flags &= ~DWC3_EP_BUSY;
 	dep->flags &= ~DWC3_EP_BUSY;
-	dep->res_trans_idx = 0;
+	dep->resource_index = 0;
 	dwc->setup_packet_pending = false;
 	dwc->setup_packet_pending = false;
 
 
 	switch (dwc->ep0state) {
 	switch (dwc->ep0state) {
@@ -774,7 +793,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
 
 
 	case EP0_STATUS_PHASE:
 	case EP0_STATUS_PHASE:
 		dev_vdbg(dwc->dev, "Status Phase\n");
 		dev_vdbg(dwc->dev, "Status Phase\n");
-		dwc3_ep0_complete_req(dwc, event);
+		dwc3_ep0_complete_status(dwc, event);
 		break;
 		break;
 	default:
 	default:
 		WARN(true, "UNKNOWN ep0state %d\n", dwc->ep0state);
 		WARN(true, "UNKNOWN ep0state %d\n", dwc->ep0state);
@@ -787,68 +806,81 @@ static void dwc3_ep0_do_control_setup(struct dwc3 *dwc,
 	dwc3_ep0_out_start(dwc);
 	dwc3_ep0_out_start(dwc);
 }
 }
 
 
-static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
-		const struct dwc3_event_depevt *event)
+static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
+		struct dwc3_ep *dep, struct dwc3_request *req)
 {
 {
-	struct dwc3_ep		*dep;
-	struct dwc3_request	*req;
 	int			ret;
 	int			ret;
 
 
-	dep = dwc->eps[0];
-
-	if (list_empty(&dep->request_list)) {
-		dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n");
-		dep->flags |= DWC3_EP_PENDING_REQUEST;
-
-		if (event->endpoint_number)
-			dep->flags |= DWC3_EP0_DIR_IN;
-		return;
-	}
-
-	req = next_request(&dep->request_list);
-	req->direction = !!event->endpoint_number;
+	req->direction = !!dep->number;
 
 
 	if (req->request.length == 0) {
 	if (req->request.length == 0) {
-		ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+		ret = dwc3_ep0_start_trans(dwc, dep->number,
 				dwc->ctrl_req_addr, 0,
 				dwc->ctrl_req_addr, 0,
 				DWC3_TRBCTL_CONTROL_DATA);
 				DWC3_TRBCTL_CONTROL_DATA);
-	} else if ((req->request.length % dep->endpoint.maxpacket)
-			&& (event->endpoint_number == 0)) {
+	} else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
+			&& (dep->number == 0)) {
+		u32		transfer_size;
+
 		ret = usb_gadget_map_request(&dwc->gadget, &req->request,
 		ret = usb_gadget_map_request(&dwc->gadget, &req->request,
-				event->endpoint_number);
+				dep->number);
 		if (ret) {
 		if (ret) {
 			dev_dbg(dwc->dev, "failed to map request\n");
 			dev_dbg(dwc->dev, "failed to map request\n");
 			return;
 			return;
 		}
 		}
 
 
-		WARN_ON(req->request.length > dep->endpoint.maxpacket);
+		WARN_ON(req->request.length > DWC3_EP0_BOUNCE_SIZE);
+
+		transfer_size = roundup(req->request.length,
+				(u32) dep->endpoint.maxpacket);
 
 
 		dwc->ep0_bounced = true;
 		dwc->ep0_bounced = true;
 
 
 		/*
 		/*
-		 * REVISIT in case request length is bigger than EP0
-		 * wMaxPacketSize, we will need two chained TRBs to handle
-		 * the transfer.
+		 * REVISIT in case request length is bigger than
+		 * DWC3_EP0_BOUNCE_SIZE we will need two chained
+		 * TRBs to handle the transfer.
 		 */
 		 */
-		ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
-				dwc->ep0_bounce_addr, dep->endpoint.maxpacket,
+		ret = dwc3_ep0_start_trans(dwc, dep->number,
+				dwc->ep0_bounce_addr, transfer_size,
 				DWC3_TRBCTL_CONTROL_DATA);
 				DWC3_TRBCTL_CONTROL_DATA);
 	} else {
 	} else {
 		ret = usb_gadget_map_request(&dwc->gadget, &req->request,
 		ret = usb_gadget_map_request(&dwc->gadget, &req->request,
-				event->endpoint_number);
+				dep->number);
 		if (ret) {
 		if (ret) {
 			dev_dbg(dwc->dev, "failed to map request\n");
 			dev_dbg(dwc->dev, "failed to map request\n");
 			return;
 			return;
 		}
 		}
 
 
-		ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
-				req->request.dma, req->request.length,
-				DWC3_TRBCTL_CONTROL_DATA);
+		ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma,
+				req->request.length, DWC3_TRBCTL_CONTROL_DATA);
 	}
 	}
 
 
 	WARN_ON(ret < 0);
 	WARN_ON(ret < 0);
 }
 }
 
 
+static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3_ep		*dep;
+	struct dwc3_request	*req;
+
+	dep = dwc->eps[0];
+
+	if (list_empty(&dep->request_list)) {
+		dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n");
+		dep->flags |= DWC3_EP_PENDING_REQUEST;
+
+		if (event->endpoint_number)
+			dep->flags |= DWC3_EP0_DIR_IN;
+		return;
+	}
+
+	req = next_request(&dep->request_list);
+	dep = dwc->eps[event->endpoint_number];
+
+	__dwc3_ep0_do_control_data(dwc, dep, req);
+}
+
 static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
 static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
 {
 {
 	struct dwc3		*dwc = dep->dwc;
 	struct dwc3		*dwc = dep->dwc;
@@ -861,10 +893,8 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
 			dwc->ctrl_req_addr, 0, type);
 			dwc->ctrl_req_addr, 0, type);
 }
 }
 
 
-static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum)
+static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
 {
 {
-	struct dwc3_ep		*dep = dwc->eps[epnum];
-
 	if (dwc->resize_fifos) {
 	if (dwc->resize_fifos) {
 		dev_dbg(dwc->dev, "starting to resize fifos\n");
 		dev_dbg(dwc->dev, "starting to resize fifos\n");
 		dwc3_gadget_resize_tx_fifos(dwc);
 		dwc3_gadget_resize_tx_fifos(dwc);
@@ -874,13 +904,21 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum)
 	WARN_ON(dwc3_ep0_start_control_status(dep));
 	WARN_ON(dwc3_ep0_start_control_status(dep));
 }
 }
 
 
+static void dwc3_ep0_do_control_status(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3_ep		*dep = dwc->eps[event->endpoint_number];
+
+	__dwc3_ep0_do_control_status(dwc, dep);
+}
+
 static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
 static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
 		const struct dwc3_event_depevt *event)
 		const struct dwc3_event_depevt *event)
 {
 {
 	dwc->setup_packet_pending = true;
 	dwc->setup_packet_pending = true;
 
 
 	/*
 	/*
-	 * This part is very tricky: If we has just handled
+	 * This part is very tricky: If we have just handled
 	 * XferNotReady(Setup) and we're now expecting a
 	 * XferNotReady(Setup) and we're now expecting a
 	 * XferComplete but, instead, we receive another
 	 * XferComplete but, instead, we receive another
 	 * XferNotReady(Setup), we should STALL and restart
 	 * XferNotReady(Setup), we should STALL and restart
@@ -974,7 +1012,7 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
 			return;
 			return;
 		}
 		}
 
 
-		dwc3_ep0_do_control_status(dwc, event->endpoint_number);
+		dwc3_ep0_do_control_status(dwc, event);
 	}
 	}
 }
 }
 
 

+ 217 - 148
drivers/usb/dwc3/gadget.c

@@ -100,6 +100,23 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
 	int		retries = 10000;
 	int		retries = 10000;
 	u32		reg;
 	u32		reg;
 
 
+	/*
+	 * Wait until device controller is ready. Only applies to 1.94a and
+	 * later RTL.
+	 */
+	if (dwc->revision >= DWC3_REVISION_194A) {
+		while (--retries) {
+			reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+			if (reg & DWC3_DSTS_DCNRD)
+				udelay(5);
+			else
+				break;
+		}
+
+		if (retries <= 0)
+			return -ETIMEDOUT;
+	}
+
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 	reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
 	reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
 
 
@@ -107,7 +124,15 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
 	reg |= DWC3_DCTL_ULSTCHNGREQ(state);
 	reg |= DWC3_DCTL_ULSTCHNGREQ(state);
 	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 
 
+	/*
+	 * The following code is racy when called from dwc3_gadget_wakeup,
+	 * and is not needed, at least on newer versions
+	 */
+	if (dwc->revision >= DWC3_REVISION_194A)
+		return 0;
+
 	/* wait for a change in DSTS */
 	/* wait for a change in DSTS */
+	retries = 10000;
 	while (--retries) {
 	while (--retries) {
 		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
 		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
 
 
@@ -265,8 +290,8 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd)
 		return "Clear Stall";
 		return "Clear Stall";
 	case DWC3_DEPCMD_SETSTALL:
 	case DWC3_DEPCMD_SETSTALL:
 		return "Set Stall";
 		return "Set Stall";
-	case DWC3_DEPCMD_GETSEQNUMBER:
-		return "Get Data Sequence Number";
+	case DWC3_DEPCMD_GETEPSTATE:
+		return "Get Endpoint State";
 	case DWC3_DEPCMD_SETTRANSFRESOURCE:
 	case DWC3_DEPCMD_SETTRANSFRESOURCE:
 		return "Set Endpoint Transfer Resource";
 		return "Set Endpoint Transfer Resource";
 	case DWC3_DEPCMD_SETEPCONFIG:
 	case DWC3_DEPCMD_SETEPCONFIG:
@@ -414,7 +439,7 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
 
 
 	params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc))
 	params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc))
 		| DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc))
 		| DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc))
-		| DWC3_DEPCFG_BURST_SIZE(dep->endpoint.maxburst);
+		| DWC3_DEPCFG_BURST_SIZE(dep->endpoint.maxburst - 1);
 
 
 	params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN
 	params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN
 		| DWC3_DEPCFG_XFER_NOT_READY_EN;
 		| DWC3_DEPCFG_XFER_NOT_READY_EN;
@@ -530,9 +555,37 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
 {
 {
 	struct dwc3_request		*req;
 	struct dwc3_request		*req;
 
 
-	if (!list_empty(&dep->req_queued))
+	if (!list_empty(&dep->req_queued)) {
 		dwc3_stop_active_transfer(dwc, dep->number);
 		dwc3_stop_active_transfer(dwc, dep->number);
 
 
+		/*
+		 * NOTICE: We are violating what the Databook says about the
+		 * EndTransfer command. Ideally we would _always_ wait for the
+		 * EndTransfer Command Completion IRQ, but that's causing too
+		 * much trouble synchronizing between us and gadget driver.
+		 *
+		 * We have discussed this with the IP Provider and it was
+		 * suggested to giveback all requests here, but give HW some
+		 * extra time to synchronize with the interconnect. We're using
+		 * an arbitraty 100us delay for that.
+		 *
+		 * Note also that a similar handling was tested by Synopsys
+		 * (thanks a lot Paul) and nothing bad has come out of it.
+		 * In short, what we're doing is:
+		 *
+		 * - Issue EndTransfer WITH CMDIOC bit set
+		 * - Wait 100us
+		 * - giveback all requests to gadget driver
+		 */
+		udelay(100);
+
+		while (!list_empty(&dep->req_queued)) {
+			req = next_request(&dep->req_queued);
+
+			dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
+		}
+	}
+
 	while (!list_empty(&dep->request_list)) {
 	while (!list_empty(&dep->request_list)) {
 		req = next_request(&dep->request_list);
 		req = next_request(&dep->request_list);
 
 
@@ -741,8 +794,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
 	case USB_ENDPOINT_XFER_ISOC:
 	case USB_ENDPOINT_XFER_ISOC:
 		trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
 		trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
 
 
-		/* IOC every DWC3_TRB_NUM / 4 so we can refill */
-		if (!(cur_slot % (DWC3_TRB_NUM / 4)))
+		if (!req->request.no_interrupt)
 			trb->ctrl |= DWC3_TRB_CTRL_IOC;
 			trb->ctrl |= DWC3_TRB_CTRL_IOC;
 		break;
 		break;
 
 
@@ -958,14 +1010,42 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
 	dep->flags |= DWC3_EP_BUSY;
 	dep->flags |= DWC3_EP_BUSY;
 
 
 	if (start_new) {
 	if (start_new) {
-		dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
+		dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc,
 				dep->number);
 				dep->number);
-		WARN_ON_ONCE(!dep->res_trans_idx);
+		WARN_ON_ONCE(!dep->resource_index);
 	}
 	}
 
 
 	return 0;
 	return 0;
 }
 }
 
 
+static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
+		struct dwc3_ep *dep, u32 cur_uf)
+{
+	u32 uf;
+
+	if (list_empty(&dep->request_list)) {
+		dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
+			dep->name);
+		return;
+	}
+
+	/* 4 micro frames in the future */
+	uf = cur_uf + dep->interval * 4;
+
+	__dwc3_gadget_kick_transfer(dep, uf, 1);
+}
+
+static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
+		struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
+{
+	u32 cur_uf, mask;
+
+	mask = ~(dep->interval - 1);
+	cur_uf = event->parameters & mask;
+
+	__dwc3_gadget_start_isoc(dwc, dep, cur_uf);
+}
+
 static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 {
 {
 	struct dwc3		*dwc = dep->dwc;
 	struct dwc3		*dwc = dep->dwc;
@@ -995,11 +1075,8 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 
 
 	list_add_tail(&req->list, &dep->request_list);
 	list_add_tail(&req->list, &dep->request_list);
 
 
-	if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && (dep->flags & DWC3_EP_BUSY))
-		dep->flags |= DWC3_EP_PENDING_REQUEST;
-
 	/*
 	/*
-	 * There are two special cases:
+	 * There are a few special cases:
 	 *
 	 *
 	 * 1. XferNotReady with empty list of requests. We need to kick the
 	 * 1. XferNotReady with empty list of requests. We need to kick the
 	 *    transfer here in that situation, otherwise we will be NAKing
 	 *    transfer here in that situation, otherwise we will be NAKing
@@ -1008,31 +1085,46 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 	 *    able to receive the data until the next request is queued.
 	 *    able to receive the data until the next request is queued.
 	 *    The following code is handling exactly that.
 	 *    The following code is handling exactly that.
 	 *
 	 *
-	 * 2. XferInProgress on Isoc EP with an active transfer. We need to
-	 *    kick the transfer here after queuing a request, otherwise the
-	 *    core may not see the modified TRB(s).
 	 */
 	 */
 	if (dep->flags & DWC3_EP_PENDING_REQUEST) {
 	if (dep->flags & DWC3_EP_PENDING_REQUEST) {
 		int	ret;
 		int	ret;
-		int	start_trans = 1;
-		u8	trans_idx = dep->res_trans_idx;
 
 
-		if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
-				(dep->flags & DWC3_EP_BUSY)) {
-			start_trans = 0;
-			WARN_ON_ONCE(!trans_idx);
-		} else {
-			trans_idx = 0;
+		ret = __dwc3_gadget_kick_transfer(dep, 0, true);
+		if (ret && ret != -EBUSY) {
+			struct dwc3	*dwc = dep->dwc;
+
+			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
+					dep->name);
 		}
 		}
+	}
 
 
-		ret = __dwc3_gadget_kick_transfer(dep, trans_idx, start_trans);
+	/*
+	 * 2. XferInProgress on Isoc EP with an active transfer. We need to
+	 *    kick the transfer here after queuing a request, otherwise the
+	 *    core may not see the modified TRB(s).
+	 */
+	if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+			(dep->flags & DWC3_EP_BUSY)) {
+		WARN_ON_ONCE(!dep->resource_index);
+		ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index,
+				false);
 		if (ret && ret != -EBUSY) {
 		if (ret && ret != -EBUSY) {
 			struct dwc3	*dwc = dep->dwc;
 			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);
 		}
 		}
-	};
+	}
+
+	/*
+	 * 3. Missed ISOC Handling. We need to start isoc transfer on the saved
+	 * uframe number.
+	 */
+	if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+		(dep->flags & DWC3_EP_MISSED_ISOC)) {
+			__dwc3_gadget_start_isoc(dwc, dep, dep->current_uf);
+			dep->flags &= ~DWC3_EP_MISSED_ISOC;
+	}
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1118,15 +1210,6 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
 	memset(&params, 0x00, sizeof(params));
 	memset(&params, 0x00, sizeof(params));
 
 
 	if (value) {
 	if (value) {
-		if (dep->number == 0 || dep->number == 1) {
-			/*
-			 * Whenever EP0 is stalled, we will restart
-			 * the state machine, thus moving back to
-			 * Setup Phase
-			 */
-			dwc->ep0state = EP0_SETUP_PHASE;
-		}
-
 		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
 		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
 			DWC3_DEPCMD_SETSTALL, &params);
 			DWC3_DEPCMD_SETSTALL, &params);
 		if (ret)
 		if (ret)
@@ -1186,7 +1269,10 @@ static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
 	dep->flags |= DWC3_EP_WEDGE;
 	dep->flags |= DWC3_EP_WEDGE;
 	spin_unlock_irqrestore(&dwc->lock, flags);
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 
-	return dwc3_gadget_ep_set_halt(ep, 1);
+	if (dep->number == 0 || dep->number == 1)
+		return dwc3_gadget_ep0_set_halt(ep, 1);
+	else
+		return dwc3_gadget_ep_set_halt(ep, 1);
 }
 }
 
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
@@ -1204,7 +1290,7 @@ static const struct usb_ep_ops dwc3_gadget_ep0_ops = {
 	.free_request	= dwc3_gadget_ep_free_request,
 	.free_request	= dwc3_gadget_ep_free_request,
 	.queue		= dwc3_gadget_ep0_queue,
 	.queue		= dwc3_gadget_ep0_queue,
 	.dequeue	= dwc3_gadget_ep_dequeue,
 	.dequeue	= dwc3_gadget_ep_dequeue,
-	.set_halt	= dwc3_gadget_ep_set_halt,
+	.set_halt	= dwc3_gadget_ep0_set_halt,
 	.set_wedge	= dwc3_gadget_ep_set_wedge,
 	.set_wedge	= dwc3_gadget_ep_set_wedge,
 };
 };
 
 
@@ -1280,9 +1366,13 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
 		goto out;
 		goto out;
 	}
 	}
 
 
-	/* write zeroes to Link Change Request */
-	reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
-	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+	/* Recent versions do this automatically */
+	if (dwc->revision < DWC3_REVISION_194A) {
+		/* write zeroes to Link Change Request */
+		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+		reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
+		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+	}
 
 
 	/* poll until Link State changes to ON */
 	/* poll until Link State changes to ON */
 	timeout = jiffies + msecs_to_jiffies(100);
 	timeout = jiffies + msecs_to_jiffies(100);
@@ -1319,16 +1409,21 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
 	return 0;
 	return 0;
 }
 }
 
 
-static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
+static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
 {
 {
 	u32			reg;
 	u32			reg;
 	u32			timeout = 500;
 	u32			timeout = 500;
 
 
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 	if (is_on) {
 	if (is_on) {
-		reg &= ~DWC3_DCTL_TRGTULST_MASK;
-		reg |= (DWC3_DCTL_RUN_STOP
-				| DWC3_DCTL_TRGTULST_RX_DET);
+		if (dwc->revision <= DWC3_REVISION_187A) {
+			reg &= ~DWC3_DCTL_TRGTULST_MASK;
+			reg |= DWC3_DCTL_TRGTULST_RX_DET;
+		}
+
+		if (dwc->revision >= DWC3_REVISION_194A)
+			reg &= ~DWC3_DCTL_KEEP_CONNECT;
+		reg |= DWC3_DCTL_RUN_STOP;
 	} else {
 	} else {
 		reg &= ~DWC3_DCTL_RUN_STOP;
 		reg &= ~DWC3_DCTL_RUN_STOP;
 	}
 	}
@@ -1346,7 +1441,7 @@ static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
 		}
 		}
 		timeout--;
 		timeout--;
 		if (!timeout)
 		if (!timeout)
-			break;
+			return -ETIMEDOUT;
 		udelay(1);
 		udelay(1);
 	} while (1);
 	} while (1);
 
 
@@ -1354,20 +1449,23 @@ static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
 			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");
+
+	return 0;
 }
 }
 
 
 static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
 static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
 {
 {
 	struct dwc3		*dwc = gadget_to_dwc(g);
 	struct dwc3		*dwc = gadget_to_dwc(g);
 	unsigned long		flags;
 	unsigned long		flags;
+	int			ret;
 
 
 	is_on = !!is_on;
 	is_on = !!is_on;
 
 
 	spin_lock_irqsave(&dwc->lock, flags);
 	spin_lock_irqsave(&dwc->lock, flags);
-	dwc3_gadget_run_stop(dwc, is_on);
+	ret = dwc3_gadget_run_stop(dwc, is_on);
 	spin_unlock_irqrestore(&dwc->lock, flags);
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 
-	return 0;
+	return ret;
 }
 }
 
 
 static int dwc3_gadget_start(struct usb_gadget *g,
 static int dwc3_gadget_start(struct usb_gadget *g,
@@ -1468,6 +1566,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
 
 
 	return 0;
 	return 0;
 }
 }
+
 static const struct usb_gadget_ops dwc3_gadget_ops = {
 static const struct usb_gadget_ops dwc3_gadget_ops = {
 	.get_frame		= dwc3_gadget_get_frame,
 	.get_frame		= dwc3_gadget_get_frame,
 	.wakeup			= dwc3_gadget_wakeup,
 	.wakeup			= dwc3_gadget_wakeup,
@@ -1558,6 +1657,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
 	struct dwc3_trb		*trb;
 	struct dwc3_trb		*trb;
 	unsigned int		count;
 	unsigned int		count;
 	unsigned int		s_pkt = 0;
 	unsigned int		s_pkt = 0;
+	unsigned int		trb_status;
 
 
 	do {
 	do {
 		req = next_request(&dep->req_queued);
 		req = next_request(&dep->req_queued);
@@ -1583,9 +1683,18 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
 
 
 		if (dep->direction) {
 		if (dep->direction) {
 			if (count) {
 			if (count) {
-				dev_err(dwc->dev, "incomplete IN transfer %s\n",
-						dep->name);
-				status = -ECONNRESET;
+				trb_status = DWC3_TRB_SIZE_TRBSTS(trb->size);
+				if (trb_status == DWC3_TRBSTS_MISSED_ISOC) {
+					dev_dbg(dwc->dev, "incomplete IN transfer %s\n",
+							dep->name);
+					dep->current_uf = event->parameters &
+						~(dep->interval - 1);
+					dep->flags |= DWC3_EP_MISSED_ISOC;
+				} else {
+					dev_err(dwc->dev, "incomplete IN transfer %s\n",
+							dep->name);
+					status = -ECONNRESET;
+				}
 			}
 			}
 		} else {
 		} else {
 			if (count && (event->status & DEPEVT_STATUS_SHORT))
 			if (count && (event->status & DEPEVT_STATUS_SHORT))
@@ -1604,7 +1713,8 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
 		if (s_pkt)
 		if (s_pkt)
 			break;
 			break;
 		if ((event->status & DEPEVT_STATUS_LST) &&
 		if ((event->status & DEPEVT_STATUS_LST) &&
-				(trb->ctrl & DWC3_TRB_CTRL_LST))
+				(trb->ctrl & (DWC3_TRB_CTRL_LST |
+						DWC3_TRB_CTRL_HWO)))
 			break;
 			break;
 		if ((event->status & DEPEVT_STATUS_IOC) &&
 		if ((event->status & DEPEVT_STATUS_IOC) &&
 				(trb->ctrl & DWC3_TRB_CTRL_IOC))
 				(trb->ctrl & DWC3_TRB_CTRL_IOC))
@@ -1657,65 +1767,6 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
 	}
 	}
 }
 }
 
 
-static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
-		struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
-{
-	u32 uf, mask;
-
-	if (list_empty(&dep->request_list)) {
-		dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
-			dep->name);
-		return;
-	}
-
-	mask = ~(dep->interval - 1);
-	uf = event->parameters & mask;
-	/* 4 micro frames in the future */
-	uf += dep->interval * 4;
-
-	__dwc3_gadget_kick_transfer(dep, uf, 1);
-}
-
-static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep,
-		const struct dwc3_event_depevt *event)
-{
-	struct dwc3 *dwc = dep->dwc;
-	struct dwc3_event_depevt mod_ev = *event;
-
-	/*
-	 * We were asked to remove one request. It is possible that this
-	 * request and a few others were started together and have the same
-	 * transfer index. Since we stopped the complete endpoint we don't
-	 * know how many requests were already completed (and not yet)
-	 * reported and how could be done (later). We purge them all until
-	 * the end of the list.
-	 */
-	mod_ev.status = DEPEVT_STATUS_LST;
-	dwc3_cleanup_done_reqs(dwc, dep, &mod_ev, -ESHUTDOWN);
-	dep->flags &= ~DWC3_EP_BUSY;
-	/* pending requests are ignored and are queued on XferNotReady */
-}
-
-static void dwc3_ep_cmd_compl(struct dwc3_ep *dep,
-		const struct dwc3_event_depevt *event)
-{
-	u32 param = event->parameters;
-	u32 cmd_type = (param >> 8) & ((1 << 5) - 1);
-
-	switch (cmd_type) {
-	case DWC3_DEPCMD_ENDTRANSFER:
-		dwc3_process_ep_cmd_complete(dep, event);
-		break;
-	case DWC3_DEPCMD_STARTTRANSFER:
-		dep->res_trans_idx = param & 0x7f;
-		break;
-	default:
-		printk(KERN_ERR "%s() unknown /unexpected type: %d\n",
-				__func__, cmd_type);
-		break;
-	};
-}
-
 static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
 static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
 		const struct dwc3_event_depevt *event)
 		const struct dwc3_event_depevt *event)
 {
 {
@@ -1724,6 +1775,9 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
 
 
 	dep = dwc->eps[epnum];
 	dep = dwc->eps[epnum];
 
 
+	if (!(dep->flags & DWC3_EP_ENABLED))
+		return;
+
 	dev_vdbg(dwc->dev, "%s: %s\n", dep->name,
 	dev_vdbg(dwc->dev, "%s: %s\n", dep->name,
 			dwc3_ep_event_string(event->endpoint_event));
 			dwc3_ep_event_string(event->endpoint_event));
 
 
@@ -1734,7 +1788,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
 
 
 	switch (event->endpoint_event) {
 	switch (event->endpoint_event) {
 	case DWC3_DEPEVT_XFERCOMPLETE:
 	case DWC3_DEPEVT_XFERCOMPLETE:
-		dep->res_trans_idx = 0;
+		dep->resource_index = 0;
 
 
 		if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
 		if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
 			dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
 			dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
@@ -1797,7 +1851,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:
-		dwc3_ep_cmd_compl(dep, event);
+		dev_vdbg(dwc->dev, "Endpoint Command Complete\n");
 		break;
 		break;
 	}
 	}
 }
 }
@@ -1820,16 +1874,16 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
 
 
 	dep = dwc->eps[epnum];
 	dep = dwc->eps[epnum];
 
 
-	WARN_ON(!dep->res_trans_idx);
-	if (dep->res_trans_idx) {
-		cmd = DWC3_DEPCMD_ENDTRANSFER;
-		cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC;
-		cmd |= DWC3_DEPCMD_PARAM(dep->res_trans_idx);
-		memset(&params, 0, sizeof(params));
-		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
-		WARN_ON_ONCE(ret);
-		dep->res_trans_idx = 0;
-	}
+	if (!dep->resource_index)
+		return;
+
+	cmd = DWC3_DEPCMD_ENDTRANSFER;
+	cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC;
+	cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
+	memset(&params, 0, sizeof(params));
+	ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
+	WARN_ON_ONCE(ret);
+	dep->resource_index = 0;
 }
 }
 
 
 static void dwc3_stop_active_transfers(struct dwc3 *dwc)
 static void dwc3_stop_active_transfers(struct dwc3 *dwc)
@@ -1872,11 +1926,9 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
 
 
 static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
 static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
 {
 {
+	int			reg;
+
 	dev_vdbg(dwc->dev, "%s\n", __func__);
 	dev_vdbg(dwc->dev, "%s\n", __func__);
-#if 0
-	XXX
-	U1/U2 is powersave optimization. Skip it for now. Anyway we need to
-	enable it before we can disable it.
 
 
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 	reg &= ~DWC3_DCTL_INITU1ENA;
 	reg &= ~DWC3_DCTL_INITU1ENA;
@@ -1884,9 +1936,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
 
 
 	reg &= ~DWC3_DCTL_INITU2ENA;
 	reg &= ~DWC3_DCTL_INITU2ENA;
 	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
-#endif
 
 
-	dwc3_stop_active_transfers(dwc);
 	dwc3_disconnect_gadget(dwc);
 	dwc3_disconnect_gadget(dwc);
 	dwc->start_config_issued = false;
 	dwc->start_config_issued = false;
 
 
@@ -1894,30 +1944,30 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
 	dwc->setup_packet_pending = false;
 	dwc->setup_packet_pending = false;
 }
 }
 
 
-static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on)
+static void dwc3_gadget_usb3_phy_suspend(struct dwc3 *dwc, int suspend)
 {
 {
 	u32			reg;
 	u32			reg;
 
 
 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
 
 
-	if (on)
-		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
-	else
+	if (suspend)
 		reg |= DWC3_GUSB3PIPECTL_SUSPHY;
 		reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+	else
+		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
 
 
 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
 }
 }
 
 
-static void dwc3_gadget_usb2_phy_power(struct dwc3 *dwc, int on)
+static void dwc3_gadget_usb2_phy_suspend(struct dwc3 *dwc, int suspend)
 {
 {
 	u32			reg;
 	u32			reg;
 
 
 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
 
 
-	if (on)
-		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
-	else
+	if (suspend)
 		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
 		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+	else
+		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
 
 
 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 }
 }
@@ -1962,16 +2012,18 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
 	/* after reset -> Default State */
 	/* after reset -> Default State */
 	dwc->dev_state = DWC3_DEFAULT_STATE;
 	dwc->dev_state = DWC3_DEFAULT_STATE;
 
 
-	/* Enable PHYs */
-	dwc3_gadget_usb2_phy_power(dwc, true);
-	dwc3_gadget_usb3_phy_power(dwc, true);
+	/* Recent versions support automatic phy suspend and don't need this */
+	if (dwc->revision < DWC3_REVISION_194A) {
+		/* Resume PHYs */
+		dwc3_gadget_usb2_phy_suspend(dwc, false);
+		dwc3_gadget_usb3_phy_suspend(dwc, false);
+	}
 
 
 	if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
 	if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
 		dwc3_disconnect_gadget(dwc);
 		dwc3_disconnect_gadget(dwc);
 
 
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 	reg &= ~DWC3_DCTL_TSTCTRL_MASK;
 	reg &= ~DWC3_DCTL_TSTCTRL_MASK;
-	reg &= ~(DWC3_DCTL_INITU1ENA | DWC3_DCTL_INITU2ENA);
 	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 	dwc->test_mode = false;
 	dwc->test_mode = false;
 
 
@@ -2010,16 +2062,16 @@ static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed)
 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 }
 }
 
 
-static void dwc3_gadget_disable_phy(struct dwc3 *dwc, u8 speed)
+static void dwc3_gadget_phy_suspend(struct dwc3 *dwc, u8 speed)
 {
 {
 	switch (speed) {
 	switch (speed) {
 	case USB_SPEED_SUPER:
 	case USB_SPEED_SUPER:
-		dwc3_gadget_usb2_phy_power(dwc, false);
+		dwc3_gadget_usb2_phy_suspend(dwc, true);
 		break;
 		break;
 	case USB_SPEED_HIGH:
 	case USB_SPEED_HIGH:
 	case USB_SPEED_FULL:
 	case USB_SPEED_FULL:
 	case USB_SPEED_LOW:
 	case USB_SPEED_LOW:
-		dwc3_gadget_usb3_phy_power(dwc, false);
+		dwc3_gadget_usb3_phy_suspend(dwc, true);
 		break;
 		break;
 	}
 	}
 }
 }
@@ -2082,8 +2134,11 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
 		break;
 		break;
 	}
 	}
 
 
-	/* Disable unneded PHY */
-	dwc3_gadget_disable_phy(dwc, dwc->gadget.speed);
+	/* Recent versions support automatic phy suspend and don't need this */
+	if (dwc->revision < DWC3_REVISION_194A) {
+		/* Suspend unneeded PHY */
+		dwc3_gadget_phy_suspend(dwc, dwc->gadget.speed);
+	}
 
 
 	dep = dwc->eps[0];
 	dep = dwc->eps[0];
 	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
 	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
@@ -2373,10 +2428,6 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
 	reg |= DWC3_DCFG_LPM_CAP;
 	reg |= DWC3_DCFG_LPM_CAP;
 	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
 	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
 
 
-	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
-	reg |= DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA;
-	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
-
 	/* Enable all but Start and End of Frame IRQs */
 	/* Enable all but Start and End of Frame IRQs */
 	reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
 	reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
 			DWC3_DEVTEN_EVNTOVERFLOWEN |
 			DWC3_DEVTEN_EVNTOVERFLOWEN |
@@ -2389,6 +2440,24 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
 			DWC3_DEVTEN_DISCONNEVTEN);
 			DWC3_DEVTEN_DISCONNEVTEN);
 	dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
 	dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
 
 
+	/* Enable USB2 LPM and automatic phy suspend only on recent versions */
+	if (dwc->revision >= DWC3_REVISION_194A) {
+		reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+		reg |= DWC3_DCFG_LPM_CAP;
+		dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+		reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN);
+
+		/* TODO: This should be configurable */
+		reg |= DWC3_DCTL_HIRD_THRES(28);
+
+		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+		dwc3_gadget_usb2_phy_suspend(dwc, false);
+		dwc3_gadget_usb3_phy_suspend(dwc, false);
+	}
+
 	ret = device_register(&dwc->gadget.dev);
 	ret = device_register(&dwc->gadget.dev);
 	if (ret) {
 	if (ret) {
 		dev_err(dwc->dev, "failed to register gadget device\n");
 		dev_err(dwc->dev, "failed to register gadget device\n");

+ 6 - 0
drivers/usb/dwc3/gadget.h

@@ -66,7 +66,12 @@ struct dwc3;
 #define DWC3_DEPCFG_FIFO_NUMBER(n)	((n) << 17)
 #define DWC3_DEPCFG_FIFO_NUMBER(n)	((n) << 17)
 #define DWC3_DEPCFG_BURST_SIZE(n)	((n) << 22)
 #define DWC3_DEPCFG_BURST_SIZE(n)	((n) << 22)
 #define DWC3_DEPCFG_DATA_SEQ_NUM(n)	((n) << 26)
 #define DWC3_DEPCFG_DATA_SEQ_NUM(n)	((n) << 26)
+/* This applies for core versions earlier than 1.94a */
 #define DWC3_DEPCFG_IGN_SEQ_NUM		(1 << 31)
 #define DWC3_DEPCFG_IGN_SEQ_NUM		(1 << 31)
+/* These apply for core versions 1.94a and later */
+#define DWC3_DEPCFG_ACTION_INIT		(0 << 30)
+#define DWC3_DEPCFG_ACTION_RESTORE	(1 << 30)
+#define DWC3_DEPCFG_ACTION_MODIFY	(2 << 30)
 
 
 /* DEPXFERCFG parameter 0 */
 /* DEPXFERCFG parameter 0 */
 #define DWC3_DEPXFERCFG_NUM_XFER_RES(n)	((n) & 0xffff)
 #define DWC3_DEPXFERCFG_NUM_XFER_RES(n)	((n) & 0xffff)
@@ -106,6 +111,7 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
 void dwc3_ep0_interrupt(struct dwc3 *dwc,
 void dwc3_ep0_interrupt(struct dwc3 *dwc,
 		const struct dwc3_event_depevt *event);
 		const struct dwc3_event_depevt *event);
 void dwc3_ep0_out_start(struct dwc3 *dwc);
 void dwc3_ep0_out_start(struct dwc3 *dwc);
+int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);
 int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
 int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
 		gfp_t gfp_flags);
 		gfp_t gfp_flags);
 int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
 int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);

+ 1 - 1
drivers/usb/early/ehci-dbgp.c

@@ -334,7 +334,7 @@ static int dbgp_control_msg(unsigned devnum, int requesttype,
 	int ret;
 	int ret;
 
 
 	read = (requesttype & USB_DIR_IN) != 0;
 	read = (requesttype & USB_DIR_IN) != 0;
-	if (size > (read ? DBGP_MAX_PACKET:0))
+	if (size > (read ? DBGP_MAX_PACKET : 0))
 		return -1;
 		return -1;
 
 
 	/* Compute the control message */
 	/* Compute the control message */

+ 9 - 0
drivers/usb/gadget/Kconfig

@@ -321,6 +321,15 @@ config USB_MV_UDC
 	  USB2.0 OTG controller, which can be configured as high speed or
 	  USB2.0 OTG controller, which can be configured as high speed or
 	  full speed USB peripheral.
 	  full speed USB peripheral.
 
 
+config USB_MV_U3D
+	tristate "MARVELL PXA2128 USB 3.0 controller"
+	depends on CPU_MMP3
+	select USB_GADGET_DUALSPEED
+	select USB_GADGET_SUPERSPEED
+	help
+	  MARVELL PXA2128 Processor series include a super speed USB3.0 device
+	  controller, which support super speed USB peripheral.
+
 #
 #
 # Controllers available in both integrated and discrete versions
 # Controllers available in both integrated and discrete versions
 #
 #

+ 1 - 0
drivers/usb/gadget/Makefile

@@ -29,6 +29,7 @@ obj-$(CONFIG_USB_EG20T)		+= pch_udc.o
 obj-$(CONFIG_USB_MV_UDC)	+= mv_udc.o
 obj-$(CONFIG_USB_MV_UDC)	+= mv_udc.o
 mv_udc-y			:= mv_udc_core.o
 mv_udc-y			:= mv_udc_core.o
 obj-$(CONFIG_USB_FUSB300)	+= fusb300_udc.o
 obj-$(CONFIG_USB_FUSB300)	+= fusb300_udc.o
+obj-$(CONFIG_USB_MV_U3D)	+= mv_u3d_core.o
 
 
 #
 #
 # USB gadget drivers
 # USB gadget drivers

+ 1 - 0
drivers/usb/gadget/acm_ms.c

@@ -235,6 +235,7 @@ static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
 static struct usb_composite_driver acm_ms_driver = {
 static struct usb_composite_driver acm_ms_driver = {
 	.name		= "g_acm_ms",
 	.name		= "g_acm_ms",
 	.dev		= &device_desc,
 	.dev		= &device_desc,
+	.max_speed	= USB_SPEED_SUPER,
 	.strings	= dev_strings,
 	.strings	= dev_strings,
 	.unbind		= __exit_p(acm_ms_unbind),
 	.unbind		= __exit_p(acm_ms_unbind),
 };
 };

+ 1 - 0
drivers/usb/gadget/at91_udc.c

@@ -1634,6 +1634,7 @@ static int at91_start(struct usb_gadget *gadget,
 	udc = container_of(gadget, struct at91_udc, gadget);
 	udc = container_of(gadget, struct at91_udc, gadget);
 	udc->driver = driver;
 	udc->driver = driver;
 	udc->gadget.dev.driver = &driver->driver;
 	udc->gadget.dev.driver = &driver->driver;
+	udc->gadget.dev.of_node = udc->pdev->dev.of_node;
 	dev_set_drvdata(&udc->gadget.dev, &driver->driver);
 	dev_set_drvdata(&udc->gadget.dev, &driver->driver);
 	udc->enabled = 1;
 	udc->enabled = 1;
 	udc->selfpowered = 1;
 	udc->selfpowered = 1;

+ 5 - 2
drivers/usb/gadget/composite.c

@@ -117,6 +117,7 @@ int config_ep_by_speed(struct usb_gadget *g,
 			struct usb_function *f,
 			struct usb_function *f,
 			struct usb_ep *_ep)
 			struct usb_ep *_ep)
 {
 {
+	struct usb_composite_dev	*cdev = get_gadget_data(g);
 	struct usb_endpoint_descriptor *chosen_desc = NULL;
 	struct usb_endpoint_descriptor *chosen_desc = NULL;
 	struct usb_descriptor_header **speed_desc = NULL;
 	struct usb_descriptor_header **speed_desc = NULL;
 
 
@@ -180,10 +181,12 @@ ep_found:
 			_ep->mult = comp_desc->bmAttributes & 0x3;
 			_ep->mult = comp_desc->bmAttributes & 0x3;
 		case USB_ENDPOINT_XFER_BULK:
 		case USB_ENDPOINT_XFER_BULK:
 		case USB_ENDPOINT_XFER_INT:
 		case USB_ENDPOINT_XFER_INT:
-			_ep->maxburst = comp_desc->bMaxBurst;
+			_ep->maxburst = comp_desc->bMaxBurst + 1;
 			break;
 			break;
 		default:
 		default:
-			/* Do nothing for control endpoints */
+			if (comp_desc->bMaxBurst != 0)
+				ERROR(cdev, "ep0 bMaxBurst must be 0\n");
+			_ep->maxburst = 1;
 			break;
 			break;
 		}
 		}
 	}
 	}

+ 7 - 0
drivers/usb/gadget/f_fs.c

@@ -21,6 +21,7 @@
 #include <linux/blkdev.h>
 #include <linux/blkdev.h>
 #include <linux/pagemap.h>
 #include <linux/pagemap.h>
 #include <linux/export.h>
 #include <linux/export.h>
+#include <linux/hid.h>
 #include <asm/unaligned.h>
 #include <asm/unaligned.h>
 
 
 #include <linux/usb/composite.h>
 #include <linux/usb/composite.h>
@@ -1671,6 +1672,12 @@ static int __must_check ffs_do_desc(char *data, unsigned len,
 	}
 	}
 		break;
 		break;
 
 
+	case HID_DT_HID:
+		pr_vdebug("hid descriptor\n");
+		if (length != sizeof(struct hid_descriptor))
+			goto inv_length;
+		break;
+
 	case USB_DT_OTG:
 	case USB_DT_OTG:
 		if (length != sizeof(struct usb_otg_descriptor))
 		if (length != sizeof(struct usb_otg_descriptor))
 			goto inv_length;
 			goto inv_length;

+ 165 - 43
drivers/usb/gadget/f_hid.c

@@ -26,6 +26,12 @@ static struct class *hidg_class;
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 /*                            HID gadget struct                            */
 /*                            HID gadget struct                            */
 
 
+struct f_hidg_req_list {
+	struct usb_request	*req;
+	unsigned int		pos;
+	struct list_head 	list;
+};
+
 struct f_hidg {
 struct f_hidg {
 	/* configuration */
 	/* configuration */
 	unsigned char			bInterfaceSubClass;
 	unsigned char			bInterfaceSubClass;
@@ -35,10 +41,10 @@ struct f_hidg {
 	unsigned short			report_length;
 	unsigned short			report_length;
 
 
 	/* recv report */
 	/* recv report */
-	char				*set_report_buff;
-	unsigned short			set_report_length;
+	struct list_head		completed_out_req;
 	spinlock_t			spinlock;
 	spinlock_t			spinlock;
 	wait_queue_head_t		read_queue;
 	wait_queue_head_t		read_queue;
+	unsigned int			qlen;
 
 
 	/* send report */
 	/* send report */
 	struct mutex			lock;
 	struct mutex			lock;
@@ -49,7 +55,9 @@ struct f_hidg {
 	int				minor;
 	int				minor;
 	struct cdev			cdev;
 	struct cdev			cdev;
 	struct usb_function		func;
 	struct usb_function		func;
+
 	struct usb_ep			*in_ep;
 	struct usb_ep			*in_ep;
+	struct usb_ep			*out_ep;
 };
 };
 
 
 static inline struct f_hidg *func_to_hidg(struct usb_function *f)
 static inline struct f_hidg *func_to_hidg(struct usb_function *f)
@@ -65,7 +73,7 @@ static struct usb_interface_descriptor hidg_interface_desc = {
 	.bDescriptorType	= USB_DT_INTERFACE,
 	.bDescriptorType	= USB_DT_INTERFACE,
 	/* .bInterfaceNumber	= DYNAMIC */
 	/* .bInterfaceNumber	= DYNAMIC */
 	.bAlternateSetting	= 0,
 	.bAlternateSetting	= 0,
-	.bNumEndpoints		= 1,
+	.bNumEndpoints		= 2,
 	.bInterfaceClass	= USB_CLASS_HID,
 	.bInterfaceClass	= USB_CLASS_HID,
 	/* .bInterfaceSubClass	= DYNAMIC */
 	/* .bInterfaceSubClass	= DYNAMIC */
 	/* .bInterfaceProtocol	= DYNAMIC */
 	/* .bInterfaceProtocol	= DYNAMIC */
@@ -96,10 +104,23 @@ static struct usb_endpoint_descriptor hidg_hs_in_ep_desc = {
 				      */
 				      */
 };
 };
 
 
+static struct usb_endpoint_descriptor hidg_hs_out_ep_desc = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_OUT,
+	.bmAttributes		= USB_ENDPOINT_XFER_INT,
+	/*.wMaxPacketSize	= DYNAMIC */
+	.bInterval		= 4, /* FIXME: Add this field in the
+				      * HID gadget configuration?
+				      * (struct hidg_func_descriptor)
+				      */
+};
+
 static struct usb_descriptor_header *hidg_hs_descriptors[] = {
 static struct usb_descriptor_header *hidg_hs_descriptors[] = {
 	(struct usb_descriptor_header *)&hidg_interface_desc,
 	(struct usb_descriptor_header *)&hidg_interface_desc,
 	(struct usb_descriptor_header *)&hidg_desc,
 	(struct usb_descriptor_header *)&hidg_desc,
 	(struct usb_descriptor_header *)&hidg_hs_in_ep_desc,
 	(struct usb_descriptor_header *)&hidg_hs_in_ep_desc,
+	(struct usb_descriptor_header *)&hidg_hs_out_ep_desc,
 	NULL,
 	NULL,
 };
 };
 
 
@@ -117,10 +138,23 @@ static struct usb_endpoint_descriptor hidg_fs_in_ep_desc = {
 				       */
 				       */
 };
 };
 
 
+static struct usb_endpoint_descriptor hidg_fs_out_ep_desc = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_OUT,
+	.bmAttributes		= USB_ENDPOINT_XFER_INT,
+	/*.wMaxPacketSize	= DYNAMIC */
+	.bInterval		= 10, /* FIXME: Add this field in the
+				       * HID gadget configuration?
+				       * (struct hidg_func_descriptor)
+				       */
+};
+
 static struct usb_descriptor_header *hidg_fs_descriptors[] = {
 static struct usb_descriptor_header *hidg_fs_descriptors[] = {
 	(struct usb_descriptor_header *)&hidg_interface_desc,
 	(struct usb_descriptor_header *)&hidg_interface_desc,
 	(struct usb_descriptor_header *)&hidg_desc,
 	(struct usb_descriptor_header *)&hidg_desc,
 	(struct usb_descriptor_header *)&hidg_fs_in_ep_desc,
 	(struct usb_descriptor_header *)&hidg_fs_in_ep_desc,
+	(struct usb_descriptor_header *)&hidg_fs_out_ep_desc,
 	NULL,
 	NULL,
 };
 };
 
 
@@ -130,9 +164,11 @@ static struct usb_descriptor_header *hidg_fs_descriptors[] = {
 static ssize_t f_hidg_read(struct file *file, char __user *buffer,
 static ssize_t f_hidg_read(struct file *file, char __user *buffer,
 			size_t count, loff_t *ptr)
 			size_t count, loff_t *ptr)
 {
 {
-	struct f_hidg	*hidg     = file->private_data;
-	char		*tmp_buff = NULL;
-	unsigned long	flags;
+	struct f_hidg *hidg = file->private_data;
+	struct f_hidg_req_list *list;
+	struct usb_request *req;
+	unsigned long flags;
+	int ret;
 
 
 	if (!count)
 	if (!count)
 		return 0;
 		return 0;
@@ -142,8 +178,9 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer,
 
 
 	spin_lock_irqsave(&hidg->spinlock, flags);
 	spin_lock_irqsave(&hidg->spinlock, flags);
 
 
-#define READ_COND (hidg->set_report_buff != NULL)
+#define READ_COND (!list_empty(&hidg->completed_out_req))
 
 
+	/* wait for at least one buffer to complete */
 	while (!READ_COND) {
 	while (!READ_COND) {
 		spin_unlock_irqrestore(&hidg->spinlock, flags);
 		spin_unlock_irqrestore(&hidg->spinlock, flags);
 		if (file->f_flags & O_NONBLOCK)
 		if (file->f_flags & O_NONBLOCK)
@@ -155,19 +192,34 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer,
 		spin_lock_irqsave(&hidg->spinlock, flags);
 		spin_lock_irqsave(&hidg->spinlock, flags);
 	}
 	}
 
 
-
-	count = min_t(unsigned, count, hidg->set_report_length);
-	tmp_buff = hidg->set_report_buff;
-	hidg->set_report_buff = NULL;
-
+	/* pick the first one */
+	list = list_first_entry(&hidg->completed_out_req,
+				struct f_hidg_req_list, list);
+	req = list->req;
+	count = min_t(unsigned int, count, req->actual - list->pos);
 	spin_unlock_irqrestore(&hidg->spinlock, flags);
 	spin_unlock_irqrestore(&hidg->spinlock, flags);
 
 
-	if (tmp_buff != NULL) {
-		/* copy to user outside spinlock */
-		count -= copy_to_user(buffer, tmp_buff, count);
-		kfree(tmp_buff);
-	} else
-		count = -ENOMEM;
+	/* copy to user outside spinlock */
+	count -= copy_to_user(buffer, req->buf + list->pos, count);
+	list->pos += count;
+
+	/*
+	 * if this request is completely handled and transfered to
+	 * userspace, remove its entry from the list and requeue it
+	 * again. Otherwise, we will revisit it again upon the next
+	 * call, taking into account its current read position.
+	 */
+	if (list->pos == req->actual) {
+		spin_lock_irqsave(&hidg->spinlock, flags);
+		list_del(&list->list);
+		kfree(list);
+		spin_unlock_irqrestore(&hidg->spinlock, flags);
+
+		req->length = hidg->report_length;
+		ret = usb_ep_queue(hidg->out_ep, req, GFP_KERNEL);
+		if (ret < 0)
+			return ret;
+	}
 
 
 	return count;
 	return count;
 }
 }
@@ -282,28 +334,37 @@ static int f_hidg_open(struct inode *inode, struct file *fd)
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 /*                                usb_function                             */
 /*                                usb_function                             */
 
 
-static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req)
+static struct usb_request *hidg_alloc_ep_req(struct usb_ep *ep, unsigned length)
 {
 {
-	struct f_hidg *hidg = (struct f_hidg *)req->context;
-
-	if (req->status != 0 || req->buf == NULL || req->actual == 0) {
-		ERROR(hidg->func.config->cdev, "%s FAILED\n", __func__);
-		return;
+	struct usb_request *req;
+
+	req = usb_ep_alloc_request(ep, GFP_ATOMIC);
+	if (req) {
+		req->length = length;
+		req->buf = kmalloc(length, GFP_ATOMIC);
+		if (!req->buf) {
+			usb_ep_free_request(ep, req);
+			req = NULL;
+		}
 	}
 	}
+	return req;
+}
 
 
-	spin_lock(&hidg->spinlock);
-
-	hidg->set_report_buff = krealloc(hidg->set_report_buff,
-					 req->actual, GFP_ATOMIC);
+static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_hidg *hidg = (struct f_hidg *) req->context;
+	struct f_hidg_req_list *req_list;
+	unsigned long flags;
 
 
-	if (hidg->set_report_buff == NULL) {
-		spin_unlock(&hidg->spinlock);
+	req_list = kzalloc(sizeof(*req_list), GFP_ATOMIC);
+	if (!req_list)
 		return;
 		return;
-	}
-	hidg->set_report_length = req->actual;
-	memcpy(hidg->set_report_buff, req->buf, req->actual);
 
 
-	spin_unlock(&hidg->spinlock);
+	req_list->req = req;
+
+	spin_lock_irqsave(&hidg->spinlock, flags);
+	list_add_tail(&req_list->list, &hidg->completed_out_req);
+	spin_unlock_irqrestore(&hidg->spinlock, flags);
 
 
 	wake_up(&hidg->read_queue);
 	wake_up(&hidg->read_queue);
 }
 }
@@ -344,9 +405,7 @@ static int hidg_setup(struct usb_function *f,
 	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
 	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
 		  | HID_REQ_SET_REPORT):
 		  | HID_REQ_SET_REPORT):
 		VDBG(cdev, "set_report | wLenght=%d\n", ctrl->wLength);
 		VDBG(cdev, "set_report | wLenght=%d\n", ctrl->wLength);
-		req->context  = hidg;
-		req->complete = hidg_set_report_complete;
-		goto respond;
+		goto stall;
 		break;
 		break;
 
 
 	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
 	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
@@ -403,16 +462,25 @@ respond:
 static void hidg_disable(struct usb_function *f)
 static void hidg_disable(struct usb_function *f)
 {
 {
 	struct f_hidg *hidg = func_to_hidg(f);
 	struct f_hidg *hidg = func_to_hidg(f);
+	struct f_hidg_req_list *list, *next;
 
 
 	usb_ep_disable(hidg->in_ep);
 	usb_ep_disable(hidg->in_ep);
 	hidg->in_ep->driver_data = NULL;
 	hidg->in_ep->driver_data = NULL;
+
+	usb_ep_disable(hidg->out_ep);
+	hidg->out_ep->driver_data = NULL;
+
+	list_for_each_entry_safe(list, next, &hidg->completed_out_req, list) {
+		list_del(&list->list);
+		kfree(list);
+	}
 }
 }
 
 
 static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 {
 	struct usb_composite_dev		*cdev = f->config->cdev;
 	struct usb_composite_dev		*cdev = f->config->cdev;
 	struct f_hidg				*hidg = func_to_hidg(f);
 	struct f_hidg				*hidg = func_to_hidg(f);
-	int status = 0;
+	int i, status = 0;
 
 
 	VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt);
 	VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt);
 
 
@@ -429,11 +497,55 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		}
 		}
 		status = usb_ep_enable(hidg->in_ep);
 		status = usb_ep_enable(hidg->in_ep);
 		if (status < 0) {
 		if (status < 0) {
-			ERROR(cdev, "Enable endpoint FAILED!\n");
+			ERROR(cdev, "Enable IN endpoint FAILED!\n");
 			goto fail;
 			goto fail;
 		}
 		}
 		hidg->in_ep->driver_data = hidg;
 		hidg->in_ep->driver_data = hidg;
 	}
 	}
+
+
+	if (hidg->out_ep != NULL) {
+		/* restart endpoint */
+		if (hidg->out_ep->driver_data != NULL)
+			usb_ep_disable(hidg->out_ep);
+
+		status = config_ep_by_speed(f->config->cdev->gadget, f,
+					    hidg->out_ep);
+		if (status) {
+			ERROR(cdev, "config_ep_by_speed FAILED!\n");
+			goto fail;
+		}
+		status = usb_ep_enable(hidg->out_ep);
+		if (status < 0) {
+			ERROR(cdev, "Enable IN endpoint FAILED!\n");
+			goto fail;
+		}
+		hidg->out_ep->driver_data = hidg;
+
+		/*
+		 * allocate a bunch of read buffers and queue them all at once.
+		 */
+		for (i = 0; i < hidg->qlen && status == 0; i++) {
+			struct usb_request *req =
+					hidg_alloc_ep_req(hidg->out_ep,
+							  hidg->report_length);
+			if (req) {
+				req->complete = hidg_set_report_complete;
+				req->context  = hidg;
+				status = usb_ep_queue(hidg->out_ep, req,
+						      GFP_ATOMIC);
+				if (status)
+					ERROR(cdev, "%s queue req --> %d\n",
+						hidg->out_ep->name, status);
+			} else {
+				usb_ep_disable(hidg->out_ep);
+				hidg->out_ep->driver_data = NULL;
+				status = -ENOMEM;
+				goto fail;
+			}
+		}
+	}
+
 fail:
 fail:
 	return status;
 	return status;
 }
 }
@@ -470,13 +582,18 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
 	ep->driver_data = c->cdev;	/* claim */
 	ep->driver_data = c->cdev;	/* claim */
 	hidg->in_ep = ep;
 	hidg->in_ep = ep;
 
 
+	ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_out_ep_desc);
+	if (!ep)
+		goto fail;
+	ep->driver_data = c->cdev;	/* claim */
+	hidg->out_ep = ep;
+
 	/* preallocate request and buffer */
 	/* preallocate request and buffer */
 	status = -ENOMEM;
 	status = -ENOMEM;
 	hidg->req = usb_ep_alloc_request(hidg->in_ep, GFP_KERNEL);
 	hidg->req = usb_ep_alloc_request(hidg->in_ep, GFP_KERNEL);
 	if (!hidg->req)
 	if (!hidg->req)
 		goto fail;
 		goto fail;
 
 
-
 	hidg->req->buf = kmalloc(hidg->report_length, GFP_KERNEL);
 	hidg->req->buf = kmalloc(hidg->report_length, GFP_KERNEL);
 	if (!hidg->req->buf)
 	if (!hidg->req->buf)
 		goto fail;
 		goto fail;
@@ -486,12 +603,12 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
 	hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol;
 	hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol;
 	hidg_hs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
 	hidg_hs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
 	hidg_fs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
 	hidg_fs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
+	hidg_hs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
+	hidg_fs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
 	hidg_desc.desc[0].bDescriptorType = HID_DT_REPORT;
 	hidg_desc.desc[0].bDescriptorType = HID_DT_REPORT;
 	hidg_desc.desc[0].wDescriptorLength =
 	hidg_desc.desc[0].wDescriptorLength =
 		cpu_to_le16(hidg->report_desc_length);
 		cpu_to_le16(hidg->report_desc_length);
 
 
-	hidg->set_report_buff = NULL;
-
 	/* copy descriptors */
 	/* copy descriptors */
 	f->descriptors = usb_copy_descriptors(hidg_fs_descriptors);
 	f->descriptors = usb_copy_descriptors(hidg_fs_descriptors);
 	if (!f->descriptors)
 	if (!f->descriptors)
@@ -500,6 +617,8 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
 	if (gadget_is_dualspeed(c->cdev->gadget)) {
 	if (gadget_is_dualspeed(c->cdev->gadget)) {
 		hidg_hs_in_ep_desc.bEndpointAddress =
 		hidg_hs_in_ep_desc.bEndpointAddress =
 			hidg_fs_in_ep_desc.bEndpointAddress;
 			hidg_fs_in_ep_desc.bEndpointAddress;
+		hidg_hs_out_ep_desc.bEndpointAddress =
+			hidg_fs_out_ep_desc.bEndpointAddress;
 		f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors);
 		f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors);
 		if (!f->hs_descriptors)
 		if (!f->hs_descriptors)
 			goto fail;
 			goto fail;
@@ -509,6 +628,7 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
 	spin_lock_init(&hidg->spinlock);
 	spin_lock_init(&hidg->spinlock);
 	init_waitqueue_head(&hidg->write_queue);
 	init_waitqueue_head(&hidg->write_queue);
 	init_waitqueue_head(&hidg->read_queue);
 	init_waitqueue_head(&hidg->read_queue);
+	INIT_LIST_HEAD(&hidg->completed_out_req);
 
 
 	/* create char device */
 	/* create char device */
 	cdev_init(&hidg->cdev, &f_hidg_fops);
 	cdev_init(&hidg->cdev, &f_hidg_fops);
@@ -553,7 +673,6 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
 	usb_free_descriptors(f->descriptors);
 	usb_free_descriptors(f->descriptors);
 
 
 	kfree(hidg->report_desc);
 	kfree(hidg->report_desc);
-	kfree(hidg->set_report_buff);
 	kfree(hidg);
 	kfree(hidg);
 }
 }
 
 
@@ -624,6 +743,9 @@ int __init hidg_bind_config(struct usb_configuration *c,
 	hidg->func.disable = hidg_disable;
 	hidg->func.disable = hidg_disable;
 	hidg->func.setup   = hidg_setup;
 	hidg->func.setup   = hidg_setup;
 
 
+	/* this could me made configurable at some point */
+	hidg->qlen	   = 4;
+
 	status = usb_add_function(c, &hidg->func);
 	status = usb_add_function(c, &hidg->func);
 	if (status)
 	if (status)
 		kfree(hidg);
 		kfree(hidg);

+ 31 - 102
drivers/usb/gadget/f_mass_storage.c

@@ -44,12 +44,12 @@
  * function for a USB device, it also illustrates a technique of
  * function for a USB device, it also illustrates a technique of
  * double-buffering for increased throughput.
  * double-buffering for increased throughput.
  *
  *
- * Function supports multiple logical units (LUNs).  Backing storage
- * for each LUN is provided by a regular file or a block device.
- * Access for each LUN can be limited to read-only.  Moreover, the
- * function can indicate that LUN is removable and/or CD-ROM.  (The
- * later implies read-only access.)
- *
+ * For more information about MSF and in particular its module
+ * parameters and sysfs interface read the
+ * <Documentation/usb/mass-storage.txt> file.
+ */
+
+/*
  * MSF is configured by specifying a fsg_config structure.  It has the
  * MSF is configured by specifying a fsg_config structure.  It has the
  * following fields:
  * following fields:
  *
  *
@@ -75,25 +75,6 @@
  *	->nofua		Flag specifying that FUA flag in SCSI WRITE(10,12)
  *	->nofua		Flag specifying that FUA flag in SCSI WRITE(10,12)
  *				commands for this LUN shall be ignored.
  *				commands for this LUN shall be ignored.
  *
  *
- *	lun_name_format	A printf-like format for names of the LUN
- *				devices.  This determines how the
- *				directory in sysfs will be named.
- *				Unless you are using several MSFs in
- *				a single gadget (as opposed to single
- *				MSF in many configurations) you may
- *				leave it as NULL (in which case
- *				"lun%d" will be used).  In the format
- *				you can use "%d" to index LUNs for
- *				MSF's with more than one LUN.  (Beware
- *				that there is only one integer given
- *				as an argument for the format and
- *				specifying invalid format may cause
- *				unspecified behaviour.)
- *	thread_name	Name of the kernel thread process used by the
- *				MSF.  You can safely set it to NULL
- *				(in which case default "file-storage"
- *				will be used).
- *
  *	vendor_name
  *	vendor_name
  *	product_name
  *	product_name
  *	release		Information used as a reply to INQUIRY
  *	release		Information used as a reply to INQUIRY
@@ -114,62 +95,6 @@
  * data track and no audio tracks; hence there need be only one
  * data track and no audio tracks; hence there need be only one
  * backing file per LUN.
  * backing file per LUN.
  *
  *
- *
- * MSF includes support for module parameters.  If gadget using it
- * decides to use it, the following module parameters will be
- * available:
- *
- *	file=filename[,filename...]
- *			Names of the files or block devices used for
- *				backing storage.
- *	ro=b[,b...]	Default false, boolean for read-only access.
- *	removable=b[,b...]
- *			Default true, boolean for removable media.
- *	cdrom=b[,b...]	Default false, boolean for whether to emulate
- *				a CD-ROM drive.
- *	nofua=b[,b...]	Default false, booleans for ignore FUA flag
- *				in SCSI WRITE(10,12) commands
- *	luns=N		Default N = number of filenames, number of
- *				LUNs to support.
- *	stall		Default determined according to the type of
- *				USB device controller (usually true),
- *				boolean to permit the driver to halt
- *				bulk endpoints.
- *
- * The module parameters may be prefixed with some string.  You need
- * to consult gadget's documentation or source to verify whether it is
- * using those module parameters and if it does what are the prefixes
- * (look for FSG_MODULE_PARAMETERS() macro usage, what's inside it is
- * the prefix).
- *
- *
- * Requirements are modest; only a bulk-in and a bulk-out endpoint are
- * needed.  The memory requirement amounts to two 16K buffers, size
- * configurable by a parameter.  Support is included for both
- * full-speed and high-speed operation.
- *
- * Note that the driver is slightly non-portable in that it assumes a
- * single memory/DMA buffer will be useable for bulk-in, bulk-out, and
- * interrupt-in endpoints.  With most device controllers this isn't an
- * issue, but there may be some with hardware restrictions that prevent
- * a buffer from being used by more than one endpoint.
- *
- *
- * The pathnames of the backing files and the ro settings are
- * available in the attribute files "file" and "ro" in the lun<n> (or
- * to be more precise in a directory which name comes from
- * "lun_name_format" option!) subdirectory of the gadget's sysfs
- * directory.  If the "removable" option is set, writing to these
- * files will simulate ejecting/loading the medium (writing an empty
- * line means eject) and adjusting a write-enable tab.  Changes to the
- * ro setting are not allowed when the medium is loaded or if CD-ROM
- * emulation is being used.
- *
- * When a LUN receive an "eject" SCSI request (Start/Stop Unit),
- * if the LUN is removable, the backing file is released to simulate
- * ejection.
- *
- *
  * This function is heavily based on "File-backed Storage Gadget" by
  * This function is heavily based on "File-backed Storage Gadget" by
  * Alan Stern which in turn is heavily based on "Gadget Zero" by David
  * Alan Stern which in turn is heavily based on "Gadget Zero" by David
  * Brownell.  The driver's SCSI command interface was based on the
  * Brownell.  The driver's SCSI command interface was based on the
@@ -211,7 +136,7 @@
  * In normal operation the main thread is started during the gadget's
  * In normal operation the main thread is started during the gadget's
  * fsg_bind() callback and stopped during fsg_unbind().  But it can
  * fsg_bind() callback and stopped during fsg_unbind().  But it can
  * also exit when it receives a signal, and there's no point leaving
  * also exit when it receives a signal, and there's no point leaving
- * the gadget running when the thread is dead.  At of this moment, MSF
+ * the gadget running when the thread is dead.  As of this moment, MSF
  * provides no way to deregister the gadget when thread dies -- maybe
  * provides no way to deregister the gadget when thread dies -- maybe
  * a callback functions is needed.
  * a callback functions is needed.
  *
  *
@@ -417,9 +342,6 @@ struct fsg_config {
 		char nofua;
 		char nofua;
 	} luns[FSG_MAX_LUNS];
 	} luns[FSG_MAX_LUNS];
 
 
-	const char		*lun_name_format;
-	const char		*thread_name;
-
 	/* Callback functions. */
 	/* Callback functions. */
 	const struct fsg_operations	*ops;
 	const struct fsg_operations	*ops;
 	/* Gadget's private data. */
 	/* Gadget's private data. */
@@ -2687,11 +2609,15 @@ static int fsg_main_thread(void *common_)
 
 
 /*************************** DEVICE ATTRIBUTES ***************************/
 /*************************** DEVICE ATTRIBUTES ***************************/
 
 
-/* Write permission is checked per LUN in store_*() functions. */
 static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro);
 static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro);
 static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, fsg_store_nofua);
 static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, fsg_store_nofua);
 static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file);
 static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file);
 
 
+static struct device_attribute dev_attr_ro_cdrom =
+	__ATTR(ro, 0444, fsg_show_ro, NULL);
+static struct device_attribute dev_attr_file_nonremovable =
+	__ATTR(file, 0444, fsg_show_file, NULL);
+
 
 
 /****************************** FSG COMMON ******************************/
 /****************************** FSG COMMON ******************************/
 
 
@@ -2792,11 +2718,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
 		curlun->dev.parent = &gadget->dev;
 		curlun->dev.parent = &gadget->dev;
 		/* curlun->dev.driver = &fsg_driver.driver; XXX */
 		/* curlun->dev.driver = &fsg_driver.driver; XXX */
 		dev_set_drvdata(&curlun->dev, &common->filesem);
 		dev_set_drvdata(&curlun->dev, &common->filesem);
-		dev_set_name(&curlun->dev,
-			     cfg->lun_name_format
-			   ? cfg->lun_name_format
-			   : "lun%d",
-			     i);
+		dev_set_name(&curlun->dev, "lun%d", i);
 
 
 		rc = device_register(&curlun->dev);
 		rc = device_register(&curlun->dev);
 		if (rc) {
 		if (rc) {
@@ -2806,10 +2728,16 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
 			goto error_release;
 			goto error_release;
 		}
 		}
 
 
-		rc = device_create_file(&curlun->dev, &dev_attr_ro);
+		rc = device_create_file(&curlun->dev,
+					curlun->cdrom
+				      ? &dev_attr_ro_cdrom
+				      : &dev_attr_ro);
 		if (rc)
 		if (rc)
 			goto error_luns;
 			goto error_luns;
-		rc = device_create_file(&curlun->dev, &dev_attr_file);
+		rc = device_create_file(&curlun->dev,
+					curlun->removable
+				      ? &dev_attr_file
+				      : &dev_attr_file_nonremovable);
 		if (rc)
 		if (rc)
 			goto error_luns;
 			goto error_luns;
 		rc = device_create_file(&curlun->dev, &dev_attr_nofua);
 		rc = device_create_file(&curlun->dev, &dev_attr_nofua);
@@ -2878,8 +2806,7 @@ buffhds_first_it:
 
 
 	/* Tell the thread to start working */
 	/* Tell the thread to start working */
 	common->thread_task =
 	common->thread_task =
-		kthread_create(fsg_main_thread, common,
-			       cfg->thread_name ?: "file-storage");
+		kthread_create(fsg_main_thread, common, "file-storage");
 	if (IS_ERR(common->thread_task)) {
 	if (IS_ERR(common->thread_task)) {
 		rc = PTR_ERR(common->thread_task);
 		rc = PTR_ERR(common->thread_task);
 		goto error_release;
 		goto error_release;
@@ -2945,8 +2872,14 @@ static void fsg_common_release(struct kref *ref)
 		/* In error recovery common->nluns may be zero. */
 		/* In error recovery common->nluns may be zero. */
 		for (; i; --i, ++lun) {
 		for (; i; --i, ++lun) {
 			device_remove_file(&lun->dev, &dev_attr_nofua);
 			device_remove_file(&lun->dev, &dev_attr_nofua);
-			device_remove_file(&lun->dev, &dev_attr_ro);
-			device_remove_file(&lun->dev, &dev_attr_file);
+			device_remove_file(&lun->dev,
+					   lun->cdrom
+					 ? &dev_attr_ro_cdrom
+					 : &dev_attr_ro);
+			device_remove_file(&lun->dev,
+					   lun->removable
+					 ? &dev_attr_file
+					 : &dev_attr_file_nonremovable);
 			fsg_lun_close(lun);
 			fsg_lun_close(lun);
 			device_unregister(&lun->dev);
 			device_unregister(&lun->dev);
 		}
 		}
@@ -3167,8 +3100,7 @@ fsg_config_from_params(struct fsg_config *cfg,
 	for (i = 0, lun = cfg->luns; i < cfg->nluns; ++i, ++lun) {
 	for (i = 0, lun = cfg->luns; i < cfg->nluns; ++i, ++lun) {
 		lun->ro = !!params->ro[i];
 		lun->ro = !!params->ro[i];
 		lun->cdrom = !!params->cdrom[i];
 		lun->cdrom = !!params->cdrom[i];
-		lun->removable = /* Removable by default */
-			params->removable_count <= i || params->removable[i];
+		lun->removable = !!params->removable[i];
 		lun->filename =
 		lun->filename =
 			params->file_count > i && params->file[i][0]
 			params->file_count > i && params->file[i][0]
 			? params->file[i]
 			? params->file[i]
@@ -3176,8 +3108,6 @@ fsg_config_from_params(struct fsg_config *cfg,
 	}
 	}
 
 
 	/* Let MSF use defaults */
 	/* Let MSF use defaults */
-	cfg->lun_name_format = 0;
-	cfg->thread_name = 0;
 	cfg->vendor_name = 0;
 	cfg->vendor_name = 0;
 	cfg->product_name = 0;
 	cfg->product_name = 0;
 	cfg->release = 0xffff;
 	cfg->release = 0xffff;
@@ -3203,4 +3133,3 @@ fsg_common_from_params(struct fsg_common *common,
 	fsg_config_from_params(&cfg, params);
 	fsg_config_from_params(&cfg, params);
 	return fsg_common_init(common, cdev, &cfg);
 	return fsg_common_init(common, cdev, &cfg);
 }
 }
-

+ 241 - 46
drivers/usb/gadget/f_uvc.c

@@ -29,6 +29,25 @@
 
 
 unsigned int uvc_gadget_trace_param;
 unsigned int uvc_gadget_trace_param;
 
 
+/*-------------------------------------------------------------------------*/
+
+/* module parameters specific to the Video streaming endpoint */
+static unsigned streaming_interval = 1;
+module_param(streaming_interval, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(streaming_interval, "1 - 16");
+
+static unsigned streaming_maxpacket = 1024;
+module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(streaming_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)");
+
+static unsigned streaming_mult;
+module_param(streaming_mult, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(streaming_mult, "0 - 2 (hs/ss only)");
+
+static unsigned streaming_maxburst;
+module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
+
 /* --------------------------------------------------------------------------
 /* --------------------------------------------------------------------------
  * Function descriptors
  * Function descriptors
  */
  */
@@ -59,6 +78,8 @@ static struct usb_gadget_strings *uvc_function_strings[] = {
 #define UVC_INTF_VIDEO_CONTROL			0
 #define UVC_INTF_VIDEO_CONTROL			0
 #define UVC_INTF_VIDEO_STREAMING		1
 #define UVC_INTF_VIDEO_STREAMING		1
 
 
+#define STATUS_BYTECOUNT			16	/* 16 bytes status */
+
 static struct usb_interface_assoc_descriptor uvc_iad __initdata = {
 static struct usb_interface_assoc_descriptor uvc_iad __initdata = {
 	.bLength		= sizeof(uvc_iad),
 	.bLength		= sizeof(uvc_iad),
 	.bDescriptorType	= USB_DT_INTERFACE_ASSOCIATION,
 	.bDescriptorType	= USB_DT_INTERFACE_ASSOCIATION,
@@ -82,12 +103,12 @@ static struct usb_interface_descriptor uvc_control_intf __initdata = {
 	.iInterface		= 0,
 	.iInterface		= 0,
 };
 };
 
 
-static struct usb_endpoint_descriptor uvc_control_ep __initdata = {
+static struct usb_endpoint_descriptor uvc_fs_control_ep __initdata = {
 	.bLength		= USB_DT_ENDPOINT_SIZE,
 	.bLength		= USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType	= USB_DT_ENDPOINT,
 	.bDescriptorType	= USB_DT_ENDPOINT,
 	.bEndpointAddress	= USB_DIR_IN,
 	.bEndpointAddress	= USB_DIR_IN,
 	.bmAttributes		= USB_ENDPOINT_XFER_INT,
 	.bmAttributes		= USB_ENDPOINT_XFER_INT,
-	.wMaxPacketSize		= cpu_to_le16(16),
+	.wMaxPacketSize		= cpu_to_le16(STATUS_BYTECOUNT),
 	.bInterval		= 8,
 	.bInterval		= 8,
 };
 };
 
 
@@ -95,7 +116,7 @@ static struct uvc_control_endpoint_descriptor uvc_control_cs_ep __initdata = {
 	.bLength		= UVC_DT_CONTROL_ENDPOINT_SIZE,
 	.bLength		= UVC_DT_CONTROL_ENDPOINT_SIZE,
 	.bDescriptorType	= USB_DT_CS_ENDPOINT,
 	.bDescriptorType	= USB_DT_CS_ENDPOINT,
 	.bDescriptorSubType	= UVC_EP_INTERRUPT,
 	.bDescriptorSubType	= UVC_EP_INTERRUPT,
-	.wMaxTransferSize	= cpu_to_le16(16),
+	.wMaxTransferSize	= cpu_to_le16(STATUS_BYTECOUNT),
 };
 };
 
 
 static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = {
 static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = {
@@ -122,7 +143,7 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = {
 	.iInterface		= 0,
 	.iInterface		= 0,
 };
 };
 
 
-static struct usb_endpoint_descriptor uvc_streaming_ep = {
+static struct usb_endpoint_descriptor uvc_fs_streaming_ep = {
 	.bLength		= USB_DT_ENDPOINT_SIZE,
 	.bLength		= USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType	= USB_DT_ENDPOINT,
 	.bDescriptorType	= USB_DT_ENDPOINT,
 	.bEndpointAddress	= USB_DIR_IN,
 	.bEndpointAddress	= USB_DIR_IN,
@@ -131,15 +152,72 @@ static struct usb_endpoint_descriptor uvc_streaming_ep = {
 	.bInterval		= 1,
 	.bInterval		= 1,
 };
 };
 
 
+static struct usb_endpoint_descriptor uvc_hs_streaming_ep = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_IN,
+	.bmAttributes		= USB_ENDPOINT_XFER_ISOC,
+	.wMaxPacketSize		= cpu_to_le16(1024),
+	.bInterval		= 1,
+};
+
+/* super speed support */
+static struct usb_endpoint_descriptor uvc_ss_control_ep __initdata = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(STATUS_BYTECOUNT),
+	.bInterval =		8,
+};
+
+static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp __initdata = {
+	.bLength =		sizeof uvc_ss_control_comp,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 3 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+	.wBytesPerInterval =	cpu_to_le16(STATUS_BYTECOUNT),
+};
+
+static struct usb_endpoint_descriptor uvc_ss_streaming_ep __initdata = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_ISOC,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+	.bInterval =		4,
+};
+
+static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = {
+	.bLength =		sizeof uvc_ss_streaming_comp,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 3 values can be tweaked if necessary */
+	.bMaxBurst =		0,
+	.bmAttributes =	0,
+	.wBytesPerInterval =	cpu_to_le16(1024),
+};
+
 static const struct usb_descriptor_header * const uvc_fs_streaming[] = {
 static const struct usb_descriptor_header * const uvc_fs_streaming[] = {
 	(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
 	(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
-	(struct usb_descriptor_header *) &uvc_streaming_ep,
+	(struct usb_descriptor_header *) &uvc_fs_streaming_ep,
 	NULL,
 	NULL,
 };
 };
 
 
 static const struct usb_descriptor_header * const uvc_hs_streaming[] = {
 static const struct usb_descriptor_header * const uvc_hs_streaming[] = {
 	(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
 	(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
-	(struct usb_descriptor_header *) &uvc_streaming_ep,
+	(struct usb_descriptor_header *) &uvc_hs_streaming_ep,
+	NULL,
+};
+
+static const struct usb_descriptor_header * const uvc_ss_streaming[] = {
+	(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
+	(struct usb_descriptor_header *) &uvc_ss_streaming_ep,
+	(struct usb_descriptor_header *) &uvc_ss_streaming_comp,
 	NULL,
 	NULL,
 };
 };
 
 
@@ -215,6 +293,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
 	struct uvc_device *uvc = to_uvc(f);
 	struct uvc_device *uvc = to_uvc(f);
 	struct v4l2_event v4l2_event;
 	struct v4l2_event v4l2_event;
 	struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
 	struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
+	int ret;
 
 
 	INFO(f->config->cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt);
 	INFO(f->config->cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt);
 
 
@@ -262,7 +341,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
 			return 0;
 			return 0;
 
 
 		if (uvc->video.ep) {
 		if (uvc->video.ep) {
-			uvc->video.ep->desc = &uvc_streaming_ep;
+			ret = config_ep_by_speed(f->config->cdev->gadget,
+					&(uvc->func), uvc->video.ep);
+			if (ret)
+				return ret;
 			usb_ep_enable(uvc->video.ep);
 			usb_ep_enable(uvc->video.ep);
 		}
 		}
 
 
@@ -368,9 +450,11 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
 {
 {
 	struct uvc_input_header_descriptor *uvc_streaming_header;
 	struct uvc_input_header_descriptor *uvc_streaming_header;
 	struct uvc_header_descriptor *uvc_control_header;
 	struct uvc_header_descriptor *uvc_control_header;
+	const struct uvc_descriptor_header * const *uvc_control_desc;
 	const struct uvc_descriptor_header * const *uvc_streaming_cls;
 	const struct uvc_descriptor_header * const *uvc_streaming_cls;
 	const struct usb_descriptor_header * const *uvc_streaming_std;
 	const struct usb_descriptor_header * const *uvc_streaming_std;
 	const struct usb_descriptor_header * const *src;
 	const struct usb_descriptor_header * const *src;
+	static struct usb_endpoint_descriptor *uvc_control_ep;
 	struct usb_descriptor_header **dst;
 	struct usb_descriptor_header **dst;
 	struct usb_descriptor_header **hdr;
 	struct usb_descriptor_header **hdr;
 	unsigned int control_size;
 	unsigned int control_size;
@@ -379,10 +463,29 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
 	unsigned int bytes;
 	unsigned int bytes;
 	void *mem;
 	void *mem;
 
 
-	uvc_streaming_cls = (speed == USB_SPEED_FULL)
-			  ? uvc->desc.fs_streaming : uvc->desc.hs_streaming;
-	uvc_streaming_std = (speed == USB_SPEED_FULL)
-			  ? uvc_fs_streaming : uvc_hs_streaming;
+	switch (speed) {
+	case USB_SPEED_SUPER:
+		uvc_control_desc = uvc->desc.ss_control;
+		uvc_streaming_cls = uvc->desc.ss_streaming;
+		uvc_streaming_std = uvc_ss_streaming;
+		uvc_control_ep = &uvc_ss_control_ep;
+		break;
+
+	case USB_SPEED_HIGH:
+		uvc_control_desc = uvc->desc.fs_control;
+		uvc_streaming_cls = uvc->desc.hs_streaming;
+		uvc_streaming_std = uvc_hs_streaming;
+		uvc_control_ep = &uvc_fs_control_ep;
+		break;
+
+	case USB_SPEED_FULL:
+	default:
+		uvc_control_desc = uvc->desc.fs_control;
+		uvc_streaming_cls = uvc->desc.fs_streaming;
+		uvc_streaming_std = uvc_fs_streaming;
+		uvc_control_ep = &uvc_fs_control_ep;
+		break;
+	}
 
 
 	/* Descriptors layout
 	/* Descriptors layout
 	 *
 	 *
@@ -400,16 +503,24 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
 	control_size = 0;
 	control_size = 0;
 	streaming_size = 0;
 	streaming_size = 0;
 	bytes = uvc_iad.bLength + uvc_control_intf.bLength
 	bytes = uvc_iad.bLength + uvc_control_intf.bLength
-	      + uvc_control_ep.bLength + uvc_control_cs_ep.bLength
+	      + uvc_control_ep->bLength + uvc_control_cs_ep.bLength
 	      + uvc_streaming_intf_alt0.bLength;
 	      + uvc_streaming_intf_alt0.bLength;
-	n_desc = 5;
 
 
-	for (src = (const struct usb_descriptor_header**)uvc->desc.control; *src; ++src) {
+	if (speed == USB_SPEED_SUPER) {
+		bytes += uvc_ss_control_comp.bLength;
+		n_desc = 6;
+	} else {
+		n_desc = 5;
+	}
+
+	for (src = (const struct usb_descriptor_header **)uvc_control_desc;
+			*src; ++src) {
 		control_size += (*src)->bLength;
 		control_size += (*src)->bLength;
 		bytes += (*src)->bLength;
 		bytes += (*src)->bLength;
 		n_desc++;
 		n_desc++;
 	}
 	}
-	for (src = (const struct usb_descriptor_header**)uvc_streaming_cls; *src; ++src) {
+	for (src = (const struct usb_descriptor_header **)uvc_streaming_cls;
+			*src; ++src) {
 		streaming_size += (*src)->bLength;
 		streaming_size += (*src)->bLength;
 		bytes += (*src)->bLength;
 		bytes += (*src)->bLength;
 		n_desc++;
 		n_desc++;
@@ -433,12 +544,15 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
 
 
 	uvc_control_header = mem;
 	uvc_control_header = mem;
 	UVC_COPY_DESCRIPTORS(mem, dst,
 	UVC_COPY_DESCRIPTORS(mem, dst,
-		(const struct usb_descriptor_header**)uvc->desc.control);
+		(const struct usb_descriptor_header **)uvc_control_desc);
 	uvc_control_header->wTotalLength = cpu_to_le16(control_size);
 	uvc_control_header->wTotalLength = cpu_to_le16(control_size);
 	uvc_control_header->bInCollection = 1;
 	uvc_control_header->bInCollection = 1;
 	uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf;
 	uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf;
 
 
-	UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep);
+	UVC_COPY_DESCRIPTOR(mem, dst, uvc_control_ep);
+	if (speed == USB_SPEED_SUPER)
+		UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_control_comp);
+
 	UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep);
 	UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep);
 	UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0);
 	UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0);
 
 
@@ -446,7 +560,8 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
 	UVC_COPY_DESCRIPTORS(mem, dst,
 	UVC_COPY_DESCRIPTORS(mem, dst,
 		(const struct usb_descriptor_header**)uvc_streaming_cls);
 		(const struct usb_descriptor_header**)uvc_streaming_cls);
 	uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size);
 	uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size);
-	uvc_streaming_header->bEndpointAddress = uvc_streaming_ep.bEndpointAddress;
+	uvc_streaming_header->bEndpointAddress =
+		uvc_fs_streaming_ep.bEndpointAddress;
 
 
 	UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std);
 	UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std);
 
 
@@ -482,6 +597,7 @@ uvc_function_unbind(struct usb_configuration *c, struct usb_function *f)
 
 
 	kfree(f->descriptors);
 	kfree(f->descriptors);
 	kfree(f->hs_descriptors);
 	kfree(f->hs_descriptors);
+	kfree(f->ss_descriptors);
 
 
 	kfree(uvc);
 	kfree(uvc);
 }
 }
@@ -496,8 +612,26 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
 
 
 	INFO(cdev, "uvc_function_bind\n");
 	INFO(cdev, "uvc_function_bind\n");
 
 
+	/* sanity check the streaming endpoint module parameters */
+	if (streaming_interval < 1)
+		streaming_interval = 1;
+	if (streaming_interval > 16)
+		streaming_interval = 16;
+	if (streaming_mult > 2)
+		streaming_mult = 2;
+	if (streaming_maxburst > 15)
+		streaming_maxburst = 15;
+
+	/*
+	 * fill in the FS video streaming specific descriptors from the
+	 * module parameters
+	 */
+	uvc_fs_streaming_ep.wMaxPacketSize = streaming_maxpacket > 1023 ?
+						1023 : streaming_maxpacket;
+	uvc_fs_streaming_ep.bInterval = streaming_interval;
+
 	/* Allocate endpoints. */
 	/* Allocate endpoints. */
-	ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
+	ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_control_ep);
 	if (!ep) {
 	if (!ep) {
 		INFO(cdev, "Unable to allocate control EP\n");
 		INFO(cdev, "Unable to allocate control EP\n");
 		goto error;
 		goto error;
@@ -505,7 +639,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
 	uvc->control_ep = ep;
 	uvc->control_ep = ep;
 	ep->driver_data = uvc;
 	ep->driver_data = uvc;
 
 
-	ep = usb_ep_autoconfig(cdev->gadget, &uvc_streaming_ep);
+	ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
 	if (!ep) {
 	if (!ep) {
 		INFO(cdev, "Unable to allocate streaming EP\n");
 		INFO(cdev, "Unable to allocate streaming EP\n");
 		goto error;
 		goto error;
@@ -526,9 +660,52 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
 	uvc_streaming_intf_alt1.bInterfaceNumber = ret;
 	uvc_streaming_intf_alt1.bInterfaceNumber = ret;
 	uvc->streaming_intf = ret;
 	uvc->streaming_intf = ret;
 
 
-	/* Copy descriptors. */
+	/* sanity check the streaming endpoint module parameters */
+	if (streaming_maxpacket > 1024)
+		streaming_maxpacket = 1024;
+
+	/* Copy descriptors for FS. */
 	f->descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
 	f->descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
-	f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
+
+	/* support high speed hardware */
+	if (gadget_is_dualspeed(cdev->gadget)) {
+		/*
+		 * Fill in the HS descriptors from the module parameters for the
+		 * Video Streaming endpoint.
+		 * NOTE: We assume that the user knows what they are doing and
+		 * won't give parameters that their UDC doesn't support.
+		 */
+		uvc_hs_streaming_ep.wMaxPacketSize = streaming_maxpacket;
+		uvc_hs_streaming_ep.wMaxPacketSize |= streaming_mult << 11;
+		uvc_hs_streaming_ep.bInterval = streaming_interval;
+		uvc_hs_streaming_ep.bEndpointAddress =
+				uvc_fs_streaming_ep.bEndpointAddress;
+
+		/* Copy descriptors. */
+		f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
+	}
+
+	/* support super speed hardware */
+	if (gadget_is_superspeed(c->cdev->gadget)) {
+		/*
+		 * Fill in the SS descriptors from the module parameters for the
+		 * Video Streaming endpoint.
+		 * NOTE: We assume that the user knows what they are doing and
+		 * won't give parameters that their UDC doesn't support.
+		 */
+		uvc_ss_streaming_ep.wMaxPacketSize = streaming_maxpacket;
+		uvc_ss_streaming_ep.bInterval = streaming_interval;
+		uvc_ss_streaming_comp.bmAttributes = streaming_mult;
+		uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst;
+		uvc_ss_streaming_comp.wBytesPerInterval =
+			streaming_maxpacket * (streaming_mult + 1) *
+			(streaming_maxburst + 1);
+		uvc_ss_streaming_ep.bEndpointAddress =
+				uvc_fs_streaming_ep.bEndpointAddress;
+
+		/* Copy descriptors. */
+		f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
+	}
 
 
 	/* 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);
@@ -583,9 +760,11 @@ error:
  */
  */
 int __init
 int __init
 uvc_bind_config(struct usb_configuration *c,
 uvc_bind_config(struct usb_configuration *c,
-		const struct uvc_descriptor_header * const *control,
+		const struct uvc_descriptor_header * const *fs_control,
+		const struct uvc_descriptor_header * const *ss_control,
 		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)
 {
 {
 	struct uvc_device *uvc;
 	struct uvc_device *uvc;
 	int ret = 0;
 	int ret = 0;
@@ -603,38 +782,54 @@ uvc_bind_config(struct usb_configuration *c,
 	uvc->state = UVC_STATE_DISCONNECTED;
 	uvc->state = UVC_STATE_DISCONNECTED;
 
 
 	/* Validate the descriptors. */
 	/* Validate the descriptors. */
-	if (control == NULL || control[0] == NULL ||
-	    control[0]->bDescriptorSubType != UVC_VC_HEADER)
+	if (fs_control == NULL || fs_control[0] == NULL ||
+		fs_control[0]->bDescriptorSubType != UVC_VC_HEADER)
 		goto error;
 		goto error;
 
 
-	if (fs_streaming == NULL || fs_streaming[0] == NULL ||
-	    fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
+	if (ss_control == NULL || ss_control[0] == NULL ||
+		ss_control[0]->bDescriptorSubType != UVC_VC_HEADER)
 		goto error;
 		goto error;
 
 
-	if (hs_streaming == NULL || hs_streaming[0] == NULL ||
-	    hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
+	if (fs_streaming == NULL || fs_streaming[0] == NULL ||
+		fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
 		goto error;
 		goto error;
 
 
-	uvc->desc.control = control;
-	uvc->desc.fs_streaming = fs_streaming;
-	uvc->desc.hs_streaming = hs_streaming;
-
-	/* Allocate string descriptor numbers. */
-	if ((ret = usb_string_id(c->cdev)) < 0)
+	if (hs_streaming == NULL || hs_streaming[0] == NULL ||
+		hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
 		goto error;
 		goto error;
-	uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = ret;
-	uvc_iad.iFunction = ret;
 
 
-	if ((ret = usb_string_id(c->cdev)) < 0)
+	if (ss_streaming == NULL || ss_streaming[0] == NULL ||
+		ss_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
 		goto error;
 		goto error;
-	uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = ret;
-	uvc_control_intf.iInterface = ret;
 
 
-	if ((ret = usb_string_id(c->cdev)) < 0)
-		goto error;
-	uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id = ret;
-	uvc_streaming_intf_alt0.iInterface = ret;
-	uvc_streaming_intf_alt1.iInterface = ret;
+	uvc->desc.fs_control = fs_control;
+	uvc->desc.ss_control = ss_control;
+	uvc->desc.fs_streaming = fs_streaming;
+	uvc->desc.hs_streaming = hs_streaming;
+	uvc->desc.ss_streaming = ss_streaming;
+
+	/* maybe allocate device-global string IDs, and patch descriptors */
+	if (uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id == 0) {
+		/* Allocate string descriptor numbers. */
+		ret = usb_string_id(c->cdev);
+		if (ret < 0)
+			goto error;
+		uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = ret;
+		uvc_iad.iFunction = ret;
+
+		ret = usb_string_id(c->cdev);
+		if (ret < 0)
+			goto error;
+		uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = ret;
+		uvc_control_intf.iInterface = ret;
+
+		ret = usb_string_id(c->cdev);
+		if (ret < 0)
+			goto error;
+		uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id = ret;
+		uvc_streaming_intf_alt0.iInterface = ret;
+		uvc_streaming_intf_alt1.iInterface = ret;
+	}
 
 
 	/* Register the function. */
 	/* Register the function. */
 	uvc->func.name = "uvc";
 	uvc->func.name = "uvc";

+ 5 - 3
drivers/usb/gadget/f_uvc.h

@@ -17,9 +17,11 @@
 #include <linux/usb/video.h>
 #include <linux/usb/video.h>
 
 
 extern int uvc_bind_config(struct usb_configuration *c,
 extern int uvc_bind_config(struct usb_configuration *c,
-			   const struct uvc_descriptor_header * const *control,
-			   const struct uvc_descriptor_header * const *fs_streaming,
-			   const struct uvc_descriptor_header * const *hs_streaming);
+		   const struct uvc_descriptor_header * const *fs_control,
+		   const struct uvc_descriptor_header * const *hs_control,
+		   const struct uvc_descriptor_header * const *fs_streaming,
+		   const struct uvc_descriptor_header * const *hs_streaming,
+		   const struct uvc_descriptor_header * const *ss_streaming);
 
 
 #endif /* _F_UVC_H_ */
 #endif /* _F_UVC_H_ */
 
 

+ 31 - 43
drivers/usb/gadget/fsl_mxc_udc.c

@@ -21,7 +21,8 @@
 #include <mach/hardware.h>
 #include <mach/hardware.h>
 
 
 static struct clk *mxc_ahb_clk;
 static struct clk *mxc_ahb_clk;
-static struct clk *mxc_usb_clk;
+static struct clk *mxc_per_clk;
+static struct clk *mxc_ipg_clk;
 
 
 /* workaround ENGcm09152 for i.MX35 */
 /* workaround ENGcm09152 for i.MX35 */
 #define USBPHYCTRL_OTGBASE_OFFSET	0x608
 #define USBPHYCTRL_OTGBASE_OFFSET	0x608
@@ -35,28 +36,31 @@ int fsl_udc_clk_init(struct platform_device *pdev)
 
 
 	pdata = pdev->dev.platform_data;
 	pdata = pdev->dev.platform_data;
 
 
-	if (!cpu_is_mx35() && !cpu_is_mx25()) {
-		mxc_ahb_clk = clk_get(&pdev->dev, "usb_ahb");
-		if (IS_ERR(mxc_ahb_clk))
-			return PTR_ERR(mxc_ahb_clk);
+	mxc_ipg_clk = devm_clk_get(&pdev->dev, "ipg");
+	if (IS_ERR(mxc_ipg_clk)) {
+		dev_err(&pdev->dev, "clk_get(\"ipg\") failed\n");
+		return PTR_ERR(mxc_ipg_clk);
+	}
 
 
-		ret = clk_enable(mxc_ahb_clk);
-		if (ret < 0) {
-			dev_err(&pdev->dev, "clk_enable(\"usb_ahb\") failed\n");
-			goto eenahb;
-		}
+	mxc_ahb_clk = devm_clk_get(&pdev->dev, "ahb");
+	if (IS_ERR(mxc_ahb_clk)) {
+		dev_err(&pdev->dev, "clk_get(\"ahb\") failed\n");
+		return PTR_ERR(mxc_ahb_clk);
 	}
 	}
 
 
-	/* make sure USB_CLK is running at 60 MHz +/- 1000 Hz */
-	mxc_usb_clk = clk_get(&pdev->dev, "usb");
-	if (IS_ERR(mxc_usb_clk)) {
-		dev_err(&pdev->dev, "clk_get(\"usb\") failed\n");
-		ret = PTR_ERR(mxc_usb_clk);
-		goto egusb;
+	mxc_per_clk = devm_clk_get(&pdev->dev, "per");
+	if (IS_ERR(mxc_per_clk)) {
+		dev_err(&pdev->dev, "clk_get(\"per\") failed\n");
+		return PTR_ERR(mxc_per_clk);
 	}
 	}
 
 
+	clk_prepare_enable(mxc_ipg_clk);
+	clk_prepare_enable(mxc_ahb_clk);
+	clk_prepare_enable(mxc_per_clk);
+
+	/* make sure USB_CLK is running at 60 MHz +/- 1000 Hz */
 	if (!cpu_is_mx51()) {
 	if (!cpu_is_mx51()) {
-		freq = clk_get_rate(mxc_usb_clk);
+		freq = clk_get_rate(mxc_per_clk);
 		if (pdata->phy_mode != FSL_USB2_PHY_ULPI &&
 		if (pdata->phy_mode != FSL_USB2_PHY_ULPI &&
 		    (freq < 59999000 || freq > 60001000)) {
 		    (freq < 59999000 || freq > 60001000)) {
 			dev_err(&pdev->dev, "USB_CLK=%lu, should be 60MHz\n", freq);
 			dev_err(&pdev->dev, "USB_CLK=%lu, should be 60MHz\n", freq);
@@ -65,24 +69,13 @@ int fsl_udc_clk_init(struct platform_device *pdev)
 		}
 		}
 	}
 	}
 
 
-	ret = clk_enable(mxc_usb_clk);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "clk_enable(\"usb_clk\") failed\n");
-		goto eenusb;
-	}
-
 	return 0;
 	return 0;
 
 
-eenusb:
 eclkrate:
 eclkrate:
-	clk_put(mxc_usb_clk);
-	mxc_usb_clk = NULL;
-egusb:
-	if (!cpu_is_mx35())
-		clk_disable(mxc_ahb_clk);
-eenahb:
-	if (!cpu_is_mx35())
-		clk_put(mxc_ahb_clk);
+	clk_disable_unprepare(mxc_ipg_clk);
+	clk_disable_unprepare(mxc_ahb_clk);
+	clk_disable_unprepare(mxc_per_clk);
+	mxc_per_clk = NULL;
 	return ret;
 	return ret;
 }
 }
 
 
@@ -104,20 +97,15 @@ void fsl_udc_clk_finalize(struct platform_device *pdev)
 
 
 	/* ULPI transceivers don't need usbpll */
 	/* ULPI transceivers don't need usbpll */
 	if (pdata->phy_mode == FSL_USB2_PHY_ULPI) {
 	if (pdata->phy_mode == FSL_USB2_PHY_ULPI) {
-		clk_disable(mxc_usb_clk);
-		clk_put(mxc_usb_clk);
-		mxc_usb_clk = NULL;
+		clk_disable_unprepare(mxc_per_clk);
+		mxc_per_clk = NULL;
 	}
 	}
 }
 }
 
 
 void fsl_udc_clk_release(void)
 void fsl_udc_clk_release(void)
 {
 {
-	if (mxc_usb_clk) {
-		clk_disable(mxc_usb_clk);
-		clk_put(mxc_usb_clk);
-	}
-	if (!cpu_is_mx35()) {
-		clk_disable(mxc_ahb_clk);
-		clk_put(mxc_ahb_clk);
-	}
+	if (mxc_per_clk)
+		clk_disable_unprepare(mxc_per_clk);
+	clk_disable_unprepare(mxc_ahb_clk);
+	clk_disable_unprepare(mxc_ipg_clk);
 }
 }

+ 10 - 8
drivers/usb/gadget/fsl_udc_core.c

@@ -24,6 +24,7 @@
 #include <linux/ioport.h>
 #include <linux/ioport.h>
 #include <linux/types.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/list.h>
@@ -1229,7 +1230,7 @@ static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
 	struct fsl_udc *udc;
 	struct fsl_udc *udc;
 
 
 	udc = container_of(gadget, struct fsl_udc, gadget);
 	udc = container_of(gadget, struct fsl_udc, gadget);
-	if (udc->transceiver)
+	if (!IS_ERR_OR_NULL(udc->transceiver))
 		return usb_phy_set_power(udc->transceiver, mA);
 		return usb_phy_set_power(udc->transceiver, mA);
 	return -ENOTSUPP;
 	return -ENOTSUPP;
 }
 }
@@ -1983,13 +1984,13 @@ static int fsl_start(struct usb_gadget_driver *driver,
 		goto out;
 		goto out;
 	}
 	}
 
 
-	if (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 */
 		udc_controller->stopped = 1;
 		udc_controller->stopped = 1;
 		printk(KERN_INFO "Suspend udc for OTG auto detect\n");
 		printk(KERN_INFO "Suspend udc for OTG auto detect\n");
 
 
 		/* connect to bus through transceiver */
 		/* connect to bus through transceiver */
-		if (udc_controller->transceiver) {
+		if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
 			retval = otg_set_peripheral(
 			retval = otg_set_peripheral(
 					udc_controller->transceiver->otg,
 					udc_controller->transceiver->otg,
 						    &udc_controller->gadget);
 						    &udc_controller->gadget);
@@ -2030,7 +2031,7 @@ static int fsl_stop(struct usb_gadget_driver *driver)
 	if (!driver || driver != udc_controller->driver || !driver->unbind)
 	if (!driver || driver != udc_controller->driver || !driver->unbind)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	if (udc_controller->transceiver)
+	if (!IS_ERR_OR_NULL(udc_controller->transceiver))
 		otg_set_peripheral(udc_controller->transceiver->otg, NULL);
 		otg_set_peripheral(udc_controller->transceiver->otg, NULL);
 
 
 	/* stop DR, disable intr */
 	/* stop DR, disable intr */
@@ -2455,8 +2456,8 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
 
 
 #ifdef CONFIG_USB_OTG
 #ifdef CONFIG_USB_OTG
 	if (pdata->operating_mode == FSL_USB2_DR_OTG) {
 	if (pdata->operating_mode == FSL_USB2_DR_OTG) {
-		udc_controller->transceiver = usb_get_transceiver();
-		if (!udc_controller->transceiver) {
+		udc_controller->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+		if (IS_ERR_OR_NULL(udc_controller->transceiver)) {
 			ERR("Can't find OTG driver!\n");
 			ERR("Can't find OTG driver!\n");
 			ret = -ENODEV;
 			ret = -ENODEV;
 			goto err_kfree;
 			goto err_kfree;
@@ -2540,7 +2541,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
 		goto err_free_irq;
 		goto err_free_irq;
 	}
 	}
 
 
-	if (!udc_controller->transceiver) {
+	if (IS_ERR_OR_NULL(udc_controller->transceiver)) {
 		/* initialize usb hw reg except for regs for EP,
 		/* initialize usb hw reg except for regs for EP,
 		 * leave usbintr reg untouched */
 		 * leave usbintr reg untouched */
 		dr_controller_setup(udc_controller);
 		dr_controller_setup(udc_controller);
@@ -2560,11 +2561,12 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
 	dev_set_name(&udc_controller->gadget.dev, "gadget");
 	dev_set_name(&udc_controller->gadget.dev, "gadget");
 	udc_controller->gadget.dev.release = fsl_udc_release;
 	udc_controller->gadget.dev.release = fsl_udc_release;
 	udc_controller->gadget.dev.parent = &pdev->dev;
 	udc_controller->gadget.dev.parent = &pdev->dev;
+	udc_controller->gadget.dev.of_node = pdev->dev.of_node;
 	ret = device_register(&udc_controller->gadget.dev);
 	ret = device_register(&udc_controller->gadget.dev);
 	if (ret < 0)
 	if (ret < 0)
 		goto err_free_irq;
 		goto err_free_irq;
 
 
-	if (udc_controller->transceiver)
+	if (!IS_ERR_OR_NULL(udc_controller->transceiver))
 		udc_controller->gadget.is_otg = 1;
 		udc_controller->gadget.is_otg = 1;
 
 
 	/* setup QH and epctrl for ep0 */
 	/* setup QH and epctrl for ep0 */

+ 3 - 3
drivers/usb/gadget/imx_udc.c

@@ -1432,7 +1432,7 @@ static int __init imx_udc_probe(struct platform_device *pdev)
 		dev_err(&pdev->dev, "can't get USB clock\n");
 		dev_err(&pdev->dev, "can't get USB clock\n");
 		goto fail2;
 		goto fail2;
 	}
 	}
-	clk_enable(clk);
+	clk_prepare_enable(clk);
 
 
 	if (clk_get_rate(clk) != 48000000) {
 	if (clk_get_rate(clk) != 48000000) {
 		D_INI(&pdev->dev,
 		D_INI(&pdev->dev,
@@ -1496,7 +1496,7 @@ fail4:
 		free_irq(imx_usb->usbd_int[i], imx_usb);
 		free_irq(imx_usb->usbd_int[i], imx_usb);
 fail3:
 fail3:
 	clk_put(clk);
 	clk_put(clk);
-	clk_disable(clk);
+	clk_disable_unprepare(clk);
 fail2:
 fail2:
 	iounmap(base);
 	iounmap(base);
 fail1:
 fail1:
@@ -1521,7 +1521,7 @@ static int __exit imx_udc_remove(struct platform_device *pdev)
 		free_irq(imx_usb->usbd_int[i], imx_usb);
 		free_irq(imx_usb->usbd_int[i], imx_usb);
 
 
 	clk_put(imx_usb->clk);
 	clk_put(imx_usb->clk);
-	clk_disable(imx_usb->clk);
+	clk_disable_unprepare(imx_usb->clk);
 	iounmap(imx_usb->base);
 	iounmap(imx_usb->base);
 
 
 	release_mem_region(imx_usb->res->start, resource_size(imx_usb->res));
 	release_mem_region(imx_usb->res->start, resource_size(imx_usb->res));

+ 25 - 60
drivers/usb/gadget/lpc32xx_udc.c

@@ -165,6 +165,7 @@ struct lpc32xx_udc {
 	int			udp_irq[4];
 	int			udp_irq[4];
 	struct clk		*usb_pll_clk;
 	struct clk		*usb_pll_clk;
 	struct clk		*usb_slv_clk;
 	struct clk		*usb_slv_clk;
+	struct clk		*usb_otg_clk;
 
 
 	/* DMA support */
 	/* DMA support */
 	u32			*udca_v_base;
 	u32			*udca_v_base;
@@ -227,33 +228,15 @@ static inline struct lpc32xx_udc *to_udc(struct usb_gadget *g)
 #define UDCA_BUFF_SIZE (128)
 #define UDCA_BUFF_SIZE (128)
 
 
 /* TODO: When the clock framework is introduced in LPC32xx, IO_ADDRESS will
 /* TODO: When the clock framework is introduced in LPC32xx, IO_ADDRESS will
- * be replaced with an inremap()ed pointer, see USB_OTG_CLK_CTRL()
+ * be replaced with an inremap()ed pointer
  * */
  * */
 #define USB_CTRL		IO_ADDRESS(LPC32XX_CLK_PM_BASE + 0x64)
 #define USB_CTRL		IO_ADDRESS(LPC32XX_CLK_PM_BASE + 0x64)
-#define USB_CLOCK_MASK		(AHB_M_CLOCK_ON | OTG_CLOCK_ON | \
-				 DEV_CLOCK_ON | I2C_CLOCK_ON)
 
 
 /* USB_CTRL bit defines */
 /* USB_CTRL bit defines */
 #define USB_SLAVE_HCLK_EN	(1 << 24)
 #define USB_SLAVE_HCLK_EN	(1 << 24)
 #define USB_HOST_NEED_CLK_EN	(1 << 21)
 #define USB_HOST_NEED_CLK_EN	(1 << 21)
 #define USB_DEV_NEED_CLK_EN	(1 << 22)
 #define USB_DEV_NEED_CLK_EN	(1 << 22)
 
 
-#define USB_OTG_CLK_CTRL(udc)	((udc)->udp_baseaddr + 0xFF4)
-#define USB_OTG_CLK_STAT(udc)	((udc)->udp_baseaddr + 0xFF8)
-
-/* USB_OTG_CLK_CTRL bit defines */
-#define AHB_M_CLOCK_ON		(1 << 4)
-#define OTG_CLOCK_ON		(1 << 3)
-#define I2C_CLOCK_ON		(1 << 2)
-#define DEV_CLOCK_ON		(1 << 1)
-#define HOST_CLOCK_ON		(1 << 0)
-
-#define USB_OTG_STAT_CONTROL(udc) (udc->udp_baseaddr + 0x110)
-
-/* USB_OTG_STAT_CONTROL bit defines */
-#define TRANSPARENT_I2C_EN	(1 << 7)
-#define HOST_EN			(1 << 0)
-
 /**********************************************************************
 /**********************************************************************
  * USB device controller register offsets
  * USB device controller register offsets
  **********************************************************************/
  **********************************************************************/
@@ -677,7 +660,7 @@ static void isp1301_udc_configure(struct lpc32xx_udc *udc)
 		ISP1301_I2C_INTERRUPT_RISING, INT_VBUS_VLD);
 		ISP1301_I2C_INTERRUPT_RISING, INT_VBUS_VLD);
 
 
 	/* Enable usb_need_clk clock after transceiver is initialized */
 	/* Enable usb_need_clk clock after transceiver is initialized */
-	writel((readl(USB_CTRL) | (1 << 22)), USB_CTRL);
+	writel((readl(USB_CTRL) | USB_DEV_NEED_CLK_EN), USB_CTRL);
 
 
 	dev_info(udc->dev, "ISP1301 Vendor ID  : 0x%04x\n",
 	dev_info(udc->dev, "ISP1301 Vendor ID  : 0x%04x\n",
 		 i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x00));
 		 i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x00));
@@ -1010,11 +993,8 @@ static void udc_dd_free(struct lpc32xx_udc *udc, struct lpc32xx_usbd_dd_gad *dd)
 /* Enables or disables most of the USB system clocks when low power mode is
 /* Enables or disables most of the USB system clocks when low power mode is
  * needed. Clocks are typically started on a connection event, and disabled
  * needed. Clocks are typically started on a connection event, and disabled
  * when a cable is disconnected */
  * when a cable is disconnected */
-#define OTGOFF_CLK_MASK (AHB_M_CLOCK_ON | I2C_CLOCK_ON)
 static void udc_clk_set(struct lpc32xx_udc *udc, int enable)
 static void udc_clk_set(struct lpc32xx_udc *udc, int enable)
 {
 {
-	int to = 1000;
-
 	if (enable != 0) {
 	if (enable != 0) {
 		if (udc->clocked)
 		if (udc->clocked)
 			return;
 			return;
@@ -1028,14 +1008,7 @@ static void udc_clk_set(struct lpc32xx_udc *udc, int enable)
 		writel(readl(USB_CTRL) | USB_DEV_NEED_CLK_EN,
 		writel(readl(USB_CTRL) | USB_DEV_NEED_CLK_EN,
 			     USB_CTRL);
 			     USB_CTRL);
 
 
-		/* Set to enable all needed USB OTG clocks */
-		writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL(udc));
-
-		while (((readl(USB_OTG_CLK_STAT(udc)) & USB_CLOCK_MASK) !=
-			USB_CLOCK_MASK) && (to > 0))
-			to--;
-		if (!to)
-			dev_dbg(udc->dev, "Cannot enable USB OTG clocking\n");
+		clk_enable(udc->usb_otg_clk);
 	} else {
 	} else {
 		if (!udc->clocked)
 		if (!udc->clocked)
 			return;
 			return;
@@ -1047,19 +1020,11 @@ static void udc_clk_set(struct lpc32xx_udc *udc, int enable)
 		/* 48MHz PLL dpwn */
 		/* 48MHz PLL dpwn */
 		clk_disable(udc->usb_pll_clk);
 		clk_disable(udc->usb_pll_clk);
 
 
-		/* Enable the USB device clock */
+		/* Disable the USB device clock */
 		writel(readl(USB_CTRL) & ~USB_DEV_NEED_CLK_EN,
 		writel(readl(USB_CTRL) & ~USB_DEV_NEED_CLK_EN,
 			     USB_CTRL);
 			     USB_CTRL);
 
 
-		/* Set to enable all needed USB OTG clocks */
-		writel(OTGOFF_CLK_MASK, USB_OTG_CLK_CTRL(udc));
-
-		while (((readl(USB_OTG_CLK_STAT(udc)) &
-			 OTGOFF_CLK_MASK) !=
-			OTGOFF_CLK_MASK) && (to > 0))
-			to--;
-		if (!to)
-			dev_dbg(udc->dev, "Cannot disable USB OTG clocking\n");
+		clk_disable(udc->usb_otg_clk);
 	}
 	}
 }
 }
 
 
@@ -3041,6 +3006,7 @@ static int lpc32xx_start(struct usb_gadget_driver *driver,
 
 
 	udc->driver = driver;
 	udc->driver = driver;
 	udc->gadget.dev.driver = &driver->driver;
 	udc->gadget.dev.driver = &driver->driver;
+	udc->gadget.dev.of_node = udc->dev->of_node;
 	udc->enabled = 1;
 	udc->enabled = 1;
 	udc->selfpowered = 1;
 	udc->selfpowered = 1;
 	udc->vbus = 0;
 	udc->vbus = 0;
@@ -3239,6 +3205,12 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev)
 		retval = PTR_ERR(udc->usb_slv_clk);
 		retval = PTR_ERR(udc->usb_slv_clk);
 		goto usb_clk_get_fail;
 		goto usb_clk_get_fail;
 	}
 	}
+	udc->usb_otg_clk = clk_get(&pdev->dev, "ck_usb_otg");
+	if (IS_ERR(udc->usb_otg_clk)) {
+		dev_err(udc->dev, "failed to acquire USB otg clock\n");
+		retval = PTR_ERR(udc->usb_slv_clk);
+		goto usb_otg_clk_get_fail;
+	}
 
 
 	/* Setup PLL clock to 48MHz */
 	/* Setup PLL clock to 48MHz */
 	retval = clk_enable(udc->usb_pll_clk);
 	retval = clk_enable(udc->usb_pll_clk);
@@ -3262,15 +3234,12 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev)
 		goto usb_clk_enable_fail;
 		goto usb_clk_enable_fail;
 	}
 	}
 
 
-	/* Set to enable all needed USB OTG clocks */
-	writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL(udc));
-
-	i = 1000;
-	while (((readl(USB_OTG_CLK_STAT(udc)) & USB_CLOCK_MASK) !=
-		USB_CLOCK_MASK) && (i > 0))
-		i--;
-	if (!i)
-		dev_dbg(udc->dev, "USB OTG clocks not correctly enabled\n");
+	/* Enable USB OTG clock */
+	retval = clk_enable(udc->usb_otg_clk);
+	if (retval < 0) {
+		dev_err(udc->dev, "failed to start USB otg clock\n");
+		goto usb_otg_clk_enable_fail;
+	}
 
 
 	/* Setup deferred workqueue data */
 	/* Setup deferred workqueue data */
 	udc->poweron = udc->pullup = 0;
 	udc->poweron = udc->pullup = 0;
@@ -3390,12 +3359,16 @@ dma_alloc_fail:
 	dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE,
 	dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE,
 			  udc->udca_v_base, udc->udca_p_base);
 			  udc->udca_v_base, udc->udca_p_base);
 i2c_fail:
 i2c_fail:
+	clk_disable(udc->usb_otg_clk);
+usb_otg_clk_enable_fail:
 	clk_disable(udc->usb_slv_clk);
 	clk_disable(udc->usb_slv_clk);
 usb_clk_enable_fail:
 usb_clk_enable_fail:
 pll_set_fail:
 pll_set_fail:
 	clk_disable(udc->usb_pll_clk);
 	clk_disable(udc->usb_pll_clk);
 pll_enable_fail:
 pll_enable_fail:
 	clk_put(udc->usb_slv_clk);
 	clk_put(udc->usb_slv_clk);
+usb_otg_clk_get_fail:
+	clk_put(udc->usb_otg_clk);
 usb_clk_get_fail:
 usb_clk_get_fail:
 	clk_put(udc->usb_pll_clk);
 	clk_put(udc->usb_pll_clk);
 pll_get_fail:
 pll_get_fail:
@@ -3433,6 +3406,8 @@ static int __devexit lpc32xx_udc_remove(struct platform_device *pdev)
 
 
 	device_unregister(&udc->gadget.dev);
 	device_unregister(&udc->gadget.dev);
 
 
+	clk_disable(udc->usb_otg_clk);
+	clk_put(udc->usb_otg_clk);
 	clk_disable(udc->usb_slv_clk);
 	clk_disable(udc->usb_slv_clk);
 	clk_put(udc->usb_slv_clk);
 	clk_put(udc->usb_slv_clk);
 	clk_disable(udc->usb_pll_clk);
 	clk_disable(udc->usb_pll_clk);
@@ -3446,7 +3421,6 @@ static int __devexit lpc32xx_udc_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 static int lpc32xx_udc_suspend(struct platform_device *pdev, pm_message_t mesg)
 static int lpc32xx_udc_suspend(struct platform_device *pdev, pm_message_t mesg)
 {
 {
-	int to = 1000;
 	struct lpc32xx_udc *udc = platform_get_drvdata(pdev);
 	struct lpc32xx_udc *udc = platform_get_drvdata(pdev);
 
 
 	if (udc->clocked) {
 	if (udc->clocked) {
@@ -3461,15 +3435,6 @@ static int lpc32xx_udc_suspend(struct platform_device *pdev, pm_message_t mesg)
 		   on resume */
 		   on resume */
 		udc->clocked = 1;
 		udc->clocked = 1;
 
 
-		/* Kill OTG and I2C clocks */
-		writel(0, USB_OTG_CLK_CTRL(udc));
-		while (((readl(USB_OTG_CLK_STAT(udc)) & OTGOFF_CLK_MASK) !=
-			OTGOFF_CLK_MASK) && (to > 0))
-			to--;
-		if (!to)
-			dev_dbg(udc->dev,
-				"USB OTG clocks not correctly enabled\n");
-
 		/* Kill global USB clock */
 		/* Kill global USB clock */
 		clk_disable(udc->usb_slv_clk);
 		clk_disable(udc->usb_slv_clk);
 	}
 	}

+ 320 - 0
drivers/usb/gadget/mv_u3d.h

@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#ifndef __MV_U3D_H
+#define __MV_U3D_H
+
+#define MV_U3D_EP_CONTEXT_ALIGNMENT	32
+#define MV_U3D_TRB_ALIGNMENT	16
+#define MV_U3D_DMA_BOUNDARY	4096
+#define MV_U3D_EP0_MAX_PKT_SIZE	512
+
+/* ep0 transfer state */
+#define MV_U3D_WAIT_FOR_SETUP		0
+#define MV_U3D_DATA_STATE_XMIT		1
+#define MV_U3D_DATA_STATE_NEED_ZLP	2
+#define MV_U3D_WAIT_FOR_OUT_STATUS	3
+#define MV_U3D_DATA_STATE_RECV		4
+#define MV_U3D_STATUS_STAGE		5
+
+#define MV_U3D_EP_MAX_LENGTH_TRANSFER	0x10000
+
+/* USB3 Interrupt Status */
+#define MV_U3D_USBINT_SETUP		0x00000001
+#define MV_U3D_USBINT_RX_COMPLETE	0x00000002
+#define MV_U3D_USBINT_TX_COMPLETE	0x00000004
+#define MV_U3D_USBINT_UNDER_RUN	0x00000008
+#define MV_U3D_USBINT_RXDESC_ERR	0x00000010
+#define MV_U3D_USBINT_TXDESC_ERR	0x00000020
+#define MV_U3D_USBINT_RX_TRB_COMPLETE	0x00000040
+#define MV_U3D_USBINT_TX_TRB_COMPLETE	0x00000080
+#define MV_U3D_USBINT_VBUS_VALID	0x00010000
+#define MV_U3D_USBINT_STORAGE_CMD_FULL	0x00020000
+#define MV_U3D_USBINT_LINK_CHG		0x01000000
+
+/* USB3 Interrupt Enable */
+#define MV_U3D_INTR_ENABLE_SETUP		0x00000001
+#define MV_U3D_INTR_ENABLE_RX_COMPLETE		0x00000002
+#define MV_U3D_INTR_ENABLE_TX_COMPLETE		0x00000004
+#define MV_U3D_INTR_ENABLE_UNDER_RUN		0x00000008
+#define MV_U3D_INTR_ENABLE_RXDESC_ERR		0x00000010
+#define MV_U3D_INTR_ENABLE_TXDESC_ERR		0x00000020
+#define MV_U3D_INTR_ENABLE_RX_TRB_COMPLETE	0x00000040
+#define MV_U3D_INTR_ENABLE_TX_TRB_COMPLETE	0x00000080
+#define MV_U3D_INTR_ENABLE_RX_BUFFER_ERR	0x00000100
+#define MV_U3D_INTR_ENABLE_VBUS_VALID		0x00010000
+#define MV_U3D_INTR_ENABLE_STORAGE_CMD_FULL	0x00020000
+#define MV_U3D_INTR_ENABLE_LINK_CHG		0x01000000
+#define MV_U3D_INTR_ENABLE_PRIME_STATUS	0x02000000
+
+/* USB3 Link Change */
+#define MV_U3D_LINK_CHANGE_LINK_UP		0x00000001
+#define MV_U3D_LINK_CHANGE_SUSPEND		0x00000002
+#define MV_U3D_LINK_CHANGE_RESUME		0x00000004
+#define MV_U3D_LINK_CHANGE_WRESET		0x00000008
+#define MV_U3D_LINK_CHANGE_HRESET		0x00000010
+#define MV_U3D_LINK_CHANGE_VBUS_INVALID	0x00000020
+#define MV_U3D_LINK_CHANGE_INACT		0x00000040
+#define MV_U3D_LINK_CHANGE_DISABLE_AFTER_U0	0x00000080
+#define MV_U3D_LINK_CHANGE_U1			0x00000100
+#define MV_U3D_LINK_CHANGE_U2			0x00000200
+#define MV_U3D_LINK_CHANGE_U3			0x00000400
+
+/* bridge setting */
+#define MV_U3D_BRIDGE_SETTING_VBUS_VALID	(1 << 16)
+
+/* Command Register Bit Masks */
+#define MV_U3D_CMD_RUN_STOP		0x00000001
+#define MV_U3D_CMD_CTRL_RESET		0x00000002
+
+/* ep control register */
+#define MV_U3D_EPXCR_EP_TYPE_CONTROL		0
+#define MV_U3D_EPXCR_EP_TYPE_ISOC		1
+#define MV_U3D_EPXCR_EP_TYPE_BULK		2
+#define MV_U3D_EPXCR_EP_TYPE_INT		3
+#define MV_U3D_EPXCR_EP_ENABLE_SHIFT		4
+#define MV_U3D_EPXCR_MAX_BURST_SIZE_SHIFT	12
+#define MV_U3D_EPXCR_MAX_PACKET_SIZE_SHIFT	16
+#define MV_U3D_USB_BULK_BURST_OUT		6
+#define MV_U3D_USB_BULK_BURST_IN		14
+
+#define MV_U3D_EPXCR_EP_FLUSH		(1 << 7)
+#define MV_U3D_EPXCR_EP_HALT		(1 << 1)
+#define MV_U3D_EPXCR_EP_INIT		(1)
+
+/* TX/RX Status Register */
+#define MV_U3D_XFERSTATUS_COMPLETE_SHIFT	24
+#define MV_U3D_COMPLETE_INVALID	0
+#define MV_U3D_COMPLETE_SUCCESS	1
+#define MV_U3D_COMPLETE_BUFF_ERR	2
+#define MV_U3D_COMPLETE_SHORT_PACKET	3
+#define MV_U3D_COMPLETE_TRB_ERR	5
+#define MV_U3D_XFERSTATUS_TRB_LENGTH_MASK	(0xFFFFFF)
+
+#define MV_U3D_USB_LINK_BYPASS_VBUS	0x8
+
+#define MV_U3D_LTSSM_PHY_INIT_DONE		0x80000000
+#define MV_U3D_LTSSM_NEVER_GO_COMPLIANCE	0x40000000
+
+#define MV_U3D_USB3_OP_REGS_OFFSET	0x100
+#define MV_U3D_USB3_PHY_OFFSET		0xB800
+
+#define DCS_ENABLE	0x1
+
+/* timeout */
+#define MV_U3D_RESET_TIMEOUT		10000
+#define MV_U3D_FLUSH_TIMEOUT		100000
+#define MV_U3D_OWN_TIMEOUT		10000
+#define LOOPS_USEC_SHIFT	4
+#define LOOPS_USEC		(1 << LOOPS_USEC_SHIFT)
+#define LOOPS(timeout)		((timeout) >> LOOPS_USEC_SHIFT)
+
+/* ep direction */
+#define MV_U3D_EP_DIR_IN		1
+#define MV_U3D_EP_DIR_OUT		0
+#define mv_u3d_ep_dir(ep)	(((ep)->ep_num == 0) ? \
+				((ep)->u3d->ep0_dir) : ((ep)->direction))
+
+/* usb capability registers */
+struct mv_u3d_cap_regs {
+	u32	rsvd[5];
+	u32	dboff;	/* doorbell register offset */
+	u32	rtsoff;	/* runtime register offset */
+	u32	vuoff;	/* vendor unique register offset */
+};
+
+/* operation registers */
+struct mv_u3d_op_regs {
+	u32	usbcmd;		/* Command register */
+	u32	rsvd1[11];
+	u32	dcbaapl;	/* Device Context Base Address low register */
+	u32	dcbaaph;	/* Device Context Base Address high register */
+	u32	rsvd2[243];
+	u32	portsc;		/* port status and control register*/
+	u32	portlinkinfo;	/* port link info register*/
+	u32	rsvd3[9917];
+	u32	doorbell;	/* doorbell register */
+};
+
+/* control enpoint enable registers */
+struct epxcr {
+	u32	epxoutcr0;	/* ep out control 0 register */
+	u32	epxoutcr1;	/* ep out control 1 register */
+	u32	epxincr0;	/* ep in control 0 register */
+	u32	epxincr1;	/* ep in control 1 register */
+};
+
+/* transfer status registers */
+struct xferstatus {
+	u32	curdeqlo;	/* current TRB pointer low */
+	u32	curdeqhi;	/* current TRB pointer high */
+	u32	statuslo;	/* transfer status low */
+	u32	statushi;	/* transfer status high */
+};
+
+/* vendor unique control registers */
+struct mv_u3d_vuc_regs {
+	u32	ctrlepenable;	/* control endpoint enable register */
+	u32	setuplock;	/* setup lock register */
+	u32	endcomplete;	/* endpoint transfer complete register */
+	u32	intrcause;	/* interrupt cause register */
+	u32	intrenable;	/* interrupt enable register */
+	u32	trbcomplete;	/* TRB complete register */
+	u32	linkchange;	/* link change register */
+	u32	rsvd1[5];
+	u32	trbunderrun;	/* TRB underrun register */
+	u32	rsvd2[43];
+	u32	bridgesetting;	/* bridge setting register */
+	u32	rsvd3[7];
+	struct xferstatus	txst[16];	/* TX status register */
+	struct xferstatus	rxst[16];	/* RX status register */
+	u32	ltssm;		/* LTSSM control register */
+	u32	pipe;		/* PIPE control register */
+	u32	linkcr0;	/* link control 0 register */
+	u32	linkcr1;	/* link control 1 register */
+	u32	rsvd6[60];
+	u32	mib0;		/* MIB0 counter register */
+	u32	usblink;	/* usb link control register */
+	u32	ltssmstate;	/* LTSSM state register */
+	u32	linkerrorcause;	/* link error cause register */
+	u32	rsvd7[60];
+	u32	devaddrtiebrkr;	/* device address and tie breaker */
+	u32	itpinfo0;	/* ITP info 0 register */
+	u32	itpinfo1;	/* ITP info 1 register */
+	u32	rsvd8[61];
+	struct epxcr	epcr[16];	/* ep control register */
+	u32	rsvd9[64];
+	u32	phyaddr;	/* PHY address register */
+	u32	phydata;	/* PHY data register */
+};
+
+/* Endpoint context structure */
+struct mv_u3d_ep_context {
+	u32	rsvd0;
+	u32	rsvd1;
+	u32	trb_addr_lo;		/* TRB address low 32 bit */
+	u32	trb_addr_hi;		/* TRB address high 32 bit */
+	u32	rsvd2;
+	u32	rsvd3;
+	struct usb_ctrlrequest setup_buffer;	/* setup data buffer */
+};
+
+/* TRB control data structure */
+struct mv_u3d_trb_ctrl {
+	u32	own:1;		/* owner of TRB */
+	u32	rsvd1:3;
+	u32	chain:1;	/* associate this TRB with the
+				next TRB on the Ring */
+	u32	ioc:1;		/* interrupt on complete */
+	u32	rsvd2:4;
+	u32	type:6;		/* TRB type */
+#define TYPE_NORMAL	1
+#define TYPE_DATA	3
+#define TYPE_LINK	6
+	u32	dir:1;		/* Working at data stage of control endpoint
+				operation. 0 is OUT and 1 is IN. */
+	u32	rsvd3:15;
+};
+
+/* TRB data structure
+ * For multiple TRB, all the TRBs' physical address should be continuous.
+ */
+struct mv_u3d_trb_hw {
+	u32	buf_addr_lo;	/* data buffer address low 32 bit */
+	u32	buf_addr_hi;	/* data buffer address high 32 bit */
+	u32	trb_len;	/* transfer length */
+	struct mv_u3d_trb_ctrl	ctrl;	/* TRB control data */
+};
+
+/* TRB structure */
+struct mv_u3d_trb {
+	struct mv_u3d_trb_hw *trb_hw;	/* point to the trb_hw structure */
+	dma_addr_t trb_dma;		/* dma address for this trb_hw */
+	struct list_head trb_list;	/* trb list */
+};
+
+/* device data structure */
+struct mv_u3d {
+	struct usb_gadget		gadget;
+	struct usb_gadget_driver	*driver;
+	spinlock_t			lock;	/* device lock */
+	struct completion		*done;
+	struct device			*dev;
+	int				irq;
+
+	/* usb controller registers */
+	struct mv_u3d_cap_regs __iomem	*cap_regs;
+	struct mv_u3d_op_regs __iomem	*op_regs;
+	struct mv_u3d_vuc_regs __iomem	*vuc_regs;
+	void __iomem			*phy_regs;
+
+	unsigned int			max_eps;
+	struct mv_u3d_ep_context	*ep_context;
+	size_t				ep_context_size;
+	dma_addr_t			ep_context_dma;
+
+	struct dma_pool			*trb_pool; /* for TRB data structure */
+	struct mv_u3d_ep		*eps;
+
+	struct mv_u3d_req		*status_req; /* ep0 status request */
+	struct usb_ctrlrequest		local_setup_buff; /* store setup data*/
+
+	unsigned int		resume_state;	/* USB state to resume */
+	unsigned int		usb_state;	/* USB current state */
+	unsigned int		ep0_state;	/* Endpoint zero state */
+	unsigned int		ep0_dir;
+
+	unsigned int		dev_addr;	/* device address */
+
+	unsigned int		errors;
+
+	unsigned		softconnect:1;
+	unsigned		vbus_active:1;	/* vbus is active or not */
+	unsigned		remote_wakeup:1; /* support remote wakeup */
+	unsigned		clock_gating:1;	/* clock gating or not */
+	unsigned		active:1;	/* udc is active or not */
+	unsigned		vbus_valid_detect:1; /* udc vbus detection */
+
+	struct mv_usb_addon_irq *vbus;
+	unsigned int		power;
+
+	struct clk		*clk;
+};
+
+/* endpoint data structure */
+struct mv_u3d_ep {
+	struct usb_ep		ep;
+	struct mv_u3d		*u3d;
+	struct list_head	queue;	/* ep request queued hardware */
+	struct list_head	req_list; /* list of ep request */
+	struct mv_u3d_ep_context	*ep_context; /* ep context */
+	u32			direction;
+	char			name[14];
+	u32			processing; /* there is ep request
+						queued on haredware */
+	spinlock_t		req_lock; /* ep lock */
+	unsigned		wedge:1;
+	unsigned		enabled:1;
+	unsigned		ep_type:2;
+	unsigned		ep_num:8;
+};
+
+/* request data structure */
+struct mv_u3d_req {
+	struct usb_request	req;
+	struct mv_u3d_ep	*ep;
+	struct list_head	queue;	/* ep requst queued on hardware */
+	struct list_head	list;	/* ep request list */
+	struct list_head	trb_list; /* trb list of a request */
+
+	struct mv_u3d_trb	*trb_head; /* point to first trb of a request */
+	unsigned		trb_count; /* TRB number in the chain */
+	unsigned		chain;	   /* TRB chain or not */
+};
+
+#endif

+ 2098 - 0
drivers/usb/gadget/mv_u3d_core.c

@@ -0,0 +1,2098 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/notifier.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/pm.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/mv_usb.h>
+#include <linux/clk.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+#include "mv_u3d.h"
+
+#define DRIVER_DESC		"Marvell PXA USB3.0 Device Controller driver"
+
+static const char driver_name[] = "mv_u3d";
+static const char driver_desc[] = DRIVER_DESC;
+
+static void mv_u3d_nuke(struct mv_u3d_ep *ep, int status);
+static void mv_u3d_stop_activity(struct mv_u3d *u3d,
+			struct usb_gadget_driver *driver);
+
+/* for endpoint 0 operations */
+static const struct usb_endpoint_descriptor mv_u3d_ep0_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	0,
+	.bmAttributes =		USB_ENDPOINT_XFER_CONTROL,
+	.wMaxPacketSize =	MV_U3D_EP0_MAX_PKT_SIZE,
+};
+
+static void mv_u3d_ep0_reset(struct mv_u3d *u3d)
+{
+	struct mv_u3d_ep *ep;
+	u32 epxcr;
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		ep = &u3d->eps[i];
+		ep->u3d = u3d;
+
+		/* ep0 ep context, ep0 in and out share the same ep context */
+		ep->ep_context = &u3d->ep_context[1];
+	}
+
+	/* reset ep state machine */
+	/* reset ep0 out */
+	epxcr = ioread32(&u3d->vuc_regs->epcr[0].epxoutcr0);
+	epxcr |= MV_U3D_EPXCR_EP_INIT;
+	iowrite32(epxcr, &u3d->vuc_regs->epcr[0].epxoutcr0);
+	udelay(5);
+	epxcr &= ~MV_U3D_EPXCR_EP_INIT;
+	iowrite32(epxcr, &u3d->vuc_regs->epcr[0].epxoutcr0);
+
+	epxcr = ((MV_U3D_EP0_MAX_PKT_SIZE
+		<< MV_U3D_EPXCR_MAX_PACKET_SIZE_SHIFT)
+		| (1 << MV_U3D_EPXCR_MAX_BURST_SIZE_SHIFT)
+		| (1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT)
+		| MV_U3D_EPXCR_EP_TYPE_CONTROL);
+	iowrite32(epxcr, &u3d->vuc_regs->epcr[0].epxoutcr1);
+
+	/* reset ep0 in */
+	epxcr = ioread32(&u3d->vuc_regs->epcr[0].epxincr0);
+	epxcr |= MV_U3D_EPXCR_EP_INIT;
+	iowrite32(epxcr, &u3d->vuc_regs->epcr[0].epxincr0);
+	udelay(5);
+	epxcr &= ~MV_U3D_EPXCR_EP_INIT;
+	iowrite32(epxcr, &u3d->vuc_regs->epcr[0].epxincr0);
+
+	epxcr = ((MV_U3D_EP0_MAX_PKT_SIZE
+		<< MV_U3D_EPXCR_MAX_PACKET_SIZE_SHIFT)
+		| (1 << MV_U3D_EPXCR_MAX_BURST_SIZE_SHIFT)
+		| (1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT)
+		| MV_U3D_EPXCR_EP_TYPE_CONTROL);
+	iowrite32(epxcr, &u3d->vuc_regs->epcr[0].epxincr1);
+}
+
+static void mv_u3d_ep0_stall(struct mv_u3d *u3d)
+{
+	u32 tmp;
+	dev_dbg(u3d->dev, "%s\n", __func__);
+
+	/* set TX and RX to stall */
+	tmp = ioread32(&u3d->vuc_regs->epcr[0].epxoutcr0);
+	tmp |= MV_U3D_EPXCR_EP_HALT;
+	iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxoutcr0);
+
+	tmp = ioread32(&u3d->vuc_regs->epcr[0].epxincr0);
+	tmp |= MV_U3D_EPXCR_EP_HALT;
+	iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxincr0);
+
+	/* update ep0 state */
+	u3d->ep0_state = MV_U3D_WAIT_FOR_SETUP;
+	u3d->ep0_dir = MV_U3D_EP_DIR_OUT;
+}
+
+static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index,
+	struct mv_u3d_req *curr_req)
+{
+	struct mv_u3d_trb	*curr_trb;
+	dma_addr_t cur_deq_lo;
+	struct mv_u3d_ep_context	*curr_ep_context;
+	int trb_complete, actual, remaining_length;
+	int direction, ep_num;
+	int retval = 0;
+	u32 tmp, status, length;
+
+	curr_ep_context = &u3d->ep_context[index];
+	direction = index % 2;
+	ep_num = index / 2;
+
+	trb_complete = 0;
+	actual = curr_req->req.length;
+
+	while (!list_empty(&curr_req->trb_list)) {
+		curr_trb = list_entry(curr_req->trb_list.next,
+					struct mv_u3d_trb, trb_list);
+		if (!curr_trb->trb_hw->ctrl.own) {
+			dev_err(u3d->dev, "%s, TRB own error!\n",
+				u3d->eps[index].name);
+			return 1;
+		}
+
+		curr_trb->trb_hw->ctrl.own = 0;
+		if (direction == MV_U3D_EP_DIR_OUT) {
+			tmp = ioread32(&u3d->vuc_regs->rxst[ep_num].statuslo);
+			cur_deq_lo =
+				ioread32(&u3d->vuc_regs->rxst[ep_num].curdeqlo);
+		} else {
+			tmp = ioread32(&u3d->vuc_regs->txst[ep_num].statuslo);
+			cur_deq_lo =
+				ioread32(&u3d->vuc_regs->txst[ep_num].curdeqlo);
+		}
+
+		status = tmp >> MV_U3D_XFERSTATUS_COMPLETE_SHIFT;
+		length = tmp & MV_U3D_XFERSTATUS_TRB_LENGTH_MASK;
+
+		if (status == MV_U3D_COMPLETE_SUCCESS ||
+			(status == MV_U3D_COMPLETE_SHORT_PACKET &&
+			direction == MV_U3D_EP_DIR_OUT)) {
+			remaining_length += length;
+			actual -= remaining_length;
+		} else {
+			dev_err(u3d->dev,
+				"complete_tr error: ep=%d %s: error = 0x%x\n",
+				index >> 1, direction ? "SEND" : "RECV",
+				status);
+			retval = -EPROTO;
+		}
+
+		list_del_init(&curr_trb->trb_list);
+	}
+	if (retval)
+		return retval;
+
+	curr_req->req.actual = actual;
+	return 0;
+}
+
+/*
+ * mv_u3d_done() - retire a request; caller blocked irqs
+ * @status : request status to be set, only works when
+ * request is still in progress.
+ */
+static
+void mv_u3d_done(struct mv_u3d_ep *ep, struct mv_u3d_req *req, int status)
+{
+	struct mv_u3d *u3d = (struct mv_u3d *)ep->u3d;
+
+	dev_dbg(u3d->dev, "mv_u3d_done: remove req->queue\n");
+	/* Removed the req from ep queue */
+	list_del_init(&req->queue);
+
+	/* req.status should be set as -EINPROGRESS in ep_queue() */
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = status;
+	else
+		status = req->req.status;
+
+	/* Free trb for the request */
+	if (!req->chain)
+		dma_pool_free(u3d->trb_pool,
+			req->trb_head->trb_hw, req->trb_head->trb_dma);
+	else {
+		dma_unmap_single(ep->u3d->gadget.dev.parent,
+			(dma_addr_t)req->trb_head->trb_dma,
+			req->trb_count * sizeof(struct mv_u3d_trb_hw),
+			DMA_BIDIRECTIONAL);
+		kfree(req->trb_head->trb_hw);
+	}
+	kfree(req->trb_head);
+
+	usb_gadget_unmap_request(&u3d->gadget, &req->req, mv_u3d_ep_dir(ep));
+
+	if (status && (status != -ESHUTDOWN)) {
+		dev_dbg(u3d->dev, "complete %s req %p stat %d len %u/%u",
+			ep->ep.name, &req->req, status,
+			req->req.actual, req->req.length);
+	}
+
+	spin_unlock(&ep->u3d->lock);
+	/*
+	 * complete() is from gadget layer,
+	 * eg fsg->bulk_in_complete()
+	 */
+	if (req->req.complete)
+		req->req.complete(&ep->ep, &req->req);
+
+	spin_lock(&ep->u3d->lock);
+}
+
+static int mv_u3d_queue_trb(struct mv_u3d_ep *ep, struct mv_u3d_req *req)
+{
+	u32 tmp, direction;
+	struct mv_u3d *u3d;
+	struct mv_u3d_ep_context *ep_context;
+	int retval = 0;
+
+	u3d = ep->u3d;
+	direction = mv_u3d_ep_dir(ep);
+
+	/* ep0 in and out share the same ep context slot 1*/
+	if (ep->ep_num == 0)
+		ep_context = &(u3d->ep_context[1]);
+	else
+		ep_context = &(u3d->ep_context[ep->ep_num * 2 + direction]);
+
+	/* check if the pipe is empty or not */
+	if (!list_empty(&ep->queue)) {
+		dev_err(u3d->dev, "add trb to non-empty queue!\n");
+		retval = -ENOMEM;
+		WARN_ON(1);
+	} else {
+		ep_context->rsvd0 = cpu_to_le32(1);
+		ep_context->rsvd1 = 0;
+
+		/* Configure the trb address and set the DCS bit.
+		 * Both DCS bit and own bit in trb should be set.
+		 */
+		ep_context->trb_addr_lo =
+			cpu_to_le32(req->trb_head->trb_dma | DCS_ENABLE);
+		ep_context->trb_addr_hi = 0;
+
+		/* Ensure that updates to the EP Context will
+		 * occure before Ring Bell.
+		 */
+		wmb();
+
+		/* ring bell the ep */
+		if (ep->ep_num == 0)
+			tmp = 0x1;
+		else
+			tmp = ep->ep_num * 2
+				+ ((direction == MV_U3D_EP_DIR_OUT) ? 0 : 1);
+
+		iowrite32(tmp, &u3d->op_regs->doorbell);
+	}
+	return retval;
+}
+
+static struct mv_u3d_trb *mv_u3d_build_trb_one(struct mv_u3d_req *req,
+				unsigned *length, dma_addr_t *dma)
+{
+	u32 temp;
+	unsigned int direction;
+	struct mv_u3d_trb *trb;
+	struct mv_u3d_trb_hw *trb_hw;
+	struct mv_u3d *u3d;
+
+	/* how big will this transfer be? */
+	*length = req->req.length - req->req.actual;
+	BUG_ON(*length > (unsigned)MV_U3D_EP_MAX_LENGTH_TRANSFER);
+
+	u3d = req->ep->u3d;
+
+	trb = kzalloc(sizeof(*trb), GFP_ATOMIC);
+	if (!trb) {
+		dev_err(u3d->dev, "%s, trb alloc fail\n", __func__);
+		return NULL;
+	}
+
+	/*
+	 * Be careful that no _GFP_HIGHMEM is set,
+	 * or we can not use dma_to_virt
+	 * cannot use GFP_KERNEL in spin lock
+	 */
+	trb_hw = dma_pool_alloc(u3d->trb_pool, GFP_ATOMIC, dma);
+	if (!trb_hw) {
+		dev_err(u3d->dev,
+			"%s, dma_pool_alloc fail\n", __func__);
+		return NULL;
+	}
+	trb->trb_dma = *dma;
+	trb->trb_hw = trb_hw;
+
+	/* initialize buffer page pointers */
+	temp = (u32)(req->req.dma + req->req.actual);
+
+	trb_hw->buf_addr_lo = cpu_to_le32(temp);
+	trb_hw->buf_addr_hi = 0;
+	trb_hw->trb_len = cpu_to_le32(*length);
+	trb_hw->ctrl.own = 1;
+
+	if (req->ep->ep_num == 0)
+		trb_hw->ctrl.type = TYPE_DATA;
+	else
+		trb_hw->ctrl.type = TYPE_NORMAL;
+
+	req->req.actual += *length;
+
+	direction = mv_u3d_ep_dir(req->ep);
+	if (direction == MV_U3D_EP_DIR_IN)
+		trb_hw->ctrl.dir = 1;
+	else
+		trb_hw->ctrl.dir = 0;
+
+	/* Enable interrupt for the last trb of a request */
+	if (!req->req.no_interrupt)
+		trb_hw->ctrl.ioc = 1;
+
+	trb_hw->ctrl.chain = 0;
+
+	wmb();
+	return trb;
+}
+
+static int mv_u3d_build_trb_chain(struct mv_u3d_req *req, unsigned *length,
+		struct mv_u3d_trb *trb, int *is_last)
+{
+	u32 temp;
+	unsigned int direction;
+	struct mv_u3d *u3d;
+
+	/* how big will this transfer be? */
+	*length = min(req->req.length - req->req.actual,
+			(unsigned)MV_U3D_EP_MAX_LENGTH_TRANSFER);
+
+	u3d = req->ep->u3d;
+
+	trb->trb_dma = 0;
+
+	/* initialize buffer page pointers */
+	temp = (u32)(req->req.dma + req->req.actual);
+
+	trb->trb_hw->buf_addr_lo = cpu_to_le32(temp);
+	trb->trb_hw->buf_addr_hi = 0;
+	trb->trb_hw->trb_len = cpu_to_le32(*length);
+	trb->trb_hw->ctrl.own = 1;
+
+	if (req->ep->ep_num == 0)
+		trb->trb_hw->ctrl.type = TYPE_DATA;
+	else
+		trb->trb_hw->ctrl.type = TYPE_NORMAL;
+
+	req->req.actual += *length;
+
+	direction = mv_u3d_ep_dir(req->ep);
+	if (direction == MV_U3D_EP_DIR_IN)
+		trb->trb_hw->ctrl.dir = 1;
+	else
+		trb->trb_hw->ctrl.dir = 0;
+
+	/* zlp is needed if req->req.zero is set */
+	if (req->req.zero) {
+		if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0)
+			*is_last = 1;
+		else
+			*is_last = 0;
+	} else if (req->req.length == req->req.actual)
+		*is_last = 1;
+	else
+		*is_last = 0;
+
+	/* Enable interrupt for the last trb of a request */
+	if (*is_last && !req->req.no_interrupt)
+		trb->trb_hw->ctrl.ioc = 1;
+
+	if (*is_last)
+		trb->trb_hw->ctrl.chain = 0;
+	else {
+		trb->trb_hw->ctrl.chain = 1;
+		dev_dbg(u3d->dev, "chain trb\n");
+	}
+
+	wmb();
+
+	return 0;
+}
+
+/* generate TRB linked list for a request
+ * usb controller only supports continous trb chain,
+ * that trb structure physical address should be continous.
+ */
+static int mv_u3d_req_to_trb(struct mv_u3d_req *req)
+{
+	unsigned count;
+	int is_last;
+	struct mv_u3d_trb *trb;
+	struct mv_u3d_trb_hw *trb_hw;
+	struct mv_u3d *u3d;
+	dma_addr_t dma;
+	unsigned length;
+	unsigned trb_num;
+
+	u3d = req->ep->u3d;
+
+	INIT_LIST_HEAD(&req->trb_list);
+
+	length = req->req.length - req->req.actual;
+	/* normally the request transfer length is less than 16KB.
+	 * we use buil_trb_one() to optimize it.
+	 */
+	if (length <= (unsigned)MV_U3D_EP_MAX_LENGTH_TRANSFER) {
+		trb = mv_u3d_build_trb_one(req, &count, &dma);
+		list_add_tail(&trb->trb_list, &req->trb_list);
+		req->trb_head = trb;
+		req->trb_count = 1;
+		req->chain = 0;
+	} else {
+		trb_num = length / MV_U3D_EP_MAX_LENGTH_TRANSFER;
+		if (length % MV_U3D_EP_MAX_LENGTH_TRANSFER)
+			trb_num++;
+
+		trb = kcalloc(trb_num, sizeof(*trb), GFP_ATOMIC);
+		if (!trb) {
+			dev_err(u3d->dev,
+					"%s, trb alloc fail\n", __func__);
+			return -ENOMEM;
+		}
+
+		trb_hw = kcalloc(trb_num, sizeof(*trb_hw), GFP_ATOMIC);
+		if (!trb_hw) {
+			dev_err(u3d->dev,
+					"%s, trb_hw alloc fail\n", __func__);
+			return -ENOMEM;
+		}
+
+		do {
+			trb->trb_hw = trb_hw;
+			if (mv_u3d_build_trb_chain(req, &count,
+						trb, &is_last)) {
+				dev_err(u3d->dev,
+					"%s, mv_u3d_build_trb_chain fail\n",
+					__func__);
+				return -EIO;
+			}
+
+			list_add_tail(&trb->trb_list, &req->trb_list);
+			req->trb_count++;
+			trb++;
+			trb_hw++;
+		} while (!is_last);
+
+		req->trb_head = list_entry(req->trb_list.next,
+					struct mv_u3d_trb, trb_list);
+		req->trb_head->trb_dma = dma_map_single(u3d->gadget.dev.parent,
+					req->trb_head->trb_hw,
+					trb_num * sizeof(*trb_hw),
+					DMA_BIDIRECTIONAL);
+
+		req->chain = 1;
+	}
+
+	return 0;
+}
+
+static int
+mv_u3d_start_queue(struct mv_u3d_ep *ep)
+{
+	struct mv_u3d *u3d = ep->u3d;
+	struct mv_u3d_req *req;
+	int ret;
+
+	if (!list_empty(&ep->req_list) && !ep->processing)
+		req = list_entry(ep->req_list.next, struct mv_u3d_req, list);
+	else
+		return 0;
+
+	ep->processing = 1;
+
+	/* set up dma mapping */
+	ret = usb_gadget_map_request(&u3d->gadget, &req->req,
+					mv_u3d_ep_dir(ep));
+	if (ret)
+		return ret;
+
+	req->req.status = -EINPROGRESS;
+	req->req.actual = 0;
+	req->trb_count = 0;
+
+	/* build trbs and push them to device queue */
+	if (!mv_u3d_req_to_trb(req)) {
+		ret = mv_u3d_queue_trb(ep, req);
+		if (ret) {
+			ep->processing = 0;
+			return ret;
+		}
+	} else {
+		ep->processing = 0;
+		dev_err(u3d->dev, "%s, mv_u3d_req_to_trb fail\n", __func__);
+		return -ENOMEM;
+	}
+
+	/* irq handler advances the queue */
+	if (req)
+		list_add_tail(&req->queue, &ep->queue);
+
+	return 0;
+}
+
+static int mv_u3d_ep_enable(struct usb_ep *_ep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	struct mv_u3d *u3d;
+	struct mv_u3d_ep *ep;
+	struct mv_u3d_ep_context *ep_context;
+	u16 max = 0;
+	unsigned maxburst = 0;
+	u32 epxcr, direction;
+
+	if (!_ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT)
+		return -EINVAL;
+
+	ep = container_of(_ep, struct mv_u3d_ep, ep);
+	u3d = ep->u3d;
+
+	if (!u3d->driver || u3d->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	direction = mv_u3d_ep_dir(ep);
+	max = le16_to_cpu(desc->wMaxPacketSize);
+
+	if (!_ep->maxburst)
+		_ep->maxburst = 1;
+	maxburst = _ep->maxburst;
+
+	/* Get the endpoint context address */
+	ep_context = (struct mv_u3d_ep_context *)ep->ep_context;
+
+	/* Set the max burst size */
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_BULK:
+		if (maxburst > 16) {
+			dev_dbg(u3d->dev,
+				"max burst should not be greater "
+				"than 16 on bulk ep\n");
+			maxburst = 1;
+			_ep->maxburst = maxburst;
+		}
+		dev_dbg(u3d->dev,
+			"maxburst: %d on bulk %s\n", maxburst, ep->name);
+		break;
+	case USB_ENDPOINT_XFER_CONTROL:
+		/* control transfer only supports maxburst as one */
+		maxburst = 1;
+		_ep->maxburst = maxburst;
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		if (maxburst != 1) {
+			dev_dbg(u3d->dev,
+				"max burst should be 1 on int ep "
+				"if transfer size is not 1024\n");
+			maxburst = 1;
+			_ep->maxburst = maxburst;
+		}
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		if (maxburst != 1) {
+			dev_dbg(u3d->dev,
+				"max burst should be 1 on isoc ep "
+				"if transfer size is not 1024\n");
+			maxburst = 1;
+			_ep->maxburst = maxburst;
+		}
+		break;
+	default:
+		goto en_done;
+	}
+
+	ep->ep.maxpacket = max;
+	ep->ep.desc = desc;
+	ep->enabled = 1;
+
+	/* Enable the endpoint for Rx or Tx and set the endpoint type */
+	if (direction == MV_U3D_EP_DIR_OUT) {
+		epxcr = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0);
+		epxcr |= MV_U3D_EPXCR_EP_INIT;
+		iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0);
+		udelay(5);
+		epxcr &= ~MV_U3D_EPXCR_EP_INIT;
+		iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0);
+
+		epxcr = ((max << MV_U3D_EPXCR_MAX_PACKET_SIZE_SHIFT)
+		      | ((maxburst - 1) << MV_U3D_EPXCR_MAX_BURST_SIZE_SHIFT)
+		      | (1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT)
+		      | (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK));
+		iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr1);
+	} else {
+		epxcr = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxincr0);
+		epxcr |= MV_U3D_EPXCR_EP_INIT;
+		iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxincr0);
+		udelay(5);
+		epxcr &= ~MV_U3D_EPXCR_EP_INIT;
+		iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxincr0);
+
+		epxcr = ((max << MV_U3D_EPXCR_MAX_PACKET_SIZE_SHIFT)
+		      | ((maxburst - 1) << MV_U3D_EPXCR_MAX_BURST_SIZE_SHIFT)
+		      | (1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT)
+		      | (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK));
+		iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxincr1);
+	}
+
+	return 0;
+en_done:
+	return -EINVAL;
+}
+
+static int  mv_u3d_ep_disable(struct usb_ep *_ep)
+{
+	struct mv_u3d *u3d;
+	struct mv_u3d_ep *ep;
+	struct mv_u3d_ep_context *ep_context;
+	u32 epxcr, direction;
+
+	if (!_ep)
+		return -EINVAL;
+
+	ep = container_of(_ep, struct mv_u3d_ep, ep);
+	if (!ep->ep.desc)
+		return -EINVAL;
+
+	u3d = ep->u3d;
+
+	/* Get the endpoint context address */
+	ep_context = ep->ep_context;
+
+	direction = mv_u3d_ep_dir(ep);
+
+	/* nuke all pending requests (does flush) */
+	mv_u3d_nuke(ep, -ESHUTDOWN);
+
+	/* Disable the endpoint for Rx or Tx and reset the endpoint type */
+	if (direction == MV_U3D_EP_DIR_OUT) {
+		epxcr = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxoutcr1);
+		epxcr &= ~((1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT)
+		      | USB_ENDPOINT_XFERTYPE_MASK);
+		iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr1);
+	} else {
+		epxcr = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxincr1);
+		epxcr &= ~((1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT)
+		      | USB_ENDPOINT_XFERTYPE_MASK);
+		iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxincr1);
+	}
+
+	ep->enabled = 0;
+
+	ep->ep.desc = NULL;
+	return 0;
+}
+
+static struct usb_request *
+mv_u3d_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct mv_u3d_req *req = NULL;
+
+	req = kzalloc(sizeof *req, gfp_flags);
+	if (!req)
+		return NULL;
+
+	INIT_LIST_HEAD(&req->queue);
+
+	return &req->req;
+}
+
+static void mv_u3d_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct mv_u3d_req *req = container_of(_req, struct mv_u3d_req, req);
+
+	kfree(req);
+}
+
+static void mv_u3d_ep_fifo_flush(struct usb_ep *_ep)
+{
+	struct mv_u3d *u3d;
+	u32 direction;
+	struct mv_u3d_ep *ep = container_of(_ep, struct mv_u3d_ep, ep);
+	unsigned int loops;
+	u32 tmp;
+
+	/* if endpoint is not enabled, cannot flush endpoint */
+	if (!ep->enabled)
+		return;
+
+	u3d = ep->u3d;
+	direction = mv_u3d_ep_dir(ep);
+
+	/* ep0 need clear bit after flushing fifo. */
+	if (!ep->ep_num) {
+		if (direction == MV_U3D_EP_DIR_OUT) {
+			tmp = ioread32(&u3d->vuc_regs->epcr[0].epxoutcr0);
+			tmp |= MV_U3D_EPXCR_EP_FLUSH;
+			iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxoutcr0);
+			udelay(10);
+			tmp &= ~MV_U3D_EPXCR_EP_FLUSH;
+			iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxoutcr0);
+		} else {
+			tmp = ioread32(&u3d->vuc_regs->epcr[0].epxincr0);
+			tmp |= MV_U3D_EPXCR_EP_FLUSH;
+			iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxincr0);
+			udelay(10);
+			tmp &= ~MV_U3D_EPXCR_EP_FLUSH;
+			iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxincr0);
+		}
+		return;
+	}
+
+	if (direction == MV_U3D_EP_DIR_OUT) {
+		tmp = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0);
+		tmp |= MV_U3D_EPXCR_EP_FLUSH;
+		iowrite32(tmp, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0);
+
+		/* Wait until flushing completed */
+		loops = LOOPS(MV_U3D_FLUSH_TIMEOUT);
+		while (ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0) &
+			MV_U3D_EPXCR_EP_FLUSH) {
+			/*
+			 * EP_FLUSH bit should be cleared to indicate this
+			 * operation is complete
+			 */
+			if (loops == 0) {
+				dev_dbg(u3d->dev,
+				    "EP FLUSH TIMEOUT for ep%d%s\n", ep->ep_num,
+				    direction ? "in" : "out");
+				return;
+			}
+			loops--;
+			udelay(LOOPS_USEC);
+		}
+	} else {	/* EP_DIR_IN */
+		tmp = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxincr0);
+		tmp |= MV_U3D_EPXCR_EP_FLUSH;
+		iowrite32(tmp, &u3d->vuc_regs->epcr[ep->ep_num].epxincr0);
+
+		/* Wait until flushing completed */
+		loops = LOOPS(MV_U3D_FLUSH_TIMEOUT);
+		while (ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxincr0) &
+			MV_U3D_EPXCR_EP_FLUSH) {
+			/*
+			* EP_FLUSH bit should be cleared to indicate this
+			* operation is complete
+			*/
+			if (loops == 0) {
+				dev_dbg(u3d->dev,
+				    "EP FLUSH TIMEOUT for ep%d%s\n", ep->ep_num,
+				    direction ? "in" : "out");
+				return;
+			}
+			loops--;
+			udelay(LOOPS_USEC);
+		}
+	}
+}
+
+/* queues (submits) an I/O request to an endpoint */
+static int
+mv_u3d_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct mv_u3d_ep *ep;
+	struct mv_u3d_req *req;
+	struct mv_u3d *u3d;
+	unsigned long flags;
+	int is_first_req = 0;
+
+	if (unlikely(!_ep || !_req))
+		return -EINVAL;
+
+	ep = container_of(_ep, struct mv_u3d_ep, ep);
+	u3d = ep->u3d;
+
+	req = container_of(_req, struct mv_u3d_req, req);
+
+	if (!ep->ep_num
+		&& u3d->ep0_state == MV_U3D_STATUS_STAGE
+		&& !_req->length) {
+		dev_dbg(u3d->dev, "ep0 status stage\n");
+		u3d->ep0_state = MV_U3D_WAIT_FOR_SETUP;
+		return 0;
+	}
+
+	dev_dbg(u3d->dev, "%s: %s, req: 0x%x\n",
+			__func__, _ep->name, (u32)req);
+
+	/* catch various bogus parameters */
+	if (!req->req.complete || !req->req.buf
+			|| !list_empty(&req->queue)) {
+		dev_err(u3d->dev,
+			"%s, bad params, _req: 0x%x,"
+			"req->req.complete: 0x%x, req->req.buf: 0x%x,"
+			"list_empty: 0x%x\n",
+			__func__, (u32)_req,
+			(u32)req->req.complete, (u32)req->req.buf,
+			(u32)list_empty(&req->queue));
+		return -EINVAL;
+	}
+	if (unlikely(!ep->ep.desc)) {
+		dev_err(u3d->dev, "%s, bad ep\n", __func__);
+		return -EINVAL;
+	}
+	if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+		if (req->req.length > ep->ep.maxpacket)
+			return -EMSGSIZE;
+	}
+
+	if (!u3d->driver || u3d->gadget.speed == USB_SPEED_UNKNOWN) {
+		dev_err(u3d->dev,
+			"bad params of driver/speed\n");
+		return -ESHUTDOWN;
+	}
+
+	req->ep = ep;
+
+	/* Software list handles usb request. */
+	spin_lock_irqsave(&ep->req_lock, flags);
+	is_first_req = list_empty(&ep->req_list);
+	list_add_tail(&req->list, &ep->req_list);
+	spin_unlock_irqrestore(&ep->req_lock, flags);
+	if (!is_first_req) {
+		dev_dbg(u3d->dev, "list is not empty\n");
+		return 0;
+	}
+
+	dev_dbg(u3d->dev, "call mv_u3d_start_queue from usb_ep_queue\n");
+	spin_lock_irqsave(&u3d->lock, flags);
+	mv_u3d_start_queue(ep);
+	spin_unlock_irqrestore(&u3d->lock, flags);
+	return 0;
+}
+
+/* dequeues (cancels, unlinks) an I/O request from an endpoint */
+static int mv_u3d_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct mv_u3d_ep *ep;
+	struct mv_u3d_req *req;
+	struct mv_u3d *u3d;
+	struct mv_u3d_ep_context *ep_context;
+	struct mv_u3d_req *next_req;
+
+	unsigned long flags;
+	int ret = 0;
+
+	if (!_ep || !_req)
+		return -EINVAL;
+
+	ep = container_of(_ep, struct mv_u3d_ep, ep);
+	u3d = ep->u3d;
+
+	spin_lock_irqsave(&ep->u3d->lock, flags);
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* The request is in progress, or completed but not dequeued */
+	if (ep->queue.next == &req->queue) {
+		_req->status = -ECONNRESET;
+		mv_u3d_ep_fifo_flush(_ep);
+
+		/* The request isn't the last request in this ep queue */
+		if (req->queue.next != &ep->queue) {
+			dev_dbg(u3d->dev,
+				"it is the last request in this ep queue\n");
+			ep_context = ep->ep_context;
+			next_req = list_entry(req->queue.next,
+					struct mv_u3d_req, queue);
+
+			/* Point first TRB of next request to the EP context. */
+			iowrite32((u32) next_req->trb_head,
+					&ep_context->trb_addr_lo);
+		} else {
+			struct mv_u3d_ep_context *ep_context;
+			ep_context = ep->ep_context;
+			ep_context->trb_addr_lo = 0;
+			ep_context->trb_addr_hi = 0;
+		}
+
+	} else
+		WARN_ON(1);
+
+	mv_u3d_done(ep, req, -ECONNRESET);
+
+	/* remove the req from the ep req list */
+	if (!list_empty(&ep->req_list)) {
+		struct mv_u3d_req *curr_req;
+		curr_req = list_entry(ep->req_list.next,
+					struct mv_u3d_req, list);
+		if (curr_req == req) {
+			list_del_init(&req->list);
+			ep->processing = 0;
+		}
+	}
+
+out:
+	spin_unlock_irqrestore(&ep->u3d->lock, flags);
+	return ret;
+}
+
+static void
+mv_u3d_ep_set_stall(struct mv_u3d *u3d, u8 ep_num, u8 direction, int stall)
+{
+	u32 tmp;
+	struct mv_u3d_ep *ep = u3d->eps;
+
+	dev_dbg(u3d->dev, "%s\n", __func__);
+	if (direction == MV_U3D_EP_DIR_OUT) {
+		tmp = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0);
+		if (stall)
+			tmp |= MV_U3D_EPXCR_EP_HALT;
+		else
+			tmp &= ~MV_U3D_EPXCR_EP_HALT;
+		iowrite32(tmp, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0);
+	} else {
+		tmp = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxincr0);
+		if (stall)
+			tmp |= MV_U3D_EPXCR_EP_HALT;
+		else
+			tmp &= ~MV_U3D_EPXCR_EP_HALT;
+		iowrite32(tmp, &u3d->vuc_regs->epcr[ep->ep_num].epxincr0);
+	}
+}
+
+static int mv_u3d_ep_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge)
+{
+	struct mv_u3d_ep *ep;
+	unsigned long flags = 0;
+	int status = 0;
+	struct mv_u3d *u3d;
+
+	ep = container_of(_ep, struct mv_u3d_ep, ep);
+	u3d = ep->u3d;
+	if (!ep->ep.desc) {
+		status = -EINVAL;
+		goto out;
+	}
+
+	if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+		status = -EOPNOTSUPP;
+		goto out;
+	}
+
+	/*
+	 * Attempt to halt IN ep will fail if any transfer requests
+	 * are still queue
+	 */
+	if (halt && (mv_u3d_ep_dir(ep) == MV_U3D_EP_DIR_IN)
+			&& !list_empty(&ep->queue)) {
+		status = -EAGAIN;
+		goto out;
+	}
+
+	spin_lock_irqsave(&ep->u3d->lock, flags);
+	mv_u3d_ep_set_stall(u3d, ep->ep_num, mv_u3d_ep_dir(ep), halt);
+	if (halt && wedge)
+		ep->wedge = 1;
+	else if (!halt)
+		ep->wedge = 0;
+	spin_unlock_irqrestore(&ep->u3d->lock, flags);
+
+	if (ep->ep_num == 0)
+		u3d->ep0_dir = MV_U3D_EP_DIR_OUT;
+out:
+	return status;
+}
+
+static int mv_u3d_ep_set_halt(struct usb_ep *_ep, int halt)
+{
+	return mv_u3d_ep_set_halt_wedge(_ep, halt, 0);
+}
+
+static int mv_u3d_ep_set_wedge(struct usb_ep *_ep)
+{
+	return mv_u3d_ep_set_halt_wedge(_ep, 1, 1);
+}
+
+static struct usb_ep_ops mv_u3d_ep_ops = {
+	.enable		= mv_u3d_ep_enable,
+	.disable	= mv_u3d_ep_disable,
+
+	.alloc_request	= mv_u3d_alloc_request,
+	.free_request	= mv_u3d_free_request,
+
+	.queue		= mv_u3d_ep_queue,
+	.dequeue	= mv_u3d_ep_dequeue,
+
+	.set_wedge	= mv_u3d_ep_set_wedge,
+	.set_halt	= mv_u3d_ep_set_halt,
+	.fifo_flush	= mv_u3d_ep_fifo_flush,
+};
+
+static void mv_u3d_controller_stop(struct mv_u3d *u3d)
+{
+	u32 tmp;
+
+	if (!u3d->clock_gating && u3d->vbus_valid_detect)
+		iowrite32(MV_U3D_INTR_ENABLE_VBUS_VALID,
+				&u3d->vuc_regs->intrenable);
+	else
+		iowrite32(0, &u3d->vuc_regs->intrenable);
+	iowrite32(~0x0, &u3d->vuc_regs->endcomplete);
+	iowrite32(~0x0, &u3d->vuc_regs->trbunderrun);
+	iowrite32(~0x0, &u3d->vuc_regs->trbcomplete);
+	iowrite32(~0x0, &u3d->vuc_regs->linkchange);
+	iowrite32(0x1, &u3d->vuc_regs->setuplock);
+
+	/* Reset the RUN bit in the command register to stop USB */
+	tmp = ioread32(&u3d->op_regs->usbcmd);
+	tmp &= ~MV_U3D_CMD_RUN_STOP;
+	iowrite32(tmp, &u3d->op_regs->usbcmd);
+	dev_dbg(u3d->dev, "after u3d_stop, USBCMD 0x%x\n",
+		ioread32(&u3d->op_regs->usbcmd));
+}
+
+static void mv_u3d_controller_start(struct mv_u3d *u3d)
+{
+	u32 usbintr;
+	u32 temp;
+
+	/* enable link LTSSM state machine */
+	temp = ioread32(&u3d->vuc_regs->ltssm);
+	temp |= MV_U3D_LTSSM_PHY_INIT_DONE;
+	iowrite32(temp, &u3d->vuc_regs->ltssm);
+
+	/* Enable interrupts */
+	usbintr = MV_U3D_INTR_ENABLE_LINK_CHG | MV_U3D_INTR_ENABLE_TXDESC_ERR |
+		MV_U3D_INTR_ENABLE_RXDESC_ERR | MV_U3D_INTR_ENABLE_TX_COMPLETE |
+		MV_U3D_INTR_ENABLE_RX_COMPLETE | MV_U3D_INTR_ENABLE_SETUP |
+		(u3d->vbus_valid_detect ? MV_U3D_INTR_ENABLE_VBUS_VALID : 0);
+	iowrite32(usbintr, &u3d->vuc_regs->intrenable);
+
+	/* Enable ctrl ep */
+	iowrite32(0x1, &u3d->vuc_regs->ctrlepenable);
+
+	/* Set the Run bit in the command register */
+	iowrite32(MV_U3D_CMD_RUN_STOP, &u3d->op_regs->usbcmd);
+	dev_dbg(u3d->dev, "after u3d_start, USBCMD 0x%x\n",
+		ioread32(&u3d->op_regs->usbcmd));
+}
+
+static int mv_u3d_controller_reset(struct mv_u3d *u3d)
+{
+	unsigned int loops;
+	u32 tmp;
+
+	/* Stop the controller */
+	tmp = ioread32(&u3d->op_regs->usbcmd);
+	tmp &= ~MV_U3D_CMD_RUN_STOP;
+	iowrite32(tmp, &u3d->op_regs->usbcmd);
+
+	/* Reset the controller to get default values */
+	iowrite32(MV_U3D_CMD_CTRL_RESET, &u3d->op_regs->usbcmd);
+
+	/* wait for reset to complete */
+	loops = LOOPS(MV_U3D_RESET_TIMEOUT);
+	while (ioread32(&u3d->op_regs->usbcmd) & MV_U3D_CMD_CTRL_RESET) {
+		if (loops == 0) {
+			dev_err(u3d->dev,
+				"Wait for RESET completed TIMEOUT\n");
+			return -ETIMEDOUT;
+		}
+		loops--;
+		udelay(LOOPS_USEC);
+	}
+
+	/* Configure the Endpoint Context Address */
+	iowrite32(u3d->ep_context_dma, &u3d->op_regs->dcbaapl);
+	iowrite32(0, &u3d->op_regs->dcbaaph);
+
+	return 0;
+}
+
+static int mv_u3d_enable(struct mv_u3d *u3d)
+{
+	struct mv_usb_platform_data *pdata = u3d->dev->platform_data;
+	int retval;
+
+	if (u3d->active)
+		return 0;
+
+	if (!u3d->clock_gating) {
+		u3d->active = 1;
+		return 0;
+	}
+
+	dev_dbg(u3d->dev, "enable u3d\n");
+	clk_enable(u3d->clk);
+	if (pdata->phy_init) {
+		retval = pdata->phy_init(u3d->phy_regs);
+		if (retval) {
+			dev_err(u3d->dev,
+				"init phy error %d\n", retval);
+			clk_disable(u3d->clk);
+			return retval;
+		}
+	}
+	u3d->active = 1;
+
+	return 0;
+}
+
+static void mv_u3d_disable(struct mv_u3d *u3d)
+{
+	struct mv_usb_platform_data *pdata = u3d->dev->platform_data;
+	if (u3d->clock_gating && u3d->active) {
+		dev_dbg(u3d->dev, "disable u3d\n");
+		if (pdata->phy_deinit)
+			pdata->phy_deinit(u3d->phy_regs);
+		clk_disable(u3d->clk);
+		u3d->active = 0;
+	}
+}
+
+static int mv_u3d_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+	struct mv_u3d *u3d;
+	unsigned long flags;
+	int retval = 0;
+
+	u3d = container_of(gadget, struct mv_u3d, gadget);
+
+	spin_lock_irqsave(&u3d->lock, flags);
+
+	u3d->vbus_active = (is_active != 0);
+	dev_dbg(u3d->dev, "%s: softconnect %d, vbus_active %d\n",
+		__func__, u3d->softconnect, u3d->vbus_active);
+	/*
+	 * 1. external VBUS detect: we can disable/enable clock on demand.
+	 * 2. UDC VBUS detect: we have to enable clock all the time.
+	 * 3. No VBUS detect: we have to enable clock all the time.
+	 */
+	if (u3d->driver && u3d->softconnect && u3d->vbus_active) {
+		retval = mv_u3d_enable(u3d);
+		if (retval == 0) {
+			/*
+			 * after clock is disabled, we lost all the register
+			 *  context. We have to re-init registers
+			 */
+			mv_u3d_controller_reset(u3d);
+			mv_u3d_ep0_reset(u3d);
+			mv_u3d_controller_start(u3d);
+		}
+	} else if (u3d->driver && u3d->softconnect) {
+		if (!u3d->active)
+			goto out;
+
+		/* stop all the transfer in queue*/
+		mv_u3d_stop_activity(u3d, u3d->driver);
+		mv_u3d_controller_stop(u3d);
+		mv_u3d_disable(u3d);
+	}
+
+out:
+	spin_unlock_irqrestore(&u3d->lock, flags);
+	return retval;
+}
+
+/* constrain controller's VBUS power usage
+ * This call is used by gadget drivers during SET_CONFIGURATION calls,
+ * reporting how much power the device may consume.  For example, this
+ * could affect how quickly batteries are recharged.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static int mv_u3d_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+	struct mv_u3d *u3d = container_of(gadget, struct mv_u3d, gadget);
+
+	u3d->power = mA;
+
+	return 0;
+}
+
+static int mv_u3d_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct mv_u3d *u3d = container_of(gadget, struct mv_u3d, gadget);
+	unsigned long flags;
+	int retval = 0;
+
+	spin_lock_irqsave(&u3d->lock, flags);
+
+	dev_dbg(u3d->dev, "%s: softconnect %d, vbus_active %d\n",
+		__func__, u3d->softconnect, u3d->vbus_active);
+	u3d->softconnect = (is_on != 0);
+	if (u3d->driver && u3d->softconnect && u3d->vbus_active) {
+		retval = mv_u3d_enable(u3d);
+		if (retval == 0) {
+			/*
+			 * after clock is disabled, we lost all the register
+			 *  context. We have to re-init registers
+			 */
+			mv_u3d_controller_reset(u3d);
+			mv_u3d_ep0_reset(u3d);
+			mv_u3d_controller_start(u3d);
+		}
+	} else if (u3d->driver && u3d->vbus_active) {
+		/* stop all the transfer in queue*/
+		mv_u3d_stop_activity(u3d, u3d->driver);
+		mv_u3d_controller_stop(u3d);
+		mv_u3d_disable(u3d);
+	}
+
+	spin_unlock_irqrestore(&u3d->lock, flags);
+
+	return retval;
+}
+
+static int mv_u3d_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
+{
+	struct mv_u3d *u3d = container_of(g, struct mv_u3d, gadget);
+	struct mv_usb_platform_data *pdata = u3d->dev->platform_data;
+	unsigned long flags;
+
+	if (u3d->driver)
+		return -EBUSY;
+
+	spin_lock_irqsave(&u3d->lock, flags);
+
+	if (!u3d->clock_gating) {
+		clk_enable(u3d->clk);
+		if (pdata->phy_init)
+			pdata->phy_init(u3d->phy_regs);
+	}
+
+	/* hook up the driver ... */
+	driver->driver.bus = NULL;
+	u3d->driver = driver;
+	u3d->gadget.dev.driver = &driver->driver;
+
+	u3d->ep0_dir = USB_DIR_OUT;
+
+	spin_unlock_irqrestore(&u3d->lock, flags);
+
+	u3d->vbus_valid_detect = 1;
+
+	return 0;
+}
+
+static int mv_u3d_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
+{
+	struct mv_u3d *u3d = container_of(g, struct mv_u3d, gadget);
+	struct mv_usb_platform_data *pdata = u3d->dev->platform_data;
+	unsigned long flags;
+
+	u3d->vbus_valid_detect = 0;
+	spin_lock_irqsave(&u3d->lock, flags);
+
+	/* enable clock to access controller register */
+	clk_enable(u3d->clk);
+	if (pdata->phy_init)
+		pdata->phy_init(u3d->phy_regs);
+
+	mv_u3d_controller_stop(u3d);
+	/* stop all usb activities */
+	u3d->gadget.speed = USB_SPEED_UNKNOWN;
+	mv_u3d_stop_activity(u3d, driver);
+	mv_u3d_disable(u3d);
+
+	if (pdata->phy_deinit)
+		pdata->phy_deinit(u3d->phy_regs);
+	clk_disable(u3d->clk);
+
+	spin_unlock_irqrestore(&u3d->lock, flags);
+
+	u3d->gadget.dev.driver = NULL;
+	u3d->driver = NULL;
+
+	return 0;
+}
+
+/* device controller usb_gadget_ops structure */
+static const struct usb_gadget_ops mv_u3d_ops = {
+	/* notify controller that VBUS is powered or not */
+	.vbus_session	= mv_u3d_vbus_session,
+
+	/* constrain controller's VBUS power usage */
+	.vbus_draw	= mv_u3d_vbus_draw,
+
+	.pullup		= mv_u3d_pullup,
+	.udc_start	= mv_u3d_start,
+	.udc_stop	= mv_u3d_stop,
+};
+
+static int mv_u3d_eps_init(struct mv_u3d *u3d)
+{
+	struct mv_u3d_ep	*ep;
+	char name[14];
+	int i;
+
+	/* initialize ep0, ep0 in/out use eps[1] */
+	ep = &u3d->eps[1];
+	ep->u3d = u3d;
+	strncpy(ep->name, "ep0", sizeof(ep->name));
+	ep->ep.name = ep->name;
+	ep->ep.ops = &mv_u3d_ep_ops;
+	ep->wedge = 0;
+	ep->ep.maxpacket = MV_U3D_EP0_MAX_PKT_SIZE;
+	ep->ep_num = 0;
+	ep->ep.desc = &mv_u3d_ep0_desc;
+	INIT_LIST_HEAD(&ep->queue);
+	INIT_LIST_HEAD(&ep->req_list);
+	ep->ep_type = USB_ENDPOINT_XFER_CONTROL;
+
+	/* add ep0 ep_context */
+	ep->ep_context = &u3d->ep_context[1];
+
+	/* initialize other endpoints */
+	for (i = 2; i < u3d->max_eps * 2; i++) {
+		ep = &u3d->eps[i];
+		if (i & 1) {
+			snprintf(name, sizeof(name), "ep%din", i >> 1);
+			ep->direction = MV_U3D_EP_DIR_IN;
+		} else {
+			snprintf(name, sizeof(name), "ep%dout", i >> 1);
+			ep->direction = MV_U3D_EP_DIR_OUT;
+		}
+		ep->u3d = u3d;
+		strncpy(ep->name, name, sizeof(ep->name));
+		ep->ep.name = ep->name;
+
+		ep->ep.ops = &mv_u3d_ep_ops;
+		ep->ep.maxpacket = (unsigned short) ~0;
+		ep->ep_num = i / 2;
+
+		INIT_LIST_HEAD(&ep->queue);
+		list_add_tail(&ep->ep.ep_list, &u3d->gadget.ep_list);
+
+		INIT_LIST_HEAD(&ep->req_list);
+		spin_lock_init(&ep->req_lock);
+		ep->ep_context = &u3d->ep_context[i];
+	}
+
+	return 0;
+}
+
+/* delete all endpoint requests, called with spinlock held */
+static void mv_u3d_nuke(struct mv_u3d_ep *ep, int status)
+{
+	/* endpoint fifo flush */
+	mv_u3d_ep_fifo_flush(&ep->ep);
+
+	while (!list_empty(&ep->queue)) {
+		struct mv_u3d_req *req = NULL;
+		req = list_entry(ep->queue.next, struct mv_u3d_req, queue);
+		mv_u3d_done(ep, req, status);
+	}
+}
+
+/* stop all USB activities */
+static
+void mv_u3d_stop_activity(struct mv_u3d *u3d, struct usb_gadget_driver *driver)
+{
+	struct mv_u3d_ep	*ep;
+
+	mv_u3d_nuke(&u3d->eps[1], -ESHUTDOWN);
+
+	list_for_each_entry(ep, &u3d->gadget.ep_list, ep.ep_list) {
+		mv_u3d_nuke(ep, -ESHUTDOWN);
+	}
+
+	/* report disconnect; the driver is already quiesced */
+	if (driver) {
+		spin_unlock(&u3d->lock);
+		driver->disconnect(&u3d->gadget);
+		spin_lock(&u3d->lock);
+	}
+}
+
+static void mv_u3d_irq_process_error(struct mv_u3d *u3d)
+{
+	/* Increment the error count */
+	u3d->errors++;
+	dev_err(u3d->dev, "%s\n", __func__);
+}
+
+static void mv_u3d_irq_process_link_change(struct mv_u3d *u3d)
+{
+	u32 linkchange;
+
+	linkchange = ioread32(&u3d->vuc_regs->linkchange);
+	iowrite32(linkchange, &u3d->vuc_regs->linkchange);
+
+	dev_dbg(u3d->dev, "linkchange: 0x%x\n", linkchange);
+
+	if (linkchange & MV_U3D_LINK_CHANGE_LINK_UP) {
+		dev_dbg(u3d->dev, "link up: ltssm state: 0x%x\n",
+			ioread32(&u3d->vuc_regs->ltssmstate));
+
+		u3d->usb_state = USB_STATE_DEFAULT;
+		u3d->ep0_dir = MV_U3D_EP_DIR_OUT;
+		u3d->ep0_state = MV_U3D_WAIT_FOR_SETUP;
+
+		/* set speed */
+		u3d->gadget.speed = USB_SPEED_SUPER;
+	}
+
+	if (linkchange & MV_U3D_LINK_CHANGE_SUSPEND) {
+		dev_dbg(u3d->dev, "link suspend\n");
+		u3d->resume_state = u3d->usb_state;
+		u3d->usb_state = USB_STATE_SUSPENDED;
+	}
+
+	if (linkchange & MV_U3D_LINK_CHANGE_RESUME) {
+		dev_dbg(u3d->dev, "link resume\n");
+		u3d->usb_state = u3d->resume_state;
+		u3d->resume_state = 0;
+	}
+
+	if (linkchange & MV_U3D_LINK_CHANGE_WRESET) {
+		dev_dbg(u3d->dev, "warm reset\n");
+		u3d->usb_state = USB_STATE_POWERED;
+	}
+
+	if (linkchange & MV_U3D_LINK_CHANGE_HRESET) {
+		dev_dbg(u3d->dev, "hot reset\n");
+		u3d->usb_state = USB_STATE_DEFAULT;
+	}
+
+	if (linkchange & MV_U3D_LINK_CHANGE_INACT)
+		dev_dbg(u3d->dev, "inactive\n");
+
+	if (linkchange & MV_U3D_LINK_CHANGE_DISABLE_AFTER_U0)
+		dev_dbg(u3d->dev, "ss.disabled\n");
+
+	if (linkchange & MV_U3D_LINK_CHANGE_VBUS_INVALID) {
+		dev_dbg(u3d->dev, "vbus invalid\n");
+		u3d->usb_state = USB_STATE_ATTACHED;
+		u3d->vbus_valid_detect = 1;
+		/* if external vbus detect is not supported,
+		 * we handle it here.
+		 */
+		if (!u3d->vbus) {
+			spin_unlock(&u3d->lock);
+			mv_u3d_vbus_session(&u3d->gadget, 0);
+			spin_lock(&u3d->lock);
+		}
+	}
+}
+
+static void mv_u3d_ch9setaddress(struct mv_u3d *u3d,
+				struct usb_ctrlrequest *setup)
+{
+	u32 tmp;
+
+	if (u3d->usb_state != USB_STATE_DEFAULT) {
+		dev_err(u3d->dev,
+			"%s, cannot setaddr in this state (%d)\n",
+			__func__, u3d->usb_state);
+		goto err;
+	}
+
+	u3d->dev_addr = (u8)setup->wValue;
+
+	dev_dbg(u3d->dev, "%s: 0x%x\n", __func__, u3d->dev_addr);
+
+	if (u3d->dev_addr > 127) {
+		dev_err(u3d->dev,
+			"%s, u3d address is wrong (out of range)\n", __func__);
+		u3d->dev_addr = 0;
+		goto err;
+	}
+
+	/* update usb state */
+	u3d->usb_state = USB_STATE_ADDRESS;
+
+	/* set the new address */
+	tmp = ioread32(&u3d->vuc_regs->devaddrtiebrkr);
+	tmp &= ~0x7F;
+	tmp |= (u32)u3d->dev_addr;
+	iowrite32(tmp, &u3d->vuc_regs->devaddrtiebrkr);
+
+	return;
+err:
+	mv_u3d_ep0_stall(u3d);
+}
+
+static int mv_u3d_is_set_configuration(struct usb_ctrlrequest *setup)
+{
+	if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
+		if (setup->bRequest == USB_REQ_SET_CONFIGURATION)
+			return 1;
+
+	return 0;
+}
+
+static void mv_u3d_handle_setup_packet(struct mv_u3d *u3d, u8 ep_num,
+	struct usb_ctrlrequest *setup)
+{
+	bool delegate = false;
+
+	mv_u3d_nuke(&u3d->eps[ep_num * 2 + MV_U3D_EP_DIR_IN], -ESHUTDOWN);
+
+	dev_dbg(u3d->dev, "SETUP %02x.%02x v%04x i%04x l%04x\n",
+			setup->bRequestType, setup->bRequest,
+			setup->wValue, setup->wIndex, setup->wLength);
+
+	/* We process some stardard setup requests here */
+	if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+		switch (setup->bRequest) {
+		case USB_REQ_GET_STATUS:
+			delegate = true;
+			break;
+
+		case USB_REQ_SET_ADDRESS:
+			mv_u3d_ch9setaddress(u3d, setup);
+			break;
+
+		case USB_REQ_CLEAR_FEATURE:
+			delegate = true;
+			break;
+
+		case USB_REQ_SET_FEATURE:
+			delegate = true;
+			break;
+
+		default:
+			delegate = true;
+		}
+	} else
+		delegate = true;
+
+	/* delegate USB standard requests to the gadget driver */
+	if (delegate == true) {
+		/* USB requests handled by gadget */
+		if (setup->wLength) {
+			/* DATA phase from gadget, STATUS phase from u3d */
+			u3d->ep0_dir = (setup->bRequestType & USB_DIR_IN)
+					? MV_U3D_EP_DIR_IN : MV_U3D_EP_DIR_OUT;
+			spin_unlock(&u3d->lock);
+			if (u3d->driver->setup(&u3d->gadget,
+				&u3d->local_setup_buff) < 0) {
+				dev_err(u3d->dev, "setup error!\n");
+				mv_u3d_ep0_stall(u3d);
+			}
+			spin_lock(&u3d->lock);
+		} else {
+			/* no DATA phase, STATUS phase from gadget */
+			u3d->ep0_dir = MV_U3D_EP_DIR_IN;
+			u3d->ep0_state = MV_U3D_STATUS_STAGE;
+			spin_unlock(&u3d->lock);
+			if (u3d->driver->setup(&u3d->gadget,
+				&u3d->local_setup_buff) < 0)
+				mv_u3d_ep0_stall(u3d);
+			spin_lock(&u3d->lock);
+		}
+
+		if (mv_u3d_is_set_configuration(setup)) {
+			dev_dbg(u3d->dev, "u3d configured\n");
+			u3d->usb_state = USB_STATE_CONFIGURED;
+		}
+	}
+}
+
+static void mv_u3d_get_setup_data(struct mv_u3d *u3d, u8 ep_num, u8 *buffer_ptr)
+{
+	struct mv_u3d_ep_context *epcontext;
+
+	epcontext = &u3d->ep_context[ep_num * 2 + MV_U3D_EP_DIR_IN];
+
+	/* Copy the setup packet to local buffer */
+	memcpy(buffer_ptr, (u8 *) &epcontext->setup_buffer, 8);
+}
+
+static void mv_u3d_irq_process_setup(struct mv_u3d *u3d)
+{
+	u32 tmp, i;
+	/* Process all Setup packet received interrupts */
+	tmp = ioread32(&u3d->vuc_regs->setuplock);
+	if (tmp) {
+		for (i = 0; i < u3d->max_eps; i++) {
+			if (tmp & (1 << i)) {
+				mv_u3d_get_setup_data(u3d, i,
+					(u8 *)(&u3d->local_setup_buff));
+				mv_u3d_handle_setup_packet(u3d, i,
+					&u3d->local_setup_buff);
+			}
+		}
+	}
+
+	iowrite32(tmp, &u3d->vuc_regs->setuplock);
+}
+
+static void mv_u3d_irq_process_tr_complete(struct mv_u3d *u3d)
+{
+	u32 tmp, bit_pos;
+	int i, ep_num = 0, direction = 0;
+	struct mv_u3d_ep	*curr_ep;
+	struct mv_u3d_req *curr_req, *temp_req;
+	int status;
+
+	tmp = ioread32(&u3d->vuc_regs->endcomplete);
+
+	dev_dbg(u3d->dev, "tr_complete: ep: 0x%x\n", tmp);
+	if (!tmp)
+		return;
+	iowrite32(tmp, &u3d->vuc_regs->endcomplete);
+
+	for (i = 0; i < u3d->max_eps * 2; i++) {
+		ep_num = i >> 1;
+		direction = i % 2;
+
+		bit_pos = 1 << (ep_num + 16 * direction);
+
+		if (!(bit_pos & tmp))
+			continue;
+
+		if (i == 0)
+			curr_ep = &u3d->eps[1];
+		else
+			curr_ep = &u3d->eps[i];
+
+		/* remove req out of ep request list after completion */
+		dev_dbg(u3d->dev, "tr comp: check req_list\n");
+		spin_lock(&curr_ep->req_lock);
+		if (!list_empty(&curr_ep->req_list)) {
+			struct mv_u3d_req *req;
+			req = list_entry(curr_ep->req_list.next,
+						struct mv_u3d_req, list);
+			list_del_init(&req->list);
+			curr_ep->processing = 0;
+		}
+		spin_unlock(&curr_ep->req_lock);
+
+		/* process the req queue until an uncomplete request */
+		list_for_each_entry_safe(curr_req, temp_req,
+			&curr_ep->queue, queue) {
+			status = mv_u3d_process_ep_req(u3d, i, curr_req);
+			if (status)
+				break;
+			/* write back status to req */
+			curr_req->req.status = status;
+
+			/* ep0 request completion */
+			if (ep_num == 0) {
+				mv_u3d_done(curr_ep, curr_req, 0);
+				break;
+			} else {
+				mv_u3d_done(curr_ep, curr_req, status);
+			}
+		}
+
+		dev_dbg(u3d->dev, "call mv_u3d_start_queue from ep complete\n");
+		mv_u3d_start_queue(curr_ep);
+	}
+}
+
+static irqreturn_t mv_u3d_irq(int irq, void *dev)
+{
+	struct mv_u3d *u3d = (struct mv_u3d *)dev;
+	u32 status, intr;
+	u32 bridgesetting;
+	u32 trbunderrun;
+
+	spin_lock(&u3d->lock);
+
+	status = ioread32(&u3d->vuc_regs->intrcause);
+	intr = ioread32(&u3d->vuc_regs->intrenable);
+	status &= intr;
+
+	if (status == 0) {
+		spin_unlock(&u3d->lock);
+		dev_err(u3d->dev, "irq error!\n");
+		return IRQ_NONE;
+	}
+
+	if (status & MV_U3D_USBINT_VBUS_VALID) {
+		bridgesetting = ioread32(&u3d->vuc_regs->bridgesetting);
+		if (bridgesetting & MV_U3D_BRIDGE_SETTING_VBUS_VALID) {
+			/* write vbus valid bit of bridge setting to clear */
+			bridgesetting = MV_U3D_BRIDGE_SETTING_VBUS_VALID;
+			iowrite32(bridgesetting, &u3d->vuc_regs->bridgesetting);
+			dev_dbg(u3d->dev, "vbus valid\n");
+
+			u3d->usb_state = USB_STATE_POWERED;
+			u3d->vbus_valid_detect = 0;
+			/* if external vbus detect is not supported,
+			 * we handle it here.
+			 */
+			if (!u3d->vbus) {
+				spin_unlock(&u3d->lock);
+				mv_u3d_vbus_session(&u3d->gadget, 1);
+				spin_lock(&u3d->lock);
+			}
+		} else
+			dev_err(u3d->dev, "vbus bit is not set\n");
+	}
+
+	/* RX data is already in the 16KB FIFO.*/
+	if (status & MV_U3D_USBINT_UNDER_RUN) {
+		trbunderrun = ioread32(&u3d->vuc_regs->trbunderrun);
+		dev_err(u3d->dev, "under run, ep%d\n", trbunderrun);
+		iowrite32(trbunderrun, &u3d->vuc_regs->trbunderrun);
+		mv_u3d_irq_process_error(u3d);
+	}
+
+	if (status & (MV_U3D_USBINT_RXDESC_ERR | MV_U3D_USBINT_TXDESC_ERR)) {
+		/* write one to clear */
+		iowrite32(status & (MV_U3D_USBINT_RXDESC_ERR
+			| MV_U3D_USBINT_TXDESC_ERR),
+			&u3d->vuc_regs->intrcause);
+		dev_err(u3d->dev, "desc err 0x%x\n", status);
+		mv_u3d_irq_process_error(u3d);
+	}
+
+	if (status & MV_U3D_USBINT_LINK_CHG)
+		mv_u3d_irq_process_link_change(u3d);
+
+	if (status & MV_U3D_USBINT_TX_COMPLETE)
+		mv_u3d_irq_process_tr_complete(u3d);
+
+	if (status & MV_U3D_USBINT_RX_COMPLETE)
+		mv_u3d_irq_process_tr_complete(u3d);
+
+	if (status & MV_U3D_USBINT_SETUP)
+		mv_u3d_irq_process_setup(u3d);
+
+	spin_unlock(&u3d->lock);
+	return IRQ_HANDLED;
+}
+
+static void mv_u3d_gadget_release(struct device *dev)
+{
+	dev_dbg(dev, "%s\n", __func__);
+}
+
+static __devexit int mv_u3d_remove(struct platform_device *dev)
+{
+	struct mv_u3d *u3d = platform_get_drvdata(dev);
+
+	BUG_ON(u3d == NULL);
+
+	usb_del_gadget_udc(&u3d->gadget);
+
+	/* free memory allocated in probe */
+	if (u3d->trb_pool)
+		dma_pool_destroy(u3d->trb_pool);
+
+	if (u3d->ep_context)
+		dma_free_coherent(&dev->dev, u3d->ep_context_size,
+			u3d->ep_context, u3d->ep_context_dma);
+
+	kfree(u3d->eps);
+
+	if (u3d->irq)
+		free_irq(u3d->irq, &dev->dev);
+
+	if (u3d->cap_regs)
+		iounmap(u3d->cap_regs);
+	u3d->cap_regs = NULL;
+
+	kfree(u3d->status_req);
+
+	clk_put(u3d->clk);
+
+	device_unregister(&u3d->gadget.dev);
+
+	platform_set_drvdata(dev, NULL);
+
+	kfree(u3d);
+
+	return 0;
+}
+
+static int mv_u3d_probe(struct platform_device *dev)
+{
+	struct mv_u3d *u3d = NULL;
+	struct mv_usb_platform_data *pdata = dev->dev.platform_data;
+	int retval = 0;
+	struct resource *r;
+	size_t size;
+
+	if (!dev->dev.platform_data) {
+		dev_err(&dev->dev, "missing platform_data\n");
+		retval = -ENODEV;
+		goto err_pdata;
+	}
+
+	u3d = kzalloc(sizeof(*u3d), GFP_KERNEL);
+	if (!u3d) {
+		dev_err(&dev->dev, "failed to allocate memory for u3d\n");
+		retval = -ENOMEM;
+		goto err_alloc_private;
+	}
+
+	spin_lock_init(&u3d->lock);
+
+	platform_set_drvdata(dev, u3d);
+
+	u3d->dev = &dev->dev;
+	u3d->vbus = pdata->vbus;
+
+	u3d->clk = clk_get(&dev->dev, pdata->clkname[0]);
+	if (IS_ERR(u3d->clk)) {
+		retval = PTR_ERR(u3d->clk);
+		goto err_get_clk;
+	}
+
+	r = platform_get_resource_byname(dev, IORESOURCE_MEM, "capregs");
+	if (!r) {
+		dev_err(&dev->dev, "no I/O memory resource defined\n");
+		retval = -ENODEV;
+		goto err_get_cap_regs;
+	}
+
+	u3d->cap_regs = (struct mv_u3d_cap_regs __iomem *)
+		ioremap(r->start, resource_size(r));
+	if (!u3d->cap_regs) {
+		dev_err(&dev->dev, "failed to map I/O memory\n");
+		retval = -EBUSY;
+		goto err_map_cap_regs;
+	} else {
+		dev_dbg(&dev->dev, "cap_regs address: 0x%x/0x%x\n",
+			(unsigned int)r->start, (unsigned int)u3d->cap_regs);
+	}
+
+	/* we will access controller register, so enable the u3d controller */
+	clk_enable(u3d->clk);
+
+	if (pdata->phy_init) {
+		retval = pdata->phy_init(u3d->phy_regs);
+		if (retval) {
+			dev_err(&dev->dev, "init phy error %d\n", retval);
+			goto err_u3d_enable;
+		}
+	}
+
+	u3d->op_regs = (struct mv_u3d_op_regs __iomem *)((u32)u3d->cap_regs
+		+ MV_U3D_USB3_OP_REGS_OFFSET);
+
+	u3d->vuc_regs = (struct mv_u3d_vuc_regs __iomem *)((u32)u3d->cap_regs
+		+ ioread32(&u3d->cap_regs->vuoff));
+
+	u3d->max_eps = 16;
+
+	/*
+	 * some platform will use usb to download image, it may not disconnect
+	 * usb gadget before loading kernel. So first stop u3d here.
+	 */
+	mv_u3d_controller_stop(u3d);
+	iowrite32(0xFFFFFFFF, &u3d->vuc_regs->intrcause);
+
+	if (pdata->phy_deinit)
+		pdata->phy_deinit(u3d->phy_regs);
+	clk_disable(u3d->clk);
+
+	size = u3d->max_eps * sizeof(struct mv_u3d_ep_context) * 2;
+	size = (size + MV_U3D_EP_CONTEXT_ALIGNMENT - 1)
+		& ~(MV_U3D_EP_CONTEXT_ALIGNMENT - 1);
+	u3d->ep_context = dma_alloc_coherent(&dev->dev, size,
+					&u3d->ep_context_dma, GFP_KERNEL);
+	if (!u3d->ep_context) {
+		dev_err(&dev->dev, "allocate ep context memory failed\n");
+		retval = -ENOMEM;
+		goto err_alloc_ep_context;
+	}
+	u3d->ep_context_size = size;
+
+	/* create TRB dma_pool resource */
+	u3d->trb_pool = dma_pool_create("u3d_trb",
+			&dev->dev,
+			sizeof(struct mv_u3d_trb_hw),
+			MV_U3D_TRB_ALIGNMENT,
+			MV_U3D_DMA_BOUNDARY);
+
+	if (!u3d->trb_pool) {
+		retval = -ENOMEM;
+		goto err_alloc_trb_pool;
+	}
+
+	size = u3d->max_eps * sizeof(struct mv_u3d_ep) * 2;
+	u3d->eps = kzalloc(size, GFP_KERNEL);
+	if (!u3d->eps) {
+		dev_err(&dev->dev, "allocate ep memory failed\n");
+		retval = -ENOMEM;
+		goto err_alloc_eps;
+	}
+
+	/* initialize ep0 status request structure */
+	u3d->status_req = kzalloc(sizeof(struct mv_u3d_req) + 8, GFP_KERNEL);
+	if (!u3d->status_req) {
+		dev_err(&dev->dev, "allocate status_req memory failed\n");
+		retval = -ENOMEM;
+		goto err_alloc_status_req;
+	}
+	INIT_LIST_HEAD(&u3d->status_req->queue);
+
+	/* allocate a small amount of memory to get valid address */
+	u3d->status_req->req.buf = (char *)u3d->status_req
+					+ sizeof(struct mv_u3d_req);
+	u3d->status_req->req.dma = virt_to_phys(u3d->status_req->req.buf);
+
+	u3d->resume_state = USB_STATE_NOTATTACHED;
+	u3d->usb_state = USB_STATE_ATTACHED;
+	u3d->ep0_dir = MV_U3D_EP_DIR_OUT;
+	u3d->remote_wakeup = 0;
+
+	r = platform_get_resource(dev, IORESOURCE_IRQ, 0);
+	if (!r) {
+		dev_err(&dev->dev, "no IRQ resource defined\n");
+		retval = -ENODEV;
+		goto err_get_irq;
+	}
+	u3d->irq = r->start;
+	if (request_irq(u3d->irq, mv_u3d_irq,
+		IRQF_DISABLED | IRQF_SHARED, driver_name, u3d)) {
+		u3d->irq = 0;
+		dev_err(&dev->dev, "Request irq %d for u3d failed\n",
+			u3d->irq);
+		retval = -ENODEV;
+		goto err_request_irq;
+	}
+
+	/* initialize gadget structure */
+	u3d->gadget.ops = &mv_u3d_ops;	/* usb_gadget_ops */
+	u3d->gadget.ep0 = &u3d->eps[1].ep;	/* gadget ep0 */
+	INIT_LIST_HEAD(&u3d->gadget.ep_list);	/* ep_list */
+	u3d->gadget.speed = USB_SPEED_UNKNOWN;	/* speed */
+
+	/* the "gadget" abstracts/virtualizes the controller */
+	dev_set_name(&u3d->gadget.dev, "gadget");
+	u3d->gadget.dev.parent = &dev->dev;
+	u3d->gadget.dev.dma_mask = dev->dev.dma_mask;
+	u3d->gadget.dev.release = mv_u3d_gadget_release;
+	u3d->gadget.name = driver_name;		/* gadget name */
+
+	retval = device_register(&u3d->gadget.dev);
+	if (retval)
+		goto err_register_gadget_device;
+
+	mv_u3d_eps_init(u3d);
+
+	/* external vbus detection */
+	if (u3d->vbus) {
+		u3d->clock_gating = 1;
+		dev_err(&dev->dev, "external vbus detection\n");
+	}
+
+	if (!u3d->clock_gating)
+		u3d->vbus_active = 1;
+
+	/* enable usb3 controller vbus detection */
+	u3d->vbus_valid_detect = 1;
+
+	retval = usb_add_gadget_udc(&dev->dev, &u3d->gadget);
+	if (retval)
+		goto err_unregister;
+
+	dev_dbg(&dev->dev, "successful probe usb3 device %s clock gating.\n",
+		u3d->clock_gating ? "with" : "without");
+
+	return 0;
+
+err_unregister:
+	device_unregister(&u3d->gadget.dev);
+err_register_gadget_device:
+	free_irq(u3d->irq, &dev->dev);
+err_request_irq:
+err_get_irq:
+	kfree(u3d->status_req);
+err_alloc_status_req:
+	kfree(u3d->eps);
+err_alloc_eps:
+	dma_pool_destroy(u3d->trb_pool);
+err_alloc_trb_pool:
+	dma_free_coherent(&dev->dev, u3d->ep_context_size,
+		u3d->ep_context, u3d->ep_context_dma);
+err_alloc_ep_context:
+	if (pdata->phy_deinit)
+		pdata->phy_deinit(u3d->phy_regs);
+	clk_disable(u3d->clk);
+err_u3d_enable:
+	iounmap(u3d->cap_regs);
+err_map_cap_regs:
+err_get_cap_regs:
+err_get_clk:
+	clk_put(u3d->clk);
+	platform_set_drvdata(dev, NULL);
+	kfree(u3d);
+err_alloc_private:
+err_pdata:
+	return retval;
+}
+
+#ifdef CONFIG_PM
+static int mv_u3d_suspend(struct device *dev)
+{
+	struct mv_u3d *u3d = dev_get_drvdata(dev);
+
+	/*
+	 * only cable is unplugged, usb can suspend.
+	 * So do not care about clock_gating == 1, it is handled by
+	 * vbus session.
+	 */
+	if (!u3d->clock_gating) {
+		mv_u3d_controller_stop(u3d);
+
+		spin_lock_irq(&u3d->lock);
+		/* stop all usb activities */
+		mv_u3d_stop_activity(u3d, u3d->driver);
+		spin_unlock_irq(&u3d->lock);
+
+		mv_u3d_disable(u3d);
+	}
+
+	return 0;
+}
+
+static int mv_u3d_resume(struct device *dev)
+{
+	struct mv_u3d *u3d = dev_get_drvdata(dev);
+	int retval;
+
+	if (!u3d->clock_gating) {
+		retval = mv_u3d_enable(u3d);
+		if (retval)
+			return retval;
+
+		if (u3d->driver && u3d->softconnect) {
+			mv_u3d_controller_reset(u3d);
+			mv_u3d_ep0_reset(u3d);
+			mv_u3d_controller_start(u3d);
+		}
+	}
+
+	return 0;
+}
+
+SIMPLE_DEV_PM_OPS(mv_u3d_pm_ops, mv_u3d_suspend, mv_u3d_resume);
+#endif
+
+static void mv_u3d_shutdown(struct platform_device *dev)
+{
+	struct mv_u3d *u3d = dev_get_drvdata(&dev->dev);
+	u32 tmp;
+
+	tmp = ioread32(&u3d->op_regs->usbcmd);
+	tmp &= ~MV_U3D_CMD_RUN_STOP;
+	iowrite32(tmp, &u3d->op_regs->usbcmd);
+}
+
+static struct platform_driver mv_u3d_driver = {
+	.probe		= mv_u3d_probe,
+	.remove		= __exit_p(mv_u3d_remove),
+	.shutdown	= mv_u3d_shutdown,
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "mv-u3d",
+#ifdef CONFIG_PM
+		.pm	= &mv_u3d_pm_ops,
+#endif
+	},
+};
+
+module_platform_driver(mv_u3d_driver);
+MODULE_ALIAS("platform:mv-u3d");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Yu Xu <yuxu@marvell.com>");
+MODULE_LICENSE("GPL");

+ 8 - 7
drivers/usb/gadget/mv_udc_core.c

@@ -19,6 +19,7 @@
 #include <linux/sched.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/timer.h>
 #include <linux/timer.h>
 #include <linux/list.h>
 #include <linux/list.h>
@@ -1381,7 +1382,7 @@ static int mv_udc_start(struct usb_gadget_driver *driver,
 		return retval;
 		return retval;
 	}
 	}
 
 
-	if (udc->transceiver) {
+	if (!IS_ERR_OR_NULL(udc->transceiver)) {
 		retval = otg_set_peripheral(udc->transceiver->otg,
 		retval = otg_set_peripheral(udc->transceiver->otg,
 					&udc->gadget);
 					&udc->gadget);
 		if (retval) {
 		if (retval) {
@@ -2107,7 +2108,7 @@ static int __devexit mv_udc_remove(struct platform_device *dev)
 	 * then vbus irq will not be requested in udc driver.
 	 * then vbus irq will not be requested in udc driver.
 	 */
 	 */
 	if (udc->pdata && udc->pdata->vbus
 	if (udc->pdata && udc->pdata->vbus
-		&& udc->clock_gating && udc->transceiver == NULL)
+		&& udc->clock_gating && IS_ERR_OR_NULL(udc->transceiver))
 		free_irq(udc->pdata->vbus->irq, &dev->dev);
 		free_irq(udc->pdata->vbus->irq, &dev->dev);
 
 
 	/* free memory allocated in probe */
 	/* free memory allocated in probe */
@@ -2180,7 +2181,7 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
 
 
 #ifdef CONFIG_USB_OTG_UTILS
 #ifdef CONFIG_USB_OTG_UTILS
 	if (pdata->mode == MV_USB_MODE_OTG)
 	if (pdata->mode == MV_USB_MODE_OTG)
-		udc->transceiver = usb_get_transceiver();
+		udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
 #endif
 #endif
 
 
 	udc->clknum = pdata->clknum;
 	udc->clknum = pdata->clknum;
@@ -2325,7 +2326,7 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
 	eps_init(udc);
 	eps_init(udc);
 
 
 	/* VBUS detect: we can disable/enable clock on demand.*/
 	/* VBUS detect: we can disable/enable clock on demand.*/
-	if (udc->transceiver)
+	if (!IS_ERR_OR_NULL(udc->transceiver))
 		udc->clock_gating = 1;
 		udc->clock_gating = 1;
 	else if (pdata->vbus) {
 	else if (pdata->vbus) {
 		udc->clock_gating = 1;
 		udc->clock_gating = 1;
@@ -2369,7 +2370,7 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
 
 
 err_unregister:
 err_unregister:
 	if (udc->pdata && udc->pdata->vbus
 	if (udc->pdata && udc->pdata->vbus
-		&& udc->clock_gating && udc->transceiver == NULL)
+		&& udc->clock_gating && IS_ERR_OR_NULL(udc->transceiver))
 		free_irq(pdata->vbus->irq, &dev->dev);
 		free_irq(pdata->vbus->irq, &dev->dev);
 	device_unregister(&udc->gadget.dev);
 	device_unregister(&udc->gadget.dev);
 err_free_irq:
 err_free_irq:
@@ -2404,7 +2405,7 @@ static int mv_udc_suspend(struct device *_dev)
 	struct mv_udc *udc = the_controller;
 	struct mv_udc *udc = the_controller;
 
 
 	/* if OTG is enabled, the following will be done in OTG driver*/
 	/* if OTG is enabled, the following will be done in OTG driver*/
-	if (udc->transceiver)
+	if (!IS_ERR_OR_NULL(udc->transceiver))
 		return 0;
 		return 0;
 
 
 	if (udc->pdata->vbus && udc->pdata->vbus->poll)
 	if (udc->pdata->vbus && udc->pdata->vbus->poll)
@@ -2437,7 +2438,7 @@ static int mv_udc_resume(struct device *_dev)
 	int retval;
 	int retval;
 
 
 	/* if OTG is enabled, the following will be done in OTG driver*/
 	/* if OTG is enabled, the following will be done in OTG driver*/
-	if (udc->transceiver)
+	if (!IS_ERR_OR_NULL(udc->transceiver))
 		return 0;
 		return 0;
 
 
 	if (!udc->clock_gating) {
 	if (!udc->clock_gating) {

+ 181 - 253
drivers/usb/gadget/omap_udc.c

@@ -35,10 +35,11 @@
 #include <linux/usb/otg.h>
 #include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
 #include <linux/clk.h>
 #include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/prefetch.h>
 #include <linux/prefetch.h>
+#include <linux/io.h>
 
 
 #include <asm/byteorder.h>
 #include <asm/byteorder.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/irq.h>
 #include <asm/unaligned.h>
 #include <asm/unaligned.h>
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
@@ -60,11 +61,6 @@
 #define	DRIVER_DESC	"OMAP UDC driver"
 #define	DRIVER_DESC	"OMAP UDC driver"
 #define	DRIVER_VERSION	"4 October 2004"
 #define	DRIVER_VERSION	"4 October 2004"
 
 
-#define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
-
-#define OMAP2_DMA_CH(ch)	(((ch) - 1) << 1)
-#define OMAP24XX_DMA(name, ch)	(OMAP24XX_DMA_##name + OMAP2_DMA_CH(ch))
-
 /*
 /*
  * The OMAP UDC needs _very_ early endpoint setup:  before enabling the
  * The OMAP UDC needs _very_ early endpoint setup:  before enabling the
  * D+ pullup to allow enumeration.  That's too early for the gadget
  * D+ pullup to allow enumeration.  That's too early for the gadget
@@ -88,14 +84,14 @@
 #ifdef	USE_ISO
 #ifdef	USE_ISO
 static unsigned fifo_mode = 3;
 static unsigned fifo_mode = 3;
 #else
 #else
-static unsigned fifo_mode = 0;
+static unsigned fifo_mode;
 #endif
 #endif
 
 
 /* "modprobe omap_udc fifo_mode=42", or else as a kernel
 /* "modprobe omap_udc fifo_mode=42", or else as a kernel
  * boot parameter "omap_udc:fifo_mode=42"
  * boot parameter "omap_udc:fifo_mode=42"
  */
  */
-module_param (fifo_mode, uint, 0);
-MODULE_PARM_DESC (fifo_mode, "endpoint configuration");
+module_param(fifo_mode, uint, 0);
+MODULE_PARM_DESC(fifo_mode, "endpoint configuration");
 
 
 #ifdef	USE_DMA
 #ifdef	USE_DMA
 static bool use_dma = 1;
 static bool use_dma = 1;
@@ -103,8 +99,8 @@ static bool use_dma = 1;
 /* "modprobe omap_udc use_dma=y", or else as a kernel
 /* "modprobe omap_udc use_dma=y", or else as a kernel
  * boot parameter "omap_udc:use_dma=y"
  * boot parameter "omap_udc:use_dma=y"
  */
  */
-module_param (use_dma, bool, 0);
-MODULE_PARM_DESC (use_dma, "enable/disable DMA");
+module_param(use_dma, bool, 0);
+MODULE_PARM_DESC(use_dma, "enable/disable DMA");
 #else	/* !USE_DMA */
 #else	/* !USE_DMA */
 
 
 /* save a bit of code */
 /* save a bit of code */
@@ -112,8 +108,8 @@ MODULE_PARM_DESC (use_dma, "enable/disable DMA");
 #endif	/* !USE_DMA */
 #endif	/* !USE_DMA */
 
 
 
 
-static const char driver_name [] = "omap_udc";
-static const char driver_desc [] = DRIVER_DESC;
+static const char driver_name[] = "omap_udc";
+static const char driver_desc[] = DRIVER_DESC;
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -251,7 +247,7 @@ static int omap_ep_disable(struct usb_ep *_ep)
 
 
 	spin_lock_irqsave(&ep->udc->lock, flags);
 	spin_lock_irqsave(&ep->udc->lock, flags);
 	ep->ep.desc = NULL;
 	ep->ep.desc = NULL;
-	nuke (ep, -ESHUTDOWN);
+	nuke(ep, -ESHUTDOWN);
 	ep->ep.maxpacket = ep->maxpacket;
 	ep->ep.maxpacket = ep->maxpacket;
 	ep->has_dma = 0;
 	ep->has_dma = 0;
 	omap_writew(UDC_SET_HALT, UDC_CTRL);
 	omap_writew(UDC_SET_HALT, UDC_CTRL);
@@ -272,10 +268,11 @@ omap_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
 	struct omap_req	*req;
 	struct omap_req	*req;
 
 
 	req = kzalloc(sizeof(*req), gfp_flags);
 	req = kzalloc(sizeof(*req), gfp_flags);
-	if (req) {
-		req->req.dma = DMA_ADDR_INVALID;
-		INIT_LIST_HEAD (&req->queue);
-	}
+	if (!req)
+		return NULL;
+
+	INIT_LIST_HEAD(&req->queue);
+
 	return &req->req;
 	return &req->req;
 }
 }
 
 
@@ -284,8 +281,7 @@ omap_free_request(struct usb_ep *ep, struct usb_request *_req)
 {
 {
 	struct omap_req	*req = container_of(_req, struct omap_req, req);
 	struct omap_req	*req = container_of(_req, struct omap_req, req);
 
 
-	if (_req)
-		kfree (req);
+	kfree(req);
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -293,6 +289,7 @@ omap_free_request(struct usb_ep *ep, struct usb_request *_req)
 static void
 static void
 done(struct omap_ep *ep, struct omap_req *req, int status)
 done(struct omap_ep *ep, struct omap_req *req, int status)
 {
 {
+	struct omap_udc		*udc = ep->udc;
 	unsigned		stopped = ep->stopped;
 	unsigned		stopped = ep->stopped;
 
 
 	list_del_init(&req->queue);
 	list_del_init(&req->queue);
@@ -302,22 +299,9 @@ done(struct omap_ep *ep, struct omap_req *req, int status)
 	else
 	else
 		status = req->req.status;
 		status = req->req.status;
 
 
-	if (use_dma && ep->has_dma) {
-		if (req->mapped) {
-			dma_unmap_single(ep->udc->gadget.dev.parent,
-				req->req.dma, req->req.length,
-				(ep->bEndpointAddress & USB_DIR_IN)
-					? DMA_TO_DEVICE
-					: DMA_FROM_DEVICE);
-			req->req.dma = DMA_ADDR_INVALID;
-			req->mapped = 0;
-		} else
-			dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
-				req->req.dma, req->req.length,
-				(ep->bEndpointAddress & USB_DIR_IN)
-					? DMA_TO_DEVICE
-					: DMA_FROM_DEVICE);
-	}
+	if (use_dma && ep->has_dma)
+		usb_gadget_unmap_request(&udc->gadget, &req->req,
+				(ep->bEndpointAddress & USB_DIR_IN));
 
 
 #ifndef	USB_TRACE
 #ifndef	USB_TRACE
 	if (status && status != -ESHUTDOWN)
 	if (status && status != -ESHUTDOWN)
@@ -365,10 +349,10 @@ write_packet(u8 *buf, struct omap_req *req, unsigned max)
 	return len;
 	return len;
 }
 }
 
 
-// FIXME change r/w fifo calling convention
+/* FIXME change r/w fifo calling convention */
 
 
 
 
-// return:  0 = still running, 1 = completed, negative = errno
+/* return:  0 = still running, 1 = completed, negative = errno */
 static int write_fifo(struct omap_ep *ep, struct omap_req *req)
 static int write_fifo(struct omap_ep *ep, struct omap_req *req)
 {
 {
 	u8		*buf;
 	u8		*buf;
@@ -430,7 +414,7 @@ read_packet(u8 *buf, struct omap_req *req, unsigned avail)
 	return len;
 	return len;
 }
 }
 
 
-// return:  0 = still running, 1 = queue empty, negative = errno
+/* return:  0 = still running, 1 = queue empty, negative = errno */
 static int read_fifo(struct omap_ep *ep, struct omap_req *req)
 static int read_fifo(struct omap_ep *ep, struct omap_req *req)
 {
 {
 	u8		*buf;
 	u8		*buf;
@@ -537,12 +521,8 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
 				: OMAP_DMA_SYNC_ELEMENT;
 				: OMAP_DMA_SYNC_ELEMENT;
 	int		dma_trigger = 0;
 	int		dma_trigger = 0;
 
 
-	if (cpu_is_omap24xx())
-		dma_trigger = OMAP24XX_DMA(USB_W2FC_TX0, ep->dma_channel);
-
 	/* measure length in either bytes or packets */
 	/* measure length in either bytes or packets */
 	if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC)
 	if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC)
-			|| (cpu_is_omap24xx() && length < ep->maxpacket)
 			|| (cpu_is_omap15xx() && length < ep->maxpacket)) {
 			|| (cpu_is_omap15xx() && length < ep->maxpacket)) {
 		txdma_ctrl = UDC_TXN_EOT | length;
 		txdma_ctrl = UDC_TXN_EOT | length;
 		omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
 		omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
@@ -601,28 +581,14 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
 	int dma_trigger = 0;
 	int dma_trigger = 0;
 	u16 w;
 	u16 w;
 
 
-	if (cpu_is_omap24xx())
-		dma_trigger = OMAP24XX_DMA(USB_W2FC_RX0, ep->dma_channel);
-
-	/* NOTE:  we filtered out "short reads" before, so we know
-	 * the buffer has only whole numbers of packets.
-	 * except MODE SELECT(6) sent the 24 bytes data in OMAP24XX DMA mode
-	 */
-	if (cpu_is_omap24xx() && packets < ep->maxpacket) {
-		omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
-				packets, 1, OMAP_DMA_SYNC_ELEMENT,
-				dma_trigger, 0);
-		req->dma_bytes = packets;
-	} else {
-		/* set up this DMA transfer, enable the fifo, start */
-		packets /= ep->ep.maxpacket;
-		packets = min(packets, (unsigned)UDC_RXN_TC + 1);
-		req->dma_bytes = packets * ep->ep.maxpacket;
-		omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
-				ep->ep.maxpacket >> 1, packets,
-				OMAP_DMA_SYNC_ELEMENT,
-				dma_trigger, 0);
-	}
+	/* set up this DMA transfer, enable the fifo, start */
+	packets /= ep->ep.maxpacket;
+	packets = min(packets, (unsigned)UDC_RXN_TC + 1);
+	req->dma_bytes = packets * ep->ep.maxpacket;
+	omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
+			ep->ep.maxpacket >> 1, packets,
+			OMAP_DMA_SYNC_ELEMENT,
+			dma_trigger, 0);
 	omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
 	omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
 		OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
 		OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
 		0, 0);
 		0, 0);
@@ -684,7 +650,7 @@ static void dma_irq(struct omap_udc *udc, u16 irq_src)
 		}
 		}
 		omap_writew(UDC_TXN_DONE, UDC_IRQ_SRC);
 		omap_writew(UDC_TXN_DONE, UDC_IRQ_SRC);
 
 
-		if (!list_empty (&ep->queue)) {
+		if (!list_empty(&ep->queue)) {
 			req = container_of(ep->queue.next,
 			req = container_of(ep->queue.next,
 					struct omap_req, queue);
 					struct omap_req, queue);
 			next_in_dma(ep, req);
 			next_in_dma(ep, req);
@@ -703,7 +669,7 @@ static void dma_irq(struct omap_udc *udc, u16 irq_src)
 		}
 		}
 		omap_writew(UDC_RXN_EOT, UDC_IRQ_SRC);
 		omap_writew(UDC_RXN_EOT, UDC_IRQ_SRC);
 
 
-		if (!list_empty (&ep->queue)) {
+		if (!list_empty(&ep->queue)) {
 			req = container_of(ep->queue.next,
 			req = container_of(ep->queue.next,
 					struct omap_req, queue);
 					struct omap_req, queue);
 			next_out_dma(ep, req);
 			next_out_dma(ep, req);
@@ -761,10 +727,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
 	ep->dma_channel = channel;
 	ep->dma_channel = channel;
 
 
 	if (is_in) {
 	if (is_in) {
-		if (cpu_is_omap24xx())
-			dma_channel = OMAP24XX_DMA(USB_W2FC_TX0, channel);
-		else
-			dma_channel = OMAP_DMA_USB_W2FC_TX0 - 1 + channel;
+		dma_channel = OMAP_DMA_USB_W2FC_TX0 - 1 + channel;
 		status = omap_request_dma(dma_channel,
 		status = omap_request_dma(dma_channel,
 			ep->ep.name, dma_error, ep, &ep->lch);
 			ep->ep.name, dma_error, ep, &ep->lch);
 		if (status == 0) {
 		if (status == 0) {
@@ -781,11 +744,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
 				0, 0);
 				0, 0);
 		}
 		}
 	} else {
 	} else {
-		if (cpu_is_omap24xx())
-			dma_channel = OMAP24XX_DMA(USB_W2FC_RX0, channel);
-		else
-			dma_channel = OMAP_DMA_USB_W2FC_RX0 - 1 + channel;
-
+		dma_channel = OMAP_DMA_USB_W2FC_RX0 - 1 + channel;
 		status = omap_request_dma(dma_channel,
 		status = omap_request_dma(dma_channel,
 			ep->ep.name, dma_error, ep, &ep->lch);
 			ep->ep.name, dma_error, ep, &ep->lch);
 		if (status == 0) {
 		if (status == 0) {
@@ -809,7 +768,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
 		omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ);
 		omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ);
 
 
 		/* channel type P: hw synch (fifo) */
 		/* channel type P: hw synch (fifo) */
-		if (cpu_class_is_omap1() && !cpu_is_omap15xx())
+		if (!cpu_is_omap15xx())
 			omap_set_dma_channel_mode(ep->lch, OMAP_DMA_LCH_P);
 			omap_set_dma_channel_mode(ep->lch, OMAP_DMA_LCH_P);
 	}
 	}
 
 
@@ -929,13 +888,11 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 
 
 	/* this isn't bogus, but OMAP DMA isn't the only hardware to
 	/* this isn't bogus, but OMAP DMA isn't the only hardware to
 	 * have a hard time with partial packet reads...  reject it.
 	 * have a hard time with partial packet reads...  reject it.
-	 * Except OMAP2 can handle the small packets.
 	 */
 	 */
 	if (use_dma
 	if (use_dma
 			&& ep->has_dma
 			&& ep->has_dma
 			&& ep->bEndpointAddress != 0
 			&& ep->bEndpointAddress != 0
 			&& (ep->bEndpointAddress & USB_DIR_IN) == 0
 			&& (ep->bEndpointAddress & USB_DIR_IN) == 0
-			&& !cpu_class_is_omap2()
 			&& (req->req.length % ep->ep.maxpacket) != 0) {
 			&& (req->req.length % ep->ep.maxpacket) != 0) {
 		DBG("%s, no partial packet OUT reads\n", __func__);
 		DBG("%s, no partial packet OUT reads\n", __func__);
 		return -EMSGSIZE;
 		return -EMSGSIZE;
@@ -945,26 +902,9 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
 	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
 		return -ESHUTDOWN;
 		return -ESHUTDOWN;
 
 
-	if (use_dma && ep->has_dma) {
-		if (req->req.dma == DMA_ADDR_INVALID) {
-			req->req.dma = dma_map_single(
-				ep->udc->gadget.dev.parent,
-				req->req.buf,
-				req->req.length,
-				(ep->bEndpointAddress & USB_DIR_IN)
-					? DMA_TO_DEVICE
-					: DMA_FROM_DEVICE);
-			req->mapped = 1;
-		} else {
-			dma_sync_single_for_device(
-				ep->udc->gadget.dev.parent,
-				req->req.dma, req->req.length,
-				(ep->bEndpointAddress & USB_DIR_IN)
-					? DMA_TO_DEVICE
-					: DMA_FROM_DEVICE);
-			req->mapped = 0;
-		}
-	}
+	if (use_dma && ep->has_dma)
+		usb_gadget_map_request(&udc->gadget, &req->req,
+				(ep->bEndpointAddress & USB_DIR_IN));
 
 
 	VDBG("%s queue req %p, len %d buf %p\n",
 	VDBG("%s queue req %p, len %d buf %p\n",
 		ep->ep.name, _req, _req->length, _req->buf);
 		ep->ep.name, _req, _req->length, _req->buf);
@@ -985,7 +925,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 		int	is_in;
 		int	is_in;
 
 
 		if (ep->bEndpointAddress == 0) {
 		if (ep->bEndpointAddress == 0) {
-			if (!udc->ep0_pending || !list_empty (&ep->queue)) {
+			if (!udc->ep0_pending || !list_empty(&ep->queue)) {
 				spin_unlock_irqrestore(&udc->lock, flags);
 				spin_unlock_irqrestore(&udc->lock, flags);
 				return -EL2HLT;
 				return -EL2HLT;
 			}
 			}
@@ -1012,7 +952,8 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 				 * always an IN ... even for IN transfers,
 				 * always an IN ... even for IN transfers,
 				 * a weird case which seem to stall OMAP.
 				 * a weird case which seem to stall OMAP.
 				 */
 				 */
-				omap_writew(UDC_EP_SEL | UDC_EP_DIR, UDC_EP_NUM);
+				omap_writew(UDC_EP_SEL | UDC_EP_DIR,
+						UDC_EP_NUM);
 				omap_writew(UDC_CLR_EP, UDC_CTRL);
 				omap_writew(UDC_CLR_EP, UDC_CTRL);
 				omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
 				omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
 				omap_writew(UDC_EP_DIR, UDC_EP_NUM);
 				omap_writew(UDC_EP_DIR, UDC_EP_NUM);
@@ -1024,7 +965,8 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 
 
 			/* non-empty DATA stage */
 			/* non-empty DATA stage */
 			} else if (is_in) {
 			} else if (is_in) {
-				omap_writew(UDC_EP_SEL | UDC_EP_DIR, UDC_EP_NUM);
+				omap_writew(UDC_EP_SEL | UDC_EP_DIR,
+						UDC_EP_NUM);
 			} else {
 			} else {
 				if (udc->ep0_setup)
 				if (udc->ep0_setup)
 					goto irq_wait;
 					goto irq_wait;
@@ -1072,7 +1014,7 @@ static int omap_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
 	spin_lock_irqsave(&ep->udc->lock, flags);
 	spin_lock_irqsave(&ep->udc->lock, flags);
 
 
 	/* make sure it's actually queued on this endpoint */
 	/* make sure it's actually queued on this endpoint */
-	list_for_each_entry (req, &ep->queue, queue) {
+	list_for_each_entry(req, &ep->queue, queue) {
 		if (&req->req == _req)
 		if (&req->req == _req)
 			break;
 			break;
 	}
 	}
@@ -1179,8 +1121,8 @@ static struct usb_ep_ops omap_ep_ops = {
 	.dequeue	= omap_ep_dequeue,
 	.dequeue	= omap_ep_dequeue,
 
 
 	.set_halt	= omap_ep_set_halt,
 	.set_halt	= omap_ep_set_halt,
-	// fifo_status ... report bytes in fifo
-	// fifo_flush ... flush fifo
+	/* fifo_status ... report bytes in fifo */
+	/* fifo_flush ... flush fifo */
 };
 };
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -1212,7 +1154,7 @@ static int omap_wakeup(struct usb_gadget *gadget)
 
 
 	/* NOTE:  non-OTG systems may use SRP TOO... */
 	/* NOTE:  non-OTG systems may use SRP TOO... */
 	} else if (!(udc->devstat & UDC_ATT)) {
 	} else if (!(udc->devstat & UDC_ATT)) {
-		if (udc->transceiver)
+		if (!IS_ERR_OR_NULL(udc->transceiver))
 			retval = otg_start_srp(udc->transceiver->otg);
 			retval = otg_start_srp(udc->transceiver->otg);
 	}
 	}
 	spin_unlock_irqrestore(&udc->lock, flags);
 	spin_unlock_irqrestore(&udc->lock, flags);
@@ -1344,7 +1286,7 @@ static int omap_vbus_draw(struct usb_gadget *gadget, unsigned mA)
 	struct omap_udc	*udc;
 	struct omap_udc	*udc;
 
 
 	udc = container_of(gadget, struct omap_udc, gadget);
 	udc = container_of(gadget, struct omap_udc, gadget);
-	if (udc->transceiver)
+	if (!IS_ERR_OR_NULL(udc->transceiver))
 		return usb_phy_set_power(udc->transceiver, mA);
 		return usb_phy_set_power(udc->transceiver, mA);
 	return -EOPNOTSUPP;
 	return -EOPNOTSUPP;
 }
 }
@@ -1410,7 +1352,7 @@ static void udc_quiesce(struct omap_udc *udc)
 
 
 	udc->gadget.speed = USB_SPEED_UNKNOWN;
 	udc->gadget.speed = USB_SPEED_UNKNOWN;
 	nuke(&udc->ep[0], -ESHUTDOWN);
 	nuke(&udc->ep[0], -ESHUTDOWN);
-	list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list)
+	list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list)
 		nuke(ep, -ESHUTDOWN);
 		nuke(ep, -ESHUTDOWN);
 }
 }
 
 
@@ -1526,7 +1468,8 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
 				/* read next OUT packet of request, maybe
 				/* read next OUT packet of request, maybe
 				 * reactiviting the fifo; stall on errors.
 				 * reactiviting the fifo; stall on errors.
 				 */
 				 */
-				if (!req || (stat = read_fifo(ep0, req)) < 0) {
+				stat = read_fifo(ep0, req);
+				if (!req || stat < 0) {
 					omap_writew(UDC_STALL_CMD, UDC_SYSCON2);
 					omap_writew(UDC_STALL_CMD, UDC_SYSCON2);
 					udc->ep0_pending = 0;
 					udc->ep0_pending = 0;
 					stat = 0;
 					stat = 0;
@@ -1659,7 +1602,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
 				/* this has rude side-effects (aborts) and
 				/* this has rude side-effects (aborts) and
 				 * can't really work if DMA-IN is active
 				 * can't really work if DMA-IN is active
 				 */
 				 */
-				DBG("%s host set_halt, NYET \n", ep->name);
+				DBG("%s host set_halt, NYET\n", ep->name);
 				goto do_stall;
 				goto do_stall;
 			}
 			}
 			use_ep(ep, 0);
 			use_ep(ep, 0);
@@ -1750,7 +1693,7 @@ delegate:
 			 */
 			 */
 			udc->ep0_setup = 1;
 			udc->ep0_setup = 1;
 			spin_unlock(&udc->lock);
 			spin_unlock(&udc->lock);
-			status = udc->driver->setup (&udc->gadget, &u.r);
+			status = udc->driver->setup(&udc->gadget, &u.r);
 			spin_lock(&udc->lock);
 			spin_lock(&udc->lock);
 			udc->ep0_setup = 0;
 			udc->ep0_setup = 0;
 		}
 		}
@@ -1793,12 +1736,12 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src)
 			if (devstat & UDC_ATT) {
 			if (devstat & UDC_ATT) {
 				udc->gadget.speed = USB_SPEED_FULL;
 				udc->gadget.speed = USB_SPEED_FULL;
 				VDBG("connect\n");
 				VDBG("connect\n");
-				if (!udc->transceiver)
+				if (IS_ERR_OR_NULL(udc->transceiver))
 					pullup_enable(udc);
 					pullup_enable(udc);
-				// if (driver->connect) call it
+				/* if (driver->connect) call it */
 			} else if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
 			} else if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
 				udc->gadget.speed = USB_SPEED_UNKNOWN;
 				udc->gadget.speed = USB_SPEED_UNKNOWN;
-				if (!udc->transceiver)
+				if (IS_ERR_OR_NULL(udc->transceiver))
 					pullup_disable(udc);
 					pullup_disable(udc);
 				DBG("disconnect, gadget %s\n",
 				DBG("disconnect, gadget %s\n",
 					udc->driver->driver.name);
 					udc->driver->driver.name);
@@ -1827,7 +1770,7 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src)
 	}
 	}
 	if (change & UDC_SUS) {
 	if (change & UDC_SUS) {
 		if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
 		if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
-			// FIXME tell isp1301 to suspend/resume (?)
+			/* FIXME tell isp1301 to suspend/resume (?) */
 			if (devstat & UDC_SUS) {
 			if (devstat & UDC_SUS) {
 				VDBG("suspend\n");
 				VDBG("suspend\n");
 				update_otg(udc);
 				update_otg(udc);
@@ -1838,12 +1781,12 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src)
 					udc->driver->suspend(&udc->gadget);
 					udc->driver->suspend(&udc->gadget);
 					spin_lock(&udc->lock);
 					spin_lock(&udc->lock);
 				}
 				}
-				if (udc->transceiver)
+				if (!IS_ERR_OR_NULL(udc->transceiver))
 					usb_phy_set_suspend(
 					usb_phy_set_suspend(
 							udc->transceiver, 1);
 							udc->transceiver, 1);
 			} else {
 			} else {
 				VDBG("resume\n");
 				VDBG("resume\n");
-				if (udc->transceiver)
+				if (!IS_ERR_OR_NULL(udc->transceiver))
 					usb_phy_set_suspend(
 					usb_phy_set_suspend(
 							udc->transceiver, 0);
 							udc->transceiver, 0);
 				if (udc->gadget.speed == USB_SPEED_FULL
 				if (udc->gadget.speed == USB_SPEED_FULL
@@ -2030,7 +1973,7 @@ static irqreturn_t omap_udc_iso_irq(int irq, void *_dev)
 	spin_lock_irqsave(&udc->lock, flags);
 	spin_lock_irqsave(&udc->lock, flags);
 
 
 	/* handle all non-DMA ISO transfers */
 	/* handle all non-DMA ISO transfers */
-	list_for_each_entry (ep, &udc->iso, iso) {
+	list_for_each_entry(ep, &udc->iso, iso) {
 		u16		stat;
 		u16		stat;
 		struct omap_req	*req;
 		struct omap_req	*req;
 
 
@@ -2089,15 +2032,11 @@ static irqreturn_t omap_udc_iso_irq(int irq, void *_dev)
 
 
 static inline int machine_without_vbus_sense(void)
 static inline int machine_without_vbus_sense(void)
 {
 {
-	return (machine_is_omap_innovator()
+	return machine_is_omap_innovator()
 		|| machine_is_omap_osk()
 		|| machine_is_omap_osk()
-		|| machine_is_omap_apollon()
-#ifndef CONFIG_MACH_OMAP_H4_OTG
-		|| machine_is_omap_h4()
-#endif
 		|| machine_is_sx1()
 		|| machine_is_sx1()
-		|| cpu_is_omap7xx() /* No known omap7xx boards with vbus sense */
-		);
+		/* No known omap7xx boards with vbus sense */
+		|| cpu_is_omap7xx();
 }
 }
 
 
 static int omap_udc_start(struct usb_gadget_driver *driver,
 static int omap_udc_start(struct usb_gadget_driver *driver,
@@ -2111,7 +2050,7 @@ static int omap_udc_start(struct usb_gadget_driver *driver,
 	if (!udc)
 	if (!udc)
 		return -ENODEV;
 		return -ENODEV;
 	if (!driver
 	if (!driver
-			// FIXME if otg, check:  driver->is_otg
+			/* FIXME if otg, check:  driver->is_otg */
 			|| driver->max_speed < USB_SPEED_FULL
 			|| driver->max_speed < USB_SPEED_FULL
 			|| !bind || !driver->setup)
 			|| !bind || !driver->setup)
 		return -EINVAL;
 		return -EINVAL;
@@ -2123,7 +2062,7 @@ static int omap_udc_start(struct usb_gadget_driver *driver,
 	}
 	}
 
 
 	/* reset state */
 	/* reset state */
-	list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
+	list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
 		ep->irqs = 0;
 		ep->irqs = 0;
 		if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC)
 		if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC)
 			continue;
 			continue;
@@ -2155,13 +2094,13 @@ static int omap_udc_start(struct usb_gadget_driver *driver,
 	omap_writew(UDC_IRQ_SRC_MASK, UDC_IRQ_SRC);
 	omap_writew(UDC_IRQ_SRC_MASK, UDC_IRQ_SRC);
 
 
 	/* connect to bus through transceiver */
 	/* connect to bus through transceiver */
-	if (udc->transceiver) {
+	if (!IS_ERR_OR_NULL(udc->transceiver)) {
 		status = otg_set_peripheral(udc->transceiver->otg,
 		status = otg_set_peripheral(udc->transceiver->otg,
 						&udc->gadget);
 						&udc->gadget);
 		if (status < 0) {
 		if (status < 0) {
 			ERR("can't bind to transceiver\n");
 			ERR("can't bind to transceiver\n");
 			if (driver->unbind) {
 			if (driver->unbind) {
-				driver->unbind (&udc->gadget);
+				driver->unbind(&udc->gadget);
 				udc->gadget.dev.driver = NULL;
 				udc->gadget.dev.driver = NULL;
 				udc->driver = NULL;
 				udc->driver = NULL;
 			}
 			}
@@ -2169,9 +2108,9 @@ static int omap_udc_start(struct usb_gadget_driver *driver,
 		}
 		}
 	} else {
 	} else {
 		if (can_pullup(udc))
 		if (can_pullup(udc))
-			pullup_enable (udc);
+			pullup_enable(udc);
 		else
 		else
-			pullup_disable (udc);
+			pullup_disable(udc);
 	}
 	}
 
 
 	/* boards that don't have VBUS sensing can't autogate 48MHz;
 	/* boards that don't have VBUS sensing can't autogate 48MHz;
@@ -2202,7 +2141,7 @@ static int omap_udc_stop(struct usb_gadget_driver *driver)
 	if (machine_without_vbus_sense())
 	if (machine_without_vbus_sense())
 		omap_vbus_session(&udc->gadget, 0);
 		omap_vbus_session(&udc->gadget, 0);
 
 
-	if (udc->transceiver)
+	if (!IS_ERR_OR_NULL(udc->transceiver))
 		(void) otg_set_peripheral(udc->transceiver->otg, NULL);
 		(void) otg_set_peripheral(udc->transceiver->otg, NULL);
 	else
 	else
 		pullup_disable(udc);
 		pullup_disable(udc);
@@ -2230,7 +2169,7 @@ static int omap_udc_stop(struct usb_gadget_driver *driver)
 static const char proc_filename[] = "driver/udc";
 static const char proc_filename[] = "driver/udc";
 
 
 #define FOURBITS "%s%s%s%s"
 #define FOURBITS "%s%s%s%s"
-#define EIGHTBITS FOURBITS FOURBITS
+#define EIGHTBITS "%s%s%s%s%s%s%s%s"
 
 
 static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
 static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
 {
 {
@@ -2252,12 +2191,21 @@ static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
 		"\n%s %s%s%sirqs %ld stat %04x " EIGHTBITS FOURBITS "%s\n",
 		"\n%s %s%s%sirqs %ld stat %04x " EIGHTBITS FOURBITS "%s\n",
 		ep->name, buf,
 		ep->name, buf,
 		ep->double_buf ? "dbuf " : "",
 		ep->double_buf ? "dbuf " : "",
-		({char *s; switch(ep->ackwait){
-		case 0: s = ""; break;
-		case 1: s = "(ackw) "; break;
-		case 2: s = "(ackw2) "; break;
-		default: s = "(?) "; break;
-		} s;}),
+		({ char *s;
+		switch (ep->ackwait) {
+		case 0:
+			s = "";
+			break;
+		case 1:
+			s = "(ackw) ";
+			break;
+		case 2:
+			s = "(ackw2) ";
+			break;
+		default:
+			s = "(?) ";
+			break;
+		} s; }),
 		ep->irqs, stat_flg,
 		ep->irqs, stat_flg,
 		(stat_flg & UDC_NO_RXPACKET) ? "no_rxpacket " : "",
 		(stat_flg & UDC_NO_RXPACKET) ? "no_rxpacket " : "",
 		(stat_flg & UDC_MISS_IN) ? "miss_in " : "",
 		(stat_flg & UDC_MISS_IN) ? "miss_in " : "",
@@ -2273,10 +2221,10 @@ static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
 		(stat_flg & UDC_NON_ISO_FIFO_EMPTY) ? "fifo_empty " : "",
 		(stat_flg & UDC_NON_ISO_FIFO_EMPTY) ? "fifo_empty " : "",
 		(stat_flg & UDC_NON_ISO_FIFO_FULL) ? "fifo_full " : "");
 		(stat_flg & UDC_NON_ISO_FIFO_FULL) ? "fifo_full " : "");
 
 
-	if (list_empty (&ep->queue))
+	if (list_empty(&ep->queue))
 		seq_printf(s, "\t(queue empty)\n");
 		seq_printf(s, "\t(queue empty)\n");
 	else
 	else
-		list_for_each_entry (req, &ep->queue, queue) {
+		list_for_each_entry(req, &ep->queue, queue) {
 			unsigned	length = req->req.actual;
 			unsigned	length = req->req.actual;
 
 
 			if (use_dma && buf[0]) {
 			if (use_dma && buf[0]) {
@@ -2294,11 +2242,16 @@ static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
 static char *trx_mode(unsigned m, int enabled)
 static char *trx_mode(unsigned m, int enabled)
 {
 {
 	switch (m) {
 	switch (m) {
-	case 0:		return enabled ? "*6wire" : "unused";
-	case 1:		return "4wire";
-	case 2:		return "3wire";
-	case 3:		return "6wire";
-	default:	return "unknown";
+	case 0:
+		return enabled ? "*6wire" : "unused";
+	case 1:
+		return "4wire";
+	case 2:
+		return "3wire";
+	case 3:
+		return "6wire";
+	default:
+		return "unknown";
 	}
 	}
 }
 }
 
 
@@ -2308,12 +2261,9 @@ static int proc_otg_show(struct seq_file *s)
 	u32		trans = 0;
 	u32		trans = 0;
 	char		*ctrl_name = "(UNKNOWN)";
 	char		*ctrl_name = "(UNKNOWN)";
 
 
-	/* XXX This needs major revision for OMAP2+ */
 	tmp = omap_readl(OTG_REV);
 	tmp = omap_readl(OTG_REV);
-	if (cpu_class_is_omap1()) {
-		ctrl_name = "tranceiver_ctrl";
-		trans = omap_readw(USB_TRANSCEIVER_CTRL);
-	}
+	ctrl_name = "tranceiver_ctrl";
+	trans = omap_readw(USB_TRANSCEIVER_CTRL);
 	seq_printf(s, "\nOTG rev %d.%d, %s %05x\n",
 	seq_printf(s, "\nOTG rev %d.%d, %s %05x\n",
 		tmp >> 4, tmp & 0xf, ctrl_name, trans);
 		tmp >> 4, tmp & 0xf, ctrl_name, trans);
 	tmp = omap_readw(OTG_SYSCON_1);
 	tmp = omap_readw(OTG_SYSCON_1);
@@ -2333,7 +2283,7 @@ static int proc_otg_show(struct seq_file *s)
 			" b_ase_brst=%d hmc=%d\n", tmp,
 			" b_ase_brst=%d hmc=%d\n", tmp,
 		(tmp & OTG_EN) ? " otg_en" : "",
 		(tmp & OTG_EN) ? " otg_en" : "",
 		(tmp & USBX_SYNCHRO) ? " synchro" : "",
 		(tmp & USBX_SYNCHRO) ? " synchro" : "",
-		// much more SRP stuff
+		/* much more SRP stuff */
 		(tmp & SRP_DATA) ? " srp_data" : "",
 		(tmp & SRP_DATA) ? " srp_data" : "",
 		(tmp & SRP_VBUS) ? " srp_vbus" : "",
 		(tmp & SRP_VBUS) ? " srp_vbus" : "",
 		(tmp & OTG_PADEN) ? " otg_paden" : "",
 		(tmp & OTG_PADEN) ? " otg_paden" : "",
@@ -2400,14 +2350,12 @@ static int proc_udc_show(struct seq_file *s, void *_)
 		HMC,
 		HMC,
 		udc->transceiver
 		udc->transceiver
 			? udc->transceiver->label
 			? udc->transceiver->label
-			: ((cpu_is_omap1710() || cpu_is_omap24xx())
+			: (cpu_is_omap1710()
 				? "external" : "(none)"));
 				? "external" : "(none)"));
-	if (cpu_class_is_omap1()) {
-		seq_printf(s, "ULPD control %04x req %04x status %04x\n",
-			omap_readw(ULPD_CLOCK_CTRL),
-			omap_readw(ULPD_SOFT_REQ),
-			omap_readw(ULPD_STATUS_REQ));
-	}
+	seq_printf(s, "ULPD control %04x req %04x status %04x\n",
+		omap_readw(ULPD_CLOCK_CTRL),
+		omap_readw(ULPD_SOFT_REQ),
+		omap_readw(ULPD_STATUS_REQ));
 
 
 	/* OTG controller registers */
 	/* OTG controller registers */
 	if (!cpu_is_omap15xx())
 	if (!cpu_is_omap15xx())
@@ -2423,7 +2371,7 @@ static int proc_udc_show(struct seq_file *s, void *_)
 		(tmp & UDC_SELF_PWR) ? " self_pwr" : "",
 		(tmp & UDC_SELF_PWR) ? " self_pwr" : "",
 		(tmp & UDC_SOFF_DIS) ? " soff_dis" : "",
 		(tmp & UDC_SOFF_DIS) ? " soff_dis" : "",
 		(tmp & UDC_PULLUP_EN) ? " PULLUP" : "");
 		(tmp & UDC_PULLUP_EN) ? " PULLUP" : "");
-	// syscon2 is write-only
+	/* syscon2 is write-only */
 
 
 	/* UDC controller registers */
 	/* UDC controller registers */
 	if (!(tmp & UDC_PULLUP_EN)) {
 	if (!(tmp & UDC_PULLUP_EN)) {
@@ -2507,7 +2455,7 @@ static int proc_udc_show(struct seq_file *s, void *_)
 	if (tmp & UDC_ATT) {
 	if (tmp & UDC_ATT) {
 		proc_ep_show(s, &udc->ep[0]);
 		proc_ep_show(s, &udc->ep[0]);
 		if (tmp & UDC_ADD) {
 		if (tmp & UDC_ADD) {
-			list_for_each_entry (ep, &udc->gadget.ep_list,
+			list_for_each_entry(ep, &udc->gadget.ep_list,
 					ep.ep_list) {
 					ep.ep_list) {
 				if (ep->ep.desc)
 				if (ep->ep.desc)
 					proc_ep_show(s, ep);
 					proc_ep_show(s, ep);
@@ -2558,7 +2506,7 @@ static inline void remove_proc_file(void) {}
  * UDC_SYSCON_1.CFG_LOCK is set can now work.  We won't use that
  * UDC_SYSCON_1.CFG_LOCK is set can now work.  We won't use that
  * capability yet though.
  * capability yet though.
  */
  */
-static unsigned __init
+static unsigned __devinit
 omap_ep_setup(char *name, u8 addr, u8 type,
 omap_ep_setup(char *name, u8 addr, u8 type,
 		unsigned buf, unsigned maxp, int dbuf)
 		unsigned buf, unsigned maxp, int dbuf)
 {
 {
@@ -2576,14 +2524,29 @@ omap_ep_setup(char *name, u8 addr, u8 type,
 	/* chip setup ... bit values are same for IN, OUT */
 	/* chip setup ... bit values are same for IN, OUT */
 	if (type == USB_ENDPOINT_XFER_ISOC) {
 	if (type == USB_ENDPOINT_XFER_ISOC) {
 		switch (maxp) {
 		switch (maxp) {
-		case 8:		epn_rxtx = 0 << 12; break;
-		case 16:	epn_rxtx = 1 << 12; break;
-		case 32:	epn_rxtx = 2 << 12; break;
-		case 64:	epn_rxtx = 3 << 12; break;
-		case 128:	epn_rxtx = 4 << 12; break;
-		case 256:	epn_rxtx = 5 << 12; break;
-		case 512:	epn_rxtx = 6 << 12; break;
-		default:	BUG();
+		case 8:
+			epn_rxtx = 0 << 12;
+			break;
+		case 16:
+			epn_rxtx = 1 << 12;
+			break;
+		case 32:
+			epn_rxtx = 2 << 12;
+			break;
+		case 64:
+			epn_rxtx = 3 << 12;
+			break;
+		case 128:
+			epn_rxtx = 4 << 12;
+			break;
+		case 256:
+			epn_rxtx = 5 << 12;
+			break;
+		case 512:
+			epn_rxtx = 6 << 12;
+			break;
+		default:
+			BUG();
 		}
 		}
 		epn_rxtx |= UDC_EPN_RX_ISO;
 		epn_rxtx |= UDC_EPN_RX_ISO;
 		dbuf = 1;
 		dbuf = 1;
@@ -2592,15 +2555,24 @@ omap_ep_setup(char *name, u8 addr, u8 type,
 		 * and ignored for PIO-IN on newer chips
 		 * and ignored for PIO-IN on newer chips
 		 * (for more reliable behavior)
 		 * (for more reliable behavior)
 		 */
 		 */
-		if (!use_dma || cpu_is_omap15xx() || cpu_is_omap24xx())
+		if (!use_dma || cpu_is_omap15xx())
 			dbuf = 0;
 			dbuf = 0;
 
 
 		switch (maxp) {
 		switch (maxp) {
-		case 8:		epn_rxtx = 0 << 12; break;
-		case 16:	epn_rxtx = 1 << 12; break;
-		case 32:	epn_rxtx = 2 << 12; break;
-		case 64:	epn_rxtx = 3 << 12; break;
-		default:	BUG();
+		case 8:
+			epn_rxtx = 0 << 12;
+			break;
+		case 16:
+			epn_rxtx = 1 << 12;
+			break;
+		case 32:
+			epn_rxtx = 2 << 12;
+			break;
+		case 64:
+			epn_rxtx = 3 << 12;
+			break;
+		default:
+			BUG();
 		}
 		}
 		if (dbuf && addr)
 		if (dbuf && addr)
 			epn_rxtx |= UDC_EPN_RX_DB;
 			epn_rxtx |= UDC_EPN_RX_DB;
@@ -2640,7 +2612,7 @@ omap_ep_setup(char *name, u8 addr, u8 type,
 	ep->ep.name = ep->name;
 	ep->ep.name = ep->name;
 	ep->ep.ops = &omap_ep_ops;
 	ep->ep.ops = &omap_ep_ops;
 	ep->ep.maxpacket = ep->maxpacket = maxp;
 	ep->ep.maxpacket = ep->maxpacket = maxp;
-	list_add_tail (&ep->ep.ep_list, &udc->gadget.ep_list);
+	list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
 
 
 	return buf;
 	return buf;
 }
 }
@@ -2648,11 +2620,11 @@ omap_ep_setup(char *name, u8 addr, u8 type,
 static void omap_udc_release(struct device *dev)
 static void omap_udc_release(struct device *dev)
 {
 {
 	complete(udc->done);
 	complete(udc->done);
-	kfree (udc);
+	kfree(udc);
 	udc = NULL;
 	udc = NULL;
 }
 }
 
 
-static int __init
+static int __devinit
 omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv)
 omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv)
 {
 {
 	unsigned	tmp, buf;
 	unsigned	tmp, buf;
@@ -2666,13 +2638,13 @@ omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv)
 	omap_writew(0, UDC_TXDMA_CFG);
 	omap_writew(0, UDC_TXDMA_CFG);
 
 
 	/* UDC_PULLUP_EN gates the chip clock */
 	/* UDC_PULLUP_EN gates the chip clock */
-	// OTG_SYSCON_1 |= DEV_IDLE_EN;
+	/* OTG_SYSCON_1 |= DEV_IDLE_EN; */
 
 
 	udc = kzalloc(sizeof(*udc), GFP_KERNEL);
 	udc = kzalloc(sizeof(*udc), GFP_KERNEL);
 	if (!udc)
 	if (!udc)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	spin_lock_init (&udc->lock);
+	spin_lock_init(&udc->lock);
 
 
 	udc->gadget.ops = &omap_gadget_ops;
 	udc->gadget.ops = &omap_gadget_ops;
 	udc->gadget.ep0 = &udc->ep[0].ep;
 	udc->gadget.ep0 = &udc->ep[0].ep;
@@ -2702,13 +2674,13 @@ omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv)
 		omap_writew(0, UDC_EP_TX(tmp));
 		omap_writew(0, UDC_EP_TX(tmp));
 	}
 	}
 
 
-#define OMAP_BULK_EP(name,addr) \
+#define OMAP_BULK_EP(name, addr) \
 	buf = omap_ep_setup(name "-bulk", addr, \
 	buf = omap_ep_setup(name "-bulk", addr, \
 			USB_ENDPOINT_XFER_BULK, buf, 64, 1);
 			USB_ENDPOINT_XFER_BULK, buf, 64, 1);
-#define OMAP_INT_EP(name,addr, maxp) \
+#define OMAP_INT_EP(name, addr, maxp) \
 	buf = omap_ep_setup(name "-int", addr, \
 	buf = omap_ep_setup(name "-int", addr, \
 			USB_ENDPOINT_XFER_INT, buf, maxp, 0);
 			USB_ENDPOINT_XFER_INT, buf, maxp, 0);
-#define OMAP_ISO_EP(name,addr, maxp) \
+#define OMAP_ISO_EP(name, addr, maxp) \
 	buf = omap_ep_setup(name "-iso", addr, \
 	buf = omap_ep_setup(name "-iso", addr, \
 			USB_ENDPOINT_XFER_ISOC, buf, maxp, 1);
 			USB_ENDPOINT_XFER_ISOC, buf, maxp, 1);
 
 
@@ -2789,15 +2761,18 @@ omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv)
 	return 0;
 	return 0;
 }
 }
 
 
-static int __init omap_udc_probe(struct platform_device *pdev)
+static int __devinit omap_udc_probe(struct platform_device *pdev)
 {
 {
 	int			status = -ENODEV;
 	int			status = -ENODEV;
 	int			hmc;
 	int			hmc;
 	struct usb_phy		*xceiv = NULL;
 	struct usb_phy		*xceiv = NULL;
 	const char		*type = NULL;
 	const char		*type = NULL;
 	struct omap_usb_config	*config = pdev->dev.platform_data;
 	struct omap_usb_config	*config = pdev->dev.platform_data;
-	struct clk		*dc_clk;
-	struct clk		*hhc_clk;
+	struct clk		*dc_clk = NULL;
+	struct clk		*hhc_clk = NULL;
+
+	if (cpu_is_omap7xx())
+		use_dma = 0;
 
 
 	/* NOTE:  "knows" the order of the resources! */
 	/* NOTE:  "knows" the order of the resources! */
 	if (!request_mem_region(pdev->resource[0].start,
 	if (!request_mem_region(pdev->resource[0].start,
@@ -2817,16 +2792,6 @@ static int __init omap_udc_probe(struct platform_device *pdev)
 		udelay(100);
 		udelay(100);
 	}
 	}
 
 
-	if (cpu_is_omap24xx()) {
-		dc_clk = clk_get(&pdev->dev, "usb_fck");
-		hhc_clk = clk_get(&pdev->dev, "usb_l4_ick");
-		BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk));
-		/* can't use omap_udc_enable_clock yet */
-		clk_enable(dc_clk);
-		clk_enable(hhc_clk);
-		udelay(100);
-	}
-
 	if (cpu_is_omap7xx()) {
 	if (cpu_is_omap7xx()) {
 		dc_clk = clk_get(&pdev->dev, "usb_dc_ck");
 		dc_clk = clk_get(&pdev->dev, "usb_dc_ck");
 		hhc_clk = clk_get(&pdev->dev, "l3_ocpi_ck");
 		hhc_clk = clk_get(&pdev->dev, "l3_ocpi_ck");
@@ -2866,8 +2831,8 @@ static int __init omap_udc_probe(struct platform_device *pdev)
 		 * use it.  Except for OTG, we don't _need_ to talk to one;
 		 * use it.  Except for OTG, we don't _need_ to talk to one;
 		 * but not having one probably means no VBUS detection.
 		 * but not having one probably means no VBUS detection.
 		 */
 		 */
-		xceiv = usb_get_transceiver();
-		if (xceiv)
+		xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
+		if (!IS_ERR_OR_NULL(xceiv))
 			type = xceiv->label;
 			type = xceiv->label;
 		else if (config->otg) {
 		else if (config->otg) {
 			DBG("OTG requires external transceiver!\n");
 			DBG("OTG requires external transceiver!\n");
@@ -2876,14 +2841,6 @@ static int __init omap_udc_probe(struct platform_device *pdev)
 
 
 		hmc = HMC_1610;
 		hmc = HMC_1610;
 
 
-		if (cpu_is_omap24xx()) {
-			/* this could be transceiverless in one of the
-			 * "we don't need to know" modes.
-			 */
-			type = "external";
-			goto known;
-		}
-
 		switch (hmc) {
 		switch (hmc) {
 		case 0:			/* POWERUP DEFAULT == 0 */
 		case 0:			/* POWERUP DEFAULT == 0 */
 		case 4:
 		case 4:
@@ -2899,7 +2856,7 @@ static int __init omap_udc_probe(struct platform_device *pdev)
 		case 16:
 		case 16:
 		case 19:
 		case 19:
 		case 25:
 		case 25:
-			if (!xceiv) {
+			if (IS_ERR_OR_NULL(xceiv)) {
 				DBG("external transceiver not registered!\n");
 				DBG("external transceiver not registered!\n");
 				type = "unknown";
 				type = "unknown";
 			}
 			}
@@ -2922,16 +2879,16 @@ bad_on_1710:
 			goto cleanup0;
 			goto cleanup0;
 		}
 		}
 	}
 	}
-known:
+
 	INFO("hmc mode %d, %s transceiver\n", hmc, type);
 	INFO("hmc mode %d, %s transceiver\n", hmc, type);
 
 
 	/* a "gadget" abstracts/virtualizes the controller */
 	/* a "gadget" abstracts/virtualizes the controller */
 	status = omap_udc_setup(pdev, xceiv);
 	status = omap_udc_setup(pdev, xceiv);
-	if (status) {
+	if (status)
 		goto cleanup0;
 		goto cleanup0;
-	}
+
 	xceiv = NULL;
 	xceiv = NULL;
-	// "udc" is now valid
+	/* "udc" is now valid */
 	pullup_disable(udc);
 	pullup_disable(udc);
 #if	defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
 #if	defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
 	udc->gadget.is_otg = (config->otg != 0);
 	udc->gadget.is_otg = (config->otg != 0);
@@ -2945,7 +2902,7 @@ known:
 
 
 	/* USB general purpose IRQ:  ep0, state changes, dma, etc */
 	/* USB general purpose IRQ:  ep0, state changes, dma, etc */
 	status = request_irq(pdev->resource[1].start, omap_udc_irq,
 	status = request_irq(pdev->resource[1].start, omap_udc_irq,
-			IRQF_SAMPLE_RANDOM, driver_name, udc);
+			0, driver_name, udc);
 	if (status != 0) {
 	if (status != 0) {
 		ERR("can't get irq %d, err %d\n",
 		ERR("can't get irq %d, err %d\n",
 			(int) pdev->resource[1].start, status);
 			(int) pdev->resource[1].start, status);
@@ -2954,7 +2911,7 @@ known:
 
 
 	/* USB "non-iso" IRQ (PIO for all but ep0) */
 	/* USB "non-iso" IRQ (PIO for all but ep0) */
 	status = request_irq(pdev->resource[2].start, omap_udc_pio_irq,
 	status = request_irq(pdev->resource[2].start, omap_udc_pio_irq,
-			IRQF_SAMPLE_RANDOM, "omap_udc pio", udc);
+			0, "omap_udc pio", udc);
 	if (status != 0) {
 	if (status != 0) {
 		ERR("can't get irq %d, err %d\n",
 		ERR("can't get irq %d, err %d\n",
 			(int) pdev->resource[2].start, status);
 			(int) pdev->resource[2].start, status);
@@ -2976,16 +2933,6 @@ known:
 		clk_disable(dc_clk);
 		clk_disable(dc_clk);
 	}
 	}
 
 
-	if (cpu_is_omap24xx()) {
-		udc->dc_clk = dc_clk;
-		udc->hhc_clk = hhc_clk;
-		/* FIXME OMAP2 don't release hhc & dc clock */
-#if 0
-		clk_disable(hhc_clk);
-		clk_disable(dc_clk);
-#endif
-	}
-
 	create_proc_file();
 	create_proc_file();
 	status = device_add(&udc->gadget.dev);
 	status = device_add(&udc->gadget.dev);
 	if (status)
 	if (status)
@@ -3007,14 +2954,14 @@ cleanup2:
 	free_irq(pdev->resource[1].start, udc);
 	free_irq(pdev->resource[1].start, udc);
 
 
 cleanup1:
 cleanup1:
-	kfree (udc);
+	kfree(udc);
 	udc = NULL;
 	udc = NULL;
 
 
 cleanup0:
 cleanup0:
-	if (xceiv)
-		usb_put_transceiver(xceiv);
+	if (!IS_ERR_OR_NULL(xceiv))
+		usb_put_phy(xceiv);
 
 
-	if (cpu_is_omap16xx() || cpu_is_omap24xx() || cpu_is_omap7xx()) {
+	if (cpu_is_omap16xx() || cpu_is_omap7xx()) {
 		clk_disable(hhc_clk);
 		clk_disable(hhc_clk);
 		clk_disable(dc_clk);
 		clk_disable(dc_clk);
 		clk_put(hhc_clk);
 		clk_put(hhc_clk);
@@ -3027,7 +2974,7 @@ cleanup0:
 	return status;
 	return status;
 }
 }
 
 
-static int __exit omap_udc_remove(struct platform_device *pdev)
+static int __devexit omap_udc_remove(struct platform_device *pdev)
 {
 {
 	DECLARE_COMPLETION_ONSTACK(done);
 	DECLARE_COMPLETION_ONSTACK(done);
 
 
@@ -3041,8 +2988,8 @@ static int __exit omap_udc_remove(struct platform_device *pdev)
 	udc->done = &done;
 	udc->done = &done;
 
 
 	pullup_disable(udc);
 	pullup_disable(udc);
-	if (udc->transceiver) {
-		usb_put_transceiver(udc->transceiver);
+	if (!IS_ERR_OR_NULL(udc->transceiver)) {
+		usb_put_phy(udc->transceiver);
 		udc->transceiver = NULL;
 		udc->transceiver = NULL;
 	}
 	}
 	omap_writew(0, UDC_SYSCON1);
 	omap_writew(0, UDC_SYSCON1);
@@ -3112,7 +3059,8 @@ static int omap_udc_resume(struct platform_device *dev)
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 static struct platform_driver udc_driver = {
 static struct platform_driver udc_driver = {
-	.remove		= __exit_p(omap_udc_remove),
+	.probe		= omap_udc_probe,
+	.remove		= __devexit_p(omap_udc_remove),
 	.suspend	= omap_udc_suspend,
 	.suspend	= omap_udc_suspend,
 	.resume		= omap_udc_resume,
 	.resume		= omap_udc_resume,
 	.driver		= {
 	.driver		= {
@@ -3121,27 +3069,7 @@ static struct platform_driver udc_driver = {
 	},
 	},
 };
 };
 
 
-static int __init udc_init(void)
-{
-	/* Disable DMA for omap7xx -- it doesn't work right. */
-	if (cpu_is_omap7xx())
-		use_dma = 0;
-
-	INFO("%s, version: " DRIVER_VERSION
-#ifdef	USE_ISO
-		" (iso)"
-#endif
-		"%s\n", driver_desc,
-		use_dma ?  " (dma)" : "");
-	return platform_driver_probe(&udc_driver, omap_udc_probe);
-}
-module_init(udc_init);
-
-static void __exit udc_exit(void)
-{
-	platform_driver_unregister(&udc_driver);
-}
-module_exit(udc_exit);
+module_platform_driver(udc_driver);
 
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");

+ 1 - 1
drivers/usb/gadget/pch_udc.c

@@ -2208,7 +2208,7 @@ static void pch_udc_complete_receiver(struct pch_udc_ep *ep)
 			return;
 			return;
 		}
 		}
 		if ((td->status & PCH_UDC_BUFF_STS) == PCH_UDC_BS_DMA_DONE)
 		if ((td->status & PCH_UDC_BUFF_STS) == PCH_UDC_BS_DMA_DONE)
-			if (td->status | PCH_UDC_DMA_LAST) {
+			if (td->status & PCH_UDC_DMA_LAST) {
 				count = td->status & PCH_UDC_RXTX_BYTES;
 				count = td->status & PCH_UDC_RXTX_BYTES;
 				break;
 				break;
 			}
 			}

+ 9 - 8
drivers/usb/gadget/pxa25x_udc.c

@@ -21,6 +21,7 @@
 #include <linux/ioport.h>
 #include <linux/ioport.h>
 #include <linux/types.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/init.h>
@@ -993,7 +994,7 @@ static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
 
 
 	udc = container_of(_gadget, struct pxa25x_udc, gadget);
 	udc = container_of(_gadget, struct pxa25x_udc, gadget);
 
 
-	if (udc->transceiver)
+	if (!IS_ERR_OR_NULL(udc->transceiver))
 		return usb_phy_set_power(udc->transceiver, mA);
 		return usb_phy_set_power(udc->transceiver, mA);
 	return -EOPNOTSUPP;
 	return -EOPNOTSUPP;
 }
 }
@@ -1299,7 +1300,7 @@ fail:
 	DMSG("registered gadget driver '%s'\n", driver->driver.name);
 	DMSG("registered gadget driver '%s'\n", driver->driver.name);
 
 
 	/* connect to bus through transceiver */
 	/* connect to bus through transceiver */
-	if (dev->transceiver) {
+	if (!IS_ERR_OR_NULL(dev->transceiver)) {
 		retval = otg_set_peripheral(dev->transceiver->otg,
 		retval = otg_set_peripheral(dev->transceiver->otg,
 						&dev->gadget);
 						&dev->gadget);
 		if (retval) {
 		if (retval) {
@@ -1359,7 +1360,7 @@ static int pxa25x_stop(struct usb_gadget_driver *driver)
 	stop_activity(dev, driver);
 	stop_activity(dev, driver);
 	local_irq_enable();
 	local_irq_enable();
 
 
-	if (dev->transceiver)
+	if (!IS_ERR_OR_NULL(dev->transceiver))
 		(void) otg_set_peripheral(dev->transceiver->otg, NULL);
 		(void) otg_set_peripheral(dev->transceiver->otg, NULL);
 
 
 	driver->unbind(&dev->gadget);
 	driver->unbind(&dev->gadget);
@@ -2159,7 +2160,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
 	dev->dev = &pdev->dev;
 	dev->dev = &pdev->dev;
 	dev->mach = pdev->dev.platform_data;
 	dev->mach = pdev->dev.platform_data;
 
 
-	dev->transceiver = usb_get_transceiver();
+	dev->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
 
 
 	if (gpio_is_valid(dev->mach->gpio_pullup)) {
 	if (gpio_is_valid(dev->mach->gpio_pullup)) {
 		if ((retval = gpio_request(dev->mach->gpio_pullup,
 		if ((retval = gpio_request(dev->mach->gpio_pullup,
@@ -2237,8 +2238,8 @@ lubbock_fail0:
 	if (gpio_is_valid(dev->mach->gpio_pullup))
 	if (gpio_is_valid(dev->mach->gpio_pullup))
 		gpio_free(dev->mach->gpio_pullup);
 		gpio_free(dev->mach->gpio_pullup);
  err_gpio_pullup:
  err_gpio_pullup:
-	if (dev->transceiver) {
-		usb_put_transceiver(dev->transceiver);
+	if (!IS_ERR_OR_NULL(dev->transceiver)) {
+		usb_put_phy(dev->transceiver);
 		dev->transceiver = NULL;
 		dev->transceiver = NULL;
 	}
 	}
 	clk_put(dev->clk);
 	clk_put(dev->clk);
@@ -2279,8 +2280,8 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)
 
 
 	clk_put(dev->clk);
 	clk_put(dev->clk);
 
 
-	if (dev->transceiver) {
-		usb_put_transceiver(dev->transceiver);
+	if (!IS_ERR_OR_NULL(dev->transceiver)) {
+		usb_put_phy(dev->transceiver);
 		dev->transceiver = NULL;
 		dev->transceiver = NULL;
 	}
 	}
 
 

+ 8 - 7
drivers/usb/gadget/pxa27x_udc.c

@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/list.h>
 #include <linux/list.h>
@@ -1573,7 +1574,7 @@ static int should_enable_udc(struct pxa_udc *udc)
 	int put_on;
 	int put_on;
 
 
 	put_on = ((udc->pullup_on) && (udc->driver));
 	put_on = ((udc->pullup_on) && (udc->driver));
-	put_on &= ((udc->vbus_sensed) || (!udc->transceiver));
+	put_on &= ((udc->vbus_sensed) || (IS_ERR_OR_NULL(udc->transceiver)));
 	return put_on;
 	return put_on;
 }
 }
 
 
@@ -1594,7 +1595,7 @@ static int should_disable_udc(struct pxa_udc *udc)
 	int put_off;
 	int put_off;
 
 
 	put_off = ((!udc->pullup_on) || (!udc->driver));
 	put_off = ((!udc->pullup_on) || (!udc->driver));
-	put_off |= ((!udc->vbus_sensed) && (udc->transceiver));
+	put_off |= ((!udc->vbus_sensed) && (!IS_ERR_OR_NULL(udc->transceiver)));
 	return put_off;
 	return put_off;
 }
 }
 
 
@@ -1665,7 +1666,7 @@ static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
 	struct pxa_udc *udc;
 	struct pxa_udc *udc;
 
 
 	udc = to_gadget_udc(_gadget);
 	udc = to_gadget_udc(_gadget);
-	if (udc->transceiver)
+	if (!IS_ERR_OR_NULL(udc->transceiver))
 		return usb_phy_set_power(udc->transceiver, mA);
 		return usb_phy_set_power(udc->transceiver, mA);
 	return -EOPNOTSUPP;
 	return -EOPNOTSUPP;
 }
 }
@@ -1834,7 +1835,7 @@ static int pxa27x_udc_start(struct usb_gadget_driver *driver,
 	dev_dbg(udc->dev, "registered gadget driver '%s'\n",
 	dev_dbg(udc->dev, "registered gadget driver '%s'\n",
 		driver->driver.name);
 		driver->driver.name);
 
 
-	if (udc->transceiver) {
+	if (!IS_ERR_OR_NULL(udc->transceiver)) {
 		retval = otg_set_peripheral(udc->transceiver->otg,
 		retval = otg_set_peripheral(udc->transceiver->otg,
 						&udc->gadget);
 						&udc->gadget);
 		if (retval) {
 		if (retval) {
@@ -1908,7 +1909,7 @@ static int pxa27x_udc_stop(struct usb_gadget_driver *driver)
 	dev_info(udc->dev, "unregistered gadget driver '%s'\n",
 	dev_info(udc->dev, "unregistered gadget driver '%s'\n",
 		 driver->driver.name);
 		 driver->driver.name);
 
 
-	if (udc->transceiver)
+	if (!IS_ERR_OR_NULL(udc->transceiver))
 		return otg_set_peripheral(udc->transceiver->otg, NULL);
 		return otg_set_peripheral(udc->transceiver->otg, NULL);
 	return 0;
 	return 0;
 }
 }
@@ -2464,7 +2465,7 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
 
 
 	udc->dev = &pdev->dev;
 	udc->dev = &pdev->dev;
 	udc->mach = pdev->dev.platform_data;
 	udc->mach = pdev->dev.platform_data;
-	udc->transceiver = usb_get_transceiver();
+	udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
 
 
 	gpio = udc->mach->gpio_pullup;
 	gpio = udc->mach->gpio_pullup;
 	if (gpio_is_valid(gpio)) {
 	if (gpio_is_valid(gpio)) {
@@ -2543,7 +2544,7 @@ static int __exit pxa_udc_remove(struct platform_device *_dev)
 	if (gpio_is_valid(gpio))
 	if (gpio_is_valid(gpio))
 		gpio_free(gpio);
 		gpio_free(gpio);
 
 
-	usb_put_transceiver(udc->transceiver);
+	usb_put_phy(udc->transceiver);
 
 
 	udc->transceiver = NULL;
 	udc->transceiver = NULL;
 	platform_set_drvdata(_dev, NULL);
 	platform_set_drvdata(_dev, NULL);

+ 110 - 105
drivers/usb/gadget/s3c-hsotg.c

@@ -112,7 +112,6 @@ struct s3c_hsotg_ep {
 	struct s3c_hsotg_req	*req;
 	struct s3c_hsotg_req	*req;
 	struct dentry		*debugfs;
 	struct dentry		*debugfs;
 
 
-	spinlock_t		lock;
 
 
 	unsigned long		total_data;
 	unsigned long		total_data;
 	unsigned int		size_loaded;
 	unsigned int		size_loaded;
@@ -136,7 +135,6 @@ struct s3c_hsotg_ep {
  * @driver: USB gadget driver
  * @driver: USB gadget driver
  * @plat: The platform specific configuration data.
  * @plat: The platform specific configuration data.
  * @regs: The memory area mapped for accessing registers.
  * @regs: The memory area mapped for accessing registers.
- * @regs_res: The resource that was allocated when claiming register space.
  * @irq: The IRQ number we are using
  * @irq: The IRQ number we are using
  * @supplies: Definition of USB power supplies
  * @supplies: Definition of USB power supplies
  * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos.
  * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos.
@@ -157,8 +155,9 @@ struct s3c_hsotg {
 	struct usb_gadget_driver *driver;
 	struct usb_gadget_driver *driver;
 	struct s3c_hsotg_plat	 *plat;
 	struct s3c_hsotg_plat	 *plat;
 
 
+	spinlock_t              lock;
+
 	void __iomem		*regs;
 	void __iomem		*regs;
-	struct resource		*regs_res;
 	int			irq;
 	int			irq;
 	struct clk		*clk;
 	struct clk		*clk;
 
 
@@ -896,7 +895,6 @@ static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
 	struct s3c_hsotg_req *hs_req = our_req(req);
 	struct s3c_hsotg_req *hs_req = our_req(req);
 	struct s3c_hsotg_ep *hs_ep = our_ep(ep);
 	struct s3c_hsotg_ep *hs_ep = our_ep(ep);
 	struct s3c_hsotg *hs = hs_ep->parent;
 	struct s3c_hsotg *hs = hs_ep->parent;
-	unsigned long irqflags;
 	bool first;
 	bool first;
 
 
 	dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n",
 	dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n",
@@ -915,19 +913,30 @@ static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
 			return ret;
 			return ret;
 	}
 	}
 
 
-	spin_lock_irqsave(&hs_ep->lock, irqflags);
-
 	first = list_empty(&hs_ep->queue);
 	first = list_empty(&hs_ep->queue);
 	list_add_tail(&hs_req->queue, &hs_ep->queue);
 	list_add_tail(&hs_req->queue, &hs_ep->queue);
 
 
 	if (first)
 	if (first)
 		s3c_hsotg_start_req(hs, hs_ep, hs_req, false);
 		s3c_hsotg_start_req(hs, hs_ep, hs_req, false);
 
 
-	spin_unlock_irqrestore(&hs_ep->lock, irqflags);
-
 	return 0;
 	return 0;
 }
 }
 
 
+static int s3c_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req,
+			      gfp_t gfp_flags)
+{
+	struct s3c_hsotg_ep *hs_ep = our_ep(ep);
+	struct s3c_hsotg *hs = hs_ep->parent;
+	unsigned long flags = 0;
+	int ret = 0;
+
+	spin_lock_irqsave(&hs->lock, flags);
+	ret = s3c_hsotg_ep_queue(ep, req, gfp_flags);
+	spin_unlock_irqrestore(&hs->lock, flags);
+
+	return ret;
+}
+
 static void s3c_hsotg_ep_free_request(struct usb_ep *ep,
 static void s3c_hsotg_ep_free_request(struct usb_ep *ep,
 				      struct usb_request *req)
 				      struct usb_request *req)
 {
 {
@@ -1383,9 +1392,9 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,
 	 */
 	 */
 
 
 	if (hs_req->req.complete) {
 	if (hs_req->req.complete) {
-		spin_unlock(&hs_ep->lock);
+		spin_unlock(&hsotg->lock);
 		hs_req->req.complete(&hs_ep->ep, &hs_req->req);
 		hs_req->req.complete(&hs_ep->ep, &hs_req->req);
-		spin_lock(&hs_ep->lock);
+		spin_lock(&hsotg->lock);
 	}
 	}
 
 
 	/*
 	/*
@@ -1403,28 +1412,6 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,
 	}
 	}
 }
 }
 
 
-/**
- * s3c_hsotg_complete_request_lock - complete a request given to us (locked)
- * @hsotg: The device state.
- * @hs_ep: The endpoint the request was on.
- * @hs_req: The request to complete.
- * @result: The result code (0 => Ok, otherwise errno)
- *
- * See s3c_hsotg_complete_request(), but called with the endpoint's
- * lock held.
- */
-static void s3c_hsotg_complete_request_lock(struct s3c_hsotg *hsotg,
-					    struct s3c_hsotg_ep *hs_ep,
-					    struct s3c_hsotg_req *hs_req,
-					    int result)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&hs_ep->lock, flags);
-	s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, result);
-	spin_unlock_irqrestore(&hs_ep->lock, flags);
-}
-
 /**
 /**
  * s3c_hsotg_rx_data - receive data from the FIFO for an endpoint
  * s3c_hsotg_rx_data - receive data from the FIFO for an endpoint
  * @hsotg: The device state.
  * @hsotg: The device state.
@@ -1444,6 +1431,7 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)
 	int max_req;
 	int max_req;
 	int read_ptr;
 	int read_ptr;
 
 
+
 	if (!hs_req) {
 	if (!hs_req) {
 		u32 epctl = readl(hsotg->regs + DOEPCTL(ep_idx));
 		u32 epctl = readl(hsotg->regs + DOEPCTL(ep_idx));
 		int ptr;
 		int ptr;
@@ -1459,8 +1447,6 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)
 		return;
 		return;
 	}
 	}
 
 
-	spin_lock(&hs_ep->lock);
-
 	to_read = size;
 	to_read = size;
 	read_ptr = hs_req->req.actual;
 	read_ptr = hs_req->req.actual;
 	max_req = hs_req->req.length - read_ptr;
 	max_req = hs_req->req.length - read_ptr;
@@ -1487,8 +1473,6 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)
 	 * alignment of the data.
 	 * alignment of the data.
 	 */
 	 */
 	readsl(fifo, hs_req->req.buf + read_ptr, to_read);
 	readsl(fifo, hs_req->req.buf + read_ptr, to_read);
-
-	spin_unlock(&hs_ep->lock);
 }
 }
 
 
 /**
 /**
@@ -1609,7 +1593,7 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
 			s3c_hsotg_send_zlp(hsotg, hs_req);
 			s3c_hsotg_send_zlp(hsotg, hs_req);
 	}
 	}
 
 
-	s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, result);
+	s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, result);
 }
 }
 
 
 /**
 /**
@@ -1864,7 +1848,7 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,
 	/* Finish ZLP handling for IN EP0 transactions */
 	/* Finish ZLP handling for IN EP0 transactions */
 	if (hsotg->eps[0].sent_zlp) {
 	if (hsotg->eps[0].sent_zlp) {
 		dev_dbg(hsotg->dev, "zlp packet received\n");
 		dev_dbg(hsotg->dev, "zlp packet received\n");
-		s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, 0);
+		s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
 		return;
 		return;
 	}
 	}
 
 
@@ -1915,7 +1899,7 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,
 		dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__);
 		dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__);
 		s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true);
 		s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true);
 	} else
 	} else
-		s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, 0);
+		s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
 }
 }
 
 
 /**
 /**
@@ -2123,9 +2107,6 @@ static void kill_all_requests(struct s3c_hsotg *hsotg,
 			      int result, bool force)
 			      int result, bool force)
 {
 {
 	struct s3c_hsotg_req *req, *treq;
 	struct s3c_hsotg_req *req, *treq;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ep->lock, flags);
 
 
 	list_for_each_entry_safe(req, treq, &ep->queue, queue) {
 	list_for_each_entry_safe(req, treq, &ep->queue, queue) {
 		/*
 		/*
@@ -2139,14 +2120,15 @@ static void kill_all_requests(struct s3c_hsotg *hsotg,
 		s3c_hsotg_complete_request(hsotg, ep, req,
 		s3c_hsotg_complete_request(hsotg, ep, req,
 					   result);
 					   result);
 	}
 	}
-
-	spin_unlock_irqrestore(&ep->lock, flags);
 }
 }
 
 
 #define call_gadget(_hs, _entry) \
 #define call_gadget(_hs, _entry) \
 	if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN &&	\
 	if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN &&	\
-	    (_hs)->driver && (_hs)->driver->_entry)	\
-		(_hs)->driver->_entry(&(_hs)->gadget);
+	    (_hs)->driver && (_hs)->driver->_entry) { \
+		spin_unlock(&_hs->lock); \
+		(_hs)->driver->_entry(&(_hs)->gadget); \
+		spin_lock(&_hs->lock); \
+		}
 
 
 /**
 /**
  * s3c_hsotg_disconnect - disconnect service
  * s3c_hsotg_disconnect - disconnect service
@@ -2388,6 +2370,7 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
 	u32 gintsts;
 	u32 gintsts;
 	u32 gintmsk;
 	u32 gintmsk;
 
 
+	spin_lock(&hsotg->lock);
 irq_retry:
 irq_retry:
 	gintsts = readl(hsotg->regs + GINTSTS);
 	gintsts = readl(hsotg->regs + GINTSTS);
 	gintmsk = readl(hsotg->regs + GINTMSK);
 	gintmsk = readl(hsotg->regs + GINTMSK);
@@ -2557,6 +2540,8 @@ irq_retry:
 	if (gintsts & IRQ_RETRY_MASK && --retry_count > 0)
 	if (gintsts & IRQ_RETRY_MASK && --retry_count > 0)
 			goto irq_retry;
 			goto irq_retry;
 
 
+	spin_unlock(&hsotg->lock);
+
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
 
 
@@ -2604,7 +2589,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
 	dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n",
 	dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n",
 		__func__, epctrl, epctrl_reg);
 		__func__, epctrl, epctrl_reg);
 
 
-	spin_lock_irqsave(&hs_ep->lock, flags);
+	spin_lock_irqsave(&hsotg->lock, flags);
 
 
 	epctrl &= ~(DxEPCTL_EPType_MASK | DxEPCTL_MPS_MASK);
 	epctrl &= ~(DxEPCTL_EPType_MASK | DxEPCTL_MPS_MASK);
 	epctrl |= DxEPCTL_MPS(mps);
 	epctrl |= DxEPCTL_MPS(mps);
@@ -2683,7 +2668,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
 	s3c_hsotg_ctrl_epint(hsotg, index, dir_in, 1);
 	s3c_hsotg_ctrl_epint(hsotg, index, dir_in, 1);
 
 
 out:
 out:
-	spin_unlock_irqrestore(&hs_ep->lock, flags);
+	spin_unlock_irqrestore(&hsotg->lock, flags);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -2710,10 +2695,10 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep)
 
 
 	epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
 	epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
 
 
+	spin_lock_irqsave(&hsotg->lock, flags);
 	/* terminate all requests with shutdown */
 	/* terminate all requests with shutdown */
 	kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, false);
 	kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, false);
 
 
-	spin_lock_irqsave(&hs_ep->lock, flags);
 
 
 	ctrl = readl(hsotg->regs + epctrl_reg);
 	ctrl = readl(hsotg->regs + epctrl_reg);
 	ctrl &= ~DxEPCTL_EPEna;
 	ctrl &= ~DxEPCTL_EPEna;
@@ -2726,7 +2711,7 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep)
 	/* disable endpoint interrupts */
 	/* disable endpoint interrupts */
 	s3c_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0);
 	s3c_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0);
 
 
-	spin_unlock_irqrestore(&hs_ep->lock, flags);
+	spin_unlock_irqrestore(&hsotg->lock, flags);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -2761,15 +2746,15 @@ static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
 
 
 	dev_info(hs->dev, "ep_dequeue(%p,%p)\n", ep, req);
 	dev_info(hs->dev, "ep_dequeue(%p,%p)\n", ep, req);
 
 
-	spin_lock_irqsave(&hs_ep->lock, flags);
+	spin_lock_irqsave(&hs->lock, flags);
 
 
 	if (!on_list(hs_ep, hs_req)) {
 	if (!on_list(hs_ep, hs_req)) {
-		spin_unlock_irqrestore(&hs_ep->lock, flags);
+		spin_unlock_irqrestore(&hs->lock, flags);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
 	s3c_hsotg_complete_request(hs, hs_ep, hs_req, -ECONNRESET);
 	s3c_hsotg_complete_request(hs, hs_ep, hs_req, -ECONNRESET);
-	spin_unlock_irqrestore(&hs_ep->lock, flags);
+	spin_unlock_irqrestore(&hs->lock, flags);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -2784,15 +2769,12 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
 	struct s3c_hsotg_ep *hs_ep = our_ep(ep);
 	struct s3c_hsotg_ep *hs_ep = our_ep(ep);
 	struct s3c_hsotg *hs = hs_ep->parent;
 	struct s3c_hsotg *hs = hs_ep->parent;
 	int index = hs_ep->index;
 	int index = hs_ep->index;
-	unsigned long irqflags;
 	u32 epreg;
 	u32 epreg;
 	u32 epctl;
 	u32 epctl;
 	u32 xfertype;
 	u32 xfertype;
 
 
 	dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value);
 	dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value);
 
 
-	spin_lock_irqsave(&hs_ep->lock, irqflags);
-
 	/* write both IN and OUT control registers */
 	/* write both IN and OUT control registers */
 
 
 	epreg = DIEPCTL(index);
 	epreg = DIEPCTL(index);
@@ -2827,19 +2809,36 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
 
 
 	writel(epctl, hs->regs + epreg);
 	writel(epctl, hs->regs + epreg);
 
 
-	spin_unlock_irqrestore(&hs_ep->lock, irqflags);
-
 	return 0;
 	return 0;
 }
 }
 
 
+/**
+ * s3c_hsotg_ep_sethalt_lock - set halt on a given endpoint with lock held
+ * @ep: The endpoint to set halt.
+ * @value: Set or unset the halt.
+ */
+static int s3c_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value)
+{
+	struct s3c_hsotg_ep *hs_ep = our_ep(ep);
+	struct s3c_hsotg *hs = hs_ep->parent;
+	unsigned long flags = 0;
+	int ret = 0;
+
+	spin_lock_irqsave(&hs->lock, flags);
+	ret = s3c_hsotg_ep_sethalt(ep, value);
+	spin_unlock_irqrestore(&hs->lock, flags);
+
+	return ret;
+}
+
 static struct usb_ep_ops s3c_hsotg_ep_ops = {
 static struct usb_ep_ops s3c_hsotg_ep_ops = {
 	.enable		= s3c_hsotg_ep_enable,
 	.enable		= s3c_hsotg_ep_enable,
 	.disable	= s3c_hsotg_ep_disable,
 	.disable	= s3c_hsotg_ep_disable,
 	.alloc_request	= s3c_hsotg_ep_alloc_request,
 	.alloc_request	= s3c_hsotg_ep_alloc_request,
 	.free_request	= s3c_hsotg_ep_free_request,
 	.free_request	= s3c_hsotg_ep_free_request,
-	.queue		= s3c_hsotg_ep_queue,
+	.queue		= s3c_hsotg_ep_queue_lock,
 	.dequeue	= s3c_hsotg_ep_dequeue,
 	.dequeue	= s3c_hsotg_ep_dequeue,
-	.set_halt	= s3c_hsotg_ep_sethalt,
+	.set_halt	= s3c_hsotg_ep_sethalt_lock,
 	/* note, don't believe we have any call for the fifo routines */
 	/* note, don't believe we have any call for the fifo routines */
 };
 };
 
 
@@ -2954,6 +2953,7 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
 	driver->driver.bus = NULL;
 	driver->driver.bus = NULL;
 	hsotg->driver = driver;
 	hsotg->driver = driver;
 	hsotg->gadget.dev.driver = &driver->driver;
 	hsotg->gadget.dev.driver = &driver->driver;
+	hsotg->gadget.dev.of_node = hsotg->dev->of_node;
 	hsotg->gadget.dev.dma_mask = hsotg->dev->dma_mask;
 	hsotg->gadget.dev.dma_mask = hsotg->dev->dma_mask;
 	hsotg->gadget.speed = USB_SPEED_UNKNOWN;
 	hsotg->gadget.speed = USB_SPEED_UNKNOWN;
 
 
@@ -2964,9 +2964,6 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
 		goto err;
 		goto err;
 	}
 	}
 
 
-	s3c_hsotg_phy_enable(hsotg);
-
-	s3c_hsotg_core_init(hsotg);
 	hsotg->last_rst = jiffies;
 	hsotg->last_rst = jiffies;
 	dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name);
 	dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name);
 	return 0;
 	return 0;
@@ -2988,6 +2985,7 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
 			  struct usb_gadget_driver *driver)
 			  struct usb_gadget_driver *driver)
 {
 {
 	struct s3c_hsotg *hsotg = to_hsotg(gadget);
 	struct s3c_hsotg *hsotg = to_hsotg(gadget);
+	unsigned long flags = 0;
 	int ep;
 	int ep;
 
 
 	if (!hsotg)
 	if (!hsotg)
@@ -3000,6 +2998,8 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
 	for (ep = 0; ep < hsotg->num_of_eps; ep++)
 	for (ep = 0; ep < hsotg->num_of_eps; ep++)
 		s3c_hsotg_ep_disable(&hsotg->eps[ep].ep);
 		s3c_hsotg_ep_disable(&hsotg->eps[ep].ep);
 
 
+	spin_lock_irqsave(&hsotg->lock, flags);
+
 	s3c_hsotg_phy_disable(hsotg);
 	s3c_hsotg_phy_disable(hsotg);
 	regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
 	regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
 
 
@@ -3007,6 +3007,8 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
 	hsotg->gadget.speed = USB_SPEED_UNKNOWN;
 	hsotg->gadget.speed = USB_SPEED_UNKNOWN;
 	hsotg->gadget.dev.driver = NULL;
 	hsotg->gadget.dev.driver = NULL;
 
 
+	spin_unlock_irqrestore(&hsotg->lock, flags);
+
 	dev_info(hsotg->dev, "unregistered gadget driver '%s'\n",
 	dev_info(hsotg->dev, "unregistered gadget driver '%s'\n",
 		 driver->driver.name);
 		 driver->driver.name);
 
 
@@ -3024,10 +3026,40 @@ static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget)
 	return s3c_hsotg_read_frameno(to_hsotg(gadget));
 	return s3c_hsotg_read_frameno(to_hsotg(gadget));
 }
 }
 
 
+/**
+ * s3c_hsotg_pullup - connect/disconnect the USB PHY
+ * @gadget: The usb gadget state
+ * @is_on: Current state of the USB PHY
+ *
+ * Connect/Disconnect the USB PHY pullup
+ */
+static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct s3c_hsotg *hsotg = to_hsotg(gadget);
+	unsigned long flags = 0;
+
+	dev_dbg(hsotg->dev, "%s: is_in: %d\n", __func__, is_on);
+
+	spin_lock_irqsave(&hsotg->lock, flags);
+	if (is_on) {
+		s3c_hsotg_phy_enable(hsotg);
+		s3c_hsotg_core_init(hsotg);
+	} else {
+		s3c_hsotg_disconnect(hsotg);
+		s3c_hsotg_phy_disable(hsotg);
+	}
+
+	hsotg->gadget.speed = USB_SPEED_UNKNOWN;
+	spin_unlock_irqrestore(&hsotg->lock, flags);
+
+	return 0;
+}
+
 static struct usb_gadget_ops s3c_hsotg_gadget_ops = {
 static struct usb_gadget_ops s3c_hsotg_gadget_ops = {
 	.get_frame	= s3c_hsotg_gadget_getframe,
 	.get_frame	= s3c_hsotg_gadget_getframe,
 	.udc_start		= s3c_hsotg_udc_start,
 	.udc_start		= s3c_hsotg_udc_start,
 	.udc_stop		= s3c_hsotg_udc_stop,
 	.udc_stop		= s3c_hsotg_udc_stop,
+	.pullup                 = s3c_hsotg_pullup,
 };
 };
 
 
 /**
 /**
@@ -3063,8 +3095,6 @@ static void __devinit s3c_hsotg_initep(struct s3c_hsotg *hsotg,
 	INIT_LIST_HEAD(&hs_ep->queue);
 	INIT_LIST_HEAD(&hs_ep->queue);
 	INIT_LIST_HEAD(&hs_ep->ep.ep_list);
 	INIT_LIST_HEAD(&hs_ep->ep.ep_list);
 
 
-	spin_lock_init(&hs_ep->lock);
-
 	/* add to the list of endpoints known by the gadget driver */
 	/* add to the list of endpoints known by the gadget driver */
 	if (epnum)
 	if (epnum)
 		list_add_tail(&hs_ep->ep.ep_list, &hsotg->gadget.ep_list);
 		list_add_tail(&hs_ep->ep.ep_list, &hsotg->gadget.ep_list);
@@ -3342,7 +3372,7 @@ static int ep_show(struct seq_file *seq, void *v)
 	seq_printf(seq, "request list (%p,%p):\n",
 	seq_printf(seq, "request list (%p,%p):\n",
 		   ep->queue.next, ep->queue.prev);
 		   ep->queue.next, ep->queue.prev);
 
 
-	spin_lock_irqsave(&ep->lock, flags);
+	spin_lock_irqsave(&hsotg->lock, flags);
 
 
 	list_for_each_entry(req, &ep->queue, queue) {
 	list_for_each_entry(req, &ep->queue, queue) {
 		if (--show_limit < 0) {
 		if (--show_limit < 0) {
@@ -3357,7 +3387,7 @@ static int ep_show(struct seq_file *seq, void *v)
 			   req->req.actual, req->req.status);
 			   req->req.actual, req->req.status);
 	}
 	}
 
 
-	spin_unlock_irqrestore(&ep->lock, flags);
+	spin_unlock_irqrestore(&hsotg->lock, flags);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -3477,7 +3507,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
-	hsotg = kzalloc(sizeof(struct s3c_hsotg), GFP_KERNEL);
+	hsotg = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsotg), GFP_KERNEL);
 	if (!hsotg) {
 	if (!hsotg) {
 		dev_err(dev, "cannot get memory\n");
 		dev_err(dev, "cannot get memory\n");
 		return -ENOMEM;
 		return -ENOMEM;
@@ -3489,46 +3519,35 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
 	hsotg->clk = clk_get(&pdev->dev, "otg");
 	hsotg->clk = clk_get(&pdev->dev, "otg");
 	if (IS_ERR(hsotg->clk)) {
 	if (IS_ERR(hsotg->clk)) {
 		dev_err(dev, "cannot get otg clock\n");
 		dev_err(dev, "cannot get otg clock\n");
-		ret = PTR_ERR(hsotg->clk);
-		goto err_mem;
+		return PTR_ERR(hsotg->clk);
 	}
 	}
 
 
 	platform_set_drvdata(pdev, hsotg);
 	platform_set_drvdata(pdev, hsotg);
 
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(dev, "cannot find register resource 0\n");
-		ret = -EINVAL;
-		goto err_clk;
-	}
-
-	hsotg->regs_res = request_mem_region(res->start, resource_size(res),
-					     dev_name(dev));
-	if (!hsotg->regs_res) {
-		dev_err(dev, "cannot reserve registers\n");
-		ret = -ENOENT;
-		goto err_clk;
-	}
 
 
-	hsotg->regs = ioremap(res->start, resource_size(res));
+	hsotg->regs = devm_request_and_ioremap(&pdev->dev, res);
 	if (!hsotg->regs) {
 	if (!hsotg->regs) {
 		dev_err(dev, "cannot map registers\n");
 		dev_err(dev, "cannot map registers\n");
 		ret = -ENXIO;
 		ret = -ENXIO;
-		goto err_regs_res;
+		goto err_clk;
 	}
 	}
 
 
 	ret = platform_get_irq(pdev, 0);
 	ret = platform_get_irq(pdev, 0);
 	if (ret < 0) {
 	if (ret < 0) {
 		dev_err(dev, "cannot find IRQ\n");
 		dev_err(dev, "cannot find IRQ\n");
-		goto err_regs;
+		goto err_clk;
 	}
 	}
 
 
+	spin_lock_init(&hsotg->lock);
+
 	hsotg->irq = ret;
 	hsotg->irq = ret;
 
 
-	ret = request_irq(ret, s3c_hsotg_irq, 0, dev_name(dev), hsotg);
+	ret = devm_request_irq(&pdev->dev, hsotg->irq, s3c_hsotg_irq, 0,
+				dev_name(dev), hsotg);
 	if (ret < 0) {
 	if (ret < 0) {
 		dev_err(dev, "cannot claim IRQ\n");
 		dev_err(dev, "cannot claim IRQ\n");
-		goto err_regs;
+		goto err_clk;
 	}
 	}
 
 
 	dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq);
 	dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq);
@@ -3558,7 +3577,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
 				 hsotg->supplies);
 				 hsotg->supplies);
 	if (ret) {
 	if (ret) {
 		dev_err(dev, "failed to request supplies: %d\n", ret);
 		dev_err(dev, "failed to request supplies: %d\n", ret);
-		goto err_irq;
+		goto err_clk;
 	}
 	}
 
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
 	ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
@@ -3642,19 +3661,11 @@ err_ep_mem:
 err_supplies:
 err_supplies:
 	s3c_hsotg_phy_disable(hsotg);
 	s3c_hsotg_phy_disable(hsotg);
 	regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
 	regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
-err_irq:
-	free_irq(hsotg->irq, hsotg);
-err_regs:
-	iounmap(hsotg->regs);
-
-err_regs_res:
-	release_resource(hsotg->regs_res);
-	kfree(hsotg->regs_res);
+
 err_clk:
 err_clk:
 	clk_disable_unprepare(hsotg->clk);
 	clk_disable_unprepare(hsotg->clk);
 	clk_put(hsotg->clk);
 	clk_put(hsotg->clk);
-err_mem:
-	kfree(hsotg);
+
 	return ret;
 	return ret;
 }
 }
 
 
@@ -3675,12 +3686,6 @@ static int __devexit s3c_hsotg_remove(struct platform_device *pdev)
 		usb_gadget_unregister_driver(hsotg->driver);
 		usb_gadget_unregister_driver(hsotg->driver);
 	}
 	}
 
 
-	free_irq(hsotg->irq, hsotg);
-	iounmap(hsotg->regs);
-
-	release_resource(hsotg->regs_res);
-	kfree(hsotg->regs_res);
-
 	s3c_hsotg_phy_disable(hsotg);
 	s3c_hsotg_phy_disable(hsotg);
 	regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
 	regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
 
 

+ 7 - 6
drivers/usb/gadget/s3c-hsudc.c

@@ -24,6 +24,7 @@
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/otg.h>
@@ -1165,7 +1166,7 @@ static int s3c_hsudc_start(struct usb_gadget *gadget,
 	}
 	}
 
 
 	/* connect to bus through transceiver */
 	/* connect to bus through transceiver */
-	if (hsudc->transceiver) {
+	if (!IS_ERR_OR_NULL(hsudc->transceiver)) {
 		ret = otg_set_peripheral(hsudc->transceiver->otg,
 		ret = otg_set_peripheral(hsudc->transceiver->otg,
 					&hsudc->gadget);
 					&hsudc->gadget);
 		if (ret) {
 		if (ret) {
@@ -1220,7 +1221,7 @@ static int s3c_hsudc_stop(struct usb_gadget *gadget,
 	s3c_hsudc_stop_activity(hsudc);
 	s3c_hsudc_stop_activity(hsudc);
 	spin_unlock_irqrestore(&hsudc->lock, flags);
 	spin_unlock_irqrestore(&hsudc->lock, flags);
 
 
-	if (hsudc->transceiver)
+	if (!IS_ERR_OR_NULL(hsudc->transceiver))
 		(void) otg_set_peripheral(hsudc->transceiver->otg, NULL);
 		(void) otg_set_peripheral(hsudc->transceiver->otg, NULL);
 
 
 	disable_irq(hsudc->irq);
 	disable_irq(hsudc->irq);
@@ -1249,7 +1250,7 @@ static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA)
 	if (!hsudc)
 	if (!hsudc)
 		return -ENODEV;
 		return -ENODEV;
 
 
-	if (hsudc->transceiver)
+	if (!IS_ERR_OR_NULL(hsudc->transceiver))
 		return usb_phy_set_power(hsudc->transceiver, mA);
 		return usb_phy_set_power(hsudc->transceiver, mA);
 
 
 	return -EOPNOTSUPP;
 	return -EOPNOTSUPP;
@@ -1282,7 +1283,7 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
 	hsudc->dev = dev;
 	hsudc->dev = dev;
 	hsudc->pd = pdev->dev.platform_data;
 	hsudc->pd = pdev->dev.platform_data;
 
 
-	hsudc->transceiver = usb_get_transceiver();
+	hsudc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
 
 
 	for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++)
 	for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++)
 		hsudc->supplies[i].supply = s3c_hsudc_supply_names[i];
 		hsudc->supplies[i].supply = s3c_hsudc_supply_names[i];
@@ -1385,8 +1386,8 @@ err_irq:
 err_remap:
 err_remap:
 	release_mem_region(res->start, resource_size(res));
 	release_mem_region(res->start, resource_size(res));
 err_res:
 err_res:
-	if (hsudc->transceiver)
-		usb_put_transceiver(hsudc->transceiver);
+	if (!IS_ERR_OR_NULL(hsudc->transceiver))
+		usb_put_phy(hsudc->transceiver);
 
 
 	regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
 	regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
 err_supplies:
 err_supplies:

+ 29 - 34
drivers/usb/gadget/storage_common.c

@@ -37,12 +37,6 @@
  * When FSG_NO_OTG is defined fsg_otg_desc won't be defined.
  * When FSG_NO_OTG is defined fsg_otg_desc won't be defined.
  */
  */
 
 
-/*
- * When FSG_BUFFHD_STATIC_BUFFER is defined when this file is included
- * the fsg_buffhd structure's buf field will be an array of FSG_BUFLEN
- * characters rather then a pointer to void.
- */
-
 /*
 /*
  * When USB_GADGET_DEBUG_FILES is defined the module param num_buffers
  * When USB_GADGET_DEBUG_FILES is defined the module param num_buffers
  * sets the number of pipeline buffers (length of the fsg_buffhd array).
  * sets the number of pipeline buffers (length of the fsg_buffhd array).
@@ -260,11 +254,7 @@ enum fsg_buffer_state {
 };
 };
 
 
 struct fsg_buffhd {
 struct fsg_buffhd {
-#ifdef FSG_BUFFHD_STATIC_BUFFER
-	char				buf[FSG_BUFLEN];
-#else
 	void				*buf;
 	void				*buf;
-#endif
 	enum fsg_buffer_state		state;
 	enum fsg_buffer_state		state;
 	struct fsg_buffhd		*next;
 	struct fsg_buffhd		*next;
 
 
@@ -627,6 +617,16 @@ static struct usb_gadget_strings	fsg_stringtab = {
  * the caller must own fsg->filesem for writing.
  * the caller must own fsg->filesem for writing.
  */
  */
 
 
+static void fsg_lun_close(struct fsg_lun *curlun)
+{
+	if (curlun->filp) {
+		LDBG(curlun, "close backing file\n");
+		fput(curlun->filp);
+		curlun->filp = NULL;
+	}
+}
+
+
 static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
 static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
 {
 {
 	int				ro;
 	int				ro;
@@ -636,6 +636,8 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
 	loff_t				size;
 	loff_t				size;
 	loff_t				num_sectors;
 	loff_t				num_sectors;
 	loff_t				min_sectors;
 	loff_t				min_sectors;
+	unsigned int			blkbits;
+	unsigned int			blksize;
 
 
 	/* R/W if we can, R/O if we must */
 	/* R/W if we can, R/O if we must */
 	ro = curlun->initially_ro;
 	ro = curlun->initially_ro;
@@ -680,17 +682,17 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
 	}
 	}
 
 
 	if (curlun->cdrom) {
 	if (curlun->cdrom) {
-		curlun->blksize = 2048;
-		curlun->blkbits = 11;
+		blksize = 2048;
+		blkbits = 11;
 	} else if (inode->i_bdev) {
 	} else if (inode->i_bdev) {
-		curlun->blksize = bdev_logical_block_size(inode->i_bdev);
-		curlun->blkbits = blksize_bits(curlun->blksize);
+		blksize = bdev_logical_block_size(inode->i_bdev);
+		blkbits = blksize_bits(blksize);
 	} else {
 	} else {
-		curlun->blksize = 512;
-		curlun->blkbits = 9;
+		blksize = 512;
+		blkbits = 9;
 	}
 	}
 
 
-	num_sectors = size >> curlun->blkbits; /* File size in logic-block-size blocks */
+	num_sectors = size >> blkbits; /* File size in logic-block-size blocks */
 	min_sectors = 1;
 	min_sectors = 1;
 	if (curlun->cdrom) {
 	if (curlun->cdrom) {
 		min_sectors = 300;	/* Smallest track is 300 frames */
 		min_sectors = 300;	/* Smallest track is 300 frames */
@@ -707,7 +709,12 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
 		goto out;
 		goto out;
 	}
 	}
 
 
+	if (fsg_lun_is_open(curlun))
+		fsg_lun_close(curlun);
+
 	get_file(filp);
 	get_file(filp);
+	curlun->blksize = blksize;
+	curlun->blkbits = blkbits;
 	curlun->ro = ro;
 	curlun->ro = ro;
 	curlun->filp = filp;
 	curlun->filp = filp;
 	curlun->file_length = size;
 	curlun->file_length = size;
@@ -721,16 +728,6 @@ out:
 }
 }
 
 
 
 
-static void fsg_lun_close(struct fsg_lun *curlun)
-{
-	if (curlun->filp) {
-		LDBG(curlun, "close backing file\n");
-		fput(curlun->filp);
-		curlun->filp = NULL;
-	}
-}
-
-
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 /*
 /*
@@ -881,19 +878,17 @@ static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
 	if (count > 0 && buf[count-1] == '\n')
 	if (count > 0 && buf[count-1] == '\n')
 		((char *) buf)[count-1] = 0;		/* Ugh! */
 		((char *) buf)[count-1] = 0;		/* Ugh! */
 
 
-	/* Eject current medium */
-	down_write(filesem);
-	if (fsg_lun_is_open(curlun)) {
-		fsg_lun_close(curlun);
-		curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
-	}
-
 	/* Load new medium */
 	/* Load new medium */
+	down_write(filesem);
 	if (count > 0 && buf[0]) {
 	if (count > 0 && buf[0]) {
+		/* fsg_lun_open() will close existing file if any. */
 		rc = fsg_lun_open(curlun, buf);
 		rc = fsg_lun_open(curlun, buf);
 		if (rc == 0)
 		if (rc == 0)
 			curlun->unit_attention_data =
 			curlun->unit_attention_data =
 					SS_NOT_READY_TO_READY_TRANSITION;
 					SS_NOT_READY_TO_READY_TRANSITION;
+	} else if (fsg_lun_is_open(curlun)) {
+		fsg_lun_close(curlun);
+		curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
 	}
 	}
 	up_write(filesem);
 	up_write(filesem);
 	return (rc < 0 ? rc : count);
 	return (rc < 0 ? rc : count);

+ 6 - 6
drivers/usb/gadget/u_ether.c

@@ -798,12 +798,6 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
 
 
 	SET_ETHTOOL_OPS(net, &ops);
 	SET_ETHTOOL_OPS(net, &ops);
 
 
-	/* two kinds of host-initiated state changes:
-	 *  - iff DATA transfer is active, carrier is "on"
-	 *  - tx queueing enabled if open *and* carrier is "on"
-	 */
-	netif_carrier_off(net);
-
 	dev->gadget = g;
 	dev->gadget = g;
 	SET_NETDEV_DEV(net, &g->dev);
 	SET_NETDEV_DEV(net, &g->dev);
 	SET_NETDEV_DEVTYPE(net, &gadget_type);
 	SET_NETDEV_DEVTYPE(net, &gadget_type);
@@ -817,6 +811,12 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
 		INFO(dev, "HOST MAC %pM\n", dev->host_mac);
 		INFO(dev, "HOST MAC %pM\n", dev->host_mac);
 
 
 		the_dev = dev;
 		the_dev = dev;
+
+		/* two kinds of host-initiated state changes:
+		 *  - iff DATA transfer is active, carrier is "on"
+		 *  - tx queueing enabled if open *and* carrier is "on"
+		 */
+		netif_carrier_off(net);
 	}
 	}
 
 
 	return status;
 	return status;

+ 3 - 1
drivers/usb/gadget/uvc.h

@@ -153,9 +153,11 @@ struct uvc_device
 
 
 	/* Descriptors */
 	/* Descriptors */
 	struct {
 	struct {
-		const struct uvc_descriptor_header * const *control;
+		const struct uvc_descriptor_header * const *fs_control;
+		const struct uvc_descriptor_header * const *ss_control;
 		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;
 	} desc;
 	} desc;
 
 
 	unsigned int control_intf;
 	unsigned int control_intf;

+ 25 - 4
drivers/usb/gadget/webcam.c

@@ -272,7 +272,15 @@ static const struct uvc_color_matching_descriptor uvc_color_matching = {
 	.bMatrixCoefficients	= 4,
 	.bMatrixCoefficients	= 4,
 };
 };
 
 
-static const struct uvc_descriptor_header * const uvc_control_cls[] = {
+static const struct uvc_descriptor_header * const uvc_fs_control_cls[] = {
+	(const struct uvc_descriptor_header *) &uvc_control_header,
+	(const struct uvc_descriptor_header *) &uvc_camera_terminal,
+	(const struct uvc_descriptor_header *) &uvc_processing,
+	(const struct uvc_descriptor_header *) &uvc_output_terminal,
+	NULL,
+};
+
+static const struct uvc_descriptor_header * const uvc_ss_control_cls[] = {
 	(const struct uvc_descriptor_header *) &uvc_control_header,
 	(const struct uvc_descriptor_header *) &uvc_control_header,
 	(const struct uvc_descriptor_header *) &uvc_camera_terminal,
 	(const struct uvc_descriptor_header *) &uvc_camera_terminal,
 	(const struct uvc_descriptor_header *) &uvc_processing,
 	(const struct uvc_descriptor_header *) &uvc_processing,
@@ -304,6 +312,18 @@ static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
 	NULL,
 	NULL,
 };
 };
 
 
+static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = {
+	(const struct uvc_descriptor_header *) &uvc_input_header,
+	(const struct uvc_descriptor_header *) &uvc_format_yuv,
+	(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
+	(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
+	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
+	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
+	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
+	(const struct uvc_descriptor_header *) &uvc_color_matching,
+	NULL,
+};
+
 /* --------------------------------------------------------------------------
 /* --------------------------------------------------------------------------
  * USB configuration
  * USB configuration
  */
  */
@@ -311,8 +331,9 @@ static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
 static int __init
 static int __init
 webcam_config_bind(struct usb_configuration *c)
 webcam_config_bind(struct usb_configuration *c)
 {
 {
-	return uvc_bind_config(c, uvc_control_cls, uvc_fs_streaming_cls,
-			       uvc_hs_streaming_cls);
+	return uvc_bind_config(c, uvc_fs_control_cls, uvc_ss_control_cls,
+		uvc_fs_streaming_cls, uvc_hs_streaming_cls,
+		uvc_ss_streaming_cls);
 }
 }
 
 
 static struct usb_configuration webcam_config_driver = {
 static struct usb_configuration webcam_config_driver = {
@@ -373,7 +394,7 @@ static struct usb_composite_driver webcam_driver = {
 	.name		= "g_webcam",
 	.name		= "g_webcam",
 	.dev		= &webcam_device_descriptor,
 	.dev		= &webcam_device_descriptor,
 	.strings	= webcam_device_strings,
 	.strings	= webcam_device_strings,
-	.max_speed	= USB_SPEED_HIGH,
+	.max_speed	= USB_SPEED_SUPER,
 	.unbind		= webcam_unbind,
 	.unbind		= webcam_unbind,
 };
 };
 
 

+ 2 - 2
drivers/usb/host/Kconfig

@@ -652,7 +652,7 @@ config USB_HCD_BCMA
 	select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
 	select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
 	select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
 	select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
 	help
 	help
-	  Enbale support for the EHCI and OCHI host controller on an bcma bus.
+	  Enable support for the EHCI and OCHI host controller on an bcma bus.
 	  It converts the bcma driver into two platform device drivers
 	  It converts the bcma driver into two platform device drivers
 	  for ehci and ohci.
 	  for ehci and ohci.
 
 
@@ -664,7 +664,7 @@ config USB_HCD_SSB
 	select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
 	select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
 	select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
 	select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
 	help
 	help
-	  Enbale support for the EHCI and OCHI host controller on an bcma bus.
+	  Enable support for the EHCI and OCHI host controller on an bcma bus.
 	  It converts the bcma driver into two platform device drivers
 	  It converts the bcma driver into two platform device drivers
 	  for ehci and ohci.
 	  for ehci and ohci.
 
 

+ 2 - 17
drivers/usb/host/ehci-atmel.c

@@ -53,30 +53,15 @@ static void atmel_stop_ehci(struct platform_device *pdev)
 static int ehci_atmel_setup(struct usb_hcd *hcd)
 static int ehci_atmel_setup(struct usb_hcd *hcd)
 {
 {
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-	int retval = 0;
+	int retval;
 
 
 	/* registers start at offset 0x0 */
 	/* registers start at offset 0x0 */
 	ehci->caps = hcd->regs;
 	ehci->caps = hcd->regs;
-	ehci->regs = hcd->regs +
-		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-	dbg_hcs_params(ehci, "reset");
-	dbg_hcc_params(ehci, "reset");
-
-	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-
-	retval = ehci_halt(ehci);
-	if (retval)
-		return retval;
 
 
-	/* data structure init */
-	retval = ehci_init(hcd);
+	retval = ehci_setup(hcd);
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 
 
-	ehci->sbrn = 0x20;
-
-	ehci_reset(ehci);
 	ehci_port_power(ehci, 0);
 	ehci_port_power(ehci, 0);
 
 
 	return retval;
 	return retval;

+ 8 - 79
drivers/usb/host/ehci-au1xxx.c

@@ -20,10 +20,12 @@ extern int usb_disabled(void);
 static int au1xxx_ehci_setup(struct usb_hcd *hcd)
 static int au1xxx_ehci_setup(struct usb_hcd *hcd)
 {
 {
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-	int ret = ehci_init(hcd);
+	int ret;
+
+	ehci->caps = hcd->regs;
+	ret = ehci_setup(hcd);
 
 
 	ehci->need_io_watchdog = 0;
 	ehci->need_io_watchdog = 0;
-	ehci_reset(ehci);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -78,7 +80,6 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
 static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 {
 {
 	struct usb_hcd *hcd;
 	struct usb_hcd *hcd;
-	struct ehci_hcd *ehci;
 	struct resource *res;
 	struct resource *res;
 	int ret;
 	int ret;
 
 
@@ -116,13 +117,6 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 		goto err3;
 		goto err3;
 	}
 	}
 
 
-	ehci = hcd_to_ehci(hcd);
-	ehci->caps = hcd->regs;
-	ehci->regs = hcd->regs +
-		HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
-	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = readl(&ehci->caps->hcs_params);
-
 	ret = usb_add_hcd(hcd, pdev->resource[1].start,
 	ret = usb_add_hcd(hcd, pdev->resource[1].start,
 			  IRQF_SHARED);
 			  IRQF_SHARED);
 	if (ret == 0) {
 	if (ret == 0) {
@@ -158,28 +152,10 @@ static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
 static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
 static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
 {
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
-	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-	unsigned long flags;
-	int rc = 0;
-
-	if (time_before(jiffies, ehci->next_statechange))
-		msleep(10);
-
-	/* Root hub was already suspended. Disable irq emission and
-	 * mark HW unaccessible.  The PM and USB cores make sure that
-	 * the root hub is either suspended or stopped.
-	 */
-	ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
-	spin_lock_irqsave(&ehci->lock, flags);
-	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
-	(void)ehci_readl(ehci, &ehci->regs->intr_enable);
-
-	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-	spin_unlock_irqrestore(&ehci->lock, flags);
-
-	// could save FLADJ in case of Vaux power loss
-	// ... we'd only use it to handle clock skew
+	bool do_wakeup = device_may_wakeup(dev);
+	int rc;
 
 
+	rc = ehci_suspend(hcd, do_wakeup);
 	alchemy_usb_control(ALCHEMY_USB_EHCI0, 0);
 	alchemy_usb_control(ALCHEMY_USB_EHCI0, 0);
 
 
 	return rc;
 	return rc;
@@ -188,56 +164,9 @@ static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
 static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
 static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
 {
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
-	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 
 
 	alchemy_usb_control(ALCHEMY_USB_EHCI0, 1);
 	alchemy_usb_control(ALCHEMY_USB_EHCI0, 1);
-
-	// maybe restore FLADJ
-
-	if (time_before(jiffies, ehci->next_statechange))
-		msleep(100);
-
-	/* Mark hardware accessible again as we are out of D3 state by now */
-	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
-	/* If CF is still set, we maintained PCI Vaux power.
-	 * Just undo the effect of ehci_pci_suspend().
-	 */
-	if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
-		int	mask = INTR_MASK;
-
-		ehci_prepare_ports_for_controller_resume(ehci);
-		if (!hcd->self.root_hub->do_remote_wakeup)
-			mask &= ~STS_PCD;
-		ehci_writel(ehci, mask, &ehci->regs->intr_enable);
-		ehci_readl(ehci, &ehci->regs->intr_enable);
-		return 0;
-	}
-
-	ehci_dbg(ehci, "lost power, restarting\n");
-	usb_root_hub_lost_power(hcd->self.root_hub);
-
-	/* Else reset, to cope with power loss or flush-to-storage
-	 * style "resume" having let BIOS kick in during reboot.
-	 */
-	(void) ehci_halt(ehci);
-	(void) ehci_reset(ehci);
-
-	/* emptying the schedule aborts any urbs */
-	spin_lock_irq(&ehci->lock);
-	if (ehci->reclaim)
-		end_unlink_async(ehci);
-	ehci_work(ehci);
-	spin_unlock_irq(&ehci->lock);
-
-	ehci_writel(ehci, ehci->command, &ehci->regs->command);
-	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
-	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
-
-	/* here we "know" root ports should always stay powered */
-	ehci_port_power(ehci, 1);
-
-	ehci->rh_state = EHCI_RH_SUSPENDED;
+	ehci_resume(hcd, false);
 
 
 	return 0;
 	return 0;
 }
 }

+ 1 - 5
drivers/usb/host/ehci-cns3xxx.c

@@ -33,14 +33,10 @@ static int cns3xxx_ehci_init(struct usb_hcd *hcd)
 	}
 	}
 
 
 	ehci->caps = hcd->regs;
 	ehci->caps = hcd->regs;
-	ehci->regs = hcd->regs
-		+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
 
 	hcd->has_tt = 0;
 	hcd->has_tt = 0;
-	ehci_reset(ehci);
 
 
-	retval = ehci_init(hcd);
+	retval = ehci_setup(hcd);
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 
 

+ 14 - 10
drivers/usb/host/ehci-dbg.c

@@ -404,9 +404,9 @@ struct debug_buffer {
 
 
 #define speed_char(info1) ({ char tmp; \
 #define speed_char(info1) ({ char tmp; \
 		switch (info1 & (3 << 12)) { \
 		switch (info1 & (3 << 12)) { \
-		case 0 << 12: tmp = 'f'; break; \
-		case 1 << 12: tmp = 'l'; break; \
-		case 2 << 12: tmp = 'h'; break; \
+		case QH_FULL_SPEED: tmp = 'f'; break; \
+		case QH_LOW_SPEED:  tmp = 'l'; break; \
+		case QH_HIGH_SPEED: tmp = 'h'; break; \
 		default: tmp = '?'; break; \
 		default: tmp = '?'; break; \
 		}; tmp; })
 		}; tmp; })
 
 
@@ -538,12 +538,13 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf)
 	spin_lock_irqsave (&ehci->lock, flags);
 	spin_lock_irqsave (&ehci->lock, flags);
 	for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh)
 	for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh)
 		qh_lines (ehci, qh, &next, &size);
 		qh_lines (ehci, qh, &next, &size);
-	if (ehci->reclaim && size > 0) {
-		temp = scnprintf (next, size, "\nreclaim =\n");
+	if (ehci->async_unlink && size > 0) {
+		temp = scnprintf(next, size, "\nunlink =\n");
 		size -= temp;
 		size -= temp;
 		next += temp;
 		next += temp;
 
 
-		for (qh = ehci->reclaim; size > 0 && qh; qh = qh->reclaim)
+		for (qh = ehci->async_unlink; size > 0 && qh;
+				qh = qh->unlink_next)
 			qh_lines (ehci, qh, &next, &size);
 			qh_lines (ehci, qh, &next, &size);
 	}
 	}
 	spin_unlock_irqrestore (&ehci->lock, flags);
 	spin_unlock_irqrestore (&ehci->lock, flags);
@@ -705,6 +706,8 @@ static const char *rh_state_string(struct ehci_hcd *ehci)
 		return "suspended";
 		return "suspended";
 	case EHCI_RH_RUNNING:
 	case EHCI_RH_RUNNING:
 		return "running";
 		return "running";
+	case EHCI_RH_STOPPING:
+		return "stopping";
 	}
 	}
 	return "?";
 	return "?";
 }
 }
@@ -841,16 +844,17 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
 		}
 		}
 	}
 	}
 
 
-	if (ehci->reclaim) {
-		temp = scnprintf(next, size, "reclaim qh %p\n", ehci->reclaim);
+	if (ehci->async_unlink) {
+		temp = scnprintf(next, size, "async unlink qh %p\n",
+				ehci->async_unlink);
 		size -= temp;
 		size -= temp;
 		next += temp;
 		next += temp;
 	}
 	}
 
 
 #ifdef EHCI_STATS
 #ifdef EHCI_STATS
 	temp = scnprintf (next, size,
 	temp = scnprintf (next, size,
-		"irq normal %ld err %ld reclaim %ld (lost %ld)\n",
-		ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,
+		"irq normal %ld err %ld iaa %ld (lost %ld)\n",
+		ehci->stats.normal, ehci->stats.error, ehci->stats.iaa,
 		ehci->stats.lost_iaa);
 		ehci->stats.lost_iaa);
 	size -= temp;
 	size -= temp;
 	next += temp;
 	next += temp;

+ 13 - 29
drivers/usb/host/ehci-fsl.c

@@ -27,6 +27,7 @@
 #include <linux/types.h>
 #include <linux/types.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/pm.h>
+#include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/fsl_devices.h>
 #include <linux/fsl_devices.h>
 
 
@@ -142,19 +143,19 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
 	if (pdata->operating_mode == FSL_USB2_DR_OTG) {
 	if (pdata->operating_mode == FSL_USB2_DR_OTG) {
 		struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 		struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 
 
-		ehci->transceiver = usb_get_transceiver();
-		dev_dbg(&pdev->dev, "hcd=0x%p  ehci=0x%p, transceiver=0x%p\n",
-			hcd, ehci, ehci->transceiver);
+		hcd->phy = usb_get_phy(USB_PHY_TYPE_USB2);
+		dev_dbg(&pdev->dev, "hcd=0x%p  ehci=0x%p, phy=0x%p\n",
+			hcd, ehci, hcd->phy);
 
 
-		if (ehci->transceiver) {
-			retval = otg_set_host(ehci->transceiver->otg,
+		if (!IS_ERR_OR_NULL(hcd->phy)) {
+			retval = otg_set_host(hcd->phy->otg,
 					      &ehci_to_hcd(ehci)->self);
 					      &ehci_to_hcd(ehci)->self);
 			if (retval) {
 			if (retval) {
-				usb_put_transceiver(ehci->transceiver);
+				usb_put_phy(hcd->phy);
 				goto err4;
 				goto err4;
 			}
 			}
 		} else {
 		} else {
-			dev_err(&pdev->dev, "can't find transceiver\n");
+			dev_err(&pdev->dev, "can't find phy\n");
 			retval = -ENODEV;
 			retval = -ENODEV;
 			goto err4;
 			goto err4;
 		}
 		}
@@ -190,11 +191,10 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
 			       struct platform_device *pdev)
 			       struct platform_device *pdev)
 {
 {
 	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
 	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
-	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 
 
-	if (ehci->transceiver) {
-		otg_set_host(ehci->transceiver->otg, NULL);
-		usb_put_transceiver(ehci->transceiver);
+	if (!IS_ERR_OR_NULL(hcd->phy)) {
+		otg_set_host(hcd->phy->otg, NULL);
+		usb_put_phy(hcd->phy);
 	}
 	}
 
 
 	usb_remove_hcd(hcd);
 	usb_remove_hcd(hcd);
@@ -313,7 +313,7 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
 	}
 	}
 
 
 	if (pdata->have_sysif_regs) {
 	if (pdata->have_sysif_regs) {
-#ifdef CONFIG_PPC_85xx
+#ifdef CONFIG_FSL_SOC_BOOKE
 		out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008);
 		out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008);
 		out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080);
 		out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080);
 #else
 #else
@@ -348,29 +348,13 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
 
 
 	/* EHCI registers start at offset 0x100 */
 	/* EHCI registers start at offset 0x100 */
 	ehci->caps = hcd->regs + 0x100;
 	ehci->caps = hcd->regs + 0x100;
-	ehci->regs = hcd->regs + 0x100 +
-		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-	dbg_hcs_params(ehci, "reset");
-	dbg_hcc_params(ehci, "reset");
-
-	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
 
 	hcd->has_tt = 1;
 	hcd->has_tt = 1;
 
 
-	retval = ehci_halt(ehci);
-	if (retval)
-		return retval;
-
-	/* data structure init */
-	retval = ehci_init(hcd);
+	retval = ehci_setup(hcd);
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 
 
-	ehci->sbrn = 0x20;
-
-	ehci_reset(ehci);
-
 	if (of_device_is_compatible(dev->parent->of_node,
 	if (of_device_is_compatible(dev->parent->of_node,
 				    "fsl,mpc5121-usb2-dr")) {
 				    "fsl,mpc5121-usb2-dr")) {
 		/*
 		/*

+ 2 - 13
drivers/usb/host/ehci-grlib.c

@@ -40,18 +40,13 @@ static int ehci_grlib_setup(struct usb_hcd *hcd)
 	struct ehci_hcd	*ehci = hcd_to_ehci(hcd);
 	struct ehci_hcd	*ehci = hcd_to_ehci(hcd);
 	int		retval;
 	int		retval;
 
 
-	retval = ehci_halt(ehci);
+	retval = ehci_setup(hcd);
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 
 
-	retval = ehci_init(hcd);
-	if (retval)
-		return retval;
-
-	ehci->sbrn = 0x20;
 	ehci_port_power(ehci, 1);
 	ehci_port_power(ehci, 1);
 
 
-	return ehci_reset(ehci);
+	return retval;
 }
 }
 
 
 
 
@@ -164,12 +159,6 @@ static int __devinit ehci_hcd_grlib_probe(struct platform_device *op)
 		ehci->big_endian_capbase = 1;
 		ehci->big_endian_capbase = 1;
 	}
 	}
 
 
-	ehci->regs = hcd->regs +
-		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-
-	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-
 	rv = usb_add_hcd(hcd, irq, 0);
 	rv = usb_add_hcd(hcd, irq, 0);
 	if (rv)
 	if (rv)
 		goto err_ehci;
 		goto err_ehci;

+ 226 - 286
drivers/usb/host/ehci-hcd.c

@@ -30,8 +30,7 @@
 #include <linux/vmalloc.h>
 #include <linux/vmalloc.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/ktime.h>
+#include <linux/hrtimer.h>
 #include <linux/list.h>
 #include <linux/list.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
@@ -94,12 +93,6 @@ static const char	hcd_name [] = "ehci_hcd";
  */
  */
 #define	EHCI_TUNE_FLS		1	/* (medium) 512-frame schedule */
 #define	EHCI_TUNE_FLS		1	/* (medium) 512-frame schedule */
 
 
-#define EHCI_IAA_MSECS		10		/* arbitrary */
-#define EHCI_IO_JIFFIES		(HZ/10)		/* io watchdog > irq_thresh */
-#define EHCI_ASYNC_JIFFIES	(HZ/20)		/* async idle timeout */
-#define EHCI_SHRINK_JIFFIES	(DIV_ROUND_UP(HZ, 200) + 1)
-						/* 5-ms async qh unlink delay */
-
 /* Initial IRQ latency:  faster than hw default */
 /* Initial IRQ latency:  faster than hw default */
 static int log2_irq_thresh = 0;		// 0 to 6
 static int log2_irq_thresh = 0;		// 0 to 6
 module_param (log2_irq_thresh, int, S_IRUGO);
 module_param (log2_irq_thresh, int, S_IRUGO);
@@ -130,41 +123,6 @@ MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us");
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-static void
-timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action)
-{
-	/* Don't override timeouts which shrink or (later) disable
-	 * the async ring; just the I/O watchdog.  Note that if a
-	 * SHRINK were pending, OFF would never be requested.
-	 */
-	if (timer_pending(&ehci->watchdog)
-			&& ((BIT(TIMER_ASYNC_SHRINK) | BIT(TIMER_ASYNC_OFF))
-				& ehci->actions))
-		return;
-
-	if (!test_and_set_bit(action, &ehci->actions)) {
-		unsigned long t;
-
-		switch (action) {
-		case TIMER_IO_WATCHDOG:
-			if (!ehci->need_io_watchdog)
-				return;
-			t = EHCI_IO_JIFFIES;
-			break;
-		case TIMER_ASYNC_OFF:
-			t = EHCI_ASYNC_JIFFIES;
-			break;
-		/* case TIMER_ASYNC_SHRINK: */
-		default:
-			t = EHCI_SHRINK_JIFFIES;
-			break;
-		}
-		mod_timer(&ehci->watchdog, t + jiffies);
-	}
-}
-
-/*-------------------------------------------------------------------------*/
-
 /*
 /*
  * handshake - spin reading hc until handshake completes or fails
  * handshake - spin reading hc until handshake completes or fails
  * @ptr: address of hc register to be read
  * @ptr: address of hc register to be read
@@ -203,29 +161,30 @@ static int handshake (struct ehci_hcd *ehci, void __iomem *ptr,
 /* check TDI/ARC silicon is in host mode */
 /* check TDI/ARC silicon is in host mode */
 static int tdi_in_host_mode (struct ehci_hcd *ehci)
 static int tdi_in_host_mode (struct ehci_hcd *ehci)
 {
 {
-	u32 __iomem	*reg_ptr;
 	u32		tmp;
 	u32		tmp;
 
 
-	reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + USBMODE);
-	tmp = ehci_readl(ehci, reg_ptr);
+	tmp = ehci_readl(ehci, &ehci->regs->usbmode);
 	return (tmp & 3) == USBMODE_CM_HC;
 	return (tmp & 3) == USBMODE_CM_HC;
 }
 }
 
 
-/* force HC to halt state from unknown (EHCI spec section 2.3) */
+/*
+ * Force HC to halt state from unknown (EHCI spec section 2.3).
+ * Must be called with interrupts enabled and the lock not held.
+ */
 static int ehci_halt (struct ehci_hcd *ehci)
 static int ehci_halt (struct ehci_hcd *ehci)
 {
 {
-	u32	temp = ehci_readl(ehci, &ehci->regs->status);
+	u32	temp;
+
+	spin_lock_irq(&ehci->lock);
 
 
 	/* disable any irqs left enabled by previous code */
 	/* disable any irqs left enabled by previous code */
 	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 
 
-	if (ehci_is_TDI(ehci) && tdi_in_host_mode(ehci) == 0) {
+	if (ehci_is_TDI(ehci) && !tdi_in_host_mode(ehci)) {
+		spin_unlock_irq(&ehci->lock);
 		return 0;
 		return 0;
 	}
 	}
 
 
-	if ((temp & STS_HALT) != 0)
-		return 0;
-
 	/*
 	/*
 	 * This routine gets called during probe before ehci->command
 	 * This routine gets called during probe before ehci->command
 	 * has been initialized, so we can't rely on its value.
 	 * has been initialized, so we can't rely on its value.
@@ -234,80 +193,20 @@ static int ehci_halt (struct ehci_hcd *ehci)
 	temp = ehci_readl(ehci, &ehci->regs->command);
 	temp = ehci_readl(ehci, &ehci->regs->command);
 	temp &= ~(CMD_RUN | CMD_IAAD);
 	temp &= ~(CMD_RUN | CMD_IAAD);
 	ehci_writel(ehci, temp, &ehci->regs->command);
 	ehci_writel(ehci, temp, &ehci->regs->command);
-	return handshake (ehci, &ehci->regs->status,
-			  STS_HALT, STS_HALT, 16 * 125);
-}
-
-#if defined(CONFIG_USB_SUSPEND) && defined(CONFIG_PPC_PS3)
-
-/*
- * The EHCI controller of the Cell Super Companion Chip used in the
- * PS3 will stop the root hub after all root hub ports are suspended.
- * When in this condition handshake will return -ETIMEDOUT.  The
- * STS_HLT bit will not be set, so inspection of the frame index is
- * used here to test for the condition.  If the condition is found
- * return success to allow the USB suspend to complete.
- */
-
-static int handshake_for_broken_root_hub(struct ehci_hcd *ehci,
-					 void __iomem *ptr, u32 mask, u32 done,
-					 int usec)
-{
-	unsigned int old_index;
-	int error;
-
-	if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
-		return -ETIMEDOUT;
-
-	old_index = ehci_read_frame_index(ehci);
-
-	error = handshake(ehci, ptr, mask, done, usec);
-
-	if (error == -ETIMEDOUT && ehci_read_frame_index(ehci) == old_index)
-		return 0;
-
-	return error;
-}
-
-#else
-
-static int handshake_for_broken_root_hub(struct ehci_hcd *ehci,
-					 void __iomem *ptr, u32 mask, u32 done,
-					 int usec)
-{
-	return -ETIMEDOUT;
-}
-
-#endif
 
 
-static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
-				       u32 mask, u32 done, int usec)
-{
-	int error;
-
-	error = handshake(ehci, ptr, mask, done, usec);
-	if (error == -ETIMEDOUT)
-		error = handshake_for_broken_root_hub(ehci, ptr, mask, done,
-						      usec);
-
-	if (error) {
-		ehci_halt(ehci);
-		ehci->rh_state = EHCI_RH_HALTED;
-		ehci_err(ehci, "force halt; handshake %p %08x %08x -> %d\n",
-			ptr, mask, done, error);
-	}
+	spin_unlock_irq(&ehci->lock);
+	synchronize_irq(ehci_to_hcd(ehci)->irq);
 
 
-	return error;
+	return handshake(ehci, &ehci->regs->status,
+			  STS_HALT, STS_HALT, 16 * 125);
 }
 }
 
 
 /* put TDI/ARC silicon into EHCI mode */
 /* put TDI/ARC silicon into EHCI mode */
 static void tdi_reset (struct ehci_hcd *ehci)
 static void tdi_reset (struct ehci_hcd *ehci)
 {
 {
-	u32 __iomem	*reg_ptr;
 	u32		tmp;
 	u32		tmp;
 
 
-	reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + USBMODE);
-	tmp = ehci_readl(ehci, reg_ptr);
+	tmp = ehci_readl(ehci, &ehci->regs->usbmode);
 	tmp |= USBMODE_CM_HC;
 	tmp |= USBMODE_CM_HC;
 	/* The default byte access to MMR space is LE after
 	/* The default byte access to MMR space is LE after
 	 * controller reset. Set the required endian mode
 	 * controller reset. Set the required endian mode
@@ -315,10 +214,13 @@ static void tdi_reset (struct ehci_hcd *ehci)
 	 */
 	 */
 	if (ehci_big_endian_mmio(ehci))
 	if (ehci_big_endian_mmio(ehci))
 		tmp |= USBMODE_BE;
 		tmp |= USBMODE_BE;
-	ehci_writel(ehci, tmp, reg_ptr);
+	ehci_writel(ehci, tmp, &ehci->regs->usbmode);
 }
 }
 
 
-/* reset a non-running (STS_HALT == 1) controller */
+/*
+ * Reset a non-running (STS_HALT == 1) controller.
+ * Must be called with interrupts enabled and the lock not held.
+ */
 static int ehci_reset (struct ehci_hcd *ehci)
 static int ehci_reset (struct ehci_hcd *ehci)
 {
 {
 	int	retval;
 	int	retval;
@@ -339,9 +241,8 @@ static int ehci_reset (struct ehci_hcd *ehci)
 
 
 	if (ehci->has_hostpc) {
 	if (ehci->has_hostpc) {
 		ehci_writel(ehci, USBMODE_EX_HC | USBMODE_EX_VBPS,
 		ehci_writel(ehci, USBMODE_EX_HC | USBMODE_EX_VBPS,
-			(u32 __iomem *)(((u8 *)ehci->regs) + USBMODE_EX));
-		ehci_writel(ehci, TXFIFO_DEFAULT,
-			(u32 __iomem *)(((u8 *)ehci->regs) + TXFILLTUNING));
+				&ehci->regs->usbmode_ex);
+		ehci_writel(ehci, TXFIFO_DEFAULT, &ehci->regs->txfill_tuning);
 	}
 	}
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
@@ -357,36 +258,40 @@ static int ehci_reset (struct ehci_hcd *ehci)
 	return retval;
 	return retval;
 }
 }
 
 
-/* idle the controller (from running) */
+/*
+ * Idle the controller (turn off the schedules).
+ * Must be called with interrupts enabled and the lock not held.
+ */
 static void ehci_quiesce (struct ehci_hcd *ehci)
 static void ehci_quiesce (struct ehci_hcd *ehci)
 {
 {
 	u32	temp;
 	u32	temp;
 
 
-#ifdef DEBUG
 	if (ehci->rh_state != EHCI_RH_RUNNING)
 	if (ehci->rh_state != EHCI_RH_RUNNING)
-		BUG ();
-#endif
+		return;
 
 
 	/* wait for any schedule enables/disables to take effect */
 	/* wait for any schedule enables/disables to take effect */
 	temp = (ehci->command << 10) & (STS_ASS | STS_PSS);
 	temp = (ehci->command << 10) & (STS_ASS | STS_PSS);
-	if (handshake_on_error_set_halt(ehci, &ehci->regs->status,
-					STS_ASS | STS_PSS, temp, 16 * 125))
-		return;
+	handshake(ehci, &ehci->regs->status, STS_ASS | STS_PSS, temp, 16 * 125);
 
 
 	/* then disable anything that's still active */
 	/* then disable anything that's still active */
+	spin_lock_irq(&ehci->lock);
 	ehci->command &= ~(CMD_ASE | CMD_PSE);
 	ehci->command &= ~(CMD_ASE | CMD_PSE);
 	ehci_writel(ehci, ehci->command, &ehci->regs->command);
 	ehci_writel(ehci, ehci->command, &ehci->regs->command);
+	spin_unlock_irq(&ehci->lock);
 
 
 	/* hardware can take 16 microframes to turn off ... */
 	/* hardware can take 16 microframes to turn off ... */
-	handshake_on_error_set_halt(ehci, &ehci->regs->status,
-				    STS_ASS | STS_PSS, 0, 16 * 125);
+	handshake(ehci, &ehci->regs->status, STS_ASS | STS_PSS, 0, 16 * 125);
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 static void end_unlink_async(struct ehci_hcd *ehci);
 static void end_unlink_async(struct ehci_hcd *ehci);
+static void unlink_empty_async(struct ehci_hcd *ehci);
 static void ehci_work(struct ehci_hcd *ehci);
 static void ehci_work(struct ehci_hcd *ehci);
+static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh);
+static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh);
 
 
+#include "ehci-timer.c"
 #include "ehci-hub.c"
 #include "ehci-hub.c"
 #include "ehci-lpm.c"
 #include "ehci-lpm.c"
 #include "ehci-mem.c"
 #include "ehci-mem.c"
@@ -396,68 +301,6 @@ static void ehci_work(struct ehci_hcd *ehci);
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-static void ehci_iaa_watchdog(unsigned long param)
-{
-	struct ehci_hcd		*ehci = (struct ehci_hcd *) param;
-	unsigned long		flags;
-
-	spin_lock_irqsave (&ehci->lock, flags);
-
-	/* Lost IAA irqs wedge things badly; seen first with a vt8235.
-	 * So we need this watchdog, but must protect it against both
-	 * (a) SMP races against real IAA firing and retriggering, and
-	 * (b) clean HC shutdown, when IAA watchdog was pending.
-	 */
-	if (ehci->reclaim
-			&& !timer_pending(&ehci->iaa_watchdog)
-			&& ehci->rh_state == EHCI_RH_RUNNING) {
-		u32 cmd, status;
-
-		/* If we get here, IAA is *REALLY* late.  It's barely
-		 * conceivable that the system is so busy that CMD_IAAD
-		 * is still legitimately set, so let's be sure it's
-		 * clear before we read STS_IAA.  (The HC should clear
-		 * CMD_IAAD when it sets STS_IAA.)
-		 */
-		cmd = ehci_readl(ehci, &ehci->regs->command);
-
-		/* If IAA is set here it either legitimately triggered
-		 * before we cleared IAAD above (but _way_ late, so we'll
-		 * still count it as lost) ... or a silicon erratum:
-		 * - VIA seems to set IAA without triggering the IRQ;
-		 * - IAAD potentially cleared without setting IAA.
-		 */
-		status = ehci_readl(ehci, &ehci->regs->status);
-		if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
-			COUNT (ehci->stats.lost_iaa);
-			ehci_writel(ehci, STS_IAA, &ehci->regs->status);
-		}
-
-		ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n",
-				status, cmd);
-		end_unlink_async(ehci);
-	}
-
-	spin_unlock_irqrestore(&ehci->lock, flags);
-}
-
-static void ehci_watchdog(unsigned long param)
-{
-	struct ehci_hcd		*ehci = (struct ehci_hcd *) param;
-	unsigned long		flags;
-
-	spin_lock_irqsave(&ehci->lock, flags);
-
-	/* stop async processing after it's idled a bit */
-	if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
-		start_unlink_async (ehci, ehci->async);
-
-	/* ehci could run by timer, without IRQs ... */
-	ehci_work (ehci);
-
-	spin_unlock_irqrestore (&ehci->lock, flags);
-}
-
 /* On some systems, leaving remote wakeup enabled prevents system shutdown.
 /* On some systems, leaving remote wakeup enabled prevents system shutdown.
  * The firmware seems to think that powering off is a wakeup event!
  * The firmware seems to think that powering off is a wakeup event!
  * This routine turns off remote wakeup and everything else, on all ports.
  * This routine turns off remote wakeup and everything else, on all ports.
@@ -473,11 +316,14 @@ static void ehci_turn_off_all_ports(struct ehci_hcd *ehci)
 
 
 /*
 /*
  * Halt HC, turn off all ports, and let the BIOS use the companion controllers.
  * Halt HC, turn off all ports, and let the BIOS use the companion controllers.
- * Should be called with ehci->lock held.
+ * Must be called with interrupts enabled and the lock not held.
  */
  */
 static void ehci_silence_controller(struct ehci_hcd *ehci)
 static void ehci_silence_controller(struct ehci_hcd *ehci)
 {
 {
 	ehci_halt(ehci);
 	ehci_halt(ehci);
+
+	spin_lock_irq(&ehci->lock);
+	ehci->rh_state = EHCI_RH_HALTED;
 	ehci_turn_off_all_ports(ehci);
 	ehci_turn_off_all_ports(ehci);
 
 
 	/* make BIOS/etc use companion controller during reboot */
 	/* make BIOS/etc use companion controller during reboot */
@@ -485,6 +331,7 @@ static void ehci_silence_controller(struct ehci_hcd *ehci)
 
 
 	/* unblock posted writes */
 	/* unblock posted writes */
 	ehci_readl(ehci, &ehci->regs->configured_flag);
 	ehci_readl(ehci, &ehci->regs->configured_flag);
+	spin_unlock_irq(&ehci->lock);
 }
 }
 
 
 /* ehci_shutdown kick in for silicon on any bus (not just pci, etc).
 /* ehci_shutdown kick in for silicon on any bus (not just pci, etc).
@@ -495,12 +342,15 @@ static void ehci_shutdown(struct usb_hcd *hcd)
 {
 {
 	struct ehci_hcd	*ehci = hcd_to_ehci(hcd);
 	struct ehci_hcd	*ehci = hcd_to_ehci(hcd);
 
 
-	del_timer_sync(&ehci->watchdog);
-	del_timer_sync(&ehci->iaa_watchdog);
-
 	spin_lock_irq(&ehci->lock);
 	spin_lock_irq(&ehci->lock);
-	ehci_silence_controller(ehci);
+	ehci->shutdown = true;
+	ehci->rh_state = EHCI_RH_STOPPING;
+	ehci->enabled_hrtimer_events = 0;
 	spin_unlock_irq(&ehci->lock);
 	spin_unlock_irq(&ehci->lock);
+
+	ehci_silence_controller(ehci);
+
+	hrtimer_cancel(&ehci->hrtimer);
 }
 }
 
 
 static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
 static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
@@ -529,28 +379,33 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
  */
  */
 static void ehci_work (struct ehci_hcd *ehci)
 static void ehci_work (struct ehci_hcd *ehci)
 {
 {
-	timer_action_done (ehci, TIMER_IO_WATCHDOG);
-
 	/* another CPU may drop ehci->lock during a schedule scan while
 	/* another CPU may drop ehci->lock during a schedule scan while
 	 * it reports urb completions.  this flag guards against bogus
 	 * it reports urb completions.  this flag guards against bogus
 	 * attempts at re-entrant schedule scanning.
 	 * attempts at re-entrant schedule scanning.
 	 */
 	 */
-	if (ehci->scanning)
+	if (ehci->scanning) {
+		ehci->need_rescan = true;
 		return;
 		return;
-	ehci->scanning = 1;
-	scan_async (ehci);
-	if (ehci->next_uframe != -1)
-		scan_periodic (ehci);
-	ehci->scanning = 0;
+	}
+	ehci->scanning = true;
+
+ rescan:
+	ehci->need_rescan = false;
+	if (ehci->async_count)
+		scan_async(ehci);
+	if (ehci->intr_count > 0)
+		scan_intr(ehci);
+	if (ehci->isoc_count > 0)
+		scan_isoc(ehci);
+	if (ehci->need_rescan)
+		goto rescan;
+	ehci->scanning = false;
 
 
 	/* the IO watchdog guards against hardware or driver bugs that
 	/* the IO watchdog guards against hardware or driver bugs that
 	 * misplace IRQs, and should let us run completely without IRQs.
 	 * misplace IRQs, and should let us run completely without IRQs.
 	 * such lossage has been observed on both VT6202 and VT8235.
 	 * such lossage has been observed on both VT6202 and VT8235.
 	 */
 	 */
-	if (ehci->rh_state == EHCI_RH_RUNNING &&
-			(ehci->async->qh_next.ptr != NULL ||
-			 ehci->periodic_sched != 0))
-		timer_action (ehci, TIMER_IO_WATCHDOG);
+	turn_on_io_watchdog(ehci);
 }
 }
 
 
 /*
 /*
@@ -563,24 +418,22 @@ static void ehci_stop (struct usb_hcd *hcd)
 	ehci_dbg (ehci, "stop\n");
 	ehci_dbg (ehci, "stop\n");
 
 
 	/* no more interrupts ... */
 	/* no more interrupts ... */
-	del_timer_sync (&ehci->watchdog);
-	del_timer_sync(&ehci->iaa_watchdog);
 
 
 	spin_lock_irq(&ehci->lock);
 	spin_lock_irq(&ehci->lock);
-	if (ehci->rh_state == EHCI_RH_RUNNING)
-		ehci_quiesce (ehci);
+	ehci->enabled_hrtimer_events = 0;
+	spin_unlock_irq(&ehci->lock);
 
 
+	ehci_quiesce(ehci);
 	ehci_silence_controller(ehci);
 	ehci_silence_controller(ehci);
 	ehci_reset (ehci);
 	ehci_reset (ehci);
-	spin_unlock_irq(&ehci->lock);
 
 
+	hrtimer_cancel(&ehci->hrtimer);
 	remove_sysfs_files(ehci);
 	remove_sysfs_files(ehci);
 	remove_debug_files (ehci);
 	remove_debug_files (ehci);
 
 
 	/* root hub is shut down separately (first, when possible) */
 	/* root hub is shut down separately (first, when possible) */
 	spin_lock_irq (&ehci->lock);
 	spin_lock_irq (&ehci->lock);
-	if (ehci->async)
-		ehci_work (ehci);
+	end_free_itds(ehci);
 	spin_unlock_irq (&ehci->lock);
 	spin_unlock_irq (&ehci->lock);
 	ehci_mem_cleanup (ehci);
 	ehci_mem_cleanup (ehci);
 
 
@@ -588,8 +441,8 @@ static void ehci_stop (struct usb_hcd *hcd)
 		usb_amd_dev_put();
 		usb_amd_dev_put();
 
 
 #ifdef	EHCI_STATS
 #ifdef	EHCI_STATS
-	ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n",
-		ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,
+	ehci_dbg(ehci, "irq normal %ld err %ld iaa %ld (lost %ld)\n",
+		ehci->stats.normal, ehci->stats.error, ehci->stats.iaa,
 		ehci->stats.lost_iaa);
 		ehci->stats.lost_iaa);
 	ehci_dbg (ehci, "complete %ld unlink %ld\n",
 	ehci_dbg (ehci, "complete %ld unlink %ld\n",
 		ehci->stats.complete, ehci->stats.unlink);
 		ehci->stats.complete, ehci->stats.unlink);
@@ -614,13 +467,10 @@ static int ehci_init(struct usb_hcd *hcd)
 	 * keep io watchdog by default, those good HCDs could turn off it later
 	 * keep io watchdog by default, those good HCDs could turn off it later
 	 */
 	 */
 	ehci->need_io_watchdog = 1;
 	ehci->need_io_watchdog = 1;
-	init_timer(&ehci->watchdog);
-	ehci->watchdog.function = ehci_watchdog;
-	ehci->watchdog.data = (unsigned long) ehci;
 
 
-	init_timer(&ehci->iaa_watchdog);
-	ehci->iaa_watchdog.function = ehci_iaa_watchdog;
-	ehci->iaa_watchdog.data = (unsigned long) ehci;
+	hrtimer_init(&ehci->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+	ehci->hrtimer.function = ehci_hrtimer_func;
+	ehci->next_hrtimer_event = EHCI_HRTIMER_NO_EVENT;
 
 
 	hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
 	hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
 
 
@@ -635,6 +485,7 @@ static int ehci_init(struct usb_hcd *hcd)
 	 * periodic_size can shrink by USBCMD update if hcc_params allows.
 	 * periodic_size can shrink by USBCMD update if hcc_params allows.
 	 */
 	 */
 	ehci->periodic_size = DEFAULT_I_TDPS;
 	ehci->periodic_size = DEFAULT_I_TDPS;
+	INIT_LIST_HEAD(&ehci->intr_qh_list);
 	INIT_LIST_HEAD(&ehci->cached_itd_list);
 	INIT_LIST_HEAD(&ehci->cached_itd_list);
 	INIT_LIST_HEAD(&ehci->cached_sitd_list);
 	INIT_LIST_HEAD(&ehci->cached_sitd_list);
 
 
@@ -656,10 +507,6 @@ static int ehci_init(struct usb_hcd *hcd)
 	else					// N microframes cached
 	else					// N microframes cached
 		ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
 		ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
 
 
-	ehci->reclaim = NULL;
-	ehci->next_uframe = -1;
-	ehci->clock_frame = -1;
-
 	/*
 	/*
 	 * dedicate a qh for the async ring head, since we couldn't unlink
 	 * dedicate a qh for the async ring head, since we couldn't unlink
 	 * a 'real' qh without stopping the async schedule [4.8].  use it
 	 * a 'real' qh without stopping the async schedule [4.8].  use it
@@ -672,7 +519,7 @@ static int ehci_init(struct usb_hcd *hcd)
 	hw->hw_next = QH_NEXT(ehci, ehci->async->qh_dma);
 	hw->hw_next = QH_NEXT(ehci, ehci->async->qh_dma);
 	hw->hw_info1 = cpu_to_hc32(ehci, QH_HEAD);
 	hw->hw_info1 = cpu_to_hc32(ehci, QH_HEAD);
 #if defined(CONFIG_PPC_PS3)
 #if defined(CONFIG_PPC_PS3)
-	hw->hw_info1 |= cpu_to_hc32(ehci, (1 << 7));	/* I = 1 */
+	hw->hw_info1 |= cpu_to_hc32(ehci, QH_INACTIVATE);
 #endif
 #endif
 	hw->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
 	hw->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
 	hw->hw_qtd_next = EHCI_LIST_END(ehci);
 	hw->hw_qtd_next = EHCI_LIST_END(ehci);
@@ -813,7 +660,7 @@ static int ehci_run (struct usb_hcd *hcd)
 	return 0;
 	return 0;
 }
 }
 
 
-static int __maybe_unused ehci_setup (struct usb_hcd *hcd)
+static int ehci_setup(struct usb_hcd *hcd)
 {
 {
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	int retval;
 	int retval;
@@ -828,15 +675,18 @@ static int __maybe_unused ehci_setup (struct usb_hcd *hcd)
 
 
 	ehci->sbrn = HCD_USB2;
 	ehci->sbrn = HCD_USB2;
 
 
-	retval = ehci_halt(ehci);
+	/* data structure init */
+	retval = ehci_init(hcd);
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 
 
-	/* data structure init */
-	retval = ehci_init(hcd);
+	retval = ehci_halt(ehci);
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 
 
+	if (ehci_is_TDI(ehci))
+		tdi_reset(ehci);
+
 	ehci_reset(ehci);
 	ehci_reset(ehci);
 
 
 	return 0;
 	return 0;
@@ -895,14 +745,28 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 
 
 	/* complete the unlinking of some qh [4.15.2.3] */
 	/* complete the unlinking of some qh [4.15.2.3] */
 	if (status & STS_IAA) {
 	if (status & STS_IAA) {
+
+		/* Turn off the IAA watchdog */
+		ehci->enabled_hrtimer_events &= ~BIT(EHCI_HRTIMER_IAA_WATCHDOG);
+
+		/*
+		 * Mild optimization: Allow another IAAD to reset the
+		 * hrtimer, if one occurs before the next expiration.
+		 * In theory we could always cancel the hrtimer, but
+		 * tests show that about half the time it will be reset
+		 * for some other event anyway.
+		 */
+		if (ehci->next_hrtimer_event == EHCI_HRTIMER_IAA_WATCHDOG)
+			++ehci->next_hrtimer_event;
+
 		/* guard against (alleged) silicon errata */
 		/* guard against (alleged) silicon errata */
 		if (cmd & CMD_IAAD)
 		if (cmd & CMD_IAAD)
 			ehci_dbg(ehci, "IAA with IAAD still set?\n");
 			ehci_dbg(ehci, "IAA with IAAD still set?\n");
-		if (ehci->reclaim) {
-			COUNT(ehci->stats.reclaim);
+		if (ehci->async_iaa) {
+			COUNT(ehci->stats.iaa);
 			end_unlink_async(ehci);
 			end_unlink_async(ehci);
 		} else
 		} else
-			ehci_dbg(ehci, "IAA with nothing to reclaim?\n");
+			ehci_dbg(ehci, "IAA with nothing unlinked?\n");
 	}
 	}
 
 
 	/* remote wakeup [4.3.1] */
 	/* remote wakeup [4.3.1] */
@@ -956,15 +820,19 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 		ehci_err(ehci, "fatal error\n");
 		ehci_err(ehci, "fatal error\n");
 		dbg_cmd(ehci, "fatal", cmd);
 		dbg_cmd(ehci, "fatal", cmd);
 		dbg_status(ehci, "fatal", status);
 		dbg_status(ehci, "fatal", status);
-		ehci_halt(ehci);
 dead:
 dead:
-		ehci_reset(ehci);
-		ehci_writel(ehci, 0, &ehci->regs->configured_flag);
 		usb_hc_died(hcd);
 		usb_hc_died(hcd);
-		/* generic layer kills/unlinks all urbs, then
-		 * uses ehci_stop to clean up the rest
-		 */
-		bh = 1;
+
+		/* Don't let the controller do anything more */
+		ehci->shutdown = true;
+		ehci->rh_state = EHCI_RH_STOPPING;
+		ehci->command &= ~(CMD_RUN | CMD_ASE | CMD_PSE);
+		ehci_writel(ehci, ehci->command, &ehci->regs->command);
+		ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+		ehci_handle_controller_death(ehci);
+
+		/* Handle completions when the controller stops */
+		bh = 0;
 	}
 	}
 
 
 	if (bh)
 	if (bh)
@@ -1026,38 +894,6 @@ static int ehci_urb_enqueue (
 	}
 	}
 }
 }
 
 
-static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
-{
-	/* failfast */
-	if (ehci->rh_state != EHCI_RH_RUNNING && ehci->reclaim)
-		end_unlink_async(ehci);
-
-	/* If the QH isn't linked then there's nothing we can do
-	 * unless we were called during a giveback, in which case
-	 * qh_completions() has to deal with it.
-	 */
-	if (qh->qh_state != QH_STATE_LINKED) {
-		if (qh->qh_state == QH_STATE_COMPLETING)
-			qh->needs_rescan = 1;
-		return;
-	}
-
-	/* defer till later if busy */
-	if (ehci->reclaim) {
-		struct ehci_qh		*last;
-
-		for (last = ehci->reclaim;
-				last->reclaim;
-				last = last->reclaim)
-			continue;
-		qh->qh_state = QH_STATE_UNLINK_WAIT;
-		last->reclaim = qh;
-
-	/* start IAA cycle */
-	} else
-		start_unlink_async (ehci, qh);
-}
-
 /* remove from hardware lists
 /* remove from hardware lists
  * completions normally happen asynchronously
  * completions normally happen asynchronously
  */
  */
@@ -1084,7 +920,7 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 		switch (qh->qh_state) {
 		switch (qh->qh_state) {
 		case QH_STATE_LINKED:
 		case QH_STATE_LINKED:
 		case QH_STATE_COMPLETING:
 		case QH_STATE_COMPLETING:
-			unlink_async(ehci, qh);
+			start_unlink_async(ehci, qh);
 			break;
 			break;
 		case QH_STATE_UNLINK:
 		case QH_STATE_UNLINK:
 		case QH_STATE_UNLINK_WAIT:
 		case QH_STATE_UNLINK_WAIT:
@@ -1104,7 +940,7 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 		switch (qh->qh_state) {
 		switch (qh->qh_state) {
 		case QH_STATE_LINKED:
 		case QH_STATE_LINKED:
 		case QH_STATE_COMPLETING:
 		case QH_STATE_COMPLETING:
-			intr_deschedule (ehci, qh);
+			start_unlink_intr(ehci, qh);
 			break;
 			break;
 		case QH_STATE_IDLE:
 		case QH_STATE_IDLE:
 			qh_completions (ehci, qh);
 			qh_completions (ehci, qh);
@@ -1152,11 +988,17 @@ rescan:
 	 * accelerate iso completions ... so spin a while.
 	 * accelerate iso completions ... so spin a while.
 	 */
 	 */
 	if (qh->hw == NULL) {
 	if (qh->hw == NULL) {
-		ehci_vdbg (ehci, "iso delay\n");
-		goto idle_timeout;
+		struct ehci_iso_stream	*stream = ep->hcpriv;
+
+		if (!list_empty(&stream->td_list))
+			goto idle_timeout;
+
+		/* BUG_ON(!list_empty(&stream->free_list)); */
+		kfree(stream);
+		goto done;
 	}
 	}
 
 
-	if (ehci->rh_state != EHCI_RH_RUNNING)
+	if (ehci->rh_state < EHCI_RH_RUNNING)
 		qh->qh_state = QH_STATE_IDLE;
 		qh->qh_state = QH_STATE_IDLE;
 	switch (qh->qh_state) {
 	switch (qh->qh_state) {
 	case QH_STATE_LINKED:
 	case QH_STATE_LINKED:
@@ -1169,7 +1011,7 @@ rescan:
 		 * may already be unlinked.
 		 * may already be unlinked.
 		 */
 		 */
 		if (tmp)
 		if (tmp)
-			unlink_async(ehci, qh);
+			start_unlink_async(ehci, qh);
 		/* FALL THROUGH */
 		/* FALL THROUGH */
 	case QH_STATE_UNLINK:		/* wait for hw to finish? */
 	case QH_STATE_UNLINK:		/* wait for hw to finish? */
 	case QH_STATE_UNLINK_WAIT:
 	case QH_STATE_UNLINK_WAIT:
@@ -1181,7 +1023,7 @@ idle_timeout:
 		if (qh->clearing_tt)
 		if (qh->clearing_tt)
 			goto idle_timeout;
 			goto idle_timeout;
 		if (list_empty (&qh->qtd_list)) {
 		if (list_empty (&qh->qtd_list)) {
-			qh_put (qh);
+			qh_destroy(ehci, qh);
 			break;
 			break;
 		}
 		}
 		/* else FALL THROUGH */
 		/* else FALL THROUGH */
@@ -1194,8 +1036,8 @@ idle_timeout:
 			list_empty (&qh->qtd_list) ? "" : "(has tds)");
 			list_empty (&qh->qtd_list) ? "" : "(has tds)");
 		break;
 		break;
 	}
 	}
+ done:
 	ep->hcpriv = NULL;
 	ep->hcpriv = NULL;
-done:
 	spin_unlock_irqrestore (&ehci->lock, flags);
 	spin_unlock_irqrestore (&ehci->lock, flags);
 }
 }
 
 
@@ -1232,9 +1074,9 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
 			 * re-linking will call qh_refresh().
 			 * re-linking will call qh_refresh().
 			 */
 			 */
 			if (eptype == USB_ENDPOINT_XFER_BULK)
 			if (eptype == USB_ENDPOINT_XFER_BULK)
-				unlink_async(ehci, qh);
+				start_unlink_async(ehci, qh);
 			else
 			else
-				intr_deschedule(ehci, qh);
+				start_unlink_intr(ehci, qh);
 		}
 		}
 	}
 	}
 	spin_unlock_irqrestore(&ehci->lock, flags);
 	spin_unlock_irqrestore(&ehci->lock, flags);
@@ -1247,6 +1089,104 @@ static int ehci_get_frame (struct usb_hcd *hcd)
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
+
+#ifdef	CONFIG_PM
+
+/* suspend/resume, section 4.3 */
+
+/* These routines handle the generic parts of controller suspend/resume */
+
+static int __maybe_unused ehci_suspend(struct usb_hcd *hcd, bool do_wakeup)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
+
+	if (time_before(jiffies, ehci->next_statechange))
+		msleep(10);
+
+	/*
+	 * Root hub was already suspended.  Disable IRQ emission and
+	 * mark HW unaccessible.  The PM and USB cores make sure that
+	 * the root hub is either suspended or stopped.
+	 */
+	ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup);
+
+	spin_lock_irq(&ehci->lock);
+	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+	(void) ehci_readl(ehci, &ehci->regs->intr_enable);
+
+	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+	spin_unlock_irq(&ehci->lock);
+
+	return 0;
+}
+
+/* Returns 0 if power was preserved, 1 if power was lost */
+static int __maybe_unused ehci_resume(struct usb_hcd *hcd, bool hibernated)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
+
+	if (time_before(jiffies, ehci->next_statechange))
+		msleep(100);
+
+	/* Mark hardware accessible again as we are back to full power by now */
+	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+	if (ehci->shutdown)
+		return 0;		/* Controller is dead */
+
+	/*
+	 * If CF is still set and we aren't resuming from hibernation
+	 * then we maintained suspend power.
+	 * Just undo the effect of ehci_suspend().
+	 */
+	if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
+			!hibernated) {
+		int	mask = INTR_MASK;
+
+		ehci_prepare_ports_for_controller_resume(ehci);
+
+		spin_lock_irq(&ehci->lock);
+		if (ehci->shutdown)
+			goto skip;
+
+		if (!hcd->self.root_hub->do_remote_wakeup)
+			mask &= ~STS_PCD;
+		ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+		ehci_readl(ehci, &ehci->regs->intr_enable);
+ skip:
+		spin_unlock_irq(&ehci->lock);
+		return 0;
+	}
+
+	/*
+	 * Else reset, to cope with power loss or resume from hibernation
+	 * having let the firmware kick in during reboot.
+	 */
+	usb_root_hub_lost_power(hcd->self.root_hub);
+	(void) ehci_halt(ehci);
+	(void) ehci_reset(ehci);
+
+	spin_lock_irq(&ehci->lock);
+	if (ehci->shutdown)
+		goto skip;
+
+	ehci_writel(ehci, ehci->command, &ehci->regs->command);
+	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
+
+	ehci->rh_state = EHCI_RH_SUSPENDED;
+	spin_unlock_irq(&ehci->lock);
+
+	/* here we "know" root ports should always stay powered */
+	ehci_port_power(ehci, 1);
+
+	return 1;
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
 /*
 /*
  * The EHCI in ChipIdea HDRC cannot be a separate module or device,
  * The EHCI in ChipIdea HDRC cannot be a separate module or device,
  * because its registers (and irq) are shared between host/gadget/otg
  * because its registers (and irq) are shared between host/gadget/otg

+ 71 - 58
drivers/usb/host/ehci-hub.c

@@ -59,6 +59,7 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
 	/* Give the connections some time to appear */
 	/* Give the connections some time to appear */
 	msleep(20);
 	msleep(20);
 
 
+	spin_lock_irq(&ehci->lock);
 	port = HCS_N_PORTS(ehci->hcs_params);
 	port = HCS_N_PORTS(ehci->hcs_params);
 	while (port--) {
 	while (port--) {
 		if (test_bit(port, &ehci->owned_ports)) {
 		if (test_bit(port, &ehci->owned_ports)) {
@@ -70,23 +71,30 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
 				clear_bit(port, &ehci->owned_ports);
 				clear_bit(port, &ehci->owned_ports);
 			else if (test_bit(port, &ehci->companion_ports))
 			else if (test_bit(port, &ehci->companion_ports))
 				ehci_writel(ehci, status & ~PORT_PE, reg);
 				ehci_writel(ehci, status & ~PORT_PE, reg);
-			else
+			else {
+				spin_unlock_irq(&ehci->lock);
 				ehci_hub_control(hcd, SetPortFeature,
 				ehci_hub_control(hcd, SetPortFeature,
 						USB_PORT_FEAT_RESET, port + 1,
 						USB_PORT_FEAT_RESET, port + 1,
 						NULL, 0);
 						NULL, 0);
+				spin_lock_irq(&ehci->lock);
+			}
 		}
 		}
 	}
 	}
+	spin_unlock_irq(&ehci->lock);
 
 
 	if (!ehci->owned_ports)
 	if (!ehci->owned_ports)
 		return;
 		return;
 	msleep(90);		/* Wait for resets to complete */
 	msleep(90);		/* Wait for resets to complete */
 
 
+	spin_lock_irq(&ehci->lock);
 	port = HCS_N_PORTS(ehci->hcs_params);
 	port = HCS_N_PORTS(ehci->hcs_params);
 	while (port--) {
 	while (port--) {
 		if (test_bit(port, &ehci->owned_ports)) {
 		if (test_bit(port, &ehci->owned_ports)) {
+			spin_unlock_irq(&ehci->lock);
 			ehci_hub_control(hcd, GetPortStatus,
 			ehci_hub_control(hcd, GetPortStatus,
 					0, port + 1,
 					0, port + 1,
 					(char *) &buf, sizeof(buf));
 					(char *) &buf, sizeof(buf));
+			spin_lock_irq(&ehci->lock);
 
 
 			/* The companion should now own the port,
 			/* The companion should now own the port,
 			 * but if something went wrong the port must not
 			 * but if something went wrong the port must not
@@ -105,9 +113,10 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
 	}
 	}
 
 
 	ehci->owned_ports = 0;
 	ehci->owned_ports = 0;
+	spin_unlock_irq(&ehci->lock);
 }
 }
 
 
-static int __maybe_unused ehci_port_change(struct ehci_hcd *ehci)
+static int ehci_port_change(struct ehci_hcd *ehci)
 {
 {
 	int i = HCS_N_PORTS(ehci->hcs_params);
 	int i = HCS_N_PORTS(ehci->hcs_params);
 
 
@@ -128,12 +137,11 @@ static int __maybe_unused ehci_port_change(struct ehci_hcd *ehci)
 	return 0;
 	return 0;
 }
 }
 
 
-static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
+static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
 		bool suspending, bool do_wakeup)
 		bool suspending, bool do_wakeup)
 {
 {
 	int		port;
 	int		port;
 	u32		temp;
 	u32		temp;
-	unsigned long	flags;
 
 
 	/* If remote wakeup is enabled for the root hub but disabled
 	/* If remote wakeup is enabled for the root hub but disabled
 	 * for the controller, we must adjust all the port wakeup flags
 	 * for the controller, we must adjust all the port wakeup flags
@@ -143,22 +151,20 @@ static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
 	if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup)
 	if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup)
 		return;
 		return;
 
 
-	spin_lock_irqsave(&ehci->lock, flags);
+	spin_lock_irq(&ehci->lock);
 
 
 	/* clear phy low-power mode before changing wakeup flags */
 	/* clear phy low-power mode before changing wakeup flags */
 	if (ehci->has_hostpc) {
 	if (ehci->has_hostpc) {
 		port = HCS_N_PORTS(ehci->hcs_params);
 		port = HCS_N_PORTS(ehci->hcs_params);
 		while (port--) {
 		while (port--) {
-			u32 __iomem	*hostpc_reg;
+			u32 __iomem	*hostpc_reg = &ehci->regs->hostpc[port];
 
 
-			hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
-					+ HOSTPC0 + 4 * port);
 			temp = ehci_readl(ehci, hostpc_reg);
 			temp = ehci_readl(ehci, hostpc_reg);
 			ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg);
 			ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg);
 		}
 		}
-		spin_unlock_irqrestore(&ehci->lock, flags);
+		spin_unlock_irq(&ehci->lock);
 		msleep(5);
 		msleep(5);
-		spin_lock_irqsave(&ehci->lock, flags);
+		spin_lock_irq(&ehci->lock);
 	}
 	}
 
 
 	port = HCS_N_PORTS(ehci->hcs_params);
 	port = HCS_N_PORTS(ehci->hcs_params);
@@ -185,10 +191,8 @@ static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
 	if (ehci->has_hostpc) {
 	if (ehci->has_hostpc) {
 		port = HCS_N_PORTS(ehci->hcs_params);
 		port = HCS_N_PORTS(ehci->hcs_params);
 		while (port--) {
 		while (port--) {
-			u32 __iomem	*hostpc_reg;
+			u32 __iomem	*hostpc_reg = &ehci->regs->hostpc[port];
 
 
-			hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
-					+ HOSTPC0 + 4 * port);
 			temp = ehci_readl(ehci, hostpc_reg);
 			temp = ehci_readl(ehci, hostpc_reg);
 			ehci_writel(ehci, temp | HOSTPC_PHCD, hostpc_reg);
 			ehci_writel(ehci, temp | HOSTPC_PHCD, hostpc_reg);
 		}
 		}
@@ -198,7 +202,7 @@ static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
 	if (!suspending && ehci_port_change(ehci))
 	if (!suspending && ehci_port_change(ehci))
 		usb_hcd_resume_root_hub(ehci_to_hcd(ehci));
 		usb_hcd_resume_root_hub(ehci_to_hcd(ehci));
 
 
-	spin_unlock_irqrestore(&ehci->lock, flags);
+	spin_unlock_irq(&ehci->lock);
 }
 }
 
 
 static int ehci_bus_suspend (struct usb_hcd *hcd)
 static int ehci_bus_suspend (struct usb_hcd *hcd)
@@ -212,10 +216,13 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
 
 
 	if (time_before (jiffies, ehci->next_statechange))
 	if (time_before (jiffies, ehci->next_statechange))
 		msleep(5);
 		msleep(5);
-	del_timer_sync(&ehci->watchdog);
-	del_timer_sync(&ehci->iaa_watchdog);
+
+	/* stop the schedules */
+	ehci_quiesce(ehci);
 
 
 	spin_lock_irq (&ehci->lock);
 	spin_lock_irq (&ehci->lock);
+	if (ehci->rh_state < EHCI_RH_RUNNING)
+		goto done;
 
 
 	/* Once the controller is stopped, port resumes that are already
 	/* Once the controller is stopped, port resumes that are already
 	 * in progress won't complete.  Hence if remote wakeup is enabled
 	 * in progress won't complete.  Hence if remote wakeup is enabled
@@ -230,11 +237,6 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
 		}
 		}
 	}
 	}
 
 
-	/* stop schedules, clean any completed work */
-	if (ehci->rh_state == EHCI_RH_RUNNING)
-		ehci_quiesce (ehci);
-	ehci_work(ehci);
-
 	/* Unlike other USB host controller types, EHCI doesn't have
 	/* Unlike other USB host controller types, EHCI doesn't have
 	 * any notion of "global" or bus-wide suspend.  The driver has
 	 * any notion of "global" or bus-wide suspend.  The driver has
 	 * to manually suspend all the active unsuspended ports, and
 	 * to manually suspend all the active unsuspended ports, and
@@ -285,11 +287,9 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
 
 
 		port = HCS_N_PORTS(ehci->hcs_params);
 		port = HCS_N_PORTS(ehci->hcs_params);
 		while (port--) {
 		while (port--) {
-			u32 __iomem	*hostpc_reg;
+			u32 __iomem	*hostpc_reg = &ehci->regs->hostpc[port];
 			u32		t3;
 			u32		t3;
 
 
-			hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
-					+ HOSTPC0 + 4 * port);
 			t3 = ehci_readl(ehci, hostpc_reg);
 			t3 = ehci_readl(ehci, hostpc_reg);
 			ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
 			ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
 			t3 = ehci_readl(ehci, hostpc_reg);
 			t3 = ehci_readl(ehci, hostpc_reg);
@@ -298,6 +298,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
 					"succeeded" : "failed");
 					"succeeded" : "failed");
 		}
 		}
 	}
 	}
+	spin_unlock_irq(&ehci->lock);
 
 
 	/* Apparently some devices need a >= 1-uframe delay here */
 	/* Apparently some devices need a >= 1-uframe delay here */
 	if (ehci->bus_suspended)
 	if (ehci->bus_suspended)
@@ -305,10 +306,18 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
 
 
 	/* turn off now-idle HC */
 	/* turn off now-idle HC */
 	ehci_halt (ehci);
 	ehci_halt (ehci);
+
+	spin_lock_irq(&ehci->lock);
+	if (ehci->enabled_hrtimer_events & BIT(EHCI_HRTIMER_POLL_DEAD))
+		ehci_handle_controller_death(ehci);
+	if (ehci->rh_state != EHCI_RH_RUNNING)
+		goto done;
 	ehci->rh_state = EHCI_RH_SUSPENDED;
 	ehci->rh_state = EHCI_RH_SUSPENDED;
 
 
-	if (ehci->reclaim)
-		end_unlink_async(ehci);
+	end_unlink_async(ehci);
+	unlink_empty_async(ehci);
+	ehci_handle_intr_unlinks(ehci);
+	end_free_itds(ehci);
 
 
 	/* allow remote wakeup */
 	/* allow remote wakeup */
 	mask = INTR_MASK;
 	mask = INTR_MASK;
@@ -317,13 +326,13 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
 	ehci_writel(ehci, mask, &ehci->regs->intr_enable);
 	ehci_writel(ehci, mask, &ehci->regs->intr_enable);
 	ehci_readl(ehci, &ehci->regs->intr_enable);
 	ehci_readl(ehci, &ehci->regs->intr_enable);
 
 
+ done:
 	ehci->next_statechange = jiffies + msecs_to_jiffies(10);
 	ehci->next_statechange = jiffies + msecs_to_jiffies(10);
+	ehci->enabled_hrtimer_events = 0;
+	ehci->next_hrtimer_event = EHCI_HRTIMER_NO_EVENT;
 	spin_unlock_irq (&ehci->lock);
 	spin_unlock_irq (&ehci->lock);
 
 
-	/* ehci_work() may have re-enabled the watchdog timer, which we do not
-	 * want, and so we must delete any pending watchdog timer events.
-	 */
-	del_timer_sync(&ehci->watchdog);
+	hrtimer_cancel(&ehci->hrtimer);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -340,10 +349,8 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
 	if (time_before (jiffies, ehci->next_statechange))
 	if (time_before (jiffies, ehci->next_statechange))
 		msleep(5);
 		msleep(5);
 	spin_lock_irq (&ehci->lock);
 	spin_lock_irq (&ehci->lock);
-	if (!HCD_HW_ACCESSIBLE(hcd)) {
-		spin_unlock_irq(&ehci->lock);
-		return -ESHUTDOWN;
-	}
+	if (!HCD_HW_ACCESSIBLE(hcd) || ehci->shutdown)
+		goto shutdown;
 
 
 	if (unlikely(ehci->debug)) {
 	if (unlikely(ehci->debug)) {
 		if (!dbgp_reset_prep())
 		if (!dbgp_reset_prep())
@@ -382,16 +389,17 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
 	spin_unlock_irq(&ehci->lock);
 	spin_unlock_irq(&ehci->lock);
 	msleep(8);
 	msleep(8);
 	spin_lock_irq(&ehci->lock);
 	spin_lock_irq(&ehci->lock);
+	if (ehci->shutdown)
+		goto shutdown;
 
 
 	/* clear phy low-power mode before resume */
 	/* clear phy low-power mode before resume */
 	if (ehci->bus_suspended && ehci->has_hostpc) {
 	if (ehci->bus_suspended && ehci->has_hostpc) {
 		i = HCS_N_PORTS(ehci->hcs_params);
 		i = HCS_N_PORTS(ehci->hcs_params);
 		while (i--) {
 		while (i--) {
 			if (test_bit(i, &ehci->bus_suspended)) {
 			if (test_bit(i, &ehci->bus_suspended)) {
-				u32 __iomem	*hostpc_reg;
+				u32 __iomem	*hostpc_reg =
+							&ehci->regs->hostpc[i];
 
 
-				hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
-						+ HOSTPC0 + 4 * i);
 				temp = ehci_readl(ehci, hostpc_reg);
 				temp = ehci_readl(ehci, hostpc_reg);
 				ehci_writel(ehci, temp & ~HOSTPC_PHCD,
 				ehci_writel(ehci, temp & ~HOSTPC_PHCD,
 						hostpc_reg);
 						hostpc_reg);
@@ -400,6 +408,8 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
 		spin_unlock_irq(&ehci->lock);
 		spin_unlock_irq(&ehci->lock);
 		msleep(5);
 		msleep(5);
 		spin_lock_irq(&ehci->lock);
 		spin_lock_irq(&ehci->lock);
+		if (ehci->shutdown)
+			goto shutdown;
 	}
 	}
 
 
 	/* manually resume the ports we suspended during bus_suspend() */
 	/* manually resume the ports we suspended during bus_suspend() */
@@ -420,6 +430,8 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
 		spin_unlock_irq(&ehci->lock);
 		spin_unlock_irq(&ehci->lock);
 		msleep(20);
 		msleep(20);
 		spin_lock_irq(&ehci->lock);
 		spin_lock_irq(&ehci->lock);
+		if (ehci->shutdown)
+			goto shutdown;
 	}
 	}
 
 
 	i = HCS_N_PORTS (ehci->hcs_params);
 	i = HCS_N_PORTS (ehci->hcs_params);
@@ -431,27 +443,25 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
 			ehci_vdbg (ehci, "resumed port %d\n", i + 1);
 			ehci_vdbg (ehci, "resumed port %d\n", i + 1);
 		}
 		}
 	}
 	}
-	(void) ehci_readl(ehci, &ehci->regs->command);
-
-	/* maybe re-activate the schedule(s) */
-	temp = 0;
-	if (ehci->async->qh_next.qh)
-		temp |= CMD_ASE;
-	if (ehci->periodic_sched)
-		temp |= CMD_PSE;
-	if (temp) {
-		ehci->command |= temp;
-		ehci_writel(ehci, ehci->command, &ehci->regs->command);
-	}
 
 
 	ehci->next_statechange = jiffies + msecs_to_jiffies(5);
 	ehci->next_statechange = jiffies + msecs_to_jiffies(5);
+	spin_unlock_irq(&ehci->lock);
+
+	ehci_handover_companion_ports(ehci);
 
 
 	/* Now we can safely re-enable irqs */
 	/* Now we can safely re-enable irqs */
+	spin_lock_irq(&ehci->lock);
+	if (ehci->shutdown)
+		goto shutdown;
 	ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
 	ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
+	(void) ehci_readl(ehci, &ehci->regs->intr_enable);
+	spin_unlock_irq(&ehci->lock);
 
 
-	spin_unlock_irq (&ehci->lock);
-	ehci_handover_companion_ports(ehci);
 	return 0;
 	return 0;
+
+ shutdown:
+	spin_unlock_irq(&ehci->lock);
+	return -ESHUTDOWN;
 }
 }
 
 
 #else
 #else
@@ -667,7 +677,7 @@ static int ehci_hub_control (
 	int		ports = HCS_N_PORTS (ehci->hcs_params);
 	int		ports = HCS_N_PORTS (ehci->hcs_params);
 	u32 __iomem	*status_reg = &ehci->regs->port_status[
 	u32 __iomem	*status_reg = &ehci->regs->port_status[
 				(wIndex & 0xff) - 1];
 				(wIndex & 0xff) - 1];
-	u32 __iomem	*hostpc_reg = NULL;
+	u32 __iomem	*hostpc_reg = &ehci->regs->hostpc[(wIndex & 0xff) - 1];
 	u32		temp, temp1, status;
 	u32		temp, temp1, status;
 	unsigned long	flags;
 	unsigned long	flags;
 	int		retval = 0;
 	int		retval = 0;
@@ -680,9 +690,6 @@ static int ehci_hub_control (
 	 * power, "this is the one", etc.  EHCI spec supports this.
 	 * power, "this is the one", etc.  EHCI spec supports this.
 	 */
 	 */
 
 
-	if (ehci->has_hostpc)
-		hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
-				+ HOSTPC0 + 4 * ((wIndex & 0xff) - 1));
 	spin_lock_irqsave (&ehci->lock, flags);
 	spin_lock_irqsave (&ehci->lock, flags);
 	switch (typeReq) {
 	switch (typeReq) {
 	case ClearHubFeature:
 	case ClearHubFeature:
@@ -724,7 +731,7 @@ static int ehci_hub_control (
 #ifdef CONFIG_USB_OTG
 #ifdef CONFIG_USB_OTG
 			if ((hcd->self.otg_port == (wIndex + 1))
 			if ((hcd->self.otg_port == (wIndex + 1))
 			    && hcd->self.b_hnp_enable) {
 			    && hcd->self.b_hnp_enable) {
-				otg_start_hnp(ehci->transceiver->otg);
+				otg_start_hnp(hcd->phy->otg);
 				break;
 				break;
 			}
 			}
 #endif
 #endif
@@ -734,7 +741,7 @@ static int ehci_hub_control (
 				goto error;
 				goto error;
 
 
 			/* clear phy low-power mode before resume */
 			/* clear phy low-power mode before resume */
-			if (hostpc_reg) {
+			if (ehci->has_hostpc) {
 				temp1 = ehci_readl(ehci, hostpc_reg);
 				temp1 = ehci_readl(ehci, hostpc_reg);
 				ehci_writel(ehci, temp1 & ~HOSTPC_PHCD,
 				ehci_writel(ehci, temp1 & ~HOSTPC_PHCD,
 						hostpc_reg);
 						hostpc_reg);
@@ -984,7 +991,7 @@ static int ehci_hub_control (
 			temp &= ~PORT_WKCONN_E;
 			temp &= ~PORT_WKCONN_E;
 			temp |= PORT_WKDISC_E | PORT_WKOC_E;
 			temp |= PORT_WKDISC_E | PORT_WKOC_E;
 			ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
 			ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
-			if (hostpc_reg) {
+			if (ehci->has_hostpc) {
 				spin_unlock_irqrestore(&ehci->lock, flags);
 				spin_unlock_irqrestore(&ehci->lock, flags);
 				msleep(5);/* 5ms for HCD enter low pwr mode */
 				msleep(5);/* 5ms for HCD enter low pwr mode */
 				spin_lock_irqsave(&ehci->lock, flags);
 				spin_lock_irqsave(&ehci->lock, flags);
@@ -1041,7 +1048,9 @@ static int ehci_hub_control (
 		case USB_PORT_FEAT_TEST:
 		case USB_PORT_FEAT_TEST:
 			if (!selector || selector > 5)
 			if (!selector || selector > 5)
 				goto error;
 				goto error;
+			spin_unlock_irqrestore(&ehci->lock, flags);
 			ehci_quiesce(ehci);
 			ehci_quiesce(ehci);
+			spin_lock_irqsave(&ehci->lock, flags);
 
 
 			/* Put all enabled ports into suspend */
 			/* Put all enabled ports into suspend */
 			while (ports--) {
 			while (ports--) {
@@ -1053,7 +1062,11 @@ static int ehci_hub_control (
 					ehci_writel(ehci, temp | PORT_SUSPEND,
 					ehci_writel(ehci, temp | PORT_SUSPEND,
 							sreg);
 							sreg);
 			}
 			}
+
+			spin_unlock_irqrestore(&ehci->lock, flags);
 			ehci_halt(ehci);
 			ehci_halt(ehci);
+			spin_lock_irqsave(&ehci->lock, flags);
+
 			temp = ehci_readl(ehci, status_reg);
 			temp = ehci_readl(ehci, status_reg);
 			temp |= selector << 16;
 			temp |= selector << 16;
 			ehci_writel(ehci, temp, status_reg);
 			ehci_writel(ehci, temp, status_reg);

+ 1 - 5
drivers/usb/host/ehci-ixp4xx.c

@@ -22,14 +22,10 @@ static int ixp4xx_ehci_init(struct usb_hcd *hcd)
 	ehci->big_endian_mmio = 1;
 	ehci->big_endian_mmio = 1;
 
 
 	ehci->caps = hcd->regs + 0x100;
 	ehci->caps = hcd->regs + 0x100;
-	ehci->regs = hcd->regs + 0x100
-		+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
 
 	hcd->has_tt = 1;
 	hcd->has_tt = 1;
-	ehci_reset(ehci);
 
 
-	retval = ehci_init(hcd);
+	retval = ehci_setup(hcd);
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 
 

+ 3 - 22
drivers/usb/host/ehci-mem.c

@@ -64,10 +64,8 @@ static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
 }
 }
 
 
 
 
-static void qh_destroy(struct ehci_qh *qh)
+static void qh_destroy(struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
 {
-	struct ehci_hcd *ehci = qh->ehci;
-
 	/* clean qtds first, and know this is not linked */
 	/* clean qtds first, and know this is not linked */
 	if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
 	if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
 		ehci_dbg (ehci, "unused qh not empty!\n");
 		ehci_dbg (ehci, "unused qh not empty!\n");
@@ -92,8 +90,6 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
 	if (!qh->hw)
 	if (!qh->hw)
 		goto fail;
 		goto fail;
 	memset(qh->hw, 0, sizeof *qh->hw);
 	memset(qh->hw, 0, sizeof *qh->hw);
-	qh->refcount = 1;
-	qh->ehci = ehci;
 	qh->qh_dma = dma;
 	qh->qh_dma = dma;
 	// INIT_LIST_HEAD (&qh->qh_list);
 	// INIT_LIST_HEAD (&qh->qh_list);
 	INIT_LIST_HEAD (&qh->qtd_list);
 	INIT_LIST_HEAD (&qh->qtd_list);
@@ -113,20 +109,6 @@ fail:
 	return NULL;
 	return NULL;
 }
 }
 
 
-/* to share a qh (cpu threads, or hc) */
-static inline struct ehci_qh *qh_get (struct ehci_qh *qh)
-{
-	WARN_ON(!qh->refcount);
-	qh->refcount++;
-	return qh;
-}
-
-static inline void qh_put (struct ehci_qh *qh)
-{
-	if (!--qh->refcount)
-		qh_destroy(qh);
-}
-
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 /* The queue heads and transfer descriptors are managed from pools tied
 /* The queue heads and transfer descriptors are managed from pools tied
@@ -136,13 +118,12 @@ static inline void qh_put (struct ehci_qh *qh)
 
 
 static void ehci_mem_cleanup (struct ehci_hcd *ehci)
 static void ehci_mem_cleanup (struct ehci_hcd *ehci)
 {
 {
-	free_cached_lists(ehci);
 	if (ehci->async)
 	if (ehci->async)
-		qh_put (ehci->async);
+		qh_destroy(ehci, ehci->async);
 	ehci->async = NULL;
 	ehci->async = NULL;
 
 
 	if (ehci->dummy)
 	if (ehci->dummy)
-		qh_put(ehci->dummy);
+		qh_destroy(ehci, ehci->dummy);
 	ehci->dummy = NULL;
 	ehci->dummy = NULL;
 
 
 	/* DMA consistent memory and pools */
 	/* DMA consistent memory and pools */

+ 7 - 20
drivers/usb/host/ehci-msm.c

@@ -145,8 +145,8 @@ static int ehci_msm_probe(struct platform_device *pdev)
 	 * powering up VBUS, mapping of registers address space and power
 	 * powering up VBUS, mapping of registers address space and power
 	 * management.
 	 * management.
 	 */
 	 */
-	phy = usb_get_transceiver();
-	if (!phy) {
+	phy = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (IS_ERR_OR_NULL(phy)) {
 		dev_err(&pdev->dev, "unable to find transceiver\n");
 		dev_err(&pdev->dev, "unable to find transceiver\n");
 		ret = -ENODEV;
 		ret = -ENODEV;
 		goto unmap;
 		goto unmap;
@@ -169,7 +169,7 @@ static int ehci_msm_probe(struct platform_device *pdev)
 	return 0;
 	return 0;
 
 
 put_transceiver:
 put_transceiver:
-	usb_put_transceiver(phy);
+	usb_put_phy(phy);
 unmap:
 unmap:
 	iounmap(hcd->regs);
 	iounmap(hcd->regs);
 put_hcd:
 put_hcd:
@@ -187,7 +187,7 @@ static int __devexit ehci_msm_remove(struct platform_device *pdev)
 	pm_runtime_set_suspended(&pdev->dev);
 	pm_runtime_set_suspended(&pdev->dev);
 
 
 	otg_set_host(phy->otg, NULL);
 	otg_set_host(phy->otg, NULL);
-	usb_put_transceiver(phy);
+	usb_put_phy(phy);
 
 
 	usb_put_hcd(hcd);
 	usb_put_hcd(hcd);
 
 
@@ -198,24 +198,11 @@ static int __devexit ehci_msm_remove(struct platform_device *pdev)
 static int ehci_msm_pm_suspend(struct device *dev)
 static int ehci_msm_pm_suspend(struct device *dev)
 {
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
-	bool wakeup = device_may_wakeup(dev);
+	bool do_wakeup = device_may_wakeup(dev);
 
 
 	dev_dbg(dev, "ehci-msm PM suspend\n");
 	dev_dbg(dev, "ehci-msm PM suspend\n");
 
 
-	/*
-	 * EHCI helper function has also the same check before manipulating
-	 * port wakeup flags.  We do check here the same condition before
-	 * calling the same helper function to avoid bringing hardware
-	 * from Low power mode when there is no need for adjusting port
-	 * wakeup flags.
-	 */
-	if (hcd->self.root_hub->do_remote_wakeup && !wakeup) {
-		pm_runtime_resume(dev);
-		ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
-				wakeup);
-	}
-
-	return 0;
+	return ehci_suspend(hcd, do_wakeup);
 }
 }
 
 
 static int ehci_msm_pm_resume(struct device *dev)
 static int ehci_msm_pm_resume(struct device *dev)
@@ -223,7 +210,7 @@ static int ehci_msm_pm_resume(struct device *dev)
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 
 
 	dev_dbg(dev, "ehci-msm PM resume\n");
 	dev_dbg(dev, "ehci-msm PM resume\n");
-	ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
+	ehci_resume(hcd, false);
 
 
 	return 0;
 	return 0;
 }
 }

+ 11 - 25
drivers/usb/host/ehci-mv.c

@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/otg.h>
 #include <linux/platform_data/mv_usb.h>
 #include <linux/platform_data/mv_usb.h>
 
 
@@ -76,7 +77,6 @@ static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv)
 
 
 static int mv_ehci_reset(struct usb_hcd *hcd)
 static int mv_ehci_reset(struct usb_hcd *hcd)
 {
 {
-	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	struct device *dev = hcd->self.controller;
 	struct device *dev = hcd->self.controller;
 	struct ehci_hcd_mv *ehci_mv = dev_get_drvdata(dev);
 	struct ehci_hcd_mv *ehci_mv = dev_get_drvdata(dev);
 	int retval;
 	int retval;
@@ -86,25 +86,13 @@ static int mv_ehci_reset(struct usb_hcd *hcd)
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
-	/*
-	 * data structure init
-	 */
-	retval = ehci_init(hcd);
-	if (retval) {
-		dev_err(dev, "ehci_init failed %d\n", retval);
-		return retval;
-	}
-
 	hcd->has_tt = 1;
 	hcd->has_tt = 1;
-	ehci->sbrn = 0x20;
 
 
-	retval = ehci_reset(ehci);
-	if (retval) {
-		dev_err(dev, "ehci_reset failed %d\n", retval);
-		return retval;
-	}
+	retval = ehci_setup(hcd);
+	if (retval)
+		dev_err(dev, "ehci_setup failed %d\n", retval);
 
 
-	return 0;
+	return retval;
 }
 }
 
 
 static const struct hc_driver mv_ehci_hc_driver = {
 static const struct hc_driver mv_ehci_hc_driver = {
@@ -247,14 +235,12 @@ static int mv_ehci_probe(struct platform_device *pdev)
 
 
 	ehci = hcd_to_ehci(hcd);
 	ehci = hcd_to_ehci(hcd);
 	ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs;
 	ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs;
-	ehci->regs = (struct ehci_regs *) ehci_mv->op_regs;
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
 
 	ehci_mv->mode = pdata->mode;
 	ehci_mv->mode = pdata->mode;
 	if (ehci_mv->mode == MV_USB_MODE_OTG) {
 	if (ehci_mv->mode == MV_USB_MODE_OTG) {
 #ifdef CONFIG_USB_OTG_UTILS
 #ifdef CONFIG_USB_OTG_UTILS
-		ehci_mv->otg = usb_get_transceiver();
-		if (!ehci_mv->otg) {
+		ehci_mv->otg = usb_get_phy(USB_PHY_TYPE_USB2);
+		if (IS_ERR_OR_NULL(ehci_mv->otg)) {
 			dev_err(&pdev->dev,
 			dev_err(&pdev->dev,
 				"unable to find transceiver\n");
 				"unable to find transceiver\n");
 			retval = -ENODEV;
 			retval = -ENODEV;
@@ -302,8 +288,8 @@ err_set_vbus:
 		pdata->set_vbus(0);
 		pdata->set_vbus(0);
 #ifdef CONFIG_USB_OTG_UTILS
 #ifdef CONFIG_USB_OTG_UTILS
 err_put_transceiver:
 err_put_transceiver:
-	if (ehci_mv->otg)
-		usb_put_transceiver(ehci_mv->otg);
+	if (!IS_ERR_OR_NULL(ehci_mv->otg))
+		usb_put_phy(ehci_mv->otg);
 #endif
 #endif
 err_disable_clk:
 err_disable_clk:
 	mv_ehci_disable(ehci_mv);
 	mv_ehci_disable(ehci_mv);
@@ -331,9 +317,9 @@ static int mv_ehci_remove(struct platform_device *pdev)
 	if (hcd->rh_registered)
 	if (hcd->rh_registered)
 		usb_remove_hcd(hcd);
 		usb_remove_hcd(hcd);
 
 
-	if (ehci_mv->otg) {
+	if (!IS_ERR_OR_NULL(ehci_mv->otg)) {
 		otg_set_host(ehci_mv->otg->otg, NULL);
 		otg_set_host(ehci_mv->otg->otg, NULL);
-		usb_put_transceiver(ehci_mv->otg);
+		usb_put_phy(ehci_mv->otg);
 	}
 	}
 
 
 	if (ehci_mv->mode == MV_USB_MODE_HOST) {
 	if (ehci_mv->mode == MV_USB_MODE_HOST) {

+ 1 - 16
drivers/usb/host/ehci-mxc.c

@@ -42,27 +42,12 @@ static int ehci_mxc_setup(struct usb_hcd *hcd)
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	int retval;
 	int retval;
 
 
-	dbg_hcs_params(ehci, "reset");
-	dbg_hcc_params(ehci, "reset");
-
-	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-
 	hcd->has_tt = 1;
 	hcd->has_tt = 1;
 
 
-	retval = ehci_halt(ehci);
+	retval = ehci_setup(hcd);
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 
 
-	/* data structure init */
-	retval = ehci_init(hcd);
-	if (retval)
-		return retval;
-
-	ehci->sbrn = 0x20;
-
-	ehci_reset(ehci);
-
 	ehci_port_power(ehci, 0);
 	ehci_port_power(ehci, 0);
 	return 0;
 	return 0;
 }
 }

+ 1 - 7
drivers/usb/host/ehci-octeon.c

@@ -56,7 +56,7 @@ static const struct hc_driver ehci_octeon_hc_driver = {
 	/*
 	/*
 	 * basic lifecycle operations
 	 * basic lifecycle operations
 	 */
 	 */
-	.reset			= ehci_init,
+	.reset			= ehci_setup,
 	.start			= ehci_run,
 	.start			= ehci_run,
 	.stop			= ehci_stop,
 	.stop			= ehci_stop,
 	.shutdown		= ehci_shutdown,
 	.shutdown		= ehci_shutdown,
@@ -150,12 +150,6 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev)
 #endif
 #endif
 
 
 	ehci->caps = hcd->regs;
 	ehci->caps = hcd->regs;
-	ehci->regs = hcd->regs +
-		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-
-	ehci_reset(ehci);
 
 
 	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (ret) {
 	if (ret) {

+ 59 - 55
drivers/usb/host/ehci-omap.c

@@ -115,9 +115,8 @@ static void omap_ehci_erratum_i693(struct ehci_hcd *ehci)
 	clk_disable(usbhost_p2_fck);
 	clk_disable(usbhost_p2_fck);
 }
 }
 
 
-static void omap_ehci_soft_phy_reset(struct platform_device *pdev, u8 port)
+static void omap_ehci_soft_phy_reset(struct usb_hcd *hcd, u8 port)
 {
 {
-	struct usb_hcd	*hcd = dev_get_drvdata(&pdev->dev);
 	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
 	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
 	unsigned reg = 0;
 	unsigned reg = 0;
 
 
@@ -139,12 +138,63 @@ static void omap_ehci_soft_phy_reset(struct platform_device *pdev, u8 port)
 		cpu_relax();
 		cpu_relax();
 
 
 		if (time_after(jiffies, timeout)) {
 		if (time_after(jiffies, timeout)) {
-			dev_dbg(&pdev->dev, "phy reset operation timed out\n");
+			dev_dbg(hcd->self.controller,
+					"phy reset operation timed out\n");
 			break;
 			break;
 		}
 		}
 	}
 	}
 }
 }
 
 
+static int omap_ehci_init(struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
+	int			rc;
+	struct ehci_hcd_omap_platform_data	*pdata;
+
+	pdata = hcd->self.controller->platform_data;
+	if (pdata->phy_reset) {
+		if (gpio_is_valid(pdata->reset_gpio_port[0]))
+			gpio_request_one(pdata->reset_gpio_port[0],
+					 GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
+
+		if (gpio_is_valid(pdata->reset_gpio_port[1]))
+			gpio_request_one(pdata->reset_gpio_port[1],
+					 GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
+
+		/* Hold the PHY in RESET for enough time till DIR is high */
+		udelay(10);
+	}
+
+	/* Soft reset the PHY using PHY reset command over ULPI */
+	if (pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY)
+		omap_ehci_soft_phy_reset(hcd, 0);
+	if (pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_PHY)
+		omap_ehci_soft_phy_reset(hcd, 1);
+
+	/* we know this is the memory we want, no need to ioremap again */
+	ehci->caps = hcd->regs;
+
+	rc = ehci_setup(hcd);
+
+	if (pdata->phy_reset) {
+		/* Hold the PHY in RESET for enough time till
+		 * PHY is settled and ready
+		 */
+		udelay(10);
+
+		if (gpio_is_valid(pdata->reset_gpio_port[0]))
+			gpio_set_value_cansleep(pdata->reset_gpio_port[0], 1);
+
+		if (gpio_is_valid(pdata->reset_gpio_port[1]))
+			gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1);
+	}
+
+	/* root ports should always stay powered */
+	ehci_port_power(ehci, 1);
+
+	return rc;
+}
+
 static int omap_ehci_hub_control(
 static int omap_ehci_hub_control(
 	struct usb_hcd	*hcd,
 	struct usb_hcd	*hcd,
 	u16		typeReq,
 	u16		typeReq,
@@ -219,7 +269,6 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
 	struct resource				*res;
 	struct resource				*res;
 	struct usb_hcd				*hcd;
 	struct usb_hcd				*hcd;
 	void __iomem				*regs;
 	void __iomem				*regs;
-	struct ehci_hcd				*omap_ehci;
 	int					ret = -ENODEV;
 	int					ret = -ENODEV;
 	int					irq;
 	int					irq;
 	int					i;
 	int					i;
@@ -281,18 +330,6 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
 		}
 		}
 	}
 	}
 
 
-	/* Hold PHYs in reset while initializing EHCI controller */
-	if (pdata->phy_reset) {
-		if (gpio_is_valid(pdata->reset_gpio_port[0]))
-			gpio_set_value_cansleep(pdata->reset_gpio_port[0], 0);
-
-		if (gpio_is_valid(pdata->reset_gpio_port[1]))
-			gpio_set_value_cansleep(pdata->reset_gpio_port[1], 0);
-
-		/* Hold the PHY in RESET for enough time till DIR is high */
-		udelay(10);
-	}
-
 	pm_runtime_enable(dev);
 	pm_runtime_enable(dev);
 	pm_runtime_get_sync(dev);
 	pm_runtime_get_sync(dev);
 
 
@@ -308,49 +345,12 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
 	ehci_write(regs, EHCI_INSNREG04,
 	ehci_write(regs, EHCI_INSNREG04,
 				EHCI_INSNREG04_DISABLE_UNSUSPEND);
 				EHCI_INSNREG04_DISABLE_UNSUSPEND);
 
 
-	/* Soft reset the PHY using PHY reset command over ULPI */
-	if (pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY)
-		omap_ehci_soft_phy_reset(pdev, 0);
-	if (pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_PHY)
-		omap_ehci_soft_phy_reset(pdev, 1);
-
-	omap_ehci = hcd_to_ehci(hcd);
-	omap_ehci->sbrn = 0x20;
-
-	/* we know this is the memory we want, no need to ioremap again */
-	omap_ehci->caps = hcd->regs;
-	omap_ehci->regs = hcd->regs
-		+ HC_LENGTH(ehci, readl(&omap_ehci->caps->hc_capbase));
-
-	dbg_hcs_params(omap_ehci, "reset");
-	dbg_hcc_params(omap_ehci, "reset");
-
-	/* cache this readonly data; minimize chip reads */
-	omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params);
-
-	ehci_reset(omap_ehci);
 	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (ret) {
 	if (ret) {
 		dev_err(dev, "failed to add hcd with err %d\n", ret);
 		dev_err(dev, "failed to add hcd with err %d\n", ret);
-		goto err_add_hcd;
+		goto err_pm_runtime;
 	}
 	}
 
 
-	if (pdata->phy_reset) {
-		/* Hold the PHY in RESET for enough time till
-		 * PHY is settled and ready
-		 */
-		udelay(10);
-
-		if (gpio_is_valid(pdata->reset_gpio_port[0]))
-			gpio_set_value_cansleep(pdata->reset_gpio_port[0], 1);
-
-		if (gpio_is_valid(pdata->reset_gpio_port[1]))
-			gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1);
-	}
-
-	/* root ports should always stay powered */
-	ehci_port_power(omap_ehci, 1);
-
 	/* get clocks */
 	/* get clocks */
 	utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
 	utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
 	if (IS_ERR(utmi_p1_fck)) {
 	if (IS_ERR(utmi_p1_fck)) {
@@ -422,8 +422,12 @@ err_utmi_p1_fck:
 	clk_put(utmi_p1_fck);
 	clk_put(utmi_p1_fck);
 
 
 err_add_hcd:
 err_add_hcd:
+	usb_remove_hcd(hcd);
+
+err_pm_runtime:
 	disable_put_regulator(pdata);
 	disable_put_regulator(pdata);
 	pm_runtime_put_sync(dev);
 	pm_runtime_put_sync(dev);
+	usb_put_hcd(hcd);
 
 
 err_io:
 err_io:
 	iounmap(regs);
 	iounmap(regs);
@@ -506,7 +510,7 @@ static const struct hc_driver ehci_omap_hc_driver = {
 	/*
 	/*
 	 * basic lifecycle operations
 	 * basic lifecycle operations
 	 */
 	 */
-	.reset			= ehci_init,
+	.reset			= omap_ehci_init,
 	.start			= ehci_run,
 	.start			= ehci_run,
 	.stop			= ehci_stop,
 	.stop			= ehci_stop,
 	.shutdown		= ehci_shutdown,
 	.shutdown		= ehci_shutdown,

+ 1 - 16
drivers/usb/host/ehci-orion.c

@@ -106,21 +106,10 @@ static int ehci_orion_setup(struct usb_hcd *hcd)
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	int retval;
 	int retval;
 
 
-	hcd->has_tt = 1;
-
-	retval = ehci_halt(ehci);
-	if (retval)
-		return retval;
-
-	/*
-	 * data structure init
-	 */
-	retval = ehci_init(hcd);
+	retval = ehci_setup(hcd);
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 
 
-	ehci_reset(ehci);
-
 	ehci_port_power(ehci, 0);
 	ehci_port_power(ehci, 0);
 
 
 	return retval;
 	return retval;
@@ -261,11 +250,7 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
 
 
 	ehci = hcd_to_ehci(hcd);
 	ehci = hcd_to_ehci(hcd);
 	ehci->caps = hcd->regs + 0x100;
 	ehci->caps = hcd->regs + 0x100;
-	ehci->regs = hcd->regs + 0x100 +
-		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 	hcd->has_tt = 1;
 	hcd->has_tt = 1;
-	ehci->sbrn = 0x20;
 
 
 	/*
 	/*
 	 * (Re-)program MBUS remapping windows if we are asked to.
 	 * (Re-)program MBUS remapping windows if we are asked to.

+ 82 - 156
drivers/usb/host/ehci-pci.c

@@ -54,6 +54,17 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 	u32			temp;
 	u32			temp;
 	int			retval;
 	int			retval;
 
 
+	ehci->caps = hcd->regs;
+
+	/*
+	 * ehci_init() causes memory for DMA transfers to be
+	 * allocated.  Thus, any vendor-specific workarounds based on
+	 * limiting the type of memory used for DMA transfers must
+	 * happen before ehci_setup() is called.
+	 *
+	 * Most other workarounds can be done either before or after
+	 * init and reset; they are located here too.
+	 */
 	switch (pdev->vendor) {
 	switch (pdev->vendor) {
 	case PCI_VENDOR_ID_TOSHIBA_2:
 	case PCI_VENDOR_ID_TOSHIBA_2:
 		/* celleb's companion chip */
 		/* celleb's companion chip */
@@ -66,20 +77,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 #endif
 #endif
 		}
 		}
 		break;
 		break;
-	}
-
-	ehci->caps = hcd->regs;
-	ehci->regs = hcd->regs +
-		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-
-	dbg_hcs_params(ehci, "reset");
-	dbg_hcc_params(ehci, "reset");
-
-        /* ehci_init() causes memory for DMA transfers to be
-         * allocated.  Thus, any vendor-specific workarounds based on
-         * limiting the type of memory used for DMA transfers must
-         * happen before ehci_init() is called. */
-	switch (pdev->vendor) {
 	case PCI_VENDOR_ID_NVIDIA:
 	case PCI_VENDOR_ID_NVIDIA:
 		/* NVidia reports that certain chips don't handle
 		/* NVidia reports that certain chips don't handle
 		 * QH, ITD, or SITD addresses above 2GB.  (But TD,
 		 * QH, ITD, or SITD addresses above 2GB.  (But TD,
@@ -95,61 +92,24 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 				ehci_warn(ehci, "can't enable NVidia "
 				ehci_warn(ehci, "can't enable NVidia "
 					"workaround for >2GB RAM\n");
 					"workaround for >2GB RAM\n");
 			break;
 			break;
-		}
-		break;
-	}
-
-	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-
-	retval = ehci_halt(ehci);
-	if (retval)
-		return retval;
 
 
-	if ((pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x7808) ||
-	    (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x4396)) {
-		/* EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may
-		 * read/write memory space which does not belong to it when
-		 * there is NULL pointer with T-bit set to 1 in the frame list
-		 * table. To avoid the issue, the frame list link pointer
-		 * should always contain a valid pointer to a inactive qh.
+		/* Some NForce2 chips have problems with selective suspend;
+		 * fixed in newer silicon.
 		 */
 		 */
-		ehci->use_dummy_qh = 1;
-		ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI "
-				"dummy qh workaround\n");
-	}
-
-	/* data structure init */
-	retval = ehci_init(hcd);
-	if (retval)
-		return retval;
-
-	switch (pdev->vendor) {
-	case PCI_VENDOR_ID_NEC:
-		ehci->need_io_watchdog = 0;
+		case 0x0068:
+			if (pdev->revision < 0xa4)
+				ehci->no_selective_suspend = 1;
+			break;
+		}
 		break;
 		break;
 	case PCI_VENDOR_ID_INTEL:
 	case PCI_VENDOR_ID_INTEL:
-		ehci->need_io_watchdog = 0;
 		ehci->fs_i_thresh = 1;
 		ehci->fs_i_thresh = 1;
-		if (pdev->device == 0x27cc) {
-			ehci->broken_periodic = 1;
-			ehci_info(ehci, "using broken periodic workaround\n");
-		}
-		if (pdev->device == 0x0806 || pdev->device == 0x0811
-				|| pdev->device == 0x0829) {
-			ehci_info(ehci, "disable lpm for langwell/penwell\n");
-			ehci->has_lpm = 0;
-		}
-		if (pdev->device == PCI_DEVICE_ID_INTEL_CE4100_USB) {
+		if (pdev->device == PCI_DEVICE_ID_INTEL_CE4100_USB)
 			hcd->has_tt = 1;
 			hcd->has_tt = 1;
-			tdi_reset(ehci);
-		}
 		break;
 		break;
 	case PCI_VENDOR_ID_TDI:
 	case PCI_VENDOR_ID_TDI:
-		if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
+		if (pdev->device == PCI_DEVICE_ID_TDI_EHCI)
 			hcd->has_tt = 1;
 			hcd->has_tt = 1;
-			tdi_reset(ehci);
-		}
 		break;
 		break;
 	case PCI_VENDOR_ID_AMD:
 	case PCI_VENDOR_ID_AMD:
 		/* AMD PLL quirk */
 		/* AMD PLL quirk */
@@ -161,28 +121,17 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 			retval = -EIO;
 			retval = -EIO;
 			goto done;
 			goto done;
 		}
 		}
-		break;
-	case PCI_VENDOR_ID_NVIDIA:
-		switch (pdev->device) {
-		/* Some NForce2 chips have problems with selective suspend;
-		 * fixed in newer silicon.
-		 */
-		case 0x0068:
-			if (pdev->revision < 0xa4)
-				ehci->no_selective_suspend = 1;
-			break;
 
 
-		/* MCP89 chips on the MacBookAir3,1 give EPROTO when
-		 * fetching device descriptors unless LPM is disabled.
-		 * There are also intermittent problems enumerating
-		 * devices with PPCD enabled.
+		/*
+		 * EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may
+		 * read/write memory space which does not belong to it when
+		 * there is NULL pointer with T-bit set to 1 in the frame list
+		 * table. To avoid the issue, the frame list link pointer
+		 * should always contain a valid pointer to a inactive qh.
 		 */
 		 */
-		case 0x0d9d:
-			ehci_info(ehci, "disable lpm/ppcd for nvidia mcp89");
-			ehci->has_lpm = 0;
-			ehci->has_ppcd = 0;
-			ehci->command &= ~CMD_PPCEE;
-			break;
+		if (pdev->device == 0x7808) {
+			ehci->use_dummy_qh = 1;
+			ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI dummy qh workaround\n");
 		}
 		}
 		break;
 		break;
 	case PCI_VENDOR_ID_VIA:
 	case PCI_VENDOR_ID_VIA:
@@ -203,6 +152,18 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 		/* AMD PLL quirk */
 		/* AMD PLL quirk */
 		if (usb_amd_find_chipset_info())
 		if (usb_amd_find_chipset_info())
 			ehci->amd_pll_fix = 1;
 			ehci->amd_pll_fix = 1;
+
+		/*
+		 * EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may
+		 * read/write memory space which does not belong to it when
+		 * there is NULL pointer with T-bit set to 1 in the frame list
+		 * table. To avoid the issue, the frame list link pointer
+		 * should always contain a valid pointer to a inactive qh.
+		 */
+		if (pdev->device == 0x4396) {
+			ehci->use_dummy_qh = 1;
+			ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI dummy qh workaround\n");
+		}
 		/* SB600 and old version of SB700 have a bug in EHCI controller,
 		/* SB600 and old version of SB700 have a bug in EHCI controller,
 		 * which causes usb devices lose response in some cases.
 		 * which causes usb devices lose response in some cases.
 		 */
 		 */
@@ -231,6 +192,40 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 		break;
 		break;
 	}
 	}
 
 
+	retval = ehci_setup(hcd);
+	if (retval)
+		return retval;
+
+	/* These workarounds need to be applied after ehci_setup() */
+	switch (pdev->vendor) {
+	case PCI_VENDOR_ID_NEC:
+		ehci->need_io_watchdog = 0;
+		break;
+	case PCI_VENDOR_ID_INTEL:
+		ehci->need_io_watchdog = 0;
+		if (pdev->device == 0x0806 || pdev->device == 0x0811
+				|| pdev->device == 0x0829) {
+			ehci_info(ehci, "disable lpm for langwell/penwell\n");
+			ehci->has_lpm = 0;
+		}
+		break;
+	case PCI_VENDOR_ID_NVIDIA:
+		switch (pdev->device) {
+		/* MCP89 chips on the MacBookAir3,1 give EPROTO when
+		 * fetching device descriptors unless LPM is disabled.
+		 * There are also intermittent problems enumerating
+		 * devices with PPCD enabled.
+		 */
+		case 0x0d9d:
+			ehci_info(ehci, "disable lpm/ppcd for nvidia mcp89");
+			ehci->has_lpm = 0;
+			ehci->has_ppcd = 0;
+			ehci->command &= ~CMD_PPCEE;
+			break;
+		}
+		break;
+	}
+
 	/* optional debug port, normally in the first BAR */
 	/* optional debug port, normally in the first BAR */
 	temp = pci_find_capability(pdev, 0x0a);
 	temp = pci_find_capability(pdev, 0x0a);
 	if (temp) {
 	if (temp) {
@@ -238,7 +233,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 		temp >>= 16;
 		temp >>= 16;
 		if ((temp & (3 << 13)) == (1 << 13)) {
 		if ((temp & (3 << 13)) == (1 << 13)) {
 			temp &= 0x1fff;
 			temp &= 0x1fff;
-			ehci->debug = ehci_to_hcd(ehci)->regs + temp;
+			ehci->debug = hcd->regs + temp;
 			temp = ehci_readl(ehci, &ehci->debug->control);
 			temp = ehci_readl(ehci, &ehci->debug->control);
 			ehci_info(ehci, "debug port %d%s\n",
 			ehci_info(ehci, "debug port %d%s\n",
 				HCS_DEBUG_PORT(ehci->hcs_params),
 				HCS_DEBUG_PORT(ehci->hcs_params),
@@ -250,8 +245,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 		}
 		}
 	}
 	}
 
 
-	ehci_reset(ehci);
-
 	/* at least the Genesys GL880S needs fixup here */
 	/* at least the Genesys GL880S needs fixup here */
 	temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
 	temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
 	temp &= 0x0f;
 	temp &= 0x0f;
@@ -275,10 +268,11 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 	}
 	}
 
 
 	/* Serial Bus Release Number is at PCI 0x60 offset */
 	/* Serial Bus Release Number is at PCI 0x60 offset */
-	pci_read_config_byte(pdev, 0x60, &ehci->sbrn);
 	if (pdev->vendor == PCI_VENDOR_ID_STMICRO
 	if (pdev->vendor == PCI_VENDOR_ID_STMICRO
 	    && pdev->device == PCI_DEVICE_ID_STMICRO_USB_HOST)
 	    && pdev->device == PCI_DEVICE_ID_STMICRO_USB_HOST)
-		ehci->sbrn = 0x20; /* ConneXT has no sbrn register */
+		;	/* ConneXT has no sbrn register */
+	else
+		pci_read_config_byte(pdev, 0x60, &ehci->sbrn);
 
 
 	/* Keep this around for a while just in case some EHCI
 	/* Keep this around for a while just in case some EHCI
 	 * implementation uses legacy PCI PM support.  This test
 	 * implementation uses legacy PCI PM support.  This test
@@ -331,29 +325,7 @@ done:
 
 
 static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
 static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
 {
 {
-	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
-	unsigned long		flags;
-	int			rc = 0;
-
-	if (time_before(jiffies, ehci->next_statechange))
-		msleep(10);
-
-	/* Root hub was already suspended. Disable irq emission and
-	 * mark HW unaccessible.  The PM and USB cores make sure that
-	 * the root hub is either suspended or stopped.
-	 */
-	ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup);
-	spin_lock_irqsave (&ehci->lock, flags);
-	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
-	(void)ehci_readl(ehci, &ehci->regs->intr_enable);
-
-	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-	spin_unlock_irqrestore (&ehci->lock, flags);
-
-	// could save FLADJ in case of Vaux power loss
-	// ... we'd only use it to handle clock skew
-
-	return rc;
+	return ehci_suspend(hcd, do_wakeup);
 }
 }
 
 
 static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev)
 static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev)
@@ -402,54 +374,8 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
 	if (usb_is_intel_switchable_ehci(pdev))
 	if (usb_is_intel_switchable_ehci(pdev))
 		ehci_enable_xhci_companion();
 		ehci_enable_xhci_companion();
 
 
-	// maybe restore FLADJ
-
-	if (time_before(jiffies, ehci->next_statechange))
-		msleep(100);
-
-	/* Mark hardware accessible again as we are out of D3 state by now */
-	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
-	/* If CF is still set and we aren't resuming from hibernation
-	 * then we maintained PCI Vaux power.
-	 * Just undo the effect of ehci_pci_suspend().
-	 */
-	if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
-				!hibernated) {
-		int	mask = INTR_MASK;
-
-		ehci_prepare_ports_for_controller_resume(ehci);
-		if (!hcd->self.root_hub->do_remote_wakeup)
-			mask &= ~STS_PCD;
-		ehci_writel(ehci, mask, &ehci->regs->intr_enable);
-		ehci_readl(ehci, &ehci->regs->intr_enable);
-		return 0;
-	}
-
-	usb_root_hub_lost_power(hcd->self.root_hub);
-
-	/* Else reset, to cope with power loss or flush-to-storage
-	 * style "resume" having let BIOS kick in during reboot.
-	 */
-	(void) ehci_halt(ehci);
-	(void) ehci_reset(ehci);
-	(void) ehci_pci_reinit(ehci, pdev);
-
-	/* emptying the schedule aborts any urbs */
-	spin_lock_irq(&ehci->lock);
-	if (ehci->reclaim)
-		end_unlink_async(ehci);
-	ehci_work(ehci);
-	spin_unlock_irq(&ehci->lock);
-
-	ehci_writel(ehci, ehci->command, &ehci->regs->command);
-	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
-	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
-
-	/* here we "know" root ports should always stay powered */
-	ehci_port_power(ehci, 1);
-
-	ehci->rh_state = EHCI_RH_SUSPENDED;
+	if (ehci_resume(hcd, hibernated) != 0)
+		(void) ehci_pci_reinit(ehci, pdev);
 	return 0;
 	return 0;
 }
 }
 #endif
 #endif

+ 3 - 4
drivers/usb/host/ehci-platform.c

@@ -153,17 +153,16 @@ static int __devexit ehci_platform_remove(struct platform_device *dev)
 static int ehci_platform_suspend(struct device *dev)
 static int ehci_platform_suspend(struct device *dev)
 {
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
-	bool wakeup = device_may_wakeup(dev);
+	bool do_wakeup = device_may_wakeup(dev);
 
 
-	ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd), wakeup);
-	return 0;
+	return ehci_suspend(hcd, do_wakeup);
 }
 }
 
 
 static int ehci_platform_resume(struct device *dev)
 static int ehci_platform_resume(struct device *dev)
 {
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 
 
-	ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
+	ehci_resume(hcd, false);
 	return 0;
 	return 0;
 }
 }
 
 

+ 2 - 15
drivers/usb/host/ehci-pmcmsp.c

@@ -78,27 +78,14 @@ static int ehci_msp_setup(struct usb_hcd *hcd)
 {
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
 	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
 	int			retval;
 	int			retval;
+
 	ehci->big_endian_mmio = 1;
 	ehci->big_endian_mmio = 1;
 	ehci->big_endian_desc = 1;
 	ehci->big_endian_desc = 1;
 
 
 	ehci->caps = hcd->regs;
 	ehci->caps = hcd->regs;
-	ehci->regs = hcd->regs +
-		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-	dbg_hcs_params(ehci, "reset");
-	dbg_hcc_params(ehci, "reset");
-
-	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 	hcd->has_tt = 1;
 	hcd->has_tt = 1;
 
 
-	retval = ehci_halt(ehci);
-	if (retval)
-		return retval;
-
-	ehci_reset(ehci);
-
-	/* data structure init */
-	retval = ehci_init(hcd);
+	retval = ehci_setup(hcd);
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 
 

+ 1 - 24
drivers/usb/host/ehci-ppc-of.c

@@ -17,24 +17,6 @@
 #include <linux/of.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/of_platform.h>
 
 
-/* called during probe() after chip reset completes */
-static int ehci_ppc_of_setup(struct usb_hcd *hcd)
-{
-	struct ehci_hcd	*ehci = hcd_to_ehci(hcd);
-	int		retval;
-
-	retval = ehci_halt(ehci);
-	if (retval)
-		return retval;
-
-	retval = ehci_init(hcd);
-	if (retval)
-		return retval;
-
-	ehci->sbrn = 0x20;
-	return ehci_reset(ehci);
-}
-
 
 
 static const struct hc_driver ehci_ppc_of_hc_driver = {
 static const struct hc_driver ehci_ppc_of_hc_driver = {
 	.description		= hcd_name,
 	.description		= hcd_name,
@@ -50,7 +32,7 @@ static const struct hc_driver ehci_ppc_of_hc_driver = {
 	/*
 	/*
 	 * basic lifecycle operations
 	 * basic lifecycle operations
 	 */
 	 */
-	.reset			= ehci_ppc_of_setup,
+	.reset			= ehci_setup,
 	.start			= ehci_run,
 	.start			= ehci_run,
 	.stop			= ehci_stop,
 	.stop			= ehci_stop,
 	.shutdown		= ehci_shutdown,
 	.shutdown		= ehci_shutdown,
@@ -178,11 +160,6 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op)
 		ehci->big_endian_desc = 1;
 		ehci->big_endian_desc = 1;
 
 
 	ehci->caps = hcd->regs;
 	ehci->caps = hcd->regs;
-	ehci->regs = hcd->regs +
-		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-
-	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
 
 	if (of_device_is_compatible(dn, "ibm,usb-ehci-440epx")) {
 	if (of_device_is_compatible(dn, "ibm,usb-ehci-440epx")) {
 		rv = ppc44x_enable_bmt(dn);
 		rv = ppc44x_enable_bmt(dn);

+ 1 - 17
drivers/usb/host/ehci-ps3.c

@@ -55,28 +55,12 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 
 
 	ehci->big_endian_mmio = 1;
 	ehci->big_endian_mmio = 1;
-
 	ehci->caps = hcd->regs;
 	ehci->caps = hcd->regs;
-	ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
-		&ehci->caps->hc_capbase));
-
-	dbg_hcs_params(ehci, "reset");
-	dbg_hcc_params(ehci, "reset");
-
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-
-	result = ehci_halt(ehci);
 
 
+	result = ehci_setup(hcd);
 	if (result)
 	if (result)
 		return result;
 		return result;
 
 
-	result = ehci_init(hcd);
-
-	if (result)
-		return result;
-
-	ehci_reset(ehci);
-
 	ps3_ehci_setup_insnreg(ehci);
 	ps3_ehci_setup_insnreg(ehci);
 
 
 	return result;
 	return result;

+ 177 - 134
drivers/usb/host/ehci-q.c

@@ -100,7 +100,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
 	 * and set the pseudo-toggle in udev. Only usb_clear_halt() will
 	 * and set the pseudo-toggle in udev. Only usb_clear_halt() will
 	 * ever clear it.
 	 * ever clear it.
 	 */
 	 */
-	if (!(hw->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
+	if (!(hw->hw_info1 & cpu_to_hc32(ehci, QH_TOGGLE_CTL))) {
 		unsigned	is_out, epnum;
 		unsigned	is_out, epnum;
 
 
 		is_out = qh->is_out;
 		is_out = qh->is_out;
@@ -265,7 +265,6 @@ __acquires(ehci->lock)
 			/* ... update hc-wide periodic stats (for usbfs) */
 			/* ... update hc-wide periodic stats (for usbfs) */
 			ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
 			ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
 		}
 		}
-		qh_put (qh);
 	}
 	}
 
 
 	if (unlikely(urb->unlinked)) {
 	if (unlikely(urb->unlinked)) {
@@ -294,9 +293,6 @@ __acquires(ehci->lock)
 	spin_lock (&ehci->lock);
 	spin_lock (&ehci->lock);
 }
 }
 
 
-static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
-static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
-
 static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
 static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
 
 
 /*
 /*
@@ -326,7 +322,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 	 *
 	 *
 	 * It's a bug for qh->qh_state to be anything other than
 	 * It's a bug for qh->qh_state to be anything other than
 	 * QH_STATE_IDLE, unless our caller is scan_async() or
 	 * QH_STATE_IDLE, unless our caller is scan_async() or
-	 * scan_periodic().
+	 * scan_intr().
 	 */
 	 */
 	state = qh->qh_state;
 	state = qh->qh_state;
 	qh->qh_state = QH_STATE_COMPLETING;
 	qh->qh_state = QH_STATE_COMPLETING;
@@ -434,7 +430,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
 
 		/* stop scanning when we reach qtds the hc is using */
 		/* stop scanning when we reach qtds the hc is using */
 		} else if (likely (!stopped
 		} else if (likely (!stopped
-				&& ehci->rh_state == EHCI_RH_RUNNING)) {
+				&& ehci->rh_state >= EHCI_RH_RUNNING)) {
 			break;
 			break;
 
 
 		/* scan the whole queue for unlinks whenever it stops */
 		/* scan the whole queue for unlinks whenever it stops */
@@ -442,7 +438,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 			stopped = 1;
 			stopped = 1;
 
 
 			/* cancel everything if we halt, suspend, etc */
 			/* cancel everything if we halt, suspend, etc */
-			if (ehci->rh_state != EHCI_RH_RUNNING)
+			if (ehci->rh_state < EHCI_RH_RUNNING)
 				last_status = -ESHUTDOWN;
 				last_status = -ESHUTDOWN;
 
 
 			/* this qtd is active; skip it unless a previous qtd
 			/* this qtd is active; skip it unless a previous qtd
@@ -836,7 +832,6 @@ qh_make (
 				is_input, 0,
 				is_input, 0,
 				hb_mult(maxp) * max_packet(maxp)));
 				hb_mult(maxp) * max_packet(maxp)));
 		qh->start = NO_FRAME;
 		qh->start = NO_FRAME;
-		qh->stamp = ehci->periodic_stamp;
 
 
 		if (urb->dev->speed == USB_SPEED_HIGH) {
 		if (urb->dev->speed == USB_SPEED_HIGH) {
 			qh->c_usecs = 0;
 			qh->c_usecs = 0;
@@ -887,7 +882,7 @@ qh_make (
 	/* using TT? */
 	/* using TT? */
 	switch (urb->dev->speed) {
 	switch (urb->dev->speed) {
 	case USB_SPEED_LOW:
 	case USB_SPEED_LOW:
-		info1 |= (1 << 12);	/* EPS "low" */
+		info1 |= QH_LOW_SPEED;
 		/* FALL THROUGH */
 		/* FALL THROUGH */
 
 
 	case USB_SPEED_FULL:
 	case USB_SPEED_FULL:
@@ -895,8 +890,8 @@ qh_make (
 		if (type != PIPE_INTERRUPT)
 		if (type != PIPE_INTERRUPT)
 			info1 |= (EHCI_TUNE_RL_TT << 28);
 			info1 |= (EHCI_TUNE_RL_TT << 28);
 		if (type == PIPE_CONTROL) {
 		if (type == PIPE_CONTROL) {
-			info1 |= (1 << 27);	/* for TT */
-			info1 |= 1 << 14;	/* toggle from qtd */
+			info1 |= QH_CONTROL_EP;		/* for TT */
+			info1 |= QH_TOGGLE_CTL;		/* toggle from qtd */
 		}
 		}
 		info1 |= maxp << 16;
 		info1 |= maxp << 16;
 
 
@@ -921,11 +916,11 @@ qh_make (
 		break;
 		break;
 
 
 	case USB_SPEED_HIGH:		/* no TT involved */
 	case USB_SPEED_HIGH:		/* no TT involved */
-		info1 |= (2 << 12);	/* EPS "high" */
+		info1 |= QH_HIGH_SPEED;
 		if (type == PIPE_CONTROL) {
 		if (type == PIPE_CONTROL) {
 			info1 |= (EHCI_TUNE_RL_HS << 28);
 			info1 |= (EHCI_TUNE_RL_HS << 28);
 			info1 |= 64 << 16;	/* usb2 fixed maxpacket */
 			info1 |= 64 << 16;	/* usb2 fixed maxpacket */
-			info1 |= 1 << 14;	/* toggle from qtd */
+			info1 |= QH_TOGGLE_CTL;	/* toggle from qtd */
 			info2 |= (EHCI_TUNE_MULT_HS << 30);
 			info2 |= (EHCI_TUNE_MULT_HS << 30);
 		} else if (type == PIPE_BULK) {
 		} else if (type == PIPE_BULK) {
 			info1 |= (EHCI_TUNE_RL_HS << 28);
 			info1 |= (EHCI_TUNE_RL_HS << 28);
@@ -946,7 +941,7 @@ qh_make (
 		ehci_dbg(ehci, "bogus dev %p speed %d\n", urb->dev,
 		ehci_dbg(ehci, "bogus dev %p speed %d\n", urb->dev,
 			urb->dev->speed);
 			urb->dev->speed);
 done:
 done:
-		qh_put (qh);
+		qh_destroy(ehci, qh);
 		return NULL;
 		return NULL;
 	}
 	}
 
 
@@ -965,6 +960,31 @@ done:
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
+static void enable_async(struct ehci_hcd *ehci)
+{
+	if (ehci->async_count++)
+		return;
+
+	/* Stop waiting to turn off the async schedule */
+	ehci->enabled_hrtimer_events &= ~BIT(EHCI_HRTIMER_DISABLE_ASYNC);
+
+	/* Don't start the schedule until ASS is 0 */
+	ehci_poll_ASS(ehci);
+	turn_on_io_watchdog(ehci);
+}
+
+static void disable_async(struct ehci_hcd *ehci)
+{
+	if (--ehci->async_count)
+		return;
+
+	/* The async schedule and async_unlink list are supposed to be empty */
+	WARN_ON(ehci->async->qh_next.qh || ehci->async_unlink);
+
+	/* Don't turn off the schedule until ASS is 1 */
+	ehci_poll_ASS(ehci);
+}
+
 /* move qh (and its qtds) onto async queue; maybe enable queue.  */
 /* move qh (and its qtds) onto async queue; maybe enable queue.  */
 
 
 static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
@@ -978,24 +998,11 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
 
 	WARN_ON(qh->qh_state != QH_STATE_IDLE);
 	WARN_ON(qh->qh_state != QH_STATE_IDLE);
 
 
-	/* (re)start the async schedule? */
-	head = ehci->async;
-	timer_action_done (ehci, TIMER_ASYNC_OFF);
-	if (!head->qh_next.qh) {
-		if (!(ehci->command & CMD_ASE)) {
-			/* in case a clear of CMD_ASE didn't take yet */
-			(void)handshake(ehci, &ehci->regs->status,
-					STS_ASS, 0, 150);
-			ehci->command |= CMD_ASE;
-			ehci_writel(ehci, ehci->command, &ehci->regs->command);
-			/* posted write need not be known to HC yet ... */
-		}
-	}
-
 	/* clear halt and/or toggle; and maybe recover from silicon quirk */
 	/* clear halt and/or toggle; and maybe recover from silicon quirk */
 	qh_refresh(ehci, qh);
 	qh_refresh(ehci, qh);
 
 
 	/* splice right after start */
 	/* splice right after start */
+	head = ehci->async;
 	qh->qh_next = head->qh_next;
 	qh->qh_next = head->qh_next;
 	qh->hw->hw_next = head->hw->hw_next;
 	qh->hw->hw_next = head->hw->hw_next;
 	wmb ();
 	wmb ();
@@ -1003,10 +1010,11 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 	head->qh_next.qh = qh;
 	head->qh_next.qh = qh;
 	head->hw->hw_next = dma;
 	head->hw->hw_next = dma;
 
 
-	qh_get(qh);
 	qh->xacterrs = 0;
 	qh->xacterrs = 0;
 	qh->qh_state = QH_STATE_LINKED;
 	qh->qh_state = QH_STATE_LINKED;
 	/* qtd completions reported later by interrupt */
 	/* qtd completions reported later by interrupt */
+
+	enable_async(ehci);
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -1090,7 +1098,7 @@ static struct ehci_qh *qh_append_tds (
 			wmb ();
 			wmb ();
 			dummy->hw_token = token;
 			dummy->hw_token = token;
 
 
-			urb->hcpriv = qh_get (qh);
+			urb->hcpriv = qh;
 		}
 		}
 	}
 	}
 	return qh;
 	return qh;
@@ -1155,117 +1163,155 @@ submit_async (
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-/* the async qh for the qtds being reclaimed are now unlinked from the HC */
-
-static void end_unlink_async (struct ehci_hcd *ehci)
+static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
 {
-	struct ehci_qh		*qh = ehci->reclaim;
-	struct ehci_qh		*next;
+	struct ehci_qh		*prev;
 
 
-	iaa_watchdog_done(ehci);
+	/* Add to the end of the list of QHs waiting for the next IAAD */
+	qh->qh_state = QH_STATE_UNLINK;
+	if (ehci->async_unlink)
+		ehci->async_unlink_last->unlink_next = qh;
+	else
+		ehci->async_unlink = qh;
+	ehci->async_unlink_last = qh;
 
 
-	// qh->hw_next = cpu_to_hc32(qh->qh_dma);
-	qh->qh_state = QH_STATE_IDLE;
-	qh->qh_next.qh = NULL;
-	qh_put (qh);			// refcount from reclaim
+	/* Unlink it from the schedule */
+	prev = ehci->async;
+	while (prev->qh_next.qh != qh)
+		prev = prev->qh_next.qh;
 
 
-	/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
-	next = qh->reclaim;
-	ehci->reclaim = next;
-	qh->reclaim = NULL;
+	prev->hw->hw_next = qh->hw->hw_next;
+	prev->qh_next = qh->qh_next;
+	if (ehci->qh_scan_next == qh)
+		ehci->qh_scan_next = qh->qh_next.qh;
+}
 
 
-	qh_completions (ehci, qh);
+static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested)
+{
+	/*
+	 * Do nothing if an IAA cycle is already running or
+	 * if one will be started shortly.
+	 */
+	if (ehci->async_iaa || ehci->async_unlinking)
+		return;
 
 
-	if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) {
-		qh_link_async (ehci, qh);
-	} else {
-		/* it's not free to turn the async schedule on/off; leave it
-		 * active but idle for a while once it empties.
-		 */
-		if (ehci->rh_state == EHCI_RH_RUNNING
-				&& ehci->async->qh_next.qh == NULL)
-			timer_action (ehci, TIMER_ASYNC_OFF);
-	}
-	qh_put(qh);			/* refcount from async list */
+	/* Do all the waiting QHs at once */
+	ehci->async_iaa = ehci->async_unlink;
+	ehci->async_unlink = NULL;
 
 
-	if (next) {
-		ehci->reclaim = NULL;
-		start_unlink_async (ehci, next);
+	/* If the controller isn't running, we don't have to wait for it */
+	if (unlikely(ehci->rh_state < EHCI_RH_RUNNING)) {
+		if (!nested)		/* Avoid recursion */
+			end_unlink_async(ehci);
+
+	/* Otherwise start a new IAA cycle */
+	} else if (likely(ehci->rh_state == EHCI_RH_RUNNING)) {
+		/* Make sure the unlinks are all visible to the hardware */
+		wmb();
+
+		ehci_writel(ehci, ehci->command | CMD_IAAD,
+				&ehci->regs->command);
+		ehci_readl(ehci, &ehci->regs->command);
+		ehci_enable_event(ehci, EHCI_HRTIMER_IAA_WATCHDOG, true);
 	}
 	}
+}
+
+/* the async qh for the qtds being unlinked are now gone from the HC */
+
+static void end_unlink_async(struct ehci_hcd *ehci)
+{
+	struct ehci_qh		*qh;
 
 
 	if (ehci->has_synopsys_hc_bug)
 	if (ehci->has_synopsys_hc_bug)
 		ehci_writel(ehci, (u32) ehci->async->qh_dma,
 		ehci_writel(ehci, (u32) ehci->async->qh_dma,
 			    &ehci->regs->async_next);
 			    &ehci->regs->async_next);
-}
-
-/* makes sure the async qh will become idle */
-/* caller must own ehci->lock */
 
 
-static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
-{
-	struct ehci_qh	*prev;
+	/* Process the idle QHs */
+ restart:
+	ehci->async_unlinking = true;
+	while (ehci->async_iaa) {
+		qh = ehci->async_iaa;
+		ehci->async_iaa = qh->unlink_next;
+		qh->unlink_next = NULL;
+
+		qh->qh_state = QH_STATE_IDLE;
+		qh->qh_next.qh = NULL;
+
+		qh_completions(ehci, qh);
+		if (!list_empty(&qh->qtd_list) &&
+				ehci->rh_state == EHCI_RH_RUNNING)
+			qh_link_async(ehci, qh);
+		disable_async(ehci);
+	}
+	ehci->async_unlinking = false;
 
 
-#ifdef DEBUG
-	assert_spin_locked(&ehci->lock);
-	if (ehci->reclaim
-			|| (qh->qh_state != QH_STATE_LINKED
-				&& qh->qh_state != QH_STATE_UNLINK_WAIT)
-			)
-		BUG ();
-#endif
+	/* Start a new IAA cycle if any QHs are waiting for it */
+	if (ehci->async_unlink) {
+		start_iaa_cycle(ehci, true);
+		if (unlikely(ehci->rh_state < EHCI_RH_RUNNING))
+			goto restart;
+	}
+}
 
 
-	/* stop async schedule right now? */
-	if (unlikely (qh == ehci->async)) {
-		/* can't get here without STS_ASS set */
-		if (ehci->rh_state != EHCI_RH_HALTED
-				&& !ehci->reclaim) {
-			/* ... and CMD_IAAD clear */
-			ehci->command &= ~CMD_ASE;
-			ehci_writel(ehci, ehci->command, &ehci->regs->command);
-			wmb ();
-			// handshake later, if we need to
-			timer_action_done (ehci, TIMER_ASYNC_OFF);
+static void unlink_empty_async(struct ehci_hcd *ehci)
+{
+	struct ehci_qh		*qh, *next;
+	bool			stopped = (ehci->rh_state < EHCI_RH_RUNNING);
+	bool			check_unlinks_later = false;
+
+	/* Unlink all the async QHs that have been empty for a timer cycle */
+	next = ehci->async->qh_next.qh;
+	while (next) {
+		qh = next;
+		next = qh->qh_next.qh;
+
+		if (list_empty(&qh->qtd_list) &&
+				qh->qh_state == QH_STATE_LINKED) {
+			if (!stopped && qh->unlink_cycle ==
+					ehci->async_unlink_cycle)
+				check_unlinks_later = true;
+			else
+				single_unlink_async(ehci, qh);
 		}
 		}
-		return;
 	}
 	}
 
 
-	qh->qh_state = QH_STATE_UNLINK;
-	ehci->reclaim = qh = qh_get (qh);
+	/* Start a new IAA cycle if any QHs are waiting for it */
+	if (ehci->async_unlink)
+		start_iaa_cycle(ehci, false);
 
 
-	prev = ehci->async;
-	while (prev->qh_next.qh != qh)
-		prev = prev->qh_next.qh;
+	/* QHs that haven't been empty for long enough will be handled later */
+	if (check_unlinks_later) {
+		ehci_enable_event(ehci, EHCI_HRTIMER_ASYNC_UNLINKS, true);
+		++ehci->async_unlink_cycle;
+	}
+}
 
 
-	prev->hw->hw_next = qh->hw->hw_next;
-	prev->qh_next = qh->qh_next;
-	if (ehci->qh_scan_next == qh)
-		ehci->qh_scan_next = qh->qh_next.qh;
-	wmb ();
+/* makes sure the async qh will become idle */
+/* caller must own ehci->lock */
 
 
-	/* If the controller isn't running, we don't have to wait for it */
-	if (unlikely(ehci->rh_state != EHCI_RH_RUNNING)) {
-		/* if (unlikely (qh->reclaim != 0))
-		 *	this will recurse, probably not much
-		 */
-		end_unlink_async (ehci);
+static void start_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	/*
+	 * If the QH isn't linked then there's nothing we can do
+	 * unless we were called during a giveback, in which case
+	 * qh_completions() has to deal with it.
+	 */
+	if (qh->qh_state != QH_STATE_LINKED) {
+		if (qh->qh_state == QH_STATE_COMPLETING)
+			qh->needs_rescan = 1;
 		return;
 		return;
 	}
 	}
 
 
-	ehci_writel(ehci, ehci->command | CMD_IAAD, &ehci->regs->command);
-	(void)ehci_readl(ehci, &ehci->regs->command);
-	iaa_watchdog_start(ehci);
+	single_unlink_async(ehci, qh);
+	start_iaa_cycle(ehci, false);
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 static void scan_async (struct ehci_hcd *ehci)
 static void scan_async (struct ehci_hcd *ehci)
 {
 {
-	bool			stopped;
 	struct ehci_qh		*qh;
 	struct ehci_qh		*qh;
-	enum ehci_timer_action	action = TIMER_IO_WATCHDOG;
-
-	timer_action_done (ehci, TIMER_ASYNC_SHRINK);
-	stopped = (ehci->rh_state != EHCI_RH_RUNNING);
+	bool			check_unlinks_later = false;
 
 
 	ehci->qh_scan_next = ehci->async->qh_next.qh;
 	ehci->qh_scan_next = ehci->async->qh_next.qh;
 	while (ehci->qh_scan_next) {
 	while (ehci->qh_scan_next) {
@@ -1281,33 +1327,30 @@ static void scan_async (struct ehci_hcd *ehci)
 			 * drops the lock.  That's why ehci->qh_scan_next
 			 * drops the lock.  That's why ehci->qh_scan_next
 			 * always holds the next qh to scan; if the next qh
 			 * always holds the next qh to scan; if the next qh
 			 * gets unlinked then ehci->qh_scan_next is adjusted
 			 * gets unlinked then ehci->qh_scan_next is adjusted
-			 * in start_unlink_async().
+			 * in single_unlink_async().
 			 */
 			 */
-			qh = qh_get(qh);
 			temp = qh_completions(ehci, qh);
 			temp = qh_completions(ehci, qh);
-			if (qh->needs_rescan)
-				unlink_async(ehci, qh);
-			qh->unlink_time = jiffies + EHCI_SHRINK_JIFFIES;
-			qh_put(qh);
-			if (temp != 0)
+			if (qh->needs_rescan) {
+				start_unlink_async(ehci, qh);
+			} else if (list_empty(&qh->qtd_list)
+					&& qh->qh_state == QH_STATE_LINKED) {
+				qh->unlink_cycle = ehci->async_unlink_cycle;
+				check_unlinks_later = true;
+			} else if (temp != 0)
 				goto rescan;
 				goto rescan;
 		}
 		}
+	}
 
 
-		/* unlink idle entries, reducing DMA usage as well
-		 * as HCD schedule-scanning costs.  delay for any qh
-		 * we just scanned, there's a not-unusual case that it
-		 * doesn't stay idle for long.
-		 * (plus, avoids some kind of re-activation race.)
-		 */
-		if (list_empty(&qh->qtd_list)
-				&& qh->qh_state == QH_STATE_LINKED) {
-			if (!ehci->reclaim && (stopped ||
-					time_after_eq(jiffies, qh->unlink_time)))
-				start_unlink_async(ehci, qh);
-			else
-				action = TIMER_ASYNC_SHRINK;
-		}
+	/*
+	 * Unlink empty entries, reducing DMA usage as well
+	 * as HCD schedule-scanning costs.  Delay for any qh
+	 * we just scanned, there's a not-unusual case that it
+	 * doesn't stay idle for long.
+	 */
+	if (check_unlinks_later && ehci->rh_state == EHCI_RH_RUNNING &&
+			!(ehci->enabled_hrtimer_events &
+				BIT(EHCI_HRTIMER_ASYNC_UNLINKS))) {
+		ehci_enable_event(ehci, EHCI_HRTIMER_ASYNC_UNLINKS, true);
+		++ehci->async_unlink_cycle;
 	}
 	}
-	if (action == TIMER_ASYNC_SHRINK)
-		timer_action (ehci, TIMER_ASYNC_SHRINK);
 }
 }

+ 54 - 81
drivers/usb/host/ehci-s5p.c

@@ -13,7 +13,9 @@
  */
  */
 
 
 #include <linux/clk.h>
 #include <linux/clk.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
+#include <linux/of_gpio.h>
 #include <plat/ehci.h>
 #include <plat/ehci.h>
 #include <plat/usb-phy.h>
 #include <plat/usb-phy.h>
 
 
@@ -40,7 +42,7 @@ static const struct hc_driver s5p_ehci_hc_driver = {
 	.irq			= ehci_irq,
 	.irq			= ehci_irq,
 	.flags			= HCD_MEMORY | HCD_USB2,
 	.flags			= HCD_MEMORY | HCD_USB2,
 
 
-	.reset			= ehci_init,
+	.reset			= ehci_setup,
 	.start			= ehci_run,
 	.start			= ehci_run,
 	.stop			= ehci_stop,
 	.stop			= ehci_stop,
 	.shutdown		= ehci_shutdown,
 	.shutdown		= ehci_shutdown,
@@ -63,6 +65,26 @@ static const struct hc_driver s5p_ehci_hc_driver = {
 	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,
 	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,
 };
 };
 
 
+static void s5p_setup_vbus_gpio(struct platform_device *pdev)
+{
+	int err;
+	int gpio;
+
+	if (!pdev->dev.of_node)
+		return;
+
+	gpio = of_get_named_gpio(pdev->dev.of_node,
+			"samsung,vbus-gpio", 0);
+	if (!gpio_is_valid(gpio))
+		return;
+
+	err = gpio_request_one(gpio, GPIOF_OUT_INIT_HIGH, "ehci_vbus_gpio");
+	if (err)
+		dev_err(&pdev->dev, "can't request ehci vbus gpio %d", gpio);
+}
+
+static u64 ehci_s5p_dma_mask = DMA_BIT_MASK(32);
+
 static int __devinit s5p_ehci_probe(struct platform_device *pdev)
 static int __devinit s5p_ehci_probe(struct platform_device *pdev)
 {
 {
 	struct s5p_ehci_platdata *pdata;
 	struct s5p_ehci_platdata *pdata;
@@ -79,7 +101,20 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
-	s5p_ehci = kzalloc(sizeof(struct s5p_ehci_hcd), GFP_KERNEL);
+	/*
+	 * Right now device-tree probed devices don't get dma_mask set.
+	 * Since shared usb code relies on it, set it here for now.
+	 * Once we move to full device tree support this will vanish off.
+	 */
+	if (!pdev->dev.dma_mask)
+		pdev->dev.dma_mask = &ehci_s5p_dma_mask;
+	if (!pdev->dev.coherent_dma_mask)
+		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+	s5p_setup_vbus_gpio(pdev);
+
+	s5p_ehci = devm_kzalloc(&pdev->dev, sizeof(struct s5p_ehci_hcd),
+				GFP_KERNEL);
 	if (!s5p_ehci)
 	if (!s5p_ehci)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
@@ -89,8 +124,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
 					dev_name(&pdev->dev));
 					dev_name(&pdev->dev));
 	if (!hcd) {
 	if (!hcd) {
 		dev_err(&pdev->dev, "Unable to create HCD\n");
 		dev_err(&pdev->dev, "Unable to create HCD\n");
-		err = -ENOMEM;
-		goto fail_hcd;
+		return -ENOMEM;
 	}
 	}
 
 
 	s5p_ehci->hcd = hcd;
 	s5p_ehci->hcd = hcd;
@@ -115,7 +149,7 @@ static int __devinit s5p_ehci_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);
-	hcd->regs = ioremap(res->start, resource_size(res));
+	hcd->regs = devm_ioremap(&pdev->dev, res->start, hcd->rsrc_len);
 	if (!hcd->regs) {
 	if (!hcd->regs) {
 		dev_err(&pdev->dev, "Failed to remap I/O memory\n");
 		dev_err(&pdev->dev, "Failed to remap I/O memory\n");
 		err = -ENOMEM;
 		err = -ENOMEM;
@@ -126,7 +160,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
 	if (!irq) {
 	if (!irq) {
 		dev_err(&pdev->dev, "Failed to get IRQ\n");
 		dev_err(&pdev->dev, "Failed to get IRQ\n");
 		err = -ENODEV;
 		err = -ENODEV;
-		goto fail;
+		goto fail_io;
 	}
 	}
 
 
 	if (pdata->phy_init)
 	if (pdata->phy_init)
@@ -134,40 +168,26 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
 
 
 	ehci = hcd_to_ehci(hcd);
 	ehci = hcd_to_ehci(hcd);
 	ehci->caps = hcd->regs;
 	ehci->caps = hcd->regs;
-	ehci->regs = hcd->regs +
-		HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
 
 
 	/* DMA burst Enable */
 	/* DMA burst Enable */
 	writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
 	writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
 
 
-	dbg_hcs_params(ehci, "reset");
-	dbg_hcc_params(ehci, "reset");
-
-	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = readl(&ehci->caps->hcs_params);
-
-	ehci_reset(ehci);
-
 	err = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	err = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (err) {
 	if (err) {
 		dev_err(&pdev->dev, "Failed to add USB HCD\n");
 		dev_err(&pdev->dev, "Failed to add USB HCD\n");
-		goto fail;
+		goto fail_io;
 	}
 	}
 
 
 	platform_set_drvdata(pdev, s5p_ehci);
 	platform_set_drvdata(pdev, s5p_ehci);
 
 
 	return 0;
 	return 0;
 
 
-fail:
-	iounmap(hcd->regs);
 fail_io:
 fail_io:
 	clk_disable(s5p_ehci->clk);
 	clk_disable(s5p_ehci->clk);
 fail_clken:
 fail_clken:
 	clk_put(s5p_ehci->clk);
 	clk_put(s5p_ehci->clk);
 fail_clk:
 fail_clk:
 	usb_put_hcd(hcd);
 	usb_put_hcd(hcd);
-fail_hcd:
-	kfree(s5p_ehci);
 	return err;
 	return err;
 }
 }
 
 
@@ -182,13 +202,10 @@ static int __devexit s5p_ehci_remove(struct platform_device *pdev)
 	if (pdata && pdata->phy_exit)
 	if (pdata && pdata->phy_exit)
 		pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
 		pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
 
 
-	iounmap(hcd->regs);
-
 	clk_disable(s5p_ehci->clk);
 	clk_disable(s5p_ehci->clk);
 	clk_put(s5p_ehci->clk);
 	clk_put(s5p_ehci->clk);
 
 
 	usb_put_hcd(hcd);
 	usb_put_hcd(hcd);
-	kfree(s5p_ehci);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -207,27 +224,12 @@ static int s5p_ehci_suspend(struct device *dev)
 {
 {
 	struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
 	struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
 	struct usb_hcd *hcd = s5p_ehci->hcd;
 	struct usb_hcd *hcd = s5p_ehci->hcd;
-	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	bool do_wakeup = device_may_wakeup(dev);
 	struct platform_device *pdev = to_platform_device(dev);
 	struct platform_device *pdev = to_platform_device(dev);
 	struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
 	struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
-	unsigned long flags;
-	int rc = 0;
-
-	if (time_before(jiffies, ehci->next_statechange))
-		msleep(20);
-
-	/*
-	 * Root hub was already suspended. Disable irq emission and
-	 * mark HW unaccessible.  The PM and USB cores make sure that
-	 * the root hub is either suspended or stopped.
-	 */
-	ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
-	spin_lock_irqsave(&ehci->lock, flags);
-	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
-	(void)ehci_readl(ehci, &ehci->regs->intr_enable);
+	int rc;
 
 
-	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-	spin_unlock_irqrestore(&ehci->lock, flags);
+	rc = ehci_suspend(hcd, do_wakeup);
 
 
 	if (pdata && pdata->phy_exit)
 	if (pdata && pdata->phy_exit)
 		pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
 		pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
@@ -241,7 +243,6 @@ static int s5p_ehci_resume(struct device *dev)
 {
 {
 	struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
 	struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
 	struct usb_hcd *hcd = s5p_ehci->hcd;
 	struct usb_hcd *hcd = s5p_ehci->hcd;
-	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	struct platform_device *pdev = to_platform_device(dev);
 	struct platform_device *pdev = to_platform_device(dev);
 	struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
 	struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
 
 
@@ -253,44 +254,7 @@ static int s5p_ehci_resume(struct device *dev)
 	/* DMA burst Enable */
 	/* DMA burst Enable */
 	writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
 	writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
 
 
-	if (time_before(jiffies, ehci->next_statechange))
-		msleep(100);
-
-	/* Mark hardware accessible again as we are out of D3 state by now */
-	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
-	if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
-		int	mask = INTR_MASK;
-
-		ehci_prepare_ports_for_controller_resume(ehci);
-		if (!hcd->self.root_hub->do_remote_wakeup)
-			mask &= ~STS_PCD;
-		ehci_writel(ehci, mask, &ehci->regs->intr_enable);
-		ehci_readl(ehci, &ehci->regs->intr_enable);
-		return 0;
-	}
-
-	usb_root_hub_lost_power(hcd->self.root_hub);
-
-	(void) ehci_halt(ehci);
-	(void) ehci_reset(ehci);
-
-	/* emptying the schedule aborts any urbs */
-	spin_lock_irq(&ehci->lock);
-	if (ehci->reclaim)
-		end_unlink_async(ehci);
-	ehci_work(ehci);
-	spin_unlock_irq(&ehci->lock);
-
-	ehci_writel(ehci, ehci->command, &ehci->regs->command);
-	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
-	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
-
-	/* here we "know" root ports should always stay powered */
-	ehci_port_power(ehci, 1);
-
-	ehci->rh_state = EHCI_RH_SUSPENDED;
-
+	ehci_resume(hcd, false);
 	return 0;
 	return 0;
 }
 }
 #else
 #else
@@ -303,6 +267,14 @@ static const struct dev_pm_ops s5p_ehci_pm_ops = {
 	.resume		= s5p_ehci_resume,
 	.resume		= s5p_ehci_resume,
 };
 };
 
 
+#ifdef CONFIG_OF
+static const struct of_device_id exynos_ehci_match[] = {
+	{ .compatible = "samsung,exynos-ehci" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, exynos_ehci_match);
+#endif
+
 static struct platform_driver s5p_ehci_driver = {
 static struct platform_driver s5p_ehci_driver = {
 	.probe		= s5p_ehci_probe,
 	.probe		= s5p_ehci_probe,
 	.remove		= __devexit_p(s5p_ehci_remove),
 	.remove		= __devexit_p(s5p_ehci_remove),
@@ -311,6 +283,7 @@ static struct platform_driver s5p_ehci_driver = {
 		.name	= "s5p-ehci",
 		.name	= "s5p-ehci",
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
 		.pm	= &s5p_ehci_pm_ops,
 		.pm	= &s5p_ehci_pm_ops,
+		.of_match_table = of_match_ptr(exynos_ehci_match),
 	}
 	}
 };
 };
 
 

+ 195 - 357
drivers/usb/host/ehci-sched.c

@@ -479,70 +479,26 @@ static int tt_no_collision (
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-static int enable_periodic (struct ehci_hcd *ehci)
+static void enable_periodic(struct ehci_hcd *ehci)
 {
 {
-	int	status;
-
-	if (ehci->periodic_sched++)
-		return 0;
-
-	/* did clearing PSE did take effect yet?
-	 * takes effect only at frame boundaries...
-	 */
-	status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
-					     STS_PSS, 0, 9 * 125);
-	if (status) {
-		usb_hc_died(ehci_to_hcd(ehci));
-		return status;
-	}
+	if (ehci->periodic_count++)
+		return;
 
 
-	ehci->command |= CMD_PSE;
-	ehci_writel(ehci, ehci->command, &ehci->regs->command);
-	/* posted write ... PSS happens later */
+	/* Stop waiting to turn off the periodic schedule */
+	ehci->enabled_hrtimer_events &= ~BIT(EHCI_HRTIMER_DISABLE_PERIODIC);
 
 
-	/* make sure ehci_work scans these */
-	ehci->next_uframe = ehci_read_frame_index(ehci)
-		% (ehci->periodic_size << 3);
-	if (unlikely(ehci->broken_periodic))
-		ehci->last_periodic_enable = ktime_get_real();
-	return 0;
+	/* Don't start the schedule until PSS is 0 */
+	ehci_poll_PSS(ehci);
+	turn_on_io_watchdog(ehci);
 }
 }
 
 
-static int disable_periodic (struct ehci_hcd *ehci)
+static void disable_periodic(struct ehci_hcd *ehci)
 {
 {
-	int	status;
-
-	if (--ehci->periodic_sched)
-		return 0;
-
-	if (unlikely(ehci->broken_periodic)) {
-		/* delay experimentally determined */
-		ktime_t safe = ktime_add_us(ehci->last_periodic_enable, 1000);
-		ktime_t now = ktime_get_real();
-		s64 delay = ktime_us_delta(safe, now);
-
-		if (unlikely(delay > 0))
-			udelay(delay);
-	}
-
-	/* did setting PSE not take effect yet?
-	 * takes effect only at frame boundaries...
-	 */
-	status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
-					     STS_PSS, STS_PSS, 9 * 125);
-	if (status) {
-		usb_hc_died(ehci_to_hcd(ehci));
-		return status;
-	}
-
-	ehci->command &= ~CMD_PSE;
-	ehci_writel(ehci, ehci->command, &ehci->regs->command);
-	/* posted write ... */
-
-	free_cached_lists(ehci);
+	if (--ehci->periodic_count)
+		return;
 
 
-	ehci->next_uframe = -1;
-	return 0;
+	/* Don't turn off the schedule until PSS is 1 */
+	ehci_poll_PSS(ehci);
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -553,7 +509,7 @@ static int disable_periodic (struct ehci_hcd *ehci)
  * this just links in a qh; caller guarantees uframe masks are set right.
  * this just links in a qh; caller guarantees uframe masks are set right.
  * no FSTN support (yet; ehci 0.96+)
  * no FSTN support (yet; ehci 0.96+)
  */
  */
-static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
+static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
 {
 	unsigned	i;
 	unsigned	i;
 	unsigned	period = qh->period;
 	unsigned	period = qh->period;
@@ -606,28 +562,38 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
 	}
 	}
 	qh->qh_state = QH_STATE_LINKED;
 	qh->qh_state = QH_STATE_LINKED;
 	qh->xacterrs = 0;
 	qh->xacterrs = 0;
-	qh_get (qh);
 
 
 	/* update per-qh bandwidth for usbfs */
 	/* update per-qh bandwidth for usbfs */
 	ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->period
 	ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->period
 		? ((qh->usecs + qh->c_usecs) / qh->period)
 		? ((qh->usecs + qh->c_usecs) / qh->period)
 		: (qh->usecs * 8);
 		: (qh->usecs * 8);
 
 
+	list_add(&qh->intr_node, &ehci->intr_qh_list);
+
 	/* maybe enable periodic schedule processing */
 	/* maybe enable periodic schedule processing */
-	return enable_periodic(ehci);
+	++ehci->intr_count;
+	enable_periodic(ehci);
 }
 }
 
 
-static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
+static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
 {
 	unsigned	i;
 	unsigned	i;
 	unsigned	period;
 	unsigned	period;
 
 
-	// FIXME:
-	// IF this isn't high speed
-	//   and this qh is active in the current uframe
-	//   (and overlay token SplitXstate is false?)
-	// THEN
-	//   qh->hw_info1 |= cpu_to_hc32(1 << 7 /* "ignore" */);
+	/*
+	 * If qh is for a low/full-speed device, simply unlinking it
+	 * could interfere with an ongoing split transaction.  To unlink
+	 * it safely would require setting the QH_INACTIVATE bit and
+	 * waiting at least one frame, as described in EHCI 4.12.2.5.
+	 *
+	 * We won't bother with any of this.  Instead, we assume that the
+	 * only reason for unlinking an interrupt QH while the current URB
+	 * is still active is to dequeue all the URBs (flush the whole
+	 * endpoint queue).
+	 *
+	 * If rebalancing the periodic schedule is ever implemented, this
+	 * approach will no longer be valid.
+	 */
 
 
 	/* high bandwidth, or otherwise part of every microframe */
 	/* high bandwidth, or otherwise part of every microframe */
 	if ((period = qh->period) == 0)
 	if ((period = qh->period) == 0)
@@ -650,18 +616,15 @@ static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
 	/* qh->qh_next still "live" to HC */
 	/* qh->qh_next still "live" to HC */
 	qh->qh_state = QH_STATE_UNLINK;
 	qh->qh_state = QH_STATE_UNLINK;
 	qh->qh_next.ptr = NULL;
 	qh->qh_next.ptr = NULL;
-	qh_put (qh);
 
 
-	/* maybe turn off periodic schedule */
-	return disable_periodic(ehci);
+	if (ehci->qh_scan_next == qh)
+		ehci->qh_scan_next = list_entry(qh->intr_node.next,
+				struct ehci_qh, intr_node);
+	list_del(&qh->intr_node);
 }
 }
 
 
-static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
+static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
 {
-	unsigned		wait;
-	struct ehci_qh_hw	*hw = qh->hw;
-	int			rc;
-
 	/* If the QH isn't linked then there's nothing we can do
 	/* If the QH isn't linked then there's nothing we can do
 	 * unless we were called during a giveback, in which case
 	 * unless we were called during a giveback, in which case
 	 * qh_completions() has to deal with it.
 	 * qh_completions() has to deal with it.
@@ -674,28 +637,45 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
 
 	qh_unlink_periodic (ehci, qh);
 	qh_unlink_periodic (ehci, qh);
 
 
-	/* simple/paranoid:  always delay, expecting the HC needs to read
-	 * qh->hw_next or finish a writeback after SPLIT/CSPLIT ... and
-	 * expect khubd to clean up after any CSPLITs we won't issue.
-	 * active high speed queues may need bigger delays...
+	/* Make sure the unlinks are visible before starting the timer */
+	wmb();
+
+	/*
+	 * The EHCI spec doesn't say how long it takes the controller to
+	 * stop accessing an unlinked interrupt QH.  The timer delay is
+	 * 9 uframes; presumably that will be long enough.
 	 */
 	 */
-	if (list_empty (&qh->qtd_list)
-			|| (cpu_to_hc32(ehci, QH_CMASK)
-					& hw->hw_info2) != 0)
-		wait = 2;
+	qh->unlink_cycle = ehci->intr_unlink_cycle;
+
+	/* New entries go at the end of the intr_unlink list */
+	if (ehci->intr_unlink)
+		ehci->intr_unlink_last->unlink_next = qh;
 	else
 	else
-		wait = 55;	/* worst case: 3 * 1024 */
+		ehci->intr_unlink = qh;
+	ehci->intr_unlink_last = qh;
+
+	if (ehci->intr_unlinking)
+		;	/* Avoid recursive calls */
+	else if (ehci->rh_state < EHCI_RH_RUNNING)
+		ehci_handle_intr_unlinks(ehci);
+	else if (ehci->intr_unlink == qh) {
+		ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true);
+		++ehci->intr_unlink_cycle;
+	}
+}
+
+static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	struct ehci_qh_hw	*hw = qh->hw;
+	int			rc;
 
 
-	udelay (wait);
 	qh->qh_state = QH_STATE_IDLE;
 	qh->qh_state = QH_STATE_IDLE;
 	hw->hw_next = EHCI_LIST_END(ehci);
 	hw->hw_next = EHCI_LIST_END(ehci);
-	wmb ();
 
 
 	qh_completions(ehci, qh);
 	qh_completions(ehci, qh);
 
 
 	/* reschedule QH iff another request is queued */
 	/* reschedule QH iff another request is queued */
-	if (!list_empty(&qh->qtd_list) &&
-			ehci->rh_state == EHCI_RH_RUNNING) {
+	if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) {
 		rc = qh_schedule(ehci, qh);
 		rc = qh_schedule(ehci, qh);
 
 
 		/* An error here likely indicates handshake failure
 		/* An error here likely indicates handshake failure
@@ -708,6 +688,10 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
 			ehci_err(ehci, "can't reschedule qh %p, err %d\n",
 			ehci_err(ehci, "can't reschedule qh %p, err %d\n",
 					qh, rc);
 					qh, rc);
 	}
 	}
+
+	/* maybe turn off periodic schedule */
+	--ehci->intr_count;
+	disable_periodic(ehci);
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -884,7 +868,7 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
 		ehci_dbg (ehci, "reused qh %p schedule\n", qh);
 		ehci_dbg (ehci, "reused qh %p schedule\n", qh);
 
 
 	/* stuff into the periodic schedule */
 	/* stuff into the periodic schedule */
-	status = qh_link_periodic (ehci, qh);
+	qh_link_periodic(ehci, qh);
 done:
 done:
 	return status;
 	return status;
 }
 }
@@ -944,6 +928,35 @@ done_not_linked:
 	return status;
 	return status;
 }
 }
 
 
+static void scan_intr(struct ehci_hcd *ehci)
+{
+	struct ehci_qh		*qh;
+
+	list_for_each_entry_safe(qh, ehci->qh_scan_next, &ehci->intr_qh_list,
+			intr_node) {
+ rescan:
+		/* clean any finished work for this qh */
+		if (!list_empty(&qh->qtd_list)) {
+			int temp;
+
+			/*
+			 * Unlinks could happen here; completion reporting
+			 * drops the lock.  That's why ehci->qh_scan_next
+			 * always holds the next qh to scan; if the next qh
+			 * gets unlinked then ehci->qh_scan_next is adjusted
+			 * in qh_unlink_periodic().
+			 */
+			temp = qh_completions(ehci, qh);
+			if (unlikely(qh->needs_rescan ||
+					(list_empty(&qh->qtd_list) &&
+						qh->qh_state == QH_STATE_LINKED)))
+				start_unlink_intr(ehci, qh);
+			else if (temp != 0)
+				goto rescan;
+		}
+	}
+}
+
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 /* ehci_iso_stream ops work with both ITD and SITD */
 /* ehci_iso_stream ops work with both ITD and SITD */
@@ -958,7 +971,6 @@ iso_stream_alloc (gfp_t mem_flags)
 		INIT_LIST_HEAD(&stream->td_list);
 		INIT_LIST_HEAD(&stream->td_list);
 		INIT_LIST_HEAD(&stream->free_list);
 		INIT_LIST_HEAD(&stream->free_list);
 		stream->next_uframe = -1;
 		stream->next_uframe = -1;
-		stream->refcount = 1;
 	}
 	}
 	return stream;
 	return stream;
 }
 }
@@ -1058,57 +1070,6 @@ iso_stream_init (
 	stream->maxp = maxp;
 	stream->maxp = maxp;
 }
 }
 
 
-static void
-iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream)
-{
-	stream->refcount--;
-
-	/* free whenever just a dev->ep reference remains.
-	 * not like a QH -- no persistent state (toggle, halt)
-	 */
-	if (stream->refcount == 1) {
-		// BUG_ON (!list_empty(&stream->td_list));
-
-		while (!list_empty (&stream->free_list)) {
-			struct list_head	*entry;
-
-			entry = stream->free_list.next;
-			list_del (entry);
-
-			/* knows about ITD vs SITD */
-			if (stream->highspeed) {
-				struct ehci_itd		*itd;
-
-				itd = list_entry (entry, struct ehci_itd,
-						itd_list);
-				dma_pool_free (ehci->itd_pool, itd,
-						itd->itd_dma);
-			} else {
-				struct ehci_sitd	*sitd;
-
-				sitd = list_entry (entry, struct ehci_sitd,
-						sitd_list);
-				dma_pool_free (ehci->sitd_pool, sitd,
-						sitd->sitd_dma);
-			}
-		}
-
-		stream->bEndpointAddress &= 0x0f;
-		if (stream->ep)
-			stream->ep->hcpriv = NULL;
-
-		kfree(stream);
-	}
-}
-
-static inline struct ehci_iso_stream *
-iso_stream_get (struct ehci_iso_stream *stream)
-{
-	if (likely (stream != NULL))
-		stream->refcount++;
-	return stream;
-}
-
 static struct ehci_iso_stream *
 static struct ehci_iso_stream *
 iso_stream_find (struct ehci_hcd *ehci, struct urb *urb)
 iso_stream_find (struct ehci_hcd *ehci, struct urb *urb)
 {
 {
@@ -1129,7 +1090,6 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb)
 	if (unlikely (stream == NULL)) {
 	if (unlikely (stream == NULL)) {
 		stream = iso_stream_alloc(GFP_ATOMIC);
 		stream = iso_stream_alloc(GFP_ATOMIC);
 		if (likely (stream != NULL)) {
 		if (likely (stream != NULL)) {
-			/* dev->ep owns the initial refcount */
 			ep->hcpriv = stream;
 			ep->hcpriv = stream;
 			stream->ep = ep;
 			stream->ep = ep;
 			iso_stream_init(ehci, stream, urb->dev, urb->pipe,
 			iso_stream_init(ehci, stream, urb->dev, urb->pipe,
@@ -1144,9 +1104,6 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb)
 		stream = NULL;
 		stream = NULL;
 	}
 	}
 
 
-	/* caller guarantees an eventual matching iso_stream_put */
-	stream = iso_stream_get (stream);
-
 	spin_unlock_irqrestore (&ehci->lock, flags);
 	spin_unlock_irqrestore (&ehci->lock, flags);
 	return stream;
 	return stream;
 }
 }
@@ -1254,17 +1211,19 @@ itd_urb_transaction (
 	spin_lock_irqsave (&ehci->lock, flags);
 	spin_lock_irqsave (&ehci->lock, flags);
 	for (i = 0; i < num_itds; i++) {
 	for (i = 0; i < num_itds; i++) {
 
 
-		/* free_list.next might be cache-hot ... but maybe
-		 * the HC caches it too. avoid that issue for now.
+		/*
+		 * Use iTDs from the free list, but not iTDs that may
+		 * still be in use by the hardware.
 		 */
 		 */
-
-		/* prefer previously-allocated itds */
-		if (likely (!list_empty(&stream->free_list))) {
-			itd = list_entry (stream->free_list.prev,
+		if (likely(!list_empty(&stream->free_list))) {
+			itd = list_first_entry(&stream->free_list,
 					struct ehci_itd, itd_list);
 					struct ehci_itd, itd_list);
+			if (itd->frame == ehci->now_frame)
+				goto alloc_itd;
 			list_del (&itd->itd_list);
 			list_del (&itd->itd_list);
 			itd_dma = itd->itd_dma;
 			itd_dma = itd->itd_dma;
 		} else {
 		} else {
+ alloc_itd:
 			spin_unlock_irqrestore (&ehci->lock, flags);
 			spin_unlock_irqrestore (&ehci->lock, flags);
 			itd = dma_pool_alloc (ehci->itd_pool, mem_flags,
 			itd = dma_pool_alloc (ehci->itd_pool, mem_flags,
 					&itd_dma);
 					&itd_dma);
@@ -1528,6 +1487,10 @@ iso_stream_schedule (
 	urb->start_frame = stream->next_uframe;
 	urb->start_frame = stream->next_uframe;
 	if (!stream->highspeed)
 	if (!stream->highspeed)
 		urb->start_frame >>= 3;
 		urb->start_frame >>= 3;
+
+	/* Make sure scan_isoc() sees these */
+	if (ehci->isoc_count == 0)
+		ehci->next_frame = now >> 3;
 	return 0;
 	return 0;
 
 
  fail:
  fail:
@@ -1615,8 +1578,7 @@ itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
 }
 }
 
 
 /* fit urb's itds into the selected schedule slot; activate as needed */
 /* fit urb's itds into the selected schedule slot; activate as needed */
-static int
-itd_link_urb (
+static void itd_link_urb(
 	struct ehci_hcd		*ehci,
 	struct ehci_hcd		*ehci,
 	struct urb		*urb,
 	struct urb		*urb,
 	unsigned		mod,
 	unsigned		mod,
@@ -1659,7 +1621,7 @@ itd_link_urb (
 			itd = list_entry (iso_sched->td_list.next,
 			itd = list_entry (iso_sched->td_list.next,
 					struct ehci_itd, itd_list);
 					struct ehci_itd, itd_list);
 			list_move_tail (&itd->itd_list, &stream->td_list);
 			list_move_tail (&itd->itd_list, &stream->td_list);
-			itd->stream = iso_stream_get (stream);
+			itd->stream = stream;
 			itd->urb = urb;
 			itd->urb = urb;
 			itd_init (ehci, stream, itd);
 			itd_init (ehci, stream, itd);
 		}
 		}
@@ -1686,8 +1648,8 @@ itd_link_urb (
 	iso_sched_free (stream, iso_sched);
 	iso_sched_free (stream, iso_sched);
 	urb->hcpriv = NULL;
 	urb->hcpriv = NULL;
 
 
-	timer_action (ehci, TIMER_IO_WATCHDOG);
-	return enable_periodic(ehci);
+	++ehci->isoc_count;
+	enable_periodic(ehci);
 }
 }
 
 
 #define	ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
 #define	ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
@@ -1702,11 +1664,8 @@ itd_link_urb (
  * (b) only this endpoint's completions submit URBs.  It seems some silicon
  * (b) only this endpoint's completions submit URBs.  It seems some silicon
  * corrupts things if you reuse completed descriptors very quickly...
  * corrupts things if you reuse completed descriptors very quickly...
  */
  */
-static unsigned
-itd_complete (
-	struct ehci_hcd	*ehci,
-	struct ehci_itd	*itd
-) {
+static bool itd_complete(struct ehci_hcd *ehci, struct ehci_itd *itd)
+{
 	struct urb				*urb = itd->urb;
 	struct urb				*urb = itd->urb;
 	struct usb_iso_packet_descriptor	*desc;
 	struct usb_iso_packet_descriptor	*desc;
 	u32					t;
 	u32					t;
@@ -1714,7 +1673,7 @@ itd_complete (
 	int					urb_index = -1;
 	int					urb_index = -1;
 	struct ehci_iso_stream			*stream = itd->stream;
 	struct ehci_iso_stream			*stream = itd->stream;
 	struct usb_device			*dev;
 	struct usb_device			*dev;
-	unsigned				retval = false;
+	bool					retval = false;
 
 
 	/* for each uframe with a packet */
 	/* for each uframe with a packet */
 	for (uframe = 0; uframe < 8; uframe++) {
 	for (uframe = 0; uframe < 8; uframe++) {
@@ -1767,9 +1726,11 @@ itd_complete (
 	ehci_urb_done(ehci, urb, 0);
 	ehci_urb_done(ehci, urb, 0);
 	retval = true;
 	retval = true;
 	urb = NULL;
 	urb = NULL;
-	(void) disable_periodic(ehci);
-	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
 
 
+	--ehci->isoc_count;
+	disable_periodic(ehci);
+
+	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
 	if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
 	if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
 		if (ehci->amd_pll_fix == 1)
 		if (ehci->amd_pll_fix == 1)
 			usb_amd_quirk_pll_enable();
 			usb_amd_quirk_pll_enable();
@@ -1783,28 +1744,20 @@ itd_complete (
 			dev->devpath, stream->bEndpointAddress & 0x0f,
 			dev->devpath, stream->bEndpointAddress & 0x0f,
 			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
 			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
 	}
 	}
-	iso_stream_put (ehci, stream);
 
 
 done:
 done:
 	itd->urb = NULL;
 	itd->urb = NULL;
-	if (ehci->clock_frame != itd->frame || itd->index[7] != -1) {
-		/* OK to recycle this ITD now. */
-		itd->stream = NULL;
-		list_move(&itd->itd_list, &stream->free_list);
-		iso_stream_put(ehci, stream);
-	} else {
-		/* HW might remember this ITD, so we can't recycle it yet.
-		 * Move it to a safe place until a new frame starts.
-		 */
-		list_move(&itd->itd_list, &ehci->cached_itd_list);
-		if (stream->refcount == 2) {
-			/* If iso_stream_put() were called here, stream
-			 * would be freed.  Instead, just prevent reuse.
-			 */
-			stream->ep->hcpriv = NULL;
-			stream->ep = NULL;
-		}
+
+	/* Add to the end of the free list for later reuse */
+	list_move_tail(&itd->itd_list, &stream->free_list);
+
+	/* Recycle the iTDs when the pipeline is empty (ep no longer in use) */
+	if (list_empty(&stream->td_list)) {
+		list_splice_tail_init(&stream->free_list,
+				&ehci->cached_itd_list);
+		start_free_itds(ehci);
 	}
 	}
+
 	return retval;
 	return retval;
 }
 }
 
 
@@ -1861,12 +1814,9 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
 		itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
 		itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
 	else
 	else
 		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
 		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
-done_not_linked:
+ done_not_linked:
 	spin_unlock_irqrestore (&ehci->lock, flags);
 	spin_unlock_irqrestore (&ehci->lock, flags);
-
-done:
-	if (unlikely (status < 0))
-		iso_stream_put (ehci, stream);
+ done:
 	return status;
 	return status;
 }
 }
 
 
@@ -1955,17 +1905,19 @@ sitd_urb_transaction (
 		 * means we never need two sitds for full speed packets.
 		 * means we never need two sitds for full speed packets.
 		 */
 		 */
 
 
-		/* free_list.next might be cache-hot ... but maybe
-		 * the HC caches it too. avoid that issue for now.
+		/*
+		 * Use siTDs from the free list, but not siTDs that may
+		 * still be in use by the hardware.
 		 */
 		 */
-
-		/* prefer previously-allocated sitds */
-		if (!list_empty(&stream->free_list)) {
-			sitd = list_entry (stream->free_list.prev,
+		if (likely(!list_empty(&stream->free_list))) {
+			sitd = list_first_entry(&stream->free_list,
 					 struct ehci_sitd, sitd_list);
 					 struct ehci_sitd, sitd_list);
+			if (sitd->frame == ehci->now_frame)
+				goto alloc_sitd;
 			list_del (&sitd->sitd_list);
 			list_del (&sitd->sitd_list);
 			sitd_dma = sitd->sitd_dma;
 			sitd_dma = sitd->sitd_dma;
 		} else {
 		} else {
+ alloc_sitd:
 			spin_unlock_irqrestore (&ehci->lock, flags);
 			spin_unlock_irqrestore (&ehci->lock, flags);
 			sitd = dma_pool_alloc (ehci->sitd_pool, mem_flags,
 			sitd = dma_pool_alloc (ehci->sitd_pool, mem_flags,
 					&sitd_dma);
 					&sitd_dma);
@@ -2034,8 +1986,7 @@ sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
 }
 }
 
 
 /* fit urb's sitds into the selected schedule slot; activate as needed */
 /* fit urb's sitds into the selected schedule slot; activate as needed */
-static int
-sitd_link_urb (
+static void sitd_link_urb(
 	struct ehci_hcd		*ehci,
 	struct ehci_hcd		*ehci,
 	struct urb		*urb,
 	struct urb		*urb,
 	unsigned		mod,
 	unsigned		mod,
@@ -2081,7 +2032,7 @@ sitd_link_urb (
 		sitd = list_entry (sched->td_list.next,
 		sitd = list_entry (sched->td_list.next,
 				struct ehci_sitd, sitd_list);
 				struct ehci_sitd, sitd_list);
 		list_move_tail (&sitd->sitd_list, &stream->td_list);
 		list_move_tail (&sitd->sitd_list, &stream->td_list);
-		sitd->stream = iso_stream_get (stream);
+		sitd->stream = stream;
 		sitd->urb = urb;
 		sitd->urb = urb;
 
 
 		sitd_patch(ehci, stream, sitd, sched, packet);
 		sitd_patch(ehci, stream, sitd, sched, packet);
@@ -2096,8 +2047,8 @@ sitd_link_urb (
 	iso_sched_free (stream, sched);
 	iso_sched_free (stream, sched);
 	urb->hcpriv = NULL;
 	urb->hcpriv = NULL;
 
 
-	timer_action (ehci, TIMER_IO_WATCHDOG);
-	return enable_periodic(ehci);
+	++ehci->isoc_count;
+	enable_periodic(ehci);
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -2115,18 +2066,15 @@ sitd_link_urb (
  * (b) only this endpoint's completions submit URBs.  It seems some silicon
  * (b) only this endpoint's completions submit URBs.  It seems some silicon
  * corrupts things if you reuse completed descriptors very quickly...
  * corrupts things if you reuse completed descriptors very quickly...
  */
  */
-static unsigned
-sitd_complete (
-	struct ehci_hcd		*ehci,
-	struct ehci_sitd	*sitd
-) {
+static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd)
+{
 	struct urb				*urb = sitd->urb;
 	struct urb				*urb = sitd->urb;
 	struct usb_iso_packet_descriptor	*desc;
 	struct usb_iso_packet_descriptor	*desc;
 	u32					t;
 	u32					t;
 	int					urb_index = -1;
 	int					urb_index = -1;
 	struct ehci_iso_stream			*stream = sitd->stream;
 	struct ehci_iso_stream			*stream = sitd->stream;
 	struct usb_device			*dev;
 	struct usb_device			*dev;
-	unsigned				retval = false;
+	bool					retval = false;
 
 
 	urb_index = sitd->index;
 	urb_index = sitd->index;
 	desc = &urb->iso_frame_desc [urb_index];
 	desc = &urb->iso_frame_desc [urb_index];
@@ -2163,9 +2111,11 @@ sitd_complete (
 	ehci_urb_done(ehci, urb, 0);
 	ehci_urb_done(ehci, urb, 0);
 	retval = true;
 	retval = true;
 	urb = NULL;
 	urb = NULL;
-	(void) disable_periodic(ehci);
-	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
 
 
+	--ehci->isoc_count;
+	disable_periodic(ehci);
+
+	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
 	if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
 	if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
 		if (ehci->amd_pll_fix == 1)
 		if (ehci->amd_pll_fix == 1)
 			usb_amd_quirk_pll_enable();
 			usb_amd_quirk_pll_enable();
@@ -2179,28 +2129,20 @@ sitd_complete (
 			dev->devpath, stream->bEndpointAddress & 0x0f,
 			dev->devpath, stream->bEndpointAddress & 0x0f,
 			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
 			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
 	}
 	}
-	iso_stream_put (ehci, stream);
 
 
 done:
 done:
 	sitd->urb = NULL;
 	sitd->urb = NULL;
-	if (ehci->clock_frame != sitd->frame) {
-		/* OK to recycle this SITD now. */
-		sitd->stream = NULL;
-		list_move(&sitd->sitd_list, &stream->free_list);
-		iso_stream_put(ehci, stream);
-	} else {
-		/* HW might remember this SITD, so we can't recycle it yet.
-		 * Move it to a safe place until a new frame starts.
-		 */
-		list_move(&sitd->sitd_list, &ehci->cached_sitd_list);
-		if (stream->refcount == 2) {
-			/* If iso_stream_put() were called here, stream
-			 * would be freed.  Instead, just prevent reuse.
-			 */
-			stream->ep->hcpriv = NULL;
-			stream->ep = NULL;
-		}
+
+	/* Add to the end of the free list for later reuse */
+	list_move_tail(&sitd->sitd_list, &stream->free_list);
+
+	/* Recycle the siTDs when the pipeline is empty (ep no longer in use) */
+	if (list_empty(&stream->td_list)) {
+		list_splice_tail_init(&stream->free_list,
+				&ehci->cached_sitd_list);
+		start_free_itds(ehci);
 	}
 	}
+
 	return retval;
 	return retval;
 }
 }
 
 
@@ -2254,74 +2196,39 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
 		sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
 		sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
 	else
 	else
 		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
 		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
-done_not_linked:
+ done_not_linked:
 	spin_unlock_irqrestore (&ehci->lock, flags);
 	spin_unlock_irqrestore (&ehci->lock, flags);
-
-done:
-	if (status < 0)
-		iso_stream_put (ehci, stream);
+ done:
 	return status;
 	return status;
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-static void free_cached_lists(struct ehci_hcd *ehci)
+static void scan_isoc(struct ehci_hcd *ehci)
 {
 {
-	struct ehci_itd *itd, *n;
-	struct ehci_sitd *sitd, *sn;
-
-	list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) {
-		struct ehci_iso_stream	*stream = itd->stream;
-		itd->stream = NULL;
-		list_move(&itd->itd_list, &stream->free_list);
-		iso_stream_put(ehci, stream);
-	}
-
-	list_for_each_entry_safe(sitd, sn, &ehci->cached_sitd_list, sitd_list) {
-		struct ehci_iso_stream	*stream = sitd->stream;
-		sitd->stream = NULL;
-		list_move(&sitd->sitd_list, &stream->free_list);
-		iso_stream_put(ehci, stream);
-	}
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void
-scan_periodic (struct ehci_hcd *ehci)
-{
-	unsigned	now_uframe, frame, clock, clock_frame, mod;
-	unsigned	modified;
-
-	mod = ehci->periodic_size << 3;
+	unsigned	uf, now_frame, frame;
+	unsigned	fmask = ehci->periodic_size - 1;
+	bool		modified, live;
 
 
 	/*
 	/*
 	 * When running, scan from last scan point up to "now"
 	 * When running, scan from last scan point up to "now"
 	 * else clean up by scanning everything that's left.
 	 * else clean up by scanning everything that's left.
 	 * Touches as few pages as possible:  cache-friendly.
 	 * Touches as few pages as possible:  cache-friendly.
 	 */
 	 */
-	now_uframe = ehci->next_uframe;
-	if (ehci->rh_state == EHCI_RH_RUNNING) {
-		clock = ehci_read_frame_index(ehci);
-		clock_frame = (clock >> 3) & (ehci->periodic_size - 1);
+	if (ehci->rh_state >= EHCI_RH_RUNNING) {
+		uf = ehci_read_frame_index(ehci);
+		now_frame = (uf >> 3) & fmask;
+		live = true;
 	} else  {
 	} else  {
-		clock = now_uframe + mod - 1;
-		clock_frame = -1;
+		now_frame = (ehci->next_frame - 1) & fmask;
+		live = false;
 	}
 	}
-	if (ehci->clock_frame != clock_frame) {
-		free_cached_lists(ehci);
-		ehci->clock_frame = clock_frame;
-	}
-	clock &= mod - 1;
-	clock_frame = clock >> 3;
-	++ehci->periodic_stamp;
+	ehci->now_frame = now_frame;
 
 
+	frame = ehci->next_frame;
 	for (;;) {
 	for (;;) {
 		union ehci_shadow	q, *q_p;
 		union ehci_shadow	q, *q_p;
 		__hc32			type, *hw_p;
 		__hc32			type, *hw_p;
-		unsigned		incomplete = false;
-
-		frame = now_uframe >> 3;
 
 
 restart:
 restart:
 		/* scan each element in frame's queue for completions */
 		/* scan each element in frame's queue for completions */
@@ -2329,48 +2236,17 @@ restart:
 		hw_p = &ehci->periodic [frame];
 		hw_p = &ehci->periodic [frame];
 		q.ptr = q_p->ptr;
 		q.ptr = q_p->ptr;
 		type = Q_NEXT_TYPE(ehci, *hw_p);
 		type = Q_NEXT_TYPE(ehci, *hw_p);
-		modified = 0;
+		modified = false;
 
 
 		while (q.ptr != NULL) {
 		while (q.ptr != NULL) {
-			unsigned		uf;
-			union ehci_shadow	temp;
-			int			live;
-
-			live = (ehci->rh_state == EHCI_RH_RUNNING);
 			switch (hc32_to_cpu(ehci, type)) {
 			switch (hc32_to_cpu(ehci, type)) {
-			case Q_TYPE_QH:
-				/* handle any completions */
-				temp.qh = qh_get (q.qh);
-				type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next);
-				q = q.qh->qh_next;
-				if (temp.qh->stamp != ehci->periodic_stamp) {
-					modified = qh_completions(ehci, temp.qh);
-					if (!modified)
-						temp.qh->stamp = ehci->periodic_stamp;
-					if (unlikely(list_empty(&temp.qh->qtd_list) ||
-							temp.qh->needs_rescan))
-						intr_deschedule(ehci, temp.qh);
-				}
-				qh_put (temp.qh);
-				break;
-			case Q_TYPE_FSTN:
-				/* for "save place" FSTNs, look at QH entries
-				 * in the previous frame for completions.
-				 */
-				if (q.fstn->hw_prev != EHCI_LIST_END(ehci)) {
-					ehci_dbg(ehci,
-						"ignoring completions from FSTNs\n");
-				}
-				type = Q_NEXT_TYPE(ehci, q.fstn->hw_next);
-				q = q.fstn->fstn_next;
-				break;
 			case Q_TYPE_ITD:
 			case Q_TYPE_ITD:
 				/* If this ITD is still active, leave it for
 				/* If this ITD is still active, leave it for
 				 * later processing ... check the next entry.
 				 * later processing ... check the next entry.
 				 * No need to check for activity unless the
 				 * No need to check for activity unless the
 				 * frame is current.
 				 * frame is current.
 				 */
 				 */
-				if (frame == clock_frame && live) {
+				if (frame == now_frame && live) {
 					rmb();
 					rmb();
 					for (uf = 0; uf < 8; uf++) {
 					for (uf = 0; uf < 8; uf++) {
 						if (q.itd->hw_transaction[uf] &
 						if (q.itd->hw_transaction[uf] &
@@ -2378,7 +2254,6 @@ restart:
 							break;
 							break;
 					}
 					}
 					if (uf < 8) {
 					if (uf < 8) {
-						incomplete = true;
 						q_p = &q.itd->itd_next;
 						q_p = &q.itd->itd_next;
 						hw_p = &q.itd->hw_next;
 						hw_p = &q.itd->hw_next;
 						type = Q_NEXT_TYPE(ehci,
 						type = Q_NEXT_TYPE(ehci,
@@ -2410,14 +2285,12 @@ restart:
 				 * No need to check for activity unless the
 				 * No need to check for activity unless the
 				 * frame is current.
 				 * frame is current.
 				 */
 				 */
-				if (((frame == clock_frame) ||
-				     (((frame + 1) & (ehci->periodic_size - 1))
-				      == clock_frame))
+				if (((frame == now_frame) ||
+				     (((frame + 1) & fmask) == now_frame))
 				    && live
 				    && live
 				    && (q.sitd->hw_results &
 				    && (q.sitd->hw_results &
 					SITD_ACTIVE(ehci))) {
 					SITD_ACTIVE(ehci))) {
 
 
-					incomplete = true;
 					q_p = &q.sitd->sitd_next;
 					q_p = &q.sitd->sitd_next;
 					hw_p = &q.sitd->hw_next;
 					hw_p = &q.sitd->hw_next;
 					type = Q_NEXT_TYPE(ehci,
 					type = Q_NEXT_TYPE(ehci,
@@ -2445,58 +2318,23 @@ restart:
 				ehci_dbg(ehci, "corrupt type %d frame %d shadow %p\n",
 				ehci_dbg(ehci, "corrupt type %d frame %d shadow %p\n",
 					type, frame, q.ptr);
 					type, frame, q.ptr);
 				// BUG ();
 				// BUG ();
+				/* FALL THROUGH */
+			case Q_TYPE_QH:
+			case Q_TYPE_FSTN:
+				/* End of the iTDs and siTDs */
 				q.ptr = NULL;
 				q.ptr = NULL;
+				break;
 			}
 			}
 
 
 			/* assume completion callbacks modify the queue */
 			/* assume completion callbacks modify the queue */
-			if (unlikely (modified)) {
-				if (likely(ehci->periodic_sched > 0))
-					goto restart;
-				/* short-circuit this scan */
-				now_uframe = clock;
-				break;
-			}
+			if (unlikely(modified && ehci->isoc_count > 0))
+				goto restart;
 		}
 		}
 
 
-		/* If we can tell we caught up to the hardware, stop now.
-		 * We can't advance our scan without collecting the ISO
-		 * transfers that are still pending in this frame.
-		 */
-		if (incomplete && ehci->rh_state == EHCI_RH_RUNNING) {
-			ehci->next_uframe = now_uframe;
+		/* Stop when we have reached the current frame */
+		if (frame == now_frame)
 			break;
 			break;
-		}
-
-		// FIXME:  this assumes we won't get lapped when
-		// latencies climb; that should be rare, but...
-		// detect it, and just go all the way around.
-		// FLR might help detect this case, so long as latencies
-		// don't exceed periodic_size msec (default 1.024 sec).
-
-		// FIXME:  likewise assumes HC doesn't halt mid-scan
-
-		if (now_uframe == clock) {
-			unsigned	now;
-
-			if (ehci->rh_state != EHCI_RH_RUNNING
-					|| ehci->periodic_sched == 0)
-				break;
-			ehci->next_uframe = now_uframe;
-			now = ehci_read_frame_index(ehci) & (mod - 1);
-			if (now_uframe == now)
-				break;
-
-			/* rescan the rest of this frame, then ... */
-			clock = now;
-			clock_frame = clock >> 3;
-			if (ehci->clock_frame != clock_frame) {
-				free_cached_lists(ehci);
-				ehci->clock_frame = clock_frame;
-				++ehci->periodic_stamp;
-			}
-		} else {
-			now_uframe++;
-			now_uframe &= mod - 1;
-		}
+		frame = (frame + 1) & fmask;
 	}
 	}
+	ehci->next_frame = now_frame;
 }
 }

+ 3 - 71
drivers/usb/host/ehci-sead3.c

@@ -160,84 +160,16 @@ static int ehci_hcd_sead3_drv_remove(struct platform_device *pdev)
 static int ehci_hcd_sead3_drv_suspend(struct device *dev)
 static int ehci_hcd_sead3_drv_suspend(struct device *dev)
 {
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
-	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-	unsigned long flags;
-	int rc = 0;
-
-	if (time_before(jiffies, ehci->next_statechange))
-		msleep(20);
-
-	/* Root hub was already suspended. Disable irq emission and
-	 * mark HW unaccessible.  The PM and USB cores make sure that
-	 * the root hub is either suspended or stopped.
-	 */
-	ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
-	spin_lock_irqsave(&ehci->lock, flags);
-	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
-	(void)ehci_readl(ehci, &ehci->regs->intr_enable);
-
-	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-	spin_unlock_irqrestore(&ehci->lock, flags);
+	bool do_wakeup = device_may_wakeup(dev);
 
 
-	/* could save FLADJ in case of Vaux power loss
-	 * ... we'd only use it to handle clock skew
-	 */
-
-	return rc;
+	return ehci_suspend(hcd, do_wakeup);
 }
 }
 
 
 static int ehci_hcd_sead3_drv_resume(struct device *dev)
 static int ehci_hcd_sead3_drv_resume(struct device *dev)
 {
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
-	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-
-	/* maybe restore FLADJ. */
-
-	if (time_before(jiffies, ehci->next_statechange))
-		msleep(100);
-
-	/* Mark hardware accessible again as we are out of D3 state by now */
-	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
-	/* If CF is still set, we maintained PCI Vaux power.
-	 * Just undo the effect of ehci_pci_suspend().
-	 */
-	if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
-		int	mask = INTR_MASK;
-
-		ehci_prepare_ports_for_controller_resume(ehci);
-		if (!hcd->self.root_hub->do_remote_wakeup)
-			mask &= ~STS_PCD;
-		ehci_writel(ehci, mask, &ehci->regs->intr_enable);
-		ehci_readl(ehci, &ehci->regs->intr_enable);
-		return 0;
-	}
-
-	ehci_dbg(ehci, "lost power, restarting\n");
-	usb_root_hub_lost_power(hcd->self.root_hub);
-
-	/* Else reset, to cope with power loss or flush-to-storage
-	 * style "resume" having let BIOS kick in during reboot.
-	 */
-	(void) ehci_halt(ehci);
-	(void) ehci_reset(ehci);
-
-	/* emptying the schedule aborts any urbs */
-	spin_lock_irq(&ehci->lock);
-	if (ehci->reclaim)
-		end_unlink_async(ehci);
-	ehci_work(ehci);
-	spin_unlock_irq(&ehci->lock);
-
-	ehci_writel(ehci, ehci->command, &ehci->regs->command);
-	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
-	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
-
-	/* here we "know" root ports should always stay powered */
-	ehci_port_power(ehci, 1);
-
-	ehci->rh_state = EHCI_RH_SUSPENDED;
 
 
+	ehci_resume(hcd, false);
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 15
drivers/usb/host/ehci-sh.c

@@ -24,25 +24,11 @@ static int ehci_sh_reset(struct usb_hcd *hcd)
 	int ret;
 	int ret;
 
 
 	ehci->caps = hcd->regs;
 	ehci->caps = hcd->regs;
-	ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
-		&ehci->caps->hc_capbase));
 
 
-	dbg_hcs_params(ehci, "reset");
-	dbg_hcc_params(ehci, "reset");
-
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-
-	ret = ehci_halt(ehci);
-	if (unlikely(ret))
-		return ret;
-
-	ret = ehci_init(hcd);
+	ret = ehci_setup(hcd);
 	if (unlikely(ret))
 	if (unlikely(ret))
 		return ret;
 		return ret;
 
 
-	ehci->sbrn = 0x20;
-
-	ehci_reset(ehci);
 	ehci_port_power(ehci, 0);
 	ehci_port_power(ehci, 0);
 
 
 	return ret;
 	return ret;

+ 4 - 67
drivers/usb/host/ehci-spear.c

@@ -41,19 +41,11 @@ static int ehci_spear_setup(struct usb_hcd *hcd)
 
 
 	/* registers start at offset 0x0 */
 	/* registers start at offset 0x0 */
 	ehci->caps = hcd->regs;
 	ehci->caps = hcd->regs;
-	ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
-				&ehci->caps->hc_capbase));
-	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-	retval = ehci_halt(ehci);
-	if (retval)
-		return retval;
 
 
-	retval = ehci_init(hcd);
+	retval = ehci_setup(hcd);
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 
 
-	ehci_reset(ehci);
 	ehci_port_power(ehci, 0);
 	ehci_port_power(ehci, 0);
 
 
 	return retval;
 	return retval;
@@ -97,71 +89,16 @@ static const struct hc_driver ehci_spear_hc_driver = {
 static int ehci_spear_drv_suspend(struct device *dev)
 static int ehci_spear_drv_suspend(struct device *dev)
 {
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
-	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-	unsigned long flags;
-	int rc = 0;
+	bool do_wakeup = device_may_wakeup(dev);
 
 
-	if (time_before(jiffies, ehci->next_statechange))
-		msleep(10);
-
-	/*
-	 * Root hub was already suspended. Disable irq emission and mark HW
-	 * unaccessible. The PM and USB cores make sure that the root hub is
-	 * either suspended or stopped.
-	 */
-	spin_lock_irqsave(&ehci->lock, flags);
-	ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
-	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
-	ehci_readl(ehci, &ehci->regs->intr_enable);
-	spin_unlock_irqrestore(&ehci->lock, flags);
-
-	return rc;
+	return ehci_suspend(hcd, do_wakeup);
 }
 }
 
 
 static int ehci_spear_drv_resume(struct device *dev)
 static int ehci_spear_drv_resume(struct device *dev)
 {
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
-	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-
-	if (time_before(jiffies, ehci->next_statechange))
-		msleep(100);
-
-	if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
-		int mask = INTR_MASK;
-
-		ehci_prepare_ports_for_controller_resume(ehci);
-
-		if (!hcd->self.root_hub->do_remote_wakeup)
-			mask &= ~STS_PCD;
-
-		ehci_writel(ehci, mask, &ehci->regs->intr_enable);
-		ehci_readl(ehci, &ehci->regs->intr_enable);
-		return 0;
-	}
-
-	usb_root_hub_lost_power(hcd->self.root_hub);
-
-	/*
-	 * Else reset, to cope with power loss or flush-to-storage style
-	 * "resume" having let BIOS kick in during reboot.
-	 */
-	ehci_halt(ehci);
-	ehci_reset(ehci);
-
-	/* emptying the schedule aborts any urbs */
-	spin_lock_irq(&ehci->lock);
-	if (ehci->reclaim)
-		end_unlink_async(ehci);
-
-	ehci_work(ehci);
-	spin_unlock_irq(&ehci->lock);
-
-	ehci_writel(ehci, ehci->command, &ehci->regs->command);
-	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
-	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
 
 
-	/* here we "know" root ports should always stay powered */
-	ehci_port_power(ehci, 1);
+	ehci_resume(hcd, false);
 	return 0;
 	return 0;
 }
 }
 #endif /* CONFIG_PM */
 #endif /* CONFIG_PM */

+ 10 - 26
drivers/usb/host/ehci-tegra.c

@@ -17,6 +17,7 @@
  */
  */
 
 
 #include <linux/clk.h>
 #include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/platform_data/tegra_usb.h>
 #include <linux/platform_data/tegra_usb.h>
 #include <linux/irq.h>
 #include <linux/irq.h>
@@ -280,30 +281,14 @@ static int tegra_ehci_setup(struct usb_hcd *hcd)
 
 
 	/* EHCI registers start at offset 0x100 */
 	/* EHCI registers start at offset 0x100 */
 	ehci->caps = hcd->regs + 0x100;
 	ehci->caps = hcd->regs + 0x100;
-	ehci->regs = hcd->regs + 0x100 +
-		HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
-
-	dbg_hcs_params(ehci, "reset");
-	dbg_hcc_params(ehci, "reset");
-
-	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = readl(&ehci->caps->hcs_params);
 
 
 	/* switch to host mode */
 	/* switch to host mode */
 	hcd->has_tt = 1;
 	hcd->has_tt = 1;
-	ehci_reset(ehci);
-
-	retval = ehci_halt(ehci);
-	if (retval)
-		return retval;
 
 
-	/* data structure init */
-	retval = ehci_init(hcd);
+	retval = ehci_setup(hcd);
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 
 
-	ehci->sbrn = 0x20;
-
 	ehci_port_power(ehci, 1);
 	ehci_port_power(ehci, 1);
 	return retval;
 	return retval;
 }
 }
@@ -460,12 +445,11 @@ static int controller_suspend(struct device *dev)
 	if (time_before(jiffies, ehci->next_statechange))
 	if (time_before(jiffies, ehci->next_statechange))
 		msleep(10);
 		msleep(10);
 
 
-	spin_lock_irqsave(&ehci->lock, flags);
+	ehci_halt(ehci);
 
 
+	spin_lock_irqsave(&ehci->lock, flags);
 	tegra->port_speed = (readl(&hw->port_status[0]) >> 26) & 0x3;
 	tegra->port_speed = (readl(&hw->port_status[0]) >> 26) & 0x3;
-	ehci_halt(ehci);
 	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
 	spin_unlock_irqrestore(&ehci->lock, flags);
 	spin_unlock_irqrestore(&ehci->lock, flags);
 
 
 	tegra_ehci_power_down(hcd);
 	tegra_ehci_power_down(hcd);
@@ -749,8 +733,8 @@ static int tegra_ehci_probe(struct platform_device *pdev)
 
 
 #ifdef CONFIG_USB_OTG_UTILS
 #ifdef CONFIG_USB_OTG_UTILS
 	if (pdata->operating_mode == TEGRA_USB_OTG) {
 	if (pdata->operating_mode == TEGRA_USB_OTG) {
-		tegra->transceiver = usb_get_transceiver();
-		if (tegra->transceiver)
+		tegra->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+		if (!IS_ERR_OR_NULL(tegra->transceiver))
 			otg_set_host(tegra->transceiver->otg, &hcd->self);
 			otg_set_host(tegra->transceiver->otg, &hcd->self);
 	}
 	}
 #endif
 #endif
@@ -773,9 +757,9 @@ static int tegra_ehci_probe(struct platform_device *pdev)
 
 
 fail:
 fail:
 #ifdef CONFIG_USB_OTG_UTILS
 #ifdef CONFIG_USB_OTG_UTILS
-	if (tegra->transceiver) {
+	if (!IS_ERR_OR_NULL(tegra->transceiver)) {
 		otg_set_host(tegra->transceiver->otg, NULL);
 		otg_set_host(tegra->transceiver->otg, NULL);
-		usb_put_transceiver(tegra->transceiver);
+		usb_put_phy(tegra->transceiver);
 	}
 	}
 #endif
 #endif
 	tegra_usb_phy_close(tegra->phy);
 	tegra_usb_phy_close(tegra->phy);
@@ -808,9 +792,9 @@ static int tegra_ehci_remove(struct platform_device *pdev)
 	pm_runtime_put_noidle(&pdev->dev);
 	pm_runtime_put_noidle(&pdev->dev);
 
 
 #ifdef CONFIG_USB_OTG_UTILS
 #ifdef CONFIG_USB_OTG_UTILS
-	if (tegra->transceiver) {
+	if (!IS_ERR_OR_NULL(tegra->transceiver)) {
 		otg_set_host(tegra->transceiver->otg, NULL);
 		otg_set_host(tegra->transceiver->otg, NULL);
-		usb_put_transceiver(tegra->transceiver);
+		usb_put_phy(tegra->transceiver);
 	}
 	}
 #endif
 #endif
 
 

+ 401 - 0
drivers/usb/host/ehci-timer.c

@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2012 by Alan Stern
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/* This file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/* Set a bit in the USBCMD register */
+static void ehci_set_command_bit(struct ehci_hcd *ehci, u32 bit)
+{
+	ehci->command |= bit;
+	ehci_writel(ehci, ehci->command, &ehci->regs->command);
+
+	/* unblock posted write */
+	ehci_readl(ehci, &ehci->regs->command);
+}
+
+/* Clear a bit in the USBCMD register */
+static void ehci_clear_command_bit(struct ehci_hcd *ehci, u32 bit)
+{
+	ehci->command &= ~bit;
+	ehci_writel(ehci, ehci->command, &ehci->regs->command);
+
+	/* unblock posted write */
+	ehci_readl(ehci, &ehci->regs->command);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI timer support...  Now using hrtimers.
+ *
+ * Lots of different events are triggered from ehci->hrtimer.  Whenever
+ * the timer routine runs, it checks each possible event; events that are
+ * currently enabled and whose expiration time has passed get handled.
+ * The set of enabled events is stored as a collection of bitflags in
+ * ehci->enabled_hrtimer_events, and they are numbered in order of
+ * increasing delay values (ranging between 1 ms and 100 ms).
+ *
+ * Rather than implementing a sorted list or tree of all pending events,
+ * we keep track only of the lowest-numbered pending event, in
+ * ehci->next_hrtimer_event.  Whenever ehci->hrtimer gets restarted, its
+ * expiration time is set to the timeout value for this event.
+ *
+ * As a result, events might not get handled right away; the actual delay
+ * could be anywhere up to twice the requested delay.  This doesn't
+ * matter, because none of the events are especially time-critical.  The
+ * ones that matter most all have a delay of 1 ms, so they will be
+ * handled after 2 ms at most, which is okay.  In addition to this, we
+ * allow for an expiration range of 1 ms.
+ */
+
+/*
+ * Delay lengths for the hrtimer event types.
+ * Keep this list sorted by delay length, in the same order as
+ * the event types indexed by enum ehci_hrtimer_event in ehci.h.
+ */
+static unsigned event_delays_ns[] = {
+	1 * NSEC_PER_MSEC,	/* EHCI_HRTIMER_POLL_ASS */
+	1 * NSEC_PER_MSEC,	/* EHCI_HRTIMER_POLL_PSS */
+	1 * NSEC_PER_MSEC,	/* EHCI_HRTIMER_POLL_DEAD */
+	1125 * NSEC_PER_USEC,	/* EHCI_HRTIMER_UNLINK_INTR */
+	2 * NSEC_PER_MSEC,	/* EHCI_HRTIMER_FREE_ITDS */
+	6 * NSEC_PER_MSEC,	/* EHCI_HRTIMER_ASYNC_UNLINKS */
+	10 * NSEC_PER_MSEC,	/* EHCI_HRTIMER_IAA_WATCHDOG */
+	10 * NSEC_PER_MSEC,	/* EHCI_HRTIMER_DISABLE_PERIODIC */
+	15 * NSEC_PER_MSEC,	/* EHCI_HRTIMER_DISABLE_ASYNC */
+	100 * NSEC_PER_MSEC,	/* EHCI_HRTIMER_IO_WATCHDOG */
+};
+
+/* Enable a pending hrtimer event */
+static void ehci_enable_event(struct ehci_hcd *ehci, unsigned event,
+		bool resched)
+{
+	ktime_t		*timeout = &ehci->hr_timeouts[event];
+
+	if (resched)
+		*timeout = ktime_add(ktime_get(),
+				ktime_set(0, event_delays_ns[event]));
+	ehci->enabled_hrtimer_events |= (1 << event);
+
+	/* Track only the lowest-numbered pending event */
+	if (event < ehci->next_hrtimer_event) {
+		ehci->next_hrtimer_event = event;
+		hrtimer_start_range_ns(&ehci->hrtimer, *timeout,
+				NSEC_PER_MSEC, HRTIMER_MODE_ABS);
+	}
+}
+
+
+/* Poll the STS_ASS status bit; see when it agrees with CMD_ASE */
+static void ehci_poll_ASS(struct ehci_hcd *ehci)
+{
+	unsigned	actual, want;
+
+	/* Don't enable anything if the controller isn't running (e.g., died) */
+	if (ehci->rh_state != EHCI_RH_RUNNING)
+		return;
+
+	want = (ehci->command & CMD_ASE) ? STS_ASS : 0;
+	actual = ehci_readl(ehci, &ehci->regs->status) & STS_ASS;
+
+	if (want != actual) {
+
+		/* Poll again later, but give up after about 20 ms */
+		if (ehci->ASS_poll_count++ < 20) {
+			ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true);
+			return;
+		}
+		ehci_warn(ehci, "Waited too long for the async schedule status, giving up\n");
+	}
+	ehci->ASS_poll_count = 0;
+
+	/* The status is up-to-date; restart or stop the schedule as needed */
+	if (want == 0) {	/* Stopped */
+		if (ehci->async_count > 0)
+			ehci_set_command_bit(ehci, CMD_ASE);
+
+	} else {		/* Running */
+		if (ehci->async_count == 0) {
+
+			/* Turn off the schedule after a while */
+			ehci_enable_event(ehci, EHCI_HRTIMER_DISABLE_ASYNC,
+					true);
+		}
+	}
+}
+
+/* Turn off the async schedule after a brief delay */
+static void ehci_disable_ASE(struct ehci_hcd *ehci)
+{
+	ehci_clear_command_bit(ehci, CMD_ASE);
+}
+
+
+/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */
+static void ehci_poll_PSS(struct ehci_hcd *ehci)
+{
+	unsigned	actual, want;
+
+	/* Don't do anything if the controller isn't running (e.g., died) */
+	if (ehci->rh_state != EHCI_RH_RUNNING)
+		return;
+
+	want = (ehci->command & CMD_PSE) ? STS_PSS : 0;
+	actual = ehci_readl(ehci, &ehci->regs->status) & STS_PSS;
+
+	if (want != actual) {
+
+		/* Poll again later, but give up after about 20 ms */
+		if (ehci->PSS_poll_count++ < 20) {
+			ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true);
+			return;
+		}
+		ehci_warn(ehci, "Waited too long for the periodic schedule status, giving up\n");
+	}
+	ehci->PSS_poll_count = 0;
+
+	/* The status is up-to-date; restart or stop the schedule as needed */
+	if (want == 0) {	/* Stopped */
+		if (ehci->periodic_count > 0)
+			ehci_set_command_bit(ehci, CMD_PSE);
+
+	} else {		/* Running */
+		if (ehci->periodic_count == 0) {
+
+			/* Turn off the schedule after a while */
+			ehci_enable_event(ehci, EHCI_HRTIMER_DISABLE_PERIODIC,
+					true);
+		}
+	}
+}
+
+/* Turn off the periodic schedule after a brief delay */
+static void ehci_disable_PSE(struct ehci_hcd *ehci)
+{
+	ehci_clear_command_bit(ehci, CMD_PSE);
+}
+
+
+/* Poll the STS_HALT status bit; see when a dead controller stops */
+static void ehci_handle_controller_death(struct ehci_hcd *ehci)
+{
+	if (!(ehci_readl(ehci, &ehci->regs->status) & STS_HALT)) {
+
+		/* Give up after a few milliseconds */
+		if (ehci->died_poll_count++ < 5) {
+			/* Try again later */
+			ehci_enable_event(ehci, EHCI_HRTIMER_POLL_DEAD, true);
+			return;
+		}
+		ehci_warn(ehci, "Waited too long for the controller to stop, giving up\n");
+	}
+
+	/* Clean up the mess */
+	ehci->rh_state = EHCI_RH_HALTED;
+	ehci_writel(ehci, 0, &ehci->regs->configured_flag);
+	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+	ehci_work(ehci);
+	end_unlink_async(ehci);
+
+	/* Not in process context, so don't try to reset the controller */
+}
+
+
+/* Handle unlinked interrupt QHs once they are gone from the hardware */
+static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci)
+{
+	bool		stopped = (ehci->rh_state < EHCI_RH_RUNNING);
+
+	/*
+	 * Process all the QHs on the intr_unlink list that were added
+	 * before the current unlink cycle began.  The list is in
+	 * temporal order, so stop when we reach the first entry in the
+	 * current cycle.  But if the root hub isn't running then
+	 * process all the QHs on the list.
+	 */
+	ehci->intr_unlinking = true;
+	while (ehci->intr_unlink) {
+		struct ehci_qh	*qh = ehci->intr_unlink;
+
+		if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle)
+			break;
+		ehci->intr_unlink = qh->unlink_next;
+		qh->unlink_next = NULL;
+		end_unlink_intr(ehci, qh);
+	}
+
+	/* Handle remaining entries later */
+	if (ehci->intr_unlink) {
+		ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true);
+		++ehci->intr_unlink_cycle;
+	}
+	ehci->intr_unlinking = false;
+}
+
+
+/* Start another free-iTDs/siTDs cycle */
+static void start_free_itds(struct ehci_hcd *ehci)
+{
+	if (!(ehci->enabled_hrtimer_events & BIT(EHCI_HRTIMER_FREE_ITDS))) {
+		ehci->last_itd_to_free = list_entry(
+				ehci->cached_itd_list.prev,
+				struct ehci_itd, itd_list);
+		ehci->last_sitd_to_free = list_entry(
+				ehci->cached_sitd_list.prev,
+				struct ehci_sitd, sitd_list);
+		ehci_enable_event(ehci, EHCI_HRTIMER_FREE_ITDS, true);
+	}
+}
+
+/* Wait for controller to stop using old iTDs and siTDs */
+static void end_free_itds(struct ehci_hcd *ehci)
+{
+	struct ehci_itd		*itd, *n;
+	struct ehci_sitd	*sitd, *sn;
+
+	if (ehci->rh_state < EHCI_RH_RUNNING) {
+		ehci->last_itd_to_free = NULL;
+		ehci->last_sitd_to_free = NULL;
+	}
+
+	list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) {
+		list_del(&itd->itd_list);
+		dma_pool_free(ehci->itd_pool, itd, itd->itd_dma);
+		if (itd == ehci->last_itd_to_free)
+			break;
+	}
+	list_for_each_entry_safe(sitd, sn, &ehci->cached_sitd_list, sitd_list) {
+		list_del(&sitd->sitd_list);
+		dma_pool_free(ehci->sitd_pool, sitd, sitd->sitd_dma);
+		if (sitd == ehci->last_sitd_to_free)
+			break;
+	}
+
+	if (!list_empty(&ehci->cached_itd_list) ||
+			!list_empty(&ehci->cached_sitd_list))
+		start_free_itds(ehci);
+}
+
+
+/* Handle lost (or very late) IAA interrupts */
+static void ehci_iaa_watchdog(struct ehci_hcd *ehci)
+{
+	if (ehci->rh_state != EHCI_RH_RUNNING)
+		return;
+
+	/*
+	 * Lost IAA irqs wedge things badly; seen first with a vt8235.
+	 * So we need this watchdog, but must protect it against both
+	 * (a) SMP races against real IAA firing and retriggering, and
+	 * (b) clean HC shutdown, when IAA watchdog was pending.
+	 */
+	if (ehci->async_iaa) {
+		u32 cmd, status;
+
+		/* If we get here, IAA is *REALLY* late.  It's barely
+		 * conceivable that the system is so busy that CMD_IAAD
+		 * is still legitimately set, so let's be sure it's
+		 * clear before we read STS_IAA.  (The HC should clear
+		 * CMD_IAAD when it sets STS_IAA.)
+		 */
+		cmd = ehci_readl(ehci, &ehci->regs->command);
+
+		/*
+		 * If IAA is set here it either legitimately triggered
+		 * after the watchdog timer expired (_way_ late, so we'll
+		 * still count it as lost) ... or a silicon erratum:
+		 * - VIA seems to set IAA without triggering the IRQ;
+		 * - IAAD potentially cleared without setting IAA.
+		 */
+		status = ehci_readl(ehci, &ehci->regs->status);
+		if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
+			COUNT(ehci->stats.lost_iaa);
+			ehci_writel(ehci, STS_IAA, &ehci->regs->status);
+		}
+
+		ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n",
+				status, cmd);
+		end_unlink_async(ehci);
+	}
+}
+
+
+/* Enable the I/O watchdog, if appropriate */
+static void turn_on_io_watchdog(struct ehci_hcd *ehci)
+{
+	/* Not needed if the controller isn't running or it's already enabled */
+	if (ehci->rh_state != EHCI_RH_RUNNING ||
+			(ehci->enabled_hrtimer_events &
+				BIT(EHCI_HRTIMER_IO_WATCHDOG)))
+		return;
+
+	/*
+	 * Isochronous transfers always need the watchdog.
+	 * For other sorts we use it only if the flag is set.
+	 */
+	if (ehci->isoc_count > 0 || (ehci->need_io_watchdog &&
+			ehci->async_count + ehci->intr_count > 0))
+		ehci_enable_event(ehci, EHCI_HRTIMER_IO_WATCHDOG, true);
+}
+
+
+/*
+ * Handler functions for the hrtimer event types.
+ * Keep this array in the same order as the event types indexed by
+ * enum ehci_hrtimer_event in ehci.h.
+ */
+static void (*event_handlers[])(struct ehci_hcd *) = {
+	ehci_poll_ASS,			/* EHCI_HRTIMER_POLL_ASS */
+	ehci_poll_PSS,			/* EHCI_HRTIMER_POLL_PSS */
+	ehci_handle_controller_death,	/* EHCI_HRTIMER_POLL_DEAD */
+	ehci_handle_intr_unlinks,	/* EHCI_HRTIMER_UNLINK_INTR */
+	end_free_itds,			/* EHCI_HRTIMER_FREE_ITDS */
+	unlink_empty_async,		/* EHCI_HRTIMER_ASYNC_UNLINKS */
+	ehci_iaa_watchdog,		/* EHCI_HRTIMER_IAA_WATCHDOG */
+	ehci_disable_PSE,		/* EHCI_HRTIMER_DISABLE_PERIODIC */
+	ehci_disable_ASE,		/* EHCI_HRTIMER_DISABLE_ASYNC */
+	ehci_work,			/* EHCI_HRTIMER_IO_WATCHDOG */
+};
+
+static enum hrtimer_restart ehci_hrtimer_func(struct hrtimer *t)
+{
+	struct ehci_hcd	*ehci = container_of(t, struct ehci_hcd, hrtimer);
+	ktime_t		now;
+	unsigned long	events;
+	unsigned long	flags;
+	unsigned	e;
+
+	spin_lock_irqsave(&ehci->lock, flags);
+
+	events = ehci->enabled_hrtimer_events;
+	ehci->enabled_hrtimer_events = 0;
+	ehci->next_hrtimer_event = EHCI_HRTIMER_NO_EVENT;
+
+	/*
+	 * Check each pending event.  If its time has expired, handle
+	 * the event; otherwise re-enable it.
+	 */
+	now = ktime_get();
+	for_each_set_bit(e, &events, EHCI_HRTIMER_NUM_EVENTS) {
+		if (now.tv64 >= ehci->hr_timeouts[e].tv64)
+			event_handlers[e](ehci);
+		else
+			ehci_enable_event(ehci, e, false);
+	}
+
+	spin_unlock_irqrestore(&ehci->lock, flags);
+	return HRTIMER_NORESTART;
+}

+ 1 - 13
drivers/usb/host/ehci-vt8500.c

@@ -48,7 +48,7 @@ static const struct hc_driver vt8500_ehci_hc_driver = {
 	/*
 	/*
 	 * basic lifecycle operations
 	 * basic lifecycle operations
 	 */
 	 */
-	.reset			= ehci_init,
+	.reset			= ehci_setup,
 	.start			= ehci_run,
 	.start			= ehci_run,
 	.stop			= ehci_stop,
 	.stop			= ehci_stop,
 	.shutdown		= ehci_shutdown,
 	.shutdown		= ehci_shutdown,
@@ -121,18 +121,6 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev)
 
 
 	ehci = hcd_to_ehci(hcd);
 	ehci = hcd_to_ehci(hcd);
 	ehci->caps = hcd->regs;
 	ehci->caps = hcd->regs;
-	ehci->regs = hcd->regs +
-		HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
-
-	dbg_hcs_params(ehci, "reset");
-	dbg_hcc_params(ehci, "reset");
-
-	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = readl(&ehci->caps->hcs_params);
-
-	ehci_port_power(ehci, 1);
-
-	ehci_reset(ehci);
 
 
 	ret = usb_add_hcd(hcd, pdev->resource[1].start,
 	ret = usb_add_hcd(hcd, pdev->resource[1].start,
 			  IRQF_SHARED);
 			  IRQF_SHARED);

+ 1 - 8
drivers/usb/host/ehci-w90x900.c

@@ -71,21 +71,14 @@ static int __devinit usb_w90x900_probe(const struct hc_driver *driver,
 	val |= ENPHY;
 	val |= ENPHY;
 	__raw_writel(val, ehci->regs+PHY1_CTR);
 	__raw_writel(val, ehci->regs+PHY1_CTR);
 
 
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-	ehci->sbrn = 0x20;
-
 	irq = platform_get_irq(pdev, 0);
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
 	if (irq < 0)
 		goto err4;
 		goto err4;
 
 
-	ehci_reset(ehci);
-
 	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (retval != 0)
 	if (retval != 0)
 		goto err4;
 		goto err4;
 
 
-	ehci_writel(ehci, 1, &ehci->regs->configured_flag);
-
 	return retval;
 	return retval;
 err4:
 err4:
 	iounmap(hcd->regs);
 	iounmap(hcd->regs);
@@ -120,7 +113,7 @@ static const struct hc_driver ehci_w90x900_hc_driver = {
 	/*
 	/*
 	 * basic lifecycle operations
 	 * basic lifecycle operations
 	 */
 	 */
-	.reset = ehci_init,
+	.reset = ehci_setup,
 	.start = ehci_run,
 	.start = ehci_run,
 
 
 	.stop = ehci_stop,
 	.stop = ehci_stop,

+ 1 - 30
drivers/usb/host/ehci-xilinx-of.c

@@ -31,30 +31,6 @@
 #include <linux/of_platform.h>
 #include <linux/of_platform.h>
 #include <linux/of_address.h>
 #include <linux/of_address.h>
 
 
-/**
- * ehci_xilinx_of_setup - Initialize the device for ehci_reset()
- * @hcd:	Pointer to the usb_hcd device to which the host controller bound
- *
- * called during probe() after chip reset completes.
- */
-static int ehci_xilinx_of_setup(struct usb_hcd *hcd)
-{
-	struct ehci_hcd	*ehci = hcd_to_ehci(hcd);
-	int		retval;
-
-	retval = ehci_halt(ehci);
-	if (retval)
-		return retval;
-
-	retval = ehci_init(hcd);
-	if (retval)
-		return retval;
-
-	ehci->sbrn = 0x20;
-
-	return ehci_reset(ehci);
-}
-
 /**
 /**
  * ehci_xilinx_port_handed_over - hand the port out if failed to enable it
  * ehci_xilinx_port_handed_over - hand the port out if failed to enable it
  * @hcd:	Pointer to the usb_hcd device to which the host controller bound
  * @hcd:	Pointer to the usb_hcd device to which the host controller bound
@@ -107,7 +83,7 @@ static const struct hc_driver ehci_xilinx_of_hc_driver = {
 	/*
 	/*
 	 * basic lifecycle operations
 	 * basic lifecycle operations
 	 */
 	 */
-	.reset			= ehci_xilinx_of_setup,
+	.reset			= ehci_setup,
 	.start			= ehci_run,
 	.start			= ehci_run,
 	.stop			= ehci_stop,
 	.stop			= ehci_stop,
 	.shutdown		= ehci_shutdown,
 	.shutdown		= ehci_shutdown,
@@ -219,11 +195,6 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op)
 	/* Debug registers are at the first 0x100 region
 	/* Debug registers are at the first 0x100 region
 	 */
 	 */
 	ehci->caps = hcd->regs + 0x100;
 	ehci->caps = hcd->regs + 0x100;
-	ehci->regs = hcd->regs + 0x100 +
-		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-
-	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
 
 	rv = usb_add_hcd(hcd, irq, 0);
 	rv = usb_add_hcd(hcd, irq, 0);
 	if (rv == 0)
 	if (rv == 0)

+ 1 - 20
drivers/usb/host/ehci-xls.c

@@ -14,30 +14,11 @@
 
 
 static int ehci_xls_setup(struct usb_hcd *hcd)
 static int ehci_xls_setup(struct usb_hcd *hcd)
 {
 {
-	int	retval;
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 
 
 	ehci->caps = hcd->regs;
 	ehci->caps = hcd->regs;
-	ehci->regs = hcd->regs +
-		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-	dbg_hcs_params(ehci, "reset");
-	dbg_hcc_params(ehci, "reset");
 
 
-	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-
-	retval = ehci_halt(ehci);
-	if (retval)
-		return retval;
-
-	/* data structure init */
-	retval = ehci_init(hcd);
-	if (retval)
-		return retval;
-
-	ehci_reset(ehci);
-
-	return retval;
+	return ehci_setup(hcd);
 }
 }
 
 
 int ehci_xls_probe_internal(const struct hc_driver *driver,
 int ehci_xls_probe_internal(const struct hc_driver *driver,

+ 75 - 63
drivers/usb/host/ehci.h

@@ -42,7 +42,7 @@ struct ehci_stats {
 	/* irq usage */
 	/* irq usage */
 	unsigned long		normal;
 	unsigned long		normal;
 	unsigned long		error;
 	unsigned long		error;
-	unsigned long		reclaim;
+	unsigned long		iaa;
 	unsigned long		lost_iaa;
 	unsigned long		lost_iaa;
 
 
 	/* termination of urbs from core */
 	/* termination of urbs from core */
@@ -51,7 +51,7 @@ struct ehci_stats {
 };
 };
 
 
 /* ehci_hcd->lock guards shared data against other CPUs:
 /* ehci_hcd->lock guards shared data against other CPUs:
- *   ehci_hcd:	async, reclaim, periodic (and shadow), ...
+ *   ehci_hcd:	async, unlink, periodic (and shadow), ...
  *   usb_host_endpoint: hcpriv
  *   usb_host_endpoint: hcpriv
  *   ehci_qh:	qh_next, qtd_list
  *   ehci_qh:	qh_next, qtd_list
  *   ehci_qtd:	qtd_list
  *   ehci_qtd:	qtd_list
@@ -62,13 +62,48 @@ struct ehci_stats {
 
 
 #define	EHCI_MAX_ROOT_PORTS	15		/* see HCS_N_PORTS */
 #define	EHCI_MAX_ROOT_PORTS	15		/* see HCS_N_PORTS */
 
 
+/*
+ * ehci_rh_state values of EHCI_RH_RUNNING or above mean that the
+ * controller may be doing DMA.  Lower values mean there's no DMA.
+ */
 enum ehci_rh_state {
 enum ehci_rh_state {
 	EHCI_RH_HALTED,
 	EHCI_RH_HALTED,
 	EHCI_RH_SUSPENDED,
 	EHCI_RH_SUSPENDED,
-	EHCI_RH_RUNNING
+	EHCI_RH_RUNNING,
+	EHCI_RH_STOPPING
 };
 };
 
 
+/*
+ * Timer events, ordered by increasing delay length.
+ * Always update event_delays_ns[] and event_handlers[] (defined in
+ * ehci-timer.c) in parallel with this list.
+ */
+enum ehci_hrtimer_event {
+	EHCI_HRTIMER_POLL_ASS,		/* Poll for async schedule off */
+	EHCI_HRTIMER_POLL_PSS,		/* Poll for periodic schedule off */
+	EHCI_HRTIMER_POLL_DEAD,		/* Wait for dead controller to stop */
+	EHCI_HRTIMER_UNLINK_INTR,	/* Wait for interrupt QH unlink */
+	EHCI_HRTIMER_FREE_ITDS,		/* Wait for unused iTDs and siTDs */
+	EHCI_HRTIMER_ASYNC_UNLINKS,	/* Unlink empty async QHs */
+	EHCI_HRTIMER_IAA_WATCHDOG,	/* Handle lost IAA interrupts */
+	EHCI_HRTIMER_DISABLE_PERIODIC,	/* Wait to disable periodic sched */
+	EHCI_HRTIMER_DISABLE_ASYNC,	/* Wait to disable async sched */
+	EHCI_HRTIMER_IO_WATCHDOG,	/* Check for missing IRQs */
+	EHCI_HRTIMER_NUM_EVENTS		/* Must come last */
+};
+#define EHCI_HRTIMER_NO_EVENT	99
+
 struct ehci_hcd {			/* one per controller */
 struct ehci_hcd {			/* one per controller */
+	/* timing support */
+	enum ehci_hrtimer_event	next_hrtimer_event;
+	unsigned		enabled_hrtimer_events;
+	ktime_t			hr_timeouts[EHCI_HRTIMER_NUM_EVENTS];
+	struct hrtimer		hrtimer;
+
+	int			PSS_poll_count;
+	int			ASS_poll_count;
+	int			died_poll_count;
+
 	/* glue to PCI and HCD framework */
 	/* glue to PCI and HCD framework */
 	struct ehci_caps __iomem *caps;
 	struct ehci_caps __iomem *caps;
 	struct ehci_regs __iomem *regs;
 	struct ehci_regs __iomem *regs;
@@ -78,30 +113,48 @@ struct ehci_hcd {			/* one per controller */
 	spinlock_t		lock;
 	spinlock_t		lock;
 	enum ehci_rh_state	rh_state;
 	enum ehci_rh_state	rh_state;
 
 
+	/* general schedule support */
+	bool			scanning:1;
+	bool			need_rescan:1;
+	bool			intr_unlinking:1;
+	bool			async_unlinking:1;
+	bool			shutdown:1;
+	struct ehci_qh		*qh_scan_next;
+
 	/* async schedule support */
 	/* async schedule support */
 	struct ehci_qh		*async;
 	struct ehci_qh		*async;
 	struct ehci_qh		*dummy;		/* For AMD quirk use */
 	struct ehci_qh		*dummy;		/* For AMD quirk use */
-	struct ehci_qh		*reclaim;
-	struct ehci_qh		*qh_scan_next;
-	unsigned		scanning : 1;
+	struct ehci_qh		*async_unlink;
+	struct ehci_qh		*async_unlink_last;
+	struct ehci_qh		*async_iaa;
+	unsigned		async_unlink_cycle;
+	unsigned		async_count;	/* async activity count */
 
 
 	/* periodic schedule support */
 	/* periodic schedule support */
 #define	DEFAULT_I_TDPS		1024		/* some HCs can do less */
 #define	DEFAULT_I_TDPS		1024		/* some HCs can do less */
 	unsigned		periodic_size;
 	unsigned		periodic_size;
 	__hc32			*periodic;	/* hw periodic table */
 	__hc32			*periodic;	/* hw periodic table */
 	dma_addr_t		periodic_dma;
 	dma_addr_t		periodic_dma;
+	struct list_head	intr_qh_list;
 	unsigned		i_thresh;	/* uframes HC might cache */
 	unsigned		i_thresh;	/* uframes HC might cache */
 
 
 	union ehci_shadow	*pshadow;	/* mirror hw periodic table */
 	union ehci_shadow	*pshadow;	/* mirror hw periodic table */
-	int			next_uframe;	/* scan periodic, start here */
-	unsigned		periodic_sched;	/* periodic activity count */
+	struct ehci_qh		*intr_unlink;
+	struct ehci_qh		*intr_unlink_last;
+	unsigned		intr_unlink_cycle;
+	unsigned		now_frame;	/* frame from HC hardware */
+	unsigned		next_frame;	/* scan periodic, start here */
+	unsigned		intr_count;	/* intr activity count */
+	unsigned		isoc_count;	/* isoc activity count */
+	unsigned		periodic_count;	/* periodic activity count */
 	unsigned		uframe_periodic_max; /* max periodic time per uframe */
 	unsigned		uframe_periodic_max; /* max periodic time per uframe */
 
 
 
 
-	/* list of itds & sitds completed while clock_frame was still active */
+	/* list of itds & sitds completed while now_frame was still active */
 	struct list_head	cached_itd_list;
 	struct list_head	cached_itd_list;
+	struct ehci_itd		*last_itd_to_free;
 	struct list_head	cached_sitd_list;
 	struct list_head	cached_sitd_list;
-	unsigned		clock_frame;
+	struct ehci_sitd	*last_sitd_to_free;
 
 
 	/* per root hub port */
 	/* per root hub port */
 	unsigned long		reset_done [EHCI_MAX_ROOT_PORTS];
 	unsigned long		reset_done [EHCI_MAX_ROOT_PORTS];
@@ -126,10 +179,6 @@ struct ehci_hcd {			/* one per controller */
 	struct dma_pool		*itd_pool;	/* itd per iso urb */
 	struct dma_pool		*itd_pool;	/* itd per iso urb */
 	struct dma_pool		*sitd_pool;	/* sitd per split iso urb */
 	struct dma_pool		*sitd_pool;	/* sitd per split iso urb */
 
 
-	struct timer_list	iaa_watchdog;
-	struct timer_list	watchdog;
-	unsigned long		actions;
-	unsigned		periodic_stamp;
 	unsigned		random_frame;
 	unsigned		random_frame;
 	unsigned long		next_statechange;
 	unsigned long		next_statechange;
 	ktime_t			last_periodic_enable;
 	ktime_t			last_periodic_enable;
@@ -143,7 +192,6 @@ struct ehci_hcd {			/* one per controller */
 	unsigned		big_endian_capbase:1;
 	unsigned		big_endian_capbase:1;
 	unsigned		has_amcc_usb23:1;
 	unsigned		has_amcc_usb23:1;
 	unsigned		need_io_watchdog:1;
 	unsigned		need_io_watchdog:1;
-	unsigned		broken_periodic:1;
 	unsigned		amd_pll_fix:1;
 	unsigned		amd_pll_fix:1;
 	unsigned		fs_i_thresh:1;	/* Intel iso scheduling */
 	unsigned		fs_i_thresh:1;	/* Intel iso scheduling */
 	unsigned		use_dummy_qh:1;	/* AMD Frame List table quirk*/
 	unsigned		use_dummy_qh:1;	/* AMD Frame List table quirk*/
@@ -175,10 +223,6 @@ struct ehci_hcd {			/* one per controller */
 #ifdef DEBUG
 #ifdef DEBUG
 	struct dentry		*debug_dir;
 	struct dentry		*debug_dir;
 #endif
 #endif
-	/*
-	 * OTG controllers and transceivers need software interaction
-	 */
-	struct usb_phy	*transceiver;
 };
 };
 
 
 /* convert between an HCD pointer and the corresponding EHCI_HCD */
 /* convert between an HCD pointer and the corresponding EHCI_HCD */
@@ -191,34 +235,6 @@ static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci)
 	return container_of ((void *) ehci, struct usb_hcd, hcd_priv);
 	return container_of ((void *) ehci, struct usb_hcd, hcd_priv);
 }
 }
 
 
-
-static inline void
-iaa_watchdog_start(struct ehci_hcd *ehci)
-{
-	WARN_ON(timer_pending(&ehci->iaa_watchdog));
-	mod_timer(&ehci->iaa_watchdog,
-			jiffies + msecs_to_jiffies(EHCI_IAA_MSECS));
-}
-
-static inline void iaa_watchdog_done(struct ehci_hcd *ehci)
-{
-	del_timer(&ehci->iaa_watchdog);
-}
-
-enum ehci_timer_action {
-	TIMER_IO_WATCHDOG,
-	TIMER_ASYNC_SHRINK,
-	TIMER_ASYNC_OFF,
-};
-
-static inline void
-timer_action_done (struct ehci_hcd *ehci, enum ehci_timer_action action)
-{
-	clear_bit (action, &ehci->actions);
-}
-
-static void free_cached_lists(struct ehci_hcd *ehci);
-
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 #include <linux/usb/ehci_def.h>
 #include <linux/usb/ehci_def.h>
@@ -328,7 +344,13 @@ union ehci_shadow {
 struct ehci_qh_hw {
 struct ehci_qh_hw {
 	__hc32			hw_next;	/* see EHCI 3.6.1 */
 	__hc32			hw_next;	/* see EHCI 3.6.1 */
 	__hc32			hw_info1;       /* see EHCI 3.6.2 */
 	__hc32			hw_info1;       /* see EHCI 3.6.2 */
-#define	QH_HEAD		0x00008000
+#define	QH_CONTROL_EP	(1 << 27)	/* FS/LS control endpoint */
+#define	QH_HEAD		(1 << 15)	/* Head of async reclamation list */
+#define	QH_TOGGLE_CTL	(1 << 14)	/* Data toggle control */
+#define	QH_HIGH_SPEED	(2 << 12)	/* Endpoint speed */
+#define	QH_LOW_SPEED	(1 << 12)
+#define	QH_FULL_SPEED	(0 << 12)
+#define	QH_INACTIVATE	(1 << 7)	/* Inactivate on next transaction */
 	__hc32			hw_info2;        /* see EHCI 3.6.2 */
 	__hc32			hw_info2;        /* see EHCI 3.6.2 */
 #define	QH_SMASK	0x000000ff
 #define	QH_SMASK	0x000000ff
 #define	QH_CMASK	0x0000ff00
 #define	QH_CMASK	0x0000ff00
@@ -346,32 +368,23 @@ struct ehci_qh_hw {
 } __attribute__ ((aligned(32)));
 } __attribute__ ((aligned(32)));
 
 
 struct ehci_qh {
 struct ehci_qh {
-	struct ehci_qh_hw	*hw;
+	struct ehci_qh_hw	*hw;		/* Must come first */
 	/* the rest is HCD-private */
 	/* the rest is HCD-private */
 	dma_addr_t		qh_dma;		/* address of qh */
 	dma_addr_t		qh_dma;		/* address of qh */
 	union ehci_shadow	qh_next;	/* ptr to qh; or periodic */
 	union ehci_shadow	qh_next;	/* ptr to qh; or periodic */
 	struct list_head	qtd_list;	/* sw qtd list */
 	struct list_head	qtd_list;	/* sw qtd list */
+	struct list_head	intr_node;	/* list of intr QHs */
 	struct ehci_qtd		*dummy;
 	struct ehci_qtd		*dummy;
-	struct ehci_qh		*reclaim;	/* next to reclaim */
-
-	struct ehci_hcd		*ehci;
-	unsigned long		unlink_time;
+	struct ehci_qh		*unlink_next;	/* next on unlink list */
 
 
-	/*
-	 * Do NOT use atomic operations for QH refcounting. On some CPUs
-	 * (PPC7448 for example), atomic operations cannot be performed on
-	 * memory that is cache-inhibited (i.e. being used for DMA).
-	 * Spinlocks are used to protect all QH fields.
-	 */
-	u32			refcount;
-	unsigned		stamp;
+	unsigned		unlink_cycle;
 
 
 	u8			needs_rescan;	/* Dequeue during giveback */
 	u8			needs_rescan;	/* Dequeue during giveback */
 	u8			qh_state;
 	u8			qh_state;
 #define	QH_STATE_LINKED		1		/* HC sees this */
 #define	QH_STATE_LINKED		1		/* HC sees this */
 #define	QH_STATE_UNLINK		2		/* HC may still see this */
 #define	QH_STATE_UNLINK		2		/* HC may still see this */
 #define	QH_STATE_IDLE		3		/* HC doesn't see this */
 #define	QH_STATE_IDLE		3		/* HC doesn't see this */
-#define	QH_STATE_UNLINK_WAIT	4		/* LINKED and on reclaim q */
+#define	QH_STATE_UNLINK_WAIT	4		/* LINKED and on unlink q */
 #define	QH_STATE_COMPLETING	5		/* don't touch token.HALT */
 #define	QH_STATE_COMPLETING	5		/* don't touch token.HALT */
 
 
 	u8			xacterrs;	/* XactErr retry counter */
 	u8			xacterrs;	/* XactErr retry counter */
@@ -421,7 +434,6 @@ struct ehci_iso_stream {
 	/* first field matches ehci_hq, but is NULL */
 	/* first field matches ehci_hq, but is NULL */
 	struct ehci_qh_hw	*hw;
 	struct ehci_qh_hw	*hw;
 
 
-	u32			refcount;
 	u8			bEndpointAddress;
 	u8			bEndpointAddress;
 	u8			highspeed;
 	u8			highspeed;
 	struct list_head	td_list;	/* queued itds/sitds */
 	struct list_head	td_list;	/* queued itds/sitds */

Неке датотеке нису приказане због велике количине промена