Merge 3.11-rc6 into usb-next
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 19 Aug 2013 03:33:01 +0000 (20:33 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 19 Aug 2013 03:33:01 +0000 (20:33 -0700)
We want these USB fixes in this branch as well.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
283 files changed:
Documentation/ABI/testing/sysfs-bus-usb
Documentation/devicetree/bindings/usb/dwc3.txt
Documentation/devicetree/bindings/usb/generic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt
Documentation/devicetree/bindings/usb/samsung-hsotg.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/usb-xhci.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/usb3503.txt
Documentation/usb/URB.txt
Documentation/usb/proc_usb_info.txt
MAINTAINERS
arch/arm/boot/dts/am335x-bone.dts
arch/arm/boot/dts/am335x-evm.dts
arch/arm/boot/dts/am335x-evmsk.dts
arch/arm/boot/dts/am33xx.dtsi
arch/arm/boot/dts/omap5.dtsi
arch/arm/boot/dts/tegra20-seaboard.dts
arch/arm/boot/dts/tegra20-trimslice.dts
arch/arm/boot/dts/tegra20-whistler.dts
arch/arm/boot/dts/tegra20.dtsi
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-omap3evm.c
arch/arm/mach-omap2/board-omap3pandora.c
arch/arm/mach-omap2/usb-host.c
arch/arm/mach-tegra/tegra.c
drivers/dma/Kconfig
drivers/dma/Makefile
drivers/dma/cppi41.c [new file with mode: 0644]
drivers/net/usb/ax88179_178a.c
drivers/net/usb/usbnet.c
drivers/usb/Kconfig
drivers/usb/Makefile
drivers/usb/atm/Makefile
drivers/usb/atm/speedtch.c
drivers/usb/atm/usbatm.c
drivers/usb/atm/usbatm.h
drivers/usb/c67x00/c67x00-drv.c
drivers/usb/chipidea/Kconfig
drivers/usb/chipidea/Makefile
drivers/usb/chipidea/bits.h
drivers/usb/chipidea/ci.h
drivers/usb/chipidea/ci_hdrc_imx.c
drivers/usb/chipidea/ci_hdrc_imx.h
drivers/usb/chipidea/ci_hdrc_msm.c
drivers/usb/chipidea/core.c
drivers/usb/chipidea/host.c
drivers/usb/chipidea/host.h
drivers/usb/chipidea/otg.c [new file with mode: 0644]
drivers/usb/chipidea/otg.h [new file with mode: 0644]
drivers/usb/chipidea/udc.c
drivers/usb/chipidea/udc.h
drivers/usb/chipidea/usbmisc_imx.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-wdm.c
drivers/usb/class/usbtmc.c
drivers/usb/core/buffer.c
drivers/usb/core/config.c
drivers/usb/core/devio.c
drivers/usb/core/driver.c
drivers/usb/core/endpoint.c
drivers/usb/core/file.c
drivers/usb/core/hcd-pci.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
drivers/usb/dwc3/Kconfig
drivers/usb/dwc3/Makefile
drivers/usb/dwc3/core.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/debug.h
drivers/usb/dwc3/debugfs.c
drivers/usb/dwc3/dwc3-exynos.c
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/dwc3/ep0.c
drivers/usb/dwc3/gadget.c
drivers/usb/dwc3/gadget.h
drivers/usb/dwc3/host.c
drivers/usb/dwc3/io.h
drivers/usb/dwc3/platform_data.h [new file with mode: 0644]
drivers/usb/gadget/Kconfig
drivers/usb/gadget/Makefile
drivers/usb/gadget/amd5536udc.c
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/at91_udc.h
drivers/usb/gadget/atmel_usba_udc.c
drivers/usb/gadget/bcm63xx_udc.c
drivers/usb/gadget/f_mass_storage.c
drivers/usb/gadget/f_uac1.c
drivers/usb/gadget/fsl_mxc_udc.c
drivers/usb/gadget/fsl_udc_core.c
drivers/usb/gadget/fusb300_udc.c
drivers/usb/gadget/goku_udc.c
drivers/usb/gadget/hid.c
drivers/usb/gadget/imx_udc.c [deleted file]
drivers/usb/gadget/imx_udc.h [deleted file]
drivers/usb/gadget/m66592-udc.c
drivers/usb/gadget/mv_u3d_core.c
drivers/usb/gadget/mv_udc_core.c
drivers/usb/gadget/omap_udc.c
drivers/usb/gadget/pxa25x_udc.c
drivers/usb/gadget/pxa27x_udc.c
drivers/usb/gadget/r8a66597-udc.c
drivers/usb/gadget/rndis.c
drivers/usb/gadget/s3c-hsotg.c
drivers/usb/gadget/s3c-hsudc.c
drivers/usb/gadget/s3c2410_udc.c
drivers/usb/gadget/storage_common.c
drivers/usb/gadget/u_uac1.c
drivers/usb/gadget/udc-core.c
drivers/usb/gadget/uvc_queue.c
drivers/usb/host/Kconfig
drivers/usb/host/Makefile
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-grlib.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-mem.c
drivers/usb/host/ehci-mv.c
drivers/usb/host/ehci-mxc.c
drivers/usb/host/ehci-octeon.c
drivers/usb/host/ehci-omap.c
drivers/usb/host/ehci-orion.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-platform.c
drivers/usb/host/ehci-pmcmsp.c
drivers/usb/host/ehci-ppc-of.c
drivers/usb/host/ehci-ps3.c
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-s5p.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/ehci-sead3.c
drivers/usb/host/ehci-sh.c
drivers/usb/host/ehci-tegra.c
drivers/usb/host/ehci-tilegx.c
drivers/usb/host/ehci-timer.c
drivers/usb/host/ehci-w90x900.c
drivers/usb/host/ehci-xilinx-of.c
drivers/usb/host/ehci.h
drivers/usb/host/fotg210-hcd.c [new file with mode: 0644]
drivers/usb/host/fotg210.h [new file with mode: 0644]
drivers/usb/host/fsl-mph-dr-of.c
drivers/usb/host/hwa-hc.c
drivers/usb/host/imx21-hcd.c
drivers/usb/host/isp116x-hcd.c
drivers/usb/host/isp116x.h
drivers/usb/host/isp1362-hcd.c
drivers/usb/host/isp1362.h
drivers/usb/host/isp1760-if.c
drivers/usb/host/ohci-at91.c
drivers/usb/host/ohci-da8xx.c
drivers/usb/host/ohci-ep93xx.c
drivers/usb/host/ohci-exynos.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-omap.c
drivers/usb/host/ohci-omap3.c
drivers/usb/host/ohci-platform.c
drivers/usb/host/ohci-ppc-of.c
drivers/usb/host/ohci-pxa27x.c
drivers/usb/host/ohci-s3c2410.c
drivers/usb/host/ohci-tilegx.c
drivers/usb/host/pci-quirks.c
drivers/usb/host/pci-quirks.h
drivers/usb/host/r8a66597-hcd.c
drivers/usb/host/sl811-hcd.c
drivers/usb/host/sl811.h
drivers/usb/host/u132-hcd.c
drivers/usb/host/xhci-dbg.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-plat.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci-trace.c [new file with mode: 0644]
drivers/usb/host/xhci-trace.h [new file with mode: 0644]
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/misc/Kconfig
drivers/usb/misc/Makefile
drivers/usb/misc/adutux.c
drivers/usb/misc/ehset.c [new file with mode: 0644]
drivers/usb/misc/ldusb.c
drivers/usb/misc/legousbtower.c
drivers/usb/misc/usb3503.c
drivers/usb/misc/usbtest.c
drivers/usb/misc/uss720.c
drivers/usb/musb/Kconfig
drivers/usb/musb/Makefile
drivers/usb/musb/am35x.c
drivers/usb/musb/blackfin.c
drivers/usb/musb/cppi_dma.c
drivers/usb/musb/da8xx.c
drivers/usb/musb/davinci.c
drivers/usb/musb/musb_am335x.c [new file with mode: 0644]
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_cppi41.c [new file with mode: 0644]
drivers/usb/musb/musb_dma.h
drivers/usb/musb/musb_dsps.c
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musbhsdma.c
drivers/usb/musb/omap2430.c
drivers/usb/musb/tusb6010.c
drivers/usb/musb/tusb6010_omap.c
drivers/usb/musb/ux500.c
drivers/usb/musb/ux500_dma.c
drivers/usb/phy/Kconfig
drivers/usb/phy/Makefile
drivers/usb/phy/am35x-phy-control.h [new file with mode: 0644]
drivers/usb/phy/phy-am335x-control.c [new file with mode: 0644]
drivers/usb/phy/phy-am335x.c [new file with mode: 0644]
drivers/usb/phy/phy-fsl-usb.c
drivers/usb/phy/phy-fsm-usb.h
drivers/usb/phy/phy-generic.c [new file with mode: 0644]
drivers/usb/phy/phy-generic.h [new file with mode: 0644]
drivers/usb/phy/phy-gpio-vbus-usb.c
drivers/usb/phy/phy-isp1301-omap.c
drivers/usb/phy/phy-msm-usb.c
drivers/usb/phy/phy-mv-u3d-usb.c
drivers/usb/phy/phy-mv-usb.c
drivers/usb/phy/phy-mxs-usb.c
drivers/usb/phy/phy-nop.c [deleted file]
drivers/usb/phy/phy-omap-control.c
drivers/usb/phy/phy-omap-usb3.c
drivers/usb/phy/phy-rcar-usb.c
drivers/usb/phy/phy-samsung-usb2.c
drivers/usb/phy/phy-samsung-usb3.c
drivers/usb/phy/phy-tegra-usb.c
drivers/usb/phy/phy-twl4030-usb.c
drivers/usb/phy/phy-twl6030-usb.c
drivers/usb/renesas_usbhs/common.c
drivers/usb/renesas_usbhs/mod_gadget.c
drivers/usb/renesas_usbhs/mod_host.c
drivers/usb/renesas_usbhs/pipe.h
drivers/usb/serial/Kconfig
drivers/usb/serial/Makefile
drivers/usb/serial/console.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/f81232.c
drivers/usb/serial/flashloader.c [deleted file]
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/funsoft.c [deleted file]
drivers/usb/serial/generic.c
drivers/usb/serial/hp4x.c [deleted file]
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_ti.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/moto_modem.c [deleted file]
drivers/usb/serial/oti6858.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/quatech2.c
drivers/usb/serial/safe_serial.c
drivers/usb/serial/siemens_mpi.c [deleted file]
drivers/usb/serial/spcp8x5.c
drivers/usb/serial/suunto.c [deleted file]
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial-simple.c [new file with mode: 0644]
drivers/usb/serial/usb-serial.c
drivers/usb/serial/vivopay-serial.c [deleted file]
drivers/usb/serial/zio.c [deleted file]
drivers/usb/usb-common.c
drivers/usb/usb-skeleton.c
drivers/usb/wusbcore/rh.c
drivers/usb/wusbcore/wa-hc.h
drivers/usb/wusbcore/wa-rpipe.c
drivers/usb/wusbcore/wa-xfer.c
drivers/uwb/hwa-rc.c
drivers/uwb/pal.c
include/linux/platform_data/tegra_usb.h [deleted file]
include/linux/usb.h
include/linux/usb/chipidea.h
include/linux/usb/gadget.h
include/linux/usb/hcd.h
include/linux/usb/nop-usb-xceiv.h [deleted file]
include/linux/usb/of.h
include/linux/usb/phy.h
include/linux/usb/tegra_usb_phy.h
include/linux/usb/usb_phy_gen_xceiv.h [new file with mode: 0644]
include/linux/usb/usbnet.h
include/linux/usb/wusb-wa.h

index 9759b8c913329cde110754b84438133a4738dcd7..0053ae262a0a9d8c3b504e66b867c4aef2884871 100644 (file)
@@ -60,7 +60,7 @@ Users:
                PowerTOP <power@bughost.org>
                http://www.lesswatts.org/projects/powertop/
 
-What:          /sys/bus/usb/device/<busnum>-<devnum>...:<config num>-<interface num>/supports_autosuspend
+What:          /sys/bus/usb/devices/<busnum>-<port[.port]>...:<config num>-<interface num>/supports_autosuspend
 Date:          January 2008
 KernelVersion: 2.6.27
 Contact:       Sarah Sharp <sarah.a.sharp@intel.com>
@@ -263,3 +263,41 @@ Description:
                Supported values are 0 - 15.
                More information on how besl values map to microseconds can be found in
                USB 2.0 ECN Errata for Link Power Management, section 4.10)
+
+What:          /sys/bus/usb/devices/.../devnum
+KernelVersion: since at least 2.6.18
+Description:
+               Device address on the USB bus.
+
+What:          /sys/bus/usb/devices/.../bConfigurationValue
+KernelVersion: since at least 2.6.18
+Description:
+               bConfigurationValue of the *active* configuration for the
+               device. Writing 0 or -1 to bConfigurationValue will reset the
+               active configuration (unconfigure the device). Writing
+               another value will change the active configuration.
+
+               Note that some devices, in violation of the USB spec, have a
+               configuration with a value equal to 0. Writing 0 to
+               bConfigurationValue for these devices will install that
+               configuration, rather then unconfigure the device.
+
+               Writing -1 will always unconfigure the device.
+
+What:          /sys/bus/usb/devices/.../busnum
+KernelVersion: 2.6.22
+Description:
+               Bus-number of the USB-bus the device is connected to.
+
+What:          /sys/bus/usb/devices/.../descriptors
+KernelVersion: 2.6.26
+Description:
+               Binary file containing cached descriptors of the device. The
+               binary data consists of the device descriptor followed by the
+               descriptors for each configuration of the device.
+               Note that the wTotalLength of the config descriptors can not
+               be trusted, as the device may have a smaller config descriptor
+               than it advertises. The bLength field of each (sub) descriptor
+               can be trusted, and can be used to seek forward one (sub)
+               descriptor at a time until the next config descriptor is found.
+               All descriptors read from this file are in bus-endian format
index 7a95c651ceb3b20f82bd0940aed222cc1e3be5c6..e807635f9e1c72acec52de0f296804b14e5d458c 100644 (file)
@@ -3,10 +3,12 @@ synopsys DWC3 CORE
 DWC3- USB3 CONTROLLER
 
 Required properties:
- - compatible: must be "synopsys,dwc3"
+ - compatible: must be "snps,dwc3"
  - reg : Address and length of the register set for the device
  - interrupts: Interrupts used by the dwc3 controller.
- - usb-phy : array of phandle for the PHY device
+ - usb-phy : array of phandle for the PHY device.  The first element
+   in the array is expected to be a handle to the USB2/HS PHY and
+   the second element is expected to be a handle to the USB3/SS PHY
 
 Optional properties:
  - tx-fifo-resize: determines if the FIFO *has* to be reallocated.
@@ -14,7 +16,7 @@ Optional properties:
 This is usually a subnode to DWC3 glue to which it is connected.
 
 dwc3@4a030000 {
-       compatible = "synopsys,dwc3";
+       compatible = "snps,dwc3";
        reg = <0x4a030000 0xcfff>;
        interrupts = <0 92 4>
        usb-phy = <&usb2_phy>, <&usb3,phy>;
diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt
new file mode 100644 (file)
index 0000000..477d5bb
--- /dev/null
@@ -0,0 +1,24 @@
+Generic USB Properties
+
+Optional properties:
+ - maximum-speed: tells USB controllers we want to work up to a certain
+                       speed. Valid arguments are "super-speed", "high-speed",
+                       "full-speed" and "low-speed". In case this isn't passed
+                       via DT, USB controllers should default to their maximum
+                       HW capability.
+ - dr_mode: tells Dual-Role USB controllers that we want to work on a
+                       particular mode. Valid arguments are "host",
+                       "peripheral" and "otg". In case this attribute isn't
+                       passed via DT, USB DRD controllers should default to
+                       OTG.
+
+This is an attribute to a USB controller such as:
+
+dwc3@4a030000 {
+       compatible = "synopsys,dwc3";
+       reg = <0x4a030000 0xcfff>;
+       interrupts = <0 92 4>
+       usb-phy = <&usb2_phy>, <&usb3,phy>;
+       maximum-speed = "super-speed";
+       dr_mode = "otg";
+};
index c4c9e9e664aac3461a378d2ab249ba0ca662b2b2..ba797d3e6326bc53a927cfa655c8cbad76db854e 100644 (file)
@@ -3,7 +3,7 @@ Tegra SOC USB PHY
 The device node for Tegra SOC USB PHY:
 
 Required properties :
- - compatible : Should be "nvidia,tegra20-usb-phy".
+ - compatible : Should be "nvidia,tegra<chip>-usb-phy".
  - reg : Defines the following set of registers, in the order listed:
    - The PHY's own register set.
      Always present.
@@ -24,17 +24,26 @@ Required properties :
 Required properties for phy_type == ulpi:
   - nvidia,phy-reset-gpio : The GPIO used to reset the PHY.
 
-Required PHY timing params for utmi phy:
+Required PHY timing params for utmi phy, for all chips:
   - nvidia,hssync-start-delay : Number of 480 Mhz clock cycles to wait before
     start of sync launches RxActive
   - nvidia,elastic-limit : Variable FIFO Depth of elastic input store
   - nvidia,idle-wait-delay : Number of 480 Mhz clock cycles of idle to wait
     before declare IDLE.
   - nvidia,term-range-adj : Range adjusment on terminations
-  - nvidia,xcvr-setup : HS driver output control
+  - Either one of the following for HS driver output control:
+    - nvidia,xcvr-setup : integer, uses the provided value.
+    - nvidia,xcvr-setup-use-fuses : boolean, indicates that the value is read
+      from the on-chip fuses
+    If both are provided, nvidia,xcvr-setup-use-fuses takes precedence.
   - nvidia,xcvr-lsfslew : LS falling slew rate control.
   - nvidia,xcvr-lsrslew :  LS rising slew rate control.
 
+Required PHY timing params for utmi phy, only on Tegra30 and above:
+  - nvidia,xcvr-hsslew : HS slew rate control.
+  - nvidia,hssquelch-level : HS squelch detector level.
+  - nvidia,hsdiscon-level : HS disconnect detector level.
+
 Optional properties:
   - nvidia,has-legacy-mode : boolean indicates whether this controller can
     operate in legacy mode (as APX 2500 / 2600). In legacy mode some
@@ -48,5 +57,5 @@ Optional properties:
       peripheral means it is device controller
       otg means it can operate as either ("on the go")
 
-Required properties for dr_mode == otg:
+VBUS control (required for dr_mode == otg, optional for dr_mode == host):
   - vbus-supply: regulator for VBUS
diff --git a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
new file mode 100644 (file)
index 0000000..b83d428
--- /dev/null
@@ -0,0 +1,40 @@
+Samsung High Speed USB OTG controller
+-----------------------------
+
+The Samsung HSOTG IP can be found on Samsung SoCs, from S3C6400 onwards.
+It gives functionality of OTG-compliant USB 2.0 host and device with
+support for USB 2.0 high-speed (480Mbps) and full-speed (12 Mbps)
+operation.
+
+Currently only device mode is supported.
+
+Binding details
+-----
+
+Required properties:
+- compatible: "samsung,s3c6400-hsotg" should be used for all currently
+    supported SoC,
+- interrupt-parent: phandle for the interrupt controller to which the
+    interrupt signal of the HSOTG block is routed,
+- interrupts: specifier of interrupt signal of interrupt controller,
+    according to bindings of interrupt controller,
+- clocks: contains an array of clock specifiers:
+    - first entry: OTG clock
+- clock-names: contains array of clock names:
+    - first entry: must be "otg"
+- vusb_d-supply: phandle to voltage regulator of digital section,
+- vusb_a-supply: phandle to voltage regulator of analog section.
+
+Example
+-----
+
+       hsotg@12480000 {
+               compatible = "samsung,s3c6400-hsotg";
+               reg = <0x12480000 0x20000>;
+               interrupts = <0 71 0>;
+               clocks = <&clock 305>;
+               clock-names = "otg";
+               vusb_d-supply = <&vusb_reg>;
+               vusb_a-supply = <&vusbdac_reg>;
+       };
+
diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt
new file mode 100644 (file)
index 0000000..5752df0
--- /dev/null
@@ -0,0 +1,14 @@
+USB xHCI controllers
+
+Required properties:
+  - compatible: should be "xhci-platform".
+  - reg: should contain address and length of the standard XHCI
+    register set for the device.
+  - interrupts: one XHCI interrupt should be described here.
+
+Example:
+       usb@f0931000 {
+               compatible = "xhci-platform";
+               reg = <0xf0931000 0x8c8>;
+               interrupts = <0x0 0x4e 0x0>;
+       };
index 8c5be48b43c82189f192e09126c3c63cf9c4db53..a018da4a7ad7527a5b926b6024362dd03a6f2ce1 100644 (file)
@@ -1,8 +1,11 @@
 SMSC USB3503 High-Speed Hub Controller
 
 Required properties:
-- compatible: Should be "smsc,usb3503".
-- reg: Specifies the i2c slave address, it should be 0x08.
+- compatible: Should be "smsc,usb3503" or "smsc,usb3503a".
+
+Optional properties:
+- reg: Specifies the i2c slave address, it is required and should be 0x08
+       if I2C is used.
 - connect-gpios: Should specify GPIO for connect.
 - disabled-ports: Should specify the ports unused.
        '1' or '2' or '3' are availe for this property to describe the port
index 00d2c644068e9ae5d0e0044150289f0976a0ae9d..50da0d4554445f30ce00809eb9dc50c30bcfcf48 100644 (file)
@@ -195,13 +195,12 @@ by the completion handler.
 
 The handler is of the following type:
 
-       typedef void (*usb_complete_t)(struct urb *, struct pt_regs *)
+       typedef void (*usb_complete_t)(struct urb *)
 
-I.e., it gets the URB that caused the completion call, plus the
-register values at the time of the corresponding interrupt (if any).
-In the completion handler, you should have a look at urb->status to
-detect any USB errors. Since the context parameter is included in the URB,
-you can pass information to the completion handler. 
+I.e., it gets the URB that caused the completion call. In the completion
+handler, you should have a look at urb->status to detect any USB errors.
+Since the context parameter is included in the URB, you can pass
+information to the completion handler.
 
 Note that even when an error (or unlink) is reported, data may have been
 transferred.  That's because USB transfers are packetized; it might take
@@ -210,12 +209,12 @@ have transferred successfully before the completion was called.
 
 
 NOTE:  ***** WARNING *****
-NEVER SLEEP IN A COMPLETION HANDLER.  These are normally called
-during hardware interrupt processing.  If you can, defer substantial
-work to a tasklet (bottom half) to keep system latencies low.  You'll
-probably need to use spinlocks to protect data structures you manipulate
-in completion handlers.
+NEVER SLEEP IN A COMPLETION HANDLER.  These are often called in atomic
+context.
 
+In the current kernel, completion handlers run with local interrupts
+disabled, but in the future this will be changed, so don't assume that
+local IRQs are always disabled inside completion handlers.
 
 1.8. How to do isochronous (ISO) transfers?
 
index c9c3f0f5ad7bfa7b81aa21342b2f1afa4638eebf..98be91982677e89bef390162440c0a90a479eb46 100644 (file)
@@ -54,9 +54,12 @@ it and 002/048 sometime later.
 
 These files can be read as binary data.  The binary data consists
 of first the device descriptor, then the descriptors for each
-configuration of the device.  Multi-byte fields in the device and
-configuration descriptors, but not other descriptors, are converted
-to host endianness by the kernel.  This information is also shown
+configuration of the device.  Multi-byte fields in the device descriptor
+are converted to host endianness by the kernel.  The configuration
+descriptors are in bus endian format! The configuration descriptor
+are wTotalLength bytes apart. If a device returns less configuration
+descriptor data than indicated by wTotalLength there will be a hole in
+the file for the missing bytes.  This information is also shown
 in text form by the /proc/bus/usb/devices file, described later.
 
 These files may also be used to write user-level drivers for the USB
index 229c66b12cc21b9ebe6479932491ecd5e8784118..94da71142b7e17f436cddef30912c86569070585 100644 (file)
@@ -8803,7 +8803,6 @@ W:        http://www.linux-usb.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git
 S:     Supported
 F:     Documentation/usb/
-F:     drivers/net/usb/
 F:     drivers/usb/
 F:     include/linux/usb.h
 F:     include/linux/usb/
index 444b4ede0d6056c878fd992e80d98416b7c94906..a8907b57c75c16c32e5946698539d0467aa1649d 100644 (file)
                        status = "okay";
                };
 
+               musb: usb@47400000 {
+                       status = "okay";
+
+                       control@44e10000 {
+                               status = "okay";
+                       };
+
+                       phy@47401300 {
+                               status = "okay";
+                       };
+
+                       usb@47401000 {
+                               status = "okay";
+                       };
+               };
+
                i2c0: i2c@44e0b000 {
                        pinctrl-names = "default";
                        pinctrl-0 = <&i2c0_pins>;
index 3aee1a43782db9068ac1d82cdd39216de5535a74..c26c16cace3c4407199c263d8037c31fdf47ca5a 100644 (file)
                        };
                };
 
+               musb: usb@47400000 {
+                       status = "okay";
+
+                       control@44e10000 {
+                               status = "okay";
+                       };
+
+                       phy@47401300 {
+                               status = "okay";
+                       };
+
+                       phy@47401b00 {
+                               status = "okay";
+                       };
+
+                       usb@47401000 {
+                               status = "okay";
+                       };
+
+                       usb@47401800 {
+                               status = "okay";
+                       };
+
+                       dma@07402000  {
+                               status = "okay";
+                       };
+               };
+
                i2c1: i2c@4802a000 {
                        pinctrl-names = "default";
                        pinctrl-0 = <&i2c1_pins>;
index 0c8ad173d2b0894b216f54d4e3b1ef9775327166..e92446c6846e4e17c2d83edb397354ebcb928392 100644 (file)
                        };
                };
 
+               musb: usb@47400000 {
+                       status = "okay";
+
+                       control@44e10000 {
+                               status = "okay";
+                       };
+
+                       phy@47401300 {
+                               status = "okay";
+                       };
+
+                       usb@47401000 {
+                               status = "okay";
+                       };
+               };
+
                epwmss2: epwmss@48304000 {
                        status = "okay";
 
index 38b446ba1ce104b42fce6b2737ba2c8755fda4a1..24d63095ab839d0c9aa4f233e294bc8aa4860964 100644 (file)
                serial5 = &uart5;
                d_can0 = &dcan0;
                d_can1 = &dcan1;
+               usb0 = &usb0;
+               usb1 = &usb1;
+               phy0 = &usb0_phy;
+               phy1 = &usb1_phy;
        };
 
        cpus {
                        status = "disabled";
                };
 
-               usb@47400000 {
-                       compatible = "ti,musb-am33xx";
-                       reg = <0x47400000 0x1000        /* usbss */
-                              0x47401000 0x800         /* musb instance 0 */
-                              0x47401800 0x800>;       /* musb instance 1 */
-                       interrupts = <17                /* usbss */
-                                     18                /* musb instance 0 */
-                                     19>;              /* musb instance 1 */
-                       multipoint = <1>;
-                       num-eps = <16>;
-                       ram-bits = <12>;
-                       port0-mode = <3>;
-                       port1-mode = <3>;
-                       power = <250>;
+               usb: usb@47400000 {
+                       compatible = "ti,am33xx-usb";
+                       reg = <0x47400000 0x1000>;
+                       ranges;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        ti,hwmods = "usb_otg_hs";
+                       status = "disabled";
+
+                       ctrl_mod: control@44e10000 {
+                               compatible = "ti,am335x-usb-ctrl-module";
+                               reg = <0x44e10620 0x10
+                                       0x44e10648 0x4>;
+                               reg-names = "phy_ctrl", "wakeup";
+                               status = "disabled";
+                       };
+
+                       usb0_phy: phy@47401300 {
+                               compatible = "ti,am335x-usb-phy";
+                               reg = <0x47401300 0x100>;
+                               reg-names = "phy";
+                               status = "disabled";
+                               ti,ctrl_mod = <&ctrl_mod>;
+                       };
+
+                       usb0: usb@47401000 {
+                               compatible = "ti,musb-am33xx";
+                               ranges;
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               reg = <0x47401000 0x200>;
+                               reg-names = "control";
+                               status = "disabled";
+
+                               musb0: usb@47401400 {
+                                       compatible = "mg,musbmhdrc";
+                                       reg = <0x47401400 0x400>;
+                                       reg-names = "mc";
+                                       interrupts = <18>;
+                                       interrupt-names = "mc";
+                                       multipoint = <1>;
+                                       num-eps = <16>;
+                                       ram-bits = <12>;
+                                       port-mode = <3>;
+                                       power = <250>;
+                                       phys = <&usb0_phy>;
+
+                               dmas = <&cppi41dma  0 0 &cppi41dma  1 0
+                                       &cppi41dma  2 0 &cppi41dma  3 0
+                                       &cppi41dma  4 0 &cppi41dma  5 0
+                                       &cppi41dma  6 0 &cppi41dma  7 0
+                                       &cppi41dma  8 0 &cppi41dma  9 0
+                                       &cppi41dma 10 0 &cppi41dma 11 0
+                                       &cppi41dma 12 0 &cppi41dma 13 0
+                                       &cppi41dma 14 0 &cppi41dma  0 1
+                                       &cppi41dma  1 1 &cppi41dma  2 1
+                                       &cppi41dma  3 1 &cppi41dma  4 1
+                                       &cppi41dma  5 1 &cppi41dma  6 1
+                                       &cppi41dma  7 1 &cppi41dma  8 1
+                                       &cppi41dma  9 1 &cppi41dma 10 1
+                                       &cppi41dma 11 1 &cppi41dma 12 1
+                                       &cppi41dma 13 1 &cppi41dma 14 1>;
+                               dma-names =
+                                       "rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7",
+                                       "rx8", "rx9", "rx10", "rx11", "rx12", "rx13",
+                                       "rx14", "rx15",
+                                       "tx1", "tx2", "tx3", "tx4", "tx5", "tx6", "tx7",
+                                       "tx8", "tx9", "tx10", "tx11", "tx12", "tx13",
+                                       "tx14", "tx15";
+                               };
+                       };
+
+                       usb1_phy: phy@47401b00 {
+                               compatible = "ti,am335x-usb-phy";
+                               reg = <0x47401b00 0x100>;
+                               reg-names = "phy";
+                               status = "disabled";
+                               ti,ctrl_mod = <&ctrl_mod>;
+                       };
+
+                       usb1: usb@47401800 {
+                               compatible = "ti,musb-am33xx";
+                               ranges;
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               reg = <0x47401800 0x200>;
+                               reg-names = "control";
+                               status = "disabled";
+
+                               musb1: usb@47401c00 {
+                                       compatible = "mg,musbmhdrc";
+                                       reg = <0x47401c00 0x400>;
+                                       reg-names = "mc";
+                                       interrupts = <19>;
+                                       interrupt-names = "mc";
+                                       multipoint = <1>;
+                                       num-eps = <16>;
+                                       ram-bits = <12>;
+                                       port-mode = <3>;
+                                       power = <250>;
+                                       phys = <&usb1_phy>;
+
+                               dmas = <&cppi41dma 15 0 &cppi41dma 16 0
+                                       &cppi41dma 17 0 &cppi41dma 18 0
+                                       &cppi41dma 19 0 &cppi41dma 20 0
+                                       &cppi41dma 21 0 &cppi41dma 22 0
+                                       &cppi41dma 23 0 &cppi41dma 24 0
+                                       &cppi41dma 25 0 &cppi41dma 26 0
+                                       &cppi41dma 27 0 &cppi41dma 28 0
+                                       &cppi41dma 29 0 &cppi41dma 15 1
+                                       &cppi41dma 16 1 &cppi41dma 17 1
+                                       &cppi41dma 18 1 &cppi41dma 19 1
+                                       &cppi41dma 20 1 &cppi41dma 21 1
+                                       &cppi41dma 22 1 &cppi41dma 23 1
+                                       &cppi41dma 24 1 &cppi41dma 25 1
+                                       &cppi41dma 26 1 &cppi41dma 27 1
+                                       &cppi41dma 28 1 &cppi41dma 29 1>;
+                               dma-names =
+                                       "rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7",
+                                       "rx8", "rx9", "rx10", "rx11", "rx12", "rx13",
+                                       "rx14", "rx15",
+                                       "tx1", "tx2", "tx3", "tx4", "tx5", "tx6", "tx7",
+                                       "tx8", "tx9", "tx10", "tx11", "tx12", "tx13",
+                                       "tx14", "tx15";
+                               };
+                       };
+
+                       cppi41dma: dma@07402000 {
+                               compatible = "ti,am3359-cppi41";
+                               reg =  <0x47400000 0x1000
+                                       0x47402000 0x1000
+                                       0x47403000 0x1000
+                                       0x47404000 0x4000>;
+                               reg-names = "glue controller scheduler queuemgr";
+                               interrupts = <17>;
+                               interrupt-names = "glue";
+                               #dma-cells = <2>;
+                               #dma-channels = <30>;
+                               #dma-requests = <256>;
+                               status = "disabled";
+                       };
                };
 
                epwmss0: epwmss@48300000 {
index e643620417a9edb4bcabe2a447dbcf38b720f746..07be2cd7b3188f6c943b1928e812dfa676973bfb 100644 (file)
                        utmi-mode = <2>;
                        ranges;
                        dwc3@4a030000 {
-                               compatible = "synopsys,dwc3";
+                               compatible = "snps,dwc3";
                                reg = <0x4a030000 0x1000>;
                                interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
                                usb-phy = <&usb2_phy>, <&usb3_phy>;
index 365760b33a26e1ea9ac7bae3a7c32f7f4bde9878..52526c9a1329947e1def9f77edf1d2e4893d7c62 100644 (file)
 
        usb@c5000000 {
                status = "okay";
-               nvidia,vbus-gpio = <&gpio TEGRA_GPIO(D, 0) GPIO_ACTIVE_HIGH>;
                dr_mode = "otg";
        };
 
index ed4b901b0227405f3cd687f1a832cad4db808f22..3e57b87cc75fe3bc3ae794622f8353d7b4614259 100644 (file)
 
        usb@c5000000 {
                status = "okay";
-               nvidia,vbus-gpio = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_HIGH>;
        };
 
        usb-phy@c5000000 {
index ab67c94db280cebb2fc8c5e7126977a3fee8fb40..a6b1b5bdf288c171e9cc307f765c94a2423952b2 100644 (file)
 
        usb@c5000000 {
                status = "okay";
-               nvidia,vbus-gpio = <&tca6416 0 GPIO_ACTIVE_HIGH>;
        };
 
        usb-phy@c5000000 {
 
        usb@c5008000 {
                status = "okay";
-               nvidia,vbus-gpio = <&tca6416 1 GPIO_ACTIVE_HIGH>;
        };
 
        usb-phy@c5008000 {
index 9653fd8288d2c53f77336111ce9a2396e04eca82..e4570834512e5f874d983d86fbb4dc011981bd13 100644 (file)
                         <&tegra_car TEGRA20_CLK_USBD>;
                clock-names = "reg", "pll_u", "timer", "utmi-pads";
                nvidia,has-legacy-mode;
-               hssync_start_delay = <9>;
-               idle_wait_delay = <17>;
-               elastic_limit = <16>;
-               term_range_adj = <6>;
-               xcvr_setup = <9>;
-               xcvr_lsfslew = <1>;
-               xcvr_lsrslew = <1>;
+               nvidia,hssync-start-delay = <9>;
+               nvidia,idle-wait-delay = <17>;
+               nvidia,elastic-limit = <16>;
+               nvidia,term-range-adj = <6>;
+               nvidia,xcvr-setup = <9>;
+               nvidia,xcvr-lsfslew = <1>;
+               nvidia,xcvr-lsrslew = <1>;
                status = "disabled";
        };
 
                         <&tegra_car TEGRA20_CLK_CLK_M>,
                         <&tegra_car TEGRA20_CLK_USBD>;
                clock-names = "reg", "pll_u", "timer", "utmi-pads";
-               hssync_start_delay = <9>;
-               idle_wait_delay = <17>;
-               elastic_limit = <16>;
-               term_range_adj = <6>;
-               xcvr_setup = <9>;
-               xcvr_lsfslew = <2>;
-               xcvr_lsrslew = <2>;
+               nvidia,hssync-start-delay = <9>;
+               nvidia,idle-wait-delay = <17>;
+               nvidia,elastic-limit = <16>;
+               nvidia,term-range-adj = <6>;
+               nvidia,xcvr-setup = <9>;
+               nvidia,xcvr-lsfslew = <2>;
+               nvidia,xcvr-lsrslew = <2>;
                status = "disabled";
        };
 
index 04c1165554125553b29fc1292404c1cc922ed965..1c6ae5f5bae76753ca637aea07b3ce828d1e7512 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/mtd/nand.h>
 #include <linux/mmc/host.h>
 #include <linux/usb/phy.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 
 #include <linux/regulator/machine.h>
 #include <linux/i2c/twl.h>
@@ -279,7 +279,7 @@ static struct regulator_consumer_supply beagle_vsim_supply[] = {
 static struct gpio_led gpio_leds[];
 
 /* PHY's VCC regulator might be added later, so flag that we need it */
-static struct nop_usb_xceiv_platform_data hsusb2_phy_data = {
+static struct usb_phy_gen_xceiv_platform_data hsusb2_phy_data = {
        .needs_vcc = true,
 };
 
index 8c026269bacaa379ec583dbeb81bd6f3ef9568b9..52bdddd41e0e38d3a1783eb1cc82cd116e2a5ea5 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/i2c/twl.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/musb.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 #include <linux/smsc911x.h>
 
 #include <linux/wl12xx.h>
@@ -468,7 +468,7 @@ struct wl12xx_platform_data omap3evm_wlan_data __initdata = {
 static struct regulator_consumer_supply omap3evm_vaux2_supplies[] = {
        REGULATOR_SUPPLY("VDD_CSIPHY1", "omap3isp"),    /* OMAP ISP */
        REGULATOR_SUPPLY("VDD_CSIPHY2", "omap3isp"),    /* OMAP ISP */
-       REGULATOR_SUPPLY("vcc", "nop_usb_xceiv.2"),     /* hsusb port 2 */
+       REGULATOR_SUPPLY("vcc", "usb_phy_gen_xceiv.2"), /* hsusb port 2 */
        REGULATOR_SUPPLY("vaux2", NULL),
 };
 
index b1547a0edfcd7df38b6e6e2cf5f74daec4ab0b36..d2b455e704861af41e7d36ec174ee7b7c7d8e014 100644 (file)
@@ -352,7 +352,7 @@ static struct regulator_consumer_supply pandora_vcc_lcd_supply[] = {
 };
 
 static struct regulator_consumer_supply pandora_usb_phy_supply[] = {
-       REGULATOR_SUPPLY("vcc", "nop_usb_xceiv.2"),     /* hsusb port 2 */
+       REGULATOR_SUPPLY("vcc", "usb_phy_gen_xceiv.2"), /* hsusb port 2 */
 };
 
 /* ads7846 on SPI and 2 nub controllers on I2C */
index 2eb19d4d0aa1cc041942ce7c8e2586dcc71d6852..e83a6a4b184af23c315a5e509a56ba8362d820e7 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/usb/phy.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 
 #include "soc.h"
 #include "omap_device.h"
@@ -349,7 +349,7 @@ static struct fixed_voltage_config hsusb_reg_config = {
        /* .init_data filled later */
 };
 
-static const char *nop_name = "nop_usb_xceiv"; /* NOP PHY driver */
+static const char *nop_name = "usb_phy_gen_xceiv"; /* NOP PHY driver */
 static const char *reg_name = "reg-fixed-voltage"; /* Regulator driver */
 
 /**
@@ -460,9 +460,9 @@ int usbhs_init_phys(struct usbhs_phy_data *phy, int num_phys)
                pdevinfo.name = nop_name;
                pdevinfo.id = phy->port;
                pdevinfo.data = phy->platform_data;
-               pdevinfo.size_data = sizeof(struct nop_usb_xceiv_platform_data);
-
-               scnprintf(phy_id, MAX_STR, "nop_usb_xceiv.%d",
+               pdevinfo.size_data =
+                       sizeof(struct usb_phy_gen_xceiv_platform_data);
+               scnprintf(phy_id, MAX_STR, "usb_phy_gen_xceiv.%d",
                                        phy->port);
                pdev = platform_device_register_full(&pdevinfo);
                if (IS_ERR(pdev)) {
index 0d1e4128d460effbe40eecb1c299d782df3c8231..fc97cfd52769f687120639481d683f675193478e 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/of_fdt.h>
 #include <linux/of_platform.h>
 #include <linux/pda_power.h>
-#include <linux/platform_data/tegra_usb.h>
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/sys_soc.h>
 #include "fuse.h"
 #include "iomap.h"
 
-static struct tegra_ehci_platform_data tegra_ehci1_pdata = {
-       .operating_mode = TEGRA_USB_OTG,
-       .power_down_on_bus_suspend = 1,
-       .vbus_gpio = -1,
-};
-
-static struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config = {
-       .reset_gpio = -1,
-       .clk = "cdev2",
-};
-
-static struct tegra_ehci_platform_data tegra_ehci2_pdata = {
-       .phy_config = &tegra_ehci2_ulpi_phy_config,
-       .operating_mode = TEGRA_USB_HOST,
-       .power_down_on_bus_suspend = 1,
-       .vbus_gpio = -1,
-};
-
-static struct tegra_ehci_platform_data tegra_ehci3_pdata = {
-       .operating_mode = TEGRA_USB_HOST,
-       .power_down_on_bus_suspend = 1,
-       .vbus_gpio = -1,
-};
-
-static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
-       OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5000000, "tegra-ehci.0",
-                      &tegra_ehci1_pdata),
-       OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5004000, "tegra-ehci.1",
-                      &tegra_ehci2_pdata),
-       OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5008000, "tegra-ehci.2",
-                      &tegra_ehci3_pdata),
-       {}
-};
-
 static void __init tegra_dt_init(void)
 {
        struct soc_device_attribute *soc_dev_attr;
@@ -112,8 +77,7 @@ static void __init tegra_dt_init(void)
         * devices
         */
 out:
-       of_platform_populate(NULL, of_default_bus_match_table,
-                               tegra20_auxdata_lookup, parent);
+       of_platform_populate(NULL, of_default_bus_match_table, NULL, parent);
 }
 
 static void __init trimslice_init(void)
index 6825957c97fb9896dbfa944e6c5520928160a74c..77bc480117b79bb2645c847bcded2b6bdbb27708 100644 (file)
@@ -287,6 +287,14 @@ config DMA_OMAP
        select DMA_ENGINE
        select DMA_VIRTUAL_CHANNELS
 
+config TI_CPPI41
+       tristate "AM33xx CPPI41 DMA support"
+       depends on ARCH_OMAP
+       select DMA_ENGINE
+       help
+         The Communications Port Programming Interface (CPPI) 4.1 DMA engine
+         is currently used by the USB driver on AM335x platforms.
+
 config MMP_PDMA
        bool "MMP PDMA support"
        depends on (ARCH_MMP || ARCH_PXA)
index 5e0f2ef8561485f9a75d7f7362e06c99fffdbcac..6d62ec30c4bc594fcd02bdb1ce79e56a28b9a41f 100644 (file)
@@ -39,3 +39,4 @@ obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o
 obj-$(CONFIG_DMA_OMAP) += omap-dma.o
 obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
 obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
+obj-$(CONFIG_TI_CPPI41) += cppi41.o
diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c
new file mode 100644 (file)
index 0000000..5dcebca
--- /dev/null
@@ -0,0 +1,1048 @@
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/of_dma.h>
+#include <linux/of_irq.h>
+#include <linux/dmapool.h>
+#include <linux/interrupt.h>
+#include <linux/of_address.h>
+#include "dmaengine.h"
+
+#define DESC_TYPE      27
+#define DESC_TYPE_HOST 0x10
+#define DESC_TYPE_TEARD        0x13
+
+#define TD_DESC_IS_RX  (1 << 16)
+#define TD_DESC_DMA_NUM        10
+
+#define DESC_LENGTH_BITS_NUM   21
+
+#define DESC_TYPE_USB  (5 << 26)
+#define DESC_PD_COMPLETE       (1 << 31)
+
+/* DMA engine */
+#define DMA_TDFDQ      4
+#define DMA_TXGCR(x)   (0x800 + (x) * 0x20)
+#define DMA_RXGCR(x)   (0x808 + (x) * 0x20)
+#define RXHPCRA0               4
+
+#define GCR_CHAN_ENABLE                (1 << 31)
+#define GCR_TEARDOWN           (1 << 30)
+#define GCR_STARV_RETRY                (1 << 24)
+#define GCR_DESC_TYPE_HOST     (1 << 14)
+
+/* DMA scheduler */
+#define DMA_SCHED_CTRL         0
+#define DMA_SCHED_CTRL_EN      (1 << 31)
+#define DMA_SCHED_WORD(x)      ((x) * 4 + 0x800)
+
+#define SCHED_ENTRY0_CHAN(x)   ((x) << 0)
+#define SCHED_ENTRY0_IS_RX     (1 << 7)
+
+#define SCHED_ENTRY1_CHAN(x)   ((x) << 8)
+#define SCHED_ENTRY1_IS_RX     (1 << 15)
+
+#define SCHED_ENTRY2_CHAN(x)   ((x) << 16)
+#define SCHED_ENTRY2_IS_RX     (1 << 23)
+
+#define SCHED_ENTRY3_CHAN(x)   ((x) << 24)
+#define SCHED_ENTRY3_IS_RX     (1 << 31)
+
+/* Queue manager */
+/* 4 KiB of memory for descriptors, 2 for each endpoint */
+#define ALLOC_DECS_NUM         128
+#define DESCS_AREAS            1
+#define TOTAL_DESCS_NUM                (ALLOC_DECS_NUM * DESCS_AREAS)
+#define QMGR_SCRATCH_SIZE      (TOTAL_DESCS_NUM * 4)
+
+#define QMGR_LRAM0_BASE                0x80
+#define QMGR_LRAM_SIZE         0x84
+#define QMGR_LRAM1_BASE                0x88
+#define QMGR_MEMBASE(x)                (0x1000 + (x) * 0x10)
+#define QMGR_MEMCTRL(x)                (0x1004 + (x) * 0x10)
+#define QMGR_MEMCTRL_IDX_SH    16
+#define QMGR_MEMCTRL_DESC_SH   8
+
+#define QMGR_NUM_PEND  5
+#define QMGR_PEND(x)   (0x90 + (x) * 4)
+
+#define QMGR_PENDING_SLOT_Q(x) (x / 32)
+#define QMGR_PENDING_BIT_Q(x)  (x % 32)
+
+#define QMGR_QUEUE_A(n)        (0x2000 + (n) * 0x10)
+#define QMGR_QUEUE_B(n)        (0x2004 + (n) * 0x10)
+#define QMGR_QUEUE_C(n)        (0x2008 + (n) * 0x10)
+#define QMGR_QUEUE_D(n)        (0x200c + (n) * 0x10)
+
+/* Glue layer specific */
+/* USBSS  / USB AM335x */
+#define USBSS_IRQ_STATUS       0x28
+#define USBSS_IRQ_ENABLER      0x2c
+#define USBSS_IRQ_CLEARR       0x30
+
+#define USBSS_IRQ_PD_COMP      (1 <<  2)
+
+struct cppi41_channel {
+       struct dma_chan chan;
+       struct dma_async_tx_descriptor txd;
+       struct cppi41_dd *cdd;
+       struct cppi41_desc *desc;
+       dma_addr_t desc_phys;
+       void __iomem *gcr_reg;
+       int is_tx;
+       u32 residue;
+
+       unsigned int q_num;
+       unsigned int q_comp_num;
+       unsigned int port_num;
+
+       unsigned td_retry;
+       unsigned td_queued:1;
+       unsigned td_seen:1;
+       unsigned td_desc_seen:1;
+};
+
+struct cppi41_desc {
+       u32 pd0;
+       u32 pd1;
+       u32 pd2;
+       u32 pd3;
+       u32 pd4;
+       u32 pd5;
+       u32 pd6;
+       u32 pd7;
+} __aligned(32);
+
+struct chan_queues {
+       u16 submit;
+       u16 complete;
+};
+
+struct cppi41_dd {
+       struct dma_device ddev;
+
+       void *qmgr_scratch;
+       dma_addr_t scratch_phys;
+
+       struct cppi41_desc *cd;
+       dma_addr_t descs_phys;
+       u32 first_td_desc;
+       struct cppi41_channel *chan_busy[ALLOC_DECS_NUM];
+
+       void __iomem *usbss_mem;
+       void __iomem *ctrl_mem;
+       void __iomem *sched_mem;
+       void __iomem *qmgr_mem;
+       unsigned int irq;
+       const struct chan_queues *queues_rx;
+       const struct chan_queues *queues_tx;
+       struct chan_queues td_queue;
+};
+
+#define FIST_COMPLETION_QUEUE  93
+static struct chan_queues usb_queues_tx[] = {
+       /* USB0 ENDP 1 */
+       [ 0] = { .submit = 32, .complete =  93},
+       [ 1] = { .submit = 34, .complete =  94},
+       [ 2] = { .submit = 36, .complete =  95},
+       [ 3] = { .submit = 38, .complete =  96},
+       [ 4] = { .submit = 40, .complete =  97},
+       [ 5] = { .submit = 42, .complete =  98},
+       [ 6] = { .submit = 44, .complete =  99},
+       [ 7] = { .submit = 46, .complete = 100},
+       [ 8] = { .submit = 48, .complete = 101},
+       [ 9] = { .submit = 50, .complete = 102},
+       [10] = { .submit = 52, .complete = 103},
+       [11] = { .submit = 54, .complete = 104},
+       [12] = { .submit = 56, .complete = 105},
+       [13] = { .submit = 58, .complete = 106},
+       [14] = { .submit = 60, .complete = 107},
+
+       /* USB1 ENDP1 */
+       [15] = { .submit = 62, .complete = 125},
+       [16] = { .submit = 64, .complete = 126},
+       [17] = { .submit = 66, .complete = 127},
+       [18] = { .submit = 68, .complete = 128},
+       [19] = { .submit = 70, .complete = 129},
+       [20] = { .submit = 72, .complete = 130},
+       [21] = { .submit = 74, .complete = 131},
+       [22] = { .submit = 76, .complete = 132},
+       [23] = { .submit = 78, .complete = 133},
+       [24] = { .submit = 80, .complete = 134},
+       [25] = { .submit = 82, .complete = 135},
+       [26] = { .submit = 84, .complete = 136},
+       [27] = { .submit = 86, .complete = 137},
+       [28] = { .submit = 88, .complete = 138},
+       [29] = { .submit = 90, .complete = 139},
+};
+
+static const struct chan_queues usb_queues_rx[] = {
+       /* USB0 ENDP 1 */
+       [ 0] = { .submit =  1, .complete = 109},
+       [ 1] = { .submit =  2, .complete = 110},
+       [ 2] = { .submit =  3, .complete = 111},
+       [ 3] = { .submit =  4, .complete = 112},
+       [ 4] = { .submit =  5, .complete = 113},
+       [ 5] = { .submit =  6, .complete = 114},
+       [ 6] = { .submit =  7, .complete = 115},
+       [ 7] = { .submit =  8, .complete = 116},
+       [ 8] = { .submit =  9, .complete = 117},
+       [ 9] = { .submit = 10, .complete = 118},
+       [10] = { .submit = 11, .complete = 119},
+       [11] = { .submit = 12, .complete = 120},
+       [12] = { .submit = 13, .complete = 121},
+       [13] = { .submit = 14, .complete = 122},
+       [14] = { .submit = 15, .complete = 123},
+
+       /* USB1 ENDP 1 */
+       [15] = { .submit = 16, .complete = 141},
+       [16] = { .submit = 17, .complete = 142},
+       [17] = { .submit = 18, .complete = 143},
+       [18] = { .submit = 19, .complete = 144},
+       [19] = { .submit = 20, .complete = 145},
+       [20] = { .submit = 21, .complete = 146},
+       [21] = { .submit = 22, .complete = 147},
+       [22] = { .submit = 23, .complete = 148},
+       [23] = { .submit = 24, .complete = 149},
+       [24] = { .submit = 25, .complete = 150},
+       [25] = { .submit = 26, .complete = 151},
+       [26] = { .submit = 27, .complete = 152},
+       [27] = { .submit = 28, .complete = 153},
+       [28] = { .submit = 29, .complete = 154},
+       [29] = { .submit = 30, .complete = 155},
+};
+
+struct cppi_glue_infos {
+       irqreturn_t (*isr)(int irq, void *data);
+       const struct chan_queues *queues_rx;
+       const struct chan_queues *queues_tx;
+       struct chan_queues td_queue;
+};
+
+static struct cppi41_channel *to_cpp41_chan(struct dma_chan *c)
+{
+       return container_of(c, struct cppi41_channel, chan);
+}
+
+static struct cppi41_channel *desc_to_chan(struct cppi41_dd *cdd, u32 desc)
+{
+       struct cppi41_channel *c;
+       u32 descs_size;
+       u32 desc_num;
+
+       descs_size = sizeof(struct cppi41_desc) * ALLOC_DECS_NUM;
+
+       if (!((desc >= cdd->descs_phys) &&
+                       (desc < (cdd->descs_phys + descs_size)))) {
+               return NULL;
+       }
+
+       desc_num = (desc - cdd->descs_phys) / sizeof(struct cppi41_desc);
+       BUG_ON(desc_num > ALLOC_DECS_NUM);
+       c = cdd->chan_busy[desc_num];
+       cdd->chan_busy[desc_num] = NULL;
+       return c;
+}
+
+static void cppi_writel(u32 val, void *__iomem *mem)
+{
+       __raw_writel(val, mem);
+}
+
+static u32 cppi_readl(void *__iomem *mem)
+{
+       return __raw_readl(mem);
+}
+
+static u32 pd_trans_len(u32 val)
+{
+       return val & ((1 << (DESC_LENGTH_BITS_NUM + 1)) - 1);
+}
+
+static irqreturn_t cppi41_irq(int irq, void *data)
+{
+       struct cppi41_dd *cdd = data;
+       struct cppi41_channel *c;
+       u32 status;
+       int i;
+
+       status = cppi_readl(cdd->usbss_mem + USBSS_IRQ_STATUS);
+       if (!(status & USBSS_IRQ_PD_COMP))
+               return IRQ_NONE;
+       cppi_writel(status, cdd->usbss_mem + USBSS_IRQ_STATUS);
+
+       for (i = QMGR_PENDING_SLOT_Q(FIST_COMPLETION_QUEUE); i < QMGR_NUM_PEND;
+                       i++) {
+               u32 val;
+               u32 q_num;
+
+               val = cppi_readl(cdd->qmgr_mem + QMGR_PEND(i));
+               if (i == QMGR_PENDING_SLOT_Q(FIST_COMPLETION_QUEUE) && val) {
+                       u32 mask;
+                       /* set corresponding bit for completetion Q 93 */
+                       mask = 1 << QMGR_PENDING_BIT_Q(FIST_COMPLETION_QUEUE);
+                       /* not set all bits for queues less than Q 93 */
+                       mask--;
+                       /* now invert and keep only Q 93+ set */
+                       val &= ~mask;
+               }
+
+               if (val)
+                       __iormb();
+
+               while (val) {
+                       u32 desc;
+
+                       q_num = __fls(val);
+                       val &= ~(1 << q_num);
+                       q_num += 32 * i;
+                       desc = cppi_readl(cdd->qmgr_mem + QMGR_QUEUE_D(q_num));
+                       desc &= ~0x1f;
+                       c = desc_to_chan(cdd, desc);
+                       if (WARN_ON(!c)) {
+                               pr_err("%s() q %d desc %08x\n", __func__,
+                                               q_num, desc);
+                               continue;
+                       }
+                       c->residue = pd_trans_len(c->desc->pd6) -
+                               pd_trans_len(c->desc->pd0);
+
+                       dma_cookie_complete(&c->txd);
+                       c->txd.callback(c->txd.callback_param);
+               }
+       }
+       return IRQ_HANDLED;
+}
+
+static dma_cookie_t cppi41_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+       dma_cookie_t cookie;
+
+       cookie = dma_cookie_assign(tx);
+
+       return cookie;
+}
+
+static int cppi41_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+       struct cppi41_channel *c = to_cpp41_chan(chan);
+
+       dma_cookie_init(chan);
+       dma_async_tx_descriptor_init(&c->txd, chan);
+       c->txd.tx_submit = cppi41_tx_submit;
+
+       if (!c->is_tx)
+               cppi_writel(c->q_num, c->gcr_reg + RXHPCRA0);
+
+       return 0;
+}
+
+static void cppi41_dma_free_chan_resources(struct dma_chan *chan)
+{
+}
+
+static enum dma_status cppi41_dma_tx_status(struct dma_chan *chan,
+       dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+       struct cppi41_channel *c = to_cpp41_chan(chan);
+       enum dma_status ret;
+
+       /* lock */
+       ret = dma_cookie_status(chan, cookie, txstate);
+       if (txstate && ret == DMA_SUCCESS)
+               txstate->residue = c->residue;
+       /* unlock */
+
+       return ret;
+}
+
+static void push_desc_queue(struct cppi41_channel *c)
+{
+       struct cppi41_dd *cdd = c->cdd;
+       u32 desc_num;
+       u32 desc_phys;
+       u32 reg;
+
+       desc_phys = lower_32_bits(c->desc_phys);
+       desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
+       WARN_ON(cdd->chan_busy[desc_num]);
+       cdd->chan_busy[desc_num] = c;
+
+       reg = (sizeof(struct cppi41_desc) - 24) / 4;
+       reg |= desc_phys;
+       cppi_writel(reg, cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num));
+}
+
+static void cppi41_dma_issue_pending(struct dma_chan *chan)
+{
+       struct cppi41_channel *c = to_cpp41_chan(chan);
+       u32 reg;
+
+       c->residue = 0;
+
+       reg = GCR_CHAN_ENABLE;
+       if (!c->is_tx) {
+               reg |= GCR_STARV_RETRY;
+               reg |= GCR_DESC_TYPE_HOST;
+               reg |= c->q_comp_num;
+       }
+
+       cppi_writel(reg, c->gcr_reg);
+
+       /*
+        * We don't use writel() but __raw_writel() so we have to make sure
+        * that the DMA descriptor in coherent memory made to the main memory
+        * before starting the dma engine.
+        */
+       __iowmb();
+       push_desc_queue(c);
+}
+
+static u32 get_host_pd0(u32 length)
+{
+       u32 reg;
+
+       reg = DESC_TYPE_HOST << DESC_TYPE;
+       reg |= length;
+
+       return reg;
+}
+
+static u32 get_host_pd1(struct cppi41_channel *c)
+{
+       u32 reg;
+
+       reg = 0;
+
+       return reg;
+}
+
+static u32 get_host_pd2(struct cppi41_channel *c)
+{
+       u32 reg;
+
+       reg = DESC_TYPE_USB;
+       reg |= c->q_comp_num;
+
+       return reg;
+}
+
+static u32 get_host_pd3(u32 length)
+{
+       u32 reg;
+
+       /* PD3 = packet size */
+       reg = length;
+
+       return reg;
+}
+
+static u32 get_host_pd6(u32 length)
+{
+       u32 reg;
+
+       /* PD6 buffer size */
+       reg = DESC_PD_COMPLETE;
+       reg |= length;
+
+       return reg;
+}
+
+static u32 get_host_pd4_or_7(u32 addr)
+{
+       u32 reg;
+
+       reg = addr;
+
+       return reg;
+}
+
+static u32 get_host_pd5(void)
+{
+       u32 reg;
+
+       reg = 0;
+
+       return reg;
+}
+
+static struct dma_async_tx_descriptor *cppi41_dma_prep_slave_sg(
+       struct dma_chan *chan, struct scatterlist *sgl, unsigned sg_len,
+       enum dma_transfer_direction dir, unsigned long tx_flags, void *context)
+{
+       struct cppi41_channel *c = to_cpp41_chan(chan);
+       struct cppi41_desc *d;
+       struct scatterlist *sg;
+       unsigned int i;
+       unsigned int num;
+
+       num = 0;
+       d = c->desc;
+       for_each_sg(sgl, sg, sg_len, i) {
+               u32 addr;
+               u32 len;
+
+               /* We need to use more than one desc once musb supports sg */
+               BUG_ON(num > 0);
+               addr = lower_32_bits(sg_dma_address(sg));
+               len = sg_dma_len(sg);
+
+               d->pd0 = get_host_pd0(len);
+               d->pd1 = get_host_pd1(c);
+               d->pd2 = get_host_pd2(c);
+               d->pd3 = get_host_pd3(len);
+               d->pd4 = get_host_pd4_or_7(addr);
+               d->pd5 = get_host_pd5();
+               d->pd6 = get_host_pd6(len);
+               d->pd7 = get_host_pd4_or_7(addr);
+
+               d++;
+       }
+
+       return &c->txd;
+}
+
+static int cpp41_cfg_chan(struct cppi41_channel *c,
+               struct dma_slave_config *cfg)
+{
+       return 0;
+}
+
+static void cppi41_compute_td_desc(struct cppi41_desc *d)
+{
+       d->pd0 = DESC_TYPE_TEARD << DESC_TYPE;
+}
+
+static u32 cppi41_pop_desc(struct cppi41_dd *cdd, unsigned queue_num)
+{
+       u32 desc;
+
+       desc = cppi_readl(cdd->qmgr_mem + QMGR_QUEUE_D(queue_num));
+       desc &= ~0x1f;
+       return desc;
+}
+
+static int cppi41_tear_down_chan(struct cppi41_channel *c)
+{
+       struct cppi41_dd *cdd = c->cdd;
+       struct cppi41_desc *td;
+       u32 reg;
+       u32 desc_phys;
+       u32 td_desc_phys;
+
+       td = cdd->cd;
+       td += cdd->first_td_desc;
+
+       td_desc_phys = cdd->descs_phys;
+       td_desc_phys += cdd->first_td_desc * sizeof(struct cppi41_desc);
+
+       if (!c->td_queued) {
+               cppi41_compute_td_desc(td);
+               __iowmb();
+
+               reg = (sizeof(struct cppi41_desc) - 24) / 4;
+               reg |= td_desc_phys;
+               cppi_writel(reg, cdd->qmgr_mem +
+                               QMGR_QUEUE_D(cdd->td_queue.submit));
+
+               reg = GCR_CHAN_ENABLE;
+               if (!c->is_tx) {
+                       reg |= GCR_STARV_RETRY;
+                       reg |= GCR_DESC_TYPE_HOST;
+                       reg |= c->q_comp_num;
+               }
+               reg |= GCR_TEARDOWN;
+               cppi_writel(reg, c->gcr_reg);
+               c->td_queued = 1;
+               c->td_retry = 100;
+       }
+
+       if (!c->td_seen) {
+               unsigned td_comp_queue;
+
+               if (c->is_tx)
+                       td_comp_queue =  cdd->td_queue.complete;
+               else
+                       td_comp_queue =  c->q_comp_num;
+
+               desc_phys = cppi41_pop_desc(cdd, td_comp_queue);
+               if (desc_phys) {
+                       __iormb();
+
+                       if (desc_phys == td_desc_phys) {
+                               u32 pd0;
+                               pd0 = td->pd0;
+                               WARN_ON((pd0 >> DESC_TYPE) != DESC_TYPE_TEARD);
+                               WARN_ON(!c->is_tx && !(pd0 & TD_DESC_IS_RX));
+                               WARN_ON((pd0 & 0x1f) != c->port_num);
+                       } else {
+                               __WARN();
+                       }
+                       c->td_seen = 1;
+               }
+       }
+       if (!c->td_desc_seen) {
+               desc_phys = cppi41_pop_desc(cdd, c->q_comp_num);
+               if (desc_phys) {
+                       __iormb();
+                       WARN_ON(c->desc_phys != desc_phys);
+                       c->td_desc_seen = 1;
+               }
+       }
+       c->td_retry--;
+       /*
+        * If the TX descriptor / channel is in use, the caller needs to poke
+        * his TD bit multiple times. After that he hardware releases the
+        * transfer descriptor followed by TD descriptor. Waiting seems not to
+        * cause any difference.
+        * RX seems to be thrown out right away. However once the TearDown
+        * descriptor gets through we are done. If we have seens the transfer
+        * descriptor before the TD we fetch it from enqueue, it has to be
+        * there waiting for us.
+        */
+       if (!c->td_seen && c->td_retry)
+               return -EAGAIN;
+
+       WARN_ON(!c->td_retry);
+       if (!c->td_desc_seen) {
+               desc_phys = cppi_readl(cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num));
+               WARN_ON(!desc_phys);
+       }
+
+       c->td_queued = 0;
+       c->td_seen = 0;
+       c->td_desc_seen = 0;
+       cppi_writel(0, c->gcr_reg);
+       return 0;
+}
+
+static int cppi41_stop_chan(struct dma_chan *chan)
+{
+       struct cppi41_channel *c = to_cpp41_chan(chan);
+       struct cppi41_dd *cdd = c->cdd;
+       u32 desc_num;
+       u32 desc_phys;
+       int ret;
+
+       ret = cppi41_tear_down_chan(c);
+       if (ret)
+               return ret;
+
+       desc_phys = lower_32_bits(c->desc_phys);
+       desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
+       WARN_ON(!cdd->chan_busy[desc_num]);
+       cdd->chan_busy[desc_num] = NULL;
+
+       return 0;
+}
+
+static int cppi41_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+       unsigned long arg)
+{
+       struct cppi41_channel *c = to_cpp41_chan(chan);
+       int ret;
+
+       switch (cmd) {
+       case DMA_SLAVE_CONFIG:
+               ret = cpp41_cfg_chan(c, (struct dma_slave_config *) arg);
+               break;
+
+       case DMA_TERMINATE_ALL:
+               ret = cppi41_stop_chan(chan);
+               break;
+
+       default:
+               ret = -ENXIO;
+               break;
+       }
+       return ret;
+}
+
+static void cleanup_chans(struct cppi41_dd *cdd)
+{
+       while (!list_empty(&cdd->ddev.channels)) {
+               struct cppi41_channel *cchan;
+
+               cchan = list_first_entry(&cdd->ddev.channels,
+                               struct cppi41_channel, chan.device_node);
+               list_del(&cchan->chan.device_node);
+               kfree(cchan);
+       }
+}
+
+static int cppi41_add_chans(struct platform_device *pdev, struct cppi41_dd *cdd)
+{
+       struct cppi41_channel *cchan;
+       int i;
+       int ret;
+       u32 n_chans;
+
+       ret = of_property_read_u32(pdev->dev.of_node, "#dma-channels",
+                       &n_chans);
+       if (ret)
+               return ret;
+       /*
+        * The channels can only be used as TX or as RX. So we add twice
+        * that much dma channels because USB can only do RX or TX.
+        */
+       n_chans *= 2;
+
+       for (i = 0; i < n_chans; i++) {
+               cchan = kzalloc(sizeof(*cchan), GFP_KERNEL);
+               if (!cchan)
+                       goto err;
+
+               cchan->cdd = cdd;
+               if (i & 1) {
+                       cchan->gcr_reg = cdd->ctrl_mem + DMA_TXGCR(i >> 1);
+                       cchan->is_tx = 1;
+               } else {
+                       cchan->gcr_reg = cdd->ctrl_mem + DMA_RXGCR(i >> 1);
+                       cchan->is_tx = 0;
+               }
+               cchan->port_num = i >> 1;
+               cchan->desc = &cdd->cd[i];
+               cchan->desc_phys = cdd->descs_phys;
+               cchan->desc_phys += i * sizeof(struct cppi41_desc);
+               cchan->chan.device = &cdd->ddev;
+               list_add_tail(&cchan->chan.device_node, &cdd->ddev.channels);
+       }
+       cdd->first_td_desc = n_chans;
+
+       return 0;
+err:
+       cleanup_chans(cdd);
+       return -ENOMEM;
+}
+
+static void purge_descs(struct platform_device *pdev, struct cppi41_dd *cdd)
+{
+       unsigned int mem_decs;
+       int i;
+
+       mem_decs = ALLOC_DECS_NUM * sizeof(struct cppi41_desc);
+
+       for (i = 0; i < DESCS_AREAS; i++) {
+
+               cppi_writel(0, cdd->qmgr_mem + QMGR_MEMBASE(i));
+               cppi_writel(0, cdd->qmgr_mem + QMGR_MEMCTRL(i));
+
+               dma_free_coherent(&pdev->dev, mem_decs, cdd->cd,
+                               cdd->descs_phys);
+       }
+}
+
+static void disable_sched(struct cppi41_dd *cdd)
+{
+       cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL);
+}
+
+static void deinit_cpii41(struct platform_device *pdev, struct cppi41_dd *cdd)
+{
+       disable_sched(cdd);
+
+       purge_descs(pdev, cdd);
+
+       cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM0_BASE);
+       cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM0_BASE);
+       dma_free_coherent(&pdev->dev, QMGR_SCRATCH_SIZE, cdd->qmgr_scratch,
+                       cdd->scratch_phys);
+}
+
+static int init_descs(struct platform_device *pdev, struct cppi41_dd *cdd)
+{
+       unsigned int desc_size;
+       unsigned int mem_decs;
+       int i;
+       u32 reg;
+       u32 idx;
+
+       BUILD_BUG_ON(sizeof(struct cppi41_desc) &
+                       (sizeof(struct cppi41_desc) - 1));
+       BUILD_BUG_ON(sizeof(struct cppi41_desc) < 32);
+       BUILD_BUG_ON(ALLOC_DECS_NUM < 32);
+
+       desc_size = sizeof(struct cppi41_desc);
+       mem_decs = ALLOC_DECS_NUM * desc_size;
+
+       idx = 0;
+       for (i = 0; i < DESCS_AREAS; i++) {
+
+               reg = idx << QMGR_MEMCTRL_IDX_SH;
+               reg |= (ilog2(desc_size) - 5) << QMGR_MEMCTRL_DESC_SH;
+               reg |= ilog2(ALLOC_DECS_NUM) - 5;
+
+               BUILD_BUG_ON(DESCS_AREAS != 1);
+               cdd->cd = dma_alloc_coherent(&pdev->dev, mem_decs,
+                               &cdd->descs_phys, GFP_KERNEL);
+               if (!cdd->cd)
+                       return -ENOMEM;
+
+               cppi_writel(cdd->descs_phys, cdd->qmgr_mem + QMGR_MEMBASE(i));
+               cppi_writel(reg, cdd->qmgr_mem + QMGR_MEMCTRL(i));
+
+               idx += ALLOC_DECS_NUM;
+       }
+       return 0;
+}
+
+static void init_sched(struct cppi41_dd *cdd)
+{
+       unsigned ch;
+       unsigned word;
+       u32 reg;
+
+       word = 0;
+       cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL);
+       for (ch = 0; ch < 15 * 2; ch += 2) {
+
+               reg = SCHED_ENTRY0_CHAN(ch);
+               reg |= SCHED_ENTRY1_CHAN(ch) | SCHED_ENTRY1_IS_RX;
+
+               reg |= SCHED_ENTRY2_CHAN(ch + 1);
+               reg |= SCHED_ENTRY3_CHAN(ch + 1) | SCHED_ENTRY3_IS_RX;
+               cppi_writel(reg, cdd->sched_mem + DMA_SCHED_WORD(word));
+               word++;
+       }
+       reg = 15 * 2 * 2 - 1;
+       reg |= DMA_SCHED_CTRL_EN;
+       cppi_writel(reg, cdd->sched_mem + DMA_SCHED_CTRL);
+}
+
+static int init_cppi41(struct platform_device *pdev, struct cppi41_dd *cdd)
+{
+       int ret;
+
+       BUILD_BUG_ON(QMGR_SCRATCH_SIZE > ((1 << 14) - 1));
+       cdd->qmgr_scratch = dma_alloc_coherent(&pdev->dev, QMGR_SCRATCH_SIZE,
+                       &cdd->scratch_phys, GFP_KERNEL);
+       if (!cdd->qmgr_scratch)
+               return -ENOMEM;
+
+       cppi_writel(cdd->scratch_phys, cdd->qmgr_mem + QMGR_LRAM0_BASE);
+       cppi_writel(QMGR_SCRATCH_SIZE, cdd->qmgr_mem + QMGR_LRAM_SIZE);
+       cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM1_BASE);
+
+       ret = init_descs(pdev, cdd);
+       if (ret)
+               goto err_td;
+
+       cppi_writel(cdd->td_queue.submit, cdd->ctrl_mem + DMA_TDFDQ);
+       init_sched(cdd);
+       return 0;
+err_td:
+       deinit_cpii41(pdev, cdd);
+       return ret;
+}
+
+static struct platform_driver cpp41_dma_driver;
+/*
+ * The param format is:
+ * X Y
+ * X: Port
+ * Y: 0 = RX else TX
+ */
+#define INFO_PORT      0
+#define INFO_IS_TX     1
+
+static bool cpp41_dma_filter_fn(struct dma_chan *chan, void *param)
+{
+       struct cppi41_channel *cchan;
+       struct cppi41_dd *cdd;
+       const struct chan_queues *queues;
+       u32 *num = param;
+
+       if (chan->device->dev->driver != &cpp41_dma_driver.driver)
+               return false;
+
+       cchan = to_cpp41_chan(chan);
+
+       if (cchan->port_num != num[INFO_PORT])
+               return false;
+
+       if (cchan->is_tx && !num[INFO_IS_TX])
+               return false;
+       cdd = cchan->cdd;
+       if (cchan->is_tx)
+               queues = cdd->queues_tx;
+       else
+               queues = cdd->queues_rx;
+
+       BUILD_BUG_ON(ARRAY_SIZE(usb_queues_rx) != ARRAY_SIZE(usb_queues_tx));
+       if (WARN_ON(cchan->port_num > ARRAY_SIZE(usb_queues_rx)))
+               return false;
+
+       cchan->q_num = queues[cchan->port_num].submit;
+       cchan->q_comp_num = queues[cchan->port_num].complete;
+       return true;
+}
+
+static struct of_dma_filter_info cpp41_dma_info = {
+       .filter_fn = cpp41_dma_filter_fn,
+};
+
+static struct dma_chan *cppi41_dma_xlate(struct of_phandle_args *dma_spec,
+               struct of_dma *ofdma)
+{
+       int count = dma_spec->args_count;
+       struct of_dma_filter_info *info = ofdma->of_dma_data;
+
+       if (!info || !info->filter_fn)
+               return NULL;
+
+       if (count != 2)
+               return NULL;
+
+       return dma_request_channel(info->dma_cap, info->filter_fn,
+                       &dma_spec->args[0]);
+}
+
+static const struct cppi_glue_infos usb_infos = {
+       .isr = cppi41_irq,
+       .queues_rx = usb_queues_rx,
+       .queues_tx = usb_queues_tx,
+       .td_queue = { .submit = 31, .complete = 0 },
+};
+
+static const struct of_device_id cppi41_dma_ids[] = {
+       { .compatible = "ti,am3359-cppi41", .data = &usb_infos},
+       {},
+};
+MODULE_DEVICE_TABLE(of, cppi41_dma_ids);
+
+static const struct cppi_glue_infos *get_glue_info(struct platform_device *pdev)
+{
+       const struct of_device_id *of_id;
+
+       of_id = of_match_node(cppi41_dma_ids, pdev->dev.of_node);
+       if (!of_id)
+               return NULL;
+       return of_id->data;
+}
+
+static int cppi41_dma_probe(struct platform_device *pdev)
+{
+       struct cppi41_dd *cdd;
+       const struct cppi_glue_infos *glue_info;
+       int irq;
+       int ret;
+
+       glue_info = get_glue_info(pdev);
+       if (!glue_info)
+               return -EINVAL;
+
+       cdd = kzalloc(sizeof(*cdd), GFP_KERNEL);
+       if (!cdd)
+               return -ENOMEM;
+
+       dma_cap_set(DMA_SLAVE, cdd->ddev.cap_mask);
+       cdd->ddev.device_alloc_chan_resources = cppi41_dma_alloc_chan_resources;
+       cdd->ddev.device_free_chan_resources = cppi41_dma_free_chan_resources;
+       cdd->ddev.device_tx_status = cppi41_dma_tx_status;
+       cdd->ddev.device_issue_pending = cppi41_dma_issue_pending;
+       cdd->ddev.device_prep_slave_sg = cppi41_dma_prep_slave_sg;
+       cdd->ddev.device_control = cppi41_dma_control;
+       cdd->ddev.dev = &pdev->dev;
+       INIT_LIST_HEAD(&cdd->ddev.channels);
+       cpp41_dma_info.dma_cap = cdd->ddev.cap_mask;
+
+       cdd->usbss_mem = of_iomap(pdev->dev.of_node, 0);
+       cdd->ctrl_mem = of_iomap(pdev->dev.of_node, 1);
+       cdd->sched_mem = of_iomap(pdev->dev.of_node, 2);
+       cdd->qmgr_mem = of_iomap(pdev->dev.of_node, 3);
+
+       if (!cdd->usbss_mem || !cdd->ctrl_mem || !cdd->sched_mem ||
+                       !cdd->qmgr_mem) {
+               ret = -ENXIO;
+               goto err_remap;
+       }
+
+       cdd->queues_rx = glue_info->queues_rx;
+       cdd->queues_tx = glue_info->queues_tx;
+       cdd->td_queue = glue_info->td_queue;
+
+       ret = init_cppi41(pdev, cdd);
+       if (ret)
+               goto err_init_cppi;
+
+       ret = cppi41_add_chans(pdev, cdd);
+       if (ret)
+               goto err_chans;
+
+       irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+       if (!irq)
+               goto err_irq;
+
+       cppi_writel(USBSS_IRQ_PD_COMP, cdd->usbss_mem + USBSS_IRQ_ENABLER);
+
+       ret = request_irq(irq, glue_info->isr, IRQF_SHARED,
+                       dev_name(&pdev->dev), cdd);
+       if (ret)
+               goto err_irq;
+       cdd->irq = irq;
+
+       ret = dma_async_device_register(&cdd->ddev);
+       if (ret)
+               goto err_dma_reg;
+
+       ret = of_dma_controller_register(pdev->dev.of_node,
+                       cppi41_dma_xlate, &cpp41_dma_info);
+       if (ret)
+               goto err_of;
+
+       platform_set_drvdata(pdev, cdd);
+       return 0;
+err_of:
+       dma_async_device_unregister(&cdd->ddev);
+err_dma_reg:
+       free_irq(irq, cdd);
+err_irq:
+       cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR);
+       cleanup_chans(cdd);
+err_chans:
+       deinit_cpii41(pdev, cdd);
+err_init_cppi:
+       iounmap(cdd->usbss_mem);
+       iounmap(cdd->ctrl_mem);
+       iounmap(cdd->sched_mem);
+       iounmap(cdd->qmgr_mem);
+err_remap:
+       kfree(cdd);
+       return ret;
+}
+
+static int cppi41_dma_remove(struct platform_device *pdev)
+{
+       struct cppi41_dd *cdd = platform_get_drvdata(pdev);
+
+       of_dma_controller_free(pdev->dev.of_node);
+       dma_async_device_unregister(&cdd->ddev);
+
+       cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR);
+       free_irq(cdd->irq, cdd);
+       cleanup_chans(cdd);
+       deinit_cpii41(pdev, cdd);
+       iounmap(cdd->usbss_mem);
+       iounmap(cdd->ctrl_mem);
+       iounmap(cdd->sched_mem);
+       iounmap(cdd->qmgr_mem);
+       kfree(cdd);
+       return 0;
+}
+
+static struct platform_driver cpp41_dma_driver = {
+       .probe  = cppi41_dma_probe,
+       .remove = cppi41_dma_remove,
+       .driver = {
+               .name = "cppi41-dma-engine",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(cppi41_dma_ids),
+       },
+};
+
+module_platform_driver(cpp41_dma_driver);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
index 2bc87e3a8141d259502bcfbfccc9e0a5b649800b..4233c05a3e326401ef1c2462d408861c693f0db1 100644 (file)
@@ -1028,12 +1028,20 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->mii.phy_id = 0x03;
        dev->mii.supports_gmii = 1;
 
+       if (usb_device_no_sg_constraint(dev->udev))
+               dev->can_dma_sg = 1;
+
        dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                              NETIF_F_RXCSUM;
 
        dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                                 NETIF_F_RXCSUM;
 
+       if (dev->can_dma_sg) {
+               dev->net->features |= NETIF_F_SG | NETIF_F_TSO;
+               dev->net->hw_features |= NETIF_F_SG | NETIF_F_TSO;
+       }
+
        /* Enable checksum offload */
        *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
               AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
index 06ee82f557d45ba31b4847c187f57771ae2c73d2..27a00b00603325c61a96d36a7b7ecd1fe64dd269 100644 (file)
@@ -1197,6 +1197,37 @@ EXPORT_SYMBOL_GPL(usbnet_tx_timeout);
 
 /*-------------------------------------------------------------------------*/
 
+static int build_dma_sg(const struct sk_buff *skb, struct urb *urb)
+{
+       unsigned num_sgs, total_len = 0;
+       int i, s = 0;
+
+       num_sgs = skb_shinfo(skb)->nr_frags + 1;
+       if (num_sgs == 1)
+               return 0;
+
+       urb->sg = kmalloc(num_sgs * sizeof(struct scatterlist), GFP_ATOMIC);
+       if (!urb->sg)
+               return -ENOMEM;
+
+       urb->num_sgs = num_sgs;
+       sg_init_table(urb->sg, urb->num_sgs);
+
+       sg_set_buf(&urb->sg[s++], skb->data, skb_headlen(skb));
+       total_len += skb_headlen(skb);
+
+       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+               struct skb_frag_struct *f = &skb_shinfo(skb)->frags[i];
+
+               total_len += skb_frag_size(f);
+               sg_set_page(&urb->sg[i + s], f->page.p, f->size,
+                               f->page_offset);
+       }
+       urb->transfer_buffer_length = total_len;
+
+       return 1;
+}
+
 netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
                                     struct net_device *net)
 {
@@ -1223,7 +1254,6 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
                        goto drop;
                }
        }
-       length = skb->len;
 
        if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) {
                netif_dbg(dev, tx_err, dev->net, "no urb\n");
@@ -1233,10 +1263,14 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
        entry = (struct skb_data *) skb->cb;
        entry->urb = urb;
        entry->dev = dev;
-       entry->length = length;
 
        usb_fill_bulk_urb (urb, dev->udev, dev->out,
                        skb->data, skb->len, tx_complete, skb);
+       if (dev->can_dma_sg) {
+               if (build_dma_sg(skb, urb) < 0)
+                       goto drop;
+       }
+       entry->length = length = urb->transfer_buffer_length;
 
        /* don't assume the hardware handles USB_ZERO_PACKET
         * NOTE:  strictly conforming cdc-ether devices should expect
@@ -1305,7 +1339,10 @@ drop:
 not_drop:
                if (skb)
                        dev_kfree_skb_any (skb);
-               usb_free_urb (urb);
+               if (urb) {
+                       kfree(urb->sg);
+                       usb_free_urb(urb);
+               }
        } else
                netif_dbg(dev, tx_queued, dev->net,
                          "> tx, len %d, type 0x%x\n", length, skb->protocol);
@@ -1356,6 +1393,7 @@ static void usbnet_bh (unsigned long param)
                        rx_process (dev, skb);
                        continue;
                case tx_done:
+                       kfree(entry->urb->sg);
                case rx_cleanup:
                        usb_free_urb (entry->urb);
                        dev_kfree_skb (skb);
@@ -1689,6 +1727,7 @@ int usbnet_resume (struct usb_interface *intf)
                        retval = usb_submit_urb(res, GFP_ATOMIC);
                        if (retval < 0) {
                                dev_kfree_skb_any(skb);
+                               kfree(res->sg);
                                usb_free_urb(res);
                                usb_autopm_put_interface_async(dev->intf);
                        } else {
index 73f62caa86097c0e735299589808a5c2be8faad9..2642b8a11e05f25c760ef84343d3dd7c17bb0390 100644 (file)
@@ -6,9 +6,26 @@
 config USB_ARCH_HAS_OHCI
        bool
 
+config USB_OHCI_BIG_ENDIAN_DESC
+       bool
+
+config USB_OHCI_BIG_ENDIAN_MMIO
+       bool
+
+config USB_OHCI_LITTLE_ENDIAN
+       bool
+       default n if STB03xxx || PPC_MPC52xx
+       default y
+
 config USB_ARCH_HAS_EHCI
        bool
 
+config USB_EHCI_BIG_ENDIAN_MMIO
+       bool
+
+config USB_EHCI_BIG_ENDIAN_DESC
+       bool
+
 config USB_ARCH_HAS_XHCI
        bool
 
index 238c5d47cadb47d469d871ad6cf0e86dc0675c8f..70d7c5b92c3ced66e0e3a48804bf883011326f74 100644 (file)
@@ -26,6 +26,7 @@ obj-$(CONFIG_USB_ISP1760_HCD) += host/
 obj-$(CONFIG_USB_IMX21_HCD)    += host/
 obj-$(CONFIG_USB_FSL_MPH_DR_OF)        += host/
 obj-$(CONFIG_USB_FUSBH200_HCD) += host/
+obj-$(CONFIG_USB_FOTG210_HCD)  += host/
 
 obj-$(CONFIG_USB_C67X00_HCD)   += c67x00/
 
@@ -45,7 +46,7 @@ obj-$(CONFIG_USB_MICROTEK)    += image/
 obj-$(CONFIG_USB_SERIAL)       += serial/
 
 obj-$(CONFIG_USB)              += misc/
-obj-$(CONFIG_USB_PHY)          += phy/
+obj-$(CONFIG_USB_SUPPORT)      += phy/
 obj-$(CONFIG_EARLY_PRINTK_DBGP)        += early/
 
 obj-$(CONFIG_USB_ATM)          += atm/
index a5d792ec3ad59328a08f544780acb9a791eef67a..ac278946b06c037ddaa88651b1843820e6627763 100644 (file)
@@ -1,9 +1,6 @@
 #
 # Makefile for USB ATM/xDSL drivers
 #
-
-ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
-
 obj-$(CONFIG_USB_CXACRU)       += cxacru.o
 obj-$(CONFIG_USB_SPEEDTOUCH)   += speedtch.o
 obj-$(CONFIG_USB_UEAGLEATM)    += ueagle-atm.o
index 807627b36cc855dae7228daffbe7ce392b694f7f..69461d65397206b24690e0e22c757fade27e6049 100644 (file)
@@ -888,7 +888,7 @@ static int speedtch_bind(struct usbatm_data *usbatm,
                usb_fill_int_urb(instance->int_urb, usb_dev,
                                 usb_rcvintpipe(usb_dev, ENDPOINT_INT),
                                 instance->int_data, sizeof(instance->int_data),
-                                speedtch_handle_int, instance, 50);
+                                speedtch_handle_int, instance, 16);
        else
                usb_dbg(usbatm, "%s: no memory for interrupt urb!\n", __func__);
 
index 5e0d33a7da58de75222807f17a915c373575ca8c..25a7bfcf666c6fdaa92b202bb6b5b154326013e8 100644 (file)
@@ -311,8 +311,6 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char
        int vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4);
        u8 pti = ((source[3] & 0xe) >> 1);
 
-       vdbg(&instance->usb_intf->dev, "%s: vpi %hd, vci %d, pti %d", __func__, vpi, vci, pti);
-
        if ((vci != instance->cached_vci) || (vpi != instance->cached_vpi)) {
                instance->cached_vpi = vpi;
                instance->cached_vci = vci;
@@ -344,7 +342,6 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char
                                __func__, sarb->len, vcc);
                /* discard cells already received */
                skb_trim(sarb, 0);
-               UDSL_ASSERT(instance, sarb->tail + ATM_CELL_PAYLOAD <= sarb->end);
        }
 
        memcpy(skb_tail_pointer(sarb), source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD);
@@ -437,8 +434,6 @@ static void usbatm_extract_cells(struct usbatm_data *instance,
                unsigned char *cell_buf = instance->cell_buf;
                unsigned int space_left = stride - buf_usage;
 
-               UDSL_ASSERT(instance, buf_usage <= stride);
-
                if (avail_data >= space_left) {
                        /* add new data and process cell */
                        memcpy(cell_buf + buf_usage, source, space_left);
@@ -479,10 +474,6 @@ static unsigned int usbatm_write_cells(struct usbatm_data *instance,
        unsigned int bytes_written;
        unsigned int stride = instance->tx_channel.stride;
 
-       vdbg(&instance->usb_intf->dev, "%s: skb->len=%d, avail_space=%u",
-            __func__, skb->len, avail_space);
-       UDSL_ASSERT(instance, !(avail_space % stride));
-
        for (bytes_written = 0; bytes_written < avail_space && ctrl->len;
             bytes_written += stride, target += stride) {
                unsigned int data_len = min_t(unsigned int, skb->len, ATM_CELL_PAYLOAD);
@@ -553,8 +544,6 @@ static void usbatm_rx_process(unsigned long data)
                                if (!urb->iso_frame_desc[i].status) {
                                        unsigned int actual_length = urb->iso_frame_desc[i].actual_length;
 
-                                       UDSL_ASSERT(instance, actual_length <= packet_size);
-
                                        if (!merge_length)
                                                merge_start = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
                                        merge_length += actual_length;
@@ -645,7 +634,6 @@ static void usbatm_cancel_send(struct usbatm_data *instance,
 {
        struct sk_buff *skb, *n;
 
-       atm_dbg(instance, "%s entered\n", __func__);
        spin_lock_irq(&instance->sndqueue.lock);
        skb_queue_walk_safe(&instance->sndqueue, skb, n) {
                if (UDSL_SKB(skb)->atm.vcc == vcc) {
@@ -663,7 +651,6 @@ static void usbatm_cancel_send(struct usbatm_data *instance,
                usbatm_pop(vcc, skb);
        }
        tasklet_enable(&instance->tx_channel.tasklet);
-       atm_dbg(instance, "%s done\n", __func__);
 }
 
 static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
@@ -674,16 +661,13 @@ static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
 
        /* racy disconnection check - fine */
        if (!instance || instance->disconnected) {
-#ifdef DEBUG
+#ifdef VERBOSE_DEBUG
                printk_ratelimited(KERN_DEBUG "%s: %s!\n", __func__, instance ? "disconnected" : "NULL instance");
 #endif
                err = -ENODEV;
                goto fail;
        }
 
-       vdbg(&instance->usb_intf->dev, "%s called (skb 0x%p, len %u)", __func__,
-            skb, skb->len);
-
        if (vcc->qos.aal != ATM_AAL5) {
                atm_rldbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);
                err = -EINVAL;
@@ -723,8 +707,6 @@ static void usbatm_destroy_instance(struct kref *kref)
 {
        struct usbatm_data *instance = container_of(kref, struct usbatm_data, refcount);
 
-       usb_dbg(instance, "%s\n", __func__);
-
        tasklet_kill(&instance->rx_channel.tasklet);
        tasklet_kill(&instance->tx_channel.tasklet);
        usb_put_dev(instance->usb_dev);
@@ -733,15 +715,11 @@ static void usbatm_destroy_instance(struct kref *kref)
 
 static void usbatm_get_instance(struct usbatm_data *instance)
 {
-       usb_dbg(instance, "%s\n", __func__);
-
        kref_get(&instance->refcount);
 }
 
 static void usbatm_put_instance(struct usbatm_data *instance)
 {
-       usb_dbg(instance, "%s\n", __func__);
-
        kref_put(&instance->refcount, usbatm_destroy_instance);
 }
 
@@ -757,7 +735,6 @@ static void usbatm_atm_dev_close(struct atm_dev *atm_dev)
        if (!instance)
                return;
 
-       usb_dbg(instance, "%s\n", __func__);
        atm_dev->dev_data = NULL; /* catch bugs */
        usbatm_put_instance(instance);  /* taken in usbatm_atm_init */
 }
@@ -813,8 +790,6 @@ static int usbatm_atm_open(struct atm_vcc *vcc)
        if (!instance)
                return -ENODEV;
 
-       atm_dbg(instance, "%s: vpi %hd, vci %d\n", __func__, vpi, vci);
-
        /* only support AAL5 */
        if ((vcc->qos.aal != ATM_AAL5)) {
                atm_warn(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);
@@ -891,11 +866,6 @@ static void usbatm_atm_close(struct atm_vcc *vcc)
        if (!instance || !vcc_data)
                return;
 
-       atm_dbg(instance, "%s entered\n", __func__);
-
-       atm_dbg(instance, "%s: deallocating vcc 0x%p with vpi %d vci %d\n",
-               __func__, vcc_data, vcc_data->vpi, vcc_data->vci);
-
        usbatm_cancel_send(instance, vcc);
 
        mutex_lock(&instance->serialize);       /* vs self, usbatm_atm_open, usbatm_usb_disconnect */
@@ -922,8 +892,6 @@ static void usbatm_atm_close(struct atm_vcc *vcc)
        clear_bit(ATM_VF_ADDR, &vcc->flags);
 
        mutex_unlock(&instance->serialize);
-
-       atm_dbg(instance, "%s successful\n", __func__);
 }
 
 static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd,
@@ -1060,12 +1028,6 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
        int i, length;
        unsigned int maxpacket, num_packets;
 
-       dev_dbg(dev, "%s: trying driver %s with vendor=%04x, product=%04x, ifnum %2d\n",
-                       __func__, driver->driver_name,
-                       le16_to_cpu(usb_dev->descriptor.idVendor),
-                       le16_to_cpu(usb_dev->descriptor.idProduct),
-                       intf->altsetting->desc.bInterfaceNumber);
-
        /* instance init */
        instance = kzalloc(sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), GFP_KERNEL);
        if (!instance) {
@@ -1158,14 +1120,13 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
        instance->rx_channel.buf_size = num_packets * maxpacket;
        instance->rx_channel.packet_size = maxpacket;
 
-#ifdef DEBUG
        for (i = 0; i < 2; i++) {
                struct usbatm_channel *channel = i ?
                        &instance->tx_channel : &instance->rx_channel;
 
-               dev_dbg(dev, "%s: using %d byte buffer for %s channel 0x%p\n", __func__, channel->buf_size, i ? "tx" : "rx", channel);
+               dev_dbg(dev, "%s: using %d byte buffer for %s channel 0x%p\n",
+                       __func__, channel->buf_size, i ? "tx" : "rx", channel);
        }
-#endif
 
        /* initialize urbs */
 
@@ -1176,8 +1137,6 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
                struct urb *urb;
                unsigned int iso_packets = usb_pipeisoc(channel->endpoint) ? channel->buf_size / channel->packet_size : 0;
 
-               UDSL_ASSERT(instance, !usb_pipeisoc(channel->endpoint) || usb_pipein(channel->endpoint));
-
                urb = usb_alloc_urb(iso_packets, GFP_KERNEL);
                if (!urb) {
                        dev_err(dev, "%s: no memory for urb %d!\n", __func__, i);
@@ -1266,8 +1225,6 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
        struct usbatm_vcc_data *vcc_data;
        int i;
 
-       dev_dbg(dev, "%s entered\n", __func__);
-
        if (!instance) {
                dev_dbg(dev, "%s: NULL instance!\n", __func__);
                return;
index 5fc489405217beb254398a3095fcd812faa36941..5651231a74371cc4b97a0b55769e078478158a35 100644 (file)
 #define VERBOSE_DEBUG
 */
 
-#ifdef DEBUG
-#define UDSL_ASSERT(instance, x)       BUG_ON(!(x))
-#else
-#define UDSL_ASSERT(instance, x)                                       \
-       do {    \
-               if (!(x))                                               \
-                       dev_warn(&(instance)->usb_intf->dev,            \
-                                "failed assertion '%s' at line %d",    \
-                                __stringify(x), __LINE__);             \
-       } while (0)
-#endif
-
 #define usb_err(instance, format, arg...)      \
        dev_err(&(instance)->usb_intf->dev , format , ## arg)
 #define usb_info(instance, format, arg...)     \
        dev_info(&(instance)->usb_intf->dev , format , ## arg)
 #define usb_warn(instance, format, arg...)     \
        dev_warn(&(instance)->usb_intf->dev , format , ## arg)
-#ifdef DEBUG
-#define usb_dbg(instance, format, arg...)      \
-       dev_printk(KERN_DEBUG , &(instance)->usb_intf->dev , format , ## arg)
-#else
 #define usb_dbg(instance, format, arg...)      \
-       do {} while (0)
-#endif
+       dev_dbg(&(instance)->usb_intf->dev , format , ## arg)
 
 /* FIXME: move to dev_* once ATM is driver model aware */
 #define atm_printk(level, instance, format, arg...)    \
        atm_printk(KERN_INFO, instance , format , ## arg)
 #define atm_warn(instance, format, arg...)     \
        atm_printk(KERN_WARNING, instance , format , ## arg)
-#ifdef DEBUG
-#define atm_dbg(instance, format, arg...)      \
-       atm_printk(KERN_DEBUG, instance , format , ## arg)
-#define atm_rldbg(instance, format, arg...)    \
+#define atm_dbg(instance, format, arg...)              \
+       dynamic_pr_debug("ATM dev %d: " format ,        \
+       (instance)->atm_dev->number , ## arg)
+#define atm_rldbg(instance, format, arg...)            \
        if (printk_ratelimit())                         \
-               atm_printk(KERN_DEBUG, instance , format , ## arg)
-#else
-#define atm_dbg(instance, format, arg...)      \
-       do {} while (0)
-#define atm_rldbg(instance, format, arg...)    \
-       do {} while (0)
-#endif
+               atm_dbg(instance , format , ## arg)
 
 
 /* flags, set by mini-driver in bind() */
index fe815ecd557eaf5ad3c2df318e731978d25db7f4..8db3380c33295be4200b6b5bfcf0515944ea2f01 100644 (file)
@@ -131,7 +131,7 @@ static int c67x00_drv_probe(struct platform_device *pdev)
        if (!res2)
                return -ENODEV;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        if (!pdata)
                return -ENODEV;
 
@@ -154,7 +154,7 @@ static int c67x00_drv_probe(struct platform_device *pdev)
 
        spin_lock_init(&c67x00->hpi.lock);
        c67x00->hpi.regstep = pdata->hpi_regstep;
-       c67x00->pdata = pdev->dev.platform_data;
+       c67x00->pdata = dev_get_platdata(&pdev->dev);
        c67x00->pdev = pdev;
 
        c67x00_ll_init(c67x00);
index d1bd8ef1f9c1d48b7e0566220149deaf0de10da4..4a851e15e58cdfb6832fbc14c93e3e96cb6f9515 100644 (file)
@@ -1,6 +1,6 @@
 config USB_CHIPIDEA
        tristate "ChipIdea Highspeed Dual Role Controller"
-       depends on USB || USB_GADGET
+       depends on (USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET)
        help
          Say Y here if your system has a dual role high speed USB
          controller based on ChipIdea silicon IP. Currently, only the
@@ -12,15 +12,14 @@ if USB_CHIPIDEA
 
 config USB_CHIPIDEA_UDC
        bool "ChipIdea device controller"
-       depends on USB_GADGET=y || (USB_CHIPIDEA=m && USB_GADGET=m)
+       depends on USB_GADGET
        help
          Say Y here to enable device controller functionality of the
          ChipIdea driver.
 
 config USB_CHIPIDEA_HOST
        bool "ChipIdea host controller"
-       depends on USB=y
-       depends on USB_EHCI_HCD=y || (USB_CHIPIDEA=m && USB_EHCI_HCD=m)
+       depends on USB_EHCI_HCD
        select USB_EHCI_ROOT_HUB_TT
        help
          Say Y here to enable host controller functionality of the
index 6cf5f68dedd8d2c08e00e2ba7d9cf99cc65fafb0..a99d980454a6073cf35a88b429c4d98bfdc030b5 100644 (file)
@@ -2,7 +2,7 @@ ccflags-$(CONFIG_USB_CHIPIDEA_DEBUG) := -DDEBUG
 
 obj-$(CONFIG_USB_CHIPIDEA)             += ci_hdrc.o
 
-ci_hdrc-y                              := core.o
+ci_hdrc-y                              := core.o otg.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC)     += udc.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST)    += host.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG)   += debug.o
index 1b23e354f9fb371f5851206b58944b0221109600..464584c6ccaeaf84d87a888d2e4b8c1382f97e61 100644 (file)
 #define OTGSC_ASVIS          BIT(18)
 #define OTGSC_BSVIS          BIT(19)
 #define OTGSC_BSEIS          BIT(20)
+#define OTGSC_1MSIS          BIT(21)
+#define OTGSC_DPIS           BIT(22)
 #define OTGSC_IDIE           BIT(24)
 #define OTGSC_AVVIE          BIT(25)
 #define OTGSC_ASVIE          BIT(26)
 #define OTGSC_BSVIE          BIT(27)
 #define OTGSC_BSEIE          BIT(28)
+#define OTGSC_1MSIE          BIT(29)
+#define OTGSC_DPIE           BIT(30)
+#define OTGSC_INT_EN_BITS      (OTGSC_IDIE | OTGSC_AVVIE | OTGSC_ASVIE \
+                               | OTGSC_BSVIE | OTGSC_BSEIE | OTGSC_1MSIE \
+                               | OTGSC_DPIE)
+#define OTGSC_INT_STATUS_BITS  (OTGSC_IDIS | OTGSC_AVVIS | OTGSC_ASVIS \
+                               | OTGSC_BSVIS | OTGSC_BSEIS | OTGSC_1MSIS \
+                               | OTGSC_DPIS)
 
 /* USBMODE */
 #define USBMODE_CM            (0x03UL <<  0)
index 33cb29f36e0610ff2164c137d6f46c45d8917108..1c94fc5257f4ef215e5600ba7e39b585e533d29b 100644 (file)
@@ -132,6 +132,9 @@ struct hw_bank {
  * @transceiver: pointer to USB PHY, if any
  * @hcd: pointer to usb_hcd for ehci host driver
  * @debugfs: root dentry for this controller in debugfs
+ * @id_event: indicates there is an id event, and handled at ci_otg_work
+ * @b_sess_valid_event: indicates there is a vbus event, and handled
+ * at ci_otg_work
  */
 struct ci_hdrc {
        struct device                   *dev;
@@ -168,6 +171,8 @@ struct ci_hdrc {
        struct usb_phy                  *transceiver;
        struct usb_hcd                  *hcd;
        struct dentry                   *debugfs;
+       bool                            id_event;
+       bool                            b_sess_valid_event;
 };
 
 static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci)
@@ -303,4 +308,7 @@ int hw_port_test_set(struct ci_hdrc *ci, u8 mode);
 
 u8 hw_port_test_get(struct ci_hdrc *ci);
 
+int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask,
+                               u32 value, unsigned int timeout_ms);
+
 #endif /* __DRIVERS_USB_CHIPIDEA_CI_H */
index 14362c00db3f3e29bfdf24b3ff8bcd029e95b749..74d998d9b45b28001e2f15f6026640ecb6e07085 100644 (file)
 #include <linux/dma-mapping.h>
 #include <linux/usb/chipidea.h>
 #include <linux/clk.h>
-#include <linux/regulator/consumer.h>
 
 #include "ci.h"
 #include "ci_hdrc_imx.h"
 
-#define pdev_to_phy(pdev) \
-       ((struct usb_phy *)platform_get_drvdata(pdev))
-
 struct ci_hdrc_imx_data {
        struct usb_phy *phy;
        struct platform_device *ci_pdev;
        struct clk *clk;
-       struct regulator *reg_vbus;
+       struct imx_usbmisc_data *usbmisc_data;
 };
 
-static const struct usbmisc_ops *usbmisc_ops;
-
 /* Common functions shared by usbmisc drivers */
 
-int usbmisc_set_ops(const struct usbmisc_ops *ops)
-{
-       if (usbmisc_ops)
-               return -EBUSY;
-
-       usbmisc_ops = ops;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(usbmisc_set_ops);
-
-void usbmisc_unset_ops(const struct usbmisc_ops *ops)
-{
-       usbmisc_ops = NULL;
-}
-EXPORT_SYMBOL_GPL(usbmisc_unset_ops);
-
-int usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev)
+static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
 {
        struct device_node *np = dev->of_node;
        struct of_phandle_args args;
+       struct imx_usbmisc_data *data;
        int ret;
 
-       usbdev->dev = dev;
+       /*
+        * In case the fsl,usbmisc property is not present this device doesn't
+        * need usbmisc. Return NULL (which is no error here)
+        */
+       if (!of_get_property(np, "fsl,usbmisc", NULL))
+               return NULL;
+
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return ERR_PTR(-ENOMEM);
 
        ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells",
                                        0, &args);
        if (ret) {
                dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n",
                        ret);
-               memset(usbdev, 0, sizeof(*usbdev));
-               return ret;
+               return ERR_PTR(ret);
        }
-       usbdev->index = args.args[0];
+
+       data->index = args.args[0];
        of_node_put(args.np);
 
        if (of_find_property(np, "disable-over-current", NULL))
-               usbdev->disable_oc = 1;
+               data->disable_oc = 1;
 
        if (of_find_property(np, "external-vbus-divider", NULL))
-               usbdev->evdo = 1;
+               data->evdo = 1;
 
-       return 0;
+       return data;
 }
-EXPORT_SYMBOL_GPL(usbmisc_get_init_data);
 
 /* End of common functions shared by usbmisc drivers*/
 
@@ -93,27 +79,19 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
                .name           = "ci_hdrc_imx",
                .capoffset      = DEF_CAPOFFSET,
                .flags          = CI_HDRC_REQUIRE_TRANSCEIVER |
-                                 CI_HDRC_PULLUP_ON_VBUS |
                                  CI_HDRC_DISABLE_STREAMING,
        };
-       struct resource *res;
        int ret;
 
-       if (of_find_property(pdev->dev.of_node, "fsl,usbmisc", NULL)
-               && !usbmisc_ops)
-               return -EPROBE_DEFER;
-
        data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
        if (!data) {
                dev_err(&pdev->dev, "Failed to allocate ci_hdrc-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->usbmisc_data = usbmisc_get_init_data(&pdev->dev);
+       if (IS_ERR(data->usbmisc_data))
+               return PTR_ERR(data->usbmisc_data);
 
        data->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(data->clk)) {
@@ -141,20 +119,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
                goto err_clk;
        }
 
-       /* we only support host now, so enable vbus here */
-       data->reg_vbus = devm_regulator_get(&pdev->dev, "vbus");
-       if (!IS_ERR(data->reg_vbus)) {
-               ret = regulator_enable(data->reg_vbus);
-               if (ret) {
-                       dev_err(&pdev->dev,
-                               "Failed to enable vbus regulator, err=%d\n",
-                               ret);
-                       goto err_clk;
-               }
-       } else {
-               data->reg_vbus = NULL;
-       }
-
        pdata.phy = data->phy;
 
        if (!pdev->dev.dma_mask)
@@ -162,12 +126,12 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
        if (!pdev->dev.coherent_dma_mask)
                pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (usbmisc_ops && usbmisc_ops->init) {
-               ret = usbmisc_ops->init(&pdev->dev);
+       if (data->usbmisc_data) {
+               ret = imx_usbmisc_init(data->usbmisc_data);
                if (ret) {
-                       dev_err(&pdev->dev,
-                               "usbmisc init failed, ret=%d\n", ret);
-                       goto err;
+                       dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n",
+                                       ret);
+                       goto err_clk;
                }
        }
 
@@ -179,14 +143,14 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
                dev_err(&pdev->dev,
                        "Can't register ci_hdrc platform device, err=%d\n",
                        ret);
-               goto err;
+               goto err_clk;
        }
 
-       if (usbmisc_ops && usbmisc_ops->post) {
-               ret = usbmisc_ops->post(&pdev->dev);
+       if (data->usbmisc_data) {
+               ret = imx_usbmisc_init_post(data->usbmisc_data);
                if (ret) {
-                       dev_err(&pdev->dev,
-                               "usbmisc post failed, ret=%d\n", ret);
+                       dev_err(&pdev->dev, "usbmisc post failed, ret=%d\n",
+                                       ret);
                        goto disable_device;
                }
        }
@@ -200,9 +164,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
 
 disable_device:
        ci_hdrc_remove_device(data->ci_pdev);
-err:
-       if (data->reg_vbus)
-               regulator_disable(data->reg_vbus);
 err_clk:
        clk_disable_unprepare(data->clk);
        return ret;
@@ -215,13 +176,8 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev)
        pm_runtime_disable(&pdev->dev);
        ci_hdrc_remove_device(data->ci_pdev);
 
-       if (data->reg_vbus)
-               regulator_disable(data->reg_vbus);
-
-       if (data->phy) {
+       if (data->phy)
                usb_phy_shutdown(data->phy);
-               module_put(data->phy->dev->driver->owner);
-       }
 
        clk_disable_unprepare(data->clk);
 
index 550bfa4576202c6f6f8f9c3f73ab8921971fd234..c7271590dd0a8af9c8e7f79508d5cf94be79ca75 100644 (file)
@@ -9,23 +9,12 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 
-/* Used to set SoC specific callbacks */
-struct usbmisc_ops {
-       /* It's called once when probe a usb device */
-       int (*init)(struct device *dev);
-       /* It's called once after adding a usb device */
-       int (*post)(struct device *dev);
-};
-
-struct usbmisc_usb_device {
-       struct device *dev; /* usb controller device */
+struct imx_usbmisc_data {
        int index;
 
        unsigned int disable_oc:1; /* over current detect disabled */
        unsigned int evdo:1; /* set external vbus divider option */
 };
 
-int usbmisc_set_ops(const struct usbmisc_ops *ops);
-void usbmisc_unset_ops(const struct usbmisc_ops *ops);
-int
-usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev);
+int imx_usbmisc_init(struct imx_usbmisc_data *);
+int imx_usbmisc_init_post(struct imx_usbmisc_data *);
index fb657ef50a9c1f3c0924d35308b66a05686a9a6d..2d51d852b474ab5af397dd6eaefb3eb48da5db89 100644 (file)
@@ -49,7 +49,6 @@ static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = {
        .name                   = "ci_hdrc_msm",
        .flags                  = CI_HDRC_REGS_SHARED |
                                  CI_HDRC_REQUIRE_TRANSCEIVER |
-                                 CI_HDRC_PULLUP_ON_VBUS |
                                  CI_HDRC_DISABLE_STREAMING,
 
        .notify_event           = ci_hdrc_msm_notify_event,
index a5df24c578fc8b65b8945781a0cacb6e6bb33977..94626409559a96a79c0d027023dbade8a645ce58 100644 (file)
 #include <linux/usb/chipidea.h>
 #include <linux/usb/of.h>
 #include <linux/phy.h>
+#include <linux/regulator/consumer.h>
 
 #include "ci.h"
 #include "udc.h"
 #include "bits.h"
 #include "host.h"
 #include "debug.h"
+#include "otg.h"
 
 /* Controller register map */
 static uintptr_t ci_regs_nolpm[] = {
@@ -197,6 +199,12 @@ static int hw_device_init(struct ci_hdrc *ci, void __iomem *base)
        if (ci->hw_ep_max > ENDPT_MAX)
                return -ENODEV;
 
+       /* Disable all interrupts bits */
+       hw_write(ci, OP_USBINTR, 0xffffffff, 0);
+
+       /* Clear all interrupts status bits*/
+       hw_write(ci, OP_USBSTS, 0xffffffff, 0xffffffff);
+
        dev_dbg(ci->dev, "ChipIdea HDRC found, lpm: %d; cap: %p op: %p\n",
                ci->hw_bank.lpm, ci->hw_bank.cap, ci->hw_bank.op);
 
@@ -264,8 +272,6 @@ int hw_device_reset(struct ci_hdrc *ci, u32 mode)
        while (hw_read(ci, OP_USBCMD, USBCMD_RST))
                udelay(10);             /* not RTOS friendly */
 
-       hw_phymode_configure(ci);
-
        if (ci->platdata->notify_event)
                ci->platdata->notify_event(ci,
                        CI_HDRC_CONTROLLER_RESET_EVENT);
@@ -289,37 +295,35 @@ int hw_device_reset(struct ci_hdrc *ci, u32 mode)
 }
 
 /**
- * ci_otg_role - pick role based on ID pin state
+ * hw_wait_reg: wait the register value
+ *
+ * Sometimes, it needs to wait register value before going on.
+ * Eg, when switch to device mode, the vbus value should be lower
+ * than OTGSC_BSV before connects to host.
+ *
  * @ci: the controller
+ * @reg: register index
+ * @mask: mast bit
+ * @value: the bit value to wait
+ * @timeout_ms: timeout in millisecond
+ *
+ * This function returns an error code if timeout
  */
-static enum ci_role ci_otg_role(struct ci_hdrc *ci)
-{
-       u32 sts = hw_read(ci, OP_OTGSC, ~0);
-       enum ci_role role = sts & OTGSC_ID
-               ? CI_ROLE_GADGET
-               : CI_ROLE_HOST;
-
-       return role;
-}
-
-/**
- * ci_role_work - perform role changing based on ID pin
- * @work: work struct
- */
-static void ci_role_work(struct work_struct *work)
+int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask,
+                               u32 value, unsigned int timeout_ms)
 {
-       struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work);
-       enum ci_role role = ci_otg_role(ci);
-
-       if (role != ci->role) {
-               dev_dbg(ci->dev, "switching from %s to %s\n",
-                       ci_role(ci)->name, ci->roles[role]->name);
-
-               ci_role_stop(ci);
-               ci_role_start(ci, role);
+       unsigned long elapse = jiffies + msecs_to_jiffies(timeout_ms);
+
+       while (hw_read(ci, reg, mask) != value) {
+               if (time_after(jiffies, elapse)) {
+                       dev_err(ci->dev, "timeout waiting for %08x in %d\n",
+                                       mask, reg);
+                       return -ETIMEDOUT;
+               }
+               msleep(20);
        }
 
-       enable_irq(ci->irq);
+       return 0;
 }
 
 static irqreturn_t ci_irq(int irq, void *data)
@@ -331,19 +335,55 @@ static irqreturn_t ci_irq(int irq, void *data)
        if (ci->is_otg)
                otgsc = hw_read(ci, OP_OTGSC, ~0);
 
-       if (ci->role != CI_ROLE_END)
-               ret = ci_role(ci)->irq(ci);
+       /*
+        * Handle id change interrupt, it indicates device/host function
+        * switch.
+        */
+       if (ci->is_otg && (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) {
+               ci->id_event = true;
+               ci_clear_otg_interrupt(ci, OTGSC_IDIS);
+               disable_irq_nosync(ci->irq);
+               queue_work(ci->wq, &ci->work);
+               return IRQ_HANDLED;
+       }
 
-       if (ci->is_otg && (otgsc & OTGSC_IDIS)) {
-               hw_write(ci, OP_OTGSC, OTGSC_IDIS, OTGSC_IDIS);
+       /*
+        * Handle vbus change interrupt, it indicates device connection
+        * and disconnection events.
+        */
+       if (ci->is_otg && (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
+               ci->b_sess_valid_event = true;
+               ci_clear_otg_interrupt(ci, OTGSC_BSVIS);
                disable_irq_nosync(ci->irq);
                queue_work(ci->wq, &ci->work);
-               ret = IRQ_HANDLED;
+               return IRQ_HANDLED;
        }
 
+       /* Handle device/host interrupt */
+       if (ci->role != CI_ROLE_END)
+               ret = ci_role(ci)->irq(ci);
+
        return ret;
 }
 
+static int ci_get_platdata(struct device *dev,
+               struct ci_hdrc_platform_data *platdata)
+{
+       /* Get the vbus regulator */
+       platdata->reg_vbus = devm_regulator_get(dev, "vbus");
+       if (PTR_ERR(platdata->reg_vbus) == -EPROBE_DEFER) {
+               return -EPROBE_DEFER;
+       } else if (PTR_ERR(platdata->reg_vbus) == -ENODEV) {
+               platdata->reg_vbus = NULL; /* no vbus regualator is needed */
+       } else if (IS_ERR(platdata->reg_vbus)) {
+               dev_err(dev, "Getting regulator error: %ld\n",
+                       PTR_ERR(platdata->reg_vbus));
+               return PTR_ERR(platdata->reg_vbus);
+       }
+
+       return 0;
+}
+
 static DEFINE_IDA(ci_ida);
 
 struct platform_device *ci_hdrc_add_device(struct device *dev,
@@ -353,6 +393,10 @@ struct platform_device *ci_hdrc_add_device(struct device *dev,
        struct platform_device *pdev;
        int id, ret;
 
+       ret = ci_get_platdata(dev, platdata);
+       if (ret)
+               return ERR_PTR(ret);
+
        id = ida_simple_get(&ci_ida, 0, 0, GFP_KERNEL);
        if (id < 0)
                return ERR_PTR(id);
@@ -398,6 +442,29 @@ void ci_hdrc_remove_device(struct platform_device *pdev)
 }
 EXPORT_SYMBOL_GPL(ci_hdrc_remove_device);
 
+static inline void ci_role_destroy(struct ci_hdrc *ci)
+{
+       ci_hdrc_gadget_destroy(ci);
+       ci_hdrc_host_destroy(ci);
+       if (ci->is_otg)
+               ci_hdrc_otg_destroy(ci);
+}
+
+static void ci_get_otg_capable(struct ci_hdrc *ci)
+{
+       if (ci->platdata->flags & CI_HDRC_DUAL_ROLE_NOT_OTG)
+               ci->is_otg = false;
+       else
+               ci->is_otg = (hw_read(ci, CAP_DCCPARAMS,
+                               DCCPARAMS_DC | DCCPARAMS_HC)
+                                       == (DCCPARAMS_DC | DCCPARAMS_HC));
+       if (ci->is_otg) {
+               dev_dbg(ci->dev, "It is OTG capable controller\n");
+               ci_disable_otg_interrupt(ci, OTGSC_INT_EN_BITS);
+               ci_clear_otg_interrupt(ci, OTGSC_INT_STATUS_BITS);
+       }
+}
+
 static int ci_hdrc_probe(struct platform_device *pdev)
 {
        struct device   *dev = &pdev->dev;
@@ -406,15 +473,13 @@ static int ci_hdrc_probe(struct platform_device *pdev)
        void __iomem    *base;
        int             ret;
        enum usb_dr_mode dr_mode;
+       struct device_node *of_node = dev->of_node ?: dev->parent->of_node;
 
        if (!dev->platform_data) {
                dev_err(dev, "platform data missing\n");
                return -ENODEV;
        }
 
-       if (!dev->of_node && dev->parent)
-               dev->of_node = dev->parent->of_node;
-
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        base = devm_ioremap_resource(dev, res);
        if (IS_ERR(base))
@@ -447,18 +512,15 @@ static int ci_hdrc_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       INIT_WORK(&ci->work, ci_role_work);
-       ci->wq = create_singlethread_workqueue("ci_otg");
-       if (!ci->wq) {
-               dev_err(dev, "can't create workqueue\n");
-               return -ENODEV;
-       }
+       ci_get_otg_capable(ci);
 
        if (!ci->platdata->phy_mode)
-               ci->platdata->phy_mode = of_usb_get_phy_mode(dev->of_node);
+               ci->platdata->phy_mode = of_usb_get_phy_mode(of_node);
+
+       hw_phymode_configure(ci);
 
        if (!ci->platdata->dr_mode)
-               ci->platdata->dr_mode = of_usb_get_dr_mode(dev->of_node);
+               ci->platdata->dr_mode = of_usb_get_dr_mode(of_node);
 
        if (ci->platdata->dr_mode == USB_DR_MODE_UNKNOWN)
                ci->platdata->dr_mode = USB_DR_MODE_OTG;
@@ -479,15 +541,34 @@ static int ci_hdrc_probe(struct platform_device *pdev)
 
        if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) {
                dev_err(dev, "no supported roles\n");
-               ret = -ENODEV;
-               goto rm_wq;
+               return -ENODEV;
+       }
+
+       if (ci->is_otg) {
+               ret = ci_hdrc_otg_init(ci);
+               if (ret) {
+                       dev_err(dev, "init otg fails, ret = %d\n", ret);
+                       goto stop;
+               }
        }
 
        if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) {
-               ci->is_otg = true;
-               /* ID pin needs 1ms debouce time, we delay 2ms for safe */
-               mdelay(2);
-               ci->role = ci_otg_role(ci);
+               if (ci->is_otg) {
+                       /*
+                        * ID pin needs 1ms debouce time,
+                        * we delay 2ms for safe.
+                        */
+                       mdelay(2);
+                       ci->role = ci_otg_role(ci);
+                       ci_enable_otg_interrupt(ci, OTGSC_IDIE);
+               } else {
+                       /*
+                        * If the controller is not OTG capable, but support
+                        * role switch, the defalt role is gadget, and the
+                        * user can switch it through debugfs.
+                        */
+                       ci->role = CI_ROLE_GADGET;
+               }
        } else {
                ci->role = ci->roles[CI_ROLE_HOST]
                        ? CI_ROLE_HOST
@@ -497,8 +578,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
        ret = ci_role_start(ci, ci->role);
        if (ret) {
                dev_err(dev, "can't start %s role\n", ci_role(ci)->name);
-               ret = -ENODEV;
-               goto rm_wq;
+               goto stop;
        }
 
        platform_set_drvdata(pdev, ci);
@@ -507,19 +587,13 @@ static int ci_hdrc_probe(struct platform_device *pdev)
        if (ret)
                goto stop;
 
-       if (ci->is_otg)
-               hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE);
-
        ret = dbg_create_files(ci);
        if (!ret)
                return 0;
 
        free_irq(ci->irq, ci);
 stop:
-       ci_role_stop(ci);
-rm_wq:
-       flush_workqueue(ci->wq);
-       destroy_workqueue(ci->wq);
+       ci_role_destroy(ci);
 
        return ret;
 }
@@ -529,10 +603,8 @@ static int ci_hdrc_remove(struct platform_device *pdev)
        struct ci_hdrc *ci = platform_get_drvdata(pdev);
 
        dbg_remove_files(ci);
-       flush_workqueue(ci->wq);
-       destroy_workqueue(ci->wq);
        free_irq(ci->irq, ci);
-       ci_role_stop(ci);
+       ci_role_destroy(ci);
 
        return 0;
 }
@@ -548,7 +620,6 @@ static struct platform_driver ci_hdrc_driver = {
 module_platform_driver(ci_hdrc_driver);
 
 MODULE_ALIAS("platform:ci_hdrc");
-MODULE_ALIAS("platform:ci13xxx");
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("David Lopo <dlopo@chipidea.mips.com>");
 MODULE_DESCRIPTION("ChipIdea HDRC Driver");
index 40d0fda4f66c8f696b0d935fa464ce3632c09020..6f96795dd20cc3ff3d0c08490ae8d87b0b2ccccf 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
 #include <linux/usb/chipidea.h>
+#include <linux/regulator/consumer.h>
 
 #include "../host/ehci.h"
 
@@ -63,10 +64,21 @@ static int host_start(struct ci_hdrc *ci)
        ehci = hcd_to_ehci(hcd);
        ehci->caps = ci->hw_bank.cap;
        ehci->has_hostpc = ci->hw_bank.lpm;
+       ehci->has_tdi_phy_lpm = ci->hw_bank.lpm;
+
+       if (ci->platdata->reg_vbus) {
+               ret = regulator_enable(ci->platdata->reg_vbus);
+               if (ret) {
+                       dev_err(ci->dev,
+                               "Failed to enable vbus regulator, ret=%d\n",
+                               ret);
+                       goto put_hcd;
+               }
+       }
 
        ret = usb_add_hcd(hcd, 0, 0);
        if (ret)
-               usb_put_hcd(hcd);
+               goto disable_reg;
        else
                ci->hcd = hcd;
 
@@ -74,6 +86,14 @@ static int host_start(struct ci_hdrc *ci)
                hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
 
        return ret;
+
+disable_reg:
+       regulator_disable(ci->platdata->reg_vbus);
+
+put_hcd:
+       usb_put_hcd(hcd);
+
+       return ret;
 }
 
 static void host_stop(struct ci_hdrc *ci)
@@ -82,6 +102,15 @@ static void host_stop(struct ci_hdrc *ci)
 
        usb_remove_hcd(hcd);
        usb_put_hcd(hcd);
+       if (ci->platdata->reg_vbus)
+               regulator_disable(ci->platdata->reg_vbus);
+}
+
+
+void ci_hdrc_host_destroy(struct ci_hdrc *ci)
+{
+       if (ci->role == CI_ROLE_HOST)
+               host_stop(ci);
 }
 
 int ci_hdrc_host_init(struct ci_hdrc *ci)
index 058875c153334db7b0807a3cb2e0926b60c065e8..5707bf379bfb4b7ce98ff4a79d585619d1c64b48 100644 (file)
@@ -4,6 +4,7 @@
 #ifdef CONFIG_USB_CHIPIDEA_HOST
 
 int ci_hdrc_host_init(struct ci_hdrc *ci);
+void ci_hdrc_host_destroy(struct ci_hdrc *ci);
 
 #else
 
@@ -12,6 +13,11 @@ static inline int ci_hdrc_host_init(struct ci_hdrc *ci)
        return -ENXIO;
 }
 
+static inline void ci_hdrc_host_destroy(struct ci_hdrc *ci)
+{
+
+}
+
 #endif
 
 #endif /* __DRIVERS_USB_CHIPIDEA_HOST_H */
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
new file mode 100644 (file)
index 0000000..39bd7ec
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * otg.c - ChipIdea USB IP core OTG driver
+ *
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * Author: Peter Chen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * This file mainly handles otgsc register, it may include OTG operation
+ * in the future.
+ */
+
+#include <linux/usb/otg.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/chipidea.h>
+
+#include "ci.h"
+#include "bits.h"
+#include "otg.h"
+
+/**
+ * ci_otg_role - pick role based on ID pin state
+ * @ci: the controller
+ */
+enum ci_role ci_otg_role(struct ci_hdrc *ci)
+{
+       u32 sts = hw_read(ci, OP_OTGSC, ~0);
+       enum ci_role role = sts & OTGSC_ID
+               ? CI_ROLE_GADGET
+               : CI_ROLE_HOST;
+
+       return role;
+}
+
+void ci_handle_vbus_change(struct ci_hdrc *ci)
+{
+       u32 otgsc;
+
+       if (!ci->is_otg)
+               return;
+
+       otgsc = hw_read(ci, OP_OTGSC, ~0);
+
+       if (otgsc & OTGSC_BSV)
+               usb_gadget_vbus_connect(&ci->gadget);
+       else
+               usb_gadget_vbus_disconnect(&ci->gadget);
+}
+
+#define CI_VBUS_STABLE_TIMEOUT_MS 5000
+static void ci_handle_id_switch(struct ci_hdrc *ci)
+{
+       enum ci_role role = ci_otg_role(ci);
+
+       if (role != ci->role) {
+               dev_dbg(ci->dev, "switching from %s to %s\n",
+                       ci_role(ci)->name, ci->roles[role]->name);
+
+               ci_role_stop(ci);
+               /* wait vbus lower than OTGSC_BSV */
+               hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0,
+                               CI_VBUS_STABLE_TIMEOUT_MS);
+               ci_role_start(ci, role);
+       }
+}
+/**
+ * ci_otg_work - perform otg (vbus/id) event handle
+ * @work: work struct
+ */
+static void ci_otg_work(struct work_struct *work)
+{
+       struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work);
+
+       if (ci->id_event) {
+               ci->id_event = false;
+               ci_handle_id_switch(ci);
+       } else if (ci->b_sess_valid_event) {
+               ci->b_sess_valid_event = false;
+               ci_handle_vbus_change(ci);
+       } else
+               dev_err(ci->dev, "unexpected event occurs at %s\n", __func__);
+
+       enable_irq(ci->irq);
+}
+
+
+/**
+ * ci_hdrc_otg_init - initialize otg struct
+ * ci: the controller
+ */
+int ci_hdrc_otg_init(struct ci_hdrc *ci)
+{
+       INIT_WORK(&ci->work, ci_otg_work);
+       ci->wq = create_singlethread_workqueue("ci_otg");
+       if (!ci->wq) {
+               dev_err(ci->dev, "can't create workqueue\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+/**
+ * ci_hdrc_otg_destroy - destroy otg struct
+ * ci: the controller
+ */
+void ci_hdrc_otg_destroy(struct ci_hdrc *ci)
+{
+       if (ci->wq) {
+               flush_workqueue(ci->wq);
+               destroy_workqueue(ci->wq);
+       }
+       ci_disable_otg_interrupt(ci, OTGSC_INT_EN_BITS);
+       ci_clear_otg_interrupt(ci, OTGSC_INT_STATUS_BITS);
+}
diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h
new file mode 100644 (file)
index 0000000..2d9f090
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * Author: Peter Chen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __DRIVERS_USB_CHIPIDEA_OTG_H
+#define __DRIVERS_USB_CHIPIDEA_OTG_H
+
+static inline void ci_clear_otg_interrupt(struct ci_hdrc *ci, u32 bits)
+{
+       /* Only clear request bits */
+       hw_write(ci, OP_OTGSC, OTGSC_INT_STATUS_BITS, bits);
+}
+
+static inline void ci_enable_otg_interrupt(struct ci_hdrc *ci, u32 bits)
+{
+       hw_write(ci, OP_OTGSC, bits, bits);
+}
+
+static inline void ci_disable_otg_interrupt(struct ci_hdrc *ci, u32 bits)
+{
+       hw_write(ci, OP_OTGSC, bits, 0);
+}
+
+int ci_hdrc_otg_init(struct ci_hdrc *ci);
+void ci_hdrc_otg_destroy(struct ci_hdrc *ci);
+enum ci_role ci_otg_role(struct ci_hdrc *ci);
+void ci_handle_vbus_change(struct ci_hdrc *ci);
+
+#endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */
index e475fcda1d6829213e2b6c22c5d2c0c7302c8671..6b4c2f2eb94649c7da6fc577b54598d53ebdfec4 100644 (file)
@@ -27,6 +27,7 @@
 #include "udc.h"
 #include "bits.h"
 #include "debug.h"
+#include "otg.h"
 
 /* control endpoint description */
 static const struct usb_endpoint_descriptor
@@ -84,8 +85,10 @@ static int hw_device_state(struct ci_hdrc *ci, u32 dma)
                /* interrupt, error, port change, reset, sleep/suspend */
                hw_write(ci, OP_USBINTR, ~0,
                             USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
+               hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
        } else {
                hw_write(ci, OP_USBINTR, ~0, 0);
+               hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
        }
        return 0;
 }
@@ -1445,9 +1448,6 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
        unsigned long flags;
        int gadget_ready = 0;
 
-       if (!(ci->platdata->flags & CI_HDRC_PULLUP_ON_VBUS))
-               return -EOPNOTSUPP;
-
        spin_lock_irqsave(&ci->lock, flags);
        ci->vbus_active = is_active;
        if (ci->driver)
@@ -1459,6 +1459,7 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
                        pm_runtime_get_sync(&_gadget->dev);
                        hw_device_reset(ci, USBMODE_CM_DC);
                        hw_device_state(ci, ci->ep0out->qh.dma);
+                       dev_dbg(ci->dev, "Connected to host\n");
                } else {
                        hw_device_state(ci, 0);
                        if (ci->platdata->notify_event)
@@ -1466,6 +1467,7 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
                                CI_HDRC_CONTROLLER_STOPPED_EVENT);
                        _gadget_stop_activity(&ci->gadget);
                        pm_runtime_put_sync(&_gadget->dev);
+                       dev_dbg(ci->dev, "Disconnected from host\n");
                }
        }
 
@@ -1509,6 +1511,9 @@ static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on)
 {
        struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
 
+       if (!ci->vbus_active)
+               return -EOPNOTSUPP;
+
        if (is_on)
                hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
        else
@@ -1630,14 +1635,11 @@ static int ci_udc_start(struct usb_gadget *gadget,
 
        ci->driver = driver;
        pm_runtime_get_sync(&ci->gadget.dev);
-       if (ci->platdata->flags & CI_HDRC_PULLUP_ON_VBUS) {
-               if (ci->vbus_active) {
-                       if (ci->platdata->flags & CI_HDRC_REGS_SHARED)
-                               hw_device_reset(ci, USBMODE_CM_DC);
-               } else {
-                       pm_runtime_put_sync(&ci->gadget.dev);
-                       goto done;
-               }
+       if (ci->vbus_active) {
+               hw_device_reset(ci, USBMODE_CM_DC);
+       } else {
+               pm_runtime_put_sync(&ci->gadget.dev);
+               goto done;
        }
 
        retval = hw_device_state(ci, ci->ep0out->qh.dma);
@@ -1660,8 +1662,7 @@ static int ci_udc_stop(struct usb_gadget *gadget,
 
        spin_lock_irqsave(&ci->lock, flags);
 
-       if (!(ci->platdata->flags & CI_HDRC_PULLUP_ON_VBUS) ||
-                       ci->vbus_active) {
+       if (ci->vbus_active) {
                hw_device_state(ci, 0);
                if (ci->platdata->notify_event)
                        ci->platdata->notify_event(ci,
@@ -1796,16 +1797,15 @@ static int udc_start(struct ci_hdrc *ci)
                }
        }
 
-       if (!(ci->platdata->flags & CI_HDRC_REGS_SHARED)) {
-               retval = hw_device_reset(ci, USBMODE_CM_DC);
-               if (retval)
-                       goto put_transceiver;
-       }
-
        if (ci->transceiver) {
                retval = otg_set_peripheral(ci->transceiver->otg,
                                                &ci->gadget);
-               if (retval)
+               /*
+                * If we implement all USB functions using chipidea drivers,
+                * it doesn't need to call above API, meanwhile, if we only
+                * use gadget function, calling above API is useless.
+                */
+               if (retval && retval != -ENOTSUPP)
                        goto put_transceiver;
        }
 
@@ -1816,6 +1816,9 @@ static int udc_start(struct ci_hdrc *ci)
        pm_runtime_no_callbacks(&ci->gadget.dev);
        pm_runtime_enable(&ci->gadget.dev);
 
+       /* Update ci->vbus_active */
+       ci_handle_vbus_change(ci);
+
        return retval;
 
 remove_trans:
@@ -1839,13 +1842,13 @@ free_qh_pool:
 }
 
 /**
- * udc_remove: parent remove must call this to remove UDC
+ * ci_hdrc_gadget_destroy: parent remove must call this to remove UDC
  *
  * No interrupts active, the IRQ has been released
  */
-static void udc_stop(struct ci_hdrc *ci)
+void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
 {
-       if (ci == NULL)
+       if (!ci->roles[CI_ROLE_GADGET])
                return;
 
        usb_del_gadget_udc(&ci->gadget);
@@ -1860,15 +1863,32 @@ static void udc_stop(struct ci_hdrc *ci)
                if (ci->global_phy)
                        usb_put_phy(ci->transceiver);
        }
-       /* my kobject is dynamic, I swear! */
-       memset(&ci->gadget, 0, sizeof(ci->gadget));
+}
+
+static int udc_id_switch_for_device(struct ci_hdrc *ci)
+{
+       if (ci->is_otg) {
+               ci_clear_otg_interrupt(ci, OTGSC_BSVIS);
+               ci_enable_otg_interrupt(ci, OTGSC_BSVIE);
+       }
+
+       return 0;
+}
+
+static void udc_id_switch_for_host(struct ci_hdrc *ci)
+{
+       if (ci->is_otg) {
+               /* host doesn't care B_SESSION_VALID event */
+               ci_clear_otg_interrupt(ci, OTGSC_BSVIS);
+               ci_disable_otg_interrupt(ci, OTGSC_BSVIE);
+       }
 }
 
 /**
  * ci_hdrc_gadget_init - initialize device related bits
  * ci: the controller
  *
- * This function enables the gadget role, if the device is "device capable".
+ * This function initializes the gadget, if the device is "device capable".
  */
 int ci_hdrc_gadget_init(struct ci_hdrc *ci)
 {
@@ -1881,11 +1901,11 @@ int ci_hdrc_gadget_init(struct ci_hdrc *ci)
        if (!rdrv)
                return -ENOMEM;
 
-       rdrv->start     = udc_start;
-       rdrv->stop      = udc_stop;
+       rdrv->start     = udc_id_switch_for_device;
+       rdrv->stop      = udc_id_switch_for_host;
        rdrv->irq       = udc_irq;
        rdrv->name      = "gadget";
        ci->roles[CI_ROLE_GADGET] = rdrv;
 
-       return 0;
+       return udc_start(ci);
 }
index 455ac2169226141b703878ecae3ecef5a6a1ace4..e66df0020bd456aadf1a0a036ab8084a098d119d 100644 (file)
@@ -84,6 +84,7 @@ struct ci_hw_req {
 #ifdef CONFIG_USB_CHIPIDEA_UDC
 
 int ci_hdrc_gadget_init(struct ci_hdrc *ci);
+void ci_hdrc_gadget_destroy(struct ci_hdrc *ci);
 
 #else
 
@@ -92,6 +93,11 @@ static inline int ci_hdrc_gadget_init(struct ci_hdrc *ci)
        return -ENXIO;
 }
 
+static inline void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
+{
+
+}
+
 #endif
 
 #endif /* __DRIVERS_USB_CHIPIDEA_UDC_H */
index ac5a4615520011089be9958c76bf702c1a1b38c3..8a1094b1182f9bc625dd18f26b5e97d852e83b1f 100644 (file)
@@ -18,8 +18,6 @@
 
 #include "ci_hdrc_imx.h"
 
-#define USB_DEV_MAX 4
-
 #define MX25_USB_PHY_CTRL_OFFSET       0x08
 #define MX25_BM_EXTERNAL_VBUS_DIVIDER  BIT(23)
 
 
 #define MX6_BM_OVER_CUR_DIS            BIT(7)
 
+struct usbmisc_ops {
+       /* It's called once when probe a usb device */
+       int (*init)(struct imx_usbmisc_data *data);
+       /* It's called once after adding a usb device */
+       int (*post)(struct imx_usbmisc_data *data);
+};
+
 struct imx_usbmisc {
        void __iomem *base;
        spinlock_t lock;
        struct clk *clk;
-       struct usbmisc_usb_device usbdev[USB_DEV_MAX];
        const struct usbmisc_ops *ops;
 };
 
 static struct imx_usbmisc *usbmisc;
 
-static struct usbmisc_usb_device *get_usbdev(struct device *dev)
-{
-       int i, ret;
-
-       for (i = 0; i < USB_DEV_MAX; i++) {
-               if (usbmisc->usbdev[i].dev == dev)
-                       return &usbmisc->usbdev[i];
-               else if (!usbmisc->usbdev[i].dev)
-                       break;
-       }
-
-       if (i >= USB_DEV_MAX)
-               return ERR_PTR(-EBUSY);
-
-       ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]);
-       if (ret)
-               return ERR_PTR(ret);
-
-       return &usbmisc->usbdev[i];
-}
-
-static int usbmisc_imx25_post(struct device *dev)
+static int usbmisc_imx25_post(struct imx_usbmisc_data *data)
 {
-       struct usbmisc_usb_device *usbdev;
        void __iomem *reg;
        unsigned long flags;
        u32 val;
 
-       usbdev = get_usbdev(dev);
-       if (IS_ERR(usbdev))
-               return PTR_ERR(usbdev);
+       if (data->index > 2)
+               return -EINVAL;
 
        reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
 
-       if (usbdev->evdo) {
+       if (data->evdo) {
                spin_lock_irqsave(&usbmisc->lock, flags);
                val = readl(reg);
                writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg);
@@ -87,20 +68,18 @@ static int usbmisc_imx25_post(struct device *dev)
        return 0;
 }
 
-static int usbmisc_imx53_init(struct device *dev)
+static int usbmisc_imx53_init(struct imx_usbmisc_data *data)
 {
-       struct usbmisc_usb_device *usbdev;
        void __iomem *reg = NULL;
        unsigned long flags;
        u32 val = 0;
 
-       usbdev = get_usbdev(dev);
-       if (IS_ERR(usbdev))
-               return PTR_ERR(usbdev);
+       if (data->index > 3)
+               return -EINVAL;
 
-       if (usbdev->disable_oc) {
+       if (data->disable_oc) {
                spin_lock_irqsave(&usbmisc->lock, flags);
-               switch (usbdev->index) {
+               switch (data->index) {
                case 0:
                        reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
                        val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG;
@@ -126,22 +105,19 @@ static int usbmisc_imx53_init(struct device *dev)
        return 0;
 }
 
-static int usbmisc_imx6q_init(struct device *dev)
+static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)
 {
-
-       struct usbmisc_usb_device *usbdev;
        unsigned long flags;
        u32 reg;
 
-       usbdev = get_usbdev(dev);
-       if (IS_ERR(usbdev))
-               return PTR_ERR(usbdev);
+       if (data->index > 3)
+               return -EINVAL;
 
-       if (usbdev->disable_oc) {
+       if (data->disable_oc) {
                spin_lock_irqsave(&usbmisc->lock, flags);
-               reg = readl(usbmisc->base + usbdev->index * 4);
+               reg = readl(usbmisc->base + data->index * 4);
                writel(reg | MX6_BM_OVER_CUR_DIS,
-                       usbmisc->base + usbdev->index * 4);
+                       usbmisc->base + data->index * 4);
                spin_unlock_irqrestore(&usbmisc->lock, flags);
        }
 
@@ -160,6 +136,26 @@ static const struct usbmisc_ops imx6q_usbmisc_ops = {
        .init = usbmisc_imx6q_init,
 };
 
+int imx_usbmisc_init(struct imx_usbmisc_data *data)
+{
+       if (!usbmisc)
+               return -EPROBE_DEFER;
+       if (!usbmisc->ops->init)
+               return 0;
+       return usbmisc->ops->init(data);
+}
+EXPORT_SYMBOL_GPL(imx_usbmisc_init);
+
+int imx_usbmisc_init_post(struct imx_usbmisc_data *data)
+{
+       if (!usbmisc)
+               return -EPROBE_DEFER;
+       if (!usbmisc->ops->post)
+               return 0;
+       return usbmisc->ops->post(data);
+}
+EXPORT_SYMBOL_GPL(imx_usbmisc_init_post);
+
 static const struct of_device_id usbmisc_imx_dt_ids[] = {
        {
                .compatible = "fsl,imx25-usbmisc",
@@ -216,19 +212,12 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
                of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
        data->ops = (const struct usbmisc_ops *)tmp_dev->data;
        usbmisc = data;
-       ret = usbmisc_set_ops(data->ops);
-       if (ret) {
-               usbmisc = NULL;
-               clk_disable_unprepare(data->clk);
-               return ret;
-       }
 
        return 0;
 }
 
 static int usbmisc_imx_remove(struct platform_device *pdev)
 {
-       usbmisc_unset_ops(usbmisc->ops);
        clk_disable_unprepare(usbmisc->clk);
        usbmisc = NULL;
        return 0;
index 9f49bfe4c6f4a24e112a71ecabee13b6e59aec0a..3e7560f004f86d7153ed3ea0eeabed09dabf6b47 100644 (file)
@@ -1295,7 +1295,7 @@ skip_countries:
                         usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
                         acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm,
                         /* works around buggy devices */
-                        epctrl->bInterval ? epctrl->bInterval : 0xff);
+                        epctrl->bInterval ? epctrl->bInterval : 16);
        acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
        acm->ctrlurb->transfer_dma = acm->ctrl_dma;
 
index 8a230f0ef77c77b9acef90b86ab902e9cd4999eb..d3318a0df8ee503f4f5ee553cda3ff1391298be4 100644 (file)
@@ -209,6 +209,7 @@ skip_error:
 static void wdm_int_callback(struct urb *urb)
 {
        int rv = 0;
+       int responding;
        int status = urb->status;
        struct wdm_device *desc;
        struct usb_cdc_notification *dr;
@@ -262,8 +263,8 @@ static void wdm_int_callback(struct urb *urb)
 
        spin_lock(&desc->iuspin);
        clear_bit(WDM_READ, &desc->flags);
-       set_bit(WDM_RESPONDING, &desc->flags);
-       if (!test_bit(WDM_DISCONNECTING, &desc->flags)
+       responding = test_and_set_bit(WDM_RESPONDING, &desc->flags);
+       if (!responding && !test_bit(WDM_DISCONNECTING, &desc->flags)
                && !test_bit(WDM_SUSPENDING, &desc->flags)) {
                rv = usb_submit_urb(desc->response, GFP_ATOMIC);
                dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d",
@@ -685,16 +686,20 @@ static void wdm_rxwork(struct work_struct *work)
 {
        struct wdm_device *desc = container_of(work, struct wdm_device, rxwork);
        unsigned long flags;
-       int rv;
+       int rv = 0;
+       int responding;
 
        spin_lock_irqsave(&desc->iuspin, flags);
        if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
                spin_unlock_irqrestore(&desc->iuspin, flags);
        } else {
+               responding = test_and_set_bit(WDM_RESPONDING, &desc->flags);
                spin_unlock_irqrestore(&desc->iuspin, flags);
-               rv = usb_submit_urb(desc->response, GFP_KERNEL);
+               if (!responding)
+                       rv = usb_submit_urb(desc->response, GFP_KERNEL);
                if (rv < 0 && rv != -EPERM) {
                        spin_lock_irqsave(&desc->iuspin, flags);
+                       clear_bit(WDM_RESPONDING, &desc->flags);
                        if (!test_bit(WDM_DISCONNECTING, &desc->flags))
                                schedule_work(&desc->rxwork);
                        spin_unlock_irqrestore(&desc->iuspin, flags);
index 83b4ef4dfcf80c71248555c5378c082182235bcf..66c4001306f00fba7f1fe3e018923054b54c93b7 100644 (file)
@@ -19,6 +19,8 @@
  * http://www.gnu.org/copyleft/gpl.html.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -119,7 +121,6 @@ static void usbtmc_delete(struct kref *kref)
        struct usbtmc_device_data *data = to_usbtmc_data(kref);
 
        usb_put_dev(data->usb_dev);
-       kfree(data);
 }
 
 static int usbtmc_open(struct inode *inode, struct file *filp)
@@ -130,10 +131,8 @@ static int usbtmc_open(struct inode *inode, struct file *filp)
 
        intf = usb_find_interface(&usbtmc_driver, iminor(inode));
        if (!intf) {
-               printk(KERN_ERR KBUILD_MODNAME
-                      ": can not find device for minor %d", iminor(inode));
-               retval = -ENODEV;
-               goto exit;
+               pr_err("can not find device for minor %d", iminor(inode));
+               return -ENODEV;
        }
 
        data = usb_get_intfdata(intf);
@@ -142,7 +141,6 @@ static int usbtmc_open(struct inode *inode, struct file *filp)
        /* Store pointer in file structure's private data field */
        filp->private_data = data;
 
-exit:
        return retval;
 }
 
@@ -394,12 +392,12 @@ static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t t
         */
        buffer[0] = 2;
        buffer[1] = data->bTag;
-       buffer[2] = ~(data->bTag);
+       buffer[2] = ~data->bTag;
        buffer[3] = 0; /* Reserved */
-       buffer[4] = (transfer_size) & 255;
-       buffer[5] = ((transfer_size) >> 8) & 255;
-       buffer[6] = ((transfer_size) >> 16) & 255;
-       buffer[7] = ((transfer_size) >> 24) & 255;
+       buffer[4] = transfer_size >> 0;
+       buffer[5] = transfer_size >> 8;
+       buffer[6] = transfer_size >> 16;
+       buffer[7] = transfer_size >> 24;
        buffer[8] = data->TermCharEnabled * 2;
        /* Use term character? */
        buffer[9] = data->TermChar;
@@ -418,7 +416,7 @@ static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t t
        /* Increment bTag -- and increment again if zero */
        data->bTag++;
        if (!data->bTag)
-               (data->bTag)++;
+               data->bTag++;
 
        if (retval < 0) {
                dev_err(&data->intf->dev, "usb_bulk_msg in send_request_dev_dep_msg_in() returned %d\n", retval);
@@ -473,7 +471,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
        done = 0;
 
        while (remaining > 0) {
-               if (!(data->rigol_quirk)) {
+               if (!data->rigol_quirk) {
                        dev_dbg(dev, "usb_bulk_msg_in: remaining(%zu), count(%zu)\n", remaining, count);
 
                        if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE - 3)
@@ -510,7 +508,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
                }
 
                /* Parse header in first packet */
-               if ((done == 0) || (!(data->rigol_quirk))) {
+               if ((done == 0) || !data->rigol_quirk) {
                        /* Sanity checks for the header */
                        if (actual < USBTMC_HEADER_SIZE) {
                                dev_err(dev, "Device sent too small first packet: %u < %u\n", actual, USBTMC_HEADER_SIZE);
@@ -554,14 +552,14 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
                                if (remaining > n_characters)
                                        remaining = n_characters;
                                /* Remove padding if it exists */
-                               if (actual > remaining) 
+                               if (actual > remaining)
                                        actual = remaining;
                        }
                        else {
                                if (this_part > n_characters)
                                        this_part = n_characters;
                                /* Remove padding if it exists */
-                               if (actual > this_part) 
+                               if (actual > this_part)
                                        actual = this_part;
                        }
 
@@ -570,7 +568,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
                        remaining -= actual;
 
                        /* Terminate if end-of-message bit received from device */
-                       if ((buffer[8] &  0x01) && (actual >= n_characters))
+                       if ((buffer[8] & 0x01) && (actual >= n_characters))
                                remaining = 0;
 
                        dev_dbg(dev, "Bulk-IN header: remaining(%zu), buf(%p), buffer(%p) done(%zu)\n", remaining,buf,buffer,done);
@@ -585,7 +583,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
                        done += actual;
                }
                else  {
-                       if (actual > remaining) 
+                       if (actual > remaining)
                                actual = remaining;
 
                        remaining -= actual;
@@ -651,12 +649,12 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
                /* Setup IO buffer for DEV_DEP_MSG_OUT message */
                buffer[0] = 1;
                buffer[1] = data->bTag;
-               buffer[2] = ~(data->bTag);
+               buffer[2] = ~data->bTag;
                buffer[3] = 0; /* Reserved */
-               buffer[4] = this_part & 255;
-               buffer[5] = (this_part >> 8) & 255;
-               buffer[6] = (this_part >> 16) & 255;
-               buffer[7] = (this_part >> 24) & 255;
+               buffer[4] = this_part >> 0;
+               buffer[5] = this_part >> 8;
+               buffer[6] = this_part >> 16;
+               buffer[7] = this_part >> 24;
                /* buffer[8] is set above... */
                buffer[9] = 0; /* Reserved */
                buffer[10] = 0; /* Reserved */
@@ -1102,7 +1100,7 @@ static int usbtmc_probe(struct usb_interface *intf,
 
        dev_dbg(&intf->dev, "%s called\n", __func__);
 
-       data = kmalloc(sizeof(struct usbtmc_device_data), GFP_KERNEL);
+       data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
        if (!data) {
                dev_err(&intf->dev, "Unable to allocate kernel memory\n");
                return -ENOMEM;
index b0585e623ba9ac38a161405b7f1c346ea063f044..23559746be92a6d9a7bef0fe1e98414e8e28c91d 100644 (file)
@@ -43,10 +43,11 @@ static const size_t pool_max[HCD_BUFFER_POOLS] = {
  *
  * Call this as part of initializing a host controller that uses the dma
  * memory allocators.  It initializes some pools of dma-coherent memory that
- * will be shared by all drivers using that controller, or returns a negative
- * errno value on error.
+ * will be shared by all drivers using that controller.
  *
  * Call hcd_buffer_destroy() to clean up after using those pools.
+ *
+ * Return: 0 if successful. A negative errno value otherwise.
  */
 int hcd_buffer_create(struct usb_hcd *hcd)
 {
index 7199adccf44488dc487641de2a085361bdaa0041..a6b2cabe7930eff53504448ab36d48b8786f3f98 100644 (file)
@@ -424,7 +424,8 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
 
        memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
        if (config->desc.bDescriptorType != USB_DT_CONFIG ||
-           config->desc.bLength < USB_DT_CONFIG_SIZE) {
+           config->desc.bLength < USB_DT_CONFIG_SIZE ||
+           config->desc.bLength > size) {
                dev_err(ddev, "invalid descriptor for config index %d: "
                    "type = 0x%X, length = %d\n", cfgidx,
                    config->desc.bDescriptorType, config->desc.bLength);
index 05986507b585897c763ac58e067e8a25f7e75374..737e3c19967bee3e81f57cc041ec9989ec38fb57 100644 (file)
@@ -725,15 +725,15 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
 
        /*
         * check for the special corner case 'get_device_id' in the printer
-        * class specification, where wIndex is (interface << 8 | altsetting)
-        * instead of just interface
+        * class specification, which we always want to allow as it is used
+        * to query things like ink level, etc.
         */
        if (requesttype == 0xa1 && request == 0) {
                alt_setting = usb_find_alt_setting(ps->dev->actconfig,
                                                   index >> 8, index & 0xff);
                if (alt_setting
                 && alt_setting->desc.bInterfaceClass == USB_CLASS_PRINTER)
-                       index >>= 8;
+                       return 0;
        }
 
        index &= 0xff;
index 7609ac4aed1cdc29493b3924c76b254cfdd09cae..124bcc50b0b7cba21f2429cd414729f9dcec08f6 100644 (file)
@@ -117,6 +117,8 @@ static DRIVER_ATTR(new_id, S_IRUGO | S_IWUSR, show_dynids, store_new_id);
  * @count: input size
  *
  * Removes a dynamic usb device ID from this driver.
+ *
+ * Return: @count on success. A negative error code otherwise.
  */
 static ssize_t
 store_remove_id(struct device_driver *driver, const char *buf, size_t count)
@@ -457,6 +459,8 @@ static int usb_unbind_interface(struct device *dev)
  * Callers must own the device lock, so driver probe() entries don't need
  * extra locking, but other call contexts may need to explicitly claim that
  * lock.
+ *
+ * Return: 0 on success.
  */
 int usb_driver_claim_interface(struct usb_driver *driver,
                                struct usb_interface *iface, void *priv)
@@ -658,6 +662,8 @@ EXPORT_SYMBOL_GPL(usb_match_one_id);
  * These device tables are exported with MODULE_DEVICE_TABLE, through
  * modutils, to support the driver loading functionality of USB hotplugging.
  *
+ * Return: The first matching usb_device_id, or %NULL.
+ *
  * What Matches:
  *
  * The "match_flags" element in a usb_device_id controls which
@@ -823,7 +829,8 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
  * Registers a USB device driver with the USB core.  The list of
  * unattached devices will be rescanned whenever a new driver is
  * added, allowing the new driver to attach to any recognized devices.
- * Returns a negative error code on failure and 0 on success.
+ *
+ * Return: A negative error code on failure and 0 on success.
  */
 int usb_register_device_driver(struct usb_device_driver *new_udriver,
                struct module *owner)
@@ -879,7 +886,8 @@ EXPORT_SYMBOL_GPL(usb_deregister_device_driver);
  * Registers a USB interface driver with the USB core.  The list of
  * unattached interfaces will be rescanned whenever a new driver is
  * added, allowing the new driver to attach to any recognized interfaces.
- * Returns a negative error code on failure and 0 on success.
+ *
+ * Return: A negative error code on failure and 0 on success.
  *
  * NOTE: if you want your driver to use the USB major number, you must call
  * usb_register_dev() to enable that functionality.  This function no longer
@@ -1213,6 +1221,8 @@ done:
  * unpredictable times.
  *
  * This routine can run only in process context.
+ *
+ * Return: 0 if the suspend succeeded.
  */
 static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
 {
@@ -1294,6 +1304,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
  * unpredictable times.
  *
  * This routine can run only in process context.
+ *
+ * Return: 0 on success.
  */
 static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
 {
@@ -1491,6 +1503,8 @@ void usb_autosuspend_device(struct usb_device *udev)
  * The caller must hold @udev's device lock.
  *
  * This routine can run only in process context.
+ *
+ * Return: 0 on success. A negative error code otherwise.
  */
 int usb_autoresume_device(struct usb_device *udev)
 {
@@ -1600,6 +1614,8 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface_no_suspend);
  * However if the autoresume fails then the counter is re-decremented.
  *
  * This routine can run only in process context.
+ *
+ * Return: 0 on success.
  */
 int usb_autopm_get_interface(struct usb_interface *intf)
 {
@@ -1633,6 +1649,8 @@ EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
  * resumed.
  *
  * This routine can run in atomic context.
+ *
+ * Return: 0 on success. A negative error code otherwise.
  */
 int usb_autopm_get_interface_async(struct usb_interface *intf)
 {
index 68cc6532e7492ee4293708ab8db9cd6e257e5e51..f13a289a07438554b6bf6479a86fef7982ef53d5 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
-#include <linux/idr.h>
 #include <linux/usb.h>
 #include "usb.h"
 
index 6a4c40766f0f131d0d133c3e263f5c3eb4aa9929..7421888087a3b752a3915c0dc70bfcda640d9122 100644 (file)
@@ -153,7 +153,7 @@ void usb_major_cleanup(void)
  * usb_deregister_dev() must be called when the driver is done with
  * the minor numbers given out by this function.
  *
- * Returns -EINVAL if something bad happens with trying to register a
+ * Return: -EINVAL if something bad happens with trying to register a
  * device, and 0 on success.
  */
 int usb_register_dev(struct usb_interface *intf,
index caeb8d6d39fbb8b2e93cb4a0e1cf9d5bd54c2a67..b9d3c43e38599e67c4cc8c409c686bb4f45fcf8a 100644 (file)
@@ -171,6 +171,8 @@ static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd,
  * through the hotplug entry's driver_data.
  *
  * Store this function in the HCD's struct pci_driver as probe().
+ *
+ * Return: 0 if successful.
  */
 int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
index 014dc996b4f6e0da44a8da8886ef5008307c6541..19ad3d2f8a24de61c35a56563b50f639868c03d9 100644 (file)
@@ -378,9 +378,10 @@ MODULE_PARM_DESC(authorized_default,
  * @buf: Buffer for USB string descriptor (header + UTF-16LE)
  * @len: Length (in bytes; may be odd) of descriptor buffer.
  *
- * The return value is the number of bytes filled in: 2 + 2*strlen(s) or
- * buflen, whichever is less.
+ * Return: The number of bytes filled in: 2 + 2*strlen(s) or @len,
+ * whichever is less.
  *
+ * Note:
  * USB String descriptors can contain at most 126 characters; input
  * strings longer than that are truncated.
  */
@@ -416,7 +417,8 @@ ascii2desc(char const *s, u8 *buf, unsigned len)
  *
  * Produces either a manufacturer, product or serial number string for the
  * virtual root hub device.
- * Returns the number of bytes filled in: the length of the descriptor or
+ *
+ * Return: The number of bytes filled in: the length of the descriptor or
  * of the provided buffer, whichever is less.
  */
 static unsigned
@@ -464,17 +466,13 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
        struct usb_ctrlrequest *cmd;
        u16             typeReq, wValue, wIndex, wLength;
        u8              *ubuf = urb->transfer_buffer;
-       /*
-        * tbuf should be as big as the BOS descriptor and
-        * the USB hub descriptor.
-        */
-       u8              tbuf[USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE]
-               __attribute__((aligned(4)));
-       const u8        *bufp = tbuf;
        unsigned        len = 0;
        int             status;
        u8              patch_wakeup = 0;
        u8              patch_protocol = 0;
+       u16             tbuf_size;
+       u8              *tbuf = NULL;
+       const u8        *bufp;
 
        might_sleep();
 
@@ -494,6 +492,18 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
        if (wLength > urb->transfer_buffer_length)
                goto error;
 
+       /*
+        * tbuf should be at least as big as the
+        * USB hub descriptor.
+        */
+       tbuf_size =  max_t(u16, sizeof(struct usb_hub_descriptor), wLength);
+       tbuf = kzalloc(tbuf_size, GFP_KERNEL);
+       if (!tbuf)
+               return -ENOMEM;
+
+       bufp = tbuf;
+
+
        urb->actual_length = 0;
        switch (typeReq) {
 
@@ -691,18 +701,12 @@ error:
                                bDeviceProtocol = USB_HUB_PR_HS_SINGLE_TT;
        }
 
+       kfree(tbuf);
+
        /* any errors get returned through the urb completion */
        spin_lock_irq(&hcd_root_hub_lock);
        usb_hcd_unlink_urb_from_ep(hcd, urb);
-
-       /* This peculiar use of spinlocks echoes what real HC drivers do.
-        * Avoiding calls to local_irq_disable/enable makes the code
-        * RT-friendly.
-        */
-       spin_unlock(&hcd_root_hub_lock);
        usb_hcd_giveback_urb(hcd, urb, status);
-       spin_lock(&hcd_root_hub_lock);
-
        spin_unlock_irq(&hcd_root_hub_lock);
        return 0;
 }
@@ -742,9 +746,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
                        memcpy(urb->transfer_buffer, buffer, length);
 
                        usb_hcd_unlink_urb_from_ep(hcd, urb);
-                       spin_unlock(&hcd_root_hub_lock);
                        usb_hcd_giveback_urb(hcd, urb, 0);
-                       spin_lock(&hcd_root_hub_lock);
                } else {
                        length = 0;
                        set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
@@ -834,10 +836,7 @@ static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                if (urb == hcd->status_urb) {
                        hcd->status_urb = NULL;
                        usb_hcd_unlink_urb_from_ep(hcd, urb);
-
-                       spin_unlock(&hcd_root_hub_lock);
                        usb_hcd_giveback_urb(hcd, urb, status);
-                       spin_lock(&hcd_root_hub_lock);
                }
        }
  done:
@@ -938,6 +937,8 @@ static void usb_bus_init (struct usb_bus *bus)
  *
  * Assigns a bus number, and links the controller into usbcore data
  * structures so that it can be seen by scanning the bus list.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
  */
 static int usb_register_bus(struct usb_bus *bus)
 {
@@ -1002,6 +1003,8 @@ static void usb_deregister_bus (struct usb_bus *bus)
  * the device properly in the device tree and then calls usb_new_device()
  * to register the usb device.  It also assigns the root hub's USB address
  * (always 1).
+ *
+ * Return: 0 if successful. A negative error code otherwise.
  */
 static int register_root_hub(struct usb_hcd *hcd)
 {
@@ -1108,7 +1111,9 @@ EXPORT_SYMBOL_GPL(usb_hcd_end_port_resume);
  * @isoc: true for isochronous transactions, false for interrupt ones
  * @bytecount: how many bytes in the transaction.
  *
- * Returns approximate bus time in nanoseconds for a periodic transaction.
+ * Return: Approximate bus time in nanoseconds for a periodic transaction.
+ *
+ * Note:
  * See USB 2.0 spec section 5.11.3; only periodic transfers need to be
  * scheduled in software, this function is only used for such scheduling.
  */
@@ -1166,7 +1171,7 @@ EXPORT_SYMBOL_GPL(usb_calc_bus_time);
  * be disabled.  The actions carried out here are required for URB
  * submission, as well as for endpoint shutdown and for usb_kill_urb.
  *
- * Returns 0 for no error, otherwise a negative error code (in which case
+ * Return: 0 for no error, otherwise a negative error code (in which case
  * the enqueue() method must fail).  If no error occurs but enqueue() fails
  * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing
  * the private spinlock and returning.
@@ -1221,7 +1226,7 @@ EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep);
  * be disabled.  The actions carried out here are required for making
  * sure than an unlink is valid.
  *
- * Returns 0 for no error, otherwise a negative error code (in which case
+ * Return: 0 for no error, otherwise a negative error code (in which case
  * the dequeue() method must fail).  The possible error codes are:
  *
  *     -EIDRM: @urb was not submitted or has already completed.
@@ -1648,6 +1653,72 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
 
 /*-------------------------------------------------------------------------*/
 
+static void __usb_hcd_giveback_urb(struct urb *urb)
+{
+       struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
+       int status = urb->unlinked;
+       unsigned long flags;
+
+       urb->hcpriv = NULL;
+       if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+           urb->actual_length < urb->transfer_buffer_length &&
+           !status))
+               status = -EREMOTEIO;
+
+       unmap_urb_for_dma(hcd, urb);
+       usbmon_urb_complete(&hcd->self, urb, status);
+       usb_unanchor_urb(urb);
+
+       /* pass ownership to the completion handler */
+       urb->status = status;
+
+       /*
+        * We disable local IRQs here avoid possible deadlock because
+        * drivers may call spin_lock() to hold lock which might be
+        * acquired in one hard interrupt handler.
+        *
+        * The local_irq_save()/local_irq_restore() around complete()
+        * will be removed if current USB drivers have been cleaned up
+        * and no one may trigger the above deadlock situation when
+        * running complete() in tasklet.
+        */
+       local_irq_save(flags);
+       urb->complete(urb);
+       local_irq_restore(flags);
+
+       atomic_dec(&urb->use_count);
+       if (unlikely(atomic_read(&urb->reject)))
+               wake_up(&usb_kill_urb_queue);
+       usb_put_urb(urb);
+}
+
+static void usb_giveback_urb_bh(unsigned long param)
+{
+       struct giveback_urb_bh *bh = (struct giveback_urb_bh *)param;
+       struct list_head local_list;
+
+       spin_lock_irq(&bh->lock);
+       bh->running = true;
+ restart:
+       list_replace_init(&bh->head, &local_list);
+       spin_unlock_irq(&bh->lock);
+
+       while (!list_empty(&local_list)) {
+               struct urb *urb;
+
+               urb = list_entry(local_list.next, struct urb, urb_list);
+               list_del_init(&urb->urb_list);
+               __usb_hcd_giveback_urb(urb);
+       }
+
+       /* check if there are new URBs to giveback */
+       spin_lock_irq(&bh->lock);
+       if (!list_empty(&bh->head))
+               goto restart;
+       bh->running = false;
+       spin_unlock_irq(&bh->lock);
+}
+
 /**
  * usb_hcd_giveback_urb - return URB from HCD to device driver
  * @hcd: host controller returning the URB
@@ -1667,25 +1738,37 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
  */
 void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
 {
-       urb->hcpriv = NULL;
-       if (unlikely(urb->unlinked))
-               status = urb->unlinked;
-       else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
-                       urb->actual_length < urb->transfer_buffer_length &&
-                       !status))
-               status = -EREMOTEIO;
+       struct giveback_urb_bh *bh;
+       bool running, high_prio_bh;
 
-       unmap_urb_for_dma(hcd, urb);
-       usbmon_urb_complete(&hcd->self, urb, status);
-       usb_unanchor_urb(urb);
+       /* pass status to tasklet via unlinked */
+       if (likely(!urb->unlinked))
+               urb->unlinked = status;
 
-       /* pass ownership to the completion handler */
-       urb->status = status;
-       urb->complete (urb);
-       atomic_dec (&urb->use_count);
-       if (unlikely(atomic_read(&urb->reject)))
-               wake_up (&usb_kill_urb_queue);
-       usb_put_urb (urb);
+       if (!hcd_giveback_urb_in_bh(hcd) && !is_root_hub(urb->dev)) {
+               __usb_hcd_giveback_urb(urb);
+               return;
+       }
+
+       if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe)) {
+               bh = &hcd->high_prio_bh;
+               high_prio_bh = true;
+       } else {
+               bh = &hcd->low_prio_bh;
+               high_prio_bh = false;
+       }
+
+       spin_lock(&bh->lock);
+       list_add_tail(&urb->urb_list, &bh->head);
+       running = bh->running;
+       spin_unlock(&bh->lock);
+
+       if (running)
+               ;
+       else if (high_prio_bh)
+               tasklet_hi_schedule(&bh->bh);
+       else
+               tasklet_schedule(&bh->bh);
 }
 EXPORT_SYMBOL_GPL(usb_hcd_giveback_urb);
 
@@ -1784,7 +1867,7 @@ rescan:
  * pass in the current alternate interface setting in cur_alt,
  * and pass in the new alternate interface setting in new_alt.
  *
- * Returns an error if the requested bandwidth change exceeds the
+ * Return: An error if the requested bandwidth change exceeds the
  * bus bandwidth or host controller internal resources.
  */
 int usb_hcd_alloc_bandwidth(struct usb_device *udev,
@@ -1954,9 +2037,12 @@ void usb_hcd_reset_endpoint(struct usb_device *udev,
  * @num_streams:       number of streams to allocate.
  * @mem_flags:         flags hcd should use to allocate memory.
  *
- * Sets up a group of bulk endpoints to have num_streams stream IDs available.
+ * Sets up a group of bulk endpoints to have @num_streams stream IDs available.
  * Drivers may queue multiple transfers to different stream IDs, which may
  * complete in a different order than they were queued.
+ *
+ * Return: On success, the number of allocated streams. On failure, a negative
+ * error code.
  */
 int usb_alloc_streams(struct usb_interface *interface,
                struct usb_host_endpoint **eps, unsigned int num_eps,
@@ -2201,6 +2287,8 @@ EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
  * khubd identifying and possibly configuring the device.
  * This is needed by OTG controller drivers, where it helps meet
  * HNP protocol timing requirements for starting a port reset.
+ *
+ * Return: 0 if successful.
  */
 int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num)
 {
@@ -2235,6 +2323,8 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum);
  *
  * If the controller isn't HALTed, calls the driver's irq handler.
  * Checks whether the controller is now dead.
+ *
+ * Return: %IRQ_HANDLED if the IRQ was handled. %IRQ_NONE otherwise.
  */
 irqreturn_t usb_hcd_irq (int irq, void *__hcd)
 {
@@ -2307,6 +2397,14 @@ EXPORT_SYMBOL_GPL (usb_hc_died);
 
 /*-------------------------------------------------------------------------*/
 
+static void init_giveback_urb_bh(struct giveback_urb_bh *bh)
+{
+
+       spin_lock_init(&bh->lock);
+       INIT_LIST_HEAD(&bh->head);
+       tasklet_init(&bh->bh, usb_giveback_urb_bh, (unsigned long)bh);
+}
+
 /**
  * usb_create_shared_hcd - create and initialize an HCD structure
  * @driver: HC driver that will use this hcd
@@ -2320,7 +2418,8 @@ EXPORT_SYMBOL_GPL (usb_hc_died);
  * HC driver's private data.  Initialize the generic members of the
  * hcd structure.
  *
- * If memory is unavailable, returns NULL.
+ * Return: On success, a pointer to the created and initialized HCD structure.
+ * On failure (e.g. if memory is unavailable), %NULL.
  */
 struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
                struct device *dev, const char *bus_name,
@@ -2384,7 +2483,8 @@ EXPORT_SYMBOL_GPL(usb_create_shared_hcd);
  * HC driver's private data.  Initialize the generic members of the
  * hcd structure.
  *
- * If memory is unavailable, returns NULL.
+ * Return: On success, a pointer to the created and initialized HCD
+ * structure. On failure (e.g. if memory is unavailable), %NULL.
  */
 struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
                struct device *dev, const char *bus_name)
@@ -2563,7 +2663,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
         * should already have been reset (and boot firmware kicked off etc).
         */
        if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
-               dev_err(hcd->self.controller, "can't setup\n");
+               dev_err(hcd->self.controller, "can't setup: %d\n", retval);
                goto err_hcd_driver_setup;
        }
        hcd->rh_pollable = 1;
@@ -2573,6 +2673,10 @@ int usb_add_hcd(struct usb_hcd *hcd,
                        && device_can_wakeup(&hcd->self.root_hub->dev))
                dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
 
+       /* initialize tasklets */
+       init_giveback_urb_bh(&hcd->high_prio_bh);
+       init_giveback_urb_bh(&hcd->low_prio_bh);
+
        /* enable irqs just before we start the controller,
         * if the BIOS provides legacy PCI irqs.
         */
@@ -2681,6 +2785,16 @@ void usb_remove_hcd(struct usb_hcd *hcd)
        usb_disconnect(&rhdev);         /* Sets rhdev to NULL */
        mutex_unlock(&usb_bus_list_lock);
 
+       /*
+        * tasklet_kill() isn't needed here because:
+        * - driver's disconnect() called from usb_disconnect() should
+        *   make sure its URBs are completed during the disconnect()
+        *   callback
+        *
+        * - it is too late to run complete() here since driver may have
+        *   been removed already now
+        */
+
        /* Prevent any more root-hub status calls from the timer.
         * The HCD might still restart the timer (if a port status change
         * interrupt occurs), but usb_hcd_poll_rh_status() won't invoke
index 558313de49111025e03c1b6b6d015a2688800498..5d6d28a76e0ac4e63937c5562b6b7ee1e3c9653c 100644 (file)
@@ -734,6 +734,8 @@ static void hub_tt_work(struct work_struct *work)
  *
  * call this function to control port's power via setting or
  * clearing the port's PORT_POWER feature.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
  */
 int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
                           int port1, bool set)
@@ -762,6 +764,8 @@ int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
  *
  * It may not be possible for that hub to handle additional full (or low)
  * speed transactions until that state is fully cleared out.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
  */
 int usb_hub_clear_tt_buffer(struct urb *urb)
 {
@@ -964,6 +968,8 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
  * see that the device has been disconnected.  When the device is
  * physically unplugged and something is plugged in, the events will
  * be received and processed normally.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
  */
 int usb_remove_device(struct usb_device *udev)
 {
@@ -1464,11 +1470,10 @@ static int hub_configure(struct usb_hub *hub,
         * and battery-powered root hubs (may provide just 8 mA).
         */
        ret = usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);
-       if (ret < 2) {
+       if (ret) {
                message = "can't get hub status";
                goto fail;
        }
-       le16_to_cpus(&hubstatus);
        hcd = bus_to_hcd(hdev->bus);
        if (hdev == hdev->bus->root_hub) {
                if (hcd->power_budget > 0)
@@ -2116,6 +2121,8 @@ static inline void announce_device(struct usb_device *udev) { }
  * @udev: newly addressed device (in ADDRESS state)
  *
  * Finish enumeration for On-The-Go devices
+ *
+ * Return: 0 if successful. A negative error code otherwise.
  */
 static int usb_enumerate_device_otg(struct usb_device *udev)
 {
@@ -2198,6 +2205,8 @@ fail:
  * If the device is WUSB and not authorized, we don't attempt to read
  * the string descriptors, as they will be errored out by the device
  * until it has been authorized.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
  */
 static int usb_enumerate_device(struct usb_device *udev)
 {
@@ -2278,13 +2287,14 @@ static void set_usb_port_removable(struct usb_device *udev)
  * udev has already been installed, but udev is not yet visible through
  * sysfs or other filesystem code.
  *
- * It will return if the device is configured properly or not.  Zero if
- * the interface was registered with the driver core; else a negative
- * errno value.
- *
  * This call is synchronous, and may not be used in an interrupt context.
  *
  * Only the hub driver or root-hub registrar should ever call this.
+ *
+ * Return: Whether the device is configured properly or not. Zero if the
+ * interface was registered with the driver core; else a negative errno
+ * value.
+ *
  */
 int usb_new_device(struct usb_device *udev)
 {
@@ -2392,6 +2402,8 @@ fail:
  *
  * We share a lock (that we have) with device_del(), so we need to
  * defer its call.
+ *
+ * Return: 0.
  */
 int usb_deauthorize_device(struct usb_device *usb_dev)
 {
@@ -2838,20 +2850,51 @@ void usb_enable_ltm(struct usb_device *udev)
 }
 EXPORT_SYMBOL_GPL(usb_enable_ltm);
 
-#ifdef CONFIG_PM
 /*
- * usb_disable_function_remotewakeup - disable usb3.0
- * device's function remote wakeup
+ * usb_enable_remote_wakeup - enable remote wakeup for a device
  * @udev: target device
  *
- * Assume there's only one function on the USB 3.0
- * device and disable remote wake for the first
- * interface. FIXME if the interface association
- * descriptor shows there's more than one function.
+ * For USB-2 devices: Set the device's remote wakeup feature.
+ *
+ * For USB-3 devices: Assume there's only one function on the device and
+ * enable remote wake for the first interface.  FIXME if the interface
+ * association descriptor shows there's more than one function.
  */
-static int usb_disable_function_remotewakeup(struct usb_device *udev)
+static int usb_enable_remote_wakeup(struct usb_device *udev)
 {
-       return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+       if (udev->speed < USB_SPEED_SUPER)
+               return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                               USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
+                               USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0,
+                               USB_CTRL_SET_TIMEOUT);
+       else
+               return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                               USB_REQ_SET_FEATURE, USB_RECIP_INTERFACE,
+                               USB_INTRF_FUNC_SUSPEND,
+                               USB_INTRF_FUNC_SUSPEND_RW |
+                                       USB_INTRF_FUNC_SUSPEND_LP,
+                               NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+/*
+ * usb_disable_remote_wakeup - disable remote wakeup for a device
+ * @udev: target device
+ *
+ * For USB-2 devices: Clear the device's remote wakeup feature.
+ *
+ * For USB-3 devices: Assume there's only one function on the device and
+ * disable remote wake for the first interface.  FIXME if the interface
+ * association descriptor shows there's more than one function.
+ */
+static int usb_disable_remote_wakeup(struct usb_device *udev)
+{
+       if (udev->speed < USB_SPEED_SUPER)
+               return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                               USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE,
+                               USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0,
+                               USB_CTRL_SET_TIMEOUT);
+       else
+               return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
                                USB_REQ_CLEAR_FEATURE, USB_RECIP_INTERFACE,
                                USB_INTRF_FUNC_SUSPEND, 0, NULL, 0,
                                USB_CTRL_SET_TIMEOUT);
@@ -2918,7 +2961,6 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
 {
        struct usb_hub  *hub = usb_hub_to_struct_hub(udev->parent);
        struct usb_port *port_dev = hub->ports[udev->portnum - 1];
-       enum pm_qos_flags_status pm_qos_stat;
        int             port1 = udev->portnum;
        int             status;
        bool            really_suspend = true;
@@ -2930,33 +2972,13 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
         * we don't explicitly enable it here.
         */
        if (udev->do_remote_wakeup) {
-               if (!hub_is_superspeed(hub->hdev)) {
-                       status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-                                       USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
-                                       USB_DEVICE_REMOTE_WAKEUP, 0,
-                                       NULL, 0,
-                                       USB_CTRL_SET_TIMEOUT);
-               } else {
-                       /* Assume there's only one function on the USB 3.0
-                        * device and enable remote wake for the first
-                        * interface. FIXME if the interface association
-                        * descriptor shows there's more than one function.
-                        */
-                       status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-                                       USB_REQ_SET_FEATURE,
-                                       USB_RECIP_INTERFACE,
-                                       USB_INTRF_FUNC_SUSPEND,
-                                       USB_INTRF_FUNC_SUSPEND_RW |
-                                       USB_INTRF_FUNC_SUSPEND_LP,
-                                       NULL, 0,
-                                       USB_CTRL_SET_TIMEOUT);
-               }
+               status = usb_enable_remote_wakeup(udev);
                if (status) {
                        dev_dbg(&udev->dev, "won't remote wakeup, status %d\n",
                                        status);
                        /* bail if autosuspend is requested */
                        if (PMSG_IS_AUTO(msg))
-                               return status;
+                               goto err_wakeup;
                }
        }
 
@@ -2965,14 +2987,16 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
                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;
+               dev_err(&udev->dev, "Failed to disable LTM before suspend\n.");
+               status = -ENOMEM;
+               if (PMSG_IS_AUTO(msg))
+                       goto err_ltm;
        }
        if (usb_unlocked_disable_lpm(udev)) {
-               dev_err(&udev->dev, "%s Failed to disable LPM before suspend\n.",
-                               __func__);
-               return -ENOMEM;
+               dev_err(&udev->dev, "Failed to disable LPM before suspend\n.");
+               status = -ENOMEM;
+               if (PMSG_IS_AUTO(msg))
+                       goto err_lpm3;
        }
 
        /* see 7.1.7.6 */
@@ -3000,28 +3024,19 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
        if (status) {
                dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",
                                port1, status);
-               /* paranoia:  "should not happen" */
-               if (udev->do_remote_wakeup) {
-                       if (!hub_is_superspeed(hub->hdev)) {
-                               (void) usb_control_msg(udev,
-                                               usb_sndctrlpipe(udev, 0),
-                                               USB_REQ_CLEAR_FEATURE,
-                                               USB_RECIP_DEVICE,
-                                               USB_DEVICE_REMOTE_WAKEUP, 0,
-                                               NULL, 0,
-                                               USB_CTRL_SET_TIMEOUT);
-                       } else
-                               (void) usb_disable_function_remotewakeup(udev);
-
-               }
 
+               /* Try to enable USB3 LPM and LTM again */
+               usb_unlocked_enable_lpm(udev);
+ err_lpm3:
+               usb_enable_ltm(udev);
+ err_ltm:
                /* Try to enable USB2 hardware LPM again */
                if (udev->usb2_hw_lpm_capable == 1)
                        usb_set_usb2_hardware_lpm(udev, 1);
 
-               /* Try to enable USB3 LTM and LPM again */
-               usb_enable_ltm(udev);
-               usb_unlocked_enable_lpm(udev);
+               if (udev->do_remote_wakeup)
+                       (void) usb_disable_remote_wakeup(udev);
+ err_wakeup:
 
                /* System sleep transitions should never fail */
                if (!PMSG_IS_AUTO(msg))
@@ -3043,14 +3058,15 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
         * Check whether current status meets the requirement of
         * usb port power off mechanism
         */
-       pm_qos_stat = dev_pm_qos_flags(&port_dev->dev,
-                       PM_QOS_FLAG_NO_POWER_OFF);
-       if (!udev->do_remote_wakeup
-                       && pm_qos_stat != PM_QOS_FLAGS_ALL
-                       && udev->persist_enabled
-                       && !status) {
-               pm_runtime_put_sync(&port_dev->dev);
-               port_dev->did_runtime_put = true;
+       if (status == 0 && !udev->do_remote_wakeup && udev->persist_enabled) {
+               enum pm_qos_flags_status pm_qos_stat;
+
+               pm_qos_stat = dev_pm_qos_flags(&port_dev->dev,
+                               PM_QOS_FLAG_NO_POWER_OFF);
+               if (pm_qos_stat != PM_QOS_FLAGS_ALL) {
+                       pm_runtime_put_sync(&port_dev->dev);
+                       port_dev->did_runtime_put = true;
+               }
        }
 
        usb_mark_last_busy(hub->hdev);
@@ -3102,8 +3118,6 @@ static int finish_port_resume(struct usb_device *udev)
        if (status == 0) {
                devstatus = 0;
                status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
-               if (status >= 0)
-                       status = (status > 0 ? 0 : -ENODEV);
 
                /* If a normal resume failed, try doing a reset-resume */
                if (status && !udev->reset_resume && udev->persist_enabled) {
@@ -3123,24 +3137,15 @@ static int finish_port_resume(struct usb_device *udev)
         * udev->reset_resume
         */
        } else if (udev->actconfig && !udev->reset_resume) {
-               if (!hub_is_superspeed(udev->parent)) {
-                       le16_to_cpus(&devstatus);
+               if (udev->speed < USB_SPEED_SUPER) {
                        if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
-                               status = usb_control_msg(udev,
-                                               usb_sndctrlpipe(udev, 0),
-                                               USB_REQ_CLEAR_FEATURE,
-                                               USB_RECIP_DEVICE,
-                                               USB_DEVICE_REMOTE_WAKEUP, 0,
-                                               NULL, 0,
-                                               USB_CTRL_SET_TIMEOUT);
+                               status = usb_disable_remote_wakeup(udev);
                } else {
                        status = usb_get_status(udev, USB_RECIP_INTERFACE, 0,
                                        &devstatus);
-                       le16_to_cpus(&devstatus);
                        if (!status && devstatus & (USB_INTRF_STAT_FUNC_RW_CAP
                                        | USB_INTRF_STAT_FUNC_RW))
-                               status =
-                                       usb_disable_function_remotewakeup(udev);
+                               status = usb_disable_remote_wakeup(udev);
                }
 
                if (status)
@@ -3274,8 +3279,6 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
        return status;
 }
 
-#endif /* CONFIG_PM */
-
 #ifdef CONFIG_PM_RUNTIME
 
 /* caller has locked udev */
@@ -3843,7 +3846,8 @@ EXPORT_SYMBOL_GPL(usb_disable_ltm);
 
 void usb_enable_ltm(struct usb_device *udev) { }
 EXPORT_SYMBOL_GPL(usb_enable_ltm);
-#endif
+
+#endif /* CONFIG_PM */
 
 
 /* USB 2.0 spec, 7.1.7.3 / fig 7-29:
@@ -4483,11 +4487,10 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
 
                        status = usb_get_status(udev, USB_RECIP_DEVICE, 0,
                                        &devstat);
-                       if (status < 2) {
+                       if (status) {
                                dev_dbg(&udev->dev, "get status %d ?\n", status);
                                goto loop_disable;
                        }
-                       le16_to_cpus(&devstat);
                        if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
                                dev_err(&udev->dev,
                                        "can't connect bus-powered hub "
@@ -5035,10 +5038,11 @@ static int descriptors_changed(struct usb_device *udev,
  * re-connected.  All drivers will be unbound, and the device will be
  * re-enumerated and probed all over again.
  *
- * Returns 0 if the reset succeeded, -ENODEV if the device has been
+ * Return: 0 if the reset succeeded, -ENODEV if the device has been
  * flagged for logical disconnection, or some other negative error code
  * if the reset wasn't even attempted.
  *
+ * Note:
  * The caller must own the device lock.  For example, it's safe to use
  * this from a driver probe() routine after downloading new firmware.
  * For calls that might not occur during probe(), drivers should lock
@@ -5194,8 +5198,9 @@ re_enumerate:
  * method), performs the port reset, and then lets the drivers know that
  * the reset is over (using their post_reset method).
  *
- * Return value is the same as for usb_reset_and_verify_device().
+ * Return: The same as for usb_reset_and_verify_device().
  *
+ * Note:
  * The caller must own the device lock.  For example, it's safe to use
  * this from a driver probe() routine after downloading new firmware.
  * For calls that might not occur during probe(), drivers should lock
@@ -5333,7 +5338,7 @@ EXPORT_SYMBOL_GPL(usb_queue_reset_device);
  * USB drivers call this function to get hub's child device
  * pointer.
  *
- * Return NULL if input param is invalid and
+ * Return: %NULL if input param is invalid and
  * child's usb_device pointer if non-NULL.
  */
 struct usb_device *usb_hub_find_child(struct usb_device *hdev,
@@ -5367,8 +5372,8 @@ void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1,
  * @hdev: USB device belonging to the usb hub
  * @port1: port num of the port
  *
- * Return connect type of the port and if input params are
- * invalid, return USB_PORT_CONNECT_TYPE_UNKNOWN.
+ * Return: The connect type of the port if successful. Or
+ * USB_PORT_CONNECT_TYPE_UNKNOWN if input params are invalid.
  */
 enum usb_port_connect_type
 usb_get_hub_port_connect_type(struct usb_device *hdev, int port1)
@@ -5428,8 +5433,8 @@ void usb_hub_adjust_deviceremovable(struct usb_device *hdev,
  * @hdev: USB device belonging to the usb hub
  * @port1: port num of the port
  *
- * Return port's acpi handle if successful, NULL if params are
- * invaild.
+ * Return: Port's acpi handle if successful, %NULL if params are
+ * invalid.
  */
 acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev,
        int port1)
index e7ee1e451660a4c9a29cee88dc9c97f3aec534c0..82927e1ed27d078f513a69727ebf7e55ef885ad8 100644 (file)
@@ -119,15 +119,15 @@ static int usb_internal_control_msg(struct usb_device *usb_dev,
  * This function sends a simple control message to a specified endpoint and
  * waits for the message to complete, or timeout.
  *
- * If successful, it returns the number of bytes transferred, otherwise a
- * negative error number.
- *
  * Don't use this function from within an interrupt context, like a bottom half
  * handler.  If you need an asynchronous message, or need to send a message
  * from within interrupt context, use usb_submit_urb().
  * If a thread in your driver uses this call, make sure your disconnect()
  * method can wait for it to complete.  Since you don't have a handle on the
  * URB used, you can't cancel the request.
+ *
+ * Return: If successful, the number of bytes transferred. Otherwise, a negative
+ * error number.
  */
 int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
                    __u8 requesttype, __u16 value, __u16 index, void *data,
@@ -170,15 +170,16 @@ EXPORT_SYMBOL_GPL(usb_control_msg);
  * This function sends a simple interrupt message to a specified endpoint and
  * waits for the message to complete, or timeout.
  *
- * If successful, it returns 0, otherwise a negative error number.  The number
- * of actual bytes transferred will be stored in the actual_length paramater.
- *
  * Don't use this function from within an interrupt context, like a bottom half
  * handler.  If you need an asynchronous message, or need to send a message
  * from within interrupt context, use usb_submit_urb() If a thread in your
  * driver uses this call, make sure your disconnect() method can wait for it to
  * complete.  Since you don't have a handle on the URB used, you can't cancel
  * the request.
+ *
+ * Return:
+ * If successful, 0. Otherwise a negative error number. The number of actual
+ * bytes transferred will be stored in the @actual_length paramater.
  */
 int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe,
                      void *data, int len, int *actual_length, int timeout)
@@ -203,9 +204,6 @@ EXPORT_SYMBOL_GPL(usb_interrupt_msg);
  * This function sends a simple bulk message to a specified endpoint
  * and waits for the message to complete, or timeout.
  *
- * If successful, it returns 0, otherwise a negative error number.  The number
- * of actual bytes transferred will be stored in the actual_length paramater.
- *
  * Don't use this function from within an interrupt context, like a bottom half
  * handler.  If you need an asynchronous message, or need to send a message
  * from within interrupt context, use usb_submit_urb() If a thread in your
@@ -217,6 +215,11 @@ EXPORT_SYMBOL_GPL(usb_interrupt_msg);
  * users are forced to abuse this routine by using it to submit URBs for
  * interrupt endpoints.  We will take the liberty of creating an interrupt URB
  * (with the default interval) if the target is an interrupt endpoint.
+ *
+ * Return:
+ * If successful, 0. Otherwise a negative error number. The number of actual
+ * bytes transferred will be stored in the @actual_length paramater.
+ *
  */
 int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
                 void *data, int len, int *actual_length, int timeout)
@@ -341,9 +344,9 @@ static void sg_complete(struct urb *urb)
  *     send every byte identified in the list.
  * @mem_flags: SLAB_* flags affecting memory allocations in this call
  *
- * Returns zero for success, else a negative errno value.  This initializes a
- * scatter/gather request, allocating resources such as I/O mappings and urb
- * memory (except maybe memory used by USB controller drivers).
+ * This initializes a scatter/gather request, allocating resources such as
+ * I/O mappings and urb memory (except maybe memory used by USB controller
+ * drivers).
  *
  * The request must be issued using usb_sg_wait(), which waits for the I/O to
  * complete (or to be canceled) and then cleans up all resources allocated by
@@ -351,6 +354,8 @@ static void sg_complete(struct urb *urb)
  *
  * The request may be canceled with usb_sg_cancel(), either before or after
  * usb_sg_wait() is called.
+ *
+ * Return: Zero for success, else a negative errno value.
  */
 int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
                unsigned pipe, unsigned period, struct scatterlist *sg,
@@ -623,7 +628,7 @@ EXPORT_SYMBOL_GPL(usb_sg_cancel);
  *
  * This call is synchronous, and may not be used in an interrupt context.
  *
- * Returns the number of bytes received on success, or else the status code
+ * Return: The number of bytes received on success, or else the status code
  * returned by the underlying usb_control_msg() call.
  */
 int usb_get_descriptor(struct usb_device *dev, unsigned char type,
@@ -671,7 +676,7 @@ EXPORT_SYMBOL_GPL(usb_get_descriptor);
  *
  * This call is synchronous, and may not be used in an interrupt context.
  *
- * Returns the number of bytes received on success, or else the status code
+ * Return: The number of bytes received on success, or else the status code
  * returned by the underlying usb_control_msg() call.
  */
 static int usb_get_string(struct usb_device *dev, unsigned short langid,
@@ -805,7 +810,7 @@ static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf)
  *
  * This call is synchronous, and may not be used in an interrupt context.
  *
- * Returns length of the string (>= 0) or usb_control_msg status (< 0).
+ * Return: length of the string (>= 0) or usb_control_msg status (< 0).
  */
 int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
 {
@@ -853,8 +858,8 @@ EXPORT_SYMBOL_GPL(usb_string);
  * @udev: the device whose string descriptor is being read
  * @index: the descriptor index
  *
- * Returns a pointer to a kmalloc'ed buffer containing the descriptor string,
- * or NULL if the index is 0 or the string could not be read.
+ * Return: A pointer to a kmalloc'ed buffer containing the descriptor string,
+ * or %NULL if the index is 0 or the string could not be read.
  */
 char *usb_cache_string(struct usb_device *udev, int index)
 {
@@ -894,7 +899,7 @@ char *usb_cache_string(struct usb_device *udev, int index)
  *
  * This call is synchronous, and may not be used in an interrupt context.
  *
- * Returns the number of bytes received on success, or else the status code
+ * Return: The number of bytes received on success, or else the status code
  * returned by the underlying usb_control_msg() call.
  */
 int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
@@ -934,13 +939,13 @@ int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
  *
  * This call is synchronous, and may not be used in an interrupt context.
  *
- * Returns the number of bytes received on success, or else the status code
- * returned by the underlying usb_control_msg() call.
+ * Returns 0 and the status value in *@data (in host byte order) on success,
+ * or else the status code from the underlying usb_control_msg() call.
  */
 int usb_get_status(struct usb_device *dev, int type, int target, void *data)
 {
        int ret;
-       u16 *status = kmalloc(sizeof(*status), GFP_KERNEL);
+       __le16 *status = kmalloc(sizeof(*status), GFP_KERNEL);
 
        if (!status)
                return -ENOMEM;
@@ -949,7 +954,12 @@ int usb_get_status(struct usb_device *dev, int type, int target, void *data)
                USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, status,
                sizeof(*status), USB_CTRL_GET_TIMEOUT);
 
-       *(u16 *)data = *status;
+       if (ret == 2) {
+               *(u16 *) data = le16_to_cpu(*status);
+               ret = 0;
+       } else if (ret >= 0) {
+               ret = -EIO;
+       }
        kfree(status);
        return ret;
 }
@@ -975,7 +985,7 @@ EXPORT_SYMBOL_GPL(usb_get_status);
  *
  * This call is synchronous, and may not be used in an interrupt context.
  *
- * Returns zero on success, or else the status code returned by the
+ * Return: Zero on success, or else the status code returned by the
  * underlying usb_control_msg() call.
  */
 int usb_clear_halt(struct usb_device *dev, int pipe)
@@ -1272,7 +1282,7 @@ void usb_enable_interface(struct usb_device *dev,
  * endpoints in that interface; all such urbs must first be completed
  * (perhaps forced by unlinking).
  *
- * Returns zero on success, or else the status code returned by the
+ * Return: Zero on success, or else the status code returned by the
  * underlying usb_control_msg() call.
  */
 int usb_set_interface(struct usb_device *dev, int interface, int alternate)
@@ -1426,7 +1436,7 @@ EXPORT_SYMBOL_GPL(usb_set_interface);
  *
  * The caller must own the device lock.
  *
- * Returns zero on success, else a negative error code.
+ * Return: Zero on success, else a negative error code.
  */
 int usb_reset_configuration(struct usb_device *dev)
 {
@@ -1968,7 +1978,7 @@ static void cancel_async_set_config(struct usb_device *udev)
  * routine gets around the normal restrictions by using a work thread to
  * submit the change-config request.
  *
- * Returns 0 if the request was successfully queued, error code otherwise.
+ * Return: 0 if the request was successfully queued, error code otherwise.
  * The caller has no way to know whether the queued request will eventually
  * succeed.
  */
index 16927fa88fbd61d2e81d02a42b6d1dfefac1fa65..c12bc790a6a702de065087b9d4c07563f3bb54b1 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/usb.h>
 #include <linux/wait.h>
 #include <linux/usb/hcd.h>
+#include <linux/scatterlist.h>
 
 #define to_urb(d) container_of(d, struct urb, kref)
 
@@ -54,12 +55,12 @@ EXPORT_SYMBOL_GPL(usb_init_urb);
  * Creates an urb for the USB driver to use, initializes a few internal
  * structures, incrementes the usage counter, and returns a pointer to it.
  *
- * If no memory is available, NULL is returned.
- *
  * If the driver want to use this urb for interrupt, control, or bulk
  * endpoints, pass '0' as the number of iso packets.
  *
  * The driver must call usb_free_urb() when it is finished with the urb.
+ *
+ * Return: A pointer to the new urb, or %NULL if no memory is available.
  */
 struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
 {
@@ -102,7 +103,7 @@ EXPORT_SYMBOL_GPL(usb_free_urb);
  * host controller driver.  This allows proper reference counting to happen
  * for urbs.
  *
- * A pointer to the urb with the incremented reference counter is returned.
+ * Return: A pointer to the urb with the incremented reference counter.
  */
 struct urb *usb_get_urb(struct urb *urb)
 {
@@ -199,13 +200,12 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
  * the particular kind of transfer, although they will not initialize
  * any transfer flags.
  *
- * Successful submissions return 0; otherwise this routine returns a
- * negative error number.  If the submission is successful, the complete()
- * callback from the URB will be called exactly once, when the USB core and
- * Host Controller Driver (HCD) are finished with the URB.  When the completion
- * function is called, control of the URB is returned to the device
- * driver which issued the request.  The completion handler may then
- * immediately free or reuse that URB.
+ * If the submission is successful, the complete() callback from the URB
+ * will be called exactly once, when the USB core and Host Controller Driver
+ * (HCD) are finished with the URB.  When the completion function is called,
+ * control of the URB is returned to the device driver which issued the
+ * request.  The completion handler may then immediately free or reuse that
+ * URB.
  *
  * With few exceptions, USB device drivers should never access URB fields
  * provided by usbcore or the HCD until its complete() is called.
@@ -240,6 +240,9 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
  * that are standardized in the USB 2.0 specification.  For bulk
  * endpoints, a synchronous usb_bulk_msg() call is available.
  *
+ * Return:
+ * 0 on successful submissions. A negative error number otherwise.
+ *
  * Request Queuing:
  *
  * URBs may be submitted to endpoints before previous ones complete, to
@@ -413,6 +416,14 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                        urb->iso_frame_desc[n].status = -EXDEV;
                        urb->iso_frame_desc[n].actual_length = 0;
                }
+       } else if (urb->num_sgs && !urb->dev->bus->no_sg_constraint &&
+                       dev->speed != USB_SPEED_WIRELESS) {
+               struct scatterlist *sg;
+               int i;
+
+               for_each_sg(urb->sg, sg, urb->num_sgs - 1, i)
+                       if (sg->length % max)
+                               return -EINVAL;
        }
 
        /* the I/O buffer must be mapped/unmapped, except when length=0 */
@@ -564,6 +575,9 @@ EXPORT_SYMBOL_GPL(usb_submit_urb);
  * particular, when a driver calls this routine, it must insure that the
  * completion handler cannot deallocate the URB.
  *
+ * Return: -EINPROGRESS on success. See description for other values on
+ * failure.
+ *
  * Unlinking and Endpoint Queues:
  *
  * [The behaviors and guarantees described below do not apply to virtual
@@ -838,6 +852,8 @@ EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs);
  *
  * Call this is you want to be sure all an anchor's
  * URBs have finished
+ *
+ * Return: Non-zero if the anchor became unused. Zero on timeout.
  */
 int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
                                  unsigned int timeout)
@@ -851,8 +867,11 @@ EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout);
  * usb_get_from_anchor - get an anchor's oldest urb
  * @anchor: the anchor whose urb you want
  *
- * this will take the oldest urb from an anchor,
+ * This will take the oldest urb from an anchor,
  * unanchor and return it
+ *
+ * Return: The oldest urb from @anchor, or %NULL if @anchor has no
+ * urbs associated with it.
  */
 struct urb *usb_get_from_anchor(struct usb_anchor *anchor)
 {
@@ -901,7 +920,7 @@ EXPORT_SYMBOL_GPL(usb_scuttle_anchored_urbs);
  * usb_anchor_empty - is an anchor empty
  * @anchor: the anchor you want to query
  *
- * returns 1 if the anchor has no urbs associated with it
+ * Return: 1 if the anchor has no urbs associated with it.
  */
 int usb_anchor_empty(struct usb_anchor *anchor)
 {
index 7dad603dde4308f77ef69a049427664e06b4be07..0a6ee2e70b25afecaae6dfce65a03fe22e40ca04 100644 (file)
@@ -68,6 +68,8 @@ MODULE_PARM_DESC(autosuspend, "default autosuspend delay");
  * @alt_num: alternate interface setting number to search for.
  *
  * Search the configuration's interface cache for the given alt setting.
+ *
+ * Return: The alternate setting, if found. %NULL otherwise.
  */
 struct usb_host_interface *usb_find_alt_setting(
                struct usb_host_config *config,
@@ -103,8 +105,7 @@ EXPORT_SYMBOL_GPL(usb_find_alt_setting);
  * @ifnum: the desired interface
  *
  * This walks the device descriptor for the currently active configuration
- * and returns a pointer to the interface with that particular interface
- * number, or null.
+ * to find the interface object with the particular interface number.
  *
  * Note that configuration descriptors are not required to assign interface
  * numbers sequentially, so that it would be incorrect to assume that
@@ -115,6 +116,9 @@ EXPORT_SYMBOL_GPL(usb_find_alt_setting);
  *
  * Don't call this function unless you are bound to one of the interfaces
  * on this device or you have locked the device!
+ *
+ * Return: A pointer to the interface that has @ifnum as interface number,
+ * if found. %NULL otherwise.
  */
 struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
                                      unsigned ifnum)
@@ -139,8 +143,7 @@ EXPORT_SYMBOL_GPL(usb_ifnum_to_if);
  * @altnum: the desired alternate setting number
  *
  * This searches the altsetting array of the specified interface for
- * an entry with the correct bAlternateSetting value and returns a pointer
- * to that entry, or null.
+ * an entry with the correct bAlternateSetting value.
  *
  * Note that altsettings need not be stored sequentially by number, so
  * it would be incorrect to assume that the first altsetting entry in
@@ -149,6 +152,9 @@ EXPORT_SYMBOL_GPL(usb_ifnum_to_if);
  *
  * Don't call this function unless you are bound to the intf interface
  * or you have locked the device!
+ *
+ * Return: A pointer to the entry of the altsetting array of @intf that
+ * has @altnum as the alternate setting number. %NULL if not found.
  */
 struct usb_host_interface *usb_altnum_to_altsetting(
                                        const struct usb_interface *intf,
@@ -191,6 +197,8 @@ static int __find_interface(struct device *dev, void *data)
  * This walks the bus device list and returns a pointer to the interface
  * with the matching minor and driver.  Note, this only works for devices
  * that share the USB major number.
+ *
+ * Return: A pointer to the interface with the matching major and @minor.
  */
 struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
 {
@@ -390,6 +398,9 @@ static unsigned usb_bus_is_wusb(struct usb_bus *bus)
  * controllers) should ever call this.
  *
  * This call may not be used in a non-sleeping context.
+ *
+ * Return: On success, a pointer to the allocated usb device. %NULL on
+ * failure.
  */
 struct usb_device *usb_alloc_dev(struct usb_device *parent,
                                 struct usb_bus *bus, unsigned port1)
@@ -501,7 +512,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
  * their probe() methods, when they bind to an interface, and release
  * them by calling usb_put_dev(), in their disconnect() methods.
  *
- * A pointer to the device with the incremented reference counter is returned.
+ * Return: A pointer to the device with the incremented reference counter.
  */
 struct usb_device *usb_get_dev(struct usb_device *dev)
 {
@@ -535,8 +546,7 @@ EXPORT_SYMBOL_GPL(usb_put_dev);
  * their probe() methods, when they bind to an interface, and release
  * them by calling usb_put_intf(), in their disconnect() methods.
  *
- * A pointer to the interface with the incremented reference counter is
- * returned.
+ * Return: A pointer to the interface with the incremented reference counter.
  */
 struct usb_interface *usb_get_intf(struct usb_interface *intf)
 {
@@ -589,7 +599,7 @@ EXPORT_SYMBOL_GPL(usb_put_intf);
  * disconnect; in some drivers (such as usb-storage) the disconnect()
  * or suspend() method will block waiting for a device reset to complete.
  *
- * Returns a negative error code for failure, otherwise 0.
+ * Return: A negative error code for failure, otherwise 0.
  */
 int usb_lock_device_for_reset(struct usb_device *udev,
                              const struct usb_interface *iface)
@@ -628,14 +638,15 @@ EXPORT_SYMBOL_GPL(usb_lock_device_for_reset);
  * usb_get_current_frame_number - return current bus frame number
  * @dev: the device whose bus is being queried
  *
- * Returns the current frame number for the USB host controller
- * used with the given USB device.  This can be used when scheduling
+ * Return: The current frame number for the USB host controller used
+ * with the given USB device. This can be used when scheduling
  * isochronous requests.
  *
- * Note that different kinds of host controller have different
- * "scheduling horizons".  While one type might support scheduling only
- * 32 frames into the future, others could support scheduling up to
- * 1024 frames into the future.
+ * Note: Different kinds of host controller have different "scheduling
+ * horizons". While one type might support scheduling only 32 frames
+ * into the future, others could support scheduling up to 1024 frames
+ * into the future.
+ *
  */
 int usb_get_current_frame_number(struct usb_device *dev)
 {
@@ -685,11 +696,12 @@ EXPORT_SYMBOL_GPL(__usb_get_extra_descriptor);
  * @mem_flags: affect whether allocation may block
  * @dma: used to return DMA address of buffer
  *
- * Return value is either null (indicating no buffer could be allocated), or
- * the cpu-space pointer to a buffer that may be used to perform DMA to the
+ * Return: Either null (indicating no buffer could be allocated), or the
+ * cpu-space pointer to a buffer that may be used to perform DMA to the
  * specified device.  Such cpu-space buffers are returned along with the DMA
  * address (through the pointer provided).
  *
+ * Note:
  * These buffers are used with URB_NO_xxx_DMA_MAP set in urb->transfer_flags
  * to avoid behaviors like using "DMA bounce buffers", or thrashing IOMMU
  * hardware during URB completion/resubmit.  The implementation varies between
@@ -735,17 +747,18 @@ EXPORT_SYMBOL_GPL(usb_free_coherent);
  * usb_buffer_map - create DMA mapping(s) for an urb
  * @urb: urb whose transfer_buffer/setup_packet will be mapped
  *
- * Return value is either null (indicating no buffer could be mapped), or
- * the parameter.  URB_NO_TRANSFER_DMA_MAP is
- * added to urb->transfer_flags if the operation succeeds.  If the device
- * is connected to this system through a non-DMA controller, this operation
- * always succeeds.
+ * URB_NO_TRANSFER_DMA_MAP is added to urb->transfer_flags if the operation
+ * succeeds. If the device is connected to this system through a non-DMA
+ * controller, this operation always succeeds.
  *
  * This call would normally be used for an urb which is reused, perhaps
  * as the target of a large periodic transfer, with usb_buffer_dmasync()
  * calls to synchronize memory and dma state.
  *
  * Reverse the effect of this call with usb_buffer_unmap().
+ *
+ * Return: Either %NULL (indicating no buffer could be mapped), or @urb.
+ *
  */
 #if 0
 struct urb *usb_buffer_map(struct urb *urb)
@@ -850,9 +863,10 @@ EXPORT_SYMBOL_GPL(usb_buffer_unmap);
  * @sg: the scatterlist to map
  * @nents: the number of entries in the scatterlist
  *
- * Return value is either < 0 (indicating no buffers could be mapped), or
- * the number of DMA mapping array entries in the scatterlist.
+ * Return: Either < 0 (indicating no buffers could be mapped), or the
+ * number of DMA mapping array entries in the scatterlist.
  *
+ * Note:
  * The caller is responsible for placing the resulting DMA addresses from
  * the scatterlist into URB transfer buffer pointers, and for setting the
  * URB_NO_TRANSFER_DMA_MAP transfer flag in each of those URBs.
index 2378958ea63e01426edbda87183674256a4334ff..3e225d5846f68a6a14e96964acf96e68d6e9511c 100644 (file)
@@ -40,6 +40,38 @@ config USB_DWC3_DUAL_ROLE
 
 endchoice
 
+comment "Platform Glue Driver Support"
+
+config USB_DWC3_OMAP
+       tristate "Texas Instruments OMAP5 and similar Platforms"
+       depends on EXTCON
+       default USB_DWC3
+       help
+         Some platforms from Texas Instruments like OMAP5, DRA7xxx and
+         AM437x use this IP for USB2/3 functionality.
+
+         Say 'Y' or 'M' here if you have one such device
+
+config USB_DWC3_EXYNOS
+       tristate "Samsung Exynos Platform"
+       default USB_DWC3
+       help
+         Recent Exynos5 SoCs ship with one DesignWare Core USB3 IP inside,
+         say 'Y' or 'M' if you have one such device.
+
+config USB_DWC3_PCI
+       tristate "PCIe-based Platforms"
+       depends on PCI
+       default USB_DWC3
+       help
+         If you're using the DesignWare Core IP with a PCIe, please say
+         'Y' or 'M' here.
+
+         One such PCIe-based platform is Synopsys' PCIe HAPS model of
+         this IP.
+
+comment "Debugging features"
+
 config USB_DWC3_DEBUG
        bool "Enable Debugging Messages"
        help
index 0c7ac92582be4807dc93861174427be30b8fef36..dd1760145c469f3f5e578319060d3ce498b5e06e 100644 (file)
@@ -27,15 +27,8 @@ endif
 # the entire driver (with all its glue layers) on several architectures
 # and make sure it compiles fine. This will also help with allmodconfig
 # and allyesconfig builds.
-#
-# The only exception is the PCI glue layer, but that's only because
-# PCI doesn't provide nops if CONFIG_PCI isn't enabled.
 ##
 
-obj-$(CONFIG_USB_DWC3)         += dwc3-omap.o
-obj-$(CONFIG_USB_DWC3)         += dwc3-exynos.o
-
-ifneq ($(CONFIG_PCI),)
-       obj-$(CONFIG_USB_DWC3)          += dwc3-pci.o
-endif
-
+obj-$(CONFIG_USB_DWC3_OMAP)            += dwc3-omap.o
+obj-$(CONFIG_USB_DWC3_EXYNOS)          += dwc3-exynos.o
+obj-$(CONFIG_USB_DWC3_PCI)             += dwc3-pci.o
index 358375e0b291098d8be40d65bdfbbff7f97f0826..577af1b237f2c3b279384e2323e9ae80e97234db 100644 (file)
@@ -6,34 +6,17 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <linux/module.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/of.h>
+#include <linux/usb/otg.h>
 
+#include "platform_data.h"
 #include "core.h"
 #include "gadget.h"
 #include "io.h"
 
 #include "debug.h"
 
-static char *maximum_speed = "super";
-module_param(maximum_speed, charp, 0);
-MODULE_PARM_DESC(maximum_speed, "Maximum supported speed.");
-
 /* -------------------------------------------------------------------------- */
 
 void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
@@ -236,7 +218,7 @@ static int dwc3_event_buffers_setup(struct dwc3 *dwc)
                dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
                                upper_32_bits(evt->dma));
                dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
-                               evt->length & 0xffff);
+                               DWC3_GEVNTSIZ_SIZE(evt->length));
                dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
        }
 
@@ -255,7 +237,8 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
 
                dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(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), DWC3_GEVNTSIZ_INTMASK
+                               | DWC3_GEVNTSIZ_SIZE(0));
                dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
        }
 }
@@ -367,18 +350,17 @@ static void dwc3_core_exit(struct dwc3 *dwc)
 
 static int dwc3_probe(struct platform_device *pdev)
 {
-       struct device_node      *node = pdev->dev.of_node;
+       struct device           *dev = &pdev->dev;
+       struct dwc3_platform_data *pdata = dev_get_platdata(dev);
+       struct device_node      *node = dev->of_node;
        struct resource         *res;
        struct dwc3             *dwc;
-       struct device           *dev = &pdev->dev;
 
        int                     ret = -ENOMEM;
 
        void __iomem            *regs;
        void                    *mem;
 
-       u8                      mode;
-
        mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
        if (!mem) {
                dev_err(dev, "not enough memory\n");
@@ -402,38 +384,32 @@ static int dwc3_probe(struct platform_device *pdev)
                dev_err(dev, "missing memory resource\n");
                return -ENODEV;
        }
-       dwc->xhci_resources[0].start = res->start;
-       dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
-                                       DWC3_XHCI_REGS_END;
-       dwc->xhci_resources[0].flags = res->flags;
-       dwc->xhci_resources[0].name = res->name;
-
-        /*
-         * Request memory region but exclude xHCI regs,
-         * since it will be requested by the xhci-plat driver.
-         */
-       res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START,
-                       resource_size(res) - DWC3_GLOBALS_REGS_START,
-                       dev_name(dev));
-       if (!res) {
-               dev_err(dev, "can't request mem region\n");
-               return -ENOMEM;
-       }
-
-       regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
-       if (!regs) {
-               dev_err(dev, "ioremap failed\n");
-               return -ENOMEM;
-       }
 
        if (node) {
+               dwc->maximum_speed = of_usb_get_maximum_speed(node);
+
                dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
                dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
+
+               dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
+               dwc->dr_mode = of_usb_get_dr_mode(node);
+       } else if (pdata) {
+               dwc->maximum_speed = pdata->maximum_speed;
+
+               dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+               dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
+
+               dwc->needs_fifo_resize = pdata->tx_fifo_resize;
+               dwc->dr_mode = pdata->dr_mode;
        } else {
                dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
                dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
        }
 
+       /* default to superspeed if no maximum_speed passed */
+       if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
+               dwc->maximum_speed = USB_SPEED_SUPER;
+
        if (IS_ERR(dwc->usb2_phy)) {
                ret = PTR_ERR(dwc->usb2_phy);
 
@@ -464,6 +440,22 @@ static int dwc3_probe(struct platform_device *pdev)
                return -EPROBE_DEFER;
        }
 
+       dwc->xhci_resources[0].start = res->start;
+       dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
+                                       DWC3_XHCI_REGS_END;
+       dwc->xhci_resources[0].flags = res->flags;
+       dwc->xhci_resources[0].name = res->name;
+
+       res->start += DWC3_GLOBALS_REGS_START;
+
+       /*
+        * Request memory region but exclude xHCI regs,
+        * since it will be requested by the xhci-plat driver.
+        */
+       regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
        usb_phy_set_suspend(dwc->usb2_phy, 0);
        usb_phy_set_suspend(dwc->usb3_phy, 0);
 
@@ -478,19 +470,6 @@ static int dwc3_probe(struct platform_device *pdev)
        dev->dma_parms  = dev->parent->dma_parms;
        dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
 
-       if (!strncmp("super", maximum_speed, 5))
-               dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
-       else if (!strncmp("high", maximum_speed, 4))
-               dwc->maximum_speed = DWC3_DCFG_HIGHSPEED;
-       else if (!strncmp("full", maximum_speed, 4))
-               dwc->maximum_speed = DWC3_DCFG_FULLSPEED1;
-       else if (!strncmp("low", maximum_speed, 3))
-               dwc->maximum_speed = DWC3_DCFG_LOWSPEED;
-       else
-               dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
-
-       dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
-
        pm_runtime_enable(dev);
        pm_runtime_get_sync(dev);
        pm_runtime_forbid(dev);
@@ -517,14 +496,15 @@ static int dwc3_probe(struct platform_device *pdev)
        }
 
        if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
-               mode = DWC3_MODE_HOST;
+               dwc->dr_mode = USB_DR_MODE_HOST;
        else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
-               mode = DWC3_MODE_DEVICE;
-       else
-               mode = DWC3_MODE_DRD;
+               dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
+
+       if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
+               dwc->dr_mode = USB_DR_MODE_OTG;
 
-       switch (mode) {
-       case DWC3_MODE_DEVICE:
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
                dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
                ret = dwc3_gadget_init(dwc);
                if (ret) {
@@ -532,7 +512,7 @@ static int dwc3_probe(struct platform_device *pdev)
                        goto err2;
                }
                break;
-       case DWC3_MODE_HOST:
+       case USB_DR_MODE_HOST:
                dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
                ret = dwc3_host_init(dwc);
                if (ret) {
@@ -540,7 +520,7 @@ static int dwc3_probe(struct platform_device *pdev)
                        goto err2;
                }
                break;
-       case DWC3_MODE_DRD:
+       case USB_DR_MODE_OTG:
                dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
                ret = dwc3_host_init(dwc);
                if (ret) {
@@ -555,10 +535,9 @@ static int dwc3_probe(struct platform_device *pdev)
                }
                break;
        default:
-               dev_err(dev, "Unsupported mode of operation %d\n", mode);
+               dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
                goto err2;
        }
-       dwc->mode = mode;
 
        ret = dwc3_debugfs_init(dwc);
        if (ret) {
@@ -571,14 +550,14 @@ static int dwc3_probe(struct platform_device *pdev)
        return 0;
 
 err3:
-       switch (mode) {
-       case DWC3_MODE_DEVICE:
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
                dwc3_gadget_exit(dwc);
                break;
-       case DWC3_MODE_HOST:
+       case USB_DR_MODE_HOST:
                dwc3_host_exit(dwc);
                break;
-       case DWC3_MODE_DRD:
+       case USB_DR_MODE_OTG:
                dwc3_host_exit(dwc);
                dwc3_gadget_exit(dwc);
                break;
@@ -611,14 +590,14 @@ static int dwc3_remove(struct platform_device *pdev)
 
        dwc3_debugfs_exit(dwc);
 
-       switch (dwc->mode) {
-       case DWC3_MODE_DEVICE:
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
                dwc3_gadget_exit(dwc);
                break;
-       case DWC3_MODE_HOST:
+       case USB_DR_MODE_HOST:
                dwc3_host_exit(dwc);
                break;
-       case DWC3_MODE_DRD:
+       case USB_DR_MODE_OTG:
                dwc3_host_exit(dwc);
                dwc3_gadget_exit(dwc);
                break;
@@ -642,12 +621,12 @@ static int dwc3_prepare(struct device *dev)
 
        spin_lock_irqsave(&dwc->lock, flags);
 
-       switch (dwc->mode) {
-       case DWC3_MODE_DEVICE:
-       case DWC3_MODE_DRD:
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
+       case USB_DR_MODE_OTG:
                dwc3_gadget_prepare(dwc);
                /* FALLTHROUGH */
-       case DWC3_MODE_HOST:
+       case USB_DR_MODE_HOST:
        default:
                dwc3_event_buffers_cleanup(dwc);
                break;
@@ -665,12 +644,12 @@ static void dwc3_complete(struct device *dev)
 
        spin_lock_irqsave(&dwc->lock, flags);
 
-       switch (dwc->mode) {
-       case DWC3_MODE_DEVICE:
-       case DWC3_MODE_DRD:
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
+       case USB_DR_MODE_OTG:
                dwc3_gadget_complete(dwc);
                /* FALLTHROUGH */
-       case DWC3_MODE_HOST:
+       case USB_DR_MODE_HOST:
        default:
                dwc3_event_buffers_setup(dwc);
                break;
@@ -686,12 +665,12 @@ static int dwc3_suspend(struct device *dev)
 
        spin_lock_irqsave(&dwc->lock, flags);
 
-       switch (dwc->mode) {
-       case DWC3_MODE_DEVICE:
-       case DWC3_MODE_DRD:
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
+       case USB_DR_MODE_OTG:
                dwc3_gadget_suspend(dwc);
                /* FALLTHROUGH */
-       case DWC3_MODE_HOST:
+       case USB_DR_MODE_HOST:
        default:
                /* do nothing */
                break;
@@ -719,12 +698,12 @@ static int dwc3_resume(struct device *dev)
 
        dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
 
-       switch (dwc->mode) {
-       case DWC3_MODE_DEVICE:
-       case DWC3_MODE_DRD:
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
+       case USB_DR_MODE_OTG:
                dwc3_gadget_resume(dwc);
                /* FALLTHROUGH */
-       case DWC3_MODE_HOST:
+       case USB_DR_MODE_HOST:
        default:
                /* do nothing */
                break;
@@ -753,6 +732,9 @@ static const struct dev_pm_ops dwc3_dev_pm_ops = {
 
 #ifdef CONFIG_OF
 static const struct of_device_id of_dwc3_match[] = {
+       {
+               .compatible = "snps,dwc3"
+       },
        {
                .compatible = "synopsys,dwc3"
        },
@@ -775,5 +757,5 @@ module_platform_driver(dwc3_driver);
 
 MODULE_ALIAS("platform:dwc3");
 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
-MODULE_LICENSE("Dual BSD/GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
index 27dad993b00706ef5a14a257c40bd353ca6ee560..f8af8d44af850075b60a64e1eac29e54bef7fc5a 100644 (file)
@@ -6,34 +6,14 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 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.
  */
 
 #ifndef __DRIVERS_USB_DWC3_CORE_H
@@ -49,6 +29,7 @@
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
 
 /* Global constants */
 #define DWC3_EP0_BOUNCE_SIZE   512
 #define DWC3_GTXFIFOSIZ_TXFDEF(n)      ((n) & 0xffff)
 #define DWC3_GTXFIFOSIZ_TXFSTADDR(n)   ((n) & 0xffff0000)
 
+/* Global Event Size Registers */
+#define DWC3_GEVNTSIZ_INTMASK          (1 << 31)
+#define DWC3_GEVNTSIZ_SIZE(n)          ((n) & 0xffff)
+
 /* Global HWPARAMS1 Register */
 #define DWC3_GHWPARAMS1_EN_PWROPT(n)   (((n) & (3 << 24)) >> 24)
 #define DWC3_GHWPARAMS1_EN_PWROPT_NO   0
 #define DWC3_MAX_HIBER_SCRATCHBUFS             15
 
 /* Device Configuration Register */
-#define DWC3_DCFG_LPM_CAP      (1 << 22)
 #define DWC3_DCFG_DEVADDR(addr)        ((addr) << 3)
 #define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
 
@@ -367,7 +351,6 @@ struct dwc3_trb;
 
 /**
  * struct dwc3_event_buffer - Software event buffer representation
- * @list: a list of event buffers
  * @buf: _THE_ buffer
  * @length: size of this buffer
  * @lpos: event offset
@@ -415,7 +398,7 @@ struct dwc3_event_buffer {
  * @number: endpoint number (1 - 15)
  * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
  * @resource_index: Resource transfer index
- * @interval: the intervall on which the ISOC transfer is started
+ * @interval: the interval on which the ISOC transfer is started
  * @name: a human readable name e.g. ep1out-bulk
  * @direction: true for TX, false for RX
  * @stream_capable: true when streams are enabled
@@ -566,11 +549,6 @@ struct dwc3_hwparams {
 /* HWPARAMS0 */
 #define DWC3_MODE(n)           ((n) & 0x7)
 
-#define DWC3_MODE_DEVICE       0
-#define DWC3_MODE_HOST         1
-#define DWC3_MODE_DRD          2
-#define DWC3_MODE_HUB          3
-
 #define DWC3_MDWIDTH(n)                (((n) & 0xff00) >> 8)
 
 /* HWPARAMS1 */
@@ -632,7 +610,7 @@ struct dwc3_scratchpad_array {
  * @u1u2: only used on revisions <1.83a for workaround
  * @maximum_speed: maximum speed requested (mainly for testing purposes)
  * @revision: revision register contents
- * @mode: mode of operation
+ * @dr_mode: requested mode of operation
  * @usb2_phy: pointer to USB2 PHY
  * @usb3_phy: pointer to USB3 PHY
  * @dcfg: saved contents of DCFG register
@@ -690,6 +668,8 @@ struct dwc3 {
        void __iomem            *regs;
        size_t                  regs_size;
 
+       enum usb_dr_mode        dr_mode;
+
        /* used for suspend/resume */
        u32                     dcfg;
        u32                     gctl;
@@ -698,7 +678,6 @@ struct dwc3 {
        u32                     u1u2;
        u32                     maximum_speed;
        u32                     revision;
-       u32                     mode;
 
 #define DWC3_REVISION_173A     0x5533173a
 #define DWC3_REVISION_175A     0x5533175a
index 5894ee8222afca0e77de66f863b3684cff41af41..fceb39dc4bba331a89e78f8d1298d566fb3d4b18 100644 (file)
@@ -6,34 +6,14 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  */
 
 #include "core.h"
index 9e9f122162f2987919d18478be2cef3370e1c186..9ac37fe1b6a77956d530642db517e57eb3481fe8 100644 (file)
@@ -6,34 +6,14 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  */
 
 #include <linux/kernel.h>
index 8ce9d7fd6cfc30051462373d3c8d1f2b681dfcb3..2f2e88a3a11a3c9a9adbcca6b104b54fa2f4352b 100644 (file)
@@ -6,10 +6,14 @@
  *
  * Author: Anton Tikhomirov <av.tikhomirov@samsung.com>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  */
 
 #include <linux/module.h>
@@ -20,7 +24,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/clk.h>
 #include <linux/usb/otg.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
 
@@ -34,13 +38,13 @@ struct dwc3_exynos {
 
 static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
 {
-       struct nop_usb_xceiv_platform_data pdata;
+       struct usb_phy_gen_xceiv_platform_data pdata;
        struct platform_device  *pdev;
        int                     ret;
 
        memset(&pdata, 0x00, sizeof(pdata));
 
-       pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
+       pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO);
        if (!pdev)
                return -ENOMEM;
 
@@ -51,7 +55,7 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
        if (ret)
                goto err1;
 
-       pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
+       pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO);
        if (!pdev) {
                ret = -ENOMEM;
                goto err1;
@@ -228,5 +232,5 @@ module_platform_driver(dwc3_exynos_driver);
 
 MODULE_ALIAS("platform:exynos-dwc3");
 MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer");
index 077f110bd746073931e75fc6c9321cd0b1003aff..ecd99451ee90d3faf53b6e2c04e7514243b65627 100644 (file)
@@ -6,34 +6,14 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  */
 
 #include <linux/module.h>
@@ -409,11 +389,9 @@ static int dwc3_omap_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       base = devm_ioremap_nocache(dev, res->start, resource_size(res));
-       if (!base) {
-               dev_err(dev, "ioremap failed\n");
-               return -ENOMEM;
-       }
+       base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
 
        spin_lock_init(&omap->lock);
 
@@ -610,5 +588,5 @@ module_platform_driver(dwc3_omap_driver);
 
 MODULE_ALIAS("platform:omap-dwc3");
 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
-MODULE_LICENSE("Dual BSD/GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer");
index ed07ec04a9622526b94666acc4f7390bcac56e25..9b138129e856aa22b27c4a83398adf55c8949247 100644 (file)
@@ -6,34 +6,14 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  */
 
 #include <linux/kernel.h>
@@ -43,7 +23,7 @@
 #include <linux/platform_device.h>
 
 #include <linux/usb/otg.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 
 /* FIXME define these in <linux/pci_ids.h> */
 #define PCI_VENDOR_ID_SYNOPSYS         0x16c3
@@ -58,13 +38,13 @@ struct dwc3_pci {
 
 static int dwc3_pci_register_phys(struct dwc3_pci *glue)
 {
-       struct nop_usb_xceiv_platform_data pdata;
+       struct usb_phy_gen_xceiv_platform_data pdata;
        struct platform_device  *pdev;
        int                     ret;
 
        memset(&pdata, 0x00, sizeof(pdata));
 
-       pdev = platform_device_alloc("nop_usb_xceiv", 0);
+       pdev = platform_device_alloc("usb_phy_gen_xceiv", 0);
        if (!pdev)
                return -ENOMEM;
 
@@ -75,7 +55,7 @@ static int dwc3_pci_register_phys(struct dwc3_pci *glue)
        if (ret)
                goto err1;
 
-       pdev = platform_device_alloc("nop_usb_xceiv", 1);
+       pdev = platform_device_alloc("usb_phy_gen_xceiv", 1);
        if (!pdev) {
                ret = -ENOMEM;
                goto err1;
@@ -211,7 +191,7 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
 };
 MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int dwc3_pci_suspend(struct device *dev)
 {
        struct pci_dev  *pci = to_pci_dev(dev);
@@ -236,28 +216,24 @@ static int dwc3_pci_resume(struct device *dev)
 
        return 0;
 }
+#endif /* CONFIG_PM_SLEEP */
 
 static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
 };
 
-#define DEV_PM_OPS     (&dwc3_pci_dev_pm_ops)
-#else
-#define DEV_PM_OPS     NULL
-#endif /* CONFIG_PM */
-
 static struct pci_driver dwc3_pci_driver = {
        .name           = "dwc3-pci",
        .id_table       = dwc3_pci_id_table,
        .probe          = dwc3_pci_probe,
        .remove         = dwc3_pci_remove,
        .driver         = {
-               .pm     = DEV_PM_OPS,
+               .pm     = &dwc3_pci_dev_pm_ops,
        },
 };
 
 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
-MODULE_LICENSE("Dual BSD/GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
 
 module_pci_driver(dwc3_pci_driver);
index 5acbb948b7048ffb22c6e921e93f6617bec1cbe7..7fa93f4bc507de41782486301760506e18f44a03 100644 (file)
@@ -6,34 +6,14 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  */
 
 #include <linux/kernel.h>
@@ -168,6 +148,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
 
                direction = !dwc->ep0_expect_in;
                dwc->delayed_status = false;
+               usb_gadget_set_state(&dwc->gadget, USB_STATE_CONFIGURED);
 
                if (dwc->ep0state == EP0_STATUS_PHASE)
                        __dwc3_ep0_do_control_status(dwc, dwc->eps[direction]);
@@ -553,8 +534,16 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
                ret = dwc3_ep0_delegate_req(dwc, ctrl);
                /* if the cfg matches and the cfg is non zero */
                if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
-                       usb_gadget_set_state(&dwc->gadget,
-                                       USB_STATE_CONFIGURED);
+
+                       /*
+                        * only change state if set_config has already
+                        * been processed. If gadget driver returns
+                        * USB_GADGET_DELAYED_STATUS, we will wait
+                        * to change the state on the next usb_ep_queue()
+                        */
+                       if (ret == 0)
+                               usb_gadget_set_state(&dwc->gadget,
+                                               USB_STATE_CONFIGURED);
 
                        /*
                         * Enable transition to U1/U2 state when
@@ -571,7 +560,7 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 
        case USB_STATE_CONFIGURED:
                ret = dwc3_ep0_delegate_req(dwc, ctrl);
-               if (!cfg)
+               if (!cfg && !ret)
                        usb_gadget_set_state(&dwc->gadget,
                                        USB_STATE_ADDRESS);
                break;
index f77083fedc68d0d1bfc7afb579e6aae96edb1d63..f168eaebdef8fc6731de7c6994c658737495fdce 100644 (file)
@@ -6,34 +6,14 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  */
 
 #include <linux/kernel.h>
@@ -520,6 +500,8 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
        u32                     reg;
        int                     ret = -ENOMEM;
 
+       dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
+
        if (!(dep->flags & DWC3_EP_ENABLED)) {
                ret = dwc3_gadget_start_config(dwc, dep);
                if (ret)
@@ -676,8 +658,6 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
                dev_err(dwc->dev, "invalid endpoint transfer type\n");
        }
 
-       dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
-
        spin_lock_irqsave(&dwc->lock, flags);
        ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false);
        spin_unlock_irqrestore(&dwc->lock, flags);
@@ -1508,6 +1488,15 @@ static int dwc3_gadget_start(struct usb_gadget *g,
        int                     irq;
        u32                     reg;
 
+       irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+       ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
+                       IRQF_SHARED, "dwc3", dwc);
+       if (ret) {
+               dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+                               irq, ret);
+               goto err0;
+       }
+
        spin_lock_irqsave(&dwc->lock, flags);
 
        if (dwc->gadget_driver) {
@@ -1515,7 +1504,7 @@ static int dwc3_gadget_start(struct usb_gadget *g,
                                dwc->gadget.name,
                                dwc->gadget_driver->driver.name);
                ret = -EBUSY;
-               goto err0;
+               goto err1;
        }
 
        dwc->gadget_driver      = driver;
@@ -1536,10 +1525,25 @@ static int dwc3_gadget_start(struct usb_gadget *g,
         * STAR#9000525659: Clock Domain Crossing on DCTL in
         * USB 2.0 Mode
         */
-       if (dwc->revision < DWC3_REVISION_220A)
+       if (dwc->revision < DWC3_REVISION_220A) {
                reg |= DWC3_DCFG_SUPERSPEED;
-       else
-               reg |= dwc->maximum_speed;
+       } else {
+               switch (dwc->maximum_speed) {
+               case USB_SPEED_LOW:
+                       reg |= DWC3_DSTS_LOWSPEED;
+                       break;
+               case USB_SPEED_FULL:
+                       reg |= DWC3_DSTS_FULLSPEED1;
+                       break;
+               case USB_SPEED_HIGH:
+                       reg |= DWC3_DSTS_HIGHSPEED;
+                       break;
+               case USB_SPEED_SUPER:   /* FALLTHROUGH */
+               case USB_SPEED_UNKNOWN: /* FALTHROUGH */
+               default:
+                       reg |= DWC3_DSTS_SUPERSPEED;
+               }
+       }
        dwc3_writel(dwc->regs, DWC3_DCFG, reg);
 
        dwc->start_config_issued = false;
@@ -1551,42 +1555,38 @@ static int dwc3_gadget_start(struct usb_gadget *g,
        ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
        if (ret) {
                dev_err(dwc->dev, "failed to enable %s\n", dep->name);
-               goto err0;
+               goto err2;
        }
 
        dep = dwc->eps[1];
        ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
        if (ret) {
                dev_err(dwc->dev, "failed to enable %s\n", dep->name);
-               goto err1;
+               goto err3;
        }
 
        /* begin to receive SETUP packets */
        dwc->ep0state = EP0_SETUP_PHASE;
        dwc3_ep0_out_start(dwc);
 
-       irq = platform_get_irq(to_platform_device(dwc->dev), 0);
-       ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
-                       IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc);
-       if (ret) {
-               dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
-                               irq, ret);
-               goto err1;
-       }
-
        dwc3_gadget_enable_irq(dwc);
 
        spin_unlock_irqrestore(&dwc->lock, flags);
 
        return 0;
 
-err1:
+err3:
        __dwc3_gadget_ep_disable(dwc->eps[0]);
 
-err0:
+err2:
        dwc->gadget_driver = NULL;
+
+err1:
        spin_unlock_irqrestore(&dwc->lock, flags);
 
+       free_irq(irq, dwc);
+
+err0:
        return ret;
 }
 
@@ -1600,9 +1600,6 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
        spin_lock_irqsave(&dwc->lock, flags);
 
        dwc3_gadget_disable_irq(dwc);
-       irq = platform_get_irq(to_platform_device(dwc->dev), 0);
-       free_irq(irq, dwc);
-
        __dwc3_gadget_ep_disable(dwc->eps[0]);
        __dwc3_gadget_ep_disable(dwc->eps[1]);
 
@@ -1610,6 +1607,9 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
 
        spin_unlock_irqrestore(&dwc->lock, flags);
 
+       irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+       free_irq(irq, dwc);
+
        return 0;
 }
 
@@ -1642,13 +1642,15 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
 
                dep->dwc = dwc;
                dep->number = epnum;
+               dep->direction = !!direction;
                dwc->eps[epnum] = dep;
 
                snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
                                (epnum & 1) ? "in" : "out");
 
                dep->endpoint.name = dep->name;
-               dep->direction = (epnum & 1);
+
+               dev_vdbg(dwc->dev, "initializing %s\n", dep->name);
 
                if (epnum == 0 || epnum == 1) {
                        dep->endpoint.maxpacket = 512;
@@ -2105,34 +2107,6 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
        dwc->setup_packet_pending = false;
 }
 
-static void dwc3_gadget_usb3_phy_suspend(struct dwc3 *dwc, int suspend)
-{
-       u32                     reg;
-
-       reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
-
-       if (suspend)
-               reg |= DWC3_GUSB3PIPECTL_SUSPHY;
-       else
-               reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
-
-       dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
-}
-
-static void dwc3_gadget_usb2_phy_suspend(struct dwc3 *dwc, int suspend)
-{
-       u32                     reg;
-
-       reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
-
-       if (suspend)
-               reg |= DWC3_GUSB2PHYCFG_SUSPHY;
-       else
-               reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
-
-       dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
-}
-
 static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
 {
        u32                     reg;
@@ -2173,13 +2147,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
        /* after reset -> Default State */
        usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT);
 
-       /* 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)
                dwc3_disconnect_gadget(dwc);
 
@@ -2223,20 +2190,6 @@ static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed)
        dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 }
 
-static void dwc3_gadget_phy_suspend(struct dwc3 *dwc, u8 speed)
-{
-       switch (speed) {
-       case USB_SPEED_SUPER:
-               dwc3_gadget_usb2_phy_suspend(dwc, true);
-               break;
-       case USB_SPEED_HIGH:
-       case USB_SPEED_FULL:
-       case USB_SPEED_LOW:
-               dwc3_gadget_usb3_phy_suspend(dwc, true);
-               break;
-       }
-}
-
 static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
 {
        struct dwc3_ep          *dep;
@@ -2312,12 +2265,6 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
                dwc3_writel(dwc->regs, DWC3_DCTL, reg);
        }
 
-       /* 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];
        ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true);
        if (ret) {
@@ -2495,61 +2442,75 @@ static void dwc3_process_event_entry(struct dwc3 *dwc,
        }
 }
 
-static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
+static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
 {
-       struct dwc3 *dwc = _dwc;
-       unsigned long flags;
+       struct dwc3_event_buffer *evt;
        irqreturn_t ret = IRQ_NONE;
-       int i;
+       int left;
+       u32 reg;
 
-       spin_lock_irqsave(&dwc->lock, flags);
+       evt = dwc->ev_buffs[buf];
+       left = evt->count;
 
-       for (i = 0; i < dwc->num_event_buffers; i++) {
-               struct dwc3_event_buffer *evt;
-               int                     left;
+       if (!(evt->flags & DWC3_EVENT_PENDING))
+               return IRQ_NONE;
 
-               evt = dwc->ev_buffs[i];
-               left = evt->count;
+       while (left > 0) {
+               union dwc3_event event;
 
-               if (!(evt->flags & DWC3_EVENT_PENDING))
-                       continue;
+               event.raw = *(u32 *) (evt->buf + evt->lpos);
 
-               while (left > 0) {
-                       union dwc3_event event;
+               dwc3_process_event_entry(dwc, &event);
 
-                       event.raw = *(u32 *) (evt->buf + evt->lpos);
+               /*
+                * FIXME we wrap around correctly to the next entry as
+                * almost all entries are 4 bytes in size. There is one
+                * entry which has 12 bytes which is a regular entry
+                * followed by 8 bytes data. ATM I don't know how
+                * things are organized if we get next to the a
+                * boundary so I worry about that once we try to handle
+                * that.
+                */
+               evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
+               left -= 4;
 
-                       dwc3_process_event_entry(dwc, &event);
+               dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
+       }
 
-                       /*
-                        * FIXME we wrap around correctly to the next entry as
-                        * almost all entries are 4 bytes in size. There is one
-                        * entry which has 12 bytes which is a regular entry
-                        * followed by 8 bytes data. ATM I don't know how
-                        * things are organized if we get next to the a
-                        * boundary so I worry about that once we try to handle
-                        * that.
-                        */
-                       evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
-                       left -= 4;
+       evt->count = 0;
+       evt->flags &= ~DWC3_EVENT_PENDING;
+       ret = IRQ_HANDLED;
 
-                       dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(i), 4);
-               }
+       /* Unmask interrupt */
+       reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf));
+       reg &= ~DWC3_GEVNTSIZ_INTMASK;
+       dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
 
-               evt->count = 0;
-               evt->flags &= ~DWC3_EVENT_PENDING;
-               ret = IRQ_HANDLED;
-       }
+       return ret;
+}
+
+static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
+{
+       struct dwc3 *dwc = _dwc;
+       unsigned long flags;
+       irqreturn_t ret = IRQ_NONE;
+       int i;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+
+       for (i = 0; i < dwc->num_event_buffers; i++)
+               ret |= dwc3_process_event_buf(dwc, i);
 
        spin_unlock_irqrestore(&dwc->lock, flags);
 
        return ret;
 }
 
-static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
+static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf)
 {
        struct dwc3_event_buffer *evt;
        u32 count;
+       u32 reg;
 
        evt = dwc->ev_buffs[buf];
 
@@ -2561,6 +2522,11 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
        evt->count = count;
        evt->flags |= DWC3_EVENT_PENDING;
 
+       /* Mask interrupt */
+       reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf));
+       reg |= DWC3_GEVNTSIZ_INTMASK;
+       dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
+
        return IRQ_WAKE_THREAD;
 }
 
@@ -2575,7 +2541,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
        for (i = 0; i < dwc->num_event_buffers; i++) {
                irqreturn_t status;
 
-               status = dwc3_process_event_buf(dwc, i);
+               status = dwc3_check_event_buf(dwc, i);
                if (status == IRQ_WAKE_THREAD)
                        ret = status;
        }
@@ -2593,7 +2559,6 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
  */
 int dwc3_gadget_init(struct dwc3 *dwc)
 {
-       u32                                     reg;
        int                                     ret;
 
        dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
@@ -2643,16 +2608,6 @@ int dwc3_gadget_init(struct dwc3 *dwc)
        if (ret)
                goto err4;
 
-       reg = dwc3_readl(dwc->regs, DWC3_DCFG);
-       reg |= DWC3_DCFG_LPM_CAP;
-       dwc3_writel(dwc->regs, DWC3_DCFG, reg);
-
-       /* Enable USB2 LPM and automatic phy suspend only on recent versions */
-       if (dwc->revision >= DWC3_REVISION_194A) {
-               dwc3_gadget_usb2_phy_suspend(dwc, false);
-               dwc3_gadget_usb3_phy_suspend(dwc, false);
-       }
-
        ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
        if (ret) {
                dev_err(dwc->dev, "failed to register udc\n");
index 99e6d7248820c790aa968c086ac6ef1f70e91c03..febe1aa7b71424790c96d92852eb8ea4d4d51453 100644 (file)
@@ -6,34 +6,14 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 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.
  */
 
 #ifndef __DRIVERS_USB_DWC3_GADGET_H
index 0fa1846eda4cfb388e44b927a3dab249554d56a1..32db328cc769f54c5a5649715461d978af92089c 100644 (file)
@@ -5,34 +5,14 @@
  *
  * Authors: Felipe Balbi <balbi@ti.com>,
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  */
 
 #include <linux/platform_device.h>
index a50f76b9d19b5107c2f93f1192b6408504b112a4..d94441c14d8cb7ebedff18c986aa0710ffd6d31a 100644 (file)
@@ -6,34 +6,14 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 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.
  */
 
 #ifndef __DRIVERS_USB_DWC3_IO_H
diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h
new file mode 100644 (file)
index 0000000..7db34f0
--- /dev/null
@@ -0,0 +1,27 @@
+/**
+ * platform_data.h - USB DWC3 Platform Data Support
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Felipe Balbi <balbi@ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/otg.h>
+
+struct dwc3_platform_data {
+       enum usb_device_speed maximum_speed;
+       enum usb_dr_mode dr_mode;
+       bool tx_fifo_resize;
+};
index 8e9368330b103a60cc7fb53be21991315c489fd8..1e3f52574367465cff95255a95613c8109b63460 100644 (file)
@@ -144,7 +144,6 @@ config USB_AT91
 config USB_LPC32XX
        tristate "LPC32XX USB Peripheral Controller"
        depends on ARCH_LPC32XX
-       depends on USB_PHY
        select USB_ISP1301
        help
           This option selects the USB device controller in the LPC32xx SoC.
@@ -206,7 +205,6 @@ config USB_FOTG210_UDC
 config USB_OMAP
        tristate "OMAP USB Device Controller"
        depends on ARCH_OMAP1
-       depends on USB_PHY
        select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
        help
           Many Texas Instruments OMAP processors have flexible full
@@ -287,21 +285,6 @@ config USB_S3C_HSOTG
          The Samsung S3C64XX USB2.0 high-speed gadget controller
          integrated into the S3C64XX series SoC.
 
-config USB_IMX
-       tristate "Freescale i.MX1 USB Peripheral Controller"
-       depends on ARCH_MXC
-       depends on BROKEN
-       help
-          Freescale's i.MX1 includes an integrated full speed
-          USB 1.1 device controller.
-
-          It has Six fixed-function endpoints, as well as endpoint
-          zero (for control transfers).
-
-          Say "y" to link the driver statically, or "m" to build a
-          dynamically linked module called "imx_udc" and force all
-          gadget drivers to also be dynamically linked.
-
 config USB_S3C2410
        tristate "S3C2410 USB Device Controller"
        depends on ARCH_S3C24XX
index bad08e66f3697abacb3327eb3f197f61ad388ad7..386db9daf1d9a254528deb6bd2273ef92b981e94 100644 (file)
@@ -13,7 +13,6 @@ obj-$(CONFIG_USB_NET2280)     += net2280.o
 obj-$(CONFIG_USB_AMD5536UDC)   += amd5536udc.o
 obj-$(CONFIG_USB_PXA25X)       += pxa25x_udc.o
 obj-$(CONFIG_USB_PXA27X)       += pxa27x_udc.o
-obj-$(CONFIG_USB_IMX)          += imx_udc.o
 obj-$(CONFIG_USB_GOKU)         += goku_udc.o
 obj-$(CONFIG_USB_OMAP)         += omap_udc.o
 obj-$(CONFIG_USB_S3C2410)      += s3c2410_udc.o
index f52dcfe8f545077df80aca9cb97f1ec2e72b6261..a9a4346c83aae221776a297eff8330aab6bb733c 100644 (file)
@@ -1122,7 +1122,7 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
                        goto finished;
                }
                if (ep->dma) {
-                       retval = prep_dma(ep, req, gfp);
+                       retval = prep_dma(ep, req, GFP_ATOMIC);
                        if (retval != 0)
                                goto finished;
                        /* write desc pointer to enable DMA */
@@ -1190,7 +1190,7 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
                 * for PPB modes, because of chain creation reasons
                 */
                if (ep->in) {
-                       retval = prep_dma(ep, req, gfp);
+                       retval = prep_dma(ep, req, GFP_ATOMIC);
                        if (retval != 0)
                                goto finished;
                }
index d9a6add0c8526e06778addb733ce3e53da78a291..4cc4fd6d14738add8cafd229e5668f63107eef0b 100644 (file)
@@ -870,6 +870,11 @@ static void clk_on(struct at91_udc *udc)
        if (udc->clocked)
                return;
        udc->clocked = 1;
+
+       if (IS_ENABLED(CONFIG_COMMON_CLK)) {
+               clk_set_rate(udc->uclk, 48000000);
+               clk_prepare_enable(udc->uclk);
+       }
        clk_prepare_enable(udc->iclk);
        clk_prepare_enable(udc->fclk);
 }
@@ -882,6 +887,8 @@ static void clk_off(struct at91_udc *udc)
        udc->gadget.speed = USB_SPEED_UNKNOWN;
        clk_disable_unprepare(udc->fclk);
        clk_disable_unprepare(udc->iclk);
+       if (IS_ENABLED(CONFIG_COMMON_CLK))
+               clk_disable_unprepare(udc->uclk);
 }
 
 /*
@@ -1697,7 +1704,7 @@ static int at91udc_probe(struct platform_device *pdev)
        int             retval;
        struct resource *res;
 
-       if (!dev->platform_data && !pdev->dev.of_node) {
+       if (!dev_get_platdata(dev) && !pdev->dev.of_node) {
                /* small (so we copy it) but critical! */
                DBG("missing platform_data\n");
                return -ENODEV;
@@ -1728,7 +1735,7 @@ static int at91udc_probe(struct platform_device *pdev)
        if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node)
                at91udc_of_init(udc, pdev->dev.of_node);
        else
-               memcpy(&udc->board, dev->platform_data,
+               memcpy(&udc->board, dev_get_platdata(dev),
                       sizeof(struct at91_udc_data));
        udc->pdev = pdev;
        udc->enabled = 0;
@@ -1774,10 +1781,12 @@ static int at91udc_probe(struct platform_device *pdev)
        /* get interface and function clocks */
        udc->iclk = clk_get(dev, "udc_clk");
        udc->fclk = clk_get(dev, "udpck");
-       if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) {
+       if (IS_ENABLED(CONFIG_COMMON_CLK))
+               udc->uclk = clk_get(dev, "usb_clk");
+       if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk) ||
+           (IS_ENABLED(CONFIG_COMMON_CLK) && IS_ERR(udc->uclk))) {
                DBG("clocks missing\n");
                retval = -ENODEV;
-               /* NOTE: we "know" here that refcounts on these are NOPs */
                goto fail1;
        }
 
@@ -1851,6 +1860,12 @@ fail3:
 fail2:
        free_irq(udc->udp_irq, udc);
 fail1:
+       if (IS_ENABLED(CONFIG_COMMON_CLK) && !IS_ERR(udc->uclk))
+               clk_put(udc->uclk);
+       if (!IS_ERR(udc->fclk))
+               clk_put(udc->fclk);
+       if (!IS_ERR(udc->iclk))
+               clk_put(udc->iclk);
        iounmap(udc->udp_baseaddr);
 fail0a:
        if (cpu_is_at91rm9200())
@@ -1894,6 +1909,8 @@ static int __exit at91udc_remove(struct platform_device *pdev)
 
        clk_put(udc->iclk);
        clk_put(udc->fclk);
+       if (IS_ENABLED(CONFIG_COMMON_CLK))
+               clk_put(udc->uclk);
 
        return 0;
 }
index e647d1c2ada4f2e3097783ebf5f4117672e08ef1..01752466338164e898b48a511078c5b2252b15a7 100644 (file)
@@ -126,7 +126,7 @@ struct at91_udc {
        unsigned                        active_suspend:1;
        u8                              addr;
        struct at91_udc_data            board;
-       struct clk                      *iclk, *fclk;
+       struct clk                      *iclk, *fclk, *uclk;
        struct platform_device          *pdev;
        struct proc_dir_entry           *pde;
        void __iomem                    *udp_baseaddr;
index 1d9722203ca66da925ac348a4021ffa0106c4c7a..40d23384b716866b6b0b30923a1ffc3515ecc244 100644 (file)
@@ -1772,6 +1772,7 @@ out:
 static int atmel_usba_start(struct usb_gadget *gadget,
                struct usb_gadget_driver *driver)
 {
+       int ret = 0;
        struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget);
        unsigned long flags;
 
@@ -1781,8 +1782,14 @@ static int atmel_usba_start(struct usb_gadget *gadget,
        udc->driver = driver;
        spin_unlock_irqrestore(&udc->lock, flags);
 
-       clk_enable(udc->pclk);
-       clk_enable(udc->hclk);
+       ret = clk_prepare_enable(udc->pclk);
+       if (ret)
+               goto out;
+       ret = clk_prepare_enable(udc->hclk);
+       if (ret) {
+               clk_disable_unprepare(udc->pclk);
+               goto out;
+       }
 
        DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name);
 
@@ -1797,9 +1804,11 @@ static int atmel_usba_start(struct usb_gadget *gadget,
                usba_writel(udc, CTRL, USBA_ENABLE_MASK);
                usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
        }
+
+out:
        spin_unlock_irqrestore(&udc->lock, flags);
 
-       return 0;
+       return ret;
 }
 
 static int atmel_usba_stop(struct usb_gadget *gadget,
@@ -1822,8 +1831,8 @@ static int atmel_usba_stop(struct usb_gadget *gadget,
 
        udc->driver = NULL;
 
-       clk_disable(udc->hclk);
-       clk_disable(udc->pclk);
+       clk_disable_unprepare(udc->hclk);
+       clk_disable_unprepare(udc->pclk);
 
        DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name);
 
@@ -1922,7 +1931,7 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
 static struct usba_ep * usba_udc_pdata(struct platform_device *pdev,
                                                 struct usba_udc *udc)
 {
-       struct usba_platform_data *pdata = pdev->dev.platform_data;
+       struct usba_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct usba_ep *eps;
        int i;
 
@@ -2022,10 +2031,14 @@ static int __init usba_udc_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, udc);
 
        /* Make sure we start from a clean slate */
-       clk_enable(pclk);
+       ret = clk_prepare_enable(pclk);
+       if (ret) {
+               dev_err(&pdev->dev, "Unable to enable pclk, aborting.\n");
+               goto err_clk_enable;
+       }
        toggle_bias(0);
        usba_writel(udc, CTRL, USBA_DISABLE_MASK);
-       clk_disable(pclk);
+       clk_disable_unprepare(pclk);
 
        if (pdev->dev.of_node)
                udc->usba_ep = atmel_udc_of_init(pdev, udc);
@@ -2081,6 +2094,7 @@ err_add_udc:
        free_irq(irq, udc);
 err_request_irq:
 err_alloc_ep:
+err_clk_enable:
        iounmap(udc->fifo);
 err_map_fifo:
        iounmap(udc->regs);
index fd24cb4540a49d6b0382b932ff99eae2dc9c309f..c58fcf1ebe414784568a9afc6911ecb00e10a409 100644 (file)
@@ -2313,7 +2313,7 @@ static void bcm63xx_udc_cleanup_debugfs(struct bcm63xx_udc *udc)
 static int bcm63xx_udc_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct bcm63xx_usbd_platform_data *pd = dev->platform_data;
+       struct bcm63xx_usbd_platform_data *pd = dev_get_platdata(dev);
        struct bcm63xx_udc *udc;
        struct resource *res;
        int rc = -ENOMEM, i, irq;
index 56f1fd1cba255259ae7618549708740d473a4319..4d4e96a5d2e9eec30eaeb0a138d773b332f36859 100644 (file)
@@ -3043,12 +3043,12 @@ fsg_config_from_params(struct fsg_config *cfg,
                lun->filename =
                        params->file_count > i && params->file[i][0]
                        ? params->file[i]
-                       : 0;
+                       : NULL;
        }
 
        /* Let MSF use defaults */
-       cfg->vendor_name = 0;
-       cfg->product_name = 0;
+       cfg->vendor_name = NULL;
+       cfg->product_name = NULL;
 
        cfg->ops = NULL;
        cfg->private_data = NULL;
index fa8ea4ea00c1a3014be0fdc35dfcc52bb17af166..2b4c82d84bfcf3da693197496d28971fc6f73e31 100644 (file)
@@ -695,7 +695,7 @@ static int generic_get_cmd(struct usb_audio_control *con, u8 cmd)
 }
 
 /* Todo: add more control selecotor dynamically */
-int __init control_selector_init(struct f_audio *audio)
+static int __init control_selector_init(struct f_audio *audio)
 {
        INIT_LIST_HEAD(&audio->cs);
        list_add(&feature_unit.list, &audio->cs);
@@ -719,7 +719,7 @@ int __init control_selector_init(struct f_audio *audio)
  *
  * Returns zero on success, else negative errno.
  */
-int __init audio_bind_config(struct usb_configuration *c)
+static int __init audio_bind_config(struct usb_configuration *c)
 {
        struct f_audio *audio;
        int status;
index d3bd7b095ba37713dfc3bdf1faaa39ddded393ac..9b140fc4d3bc5adcc4b815a885f7807fe6166b59 100644 (file)
@@ -33,7 +33,7 @@ int fsl_udc_clk_init(struct platform_device *pdev)
        unsigned long freq;
        int ret;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
 
        mxc_ipg_clk = devm_clk_get(&pdev->dev, "ipg");
        if (IS_ERR(mxc_ipg_clk)) {
@@ -80,7 +80,7 @@ eclkrate:
 
 int fsl_udc_clk_finalize(struct platform_device *pdev)
 {
-       struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+       struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
        int ret = 0;
 
        /* workaround ENGcm09152 for i.MX35 */
index a766a4ca1cb78ff627b3de85b4a4aac01713cd38..36ac7cfba91df850224c96a397fe06838b071720 100644 (file)
@@ -2248,7 +2248,7 @@ static int __init struct_udc_setup(struct fsl_udc *udc,
        struct fsl_usb2_platform_data *pdata;
        size_t size;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        udc->phy_mode = pdata->phy_mode;
 
        udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL);
@@ -2343,7 +2343,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        udc_controller->pdata = pdata;
        spin_lock_init(&udc_controller->lock);
        udc_controller->stopped = 1;
@@ -2524,7 +2524,7 @@ err_kfree:
 static int __exit fsl_udc_remove(struct platform_device *pdev)
 {
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+       struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
        DECLARE_COMPLETION(done);
 
index c83f3e16532582adcd4e600f0b11aefaa58a5661..f1dd6daabe217c0742140c1619c3be5aa22c8c54 100644 (file)
@@ -557,7 +557,7 @@ static void fusb300_set_cxdone(struct fusb300 *fusb300)
 }
 
 /* read data from cx fifo */
-void fusb300_rdcxf(struct fusb300 *fusb300,
+static void fusb300_rdcxf(struct fusb300 *fusb300,
                   u8 *buffer, u32 length)
 {
        int i = 0;
index 52dd6cc6c0aa2e3e016eedced4fa00f61dafb896..c64deb9e3d62368e073893448dfe9f8b7ec610cc 100644 (file)
@@ -772,7 +772,7 @@ goku_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 
        } /* else pio or dma irq handler advances the queue. */
 
-       if (likely(req != 0))
+       if (likely(req != NULL))
                list_add_tail(&req->queue, &ep->queue);
 
        if (likely(!list_empty(&ep->queue))
index c36260ea8bf2ed0a5beea8aafb8377d235b7fa1d..778613eb37af8aaefd943c63c991462f722d435f 100644 (file)
@@ -185,7 +185,7 @@ static int __exit hid_unbind(struct usb_composite_dev *cdev)
 
 static int __init hidg_plat_driver_probe(struct platform_device *pdev)
 {
-       struct hidg_func_descriptor *func = pdev->dev.platform_data;
+       struct hidg_func_descriptor *func = dev_get_platdata(&pdev->dev);
        struct hidg_func_node *entry;
 
        if (!func) {
diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c
deleted file mode 100644 (file)
index 9b2d24e..0000000
+++ /dev/null
@@ -1,1544 +0,0 @@
-/*
- *     driver/usb/gadget/imx_udc.c
- *
- *     Copyright (C) 2005 Mike Lee <eemike@gmail.com>
- *     Copyright (C) 2008 Darius Augulis <augulis.darius@gmail.com>
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- *
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/slab.h>
-#include <linux/prefetch.h>
-
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-
-#include <linux/platform_data/usb-imx_udc.h>
-#include <mach/hardware.h>
-
-#include "imx_udc.h"
-
-static const char driver_name[] = "imx_udc";
-static const char ep0name[] = "ep0";
-
-void ep0_chg_stat(const char *label, struct imx_udc_struct *imx_usb,
-                                                       enum ep0_state stat);
-
-/*******************************************************************************
- * IMX UDC hardware related functions
- *******************************************************************************
- */
-
-void imx_udc_enable(struct imx_udc_struct *imx_usb)
-{
-       int temp = __raw_readl(imx_usb->base + USB_CTRL);
-       __raw_writel(temp | CTRL_FE_ENA | CTRL_AFE_ENA,
-                                               imx_usb->base + USB_CTRL);
-       imx_usb->gadget.speed = USB_SPEED_FULL;
-}
-
-void imx_udc_disable(struct imx_udc_struct *imx_usb)
-{
-       int temp = __raw_readl(imx_usb->base + USB_CTRL);
-
-       __raw_writel(temp & ~(CTRL_FE_ENA | CTRL_AFE_ENA),
-                imx_usb->base + USB_CTRL);
-
-       ep0_chg_stat(__func__, imx_usb, EP0_IDLE);
-       imx_usb->gadget.speed = USB_SPEED_UNKNOWN;
-}
-
-void imx_udc_reset(struct imx_udc_struct *imx_usb)
-{
-       int temp = __raw_readl(imx_usb->base + USB_ENAB);
-
-       /* set RST bit */
-       __raw_writel(temp | ENAB_RST, imx_usb->base + USB_ENAB);
-
-       /* wait RST bit to clear */
-       do {} while (__raw_readl(imx_usb->base + USB_ENAB) & ENAB_RST);
-
-       /* wait CFG bit to assert */
-       do {} while (!(__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG));
-
-       /* udc module is now ready */
-}
-
-void imx_udc_config(struct imx_udc_struct *imx_usb)
-{
-       u8 ep_conf[5];
-       u8 i, j, cfg;
-       struct imx_ep_struct *imx_ep;
-
-       /* wait CFG bit to assert */
-       do {} while (!(__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG));
-
-       /* Download the endpoint buffer for endpoint 0. */
-       for (j = 0; j < 5; j++) {
-               i = (j == 2 ? imx_usb->imx_ep[0].fifosize : 0x00);
-               __raw_writeb(i, imx_usb->base + USB_DDAT);
-               do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_BSY);
-       }
-
-       /* Download the endpoint buffers for endpoints 1-5.
-        * We specify two configurations, one interface
-        */
-       for (cfg = 1; cfg < 3; cfg++) {
-               for (i = 1; i < IMX_USB_NB_EP; i++) {
-                       imx_ep = &imx_usb->imx_ep[i];
-                       /* EP no | Config no */
-                       ep_conf[0] = (i << 4) | (cfg << 2);
-                       /* Type | Direction */
-                       ep_conf[1] = (imx_ep->bmAttributes << 3) |
-                                       (EP_DIR(imx_ep) << 2);
-                       /* Max packet size */
-                       ep_conf[2] = imx_ep->fifosize;
-                       /* TRXTYP */
-                       ep_conf[3] = 0xC0;
-                       /* FIFO no */
-                       ep_conf[4] = i;
-
-                       D_INI(imx_usb->dev,
-                               "<%s> ep%d_conf[%d]:"
-                               "[%02x-%02x-%02x-%02x-%02x]\n",
-                               __func__, i, cfg,
-                               ep_conf[0], ep_conf[1], ep_conf[2],
-                               ep_conf[3], ep_conf[4]);
-
-                       for (j = 0; j < 5; j++) {
-                               __raw_writeb(ep_conf[j],
-                                       imx_usb->base + USB_DDAT);
-                               do {} while (__raw_readl(imx_usb->base
-                                                               + USB_DADR)
-                                       & DADR_BSY);
-                       }
-               }
-       }
-
-       /* wait CFG bit to clear */
-       do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG);
-}
-
-void imx_udc_init_irq(struct imx_udc_struct *imx_usb)
-{
-       int i;
-
-       /* Mask and clear all irqs */
-       __raw_writel(0xFFFFFFFF, imx_usb->base + USB_MASK);
-       __raw_writel(0xFFFFFFFF, imx_usb->base + USB_INTR);
-       for (i = 0; i < IMX_USB_NB_EP; i++) {
-               __raw_writel(0x1FF, imx_usb->base + USB_EP_MASK(i));
-               __raw_writel(0x1FF, imx_usb->base + USB_EP_INTR(i));
-       }
-
-       /* Enable USB irqs */
-       __raw_writel(INTR_MSOF | INTR_FRAME_MATCH, imx_usb->base + USB_MASK);
-
-       /* Enable EP0 irqs */
-       __raw_writel(0x1FF & ~(EPINTR_DEVREQ | EPINTR_MDEVREQ | EPINTR_EOT
-               | EPINTR_EOF | EPINTR_FIFO_EMPTY | EPINTR_FIFO_FULL),
-               imx_usb->base + USB_EP_MASK(0));
-}
-
-void imx_udc_init_ep(struct imx_udc_struct *imx_usb)
-{
-       int i, max, temp;
-       struct imx_ep_struct *imx_ep;
-       for (i = 0; i < IMX_USB_NB_EP; i++) {
-               imx_ep = &imx_usb->imx_ep[i];
-               switch (imx_ep->fifosize) {
-               case 8:
-                       max = 0;
-                       break;
-               case 16:
-                       max = 1;
-                       break;
-               case 32:
-                       max = 2;
-                       break;
-               case 64:
-                       max = 3;
-                       break;
-               default:
-                       max = 1;
-                       break;
-               }
-               temp = (EP_DIR(imx_ep) << 7) | (max << 5)
-                       | (imx_ep->bmAttributes << 3);
-               __raw_writel(temp, imx_usb->base + USB_EP_STAT(i));
-               __raw_writel(temp | EPSTAT_FLUSH,
-                                               imx_usb->base + USB_EP_STAT(i));
-               D_INI(imx_usb->dev, "<%s> ep%d_stat %08x\n", __func__, i,
-                       __raw_readl(imx_usb->base + USB_EP_STAT(i)));
-       }
-}
-
-void imx_udc_init_fifo(struct imx_udc_struct *imx_usb)
-{
-       int i, temp;
-       struct imx_ep_struct *imx_ep;
-       for (i = 0; i < IMX_USB_NB_EP; i++) {
-               imx_ep = &imx_usb->imx_ep[i];
-
-               /* Fifo control */
-               temp = EP_DIR(imx_ep) ? 0x0B000000 : 0x0F000000;
-               __raw_writel(temp, imx_usb->base + USB_EP_FCTRL(i));
-               D_INI(imx_usb->dev, "<%s> ep%d_fctrl %08x\n", __func__, i,
-                       __raw_readl(imx_usb->base + USB_EP_FCTRL(i)));
-
-               /* Fifo alarm */
-               temp = (i ? imx_ep->fifosize / 2 : 0);
-               __raw_writel(temp, imx_usb->base + USB_EP_FALRM(i));
-               D_INI(imx_usb->dev, "<%s> ep%d_falrm %08x\n", __func__, i,
-                       __raw_readl(imx_usb->base + USB_EP_FALRM(i)));
-       }
-}
-
-static void imx_udc_init(struct imx_udc_struct *imx_usb)
-{
-       /* Reset UDC */
-       imx_udc_reset(imx_usb);
-
-       /* Download config to enpoint buffer */
-       imx_udc_config(imx_usb);
-
-       /* Setup interrups */
-       imx_udc_init_irq(imx_usb);
-
-       /* Setup endpoints */
-       imx_udc_init_ep(imx_usb);
-
-       /* Setup fifos */
-       imx_udc_init_fifo(imx_usb);
-}
-
-void imx_ep_irq_enable(struct imx_ep_struct *imx_ep)
-{
-
-       int i = EP_NO(imx_ep);
-
-       __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_MASK(i));
-       __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_INTR(i));
-       __raw_writel(0x1FF & ~(EPINTR_EOT | EPINTR_EOF),
-               imx_ep->imx_usb->base + USB_EP_MASK(i));
-}
-
-void imx_ep_irq_disable(struct imx_ep_struct *imx_ep)
-{
-
-       int i = EP_NO(imx_ep);
-
-       __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_MASK(i));
-       __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_INTR(i));
-}
-
-int imx_ep_empty(struct imx_ep_struct *imx_ep)
-{
-       struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
-
-       return __raw_readl(imx_usb->base + USB_EP_FSTAT(EP_NO(imx_ep)))
-                       & FSTAT_EMPTY;
-}
-
-unsigned imx_fifo_bcount(struct imx_ep_struct *imx_ep)
-{
-       struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
-
-       return (__raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)))
-                       & EPSTAT_BCOUNT) >> 16;
-}
-
-void imx_flush(struct imx_ep_struct *imx_ep)
-{
-       struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
-
-       int temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
-       __raw_writel(temp | EPSTAT_FLUSH,
-               imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
-}
-
-void imx_ep_stall(struct imx_ep_struct *imx_ep)
-{
-       struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
-       int temp, i;
-
-       D_ERR(imx_usb->dev,
-               "<%s> Forced stall on %s\n", __func__, imx_ep->ep.name);
-
-       imx_flush(imx_ep);
-
-       /* Special care for ep0 */
-       if (!EP_NO(imx_ep)) {
-               temp = __raw_readl(imx_usb->base + USB_CTRL);
-               __raw_writel(temp | CTRL_CMDOVER | CTRL_CMDERROR,
-                                               imx_usb->base + USB_CTRL);
-               do { } while (__raw_readl(imx_usb->base + USB_CTRL)
-                                               & CTRL_CMDOVER);
-               temp = __raw_readl(imx_usb->base + USB_CTRL);
-               __raw_writel(temp & ~CTRL_CMDERROR, imx_usb->base + USB_CTRL);
-       }
-       else {
-               temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
-               __raw_writel(temp | EPSTAT_STALL,
-                       imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
-
-               for (i = 0; i < 100; i ++) {
-                       temp = __raw_readl(imx_usb->base
-                                               + USB_EP_STAT(EP_NO(imx_ep)));
-                       if (!(temp & EPSTAT_STALL))
-                               break;
-                       udelay(20);
-               }
-               if (i == 100)
-                       D_ERR(imx_usb->dev, "<%s> Non finished stall on %s\n",
-                               __func__, imx_ep->ep.name);
-       }
-}
-
-static int imx_udc_get_frame(struct usb_gadget *_gadget)
-{
-       struct imx_udc_struct *imx_usb = container_of(_gadget,
-                       struct imx_udc_struct, gadget);
-
-       return __raw_readl(imx_usb->base + USB_FRAME) & 0x7FF;
-}
-
-static int imx_udc_wakeup(struct usb_gadget *_gadget)
-{
-       return 0;
-}
-
-/*******************************************************************************
- * USB request control functions
- *******************************************************************************
- */
-
-static void ep_add_request(struct imx_ep_struct *imx_ep,
-                                                       struct imx_request *req)
-{
-       if (unlikely(!req))
-               return;
-
-       req->in_use = 1;
-       list_add_tail(&req->queue, &imx_ep->queue);
-}
-
-static void ep_del_request(struct imx_ep_struct *imx_ep,
-                                                       struct imx_request *req)
-{
-       if (unlikely(!req))
-               return;
-
-       list_del_init(&req->queue);
-       req->in_use = 0;
-}
-
-static void done(struct imx_ep_struct *imx_ep,
-                                       struct imx_request *req, int status)
-{
-       ep_del_request(imx_ep, req);
-
-       if (likely(req->req.status == -EINPROGRESS))
-               req->req.status = status;
-       else
-               status = req->req.status;
-
-       if (status && status != -ESHUTDOWN)
-               D_ERR(imx_ep->imx_usb->dev,
-                       "<%s> complete %s req %p stat %d len %u/%u\n", __func__,
-                       imx_ep->ep.name, &req->req, status,
-                       req->req.actual, req->req.length);
-
-       req->req.complete(&imx_ep->ep, &req->req);
-}
-
-static void nuke(struct imx_ep_struct *imx_ep, int status)
-{
-       struct imx_request *req;
-
-       while (!list_empty(&imx_ep->queue)) {
-               req = list_entry(imx_ep->queue.next, struct imx_request, queue);
-               done(imx_ep, req, status);
-       }
-}
-
-/*******************************************************************************
- * Data tansfer over USB functions
- *******************************************************************************
- */
-static int read_packet(struct imx_ep_struct *imx_ep, struct imx_request *req)
-{
-       u8      *buf;
-       int     bytes_ep, bufferspace, count, i;
-
-       bytes_ep = imx_fifo_bcount(imx_ep);
-       bufferspace = req->req.length - req->req.actual;
-
-       buf = req->req.buf + req->req.actual;
-       prefetchw(buf);
-
-       if (unlikely(imx_ep_empty(imx_ep)))
-               count = 0;      /* zlp */
-       else
-               count = min(bytes_ep, bufferspace);
-
-       for (i = count; i > 0; i--)
-               *buf++ = __raw_readb(imx_ep->imx_usb->base
-                                               + USB_EP_FDAT0(EP_NO(imx_ep)));
-       req->req.actual += count;
-
-       return count;
-}
-
-static int write_packet(struct imx_ep_struct *imx_ep, struct imx_request *req)
-{
-       u8      *buf;
-       int     length, count, temp;
-
-       if (unlikely(__raw_readl(imx_ep->imx_usb->base +
-                                USB_EP_STAT(EP_NO(imx_ep))) & EPSTAT_ZLPS)) {
-               D_TRX(imx_ep->imx_usb->dev, "<%s> zlp still queued in EP %s\n",
-                       __func__, imx_ep->ep.name);
-               return -1;
-       }
-
-       buf = req->req.buf + req->req.actual;
-       prefetch(buf);
-
-       length = min(req->req.length - req->req.actual, (u32)imx_ep->fifosize);
-
-       if (imx_fifo_bcount(imx_ep) + length > imx_ep->fifosize) {
-               D_TRX(imx_ep->imx_usb->dev, "<%s> packet overfill %s fifo\n",
-                       __func__, imx_ep->ep.name);
-               return -1;
-       }
-
-       req->req.actual += length;
-       count = length;
-
-       if (!count && req->req.zero) {  /* zlp */
-               temp = __raw_readl(imx_ep->imx_usb->base
-                       + USB_EP_STAT(EP_NO(imx_ep)));
-               __raw_writel(temp | EPSTAT_ZLPS, imx_ep->imx_usb->base
-                       + USB_EP_STAT(EP_NO(imx_ep)));
-               D_TRX(imx_ep->imx_usb->dev, "<%s> zero packet\n", __func__);
-               return 0;
-       }
-
-       while (count--) {
-               if (count == 0) {       /* last byte */
-                       temp = __raw_readl(imx_ep->imx_usb->base
-                               + USB_EP_FCTRL(EP_NO(imx_ep)));
-                       __raw_writel(temp | FCTRL_WFR, imx_ep->imx_usb->base
-                               + USB_EP_FCTRL(EP_NO(imx_ep)));
-               }
-               __raw_writeb(*buf++,
-                       imx_ep->imx_usb->base + USB_EP_FDAT0(EP_NO(imx_ep)));
-       }
-
-       return length;
-}
-
-static int read_fifo(struct imx_ep_struct *imx_ep, struct imx_request *req)
-{
-       int     bytes = 0,
-               count,
-               completed = 0;
-
-       while (__raw_readl(imx_ep->imx_usb->base + USB_EP_FSTAT(EP_NO(imx_ep)))
-               & FSTAT_FR) {
-                       count = read_packet(imx_ep, req);
-                       bytes += count;
-
-                       completed = (count != imx_ep->fifosize);
-                       if (completed || req->req.actual == req->req.length) {
-                               completed = 1;
-                               break;
-                       }
-       }
-
-       if (completed || !req->req.length) {
-               done(imx_ep, req, 0);
-               D_REQ(imx_ep->imx_usb->dev, "<%s> %s req<%p> %s\n",
-                       __func__, imx_ep->ep.name, req,
-                       completed ? "completed" : "not completed");
-               if (!EP_NO(imx_ep))
-                       ep0_chg_stat(__func__, imx_ep->imx_usb, EP0_IDLE);
-       }
-
-       D_TRX(imx_ep->imx_usb->dev, "<%s> bytes read: %d\n", __func__, bytes);
-
-       return completed;
-}
-
-static int write_fifo(struct imx_ep_struct *imx_ep, struct imx_request *req)
-{
-       int     bytes = 0,
-               count,
-               completed = 0;
-
-       while (!completed) {
-               count = write_packet(imx_ep, req);
-               if (count < 0)
-                       break; /* busy */
-               bytes += count;
-
-               /* last packet "must be" short (or a zlp) */
-               completed = (count != imx_ep->fifosize);
-
-               if (unlikely(completed)) {
-                       done(imx_ep, req, 0);
-                       D_REQ(imx_ep->imx_usb->dev, "<%s> %s req<%p> %s\n",
-                               __func__, imx_ep->ep.name, req,
-                               completed ? "completed" : "not completed");
-                       if (!EP_NO(imx_ep))
-                               ep0_chg_stat(__func__,
-                                               imx_ep->imx_usb, EP0_IDLE);
-               }
-       }
-
-       D_TRX(imx_ep->imx_usb->dev, "<%s> bytes sent: %d\n", __func__, bytes);
-
-       return completed;
-}
-
-/*******************************************************************************
- * Endpoint handlers
- *******************************************************************************
- */
-static int handle_ep(struct imx_ep_struct *imx_ep)
-{
-       struct imx_request *req;
-       int completed = 0;
-
-       do {
-               if (!list_empty(&imx_ep->queue))
-                       req = list_entry(imx_ep->queue.next,
-                               struct imx_request, queue);
-               else {
-                       D_REQ(imx_ep->imx_usb->dev, "<%s> no request on %s\n",
-                               __func__, imx_ep->ep.name);
-                       return 0;
-               }
-
-               if (EP_DIR(imx_ep))     /* to host */
-                       completed = write_fifo(imx_ep, req);
-               else                    /* to device */
-                       completed = read_fifo(imx_ep, req);
-
-               dump_ep_stat(__func__, imx_ep);
-
-       } while (completed);
-
-       return 0;
-}
-
-static int handle_ep0(struct imx_ep_struct *imx_ep)
-{
-       struct imx_request *req = NULL;
-       int ret = 0;
-
-       if (!list_empty(&imx_ep->queue)) {
-               req = list_entry(imx_ep->queue.next, struct imx_request, queue);
-
-               switch (imx_ep->imx_usb->ep0state) {
-
-               case EP0_IN_DATA_PHASE:                 /* GET_DESCRIPTOR */
-                       write_fifo(imx_ep, req);
-                       break;
-               case EP0_OUT_DATA_PHASE:                /* SET_DESCRIPTOR */
-                       read_fifo(imx_ep, req);
-                       break;
-               default:
-                       D_EP0(imx_ep->imx_usb->dev,
-                               "<%s> ep0 i/o, odd state %d\n",
-                               __func__, imx_ep->imx_usb->ep0state);
-                       ep_del_request(imx_ep, req);
-                       ret = -EL2HLT;
-                       break;
-               }
-       }
-
-       else
-               D_ERR(imx_ep->imx_usb->dev, "<%s> no request on %s\n",
-                                               __func__, imx_ep->ep.name);
-
-       return ret;
-}
-
-static void handle_ep0_devreq(struct imx_udc_struct *imx_usb)
-{
-       struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[0];
-       union {
-               struct usb_ctrlrequest  r;
-               u8                      raw[8];
-               u32                     word[2];
-       } u;
-       int temp, i;
-
-       nuke(imx_ep, -EPROTO);
-
-       /* read SETUP packet */
-       for (i = 0; i < 2; i++) {
-               if (imx_ep_empty(imx_ep)) {
-                       D_ERR(imx_usb->dev,
-                               "<%s> no setup packet received\n", __func__);
-                       goto stall;
-               }
-               u.word[i] = __raw_readl(imx_usb->base
-                                               + USB_EP_FDAT(EP_NO(imx_ep)));
-       }
-
-       temp = imx_ep_empty(imx_ep);
-       while (!imx_ep_empty(imx_ep)) {
-               i = __raw_readl(imx_usb->base + USB_EP_FDAT(EP_NO(imx_ep)));
-               D_ERR(imx_usb->dev,
-                       "<%s> wrong to have extra bytes for setup : 0x%08x\n",
-                       __func__, i);
-       }
-       if (!temp)
-               goto stall;
-
-       le16_to_cpus(&u.r.wValue);
-       le16_to_cpus(&u.r.wIndex);
-       le16_to_cpus(&u.r.wLength);
-
-       D_REQ(imx_usb->dev, "<%s> SETUP %02x.%02x v%04x i%04x l%04x\n",
-               __func__, u.r.bRequestType, u.r.bRequest,
-               u.r.wValue, u.r.wIndex, u.r.wLength);
-
-       if (imx_usb->set_config) {
-               /* NACK the host by using CMDOVER */
-               temp = __raw_readl(imx_usb->base + USB_CTRL);
-               __raw_writel(temp | CTRL_CMDOVER, imx_usb->base + USB_CTRL);
-
-               D_ERR(imx_usb->dev,
-                       "<%s> set config req is pending, NACK the host\n",
-                       __func__);
-               return;
-       }
-
-       if (u.r.bRequestType & USB_DIR_IN)
-               ep0_chg_stat(__func__, imx_usb, EP0_IN_DATA_PHASE);
-       else
-               ep0_chg_stat(__func__, imx_usb, EP0_OUT_DATA_PHASE);
-
-       i = imx_usb->driver->setup(&imx_usb->gadget, &u.r);
-       if (i < 0) {
-               D_ERR(imx_usb->dev, "<%s> device setup error %d\n",
-                       __func__, i);
-               goto stall;
-       }
-
-       return;
-stall:
-       D_ERR(imx_usb->dev, "<%s> protocol STALL\n", __func__);
-       imx_ep_stall(imx_ep);
-       ep0_chg_stat(__func__, imx_usb, EP0_STALL);
-       return;
-}
-
-/*******************************************************************************
- * USB gadget callback functions
- *******************************************************************************
- */
-
-static int imx_ep_enable(struct usb_ep *usb_ep,
-                               const struct usb_endpoint_descriptor *desc)
-{
-       struct imx_ep_struct *imx_ep = container_of(usb_ep,
-                                               struct imx_ep_struct, ep);
-       struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
-       unsigned long flags;
-
-       if (!usb_ep
-               || !desc
-               || !EP_NO(imx_ep)
-               || desc->bDescriptorType != USB_DT_ENDPOINT
-               || imx_ep->bEndpointAddress != desc->bEndpointAddress) {
-                       D_ERR(imx_usb->dev,
-                               "<%s> bad ep or descriptor\n", __func__);
-                       return -EINVAL;
-       }
-
-       if (imx_ep->bmAttributes != desc->bmAttributes) {
-               D_ERR(imx_usb->dev,
-                       "<%s> %s type mismatch\n", __func__, usb_ep->name);
-               return -EINVAL;
-       }
-
-       if (imx_ep->fifosize < usb_endpoint_maxp(desc)) {
-               D_ERR(imx_usb->dev,
-                       "<%s> bad %s maxpacket\n", __func__, usb_ep->name);
-               return -ERANGE;
-       }
-
-       if (!imx_usb->driver || imx_usb->gadget.speed == USB_SPEED_UNKNOWN) {
-               D_ERR(imx_usb->dev, "<%s> bogus device state\n", __func__);
-               return -ESHUTDOWN;
-       }
-
-       local_irq_save(flags);
-
-       imx_ep->stopped = 0;
-       imx_flush(imx_ep);
-       imx_ep_irq_enable(imx_ep);
-
-       local_irq_restore(flags);
-
-       D_EPX(imx_usb->dev, "<%s> ENABLED %s\n", __func__, usb_ep->name);
-       return 0;
-}
-
-static int imx_ep_disable(struct usb_ep *usb_ep)
-{
-       struct imx_ep_struct *imx_ep = container_of(usb_ep,
-                                               struct imx_ep_struct, ep);
-       unsigned long flags;
-
-       if (!usb_ep || !EP_NO(imx_ep) || !list_empty(&imx_ep->queue)) {
-               D_ERR(imx_ep->imx_usb->dev, "<%s> %s can not be disabled\n",
-                       __func__, usb_ep ? imx_ep->ep.name : NULL);
-               return -EINVAL;
-       }
-
-       local_irq_save(flags);
-
-       imx_ep->stopped = 1;
-       nuke(imx_ep, -ESHUTDOWN);
-       imx_flush(imx_ep);
-       imx_ep_irq_disable(imx_ep);
-
-       local_irq_restore(flags);
-
-       D_EPX(imx_ep->imx_usb->dev,
-               "<%s> DISABLED %s\n", __func__, usb_ep->name);
-       return 0;
-}
-
-static struct usb_request *imx_ep_alloc_request
-                                       (struct usb_ep *usb_ep, gfp_t gfp_flags)
-{
-       struct imx_request *req;
-
-       if (!usb_ep)
-               return NULL;
-
-       req = kzalloc(sizeof *req, gfp_flags);
-       if (!req)
-               return NULL;
-
-       INIT_LIST_HEAD(&req->queue);
-       req->in_use = 0;
-
-       return &req->req;
-}
-
-static void imx_ep_free_request
-                       (struct usb_ep *usb_ep, struct usb_request *usb_req)
-{
-       struct imx_request *req;
-
-       req = container_of(usb_req, struct imx_request, req);
-       WARN_ON(!list_empty(&req->queue));
-       kfree(req);
-}
-
-static int imx_ep_queue
-       (struct usb_ep *usb_ep, struct usb_request *usb_req, gfp_t gfp_flags)
-{
-       struct imx_ep_struct    *imx_ep;
-       struct imx_udc_struct   *imx_usb;
-       struct imx_request      *req;
-       unsigned long           flags;
-       int                     ret = 0;
-
-       imx_ep = container_of(usb_ep, struct imx_ep_struct, ep);
-       imx_usb = imx_ep->imx_usb;
-       req = container_of(usb_req, struct imx_request, req);
-
-       /*
-         Special care on IMX udc.
-         Ignore enqueue when after set configuration from the
-         host. This assume all gadget drivers reply set
-         configuration with the next ep0 req enqueue.
-       */
-       if (imx_usb->set_config && !EP_NO(imx_ep)) {
-               imx_usb->set_config = 0;
-               D_ERR(imx_usb->dev,
-                       "<%s> gadget reply set config\n", __func__);
-               return 0;
-       }
-
-       if (unlikely(!usb_req || !req || !usb_req->complete || !usb_req->buf)) {
-               D_ERR(imx_usb->dev, "<%s> bad params\n", __func__);
-               return -EINVAL;
-       }
-
-       if (unlikely(!usb_ep || !imx_ep)) {
-               D_ERR(imx_usb->dev, "<%s> bad ep\n", __func__);
-               return -EINVAL;
-       }
-
-       if (!imx_usb->driver || imx_usb->gadget.speed == USB_SPEED_UNKNOWN) {
-               D_ERR(imx_usb->dev, "<%s> bogus device state\n", __func__);
-               return -ESHUTDOWN;
-       }
-
-       /* Debug */
-       D_REQ(imx_usb->dev, "<%s> ep%d %s request for [%d] bytes\n",
-               __func__, EP_NO(imx_ep),
-               ((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state
-                                                       == EP0_IN_DATA_PHASE)
-               || (EP_NO(imx_ep) && EP_DIR(imx_ep)))
-                                       ? "IN" : "OUT", usb_req->length);
-       dump_req(__func__, imx_ep, usb_req);
-
-       if (imx_ep->stopped) {
-               usb_req->status = -ESHUTDOWN;
-               return -ESHUTDOWN;
-       }
-
-       if (req->in_use) {
-               D_ERR(imx_usb->dev,
-                       "<%s> refusing to queue req %p (already queued)\n",
-                       __func__, req);
-               return 0;
-       }
-
-       local_irq_save(flags);
-
-       usb_req->status = -EINPROGRESS;
-       usb_req->actual = 0;
-
-       ep_add_request(imx_ep, req);
-
-       if (!EP_NO(imx_ep))
-               ret = handle_ep0(imx_ep);
-       else
-               ret = handle_ep(imx_ep);
-
-       local_irq_restore(flags);
-       return ret;
-}
-
-static int imx_ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req)
-{
-
-       struct imx_ep_struct *imx_ep = container_of
-                                       (usb_ep, struct imx_ep_struct, ep);
-       struct imx_request *req;
-       unsigned long flags;
-
-       if (unlikely(!usb_ep || !EP_NO(imx_ep))) {
-               D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__);
-               return -EINVAL;
-       }
-
-       local_irq_save(flags);
-
-       /* make sure it's actually queued on this endpoint */
-       list_for_each_entry(req, &imx_ep->queue, queue) {
-               if (&req->req == usb_req)
-                       break;
-       }
-       if (&req->req != usb_req) {
-               local_irq_restore(flags);
-               return -EINVAL;
-       }
-
-       done(imx_ep, req, -ECONNRESET);
-
-       local_irq_restore(flags);
-       return 0;
-}
-
-static int imx_ep_set_halt(struct usb_ep *usb_ep, int value)
-{
-       struct imx_ep_struct *imx_ep = container_of
-                                       (usb_ep, struct imx_ep_struct, ep);
-       unsigned long flags;
-
-       if (unlikely(!usb_ep || !EP_NO(imx_ep))) {
-               D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__);
-               return -EINVAL;
-       }
-
-       local_irq_save(flags);
-
-       if ((imx_ep->bEndpointAddress & USB_DIR_IN)
-               && !list_empty(&imx_ep->queue)) {
-                       local_irq_restore(flags);
-                       return -EAGAIN;
-       }
-
-       imx_ep_stall(imx_ep);
-
-       local_irq_restore(flags);
-
-       D_EPX(imx_ep->imx_usb->dev, "<%s> %s halt\n", __func__, usb_ep->name);
-       return 0;
-}
-
-static int imx_ep_fifo_status(struct usb_ep *usb_ep)
-{
-       struct imx_ep_struct *imx_ep = container_of
-                                       (usb_ep, struct imx_ep_struct, ep);
-
-       if (!usb_ep) {
-               D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__);
-               return -ENODEV;
-       }
-
-       if (imx_ep->imx_usb->gadget.speed == USB_SPEED_UNKNOWN)
-               return 0;
-       else
-               return imx_fifo_bcount(imx_ep);
-}
-
-static void imx_ep_fifo_flush(struct usb_ep *usb_ep)
-{
-       struct imx_ep_struct *imx_ep = container_of
-                                       (usb_ep, struct imx_ep_struct, ep);
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       if (!usb_ep || !EP_NO(imx_ep) || !list_empty(&imx_ep->queue)) {
-               D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__);
-               local_irq_restore(flags);
-               return;
-       }
-
-       /* toggle and halt bits stay unchanged */
-       imx_flush(imx_ep);
-
-       local_irq_restore(flags);
-}
-
-static struct usb_ep_ops imx_ep_ops = {
-       .enable         = imx_ep_enable,
-       .disable        = imx_ep_disable,
-
-       .alloc_request  = imx_ep_alloc_request,
-       .free_request   = imx_ep_free_request,
-
-       .queue          = imx_ep_queue,
-       .dequeue        = imx_ep_dequeue,
-
-       .set_halt       = imx_ep_set_halt,
-       .fifo_status    = imx_ep_fifo_status,
-       .fifo_flush     = imx_ep_fifo_flush,
-};
-
-/*******************************************************************************
- * USB endpoint control functions
- *******************************************************************************
- */
-
-void ep0_chg_stat(const char *label,
-                       struct imx_udc_struct *imx_usb, enum ep0_state stat)
-{
-       D_EP0(imx_usb->dev, "<%s> from %15s to %15s\n",
-               label, state_name[imx_usb->ep0state], state_name[stat]);
-
-       if (imx_usb->ep0state == stat)
-               return;
-
-       imx_usb->ep0state = stat;
-}
-
-static void usb_init_data(struct imx_udc_struct *imx_usb)
-{
-       struct imx_ep_struct *imx_ep;
-       u8 i;
-
-       /* device/ep0 records init */
-       INIT_LIST_HEAD(&imx_usb->gadget.ep_list);
-       INIT_LIST_HEAD(&imx_usb->gadget.ep0->ep_list);
-       ep0_chg_stat(__func__, imx_usb, EP0_IDLE);
-
-       /* basic endpoint records init */
-       for (i = 0; i < IMX_USB_NB_EP; i++) {
-               imx_ep = &imx_usb->imx_ep[i];
-
-               if (i) {
-                       list_add_tail(&imx_ep->ep.ep_list,
-                               &imx_usb->gadget.ep_list);
-                       imx_ep->stopped = 1;
-               } else
-                       imx_ep->stopped = 0;
-
-               INIT_LIST_HEAD(&imx_ep->queue);
-       }
-}
-
-static void udc_stop_activity(struct imx_udc_struct *imx_usb,
-                                       struct usb_gadget_driver *driver)
-{
-       struct imx_ep_struct *imx_ep;
-       int i;
-
-       if (imx_usb->gadget.speed == USB_SPEED_UNKNOWN)
-               driver = NULL;
-
-       /* prevent new request submissions, kill any outstanding requests  */
-       for (i = 1; i < IMX_USB_NB_EP; i++) {
-               imx_ep = &imx_usb->imx_ep[i];
-               imx_flush(imx_ep);
-               imx_ep->stopped = 1;
-               imx_ep_irq_disable(imx_ep);
-               nuke(imx_ep, -ESHUTDOWN);
-       }
-
-       imx_usb->cfg = 0;
-       imx_usb->intf = 0;
-       imx_usb->alt = 0;
-
-       if (driver)
-               driver->disconnect(&imx_usb->gadget);
-}
-
-/*******************************************************************************
- * Interrupt handlers
- *******************************************************************************
- */
-
-/*
- * Called when timer expires.
- * Timer is started when CFG_CHG is received.
- */
-static void handle_config(unsigned long data)
-{
-       struct imx_udc_struct *imx_usb = (void *)data;
-       struct usb_ctrlrequest u;
-       int temp, cfg, intf, alt;
-
-       local_irq_disable();
-
-       temp = __raw_readl(imx_usb->base + USB_STAT);
-       cfg  = (temp & STAT_CFG) >> 5;
-       intf = (temp & STAT_INTF) >> 3;
-       alt  =  temp & STAT_ALTSET;
-
-       D_REQ(imx_usb->dev,
-               "<%s> orig config C=%d, I=%d, A=%d / "
-               "req config C=%d, I=%d, A=%d\n",
-               __func__, imx_usb->cfg, imx_usb->intf, imx_usb->alt,
-               cfg, intf, alt);
-
-       if (cfg == 1 || cfg == 2) {
-
-               if (imx_usb->cfg != cfg) {
-                       u.bRequest = USB_REQ_SET_CONFIGURATION;
-                       u.bRequestType = USB_DIR_OUT |
-                                       USB_TYPE_STANDARD |
-                                       USB_RECIP_DEVICE;
-                       u.wValue = cfg;
-                       u.wIndex = 0;
-                       u.wLength = 0;
-                       imx_usb->cfg = cfg;
-                       imx_usb->driver->setup(&imx_usb->gadget, &u);
-
-               }
-               if (imx_usb->intf != intf || imx_usb->alt != alt) {
-                       u.bRequest = USB_REQ_SET_INTERFACE;
-                       u.bRequestType = USB_DIR_OUT |
-                                         USB_TYPE_STANDARD |
-                                         USB_RECIP_INTERFACE;
-                       u.wValue = alt;
-                       u.wIndex = intf;
-                       u.wLength = 0;
-                       imx_usb->intf = intf;
-                       imx_usb->alt = alt;
-                       imx_usb->driver->setup(&imx_usb->gadget, &u);
-               }
-       }
-
-       imx_usb->set_config = 0;
-
-       local_irq_enable();
-}
-
-static irqreturn_t imx_udc_irq(int irq, void *dev)
-{
-       struct imx_udc_struct *imx_usb = dev;
-       int intr = __raw_readl(imx_usb->base + USB_INTR);
-       int temp;
-
-       if (intr & (INTR_WAKEUP | INTR_SUSPEND | INTR_RESUME | INTR_RESET_START
-                       | INTR_RESET_STOP | INTR_CFG_CHG)) {
-                               dump_intr(__func__, intr, imx_usb->dev);
-                               dump_usb_stat(__func__, imx_usb);
-       }
-
-       if (!imx_usb->driver)
-               goto end_irq;
-
-       if (intr & INTR_SOF) {
-               /* Copy from Freescale BSP.
-                  We must enable SOF intr and set CMDOVER.
-                  Datasheet don't specifiy this action, but it
-                  is done in Freescale BSP, so just copy it.
-               */
-               if (imx_usb->ep0state == EP0_IDLE) {
-                       temp = __raw_readl(imx_usb->base + USB_CTRL);
-                       __raw_writel(temp | CTRL_CMDOVER,
-                                               imx_usb->base + USB_CTRL);
-               }
-       }
-
-       if (intr & INTR_CFG_CHG) {
-               /* A workaround of serious IMX UDC bug.
-                  Handling of CFG_CHG should be delayed for some time, because
-                  IMX does not NACK the host when CFG_CHG interrupt is pending.
-                  There is no time to handle current CFG_CHG
-                  if next CFG_CHG or SETUP packed is send immediately.
-                  We have to clear CFG_CHG, start the timer and
-                  NACK the host by setting CTRL_CMDOVER
-                  if it sends any SETUP packet.
-                  When timer expires, handler is called to handle configuration
-                  changes. While CFG_CHG is not handled (set_config=1),
-                  we must NACK the host to every SETUP packed.
-                  This delay prevents from going out of sync with host.
-                */
-               __raw_writel(INTR_CFG_CHG, imx_usb->base + USB_INTR);
-               imx_usb->set_config = 1;
-               mod_timer(&imx_usb->timer, jiffies + 5);
-               goto end_irq;
-       }
-
-       if (intr & INTR_WAKEUP) {
-               if (imx_usb->gadget.speed == USB_SPEED_UNKNOWN
-                       && imx_usb->driver && imx_usb->driver->resume)
-                               imx_usb->driver->resume(&imx_usb->gadget);
-               imx_usb->set_config = 0;
-               del_timer(&imx_usb->timer);
-               imx_usb->gadget.speed = USB_SPEED_FULL;
-       }
-
-       if (intr & INTR_SUSPEND) {
-               if (imx_usb->gadget.speed != USB_SPEED_UNKNOWN
-                       && imx_usb->driver && imx_usb->driver->suspend)
-                               imx_usb->driver->suspend(&imx_usb->gadget);
-               imx_usb->set_config = 0;
-               del_timer(&imx_usb->timer);
-               imx_usb->gadget.speed = USB_SPEED_UNKNOWN;
-       }
-
-       if (intr & INTR_RESET_START) {
-               __raw_writel(intr, imx_usb->base + USB_INTR);
-               udc_stop_activity(imx_usb, imx_usb->driver);
-               imx_usb->set_config = 0;
-               del_timer(&imx_usb->timer);
-               imx_usb->gadget.speed = USB_SPEED_UNKNOWN;
-       }
-
-       if (intr & INTR_RESET_STOP)
-               imx_usb->gadget.speed = USB_SPEED_FULL;
-
-end_irq:
-       __raw_writel(intr, imx_usb->base + USB_INTR);
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t imx_udc_ctrl_irq(int irq, void *dev)
-{
-       struct imx_udc_struct *imx_usb = dev;
-       struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[0];
-       int intr = __raw_readl(imx_usb->base + USB_EP_INTR(0));
-
-       dump_ep_intr(__func__, 0, intr, imx_usb->dev);
-
-       if (!imx_usb->driver) {
-               __raw_writel(intr, imx_usb->base + USB_EP_INTR(0));
-               return IRQ_HANDLED;
-       }
-
-       /* DEVREQ has highest priority */
-       if (intr & (EPINTR_DEVREQ | EPINTR_MDEVREQ))
-               handle_ep0_devreq(imx_usb);
-       /* Seem i.MX is missing EOF interrupt sometimes.
-        * Therefore we don't monitor EOF.
-        * We call handle_ep0() only if a request is queued for ep0.
-        */
-       else if (!list_empty(&imx_ep->queue))
-               handle_ep0(imx_ep);
-
-       __raw_writel(intr, imx_usb->base + USB_EP_INTR(0));
-
-       return IRQ_HANDLED;
-}
-
-#ifndef MX1_INT_USBD0
-#define MX1_INT_USBD0 MX1_USBD_INT0
-#endif
-
-static irqreturn_t imx_udc_bulk_irq(int irq, void *dev)
-{
-       struct imx_udc_struct *imx_usb = dev;
-       struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[irq - MX1_INT_USBD0];
-       int intr = __raw_readl(imx_usb->base + USB_EP_INTR(EP_NO(imx_ep)));
-
-       dump_ep_intr(__func__, irq - MX1_INT_USBD0, intr, imx_usb->dev);
-
-       if (!imx_usb->driver) {
-               __raw_writel(intr, imx_usb->base + USB_EP_INTR(EP_NO(imx_ep)));
-               return IRQ_HANDLED;
-       }
-
-       handle_ep(imx_ep);
-
-       __raw_writel(intr, imx_usb->base + USB_EP_INTR(EP_NO(imx_ep)));
-
-       return IRQ_HANDLED;
-}
-
-irq_handler_t intr_handler(int i)
-{
-       switch (i) {
-       case 0:
-               return imx_udc_ctrl_irq;
-       case 1:
-       case 2:
-       case 3:
-       case 4:
-       case 5:
-               return imx_udc_bulk_irq;
-       default:
-               return imx_udc_irq;
-       }
-}
-
-/*******************************************************************************
- * Static defined IMX UDC structure
- *******************************************************************************
- */
-
-static int imx_udc_start(struct usb_gadget *gadget,
-               struct usb_gadget_driver *driver);
-static int imx_udc_stop(struct usb_gadget *gadget,
-               struct usb_gadget_driver *driver);
-static const struct usb_gadget_ops imx_udc_ops = {
-       .get_frame      = imx_udc_get_frame,
-       .wakeup         = imx_udc_wakeup,
-       .udc_start      = imx_udc_start,
-       .udc_stop       = imx_udc_stop,
-};
-
-static struct imx_udc_struct controller = {
-       .gadget = {
-               .ops            = &imx_udc_ops,
-               .ep0            = &controller.imx_ep[0].ep,
-               .name           = driver_name,
-               .dev = {
-                       .init_name      = "gadget",
-               },
-       },
-
-       .imx_ep[0] = {
-               .ep = {
-                       .name           = ep0name,
-                       .ops            = &imx_ep_ops,
-                       .maxpacket      = 32,
-               },
-               .imx_usb                = &controller,
-               .fifosize               = 32,
-               .bEndpointAddress       = 0,
-               .bmAttributes           = USB_ENDPOINT_XFER_CONTROL,
-        },
-       .imx_ep[1] = {
-               .ep = {
-                       .name           = "ep1in-bulk",
-                       .ops            = &imx_ep_ops,
-                       .maxpacket      = 64,
-               },
-               .imx_usb                = &controller,
-               .fifosize               = 64,
-               .bEndpointAddress       = USB_DIR_IN | 1,
-               .bmAttributes           = USB_ENDPOINT_XFER_BULK,
-        },
-       .imx_ep[2] = {
-               .ep = {
-                       .name           = "ep2out-bulk",
-                       .ops            = &imx_ep_ops,
-                       .maxpacket      = 64,
-               },
-               .imx_usb                = &controller,
-               .fifosize               = 64,
-               .bEndpointAddress       = USB_DIR_OUT | 2,
-               .bmAttributes           = USB_ENDPOINT_XFER_BULK,
-        },
-       .imx_ep[3] = {
-               .ep = {
-                       .name           = "ep3out-bulk",
-                       .ops            = &imx_ep_ops,
-                       .maxpacket      = 32,
-               },
-               .imx_usb                = &controller,
-               .fifosize               = 32,
-               .bEndpointAddress       = USB_DIR_OUT | 3,
-               .bmAttributes           = USB_ENDPOINT_XFER_BULK,
-        },
-       .imx_ep[4] = {
-               .ep = {
-                       .name           = "ep4in-int",
-                       .ops            = &imx_ep_ops,
-                       .maxpacket      = 32,
-                },
-               .imx_usb                = &controller,
-               .fifosize               = 32,
-               .bEndpointAddress       = USB_DIR_IN | 4,
-               .bmAttributes           = USB_ENDPOINT_XFER_INT,
-        },
-       .imx_ep[5] = {
-               .ep = {
-                       .name           = "ep5out-int",
-                       .ops            = &imx_ep_ops,
-                       .maxpacket      = 32,
-               },
-               .imx_usb                = &controller,
-               .fifosize               = 32,
-               .bEndpointAddress       = USB_DIR_OUT | 5,
-               .bmAttributes           = USB_ENDPOINT_XFER_INT,
-        },
-};
-
-/*******************************************************************************
- * USB gadget driver functions
- *******************************************************************************
- */
-static int imx_udc_start(struct usb_gadget *gadget,
-               struct usb_gadget_driver *driver)
-{
-       struct imx_udc_struct *imx_usb;
-
-       imx_usb = container_of(gadget, struct imx_udc_struct, gadget);
-       /* first hook up the driver ... */
-       imx_usb->driver = driver;
-
-       D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n",
-               __func__, driver->driver.name);
-
-       imx_udc_enable(imx_usb);
-
-       return 0;
-}
-
-static int imx_udc_stop(struct usb_gadget *gadget,
-               struct usb_gadget_driver *driver)
-{
-       struct imx_udc_struct *imx_usb = container_of(gadget,
-                       struct imx_udc_struct, gadget);
-
-       udc_stop_activity(imx_usb, driver);
-       imx_udc_disable(imx_usb);
-       del_timer(&imx_usb->timer);
-
-       imx_usb->driver = NULL;
-
-       D_INI(imx_usb->dev, "<%s> unregistered gadget driver '%s'\n",
-               __func__, driver->driver.name);
-
-       return 0;
-}
-
-/*******************************************************************************
- * Module functions
- *******************************************************************************
- */
-
-static int __init imx_udc_probe(struct platform_device *pdev)
-{
-       struct imx_udc_struct *imx_usb = &controller;
-       struct resource *res;
-       struct imxusb_platform_data *pdata;
-       struct clk *clk;
-       void __iomem *base;
-       int ret = 0;
-       int i;
-       resource_size_t res_size;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "can't get device resources\n");
-               return -ENODEV;
-       }
-
-       pdata = pdev->dev.platform_data;
-       if (!pdata) {
-               dev_err(&pdev->dev, "driver needs platform data\n");
-               return -ENODEV;
-       }
-
-       res_size = resource_size(res);
-       if (!request_mem_region(res->start, res_size, res->name)) {
-               dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n",
-                       res_size, res->start);
-               return -ENOMEM;
-       }
-
-       if (pdata->init) {
-               ret = pdata->init(&pdev->dev);
-               if (ret)
-                       goto fail0;
-       }
-
-       base = ioremap(res->start, res_size);
-       if (!base) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               ret = -EIO;
-               goto fail1;
-       }
-
-       clk = clk_get(NULL, "usbd_clk");
-       if (IS_ERR(clk)) {
-               ret = PTR_ERR(clk);
-               dev_err(&pdev->dev, "can't get USB clock\n");
-               goto fail2;
-       }
-       clk_prepare_enable(clk);
-
-       if (clk_get_rate(clk) != 48000000) {
-               D_INI(&pdev->dev,
-                       "Bad USB clock (%d Hz), changing to 48000000 Hz\n",
-                       (int)clk_get_rate(clk));
-               if (clk_set_rate(clk, 48000000)) {
-                       dev_err(&pdev->dev,
-                               "Unable to set correct USB clock (48MHz)\n");
-                       ret = -EIO;
-                       goto fail3;
-               }
-       }
-
-       for (i = 0; i < IMX_USB_NB_EP + 1; i++) {
-               imx_usb->usbd_int[i] = platform_get_irq(pdev, i);
-               if (imx_usb->usbd_int[i] < 0) {
-                       dev_err(&pdev->dev, "can't get irq number\n");
-                       ret = -ENODEV;
-                       goto fail3;
-               }
-       }
-
-       for (i = 0; i < IMX_USB_NB_EP + 1; i++) {
-               ret = request_irq(imx_usb->usbd_int[i], intr_handler(i),
-                                    0, driver_name, imx_usb);
-               if (ret) {
-                       dev_err(&pdev->dev, "can't get irq %i, err %d\n",
-                               imx_usb->usbd_int[i], ret);
-                       for (--i; i >= 0; i--)
-                               free_irq(imx_usb->usbd_int[i], imx_usb);
-                       goto fail3;
-               }
-       }
-
-       imx_usb->res = res;
-       imx_usb->base = base;
-       imx_usb->clk = clk;
-       imx_usb->dev = &pdev->dev;
-
-       platform_set_drvdata(pdev, imx_usb);
-
-       usb_init_data(imx_usb);
-       imx_udc_init(imx_usb);
-
-       init_timer(&imx_usb->timer);
-       imx_usb->timer.function = handle_config;
-       imx_usb->timer.data = (unsigned long)imx_usb;
-
-       ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget);
-       if (ret)
-               goto fail4;
-
-       return 0;
-fail4:
-       for (i = 0; i < IMX_USB_NB_EP + 1; i++)
-               free_irq(imx_usb->usbd_int[i], imx_usb);
-fail3:
-       clk_put(clk);
-       clk_disable_unprepare(clk);
-fail2:
-       iounmap(base);
-fail1:
-       if (pdata->exit)
-               pdata->exit(&pdev->dev);
-fail0:
-       release_mem_region(res->start, res_size);
-       return ret;
-}
-
-static int __exit imx_udc_remove(struct platform_device *pdev)
-{
-       struct imx_udc_struct *imx_usb = platform_get_drvdata(pdev);
-       struct imxusb_platform_data *pdata = pdev->dev.platform_data;
-       int i;
-
-       usb_del_gadget_udc(&imx_usb->gadget);
-       imx_udc_disable(imx_usb);
-       del_timer(&imx_usb->timer);
-
-       for (i = 0; i < IMX_USB_NB_EP + 1; i++)
-               free_irq(imx_usb->usbd_int[i], imx_usb);
-
-       clk_put(imx_usb->clk);
-       clk_disable_unprepare(imx_usb->clk);
-       iounmap(imx_usb->base);
-
-       release_mem_region(imx_usb->res->start, resource_size(imx_usb->res));
-
-       if (pdata->exit)
-               pdata->exit(&pdev->dev);
-
-       return 0;
-}
-
-/*----------------------------------------------------------------------------*/
-
-#ifdef CONFIG_PM
-#define        imx_udc_suspend NULL
-#define        imx_udc_resume  NULL
-#else
-#define        imx_udc_suspend NULL
-#define        imx_udc_resume  NULL
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-static struct platform_driver udc_driver = {
-       .driver         = {
-               .name   = driver_name,
-               .owner  = THIS_MODULE,
-       },
-       .remove         = __exit_p(imx_udc_remove),
-       .suspend        = imx_udc_suspend,
-       .resume         = imx_udc_resume,
-};
-
-module_platform_driver_probe(udc_driver, imx_udc_probe);
-
-MODULE_DESCRIPTION("IMX USB Device Controller driver");
-MODULE_AUTHOR("Darius Augulis <augulis.darius@gmail.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx_udc");
diff --git a/drivers/usb/gadget/imx_udc.h b/drivers/usb/gadget/imx_udc.h
deleted file mode 100644 (file)
index d118fb7..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- *     Copyright (C) 2005 Mike Lee(eemike@gmail.com)
- *
- *     This udc driver is now under testing and code is based on pxa2xx_udc.h
- *     Please use it with your own risk!
- *
- *     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.
- */
-
-#ifndef __LINUX_USB_GADGET_IMX_H
-#define __LINUX_USB_GADGET_IMX_H
-
-#include <linux/types.h>
-
-/* Helper macros */
-#define EP_NO(ep)      ((ep->bEndpointAddress) & ~USB_DIR_IN) /* IN:1, OUT:0 */
-#define EP_DIR(ep)     ((ep->bEndpointAddress) & USB_DIR_IN ? 1 : 0)
-#define IMX_USB_NB_EP  6
-
-/* Driver structures */
-struct imx_request {
-       struct usb_request                      req;
-       struct list_head                        queue;
-       unsigned int                            in_use;
-};
-
-enum ep0_state {
-       EP0_IDLE,
-       EP0_IN_DATA_PHASE,
-       EP0_OUT_DATA_PHASE,
-       EP0_CONFIG,
-       EP0_STALL,
-};
-
-struct imx_ep_struct {
-       struct usb_ep                           ep;
-       struct imx_udc_struct                   *imx_usb;
-       struct list_head                        queue;
-       unsigned char                           stopped;
-       unsigned char                           fifosize;
-       unsigned char                           bEndpointAddress;
-       unsigned char                           bmAttributes;
-};
-
-struct imx_udc_struct {
-       struct usb_gadget                       gadget;
-       struct usb_gadget_driver                *driver;
-       struct device                           *dev;
-       struct imx_ep_struct                    imx_ep[IMX_USB_NB_EP];
-       struct clk                              *clk;
-       struct timer_list                       timer;
-       enum ep0_state                          ep0state;
-       struct resource                         *res;
-       void __iomem                            *base;
-       unsigned char                           set_config;
-       int                                     cfg,
-                                               intf,
-                                               alt,
-                                               usbd_int[7];
-};
-
-/* USB registers */
-#define  USB_FRAME             (0x00)  /* USB frame */
-#define  USB_SPEC              (0x04)  /* USB Spec */
-#define  USB_STAT              (0x08)  /* USB Status */
-#define  USB_CTRL              (0x0C)  /* USB Control */
-#define  USB_DADR              (0x10)  /* USB Desc RAM addr */
-#define  USB_DDAT              (0x14)  /* USB Desc RAM/EP buffer data */
-#define  USB_INTR              (0x18)  /* USB interrupt */
-#define  USB_MASK              (0x1C)  /* USB Mask */
-#define  USB_ENAB              (0x24)  /* USB Enable */
-#define  USB_EP_STAT(x)                (0x30 + (x*0x30)) /* USB status/control */
-#define  USB_EP_INTR(x)                (0x34 + (x*0x30)) /* USB interrupt */
-#define  USB_EP_MASK(x)                (0x38 + (x*0x30)) /* USB mask */
-#define  USB_EP_FDAT(x)                (0x3C + (x*0x30)) /* USB FIFO data */
-#define  USB_EP_FDAT0(x)       (0x3C + (x*0x30)) /* USB FIFO data */
-#define  USB_EP_FDAT1(x)       (0x3D + (x*0x30)) /* USB FIFO data */
-#define  USB_EP_FDAT2(x)       (0x3E + (x*0x30)) /* USB FIFO data */
-#define  USB_EP_FDAT3(x)       (0x3F + (x*0x30)) /* USB FIFO data */
-#define  USB_EP_FSTAT(x)       (0x40 + (x*0x30)) /* USB FIFO status */
-#define  USB_EP_FCTRL(x)       (0x44 + (x*0x30)) /* USB FIFO control */
-#define  USB_EP_LRFP(x)                (0x48 + (x*0x30)) /* USB last rd f. pointer */
-#define  USB_EP_LWFP(x)                (0x4C + (x*0x30)) /* USB last wr f. pointer */
-#define  USB_EP_FALRM(x)       (0x50 + (x*0x30)) /* USB FIFO alarm */
-#define  USB_EP_FRDP(x)                (0x54 + (x*0x30)) /* USB FIFO read pointer */
-#define  USB_EP_FWRP(x)                (0x58 + (x*0x30)) /* USB FIFO write pointer */
-/* USB Control Register Bit Fields.*/
-#define CTRL_CMDOVER           (1<<6)  /* UDC status */
-#define CTRL_CMDERROR          (1<<5)  /* UDC status */
-#define CTRL_FE_ENA            (1<<3)  /* Enable Font End logic */
-#define CTRL_UDC_RST           (1<<2)  /* UDC reset */
-#define CTRL_AFE_ENA           (1<<1)  /* Analog Font end enable */
-#define CTRL_RESUME            (1<<0)  /* UDC resume */
-/* USB Status Register Bit Fields.*/
-#define STAT_RST               (1<<8)
-#define STAT_SUSP              (1<<7)
-#define STAT_CFG               (3<<5)
-#define STAT_INTF              (3<<3)
-#define STAT_ALTSET            (7<<0)
-/* USB Interrupt Status/Mask Registers Bit fields */
-#define INTR_WAKEUP            (1<<31) /* Wake up Interrupt */
-#define INTR_MSOF              (1<<7)  /* Missed Start of Frame */
-#define INTR_SOF               (1<<6)  /* Start of Frame */
-#define INTR_RESET_STOP                (1<<5)  /* Reset Signaling stop */
-#define INTR_RESET_START       (1<<4)  /* Reset Signaling start */
-#define INTR_RESUME            (1<<3)  /* Suspend to resume */
-#define INTR_SUSPEND           (1<<2)  /* Active to suspend */
-#define INTR_FRAME_MATCH       (1<<1)  /* Frame matched */
-#define INTR_CFG_CHG           (1<<0)  /* Configuration change occurred */
-/* USB Enable Register Bit Fields.*/
-#define ENAB_RST               (1<<31) /* Reset USB modules */
-#define ENAB_ENAB              (1<<30) /* Enable USB modules*/
-#define ENAB_SUSPEND           (1<<29) /* Suspend USB modules */
-#define ENAB_ENDIAN            (1<<28) /* Endian of USB modules */
-#define ENAB_PWRMD             (1<<0)  /* Power mode of USB modules */
-/* USB Descriptor Ram Address Register bit fields */
-#define DADR_CFG               (1<<31) /* Configuration */
-#define DADR_BSY               (1<<30) /* Busy status */
-#define DADR_DADR              (0x1FF) /* Descriptor Ram Address */
-/* USB Descriptor RAM/Endpoint Buffer Data Register bit fields */
-#define DDAT_DDAT              (0xFF)  /* Descriptor Endpoint Buffer */
-/* USB Endpoint Status Register bit fields */
-#define EPSTAT_BCOUNT          (0x7F<<16)      /* Endpoint FIFO byte count */
-#define EPSTAT_SIP             (1<<8)  /* Endpoint setup in progress */
-#define EPSTAT_DIR             (1<<7)  /* Endpoint transfer direction */
-#define EPSTAT_MAX             (3<<5)  /* Endpoint Max packet size */
-#define EPSTAT_TYP             (3<<3)  /* Endpoint type */
-#define EPSTAT_ZLPS            (1<<2)  /* Send zero length packet */
-#define EPSTAT_FLUSH           (1<<1)  /* Endpoint FIFO Flush */
-#define EPSTAT_STALL           (1<<0)  /* Force stall */
-/* USB Endpoint FIFO Status Register bit fields */
-#define FSTAT_FRAME_STAT       (0xF<<24)       /* Frame status bit [0-3] */
-#define FSTAT_ERR              (1<<22) /* FIFO error */
-#define FSTAT_UF               (1<<21) /* FIFO underflow */
-#define FSTAT_OF               (1<<20) /* FIFO overflow */
-#define FSTAT_FR               (1<<19) /* FIFO frame ready */
-#define FSTAT_FULL             (1<<18) /* FIFO full */
-#define FSTAT_ALRM             (1<<17) /* FIFO alarm */
-#define FSTAT_EMPTY            (1<<16) /* FIFO empty */
-/* USB Endpoint FIFO Control Register bit fields */
-#define FCTRL_WFR              (1<<29) /* Write frame end */
-/* USB Endpoint Interrupt Status Regsiter bit fields */
-#define EPINTR_FIFO_FULL       (1<<8)  /* fifo full */
-#define EPINTR_FIFO_EMPTY      (1<<7)  /* fifo empty */
-#define EPINTR_FIFO_ERROR      (1<<6)  /* fifo error */
-#define EPINTR_FIFO_HIGH       (1<<5)  /* fifo high */
-#define EPINTR_FIFO_LOW                (1<<4)  /* fifo low */
-#define EPINTR_MDEVREQ         (1<<3)  /* multi Device request */
-#define EPINTR_EOT             (1<<2)  /* fifo end of transfer */
-#define EPINTR_DEVREQ          (1<<1)  /* Device request */
-#define EPINTR_EOF             (1<<0)  /* fifo end of frame */
-
-/* Debug macros */
-#ifdef DEBUG
-
-/* #define DEBUG_REQ */
-/* #define DEBUG_TRX */
-/* #define DEBUG_INIT */
-/* #define DEBUG_EP0 */
-/* #define DEBUG_EPX */
-/* #define DEBUG_IRQ */
-/* #define DEBUG_EPIRQ */
-/* #define DEBUG_DUMP */
-/* #define DEBUG_ERR */
-
-#ifdef DEBUG_REQ
-       #define D_REQ(dev, args...)     dev_dbg(dev, ## args)
-#else
-       #define D_REQ(dev, args...)     do {} while (0)
-#endif /* DEBUG_REQ */
-
-#ifdef DEBUG_TRX
-       #define D_TRX(dev, args...)     dev_dbg(dev, ## args)
-#else
-       #define D_TRX(dev, args...)     do {} while (0)
-#endif /* DEBUG_TRX */
-
-#ifdef DEBUG_INIT
-       #define D_INI(dev, args...)     dev_dbg(dev, ## args)
-#else
-       #define D_INI(dev, args...)     do {} while (0)
-#endif /* DEBUG_INIT */
-
-#ifdef DEBUG_EP0
-       static const char *state_name[] = {
-               "EP0_IDLE",
-               "EP0_IN_DATA_PHASE",
-               "EP0_OUT_DATA_PHASE",
-               "EP0_CONFIG",
-               "EP0_STALL"
-       };
-       #define D_EP0(dev, args...)     dev_dbg(dev, ## args)
-#else
-       #define D_EP0(dev, args...)     do {} while (0)
-#endif /* DEBUG_EP0 */
-
-#ifdef DEBUG_EPX
-       #define D_EPX(dev, args...)     dev_dbg(dev, ## args)
-#else
-       #define D_EPX(dev, args...)     do {} while (0)
-#endif /* DEBUG_EP0 */
-
-#ifdef DEBUG_IRQ
-       static void dump_intr(const char *label, int irqreg, struct device *dev)
-       {
-               dev_dbg(dev, "<%s> USB_INTR=[%s%s%s%s%s%s%s%s%s]\n", label,
-                       (irqreg & INTR_WAKEUP) ? " wake" : "",
-                       (irqreg & INTR_MSOF) ? " msof" : "",
-                       (irqreg & INTR_SOF) ? " sof" : "",
-                       (irqreg & INTR_RESUME) ? " resume" : "",
-                       (irqreg & INTR_SUSPEND) ? " suspend" : "",
-                       (irqreg & INTR_RESET_STOP) ? " noreset" : "",
-                       (irqreg & INTR_RESET_START) ? " reset" : "",
-                       (irqreg & INTR_FRAME_MATCH) ? " fmatch" : "",
-                       (irqreg & INTR_CFG_CHG) ? " config" : "");
-       }
-#else
-       #define dump_intr(x, y, z)              do {} while (0)
-#endif /* DEBUG_IRQ */
-
-#ifdef DEBUG_EPIRQ
-       static void dump_ep_intr(const char *label, int nr, int irqreg,
-                                                       struct device *dev)
-       {
-               dev_dbg(dev, "<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n", label, nr,
-                       (irqreg & EPINTR_FIFO_FULL) ? " full" : "",
-                       (irqreg & EPINTR_FIFO_EMPTY) ? " fempty" : "",
-                       (irqreg & EPINTR_FIFO_ERROR) ? " ferr" : "",
-                       (irqreg & EPINTR_FIFO_HIGH) ? " fhigh" : "",
-                       (irqreg & EPINTR_FIFO_LOW) ? " flow" : "",
-                       (irqreg & EPINTR_MDEVREQ) ? " mreq" : "",
-                       (irqreg & EPINTR_EOF) ? " eof" : "",
-                       (irqreg & EPINTR_DEVREQ) ? " devreq" : "",
-                       (irqreg & EPINTR_EOT) ? " eot" : "");
-       }
-#else
-       #define dump_ep_intr(x, y, z, i)        do {} while (0)
-#endif /* DEBUG_IRQ */
-
-#ifdef DEBUG_DUMP
-       static void dump_usb_stat(const char *label,
-                                               struct imx_udc_struct *imx_usb)
-       {
-               int temp = __raw_readl(imx_usb->base + USB_STAT);
-
-               dev_dbg(imx_usb->dev,
-                       "<%s> USB_STAT=[%s%s CFG=%d, INTF=%d, ALTR=%d]\n", label,
-                       (temp & STAT_RST) ? " reset" : "",
-                       (temp & STAT_SUSP) ? " suspend" : "",
-                       (temp & STAT_CFG) >> 5,
-                       (temp & STAT_INTF) >> 3,
-                       (temp & STAT_ALTSET));
-       }
-
-       static void dump_ep_stat(const char *label,
-                                               struct imx_ep_struct *imx_ep)
-       {
-               int temp = __raw_readl(imx_ep->imx_usb->base
-                                               + USB_EP_INTR(EP_NO(imx_ep)));
-
-               dev_dbg(imx_ep->imx_usb->dev,
-                       "<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n",
-                       label, EP_NO(imx_ep),
-                       (temp & EPINTR_FIFO_FULL) ? " full" : "",
-                       (temp & EPINTR_FIFO_EMPTY) ? " fempty" : "",
-                       (temp & EPINTR_FIFO_ERROR) ? " ferr" : "",
-                       (temp & EPINTR_FIFO_HIGH) ? " fhigh" : "",
-                       (temp & EPINTR_FIFO_LOW) ? " flow" : "",
-                       (temp & EPINTR_MDEVREQ) ? " mreq" : "",
-                       (temp & EPINTR_EOF) ? " eof" : "",
-                       (temp & EPINTR_DEVREQ) ? " devreq" : "",
-                       (temp & EPINTR_EOT) ? " eot" : "");
-
-               temp = __raw_readl(imx_ep->imx_usb->base
-                                               + USB_EP_STAT(EP_NO(imx_ep)));
-
-               dev_dbg(imx_ep->imx_usb->dev,
-                       "<%s> EP%d_STAT=[%s%s bcount=%d]\n",
-                       label, EP_NO(imx_ep),
-                       (temp & EPSTAT_SIP) ? " sip" : "",
-                       (temp & EPSTAT_STALL) ? " stall" : "",
-                       (temp & EPSTAT_BCOUNT) >> 16);
-
-               temp = __raw_readl(imx_ep->imx_usb->base
-                                               + USB_EP_FSTAT(EP_NO(imx_ep)));
-
-               dev_dbg(imx_ep->imx_usb->dev,
-                       "<%s> EP%d_FSTAT=[%s%s%s%s%s%s%s]\n",
-                       label, EP_NO(imx_ep),
-                       (temp & FSTAT_ERR) ? " ferr" : "",
-                       (temp & FSTAT_UF) ? " funder" : "",
-                       (temp & FSTAT_OF) ? " fover" : "",
-                       (temp & FSTAT_FR) ? " fready" : "",
-                       (temp & FSTAT_FULL) ? " ffull" : "",
-                       (temp & FSTAT_ALRM) ? " falarm" : "",
-                       (temp & FSTAT_EMPTY) ? " fempty" : "");
-       }
-
-       static void dump_req(const char *label, struct imx_ep_struct *imx_ep,
-                                                       struct usb_request *req)
-       {
-               int i;
-
-               if (!req || !req->buf) {
-                       dev_dbg(imx_ep->imx_usb->dev,
-                                       "<%s> req or req buf is free\n", label);
-                       return;
-               }
-
-               if ((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state
-                       == EP0_IN_DATA_PHASE)
-                       || (EP_NO(imx_ep) && EP_DIR(imx_ep))) {
-
-                       dev_dbg(imx_ep->imx_usb->dev,
-                                               "<%s> request dump <", label);
-                       for (i = 0; i < req->length; i++)
-                               printk("%02x-", *((u8 *)req->buf + i));
-                       printk(">\n");
-               }
-       }
-
-#else
-       #define dump_ep_stat(x, y)              do {} while (0)
-       #define dump_usb_stat(x, y)             do {} while (0)
-       #define dump_req(x, y, z)               do {} while (0)
-#endif /* DEBUG_DUMP */
-
-#ifdef DEBUG_ERR
-       #define D_ERR(dev, args...)     dev_dbg(dev, ## args)
-#else
-       #define D_ERR(dev, args...)     do {} while (0)
-#endif
-
-#else
-       #define D_REQ(dev, args...)             do {} while (0)
-       #define D_TRX(dev, args...)             do {} while (0)
-       #define D_INI(dev, args...)             do {} while (0)
-       #define D_EP0(dev, args...)             do {} while (0)
-       #define D_EPX(dev, args...)             do {} while (0)
-       #define dump_ep_intr(x, y, z, i)        do {} while (0)
-       #define dump_intr(x, y, z)              do {} while (0)
-       #define dump_ep_stat(x, y)              do {} while (0)
-       #define dump_usb_stat(x, y)             do {} while (0)
-       #define dump_req(x, y, z)               do {} while (0)
-       #define D_ERR(dev, args...)             do {} while (0)
-#endif /* DEBUG */
-
-#endif /* __LINUX_USB_GADGET_IMX_H */
index 46ba9838c3a091d084af2472cd39ada76e42ac71..d5f050d30edfe7c917bbb6c09cfc3a4082404f7e 100644 (file)
@@ -1584,7 +1584,7 @@ static int __init m66592_probe(struct platform_device *pdev)
                goto clean_up;
        }
 
-       if (pdev->dev.platform_data == NULL) {
+       if (dev_get_platdata(&pdev->dev) == NULL) {
                dev_err(&pdev->dev, "no platform data\n");
                ret = -ENODEV;
                goto clean_up;
@@ -1598,7 +1598,7 @@ static int __init m66592_probe(struct platform_device *pdev)
                goto clean_up;
        }
 
-       m66592->pdata = pdev->dev.platform_data;
+       m66592->pdata = dev_get_platdata(&pdev->dev);
        m66592->irq_trigger = ires->flags & IRQF_TRIGGER_MASK;
 
        spin_lock_init(&m66592->lock);
index ec6a2d2903988ffb7a23aa12b63b0f95fd4f601a..bbb6e98c4384292d3446b62f8671decaf0a51c55 100644 (file)
@@ -1109,7 +1109,7 @@ static int mv_u3d_controller_reset(struct mv_u3d *u3d)
 
 static int mv_u3d_enable(struct mv_u3d *u3d)
 {
-       struct mv_usb_platform_data *pdata = u3d->dev->platform_data;
+       struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev);
        int retval;
 
        if (u3d->active)
@@ -1138,7 +1138,7 @@ static int mv_u3d_enable(struct mv_u3d *u3d)
 
 static void mv_u3d_disable(struct mv_u3d *u3d)
 {
-       struct mv_usb_platform_data *pdata = u3d->dev->platform_data;
+       struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev);
        if (u3d->clock_gating && u3d->active) {
                dev_dbg(u3d->dev, "disable u3d\n");
                if (pdata->phy_deinit)
@@ -1246,7 +1246,7 @@ 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;
+       struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev);
        unsigned long flags;
 
        if (u3d->driver)
@@ -1277,7 +1277,7 @@ 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;
+       struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev);
        unsigned long flags;
 
        u3d->vbus_valid_detect = 0;
@@ -1794,12 +1794,12 @@ static int mv_u3d_remove(struct platform_device *dev)
 static int mv_u3d_probe(struct platform_device *dev)
 {
        struct mv_u3d *u3d = NULL;
-       struct mv_usb_platform_data *pdata = dev->dev.platform_data;
+       struct mv_usb_platform_data *pdata = dev_get_platdata(&dev->dev);
        int retval = 0;
        struct resource *r;
        size_t size;
 
-       if (!dev->dev.platform_data) {
+       if (!dev_get_platdata(&dev->dev)) {
                dev_err(&dev->dev, "missing platform_data\n");
                retval = -ENODEV;
                goto err_pdata;
index c2a57023e4671ccbb5a9e7f8930fecb67226901a..104cdbea635a6aee2ad169981382e37074ff141d 100644 (file)
@@ -2100,7 +2100,7 @@ static int mv_udc_remove(struct platform_device *pdev)
 
 static int mv_udc_probe(struct platform_device *pdev)
 {
-       struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
+       struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct mv_udc *udc;
        int retval = 0;
        struct resource *r;
@@ -2118,7 +2118,7 @@ static int mv_udc_probe(struct platform_device *pdev)
        }
 
        udc->done = &release_done;
-       udc->pdata = pdev->dev.platform_data;
+       udc->pdata = dev_get_platdata(&pdev->dev);
        spin_lock_init(&udc->lock);
 
        udc->dev = pdev;
index b8ed74a823cbb41c6f585fe422483905fc2567ea..83957cc225d982e9aba26ab717820c34b82a1308 100644 (file)
@@ -2734,7 +2734,7 @@ static int omap_udc_probe(struct platform_device *pdev)
        int                     hmc;
        struct usb_phy          *xceiv = NULL;
        const char              *type = NULL;
-       struct omap_usb_config  *config = pdev->dev.platform_data;
+       struct omap_usb_config  *config = dev_get_platdata(&pdev->dev);
        struct clk              *dc_clk = NULL;
        struct clk              *hhc_clk = NULL;
 
index 95c531d5aa4fa2dd9fcf4d038c5426254cb16629..cc9207473dbc33f204bbd4009eb9e2138f966da6 100644 (file)
@@ -2117,7 +2117,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
 
        /* other non-static parts of init */
        dev->dev = &pdev->dev;
-       dev->mach = pdev->dev.platform_data;
+       dev->mach = dev_get_platdata(&pdev->dev);
 
        dev->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
 
index 41cea9566ac8bba0e194dc8b2f55668fa1d1707e..3c97da7760dac4d75797954398082866ebb56ff9 100644 (file)
@@ -2422,7 +2422,7 @@ static int pxa_udc_probe(struct platform_device *pdev)
                return udc->irq;
 
        udc->dev = &pdev->dev;
-       udc->mach = pdev->dev.platform_data;
+       udc->mach = dev_get_platdata(&pdev->dev);
        udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
 
        gpio = udc->mach->gpio_pullup;
index c6af649f324008bb31706baecac5d91497a27cd7..68be48d3340411c9e91632e19dd15ec4fd3cbfe1 100644 (file)
@@ -1910,7 +1910,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
 
        spin_lock_init(&r8a66597->lock);
        platform_set_drvdata(pdev, r8a66597);
-       r8a66597->pdata = pdev->dev.platform_data;
+       r8a66597->pdata = dev_get_platdata(&pdev->dev);
        r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
 
        r8a66597->gadget.ops = &r8a66597_gadget_ops;
index 3e3ea720303043c4df215143eb926f20179bb1d9..9575085ded8112e05eddda04a60d52231b1f0a02 100644 (file)
@@ -1142,7 +1142,7 @@ static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
 #endif /* CONFIG_USB_GADGET_DEBUG_FILES */
 
 
-int rndis_init(void)
+static int rndis_init(void)
 {
        u8 i;
 
@@ -1176,7 +1176,7 @@ int rndis_init(void)
 }
 module_init(rndis_init);
 
-void rndis_exit(void)
+static void rndis_exit(void)
 {
 #ifdef CONFIG_USB_GADGET_DEBUG_FILES
        u8 i;
index af22f24046b239dcc9dda8553c17377326c62ded..d69b36a99dbcd8ae5a1bc57275398be86a2562ca 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/regulator/consumer.h>
+#include <linux/of_platform.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
@@ -3450,7 +3451,7 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
 
 static int s3c_hsotg_probe(struct platform_device *pdev)
 {
-       struct s3c_hsotg_plat *plat = pdev->dev.platform_data;
+       struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev);
        struct usb_phy *phy;
        struct device *dev = &pdev->dev;
        struct s3c_hsotg_ep *eps;
@@ -3469,7 +3470,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
        phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
        if (IS_ERR(phy)) {
                /* Fallback for pdata */
-               plat = pdev->dev.platform_data;
+               plat = dev_get_platdata(&pdev->dev);
                if (!plat) {
                        dev_err(&pdev->dev, "no platform data or transceiver defined\n");
                        return -EPROBE_DEFER;
@@ -3648,10 +3649,19 @@ static int s3c_hsotg_remove(struct platform_device *pdev)
 #define s3c_hsotg_resume NULL
 #endif
 
+#ifdef CONFIG_OF
+static const struct of_device_id s3c_hsotg_of_ids[] = {
+       { .compatible = "samsung,s3c6400-hsotg", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, s3c_hsotg_of_ids);
+#endif
+
 static struct platform_driver s3c_hsotg_driver = {
        .driver         = {
                .name   = "s3c-hsotg",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(s3c_hsotg_of_ids),
        },
        .probe          = s3c_hsotg_probe,
        .remove         = s3c_hsotg_remove,
index b1f0771fbd3def2b35714515c40f0c5b14fadc21..1a1a41498db20545264dbfbf46f930e5cd735b8d 100644 (file)
@@ -1262,7 +1262,7 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct resource *res;
        struct s3c_hsudc *hsudc;
-       struct s3c24xx_hsudc_platdata *pd = pdev->dev.platform_data;
+       struct s3c24xx_hsudc_platdata *pd = dev_get_platdata(&pdev->dev);
        int ret, i;
 
        hsudc = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsudc) +
@@ -1275,7 +1275,7 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, dev);
        hsudc->dev = dev;
-       hsudc->pd = pdev->dev.platform_data;
+       hsudc->pd = dev_get_platdata(&pdev->dev);
 
        hsudc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
 
index 09c4f70c93c4cb13639cf89ed7d423c2231df621..c72d810e6b36d7420ed6c28d774e79ebf30ab0d7 100644 (file)
@@ -1809,7 +1809,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
        }
 
        spin_lock_init(&udc->lock);
-       udc_info = pdev->dev.platform_data;
+       udc_info = dev_get_platdata(&pdev->dev);
 
        rsrc_start = S3C2410_PA_USBDEV;
        rsrc_len   = S3C24XX_SZ_USBDEV;
index dbce3a9074e6ebac353ec891ecc7c6726c5359b7..8c71212a8c524cbf4b494b0c8aaa9bd94b3c7186 100644 (file)
@@ -172,7 +172,7 @@ MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers");
  */
 #define fsg_num_buffers        CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
 
-#endif /* CONFIG_USB_DEBUG */
+#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
 
 /* check if fsg_num_buffers is within a valid range */
 static inline int fsg_num_buffers_validate(void)
index c7d460f43390da9dd5bfad40774f8c6b3fccf54d..7a55fea43430551b9f7d83d11cebe02a351ccf44 100644 (file)
@@ -191,7 +191,7 @@ try_again:
        frames = bytes_to_frames(runtime, count);
        old_fs = get_fs();
        set_fs(KERNEL_DS);
-       result = snd_pcm_lib_write(snd->substream, buf, frames);
+       result = snd_pcm_lib_write(snd->substream, (void __user *)buf, frames);
        if (result != frames) {
                ERROR(card, "Playback error: %d\n", (int)result);
                set_fs(old_fs);
index 13e25f80fc201f347784ace2f35c7003850f381a..546bfda3059a6b119935cbf273de9fd8fef1500e 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/list.h>
 #include <linux/err.h>
 #include <linux/dma-mapping.h>
+#include <linux/workqueue.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
@@ -105,11 +106,18 @@ EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
 
 /* ------------------------------------------------------------------------- */
 
+static void usb_gadget_state_work(struct work_struct *work)
+{
+       struct usb_gadget       *gadget = work_to_gadget(work);
+
+       sysfs_notify(&gadget->dev.kobj, NULL, "state");
+}
+
 void usb_gadget_set_state(struct usb_gadget *gadget,
                enum usb_device_state state)
 {
        gadget->state = state;
-       sysfs_notify(&gadget->dev.kobj, NULL, "state");
+       schedule_work(&gadget->work);
 }
 EXPORT_SYMBOL_GPL(usb_gadget_set_state);
 
@@ -196,6 +204,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
                goto err1;
 
        dev_set_name(&gadget->dev, "gadget");
+       INIT_WORK(&gadget->work, usb_gadget_state_work);
        gadget->dev.parent = parent;
 
 #ifdef CONFIG_HAS_DMA
@@ -315,6 +324,7 @@ found:
                usb_gadget_remove_driver(udc);
 
        kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
+       flush_work(&gadget->work);
        device_unregister(&udc->dev);
        device_unregister(&gadget->dev);
 }
index e6170478ea9f737b0a6eeec9a1a9524a5307db62..0bb5d50075de108ea3636d7973d9eda10984856b 100644 (file)
@@ -193,12 +193,16 @@ static int uvc_queue_buffer(struct uvc_video_queue *queue,
 
        mutex_lock(&queue->mutex);
        ret = vb2_qbuf(&queue->queue, buf);
+       if (ret < 0)
+               goto done;
+
        spin_lock_irqsave(&queue->irqlock, flags);
        ret = (queue->flags & UVC_QUEUE_PAUSED) != 0;
        queue->flags &= ~UVC_QUEUE_PAUSED;
        spin_unlock_irqrestore(&queue->irqlock, flags);
-       mutex_unlock(&queue->mutex);
 
+done:
+       mutex_unlock(&queue->mutex);
        return ret;
 }
 
index 4263d011392c08f752e8c00cf49e64da770115e4..5be0326aae38f602fd41a15a2c52a3d40db0ebbc 100644 (file)
@@ -29,15 +29,6 @@ if USB_XHCI_HCD
 config USB_XHCI_PLATFORM
        tristate
 
-config USB_XHCI_HCD_DEBUGGING
-       bool "Debugging for the xHCI host controller"
-       ---help---
-         Say 'Y' to turn on debugging for the xHCI host controller driver.
-         This will spew debugging output, even in interrupt context.
-         This should only be used for debugging xHCI driver bugs.
-
-         If unsure, say N.
-
 endif # USB_XHCI_HCD
 
 config USB_EHCI_HCD
@@ -113,12 +104,6 @@ config USB_EHCI_HCD_PMC_MSP
                Enables support for the onchip USB controller on the PMC_MSP7100 Family SoC's.
                If unsure, say N.
 
-config USB_EHCI_BIG_ENDIAN_MMIO
-       bool
-
-config USB_EHCI_BIG_ENDIAN_DESC
-       bool
-
 config XPS_USB_HCD_XILINX
        bool "Use Xilinx usb host EHCI controller core"
        depends on (PPC32 || MICROBLAZE)
@@ -148,13 +133,11 @@ config USB_EHCI_MXC
 config USB_EHCI_HCD_OMAP
        tristate "EHCI support for OMAP3 and later chips"
        depends on ARCH_OMAP
+       select NOP_USB_XCEIV
        default y
        ---help---
          Enables support for the on-chip EHCI controller on
          OMAP3 and later chips.
-         If your system uses a PHY on the USB port, you will need to
-         enable USB_PHY and the appropriate PHY driver as well. Most
-         boards need the NOP_USB_XCEIV PHY driver.
 
 config USB_EHCI_HCD_ORION
        tristate  "Support for Marvell EBU on-chip EHCI USB controller"
@@ -186,7 +169,6 @@ config USB_EHCI_HCD_AT91
 config USB_EHCI_MSM
        tristate "Support for Qualcomm QSD/MSM on-chip EHCI USB controller"
        depends on ARCH_MSM
-       depends on USB_PHY
        select USB_EHCI_ROOT_HUB_TT
        select USB_MSM_OTG
        ---help---
@@ -354,6 +336,18 @@ config USB_FUSBH200_HCD
        To compile this driver as a module, choose M here: the
        module will be called fusbh200-hcd.
 
+config USB_FOTG210_HCD
+       tristate "FOTG210 HCD support"
+       depends on USB
+       default N
+       ---help---
+         Faraday FOTG210 is an OTG controller which can be configured as
+         an USB2.0 host. It is designed to meet USB2.0 EHCI specification
+         with minor modification.
+
+         To compile this driver as a module, choose M here: the
+         module will be called fotg210-hcd.
+
 config USB_OHCI_HCD
        tristate "OHCI HCD (USB 1.1) support"
        select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
@@ -497,20 +491,6 @@ config USB_OCTEON_OHCI
          controller.  It is needed for low-speed USB 1.0 device
          support.  All CN6XXX based chips with USB are supported.
 
-
-config USB_OHCI_BIG_ENDIAN_DESC
-       bool
-       default n
-
-config USB_OHCI_BIG_ENDIAN_MMIO
-       bool
-       default n
-
-config USB_OHCI_LITTLE_ENDIAN
-       bool
-       default n if STB03xxx || PPC_MPC52xx
-       default y
-
 endif # USB_OHCI_HCD
 
 config USB_UHCI_HCD
@@ -710,3 +690,20 @@ config USB_HCD_SSB
          for ehci and ohci.
 
          If unsure, say N.
+
+config USB_HCD_TEST_MODE
+       bool "HCD test mode support"
+       ---help---
+         Say 'Y' to enable additional software test modes that may be
+         supported by the host controller drivers.
+
+         One such test mode is the Embedded High-speed Host Electrical Test
+         (EHSET) for EHCI host controller hardware, specifically the "Single
+         Step Set Feature" test.  Typically this will be enabled for On-the-Go
+         or embedded hosts that need to undergo USB-IF compliance testing with
+         the aid of special testing hardware.  In the future, this may expand
+         to include other tests that require support from a HCD driver.
+
+         This option is of interest only to developers who need to validate
+         their USB hardware designs.  It is not needed for normal use.  If
+         unsure, say N.
index bea71127b15f5f13d2423e44d41224ca11264499..50b0041c09a95464ed9ff353b090818e39d0112c 100644 (file)
@@ -4,6 +4,9 @@
 
 ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
 
+# tell define_trace.h where to find the xhci trace header
+CFLAGS_xhci-trace.o := -I$(src)
+
 isp1760-y := isp1760-hcd.o isp1760-if.o
 
 fhci-y := fhci-hcd.o fhci-hub.o fhci-q.o
@@ -13,6 +16,7 @@ fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o
 
 xhci-hcd-y := xhci.o xhci-mem.o
 xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
+xhci-hcd-y += xhci-trace.o
 xhci-hcd-$(CONFIG_PCI) += xhci-pci.o
 
 ifneq ($(CONFIG_USB_XHCI_PLATFORM), )
@@ -58,3 +62,4 @@ obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
 obj-$(CONFIG_USB_HCD_BCMA)     += bcma-hcd.o
 obj-$(CONFIG_USB_HCD_SSB)      += ssb-hcd.o
 obj-$(CONFIG_USB_FUSBH200_HCD) += fusbh200-hcd.o
+obj-$(CONFIG_USB_FOTG210_HCD)  += fotg210-hcd.o
index bd831ec06dcd8b8192749bc31d4afd137ab361bf..e44f442e2fb73b8ce6ce1a5bae0a884d9d540791 100644 (file)
@@ -57,7 +57,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
        pr_debug("initializing FSL-SOC USB Controller\n");
 
        /* Need platform data for setup */
-       pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data;
+       pdata = (struct fsl_usb2_platform_data *)dev_get_platdata(&pdev->dev);
        if (!pdata) {
                dev_err(&pdev->dev,
                        "No platform data for %s.\n", dev_name(&pdev->dev));
@@ -190,7 +190,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
 static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
                               struct platform_device *pdev)
 {
-       struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+       struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
        if (!IS_ERR_OR_NULL(hcd->phy)) {
                otg_set_host(hcd->phy->otg, NULL);
@@ -218,7 +218,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
        void __iomem *non_ehci = hcd->regs;
        struct device *dev = hcd->self.controller;
-       struct fsl_usb2_platform_data *pdata = dev->platform_data;
+       struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev);
 
        if (pdata->controller_ver < 0) {
                dev_warn(hcd->self.controller, "Could not get controller version\n");
@@ -291,7 +291,7 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
        struct fsl_usb2_platform_data *pdata;
        void __iomem *non_ehci = hcd->regs;
 
-       pdata = hcd->self.controller->platform_data;
+       pdata = dev_get_platdata(hcd->self.controller);
 
        if (pdata->have_sysif_regs) {
                /*
@@ -363,7 +363,7 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
        struct device *dev;
 
        dev = hcd->self.controller;
-       pdata = hcd->self.controller->platform_data;
+       pdata = dev_get_platdata(hcd->self.controller);
        ehci->big_endian_desc = pdata->big_endian_desc;
        ehci->big_endian_mmio = pdata->big_endian_mmio;
 
@@ -415,7 +415,7 @@ static int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
 {
        struct usb_hcd *hcd = dev_get_drvdata(dev);
        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-       struct fsl_usb2_platform_data *pdata = dev->platform_data;
+       struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev);
        u32 tmp;
 
 #ifdef DEBUG
@@ -484,7 +484,7 @@ static int ehci_fsl_mpc512x_drv_resume(struct device *dev)
 {
        struct usb_hcd *hcd = dev_get_drvdata(dev);
        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-       struct fsl_usb2_platform_data *pdata = dev->platform_data;
+       struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev);
        u32 tmp;
 
        dev_dbg(dev, "suspend=%d already_suspended=%d\n",
@@ -669,7 +669,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
         * generic hardware linkage
         */
        .irq = ehci_irq,
-       .flags = HCD_USB2 | HCD_MEMORY,
+       .flags = HCD_USB2 | HCD_MEMORY | HCD_BH,
 
        /*
         * basic lifecycle operations
index a77bd8dc33f42fe6662cd88b9b2fbb8f879a6aa2..b52a66ce92e8592b123239aa24b724dddfd085fa 100644 (file)
@@ -43,7 +43,7 @@ static const struct hc_driver ehci_grlib_hc_driver = {
         * generic hardware linkage
         */
        .irq                    = ehci_irq,
-       .flags                  = HCD_MEMORY | HCD_USB2,
+       .flags                  = HCD_MEMORY | HCD_USB2 | HCD_BH,
 
        /*
         * basic lifecycle operations
@@ -167,15 +167,6 @@ static int ehci_hcd_grlib_remove(struct platform_device *op)
 }
 
 
-static void ehci_hcd_grlib_shutdown(struct platform_device *op)
-{
-       struct usb_hcd *hcd = platform_get_drvdata(op);
-
-       if (hcd->driver->shutdown)
-               hcd->driver->shutdown(hcd);
-}
-
-
 static const struct of_device_id ehci_hcd_grlib_of_match[] = {
        {
                .name = "GAISLER_EHCI",
@@ -191,7 +182,7 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_grlib_of_match);
 static struct platform_driver ehci_grlib_driver = {
        .probe          = ehci_hcd_grlib_probe,
        .remove         = ehci_hcd_grlib_remove,
-       .shutdown       = ehci_hcd_grlib_shutdown,
+       .shutdown       = usb_hcd_platform_shutdown,
        .driver = {
                .name = "grlib-ehci",
                .owner = THIS_MODULE,
index 7abf1ce3a670ffeed76be2bcf1da9fccfcf63399..73c72997cd4f0c363ae386ecaf65b1609c99cc06 100644 (file)
@@ -487,6 +487,7 @@ static int ehci_init(struct usb_hcd *hcd)
        ehci->periodic_size = DEFAULT_I_TDPS;
        INIT_LIST_HEAD(&ehci->async_unlink);
        INIT_LIST_HEAD(&ehci->async_idle);
+       INIT_LIST_HEAD(&ehci->intr_unlink_wait);
        INIT_LIST_HEAD(&ehci->intr_unlink);
        INIT_LIST_HEAD(&ehci->intr_qh_list);
        INIT_LIST_HEAD(&ehci->cached_itd_list);
@@ -942,7 +943,7 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
        unsigned long           flags;
-       struct ehci_qh          *qh, *tmp;
+       struct ehci_qh          *qh;
 
        /* ASSERT:  any requests/urbs are being unlinked */
        /* ASSERT:  nobody can be submitting urbs for this any more */
@@ -972,17 +973,13 @@ rescan:
                qh->qh_state = QH_STATE_IDLE;
        switch (qh->qh_state) {
        case QH_STATE_LINKED:
-       case QH_STATE_COMPLETING:
-               for (tmp = ehci->async->qh_next.qh;
-                               tmp && tmp != qh;
-                               tmp = tmp->qh_next.qh)
-                       continue;
-               /* periodic qh self-unlinks on empty, and a COMPLETING qh
-                * may already be unlinked.
-                */
-               if (tmp)
+               WARN_ON(!list_empty(&qh->qtd_list));
+               if (usb_endpoint_type(&ep->desc) != USB_ENDPOINT_XFER_INT)
                        start_unlink_async(ehci, qh);
+               else
+                       start_unlink_intr(ehci, qh);
                /* FALL THROUGH */
+       case QH_STATE_COMPLETING:       /* already in unlinking */
        case QH_STATE_UNLINK:           /* wait for hw to finish? */
        case QH_STATE_UNLINK_WAIT:
 idle_timeout:
@@ -1169,7 +1166,7 @@ static const struct hc_driver ehci_hc_driver = {
         * generic hardware linkage
         */
        .irq =                  ehci_irq,
-       .flags =                HCD_MEMORY | HCD_USB2,
+       .flags =                HCD_MEMORY | HCD_USB2 | HCD_BH,
 
        /*
         * basic lifecycle operations
index 6dce37555c4f6303b5efa657af88096db2b2140e..3bf9f482710c1574999b3ad340c9a2e21ed19d32 100644 (file)
@@ -183,7 +183,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
        spin_lock_irq(&ehci->lock);
 
        /* clear phy low-power mode before changing wakeup flags */
-       if (ehci->has_hostpc) {
+       if (ehci->has_tdi_phy_lpm) {
                port = HCS_N_PORTS(ehci->hcs_params);
                while (port--) {
                        u32 __iomem     *hostpc_reg = &ehci->regs->hostpc[port];
@@ -217,7 +217,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
        }
 
        /* enter phy low-power mode again */
-       if (ehci->has_hostpc) {
+       if (ehci->has_tdi_phy_lpm) {
                port = HCS_N_PORTS(ehci->hcs_params);
                while (port--) {
                        u32 __iomem     *hostpc_reg = &ehci->regs->hostpc[port];
@@ -309,7 +309,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
                }
        }
 
-       if (changed && ehci->has_hostpc) {
+       if (changed && ehci->has_tdi_phy_lpm) {
                spin_unlock_irq(&ehci->lock);
                msleep(5);      /* 5 ms for HCD to enter low-power mode */
                spin_lock_irq(&ehci->lock);
@@ -345,6 +345,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
 
        end_unlink_async(ehci);
        unlink_empty_async_suspended(ehci);
+       ehci_handle_start_intr_unlinks(ehci);
        ehci_handle_intr_unlinks(ehci);
        end_free_itds(ehci);
 
@@ -435,7 +436,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
                goto shutdown;
 
        /* clear phy low-power mode before resume */
-       if (ehci->bus_suspended && ehci->has_hostpc) {
+       if (ehci->bus_suspended && ehci->has_tdi_phy_lpm) {
                i = HCS_N_PORTS(ehci->hcs_params);
                while (i--) {
                        if (test_bit(i, &ehci->bus_suspended)) {
@@ -710,6 +711,145 @@ ehci_hub_descriptor (
        desc->wHubCharacteristics = cpu_to_le16(temp);
 }
 
+/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_USB_HCD_TEST_MODE
+
+#define EHSET_TEST_SINGLE_STEP_SET_FEATURE 0x06
+
+static void usb_ehset_completion(struct urb *urb)
+{
+       struct completion  *done = urb->context;
+
+       complete(done);
+}
+static int submit_single_step_set_feature(
+       struct usb_hcd  *hcd,
+       struct urb      *urb,
+       int             is_setup
+);
+
+/*
+ * Allocate and initialize a control URB. This request will be used by the
+ * EHSET SINGLE_STEP_SET_FEATURE test in which the DATA and STATUS stages
+ * of the GetDescriptor request are sent 15 seconds after the SETUP stage.
+ * Return NULL if failed.
+ */
+static struct urb *request_single_step_set_feature_urb(
+       struct usb_device       *udev,
+       void                    *dr,
+       void                    *buf,
+       struct completion       *done
+) {
+       struct urb *urb;
+       struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+       struct usb_host_endpoint *ep;
+
+       urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!urb)
+               return NULL;
+
+       urb->pipe = usb_rcvctrlpipe(udev, 0);
+       ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out)
+                               [usb_pipeendpoint(urb->pipe)];
+       if (!ep) {
+               usb_free_urb(urb);
+               return NULL;
+       }
+
+       urb->ep = ep;
+       urb->dev = udev;
+       urb->setup_packet = (void *)dr;
+       urb->transfer_buffer = buf;
+       urb->transfer_buffer_length = USB_DT_DEVICE_SIZE;
+       urb->complete = usb_ehset_completion;
+       urb->status = -EINPROGRESS;
+       urb->actual_length = 0;
+       urb->transfer_flags = URB_DIR_IN;
+       usb_get_urb(urb);
+       atomic_inc(&urb->use_count);
+       atomic_inc(&urb->dev->urbnum);
+       urb->setup_dma = dma_map_single(
+                       hcd->self.controller,
+                       urb->setup_packet,
+                       sizeof(struct usb_ctrlrequest),
+                       DMA_TO_DEVICE);
+       urb->transfer_dma = dma_map_single(
+                       hcd->self.controller,
+                       urb->transfer_buffer,
+                       urb->transfer_buffer_length,
+                       DMA_FROM_DEVICE);
+       urb->context = done;
+       return urb;
+}
+
+static int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
+{
+       int retval = -ENOMEM;
+       struct usb_ctrlrequest *dr;
+       struct urb *urb;
+       struct usb_device *udev;
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+       struct usb_device_descriptor *buf;
+       DECLARE_COMPLETION_ONSTACK(done);
+
+       /* Obtain udev of the rhub's child port */
+       udev = usb_hub_find_child(hcd->self.root_hub, port);
+       if (!udev) {
+               ehci_err(ehci, "No device attached to the RootHub\n");
+               return -ENODEV;
+       }
+       buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+       if (!dr) {
+               kfree(buf);
+               return -ENOMEM;
+       }
+
+       /* Fill Setup packet for GetDescriptor */
+       dr->bRequestType = USB_DIR_IN;
+       dr->bRequest = USB_REQ_GET_DESCRIPTOR;
+       dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8);
+       dr->wIndex = 0;
+       dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE);
+       urb = request_single_step_set_feature_urb(udev, dr, buf, &done);
+       if (!urb)
+               goto cleanup;
+
+       /* Submit just the SETUP stage */
+       retval = submit_single_step_set_feature(hcd, urb, 1);
+       if (retval)
+               goto out1;
+       if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) {
+               usb_kill_urb(urb);
+               retval = -ETIMEDOUT;
+               ehci_err(ehci, "%s SETUP stage timed out on ep0\n", __func__);
+               goto out1;
+       }
+       msleep(15 * 1000);
+
+       /* Complete remaining DATA and STATUS stages using the same URB */
+       urb->status = -EINPROGRESS;
+       usb_get_urb(urb);
+       atomic_inc(&urb->use_count);
+       atomic_inc(&urb->dev->urbnum);
+       retval = submit_single_step_set_feature(hcd, urb, 0);
+       if (!retval && !wait_for_completion_timeout(&done,
+                                               msecs_to_jiffies(2000))) {
+               usb_kill_urb(urb);
+               retval = -ETIMEDOUT;
+               ehci_err(ehci, "%s IN stage timed out on ep0\n", __func__);
+       }
+out1:
+       usb_free_urb(urb);
+cleanup:
+       kfree(dr);
+       kfree(buf);
+       return retval;
+}
+#endif /* CONFIG_USB_HCD_TEST_MODE */
 /*-------------------------------------------------------------------------*/
 
 static int ehci_hub_control (
@@ -788,7 +928,7 @@ static int ehci_hub_control (
                                goto error;
 
                        /* clear phy low-power mode before resume */
-                       if (ehci->has_hostpc) {
+                       if (ehci->has_tdi_phy_lpm) {
                                temp1 = ehci_readl(ehci, hostpc_reg);
                                ehci_writel(ehci, temp1 & ~HOSTPC_PHCD,
                                                hostpc_reg);
@@ -801,6 +941,8 @@ static int ehci_hub_control (
                        ehci_writel(ehci, temp | PORT_RESUME, status_reg);
                        ehci->reset_done[wIndex] = jiffies
                                        + msecs_to_jiffies(20);
+                       set_bit(wIndex, &ehci->resuming_ports);
+                       usb_hcd_start_port_resume(&hcd->self, wIndex);
                        break;
                case USB_PORT_FEAT_C_SUSPEND:
                        clear_bit(wIndex, &ehci->port_c_suspend);
@@ -865,11 +1007,11 @@ static int ehci_hub_control (
                        }
                }
 
-               /* whoever resumes must GetPortStatus to complete it!! */
-               if (temp & PORT_RESUME) {
+               /* no reset or resume pending */
+               if (!ehci->reset_done[wIndex]) {
 
                        /* Remote Wakeup received? */
-                       if (!ehci->reset_done[wIndex]) {
+                       if (temp & PORT_RESUME) {
                                /* resume signaling for 20 msec */
                                ehci->reset_done[wIndex] = jiffies
                                                + msecs_to_jiffies(20);
@@ -880,38 +1022,34 @@ static int ehci_hub_control (
                                                ehci->reset_done[wIndex]);
                        }
 
-                       /* resume completed? */
-                       else if (time_after_eq(jiffies,
-                                       ehci->reset_done[wIndex])) {
-                               clear_bit(wIndex, &ehci->suspended_ports);
-                               set_bit(wIndex, &ehci->port_c_suspend);
-                               ehci->reset_done[wIndex] = 0;
-                               usb_hcd_end_port_resume(&hcd->self, wIndex);
-
-                               /* stop resume signaling */
-                               temp &= ~(PORT_RWC_BITS |
-                                               PORT_SUSPEND | PORT_RESUME);
-                               ehci_writel(ehci, temp, status_reg);
-                               clear_bit(wIndex, &ehci->resuming_ports);
-                               retval = ehci_handshake(ehci, status_reg,
-                                          PORT_RESUME, 0, 2000 /* 2msec */);
-                               if (retval != 0) {
-                                       ehci_err(ehci,
-                                               "port %d resume error %d\n",
+               /* reset or resume not yet complete */
+               } else if (!time_after_eq(jiffies, ehci->reset_done[wIndex])) {
+                       ;       /* wait until it is complete */
+
+               /* resume completed */
+               } else if (test_bit(wIndex, &ehci->resuming_ports)) {
+                       clear_bit(wIndex, &ehci->suspended_ports);
+                       set_bit(wIndex, &ehci->port_c_suspend);
+                       ehci->reset_done[wIndex] = 0;
+                       usb_hcd_end_port_resume(&hcd->self, wIndex);
+
+                       /* stop resume signaling */
+                       temp &= ~(PORT_RWC_BITS | PORT_SUSPEND | PORT_RESUME);
+                       ehci_writel(ehci, temp, status_reg);
+                       clear_bit(wIndex, &ehci->resuming_ports);
+                       retval = ehci_handshake(ehci, status_reg,
+                                       PORT_RESUME, 0, 2000 /* 2msec */);
+                       if (retval != 0) {
+                               ehci_err(ehci, "port %d resume error %d\n",
                                                wIndex + 1, retval);
-                                       goto error;
-                               }
-                               temp = ehci_readl(ehci, status_reg);
+                               goto error;
                        }
-               }
+                       temp = ehci_readl(ehci, status_reg);
 
                /* whoever resets must GetPortStatus to complete it!! */
-               if ((temp & PORT_RESET)
-                               && time_after_eq(jiffies,
-                                       ehci->reset_done[wIndex])) {
+               } else {
                        status |= USB_PORT_STAT_C_RESET << 16;
                        ehci->reset_done [wIndex] = 0;
-                       clear_bit(wIndex, &ehci->resuming_ports);
 
                        /* force reset to complete */
                        ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET),
@@ -932,11 +1070,6 @@ static int ehci_hub_control (
                                        ehci_readl(ehci, status_reg));
                }
 
-               if (!(temp & (PORT_RESUME|PORT_RESET))) {
-                       ehci->reset_done[wIndex] = 0;
-                       clear_bit(wIndex, &ehci->resuming_ports);
-               }
-
                /* transfer dedicated ports to the companion hc */
                if ((temp & PORT_CONNECT) &&
                                test_bit(wIndex, &ehci->companion_ports)) {
@@ -1032,12 +1165,12 @@ static int ehci_hub_control (
 
                        /* After above check the port must be connected.
                         * Set appropriate bit thus could put phy into low power
-                        * mode if we have hostpc feature
+                        * mode if we have tdi_phy_lpm feature
                         */
                        temp &= ~PORT_WKCONN_E;
                        temp |= PORT_WKDISC_E | PORT_WKOC_E;
                        ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
-                       if (ehci->has_hostpc) {
+                       if (ehci->has_tdi_phy_lpm) {
                                spin_unlock_irqrestore(&ehci->lock, flags);
                                msleep(5);/* 5ms for HCD enter low pwr mode */
                                spin_lock_irqsave(&ehci->lock, flags);
@@ -1057,7 +1190,7 @@ static int ehci_hub_control (
                                                status_reg);
                        break;
                case USB_PORT_FEAT_RESET:
-                       if (temp & PORT_RESUME)
+                       if (temp & (PORT_SUSPEND|PORT_RESUME))
                                goto error;
                        /* line status bits may report this as low speed,
                         * which can be fine if this root hub has a
@@ -1092,6 +1225,15 @@ static int ehci_hub_control (
                 * about the EHCI-specific stuff.
                 */
                case USB_PORT_FEAT_TEST:
+#ifdef CONFIG_USB_HCD_TEST_MODE
+                       if (selector == EHSET_TEST_SINGLE_STEP_SET_FEATURE) {
+                               spin_unlock_irqrestore(&ehci->lock, flags);
+                               retval = ehset_single_step_set_feature(hcd,
+                                                                       wIndex);
+                               spin_lock_irqsave(&ehci->lock, flags);
+                               break;
+                       }
+#endif
                        if (!selector || selector > 5)
                                goto error;
                        spin_unlock_irqrestore(&ehci->lock, flags);
index ef2c3a1eca4b207bb510a65161c7cfb3dc77c726..52a77734a225fa05a8afc6ede8df5deb4a7089dd 100644 (file)
@@ -93,6 +93,7 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
        qh->qh_dma = dma;
        // INIT_LIST_HEAD (&qh->qh_list);
        INIT_LIST_HEAD (&qh->qtd_list);
+       INIT_LIST_HEAD(&qh->unlink_node);
 
        /* dummy td enables safe urb queuing */
        qh->dummy = ehci_qtd_alloc (ehci, flags);
index 915c2db96dce8fdc3dded7b17915e501367f356e..417c10da945078e37ddf20e7be290e996936074e 100644 (file)
@@ -96,7 +96,7 @@ static const struct hc_driver mv_ehci_hc_driver = {
         * generic hardware linkage
         */
        .irq = ehci_irq,
-       .flags = HCD_MEMORY | HCD_USB2,
+       .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
 
        /*
         * basic lifecycle operations
@@ -131,7 +131,7 @@ static const struct hc_driver mv_ehci_hc_driver = {
 
 static int mv_ehci_probe(struct platform_device *pdev)
 {
-       struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
+       struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct usb_hcd *hcd;
        struct ehci_hcd *ehci;
        struct ehci_hcd_mv *ehci_mv;
index e4c34ac386c08936fcb532399fff1d5d39cbe1c3..5899ad6626c7525feafc68d712de54906355c5cc 100644 (file)
@@ -49,7 +49,7 @@ static const struct ehci_driver_overrides ehci_mxc_overrides __initconst = {
 
 static int ehci_mxc_drv_probe(struct platform_device *pdev)
 {
-       struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
+       struct mxc_usbh_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct usb_hcd *hcd;
        struct resource *res;
        int irq, ret;
@@ -174,7 +174,7 @@ err_alloc:
 
 static int ehci_mxc_drv_remove(struct platform_device *pdev)
 {
-       struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
+       struct mxc_usbh_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
        struct ehci_mxc_priv *priv = (struct ehci_mxc_priv *) ehci->priv;
@@ -197,20 +197,12 @@ static int ehci_mxc_drv_remove(struct platform_device *pdev)
        return 0;
 }
 
-static void ehci_mxc_drv_shutdown(struct platform_device *pdev)
-{
-       struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
-       if (hcd->driver->shutdown)
-               hcd->driver->shutdown(hcd);
-}
-
 MODULE_ALIAS("platform:mxc-ehci");
 
 static struct platform_driver ehci_mxc_driver = {
        .probe = ehci_mxc_drv_probe,
        .remove = ehci_mxc_drv_remove,
-       .shutdown = ehci_mxc_drv_shutdown,
+       .shutdown = usb_hcd_platform_shutdown,
        .driver = {
                   .name = "mxc-ehci",
        },
index 45cc00158412ac8a380cda88a28a4bb7536d62fa..ab0397e4d8f3eadae916d07434f4431f3d59def3 100644 (file)
@@ -51,7 +51,7 @@ static const struct hc_driver ehci_octeon_hc_driver = {
         * generic hardware linkage
         */
        .irq                    = ehci_irq,
-       .flags                  = HCD_MEMORY | HCD_USB2,
+       .flags                  = HCD_MEMORY | HCD_USB2 | HCD_BH,
 
        /*
         * basic lifecycle operations
index 9bd7dfe3315bba47bfd220d06d484fcdd4700230..78b01fa475bbfc85e0aa35fcd9ab917b963689ee 100644 (file)
@@ -100,7 +100,7 @@ static const struct ehci_driver_overrides ehci_omap_overrides __initdata = {
 static int ehci_hcd_omap_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct usbhs_omap_platform_data *pdata = dev->platform_data;
+       struct usbhs_omap_platform_data *pdata = dev_get_platdata(dev);
        struct resource *res;
        struct usb_hcd  *hcd;
        void __iomem *regs;
@@ -119,7 +119,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
 
        /* For DT boot, get platform data from parent. i.e. usbhshost */
        if (dev->of_node) {
-               pdata = dev->parent->platform_data;
+               pdata = dev_get_platdata(dev->parent);
                dev->platform_data = pdata;
        }
 
@@ -278,14 +278,6 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev)
        return 0;
 }
 
-static void ehci_hcd_omap_shutdown(struct platform_device *pdev)
-{
-       struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev);
-
-       if (hcd->driver->shutdown)
-               hcd->driver->shutdown(hcd);
-}
-
 static const struct of_device_id omap_ehci_dt_ids[] = {
        { .compatible = "ti,ehci-omap" },
        { }
@@ -296,7 +288,7 @@ MODULE_DEVICE_TABLE(of, omap_ehci_dt_ids);
 static struct platform_driver ehci_hcd_omap_driver = {
        .probe                  = ehci_hcd_omap_probe,
        .remove                 = ehci_hcd_omap_remove,
-       .shutdown               = ehci_hcd_omap_shutdown,
+       .shutdown               = usb_hcd_platform_shutdown,
        /*.suspend              = ehci_hcd_omap_suspend, */
        /*.resume               = ehci_hcd_omap_resume, */
        .driver = {
index 1a450aa13ebf04aaa3b8fef5ce9e296412b89373..d1dfb9db5b420845edec3a30b81bdd30792704e9 100644 (file)
@@ -139,7 +139,7 @@ ehci_orion_conf_mbus_windows(struct usb_hcd *hcd,
 
 static int ehci_orion_drv_probe(struct platform_device *pdev)
 {
-       struct orion_ehci_data *pd = pdev->dev.platform_data;
+       struct orion_ehci_data *pd = dev_get_platdata(&pdev->dev);
        const struct mbus_dram_target_info *dram;
        struct resource *res;
        struct usb_hcd *hcd;
index 595d210655b67ef79e95fdbd5cc0c347060089c6..6bd299e61f58d23202183f3186c9542f99e93a23 100644 (file)
@@ -315,53 +315,11 @@ done:
  * Also they depend on separate root hub suspend/resume.
  */
 
-static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev)
-{
-       return pdev->class == PCI_CLASS_SERIAL_USB_EHCI &&
-               pdev->vendor == PCI_VENDOR_ID_INTEL &&
-               (pdev->device == 0x1E26 ||
-                pdev->device == 0x8C2D ||
-                pdev->device == 0x8C26 ||
-                pdev->device == 0x9C26);
-}
-
-static void ehci_enable_xhci_companion(void)
-{
-       struct pci_dev          *companion = NULL;
-
-       /* The xHCI and EHCI controllers are not on the same PCI slot */
-       for_each_pci_dev(companion) {
-               if (!usb_is_intel_switchable_xhci(companion))
-                       continue;
-               usb_enable_xhci_ports(companion);
-               return;
-       }
-}
-
 static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
        struct pci_dev          *pdev = to_pci_dev(hcd->self.controller);
 
-       /* The BIOS on systems with the Intel Panther Point chipset may or may
-        * not support xHCI natively.  That means that during system resume, it
-        * may switch the ports back to EHCI so that users can use their
-        * keyboard to select a kernel from GRUB after resume from hibernate.
-        *
-        * The BIOS is supposed to remember whether the OS had xHCI ports
-        * enabled before resume, and switch the ports back to xHCI when the
-        * BIOS/OS semaphore is written, but we all know we can't trust BIOS
-        * writers.
-        *
-        * Unconditionally switch the ports back to xHCI after a system resume.
-        * We can't tell whether the EHCI or xHCI controller will be resumed
-        * first, so we have to do the port switchover in both drivers.  Writing
-        * a '1' to the port switchover registers should have no effect if the
-        * port was already switched over.
-        */
-       if (usb_is_intel_switchable_ehci(pdev))
-               ehci_enable_xhci_companion();
-
        if (ehci_resume(hcd, hibernated) != 0)
                (void) ehci_pci_reinit(ehci, pdev);
        return 0;
index 5196d728517d03474270888adbfd98fb9ab73d4c..f6b790ca8cf2415805d827fcceebbde48291a935 100644 (file)
@@ -39,7 +39,7 @@ static const char hcd_name[] = "ehci-platform";
 static int ehci_platform_reset(struct usb_hcd *hcd)
 {
        struct platform_device *pdev = to_platform_device(hcd->self.controller);
-       struct usb_ehci_pdata *pdata = pdev->dev.platform_data;
+       struct usb_ehci_pdata *pdata = dev_get_platdata(&pdev->dev);
        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
        int retval;
 
@@ -87,14 +87,14 @@ static int ehci_platform_probe(struct platform_device *dev)
         * use reasonable defaults so platforms don't have to provide these.
         * with DT probing on ARM, none of these are set.
         */
-       if (!dev->dev.platform_data)
+       if (!dev_get_platdata(&dev->dev))
                dev->dev.platform_data = &ehci_platform_defaults;
        if (!dev->dev.dma_mask)
                dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
        if (!dev->dev.coherent_dma_mask)
                dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
 
-       pdata = dev->dev.platform_data;
+       pdata = dev_get_platdata(&dev->dev);
 
        irq = platform_get_irq(dev, 0);
        if (irq < 0) {
@@ -148,7 +148,7 @@ err_power:
 static int ehci_platform_remove(struct platform_device *dev)
 {
        struct usb_hcd *hcd = platform_get_drvdata(dev);
-       struct usb_ehci_pdata *pdata = dev->dev.platform_data;
+       struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
 
        usb_remove_hcd(hcd);
        usb_put_hcd(hcd);
@@ -167,7 +167,7 @@ static int ehci_platform_remove(struct platform_device *dev)
 static int ehci_platform_suspend(struct device *dev)
 {
        struct usb_hcd *hcd = dev_get_drvdata(dev);
-       struct usb_ehci_pdata *pdata = dev->platform_data;
+       struct usb_ehci_pdata *pdata = dev_get_platdata(dev);
        struct platform_device *pdev =
                container_of(dev, struct platform_device, dev);
        bool do_wakeup = device_may_wakeup(dev);
@@ -184,7 +184,7 @@ static int ehci_platform_suspend(struct device *dev)
 static int ehci_platform_resume(struct device *dev)
 {
        struct usb_hcd *hcd = dev_get_drvdata(dev);
-       struct usb_ehci_pdata *pdata = dev->platform_data;
+       struct usb_ehci_pdata *pdata = dev_get_platdata(dev);
        struct platform_device *pdev =
                container_of(dev, struct platform_device, dev);
 
index 601e208bd782c07e9d0bb1b60d238ccbb7774758..893b707f0000abf0e323f39b28b6060a3293bcef 100644 (file)
@@ -286,7 +286,7 @@ static const struct hc_driver ehci_msp_hc_driver = {
 #else
        .irq =                  ehci_irq,
 #endif
-       .flags =                HCD_MEMORY | HCD_USB2,
+       .flags =                HCD_MEMORY | HCD_USB2 | HCD_BH,
 
        /*
         * basic lifecycle operations
index 86da09c0f8d0262479ecef2927ae36a6eb1f0516..6cc5567bf9c87faaa8c4a21dcb4202e8e6e7fb94 100644 (file)
@@ -28,7 +28,7 @@ static const struct hc_driver ehci_ppc_of_hc_driver = {
         * generic hardware linkage
         */
        .irq                    = ehci_irq,
-       .flags                  = HCD_MEMORY | HCD_USB2,
+       .flags                  = HCD_MEMORY | HCD_USB2 | HCD_BH,
 
        /*
         * basic lifecycle operations
@@ -215,15 +215,6 @@ static int ehci_hcd_ppc_of_remove(struct platform_device *op)
 }
 
 
-static void ehci_hcd_ppc_of_shutdown(struct platform_device *op)
-{
-       struct usb_hcd *hcd = platform_get_drvdata(op);
-
-       if (hcd->driver->shutdown)
-               hcd->driver->shutdown(hcd);
-}
-
-
 static const struct of_device_id ehci_hcd_ppc_of_match[] = {
        {
                .compatible = "usb-ehci",
@@ -236,7 +227,7 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_ppc_of_match);
 static struct platform_driver ehci_hcd_ppc_of_driver = {
        .probe          = ehci_hcd_ppc_of_probe,
        .remove         = ehci_hcd_ppc_of_remove,
-       .shutdown       = ehci_hcd_ppc_of_shutdown,
+       .shutdown       = usb_hcd_platform_shutdown,
        .driver = {
                .name = "ppc-of-ehci",
                .owner = THIS_MODULE,
index fd983771b02559cb56c6210e6813d9b223a80f7a..8188542ba17ea01214a3ab0f269fe07cb6cb1744 100644 (file)
@@ -71,7 +71,7 @@ static const struct hc_driver ps3_ehci_hc_driver = {
        .product_desc           = "PS3 EHCI Host Controller",
        .hcd_priv_size          = sizeof(struct ehci_hcd),
        .irq                    = ehci_irq,
-       .flags                  = HCD_MEMORY | HCD_USB2,
+       .flags                  = HCD_MEMORY | HCD_USB2 | HCD_BH,
        .reset                  = ps3_ehci_hc_reset,
        .start                  = ehci_run,
        .stop                   = ehci_stop,
index d34b399b78e2c30665792857a34615b6c9a0c227..33336874c47bc023792a89ce224d3a7a6bb37209 100644 (file)
@@ -254,8 +254,6 @@ static int qtd_copy_status (
 
 static void
 ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status)
-__releases(ehci->lock)
-__acquires(ehci->lock)
 {
        if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
                /* ... update hc-wide periodic stats */
@@ -281,11 +279,8 @@ __acquires(ehci->lock)
                urb->actual_length, urb->transfer_buffer_length);
 #endif
 
-       /* complete() can reenter this HCD */
        usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
-       spin_unlock (&ehci->lock);
        usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status);
-       spin_lock (&ehci->lock);
 }
 
 static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
@@ -1143,6 +1138,109 @@ submit_async (
        return rc;
 }
 
+/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_USB_HCD_TEST_MODE
+/*
+ * This function creates the qtds and submits them for the
+ * SINGLE_STEP_SET_FEATURE Test.
+ * This is done in two parts: first SETUP req for GetDesc is sent then
+ * 15 seconds later, the IN stage for GetDesc starts to req data from dev
+ *
+ * is_setup : i/p arguement decides which of the two stage needs to be
+ * performed; TRUE - SETUP and FALSE - IN+STATUS
+ * Returns 0 if success
+ */
+static int submit_single_step_set_feature(
+       struct usb_hcd  *hcd,
+       struct urb      *urb,
+       int             is_setup
+) {
+       struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
+       struct list_head        qtd_list;
+       struct list_head        *head;
+
+       struct ehci_qtd         *qtd, *qtd_prev;
+       dma_addr_t              buf;
+       int                     len, maxpacket;
+       u32                     token;
+
+       INIT_LIST_HEAD(&qtd_list);
+       head = &qtd_list;
+
+       /* URBs map to sequences of QTDs:  one logical transaction */
+       qtd = ehci_qtd_alloc(ehci, GFP_KERNEL);
+       if (unlikely(!qtd))
+               return -1;
+       list_add_tail(&qtd->qtd_list, head);
+       qtd->urb = urb;
+
+       token = QTD_STS_ACTIVE;
+       token |= (EHCI_TUNE_CERR << 10);
+
+       len = urb->transfer_buffer_length;
+       /*
+        * Check if the request is to perform just the SETUP stage (getDesc)
+        * as in SINGLE_STEP_SET_FEATURE test, DATA stage (IN) happens
+        * 15 secs after the setup
+        */
+       if (is_setup) {
+               /* SETUP pid */
+               qtd_fill(ehci, qtd, urb->setup_dma,
+                               sizeof(struct usb_ctrlrequest),
+                               token | (2 /* "setup" */ << 8), 8);
+
+               submit_async(ehci, urb, &qtd_list, GFP_ATOMIC);
+               return 0; /*Return now; we shall come back after 15 seconds*/
+       }
+
+       /*
+        * IN: data transfer stage:  buffer setup : start the IN txn phase for
+        * the get_Desc SETUP which was sent 15seconds back
+        */
+       token ^= QTD_TOGGLE;   /*We need to start IN with DATA-1 Pid-sequence*/
+       buf = urb->transfer_dma;
+
+       token |= (1 /* "in" */ << 8);  /*This is IN stage*/
+
+       maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, 0));
+
+       qtd_fill(ehci, qtd, buf, len, token, maxpacket);
+
+       /*
+        * Our IN phase shall always be a short read; so keep the queue running
+        * and let it advance to the next qtd which zero length OUT status
+        */
+       qtd->hw_alt_next = EHCI_LIST_END(ehci);
+
+       /* STATUS stage for GetDesc control request */
+       token ^= 0x0100;        /* "in" <--> "out"  */
+       token |= QTD_TOGGLE;    /* force DATA1 */
+
+       qtd_prev = qtd;
+       qtd = ehci_qtd_alloc(ehci, GFP_ATOMIC);
+       if (unlikely(!qtd))
+               goto cleanup;
+       qtd->urb = urb;
+       qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma);
+       list_add_tail(&qtd->qtd_list, head);
+
+       /* dont fill any data in such packets */
+       qtd_fill(ehci, qtd, 0, 0, token, 0);
+
+       /* by default, enable interrupt on urb completion */
+       if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT)))
+               qtd->hw_token |= cpu_to_hc32(ehci, QTD_IOC);
+
+       submit_async(ehci, urb, &qtd_list, GFP_KERNEL);
+
+       return 0;
+
+cleanup:
+       qtd_list_free(ehci, urb, head);
+       return -1;
+}
+#endif /* CONFIG_USB_HCD_TEST_MODE */
+
 /*-------------------------------------------------------------------------*/
 
 static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
index 7cc26e621aa7c509da43e3712c9f0febc9fbfcdd..7c3de95c7054339a5f62b64322f55a24f2bb286b 100644 (file)
@@ -75,7 +75,7 @@ static void s5p_setup_vbus_gpio(struct platform_device *pdev)
 
 static int s5p_ehci_probe(struct platform_device *pdev)
 {
-       struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
+       struct s5p_ehci_platdata *pdata = dev_get_platdata(&pdev->dev);
        struct s5p_ehci_hcd *s5p_ehci;
        struct usb_hcd *hcd;
        struct ehci_hcd *ehci;
@@ -220,14 +220,6 @@ static int s5p_ehci_remove(struct platform_device *pdev)
        return 0;
 }
 
-static void s5p_ehci_shutdown(struct platform_device *pdev)
-{
-       struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
-       if (hcd->driver->shutdown)
-               hcd->driver->shutdown(hcd);
-}
-
 #ifdef CONFIG_PM
 static int s5p_ehci_suspend(struct device *dev)
 {
@@ -297,7 +289,7 @@ MODULE_DEVICE_TABLE(of, exynos_ehci_match);
 static struct platform_driver s5p_ehci_driver = {
        .probe          = s5p_ehci_probe,
        .remove         = s5p_ehci_remove,
-       .shutdown       = s5p_ehci_shutdown,
+       .shutdown       = usb_hcd_platform_shutdown,
        .driver = {
                .name   = "s5p-ehci",
                .owner  = THIS_MODULE,
index 8e3c878f38cf57e64cb24c25a992b59e184ce322..66310894ad977b336820a8d3a7f37b5fbdaa38f7 100644 (file)
@@ -601,12 +601,29 @@ static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
        list_del(&qh->intr_node);
 }
 
+static void cancel_unlink_wait_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+       if (qh->qh_state != QH_STATE_LINKED ||
+                       list_empty(&qh->unlink_node))
+               return;
+
+       list_del_init(&qh->unlink_node);
+
+       /*
+        * TODO: disable the event of EHCI_HRTIMER_START_UNLINK_INTR for
+        * avoiding unnecessary CPU wakeup
+        */
+}
+
 static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
        /* If the QH isn't linked then there's nothing we can do. */
        if (qh->qh_state != QH_STATE_LINKED)
                return;
 
+       /* if the qh is waiting for unlink, cancel it now */
+       cancel_unlink_wait_intr(ehci, qh);
+
        qh_unlink_periodic (ehci, qh);
 
        /* Make sure the unlinks are visible before starting the timer */
@@ -632,6 +649,27 @@ static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
        }
 }
 
+/*
+ * It is common only one intr URB is scheduled on one qh, and
+ * given complete() is run in tasklet context, introduce a bit
+ * delay to avoid unlink qh too early.
+ */
+static void start_unlink_intr_wait(struct ehci_hcd *ehci,
+                                  struct ehci_qh *qh)
+{
+       qh->unlink_cycle = ehci->intr_unlink_wait_cycle;
+
+       /* New entries go at the end of the intr_unlink_wait list */
+       list_add_tail(&qh->unlink_node, &ehci->intr_unlink_wait);
+
+       if (ehci->rh_state < EHCI_RH_RUNNING)
+               ehci_handle_start_intr_unlinks(ehci);
+       else if (ehci->intr_unlink_wait.next == &qh->unlink_node) {
+               ehci_enable_event(ehci, EHCI_HRTIMER_START_UNLINK_INTR, true);
+               ++ehci->intr_unlink_wait_cycle;
+       }
+}
+
 static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
        struct ehci_qh_hw       *hw = qh->hw;
@@ -889,6 +927,9 @@ static int intr_submit (
        if (qh->qh_state == QH_STATE_IDLE) {
                qh_refresh(ehci, qh);
                qh_link_periodic(ehci, qh);
+       } else {
+               /* cancel unlink wait for the qh */
+               cancel_unlink_wait_intr(ehci, qh);
        }
 
        /* ... update usbfs periodic stats */
@@ -924,9 +965,11 @@ static void scan_intr(struct ehci_hcd *ehci)
                         * in qh_unlink_periodic().
                         */
                        temp = qh_completions(ehci, qh);
-                       if (unlikely(temp || (list_empty(&qh->qtd_list) &&
-                                       qh->qh_state == QH_STATE_LINKED)))
+                       if (unlikely(temp))
                                start_unlink_intr(ehci, qh);
+                       else if (unlikely(list_empty(&qh->qtd_list) &&
+                                       qh->qh_state == QH_STATE_LINKED))
+                               start_unlink_intr_wait(ehci, qh);
                }
        }
 }
index b2de52d3961488f249aeb9d4026efe2d603b72bb..8a734498079bc176938c57a6b132c146e9be00dd 100644 (file)
@@ -55,7 +55,7 @@ const struct hc_driver ehci_sead3_hc_driver = {
         * generic hardware linkage
         */
        .irq                    = ehci_irq,
-       .flags                  = HCD_MEMORY | HCD_USB2,
+       .flags                  = HCD_MEMORY | HCD_USB2 | HCD_BH,
 
        /*
         * basic lifecycle operations
index c4c0ee92a397b7172b9ecd04da481079ac272801..dc899eb2b86183561351d78e8dba1ceffc9cbb18 100644 (file)
@@ -36,7 +36,7 @@ static const struct hc_driver ehci_sh_hc_driver = {
         * generic hardware linkage
         */
        .irq                            = ehci_irq,
-       .flags                          = HCD_USB2 | HCD_MEMORY,
+       .flags                          = HCD_USB2 | HCD_MEMORY | HCD_BH,
 
        /*
         * basic lifecycle operations
@@ -104,7 +104,7 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev)
                goto fail_create_hcd;
        }
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
 
        /* initialize hcd */
        hcd = usb_create_hcd(&ehci_sh_hc_driver, &pdev->dev,
index 6ee7ef79b4f86a5c802e33245592d40ec27127a5..78fa76da332435a83cc3c55226d33cbeb2e78afe 100644 (file)
@@ -25,9 +25,9 @@
 #include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/platform_device.h>
-#include <linux/platform_data/tegra_usb.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/usb/ehci_def.h>
 
 static struct hc_driver __read_mostly tegra_ehci_hc_driver;
 
+struct tegra_ehci_soc_config {
+       bool has_hostpc;
+};
+
 static int (*orig_hub_control)(struct usb_hcd *hcd,
                                u16 typeReq, u16 wValue, u16 wIndex,
                                char *buf, u16 wLength);
@@ -58,7 +62,6 @@ static int (*orig_hub_control)(struct usb_hcd *hcd,
 struct tegra_ehci_hcd {
        struct tegra_usb_phy *phy;
        struct clk *clk;
-       struct usb_phy *transceiver;
        int port_resuming;
        bool needs_double_reset;
        enum tegra_usb_phy_port_speed port_speed;
@@ -322,50 +325,38 @@ static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
        free_dma_aligned_buffer(urb);
 }
 
-static int setup_vbus_gpio(struct platform_device *pdev,
-                          struct tegra_ehci_platform_data *pdata)
-{
-       int err = 0;
-       int gpio;
-
-       gpio = pdata->vbus_gpio;
-       if (!gpio_is_valid(gpio))
-               gpio = of_get_named_gpio(pdev->dev.of_node,
-                                        "nvidia,vbus-gpio", 0);
-       if (!gpio_is_valid(gpio))
-               return 0;
+static const struct tegra_ehci_soc_config tegra30_soc_config = {
+       .has_hostpc = true,
+};
 
-       err = gpio_request(gpio, "vbus_gpio");
-       if (err) {
-               dev_err(&pdev->dev, "can't request vbus gpio %d", gpio);
-               return err;
-       }
-       err = gpio_direction_output(gpio, 1);
-       if (err) {
-               dev_err(&pdev->dev, "can't enable vbus\n");
-               return err;
-       }
+static const struct tegra_ehci_soc_config tegra20_soc_config = {
+       .has_hostpc = false,
+};
 
-       return err;
-}
+static struct of_device_id tegra_ehci_of_match[] = {
+       { .compatible = "nvidia,tegra30-ehci", .data = &tegra30_soc_config },
+       { .compatible = "nvidia,tegra20-ehci", .data = &tegra20_soc_config },
+       { },
+};
 
 static int tegra_ehci_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *match;
+       const struct tegra_ehci_soc_config *soc_config;
        struct resource *res;
        struct usb_hcd *hcd;
        struct ehci_hcd *ehci;
        struct tegra_ehci_hcd *tegra;
-       struct tegra_ehci_platform_data *pdata;
        int err = 0;
        int irq;
-       struct device_node *np_phy;
        struct usb_phy *u_phy;
 
-       pdata = pdev->dev.platform_data;
-       if (!pdata) {
-               dev_err(&pdev->dev, "Platform data missing\n");
-               return -EINVAL;
+       match = of_match_device(tegra_ehci_of_match, &pdev->dev);
+       if (!match) {
+               dev_err(&pdev->dev, "Error: No device match found\n");
+               return -ENODEV;
        }
+       soc_config = match->data;
 
        /* Right now device-tree probed devices don't get dma_mask set.
         * Since shared usb code relies on it, set it here for now.
@@ -376,14 +367,11 @@ static int tegra_ehci_probe(struct platform_device *pdev)
        if (!pdev->dev.coherent_dma_mask)
                pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
 
-       setup_vbus_gpio(pdev, pdata);
-
        hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev,
                                        dev_name(&pdev->dev));
        if (!hcd) {
                dev_err(&pdev->dev, "Unable to create HCD\n");
-               err = -ENOMEM;
-               goto cleanup_vbus_gpio;
+               return -ENOMEM;
        }
        platform_set_drvdata(pdev, hcd);
        ehci = hcd_to_ehci(hcd);
@@ -406,13 +394,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
        udelay(1);
        tegra_periph_reset_deassert(tegra->clk);
 
-       np_phy = of_parse_phandle(pdev->dev.of_node, "nvidia,phy", 0);
-       if (!np_phy) {
-               err = -ENODEV;
-               goto cleanup_clk_en;
-       }
-
-       u_phy = tegra_usb_get_phy(np_phy);
+       u_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0);
        if (IS_ERR(u_phy)) {
                err = PTR_ERR(u_phy);
                goto cleanup_clk_en;
@@ -437,6 +419,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
                goto cleanup_clk_en;
        }
        ehci->caps = hcd->regs + 0x100;
+       ehci->has_hostpc = soc_config->has_hostpc;
 
        err = usb_phy_init(hcd->phy);
        if (err) {
@@ -466,26 +449,18 @@ static int tegra_ehci_probe(struct platform_device *pdev)
                goto cleanup_phy;
        }
 
-       if (pdata->operating_mode == TEGRA_USB_OTG) {
-               tegra->transceiver =
-                       devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
-               if (!IS_ERR(tegra->transceiver))
-                       otg_set_host(tegra->transceiver->otg, &hcd->self);
-       } else {
-               tegra->transceiver = ERR_PTR(-ENODEV);
-       }
+       otg_set_host(u_phy->otg, &hcd->self);
 
        err = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (err) {
                dev_err(&pdev->dev, "Failed to add USB HCD\n");
-               goto cleanup_transceiver;
+               goto cleanup_otg_set_host;
        }
 
        return err;
 
-cleanup_transceiver:
-       if (!IS_ERR(tegra->transceiver))
-               otg_set_host(tegra->transceiver->otg, NULL);
+cleanup_otg_set_host:
+       otg_set_host(u_phy->otg, NULL);
 cleanup_phy:
        usb_phy_shutdown(hcd->phy);
 cleanup_clk_en:
@@ -494,8 +469,6 @@ cleanup_clk_get:
        clk_put(tegra->clk);
 cleanup_hcd_create:
        usb_put_hcd(hcd);
-cleanup_vbus_gpio:
-       /* FIXME: Undo setup_vbus_gpio() here */
        return err;
 }
 
@@ -505,8 +478,7 @@ static int tegra_ehci_remove(struct platform_device *pdev)
        struct tegra_ehci_hcd *tegra =
                (struct tegra_ehci_hcd *)hcd_to_ehci(hcd)->priv;
 
-       if (!IS_ERR(tegra->transceiver))
-               otg_set_host(tegra->transceiver->otg, NULL);
+       otg_set_host(hcd->phy->otg, NULL);
 
        usb_phy_shutdown(hcd->phy);
        usb_remove_hcd(hcd);
@@ -525,11 +497,6 @@ static void tegra_ehci_hcd_shutdown(struct platform_device *pdev)
                hcd->driver->shutdown(hcd);
 }
 
-static struct of_device_id tegra_ehci_of_match[] = {
-       { .compatible = "nvidia,tegra20-ehci", },
-       { },
-};
-
 static struct platform_driver tegra_ehci_driver = {
        .probe          = tegra_ehci_probe,
        .remove         = tegra_ehci_remove,
index d72b2929c03db50e103ee3f481694001fddae3c1..67026ffbf9a871c9780a4b0b7f0d6c739c904e73 100644 (file)
@@ -61,7 +61,7 @@ static const struct hc_driver ehci_tilegx_hc_driver = {
         * Generic hardware linkage.
         */
        .irq                    = ehci_irq,
-       .flags                  = HCD_MEMORY | HCD_USB2,
+       .flags                  = HCD_MEMORY | HCD_USB2 | HCD_BH,
 
        /*
         * Basic lifecycle operations.
@@ -101,7 +101,7 @@ static int ehci_hcd_tilegx_drv_probe(struct platform_device *pdev)
 {
        struct usb_hcd *hcd;
        struct ehci_hcd *ehci;
-       struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data;
+       struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
        pte_t pte = { 0 };
        int my_cpu = smp_processor_id();
        int ret;
@@ -186,7 +186,7 @@ err_hcd:
 static int ehci_hcd_tilegx_drv_remove(struct platform_device *pdev)
 {
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
-       struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data;
+       struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
        usb_remove_hcd(hcd);
        usb_put_hcd(hcd);
index 11e5b32f73e943824ca262f3bb61462dacb82b15..424ac5d8371479fe54501139fd68be9e58a62167 100644 (file)
@@ -72,6 +72,7 @@ static unsigned event_delays_ns[] = {
        1 * NSEC_PER_MSEC,      /* EHCI_HRTIMER_POLL_DEAD */
        1125 * NSEC_PER_USEC,   /* EHCI_HRTIMER_UNLINK_INTR */
        2 * NSEC_PER_MSEC,      /* EHCI_HRTIMER_FREE_ITDS */
+       5 * NSEC_PER_MSEC,      /* EHCI_HRTIMER_START_UNLINK_INTR */
        6 * NSEC_PER_MSEC,      /* EHCI_HRTIMER_ASYNC_UNLINKS */
        10 * NSEC_PER_MSEC,     /* EHCI_HRTIMER_IAA_WATCHDOG */
        10 * NSEC_PER_MSEC,     /* EHCI_HRTIMER_DISABLE_PERIODIC */
@@ -215,6 +216,36 @@ static void ehci_handle_controller_death(struct ehci_hcd *ehci)
        /* Not in process context, so don't try to reset the controller */
 }
 
+/* start to unlink interrupt QHs  */
+static void ehci_handle_start_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.
+        */
+       while (!list_empty(&ehci->intr_unlink_wait)) {
+               struct ehci_qh  *qh;
+
+               qh = list_first_entry(&ehci->intr_unlink_wait,
+                               struct ehci_qh, unlink_node);
+               if (!stopped && (qh->unlink_cycle ==
+                               ehci->intr_unlink_wait_cycle))
+                       break;
+               list_del_init(&qh->unlink_node);
+               start_unlink_intr(ehci, qh);
+       }
+
+       /* Handle remaining entries later */
+       if (!list_empty(&ehci->intr_unlink_wait)) {
+               ehci_enable_event(ehci, EHCI_HRTIMER_START_UNLINK_INTR, true);
+               ++ehci->intr_unlink_wait_cycle;
+       }
+}
 
 /* Handle unlinked interrupt QHs once they are gone from the hardware */
 static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci)
@@ -236,7 +267,7 @@ static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci)
                                unlink_node);
                if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle)
                        break;
-               list_del(&qh->unlink_node);
+               list_del_init(&qh->unlink_node);
                end_unlink_intr(ehci, qh);
        }
 
@@ -363,6 +394,7 @@ static void (*event_handlers[])(struct ehci_hcd *) = {
        ehci_handle_controller_death,   /* EHCI_HRTIMER_POLL_DEAD */
        ehci_handle_intr_unlinks,       /* EHCI_HRTIMER_UNLINK_INTR */
        end_free_itds,                  /* EHCI_HRTIMER_FREE_ITDS */
+       ehci_handle_start_intr_unlinks, /* EHCI_HRTIMER_START_UNLINK_INTR */
        unlink_empty_async,             /* EHCI_HRTIMER_ASYNC_UNLINKS */
        ehci_iaa_watchdog,              /* EHCI_HRTIMER_IAA_WATCHDOG */
        ehci_disable_PSE,               /* EHCI_HRTIMER_DISABLE_PERIODIC */
index 59e0e24c753febfb76369be8f872cb3731c2f365..1c370dfbee0d35e6a3cf2b1288836df2116599c5 100644 (file)
@@ -108,7 +108,7 @@ static const struct hc_driver ehci_w90x900_hc_driver = {
         * generic hardware linkage
         */
        .irq = ehci_irq,
-       .flags = HCD_USB2|HCD_MEMORY,
+       .flags = HCD_USB2|HCD_MEMORY|HCD_BH,
 
        /*
         * basic lifecycle operations
index 35c7f90384a6f03d947dee5576a5ba41dfd3c004..95979f9f4381d8e8e573c7e0fe254d5585d23ab8 100644 (file)
@@ -79,7 +79,7 @@ static const struct hc_driver ehci_xilinx_of_hc_driver = {
         * generic hardware linkage
         */
        .irq                    = ehci_irq,
-       .flags                  = HCD_MEMORY | HCD_USB2,
+       .flags                  = HCD_MEMORY | HCD_USB2 | HCD_BH,
 
        /*
         * basic lifecycle operations
@@ -220,21 +220,6 @@ static int ehci_hcd_xilinx_of_remove(struct platform_device *op)
        return 0;
 }
 
-/**
- * ehci_hcd_xilinx_of_shutdown - shutdown the hcd
- * @op:                pointer to platform_device structure that is to be removed
- *
- * Properly shutdown the hcd, call driver's shutdown routine.
- */
-static void ehci_hcd_xilinx_of_shutdown(struct platform_device *op)
-{
-       struct usb_hcd *hcd = platform_get_drvdata(op);
-
-       if (hcd->driver->shutdown)
-               hcd->driver->shutdown(hcd);
-}
-
-
 static const struct of_device_id ehci_hcd_xilinx_of_match[] = {
                {.compatible = "xlnx,xps-usb-host-1.00.a",},
        {},
@@ -244,7 +229,7 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_xilinx_of_match);
 static struct platform_driver ehci_hcd_xilinx_of_driver = {
        .probe          = ehci_hcd_xilinx_of_probe,
        .remove         = ehci_hcd_xilinx_of_remove,
-       .shutdown       = ehci_hcd_xilinx_of_shutdown,
+       .shutdown       = usb_hcd_platform_shutdown,
        .driver = {
                .name = "xilinx-of-ehci",
                .owner = THIS_MODULE,
index 64f9a08e959c73db9359112b1ae6bb889e0b29c4..2822e79e1fbcf7feb9ab5efd5af70a8f2e64a27f 100644 (file)
@@ -88,6 +88,7 @@ enum ehci_hrtimer_event {
        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_START_UNLINK_INTR, /* Unlink empty interrupt QHs */
        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 */
@@ -143,7 +144,9 @@ struct ehci_hcd {                   /* one per controller */
        unsigned                i_thresh;       /* uframes HC might cache */
 
        union ehci_shadow       *pshadow;       /* mirror hw periodic table */
+       struct list_head        intr_unlink_wait;
        struct list_head        intr_unlink;
+       unsigned                intr_unlink_wait_cycle;
        unsigned                intr_unlink_cycle;
        unsigned                now_frame;      /* frame from HC hardware */
        unsigned                last_iso_frame; /* last frame scanned for iso */
@@ -210,6 +213,7 @@ struct ehci_hcd {                   /* one per controller */
        #define OHCI_HCCTRL_LEN         0x4
        __hc32                  *ohci_hcctrl_reg;
        unsigned                has_hostpc:1;
+       unsigned                has_tdi_phy_lpm:1;
        unsigned                has_ppcd:1; /* support per-port change bits */
        u8                      sbrn;           /* packed release number */
 
diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c
new file mode 100644 (file)
index 0000000..fce13bc
--- /dev/null
@@ -0,0 +1,6049 @@
+/*
+ * Faraday FOTG210 EHCI-like driver
+ *
+ * Copyright (c) 2013 Faraday Technology Corporation
+ *
+ * Author: Yuan-Hsin Chen <yhchen@faraday-tech.com>
+ *        Feng-Hsin Chiang <john453@faraday-tech.com>
+ *        Po-Yu Chuang <ratbert.chuang@gmail.com>
+ *
+ * Most of code borrowed from the Linux-3.7 EHCI driver
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/dmapool.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/hrtimer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/unaligned.h>
+
+/*-------------------------------------------------------------------------*/
+#define DRIVER_AUTHOR "Yuan-Hsin Chen"
+#define DRIVER_DESC "FOTG210 Host Controller (EHCI) Driver"
+
+static const char      hcd_name[] = "fotg210_hcd";
+
+#undef VERBOSE_DEBUG
+#undef FOTG210_URB_TRACE
+
+#ifdef DEBUG
+#define FOTG210_STATS
+#endif
+
+/* magic numbers that can affect system performance */
+#define        FOTG210_TUNE_CERR               3 /* 0-3 qtd retries; 0 == don't stop */
+#define        FOTG210_TUNE_RL_HS              4 /* nak throttle; see 4.9 */
+#define        FOTG210_TUNE_RL_TT              0
+#define        FOTG210_TUNE_MULT_HS    1       /* 1-3 transactions/uframe; 4.10.3 */
+#define        FOTG210_TUNE_MULT_TT    1
+/*
+ * Some drivers think it's safe to schedule isochronous transfers more than
+ * 256 ms into the future (partly as a result of an old bug in the scheduling
+ * code).  In an attempt to avoid trouble, we will use a minimum scheduling
+ * length of 512 frames instead of 256.
+ */
+#define        FOTG210_TUNE_FLS                1 /* (medium) 512-frame schedule */
+
+/* Initial IRQ latency:  faster than hw default */
+static int log2_irq_thresh;            /* 0 to 6 */
+module_param(log2_irq_thresh, int, S_IRUGO);
+MODULE_PARM_DESC(log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
+
+/* initial park setting:  slower than hw default */
+static unsigned park;
+module_param(park, uint, S_IRUGO);
+MODULE_PARM_DESC(park, "park setting; 1-3 back-to-back async packets");
+
+/* for link power management(LPM) feature */
+static unsigned int hird;
+module_param(hird, int, S_IRUGO);
+MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us");
+
+#define        INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
+
+#include "fotg210.h"
+
+/*-------------------------------------------------------------------------*/
+
+#define fotg210_dbg(fotg210, fmt, args...) \
+       dev_dbg(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args)
+#define fotg210_err(fotg210, fmt, args...) \
+       dev_err(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args)
+#define fotg210_info(fotg210, fmt, args...) \
+       dev_info(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args)
+#define fotg210_warn(fotg210, fmt, args...) \
+       dev_warn(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args)
+
+#ifdef VERBOSE_DEBUG
+#      define fotg210_vdbg fotg210_dbg
+#else
+       static inline void fotg210_vdbg(struct fotg210_hcd *fotg210, ...) {}
+#endif
+
+#ifdef DEBUG
+
+/* check the values in the HCSPARAMS register
+ * (host controller _Structural_ parameters)
+ * see EHCI spec, Table 2-4 for each value
+ */
+static void dbg_hcs_params(struct fotg210_hcd *fotg210, char *label)
+{
+       u32     params = fotg210_readl(fotg210, &fotg210->caps->hcs_params);
+
+       fotg210_dbg(fotg210,
+               "%s hcs_params 0x%x ports=%d\n",
+               label, params,
+               HCS_N_PORTS(params)
+               );
+}
+#else
+
+static inline void dbg_hcs_params(struct fotg210_hcd *fotg210, char *label) {}
+
+#endif
+
+#ifdef DEBUG
+
+/* check the values in the HCCPARAMS register
+ * (host controller _Capability_ parameters)
+ * see EHCI Spec, Table 2-5 for each value
+ * */
+static void dbg_hcc_params(struct fotg210_hcd *fotg210, char *label)
+{
+       u32     params = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
+
+       fotg210_dbg(fotg210,
+               "%s hcc_params %04x uframes %s%s\n",
+               label,
+               params,
+               HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
+               HCC_CANPARK(params) ? " park" : "");
+}
+#else
+
+static inline void dbg_hcc_params(struct fotg210_hcd *fotg210, char *label) {}
+
+#endif
+
+#ifdef DEBUG
+
+static void __maybe_unused
+dbg_qtd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd)
+{
+       fotg210_dbg(fotg210, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
+               hc32_to_cpup(fotg210, &qtd->hw_next),
+               hc32_to_cpup(fotg210, &qtd->hw_alt_next),
+               hc32_to_cpup(fotg210, &qtd->hw_token),
+               hc32_to_cpup(fotg210, &qtd->hw_buf[0]));
+       if (qtd->hw_buf[1])
+               fotg210_dbg(fotg210, "  p1=%08x p2=%08x p3=%08x p4=%08x\n",
+                       hc32_to_cpup(fotg210, &qtd->hw_buf[1]),
+                       hc32_to_cpup(fotg210, &qtd->hw_buf[2]),
+                       hc32_to_cpup(fotg210, &qtd->hw_buf[3]),
+                       hc32_to_cpup(fotg210, &qtd->hw_buf[4]));
+}
+
+static void __maybe_unused
+dbg_qh(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+       struct fotg210_qh_hw *hw = qh->hw;
+
+       fotg210_dbg(fotg210, "%s qh %p n%08x info %x %x qtd %x\n", label,
+               qh, hw->hw_next, hw->hw_info1, hw->hw_info2, hw->hw_current);
+       dbg_qtd("overlay", fotg210, (struct fotg210_qtd *) &hw->hw_qtd_next);
+}
+
+static void __maybe_unused
+dbg_itd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_itd *itd)
+{
+       fotg210_dbg(fotg210, "%s[%d] itd %p, next %08x, urb %p\n",
+               label, itd->frame, itd, hc32_to_cpu(fotg210, itd->hw_next),
+               itd->urb);
+       fotg210_dbg(fotg210,
+               "  trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+               hc32_to_cpu(fotg210, itd->hw_transaction[0]),
+               hc32_to_cpu(fotg210, itd->hw_transaction[1]),
+               hc32_to_cpu(fotg210, itd->hw_transaction[2]),
+               hc32_to_cpu(fotg210, itd->hw_transaction[3]),
+               hc32_to_cpu(fotg210, itd->hw_transaction[4]),
+               hc32_to_cpu(fotg210, itd->hw_transaction[5]),
+               hc32_to_cpu(fotg210, itd->hw_transaction[6]),
+               hc32_to_cpu(fotg210, itd->hw_transaction[7]));
+       fotg210_dbg(fotg210,
+               "  buf:   %08x %08x %08x %08x %08x %08x %08x\n",
+               hc32_to_cpu(fotg210, itd->hw_bufp[0]),
+               hc32_to_cpu(fotg210, itd->hw_bufp[1]),
+               hc32_to_cpu(fotg210, itd->hw_bufp[2]),
+               hc32_to_cpu(fotg210, itd->hw_bufp[3]),
+               hc32_to_cpu(fotg210, itd->hw_bufp[4]),
+               hc32_to_cpu(fotg210, itd->hw_bufp[5]),
+               hc32_to_cpu(fotg210, itd->hw_bufp[6]));
+       fotg210_dbg(fotg210, "  index: %d %d %d %d %d %d %d %d\n",
+               itd->index[0], itd->index[1], itd->index[2],
+               itd->index[3], itd->index[4], itd->index[5],
+               itd->index[6], itd->index[7]);
+}
+
+static int __maybe_unused
+dbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
+{
+       return scnprintf(buf, len,
+               "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s",
+               label, label[0] ? " " : "", status,
+               (status & STS_ASS) ? " Async" : "",
+               (status & STS_PSS) ? " Periodic" : "",
+               (status & STS_RECL) ? " Recl" : "",
+               (status & STS_HALT) ? " Halt" : "",
+               (status & STS_IAA) ? " IAA" : "",
+               (status & STS_FATAL) ? " FATAL" : "",
+               (status & STS_FLR) ? " FLR" : "",
+               (status & STS_PCD) ? " PCD" : "",
+               (status & STS_ERR) ? " ERR" : "",
+               (status & STS_INT) ? " INT" : ""
+               );
+}
+
+static int __maybe_unused
+dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
+{
+       return scnprintf(buf, len,
+               "%s%sintrenable %02x%s%s%s%s%s%s",
+               label, label[0] ? " " : "", enable,
+               (enable & STS_IAA) ? " IAA" : "",
+               (enable & STS_FATAL) ? " FATAL" : "",
+               (enable & STS_FLR) ? " FLR" : "",
+               (enable & STS_PCD) ? " PCD" : "",
+               (enable & STS_ERR) ? " ERR" : "",
+               (enable & STS_INT) ? " INT" : ""
+               );
+}
+
+static const char *const fls_strings[] = { "1024", "512", "256", "??" };
+
+static int
+dbg_command_buf(char *buf, unsigned len, const char *label, u32 command)
+{
+       return scnprintf(buf, len,
+               "%s%scommand %07x %s=%d ithresh=%d%s%s%s "
+               "period=%s%s %s",
+               label, label[0] ? " " : "", command,
+               (command & CMD_PARK) ? " park" : "(park)",
+               CMD_PARK_CNT(command),
+               (command >> 16) & 0x3f,
+               (command & CMD_IAAD) ? " IAAD" : "",
+               (command & CMD_ASE) ? " Async" : "",
+               (command & CMD_PSE) ? " Periodic" : "",
+               fls_strings[(command >> 2) & 0x3],
+               (command & CMD_RESET) ? " Reset" : "",
+               (command & CMD_RUN) ? "RUN" : "HALT"
+               );
+}
+
+static int
+dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)
+{
+       char    *sig;
+
+       /* signaling state */
+       switch (status & (3 << 10)) {
+       case 0 << 10:
+               sig = "se0";
+               break;
+       case 1 << 10:
+               sig = "k";
+               break; /* low speed */
+       case 2 << 10:
+               sig = "j";
+               break;
+       default:
+               sig = "?";
+               break;
+       }
+
+       return scnprintf(buf, len,
+               "%s%sport:%d status %06x %d "
+               "sig=%s%s%s%s%s%s%s%s",
+               label, label[0] ? " " : "", port, status,
+               status>>25,/*device address */
+               sig,
+               (status & PORT_RESET) ? " RESET" : "",
+               (status & PORT_SUSPEND) ? " SUSPEND" : "",
+               (status & PORT_RESUME) ? " RESUME" : "",
+               (status & PORT_PEC) ? " PEC" : "",
+               (status & PORT_PE) ? " PE" : "",
+               (status & PORT_CSC) ? " CSC" : "",
+               (status & PORT_CONNECT) ? " CONNECT" : "");
+}
+
+#else
+static inline void __maybe_unused
+dbg_qh(char *label, struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{}
+
+static inline int __maybe_unused
+dbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
+{ return 0; }
+
+static inline int __maybe_unused
+dbg_command_buf(char *buf, unsigned len, const char *label, u32 command)
+{ return 0; }
+
+static inline int __maybe_unused
+dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
+{ return 0; }
+
+static inline int __maybe_unused
+dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)
+{ return 0; }
+
+#endif /* DEBUG */
+
+/* functions have the "wrong" filename when they're output... */
+#define dbg_status(fotg210, label, status) { \
+       char _buf[80]; \
+       dbg_status_buf(_buf, sizeof(_buf), label, status); \
+       fotg210_dbg(fotg210, "%s\n", _buf); \
+}
+
+#define dbg_cmd(fotg210, label, command) { \
+       char _buf[80]; \
+       dbg_command_buf(_buf, sizeof(_buf), label, command); \
+       fotg210_dbg(fotg210, "%s\n", _buf); \
+}
+
+#define dbg_port(fotg210, label, port, status) { \
+       char _buf[80]; \
+       dbg_port_buf(_buf, sizeof(_buf), label, port, status); \
+       fotg210_dbg(fotg210, "%s\n", _buf); \
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef STUB_DEBUG_FILES
+
+static inline void create_debug_files(struct fotg210_hcd *bus) { }
+static inline void remove_debug_files(struct fotg210_hcd *bus) { }
+
+#else
+
+/* troubleshooting help: expose state in debugfs */
+
+static int debug_async_open(struct inode *, struct file *);
+static int debug_periodic_open(struct inode *, struct file *);
+static int debug_registers_open(struct inode *, struct file *);
+static int debug_async_open(struct inode *, struct file *);
+
+static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
+static int debug_close(struct inode *, struct file *);
+
+static const struct file_operations debug_async_fops = {
+       .owner          = THIS_MODULE,
+       .open           = debug_async_open,
+       .read           = debug_output,
+       .release        = debug_close,
+       .llseek         = default_llseek,
+};
+static const struct file_operations debug_periodic_fops = {
+       .owner          = THIS_MODULE,
+       .open           = debug_periodic_open,
+       .read           = debug_output,
+       .release        = debug_close,
+       .llseek         = default_llseek,
+};
+static const struct file_operations debug_registers_fops = {
+       .owner          = THIS_MODULE,
+       .open           = debug_registers_open,
+       .read           = debug_output,
+       .release        = debug_close,
+       .llseek         = default_llseek,
+};
+
+static struct dentry *fotg210_debug_root;
+
+struct debug_buffer {
+       ssize_t (*fill_func)(struct debug_buffer *);    /* fill method */
+       struct usb_bus *bus;
+       struct mutex mutex;     /* protect filling of buffer */
+       size_t count;           /* number of characters filled into buffer */
+       char *output_buf;
+       size_t alloc_size;
+};
+
+#define speed_char(info1)({ char tmp; \
+               switch (info1 & (3 << 12)) { \
+               case QH_FULL_SPEED:     \
+                       tmp = 'f'; break; \
+               case QH_LOW_SPEED:      \
+                       tmp = 'l'; break; \
+               case QH_HIGH_SPEED:     \
+                       tmp = 'h'; break; \
+               default:                \
+                       tmp = '?'; break; \
+               }; tmp; })
+
+static inline char token_mark(struct fotg210_hcd *fotg210, __hc32 token)
+{
+       __u32 v = hc32_to_cpu(fotg210, token);
+
+       if (v & QTD_STS_ACTIVE)
+               return '*';
+       if (v & QTD_STS_HALT)
+               return '-';
+       if (!IS_SHORT_READ(v))
+               return ' ';
+       /* tries to advance through hw_alt_next */
+       return '/';
+}
+
+static void qh_lines(
+       struct fotg210_hcd *fotg210,
+       struct fotg210_qh *qh,
+       char **nextp,
+       unsigned *sizep
+)
+{
+       u32                     scratch;
+       u32                     hw_curr;
+       struct fotg210_qtd      *td;
+       unsigned                temp;
+       unsigned                size = *sizep;
+       char                    *next = *nextp;
+       char                    mark;
+       __le32                  list_end = FOTG210_LIST_END(fotg210);
+       struct fotg210_qh_hw    *hw = qh->hw;
+
+       if (hw->hw_qtd_next == list_end)        /* NEC does this */
+               mark = '@';
+       else
+               mark = token_mark(fotg210, hw->hw_token);
+       if (mark == '/') {      /* qh_alt_next controls qh advance? */
+               if ((hw->hw_alt_next & QTD_MASK(fotg210))
+                               == fotg210->async->hw->hw_alt_next)
+                       mark = '#';     /* blocked */
+               else if (hw->hw_alt_next == list_end)
+                       mark = '.';     /* use hw_qtd_next */
+               /* else alt_next points to some other qtd */
+       }
+       scratch = hc32_to_cpup(fotg210, &hw->hw_info1);
+       hw_curr = (mark == '*') ? hc32_to_cpup(fotg210, &hw->hw_current) : 0;
+       temp = scnprintf(next, size,
+                       "qh/%p dev%d %cs ep%d %08x %08x(%08x%c %s nak%d)",
+                       qh, scratch & 0x007f,
+                       speed_char(scratch),
+                       (scratch >> 8) & 0x000f,
+                       scratch, hc32_to_cpup(fotg210, &hw->hw_info2),
+                       hc32_to_cpup(fotg210, &hw->hw_token), mark,
+                       (cpu_to_hc32(fotg210, QTD_TOGGLE) & hw->hw_token)
+                               ? "data1" : "data0",
+                       (hc32_to_cpup(fotg210, &hw->hw_alt_next) >> 1) & 0x0f);
+       size -= temp;
+       next += temp;
+
+       /* hc may be modifying the list as we read it ... */
+       list_for_each_entry(td, &qh->qtd_list, qtd_list) {
+               scratch = hc32_to_cpup(fotg210, &td->hw_token);
+               mark = ' ';
+               if (hw_curr == td->qtd_dma)
+                       mark = '*';
+               else if (hw->hw_qtd_next == cpu_to_hc32(fotg210, td->qtd_dma))
+                       mark = '+';
+               else if (QTD_LENGTH(scratch)) {
+                       if (td->hw_alt_next == fotg210->async->hw->hw_alt_next)
+                               mark = '#';
+                       else if (td->hw_alt_next != list_end)
+                               mark = '/';
+               }
+               temp = snprintf(next, size,
+                               "\n\t%p%c%s len=%d %08x urb %p",
+                               td, mark, ({ char *tmp;
+                                switch ((scratch>>8)&0x03) {
+                                case 0:
+                                       tmp = "out";
+                                       break;
+                                case 1:
+                                       tmp = "in";
+                                       break;
+                                case 2:
+                                       tmp = "setup";
+                                       break;
+                                default:
+                                       tmp = "?";
+                                       break;
+                                } tmp; }),
+                               (scratch >> 16) & 0x7fff,
+                               scratch,
+                               td->urb);
+               if (size < temp)
+                       temp = size;
+               size -= temp;
+               next += temp;
+               if (temp == size)
+                       goto done;
+       }
+
+       temp = snprintf(next, size, "\n");
+       if (size < temp)
+               temp = size;
+       size -= temp;
+       next += temp;
+
+done:
+       *sizep = size;
+       *nextp = next;
+}
+
+static ssize_t fill_async_buffer(struct debug_buffer *buf)
+{
+       struct usb_hcd          *hcd;
+       struct fotg210_hcd      *fotg210;
+       unsigned long           flags;
+       unsigned                temp, size;
+       char                    *next;
+       struct fotg210_qh               *qh;
+
+       hcd = bus_to_hcd(buf->bus);
+       fotg210 = hcd_to_fotg210(hcd);
+       next = buf->output_buf;
+       size = buf->alloc_size;
+
+       *next = 0;
+
+       /* dumps a snapshot of the async schedule.
+        * usually empty except for long-term bulk reads, or head.
+        * one QH per line, and TDs we know about
+        */
+       spin_lock_irqsave(&fotg210->lock, flags);
+       for (qh = fotg210->async->qh_next.qh; size > 0 && qh;
+            qh = qh->qh_next.qh)
+               qh_lines(fotg210, qh, &next, &size);
+       if (fotg210->async_unlink && size > 0) {
+               temp = scnprintf(next, size, "\nunlink =\n");
+               size -= temp;
+               next += temp;
+
+               for (qh = fotg210->async_unlink; size > 0 && qh;
+                               qh = qh->unlink_next)
+                       qh_lines(fotg210, qh, &next, &size);
+       }
+       spin_unlock_irqrestore(&fotg210->lock, flags);
+
+       return strlen(buf->output_buf);
+}
+
+#define DBG_SCHED_LIMIT 64
+static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
+{
+       struct usb_hcd          *hcd;
+       struct fotg210_hcd              *fotg210;
+       unsigned long           flags;
+       union fotg210_shadow    p, *seen;
+       unsigned                temp, size, seen_count;
+       char                    *next;
+       unsigned                i;
+       __hc32                  tag;
+
+       seen = kmalloc(DBG_SCHED_LIMIT * sizeof(*seen), GFP_ATOMIC);
+       if (!seen)
+               return 0;
+       seen_count = 0;
+
+       hcd = bus_to_hcd(buf->bus);
+       fotg210 = hcd_to_fotg210(hcd);
+       next = buf->output_buf;
+       size = buf->alloc_size;
+
+       temp = scnprintf(next, size, "size = %d\n", fotg210->periodic_size);
+       size -= temp;
+       next += temp;
+
+       /* dump a snapshot of the periodic schedule.
+        * iso changes, interrupt usually doesn't.
+        */
+       spin_lock_irqsave(&fotg210->lock, flags);
+       for (i = 0; i < fotg210->periodic_size; i++) {
+               p = fotg210->pshadow[i];
+               if (likely(!p.ptr))
+                       continue;
+               tag = Q_NEXT_TYPE(fotg210, fotg210->periodic[i]);
+
+               temp = scnprintf(next, size, "%4d: ", i);
+               size -= temp;
+               next += temp;
+
+               do {
+                       struct fotg210_qh_hw *hw;
+
+                       switch (hc32_to_cpu(fotg210, tag)) {
+                       case Q_TYPE_QH:
+                               hw = p.qh->hw;
+                               temp = scnprintf(next, size, " qh%d-%04x/%p",
+                                               p.qh->period,
+                                               hc32_to_cpup(fotg210,
+                                                       &hw->hw_info2)
+                                                       /* uframe masks */
+                                                       & (QH_CMASK | QH_SMASK),
+                                               p.qh);
+                               size -= temp;
+                               next += temp;
+                               /* don't repeat what follows this qh */
+                               for (temp = 0; temp < seen_count; temp++) {
+                                       if (seen[temp].ptr != p.ptr)
+                                               continue;
+                                       if (p.qh->qh_next.ptr) {
+                                               temp = scnprintf(next, size,
+                                                       " ...");
+                                               size -= temp;
+                                               next += temp;
+                                       }
+                                       break;
+                               }
+                               /* show more info the first time around */
+                               if (temp == seen_count) {
+                                       u32     scratch = hc32_to_cpup(fotg210,
+                                                       &hw->hw_info1);
+                                       struct fotg210_qtd      *qtd;
+                                       char            *type = "";
+
+                                       /* count tds, get ep direction */
+                                       temp = 0;
+                                       list_for_each_entry(qtd,
+                                                       &p.qh->qtd_list,
+                                                       qtd_list) {
+                                               temp++;
+                                               switch (0x03 & (hc32_to_cpu(
+                                                       fotg210,
+                                                       qtd->hw_token) >> 8)) {
+                                               case 0:
+                                                       type = "out";
+                                                       continue;
+                                               case 1:
+                                                       type = "in";
+                                                       continue;
+                                               }
+                                       }
+
+                                       temp = scnprintf(next, size,
+                                               "(%c%d ep%d%s "
+                                               "[%d/%d] q%d p%d)",
+                                               speed_char(scratch),
+                                               scratch & 0x007f,
+                                               (scratch >> 8) & 0x000f, type,
+                                               p.qh->usecs, p.qh->c_usecs,
+                                               temp,
+                                               0x7ff & (scratch >> 16));
+
+                                       if (seen_count < DBG_SCHED_LIMIT)
+                                               seen[seen_count++].qh = p.qh;
+                               } else
+                                       temp = 0;
+                               tag = Q_NEXT_TYPE(fotg210, hw->hw_next);
+                               p = p.qh->qh_next;
+                               break;
+                       case Q_TYPE_FSTN:
+                               temp = scnprintf(next, size,
+                                       " fstn-%8x/%p", p.fstn->hw_prev,
+                                       p.fstn);
+                               tag = Q_NEXT_TYPE(fotg210, p.fstn->hw_next);
+                               p = p.fstn->fstn_next;
+                               break;
+                       case Q_TYPE_ITD:
+                               temp = scnprintf(next, size,
+                                       " itd/%p", p.itd);
+                               tag = Q_NEXT_TYPE(fotg210, p.itd->hw_next);
+                               p = p.itd->itd_next;
+                               break;
+                       }
+                       size -= temp;
+                       next += temp;
+               } while (p.ptr);
+
+               temp = scnprintf(next, size, "\n");
+               size -= temp;
+               next += temp;
+       }
+       spin_unlock_irqrestore(&fotg210->lock, flags);
+       kfree(seen);
+
+       return buf->alloc_size - size;
+}
+#undef DBG_SCHED_LIMIT
+
+static const char *rh_state_string(struct fotg210_hcd *fotg210)
+{
+       switch (fotg210->rh_state) {
+       case FOTG210_RH_HALTED:
+               return "halted";
+       case FOTG210_RH_SUSPENDED:
+               return "suspended";
+       case FOTG210_RH_RUNNING:
+               return "running";
+       case FOTG210_RH_STOPPING:
+               return "stopping";
+       }
+       return "?";
+}
+
+static ssize_t fill_registers_buffer(struct debug_buffer *buf)
+{
+       struct usb_hcd          *hcd;
+       struct fotg210_hcd      *fotg210;
+       unsigned long           flags;
+       unsigned                temp, size, i;
+       char                    *next, scratch[80];
+       static const char       fmt[] = "%*s\n";
+       static const char       label[] = "";
+
+       hcd = bus_to_hcd(buf->bus);
+       fotg210 = hcd_to_fotg210(hcd);
+       next = buf->output_buf;
+       size = buf->alloc_size;
+
+       spin_lock_irqsave(&fotg210->lock, flags);
+
+       if (!HCD_HW_ACCESSIBLE(hcd)) {
+               size = scnprintf(next, size,
+                       "bus %s, device %s\n"
+                       "%s\n"
+                       "SUSPENDED(no register access)\n",
+                       hcd->self.controller->bus->name,
+                       dev_name(hcd->self.controller),
+                       hcd->product_desc);
+               goto done;
+       }
+
+       /* Capability Registers */
+       i = HC_VERSION(fotg210, fotg210_readl(fotg210,
+                                             &fotg210->caps->hc_capbase));
+       temp = scnprintf(next, size,
+               "bus %s, device %s\n"
+               "%s\n"
+               "EHCI %x.%02x, rh state %s\n",
+               hcd->self.controller->bus->name,
+               dev_name(hcd->self.controller),
+               hcd->product_desc,
+               i >> 8, i & 0x0ff, rh_state_string(fotg210));
+       size -= temp;
+       next += temp;
+
+       /* FIXME interpret both types of params */
+       i = fotg210_readl(fotg210, &fotg210->caps->hcs_params);
+       temp = scnprintf(next, size, "structural params 0x%08x\n", i);
+       size -= temp;
+       next += temp;
+
+       i = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
+       temp = scnprintf(next, size, "capability params 0x%08x\n", i);
+       size -= temp;
+       next += temp;
+
+       /* Operational Registers */
+       temp = dbg_status_buf(scratch, sizeof(scratch), label,
+                       fotg210_readl(fotg210, &fotg210->regs->status));
+       temp = scnprintf(next, size, fmt, temp, scratch);
+       size -= temp;
+       next += temp;
+
+       temp = dbg_command_buf(scratch, sizeof(scratch), label,
+                       fotg210_readl(fotg210, &fotg210->regs->command));
+       temp = scnprintf(next, size, fmt, temp, scratch);
+       size -= temp;
+       next += temp;
+
+       temp = dbg_intr_buf(scratch, sizeof(scratch), label,
+                       fotg210_readl(fotg210, &fotg210->regs->intr_enable));
+       temp = scnprintf(next, size, fmt, temp, scratch);
+       size -= temp;
+       next += temp;
+
+       temp = scnprintf(next, size, "uframe %04x\n",
+                       fotg210_read_frame_index(fotg210));
+       size -= temp;
+       next += temp;
+
+       if (fotg210->async_unlink) {
+               temp = scnprintf(next, size, "async unlink qh %p\n",
+                               fotg210->async_unlink);
+               size -= temp;
+               next += temp;
+       }
+
+#ifdef FOTG210_STATS
+       temp = scnprintf(next, size,
+               "irq normal %ld err %ld iaa %ld(lost %ld)\n",
+               fotg210->stats.normal, fotg210->stats.error, fotg210->stats.iaa,
+               fotg210->stats.lost_iaa);
+       size -= temp;
+       next += temp;
+
+       temp = scnprintf(next, size, "complete %ld unlink %ld\n",
+               fotg210->stats.complete, fotg210->stats.unlink);
+       size -= temp;
+       next += temp;
+#endif
+
+done:
+       spin_unlock_irqrestore(&fotg210->lock, flags);
+
+       return buf->alloc_size - size;
+}
+
+static struct debug_buffer *alloc_buffer(struct usb_bus *bus,
+                               ssize_t (*fill_func)(struct debug_buffer *))
+{
+       struct debug_buffer *buf;
+
+       buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
+
+       if (buf) {
+               buf->bus = bus;
+               buf->fill_func = fill_func;
+               mutex_init(&buf->mutex);
+               buf->alloc_size = PAGE_SIZE;
+       }
+
+       return buf;
+}
+
+static int fill_buffer(struct debug_buffer *buf)
+{
+       int ret = 0;
+
+       if (!buf->output_buf)
+               buf->output_buf = vmalloc(buf->alloc_size);
+
+       if (!buf->output_buf) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = buf->fill_func(buf);
+
+       if (ret >= 0) {
+               buf->count = ret;
+               ret = 0;
+       }
+
+out:
+       return ret;
+}
+
+static ssize_t debug_output(struct file *file, char __user *user_buf,
+                           size_t len, loff_t *offset)
+{
+       struct debug_buffer *buf = file->private_data;
+       int ret = 0;
+
+       mutex_lock(&buf->mutex);
+       if (buf->count == 0) {
+               ret = fill_buffer(buf);
+               if (ret != 0) {
+                       mutex_unlock(&buf->mutex);
+                       goto out;
+               }
+       }
+       mutex_unlock(&buf->mutex);
+
+       ret = simple_read_from_buffer(user_buf, len, offset,
+                                     buf->output_buf, buf->count);
+
+out:
+       return ret;
+
+}
+
+static int debug_close(struct inode *inode, struct file *file)
+{
+       struct debug_buffer *buf = file->private_data;
+
+       if (buf) {
+               vfree(buf->output_buf);
+               kfree(buf);
+       }
+
+       return 0;
+}
+static int debug_async_open(struct inode *inode, struct file *file)
+{
+       file->private_data = alloc_buffer(inode->i_private, fill_async_buffer);
+
+       return file->private_data ? 0 : -ENOMEM;
+}
+
+static int debug_periodic_open(struct inode *inode, struct file *file)
+{
+       struct debug_buffer *buf;
+       buf = alloc_buffer(inode->i_private, fill_periodic_buffer);
+       if (!buf)
+               return -ENOMEM;
+
+       buf->alloc_size = (sizeof(void *) == 4 ? 6 : 8)*PAGE_SIZE;
+       file->private_data = buf;
+       return 0;
+}
+
+static int debug_registers_open(struct inode *inode, struct file *file)
+{
+       file->private_data = alloc_buffer(inode->i_private,
+                                         fill_registers_buffer);
+
+       return file->private_data ? 0 : -ENOMEM;
+}
+
+static inline void create_debug_files(struct fotg210_hcd *fotg210)
+{
+       struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self;
+
+       fotg210->debug_dir = debugfs_create_dir(bus->bus_name,
+                                               fotg210_debug_root);
+       if (!fotg210->debug_dir)
+               return;
+
+       if (!debugfs_create_file("async", S_IRUGO, fotg210->debug_dir, bus,
+                                               &debug_async_fops))
+               goto file_error;
+
+       if (!debugfs_create_file("periodic", S_IRUGO, fotg210->debug_dir, bus,
+                                               &debug_periodic_fops))
+               goto file_error;
+
+       if (!debugfs_create_file("registers", S_IRUGO, fotg210->debug_dir, bus,
+                                                   &debug_registers_fops))
+               goto file_error;
+
+       return;
+
+file_error:
+       debugfs_remove_recursive(fotg210->debug_dir);
+}
+
+static inline void remove_debug_files(struct fotg210_hcd *fotg210)
+{
+       debugfs_remove_recursive(fotg210->debug_dir);
+}
+
+#endif /* STUB_DEBUG_FILES */
+/*-------------------------------------------------------------------------*/
+
+/*
+ * handshake - spin reading hc until handshake completes or fails
+ * @ptr: address of hc register to be read
+ * @mask: bits to look at in result of read
+ * @done: value of those bits when handshake succeeds
+ * @usec: timeout in microseconds
+ *
+ * Returns negative errno, or zero on success
+ *
+ * Success happens when the "mask" bits have the specified value (hardware
+ * handshake done).  There are two failure modes:  "usec" have passed (major
+ * hardware flakeout), or the register reads as all-ones (hardware removed).
+ *
+ * That last failure should_only happen in cases like physical cardbus eject
+ * before driver shutdown. But it also seems to be caused by bugs in cardbus
+ * bridge shutdown:  shutting down the bridge before the devices using it.
+ */
+static int handshake(struct fotg210_hcd *fotg210, void __iomem *ptr,
+                     u32 mask, u32 done, int usec)
+{
+       u32     result;
+
+       do {
+               result = fotg210_readl(fotg210, ptr);
+               if (result == ~(u32)0)          /* card removed */
+                       return -ENODEV;
+               result &= mask;
+               if (result == done)
+                       return 0;
+               udelay(1);
+               usec--;
+       } while (usec > 0);
+       return -ETIMEDOUT;
+}
+
+/*
+ * 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 fotg210_halt(struct fotg210_hcd *fotg210)
+{
+       u32     temp;
+
+       spin_lock_irq(&fotg210->lock);
+
+       /* disable any irqs left enabled by previous code */
+       fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
+
+       /*
+        * This routine gets called during probe before fotg210->command
+        * has been initialized, so we can't rely on its value.
+        */
+       fotg210->command &= ~CMD_RUN;
+       temp = fotg210_readl(fotg210, &fotg210->regs->command);
+       temp &= ~(CMD_RUN | CMD_IAAD);
+       fotg210_writel(fotg210, temp, &fotg210->regs->command);
+
+       spin_unlock_irq(&fotg210->lock);
+       synchronize_irq(fotg210_to_hcd(fotg210)->irq);
+
+       return handshake(fotg210, &fotg210->regs->status,
+                         STS_HALT, STS_HALT, 16 * 125);
+}
+
+/*
+ * Reset a non-running (STS_HALT == 1) controller.
+ * Must be called with interrupts enabled and the lock not held.
+ */
+static int fotg210_reset(struct fotg210_hcd *fotg210)
+{
+       int     retval;
+       u32     command = fotg210_readl(fotg210, &fotg210->regs->command);
+
+       /* If the EHCI debug controller is active, special care must be
+        * taken before and after a host controller reset */
+       if (fotg210->debug && !dbgp_reset_prep(fotg210_to_hcd(fotg210)))
+               fotg210->debug = NULL;
+
+       command |= CMD_RESET;
+       dbg_cmd(fotg210, "reset", command);
+       fotg210_writel(fotg210, command, &fotg210->regs->command);
+       fotg210->rh_state = FOTG210_RH_HALTED;
+       fotg210->next_statechange = jiffies;
+       retval = handshake(fotg210, &fotg210->regs->command,
+                           CMD_RESET, 0, 250 * 1000);
+
+       if (retval)
+               return retval;
+
+       if (fotg210->debug)
+               dbgp_external_startup(fotg210_to_hcd(fotg210));
+
+       fotg210->port_c_suspend = fotg210->suspended_ports =
+                       fotg210->resuming_ports = 0;
+       return retval;
+}
+
+/*
+ * Idle the controller (turn off the schedules).
+ * Must be called with interrupts enabled and the lock not held.
+ */
+static void fotg210_quiesce(struct fotg210_hcd *fotg210)
+{
+       u32     temp;
+
+       if (fotg210->rh_state != FOTG210_RH_RUNNING)
+               return;
+
+       /* wait for any schedule enables/disables to take effect */
+       temp = (fotg210->command << 10) & (STS_ASS | STS_PSS);
+       handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, temp,
+                 16 * 125);
+
+       /* then disable anything that's still active */
+       spin_lock_irq(&fotg210->lock);
+       fotg210->command &= ~(CMD_ASE | CMD_PSE);
+       fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
+       spin_unlock_irq(&fotg210->lock);
+
+       /* hardware can take 16 microframes to turn off ... */
+       handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, 0,
+                 16 * 125);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void end_unlink_async(struct fotg210_hcd *fotg210);
+static void unlink_empty_async(struct fotg210_hcd *fotg210);
+static void fotg210_work(struct fotg210_hcd *fotg210);
+static void start_unlink_intr(struct fotg210_hcd *fotg210,
+                             struct fotg210_qh *qh);
+static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
+
+/*-------------------------------------------------------------------------*/
+
+/* Set a bit in the USBCMD register */
+static void fotg210_set_command_bit(struct fotg210_hcd *fotg210, u32 bit)
+{
+       fotg210->command |= bit;
+       fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
+
+       /* unblock posted write */
+       fotg210_readl(fotg210, &fotg210->regs->command);
+}
+
+/* Clear a bit in the USBCMD register */
+static void fotg210_clear_command_bit(struct fotg210_hcd *fotg210, u32 bit)
+{
+       fotg210->command &= ~bit;
+       fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
+
+       /* unblock posted write */
+       fotg210_readl(fotg210, &fotg210->regs->command);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI timer support...  Now using hrtimers.
+ *
+ * Lots of different events are triggered from fotg210->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
+ * fotg210->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
+ * fotg210->next_hrtimer_event.  Whenever fotg210->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 fotg210_hrtimer_event in fotg210.h.
+ */
+static unsigned event_delays_ns[] = {
+       1 * NSEC_PER_MSEC,      /* FOTG210_HRTIMER_POLL_ASS */
+       1 * NSEC_PER_MSEC,      /* FOTG210_HRTIMER_POLL_PSS */
+       1 * NSEC_PER_MSEC,      /* FOTG210_HRTIMER_POLL_DEAD */
+       1125 * NSEC_PER_USEC,   /* FOTG210_HRTIMER_UNLINK_INTR */
+       2 * NSEC_PER_MSEC,      /* FOTG210_HRTIMER_FREE_ITDS */
+       6 * NSEC_PER_MSEC,      /* FOTG210_HRTIMER_ASYNC_UNLINKS */
+       10 * NSEC_PER_MSEC,     /* FOTG210_HRTIMER_IAA_WATCHDOG */
+       10 * NSEC_PER_MSEC,     /* FOTG210_HRTIMER_DISABLE_PERIODIC */
+       15 * NSEC_PER_MSEC,     /* FOTG210_HRTIMER_DISABLE_ASYNC */
+       100 * NSEC_PER_MSEC,    /* FOTG210_HRTIMER_IO_WATCHDOG */
+};
+
+/* Enable a pending hrtimer event */
+static void fotg210_enable_event(struct fotg210_hcd *fotg210, unsigned event,
+               bool resched)
+{
+       ktime_t         *timeout = &fotg210->hr_timeouts[event];
+
+       if (resched)
+               *timeout = ktime_add(ktime_get(),
+                               ktime_set(0, event_delays_ns[event]));
+       fotg210->enabled_hrtimer_events |= (1 << event);
+
+       /* Track only the lowest-numbered pending event */
+       if (event < fotg210->next_hrtimer_event) {
+               fotg210->next_hrtimer_event = event;
+               hrtimer_start_range_ns(&fotg210->hrtimer, *timeout,
+                               NSEC_PER_MSEC, HRTIMER_MODE_ABS);
+       }
+}
+
+
+/* Poll the STS_ASS status bit; see when it agrees with CMD_ASE */
+static void fotg210_poll_ASS(struct fotg210_hcd *fotg210)
+{
+       unsigned        actual, want;
+
+       /* Don't enable anything if the controller isn't running (e.g., died) */
+       if (fotg210->rh_state != FOTG210_RH_RUNNING)
+               return;
+
+       want = (fotg210->command & CMD_ASE) ? STS_ASS : 0;
+       actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_ASS;
+
+       if (want != actual) {
+
+               /* Poll again later, but give up after about 20 ms */
+               if (fotg210->ASS_poll_count++ < 20) {
+                       fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_ASS,
+                                            true);
+                       return;
+               }
+               fotg210_dbg(fotg210, "Waited too long for the async schedule status (%x/%x), giving up\n",
+                               want, actual);
+       }
+       fotg210->ASS_poll_count = 0;
+
+       /* The status is up-to-date; restart or stop the schedule as needed */
+       if (want == 0) {        /* Stopped */
+               if (fotg210->async_count > 0)
+                       fotg210_set_command_bit(fotg210, CMD_ASE);
+
+       } else {                /* Running */
+               if (fotg210->async_count == 0) {
+
+                       /* Turn off the schedule after a while */
+                       fotg210_enable_event(fotg210,
+                                            FOTG210_HRTIMER_DISABLE_ASYNC,
+                                            true);
+               }
+       }
+}
+
+/* Turn off the async schedule after a brief delay */
+static void fotg210_disable_ASE(struct fotg210_hcd *fotg210)
+{
+       fotg210_clear_command_bit(fotg210, CMD_ASE);
+}
+
+
+/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */
+static void fotg210_poll_PSS(struct fotg210_hcd *fotg210)
+{
+       unsigned        actual, want;
+
+       /* Don't do anything if the controller isn't running (e.g., died) */
+       if (fotg210->rh_state != FOTG210_RH_RUNNING)
+               return;
+
+       want = (fotg210->command & CMD_PSE) ? STS_PSS : 0;
+       actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_PSS;
+
+       if (want != actual) {
+
+               /* Poll again later, but give up after about 20 ms */
+               if (fotg210->PSS_poll_count++ < 20) {
+                       fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_PSS,
+                                            true);
+                       return;
+               }
+               fotg210_dbg(fotg210, "Waited too long for the periodic schedule status (%x/%x), giving up\n",
+                               want, actual);
+       }
+       fotg210->PSS_poll_count = 0;
+
+       /* The status is up-to-date; restart or stop the schedule as needed */
+       if (want == 0) {        /* Stopped */
+               if (fotg210->periodic_count > 0)
+                       fotg210_set_command_bit(fotg210, CMD_PSE);
+
+       } else {                /* Running */
+               if (fotg210->periodic_count == 0) {
+
+                       /* Turn off the schedule after a while */
+                       fotg210_enable_event(fotg210,
+                                            FOTG210_HRTIMER_DISABLE_PERIODIC,
+                                            true);
+               }
+       }
+}
+
+/* Turn off the periodic schedule after a brief delay */
+static void fotg210_disable_PSE(struct fotg210_hcd *fotg210)
+{
+       fotg210_clear_command_bit(fotg210, CMD_PSE);
+}
+
+
+/* Poll the STS_HALT status bit; see when a dead controller stops */
+static void fotg210_handle_controller_death(struct fotg210_hcd *fotg210)
+{
+       if (!(fotg210_readl(fotg210, &fotg210->regs->status) & STS_HALT)) {
+
+               /* Give up after a few milliseconds */
+               if (fotg210->died_poll_count++ < 5) {
+                       /* Try again later */
+                       fotg210_enable_event(fotg210,
+                                            FOTG210_HRTIMER_POLL_DEAD, true);
+                       return;
+               }
+               fotg210_warn(fotg210, "Waited too long for the controller to stop, giving up\n");
+       }
+
+       /* Clean up the mess */
+       fotg210->rh_state = FOTG210_RH_HALTED;
+       fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
+       fotg210_work(fotg210);
+       end_unlink_async(fotg210);
+
+       /* 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 fotg210_handle_intr_unlinks(struct fotg210_hcd *fotg210)
+{
+       bool            stopped = (fotg210->rh_state < FOTG210_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.
+        */
+       fotg210->intr_unlinking = true;
+       while (fotg210->intr_unlink) {
+               struct fotg210_qh       *qh = fotg210->intr_unlink;
+
+               if (!stopped && qh->unlink_cycle == fotg210->intr_unlink_cycle)
+                       break;
+               fotg210->intr_unlink = qh->unlink_next;
+               qh->unlink_next = NULL;
+               end_unlink_intr(fotg210, qh);
+       }
+
+       /* Handle remaining entries later */
+       if (fotg210->intr_unlink) {
+               fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR,
+                                    true);
+               ++fotg210->intr_unlink_cycle;
+       }
+       fotg210->intr_unlinking = false;
+}
+
+
+/* Start another free-iTDs/siTDs cycle */
+static void start_free_itds(struct fotg210_hcd *fotg210)
+{
+       if (!(fotg210->enabled_hrtimer_events &
+                       BIT(FOTG210_HRTIMER_FREE_ITDS))) {
+               fotg210->last_itd_to_free = list_entry(
+                               fotg210->cached_itd_list.prev,
+                               struct fotg210_itd, itd_list);
+               fotg210_enable_event(fotg210, FOTG210_HRTIMER_FREE_ITDS, true);
+       }
+}
+
+/* Wait for controller to stop using old iTDs and siTDs */
+static void end_free_itds(struct fotg210_hcd *fotg210)
+{
+       struct fotg210_itd              *itd, *n;
+
+       if (fotg210->rh_state < FOTG210_RH_RUNNING)
+               fotg210->last_itd_to_free = NULL;
+
+       list_for_each_entry_safe(itd, n, &fotg210->cached_itd_list, itd_list) {
+               list_del(&itd->itd_list);
+               dma_pool_free(fotg210->itd_pool, itd, itd->itd_dma);
+               if (itd == fotg210->last_itd_to_free)
+                       break;
+       }
+
+       if (!list_empty(&fotg210->cached_itd_list))
+               start_free_itds(fotg210);
+}
+
+
+/* Handle lost (or very late) IAA interrupts */
+static void fotg210_iaa_watchdog(struct fotg210_hcd *fotg210)
+{
+       if (fotg210->rh_state != FOTG210_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 (fotg210->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 = fotg210_readl(fotg210, &fotg210->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 = fotg210_readl(fotg210, &fotg210->regs->status);
+               if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
+                       COUNT(fotg210->stats.lost_iaa);
+                       fotg210_writel(fotg210, STS_IAA,
+                                      &fotg210->regs->status);
+               }
+
+               fotg210_vdbg(fotg210, "IAA watchdog: status %x cmd %x\n",
+                               status, cmd);
+               end_unlink_async(fotg210);
+       }
+}
+
+
+/* Enable the I/O watchdog, if appropriate */
+static void turn_on_io_watchdog(struct fotg210_hcd *fotg210)
+{
+       /* Not needed if the controller isn't running or it's already enabled */
+       if (fotg210->rh_state != FOTG210_RH_RUNNING ||
+                       (fotg210->enabled_hrtimer_events &
+                               BIT(FOTG210_HRTIMER_IO_WATCHDOG)))
+               return;
+
+       /*
+        * Isochronous transfers always need the watchdog.
+        * For other sorts we use it only if the flag is set.
+        */
+       if (fotg210->isoc_count > 0 || (fotg210->need_io_watchdog &&
+                       fotg210->async_count + fotg210->intr_count > 0))
+               fotg210_enable_event(fotg210, FOTG210_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 fotg210_hrtimer_event in fotg210.h.
+ */
+static void (*event_handlers[])(struct fotg210_hcd *) = {
+       fotg210_poll_ASS,                       /* FOTG210_HRTIMER_POLL_ASS */
+       fotg210_poll_PSS,                       /* FOTG210_HRTIMER_POLL_PSS */
+       fotg210_handle_controller_death,        /* FOTG210_HRTIMER_POLL_DEAD */
+       fotg210_handle_intr_unlinks,    /* FOTG210_HRTIMER_UNLINK_INTR */
+       end_free_itds,                  /* FOTG210_HRTIMER_FREE_ITDS */
+       unlink_empty_async,             /* FOTG210_HRTIMER_ASYNC_UNLINKS */
+       fotg210_iaa_watchdog,           /* FOTG210_HRTIMER_IAA_WATCHDOG */
+       fotg210_disable_PSE,            /* FOTG210_HRTIMER_DISABLE_PERIODIC */
+       fotg210_disable_ASE,            /* FOTG210_HRTIMER_DISABLE_ASYNC */
+       fotg210_work,                   /* FOTG210_HRTIMER_IO_WATCHDOG */
+};
+
+static enum hrtimer_restart fotg210_hrtimer_func(struct hrtimer *t)
+{
+       struct fotg210_hcd *fotg210 =
+                       container_of(t, struct fotg210_hcd, hrtimer);
+       ktime_t         now;
+       unsigned long   events;
+       unsigned long   flags;
+       unsigned        e;
+
+       spin_lock_irqsave(&fotg210->lock, flags);
+
+       events = fotg210->enabled_hrtimer_events;
+       fotg210->enabled_hrtimer_events = 0;
+       fotg210->next_hrtimer_event = FOTG210_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, FOTG210_HRTIMER_NUM_EVENTS) {
+               if (now.tv64 >= fotg210->hr_timeouts[e].tv64)
+                       event_handlers[e](fotg210);
+               else
+                       fotg210_enable_event(fotg210, e, false);
+       }
+
+       spin_unlock_irqrestore(&fotg210->lock, flags);
+       return HRTIMER_NORESTART;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define fotg210_bus_suspend    NULL
+#define fotg210_bus_resume     NULL
+
+/*-------------------------------------------------------------------------*/
+
+static int check_reset_complete(
+       struct fotg210_hcd      *fotg210,
+       int             index,
+       u32 __iomem     *status_reg,
+       int             port_status
+) {
+       if (!(port_status & PORT_CONNECT))
+               return port_status;
+
+       /* if reset finished and it's still not enabled -- handoff */
+       if (!(port_status & PORT_PE)) {
+               /* with integrated TT, there's nobody to hand it to! */
+               fotg210_dbg(fotg210,
+                       "Failed to enable port %d on root hub TT\n",
+                       index+1);
+               return port_status;
+       } else {
+               fotg210_dbg(fotg210, "port %d reset complete, port enabled\n",
+                       index + 1);
+       }
+
+       return port_status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+
+/* build "status change" packet (one or two bytes) from HC registers */
+
+static int
+fotg210_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+       struct fotg210_hcd      *fotg210 = hcd_to_fotg210(hcd);
+       u32             temp, status;
+       u32             mask;
+       int             retval = 1;
+       unsigned long   flags;
+
+       /* init status to no-changes */
+       buf[0] = 0;
+
+       /* Inform the core about resumes-in-progress by returning
+        * a non-zero value even if there are no status changes.
+        */
+       status = fotg210->resuming_ports;
+
+       mask = PORT_CSC | PORT_PEC;
+       /* PORT_RESUME from hardware ~= PORT_STAT_C_SUSPEND */
+
+       /* no hub change reports (bit 0) for now (power, ...) */
+
+       /* port N changes (bit N)? */
+       spin_lock_irqsave(&fotg210->lock, flags);
+
+       temp = fotg210_readl(fotg210, &fotg210->regs->port_status);
+
+       /*
+        * Return status information even for ports with OWNER set.
+        * Otherwise khubd wouldn't see the disconnect event when a
+        * high-speed device is switched over to the companion
+        * controller by the user.
+        */
+
+       if ((temp & mask) != 0 || test_bit(0, &fotg210->port_c_suspend)
+                       || (fotg210->reset_done[0] && time_after_eq(
+                               jiffies, fotg210->reset_done[0]))) {
+               buf[0] |= 1 << 1;
+               status = STS_PCD;
+       }
+       /* FIXME autosuspend idle root hubs */
+       spin_unlock_irqrestore(&fotg210->lock, flags);
+       return status ? retval : 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+fotg210_hub_descriptor(
+       struct fotg210_hcd              *fotg210,
+       struct usb_hub_descriptor       *desc
+) {
+       int             ports = HCS_N_PORTS(fotg210->hcs_params);
+       u16             temp;
+
+       desc->bDescriptorType = 0x29;
+       desc->bPwrOn2PwrGood = 10;      /* fotg210 1.0, 2.3.9 says 20ms max */
+       desc->bHubContrCurrent = 0;
+
+       desc->bNbrPorts = ports;
+       temp = 1 + (ports / 8);
+       desc->bDescLength = 7 + 2 * temp;
+
+       /* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+       memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
+       memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
+
+       temp = 0x0008;          /* per-port overcurrent reporting */
+       temp |= 0x0002;         /* no power switching */
+       desc->wHubCharacteristics = cpu_to_le16(temp);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int fotg210_hub_control(
+       struct usb_hcd  *hcd,
+       u16             typeReq,
+       u16             wValue,
+       u16             wIndex,
+       char            *buf,
+       u16             wLength
+) {
+       struct fotg210_hcd      *fotg210 = hcd_to_fotg210(hcd);
+       int             ports = HCS_N_PORTS(fotg210->hcs_params);
+       u32 __iomem     *status_reg = &fotg210->regs->port_status;
+       u32             temp, temp1, status;
+       unsigned long   flags;
+       int             retval = 0;
+       unsigned        selector;
+
+       /*
+        * FIXME:  support SetPortFeatures USB_PORT_FEAT_INDICATOR.
+        * HCS_INDICATOR may say we can change LEDs to off/amber/green.
+        * (track current state ourselves) ... blink for diagnostics,
+        * power, "this is the one", etc.  EHCI spec supports this.
+        */
+
+       spin_lock_irqsave(&fotg210->lock, flags);
+       switch (typeReq) {
+       case ClearHubFeature:
+               switch (wValue) {
+               case C_HUB_LOCAL_POWER:
+               case C_HUB_OVER_CURRENT:
+                       /* no hub-wide feature/status flags */
+                       break;
+               default:
+                       goto error;
+               }
+               break;
+       case ClearPortFeature:
+               if (!wIndex || wIndex > ports)
+                       goto error;
+               wIndex--;
+               temp = fotg210_readl(fotg210, status_reg);
+               temp &= ~PORT_RWC_BITS;
+
+               /*
+                * Even if OWNER is set, so the port is owned by the
+                * companion controller, khubd needs to be able to clear
+                * the port-change status bits (especially
+                * USB_PORT_STAT_C_CONNECTION).
+                */
+
+               switch (wValue) {
+               case USB_PORT_FEAT_ENABLE:
+                       fotg210_writel(fotg210, temp & ~PORT_PE, status_reg);
+                       break;
+               case USB_PORT_FEAT_C_ENABLE:
+                       fotg210_writel(fotg210, temp | PORT_PEC, status_reg);
+                       break;
+               case USB_PORT_FEAT_SUSPEND:
+                       if (temp & PORT_RESET)
+                               goto error;
+                       if (!(temp & PORT_SUSPEND))
+                               break;
+                       if ((temp & PORT_PE) == 0)
+                               goto error;
+
+                       /* resume signaling for 20 msec */
+                       fotg210_writel(fotg210, temp | PORT_RESUME, status_reg);
+                       fotg210->reset_done[wIndex] = jiffies
+                                       + msecs_to_jiffies(20);
+                       break;
+               case USB_PORT_FEAT_C_SUSPEND:
+                       clear_bit(wIndex, &fotg210->port_c_suspend);
+                       break;
+               case USB_PORT_FEAT_C_CONNECTION:
+                       fotg210_writel(fotg210, temp | PORT_CSC, status_reg);
+                       break;
+               case USB_PORT_FEAT_C_OVER_CURRENT:
+                       fotg210_writel(fotg210, temp | OTGISR_OVC,
+                                      &fotg210->regs->otgisr);
+                       break;
+               case USB_PORT_FEAT_C_RESET:
+                       /* GetPortStatus clears reset */
+                       break;
+               default:
+                       goto error;
+               }
+               fotg210_readl(fotg210, &fotg210->regs->command);
+               break;
+       case GetHubDescriptor:
+               fotg210_hub_descriptor(fotg210, (struct usb_hub_descriptor *)
+                       buf);
+               break;
+       case GetHubStatus:
+               /* no hub-wide feature/status flags */
+               memset(buf, 0, 4);
+               /*cpu_to_le32s ((u32 *) buf); */
+               break;
+       case GetPortStatus:
+               if (!wIndex || wIndex > ports)
+                       goto error;
+               wIndex--;
+               status = 0;
+               temp = fotg210_readl(fotg210, status_reg);
+
+               /* wPortChange bits */
+               if (temp & PORT_CSC)
+                       status |= USB_PORT_STAT_C_CONNECTION << 16;
+               if (temp & PORT_PEC)
+                       status |= USB_PORT_STAT_C_ENABLE << 16;
+
+               temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr);
+               if (temp1 & OTGISR_OVC)
+                       status |= USB_PORT_STAT_C_OVERCURRENT << 16;
+
+               /* whoever resumes must GetPortStatus to complete it!! */
+               if (temp & PORT_RESUME) {
+
+                       /* Remote Wakeup received? */
+                       if (!fotg210->reset_done[wIndex]) {
+                               /* resume signaling for 20 msec */
+                               fotg210->reset_done[wIndex] = jiffies
+                                               + msecs_to_jiffies(20);
+                               /* check the port again */
+                               mod_timer(&fotg210_to_hcd(fotg210)->rh_timer,
+                                               fotg210->reset_done[wIndex]);
+                       }
+
+                       /* resume completed? */
+                       else if (time_after_eq(jiffies,
+                                       fotg210->reset_done[wIndex])) {
+                               clear_bit(wIndex, &fotg210->suspended_ports);
+                               set_bit(wIndex, &fotg210->port_c_suspend);
+                               fotg210->reset_done[wIndex] = 0;
+
+                               /* stop resume signaling */
+                               temp = fotg210_readl(fotg210, status_reg);
+                               fotg210_writel(fotg210,
+                                       temp & ~(PORT_RWC_BITS | PORT_RESUME),
+                                       status_reg);
+                               clear_bit(wIndex, &fotg210->resuming_ports);
+                               retval = handshake(fotg210, status_reg,
+                                          PORT_RESUME, 0, 2000 /* 2msec */);
+                               if (retval != 0) {
+                                       fotg210_err(fotg210,
+                                               "port %d resume error %d\n",
+                                               wIndex + 1, retval);
+                                       goto error;
+                               }
+                               temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+                       }
+               }
+
+               /* whoever resets must GetPortStatus to complete it!! */
+               if ((temp & PORT_RESET)
+                               && time_after_eq(jiffies,
+                                       fotg210->reset_done[wIndex])) {
+                       status |= USB_PORT_STAT_C_RESET << 16;
+                       fotg210->reset_done[wIndex] = 0;
+                       clear_bit(wIndex, &fotg210->resuming_ports);
+
+                       /* force reset to complete */
+                       fotg210_writel(fotg210,
+                                      temp & ~(PORT_RWC_BITS | PORT_RESET),
+                                      status_reg);
+                       /* REVISIT:  some hardware needs 550+ usec to clear
+                        * this bit; seems too long to spin routinely...
+                        */
+                       retval = handshake(fotg210, status_reg,
+                                       PORT_RESET, 0, 1000);
+                       if (retval != 0) {
+                               fotg210_err(fotg210, "port %d reset error %d\n",
+                                       wIndex + 1, retval);
+                               goto error;
+                       }
+
+                       /* see what we found out */
+                       temp = check_reset_complete(fotg210, wIndex, status_reg,
+                                       fotg210_readl(fotg210, status_reg));
+               }
+
+               if (!(temp & (PORT_RESUME|PORT_RESET))) {
+                       fotg210->reset_done[wIndex] = 0;
+                       clear_bit(wIndex, &fotg210->resuming_ports);
+               }
+
+               /* transfer dedicated ports to the companion hc */
+               if ((temp & PORT_CONNECT) &&
+                               test_bit(wIndex, &fotg210->companion_ports)) {
+                       temp &= ~PORT_RWC_BITS;
+                       fotg210_writel(fotg210, temp, status_reg);
+                       fotg210_dbg(fotg210, "port %d --> companion\n",
+                                   wIndex + 1);
+                       temp = fotg210_readl(fotg210, status_reg);
+               }
+
+               /*
+                * Even if OWNER is set, there's no harm letting khubd
+                * see the wPortStatus values (they should all be 0 except
+                * for PORT_POWER anyway).
+                */
+
+               if (temp & PORT_CONNECT) {
+                       status |= USB_PORT_STAT_CONNECTION;
+                       status |= fotg210_port_speed(fotg210, temp);
+               }
+               if (temp & PORT_PE)
+                       status |= USB_PORT_STAT_ENABLE;
+
+               /* maybe the port was unsuspended without our knowledge */
+               if (temp & (PORT_SUSPEND|PORT_RESUME)) {
+                       status |= USB_PORT_STAT_SUSPEND;
+               } else if (test_bit(wIndex, &fotg210->suspended_ports)) {
+                       clear_bit(wIndex, &fotg210->suspended_ports);
+                       clear_bit(wIndex, &fotg210->resuming_ports);
+                       fotg210->reset_done[wIndex] = 0;
+                       if (temp & PORT_PE)
+                               set_bit(wIndex, &fotg210->port_c_suspend);
+               }
+
+               temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr);
+               if (temp1 & OTGISR_OVC)
+                       status |= USB_PORT_STAT_OVERCURRENT;
+               if (temp & PORT_RESET)
+                       status |= USB_PORT_STAT_RESET;
+               if (test_bit(wIndex, &fotg210->port_c_suspend))
+                       status |= USB_PORT_STAT_C_SUSPEND << 16;
+
+#ifndef        VERBOSE_DEBUG
+       if (status & ~0xffff)   /* only if wPortChange is interesting */
+#endif
+               dbg_port(fotg210, "GetStatus", wIndex + 1, temp);
+               put_unaligned_le32(status, buf);
+               break;
+       case SetHubFeature:
+               switch (wValue) {
+               case C_HUB_LOCAL_POWER:
+               case C_HUB_OVER_CURRENT:
+                       /* no hub-wide feature/status flags */
+                       break;
+               default:
+                       goto error;
+               }
+               break;
+       case SetPortFeature:
+               selector = wIndex >> 8;
+               wIndex &= 0xff;
+
+               if (!wIndex || wIndex > ports)
+                       goto error;
+               wIndex--;
+               temp = fotg210_readl(fotg210, status_reg);
+               temp &= ~PORT_RWC_BITS;
+               switch (wValue) {
+               case USB_PORT_FEAT_SUSPEND:
+                       if ((temp & PORT_PE) == 0
+                                       || (temp & PORT_RESET) != 0)
+                               goto error;
+
+                       /* After above check the port must be connected.
+                        * Set appropriate bit thus could put phy into low power
+                        * mode if we have hostpc feature
+                        */
+                       fotg210_writel(fotg210, temp | PORT_SUSPEND,
+                                      status_reg);
+                       set_bit(wIndex, &fotg210->suspended_ports);
+                       break;
+               case USB_PORT_FEAT_RESET:
+                       if (temp & PORT_RESUME)
+                               goto error;
+                       /* line status bits may report this as low speed,
+                        * which can be fine if this root hub has a
+                        * transaction translator built in.
+                        */
+                       fotg210_vdbg(fotg210, "port %d reset\n", wIndex + 1);
+                       temp |= PORT_RESET;
+                       temp &= ~PORT_PE;
+
+                       /*
+                        * caller must wait, then call GetPortStatus
+                        * usb 2.0 spec says 50 ms resets on root
+                        */
+                       fotg210->reset_done[wIndex] = jiffies
+                                       + msecs_to_jiffies(50);
+                       fotg210_writel(fotg210, temp, status_reg);
+                       break;
+
+               /* For downstream facing ports (these):  one hub port is put
+                * into test mode according to USB2 11.24.2.13, then the hub
+                * must be reset (which for root hub now means rmmod+modprobe,
+                * or else system reboot).  See EHCI 2.3.9 and 4.14 for info
+                * about the EHCI-specific stuff.
+                */
+               case USB_PORT_FEAT_TEST:
+                       if (!selector || selector > 5)
+                               goto error;
+                       spin_unlock_irqrestore(&fotg210->lock, flags);
+                       fotg210_quiesce(fotg210);
+                       spin_lock_irqsave(&fotg210->lock, flags);
+
+                       /* Put all enabled ports into suspend */
+                       temp = fotg210_readl(fotg210, status_reg) &
+                               ~PORT_RWC_BITS;
+                       if (temp & PORT_PE)
+                               fotg210_writel(fotg210, temp | PORT_SUSPEND,
+                                               status_reg);
+
+                       spin_unlock_irqrestore(&fotg210->lock, flags);
+                       fotg210_halt(fotg210);
+                       spin_lock_irqsave(&fotg210->lock, flags);
+
+                       temp = fotg210_readl(fotg210, status_reg);
+                       temp |= selector << 16;
+                       fotg210_writel(fotg210, temp, status_reg);
+                       break;
+
+               default:
+                       goto error;
+               }
+               fotg210_readl(fotg210, &fotg210->regs->command);
+               break;
+
+       default:
+error:
+               /* "stall" on error */
+               retval = -EPIPE;
+       }
+       spin_unlock_irqrestore(&fotg210->lock, flags);
+       return retval;
+}
+
+static void __maybe_unused fotg210_relinquish_port(struct usb_hcd *hcd,
+               int portnum)
+{
+       return;
+}
+
+static int __maybe_unused fotg210_port_handed_over(struct usb_hcd *hcd,
+               int portnum)
+{
+       return 0;
+}
+/*-------------------------------------------------------------------------*/
+/*
+ * There's basically three types of memory:
+ *     - data used only by the HCD ... kmalloc is fine
+ *     - async and periodic schedules, shared by HC and HCD ... these
+ *       need to use dma_pool or dma_alloc_coherent
+ *     - driver buffers, read/written by HC ... single shot DMA mapped
+ *
+ * There's also "register" data (e.g. PCI or SOC), which is memory mapped.
+ * No memory seen by this driver is pageable.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* Allocate the key transfer structures from the previously allocated pool */
+
+static inline void fotg210_qtd_init(struct fotg210_hcd *fotg210,
+                                   struct fotg210_qtd *qtd, dma_addr_t dma)
+{
+       memset(qtd, 0, sizeof(*qtd));
+       qtd->qtd_dma = dma;
+       qtd->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT);
+       qtd->hw_next = FOTG210_LIST_END(fotg210);
+       qtd->hw_alt_next = FOTG210_LIST_END(fotg210);
+       INIT_LIST_HEAD(&qtd->qtd_list);
+}
+
+static struct fotg210_qtd *fotg210_qtd_alloc(struct fotg210_hcd *fotg210,
+                                            gfp_t flags)
+{
+       struct fotg210_qtd              *qtd;
+       dma_addr_t              dma;
+
+       qtd = dma_pool_alloc(fotg210->qtd_pool, flags, &dma);
+       if (qtd != NULL)
+               fotg210_qtd_init(fotg210, qtd, dma);
+
+       return qtd;
+}
+
+static inline void fotg210_qtd_free(struct fotg210_hcd *fotg210,
+                                   struct fotg210_qtd *qtd)
+{
+       dma_pool_free(fotg210->qtd_pool, qtd, qtd->qtd_dma);
+}
+
+
+static void qh_destroy(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+       /* clean qtds first, and know this is not linked */
+       if (!list_empty(&qh->qtd_list) || qh->qh_next.ptr) {
+               fotg210_dbg(fotg210, "unused qh not empty!\n");
+               BUG();
+       }
+       if (qh->dummy)
+               fotg210_qtd_free(fotg210, qh->dummy);
+       dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma);
+       kfree(qh);
+}
+
+static struct fotg210_qh *fotg210_qh_alloc(struct fotg210_hcd *fotg210,
+                                          gfp_t flags)
+{
+       struct fotg210_qh               *qh;
+       dma_addr_t              dma;
+
+       qh = kzalloc(sizeof(*qh), GFP_ATOMIC);
+       if (!qh)
+               goto done;
+       qh->hw = (struct fotg210_qh_hw *)
+               dma_pool_alloc(fotg210->qh_pool, flags, &dma);
+       if (!qh->hw)
+               goto fail;
+       memset(qh->hw, 0, sizeof(*qh->hw));
+       qh->qh_dma = dma;
+       INIT_LIST_HEAD(&qh->qtd_list);
+
+       /* dummy td enables safe urb queuing */
+       qh->dummy = fotg210_qtd_alloc(fotg210, flags);
+       if (qh->dummy == NULL) {
+               fotg210_dbg(fotg210, "no dummy td\n");
+               goto fail1;
+       }
+done:
+       return qh;
+fail1:
+       dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma);
+fail:
+       kfree(qh);
+       return NULL;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* The queue heads and transfer descriptors are managed from pools tied
+ * to each of the "per device" structures.
+ * This is the initialisation and cleanup code.
+ */
+
+static void fotg210_mem_cleanup(struct fotg210_hcd *fotg210)
+{
+       if (fotg210->async)
+               qh_destroy(fotg210, fotg210->async);
+       fotg210->async = NULL;
+
+       if (fotg210->dummy)
+               qh_destroy(fotg210, fotg210->dummy);
+       fotg210->dummy = NULL;
+
+       /* DMA consistent memory and pools */
+       if (fotg210->qtd_pool)
+               dma_pool_destroy(fotg210->qtd_pool);
+       fotg210->qtd_pool = NULL;
+
+       if (fotg210->qh_pool) {
+               dma_pool_destroy(fotg210->qh_pool);
+               fotg210->qh_pool = NULL;
+       }
+
+       if (fotg210->itd_pool)
+               dma_pool_destroy(fotg210->itd_pool);
+       fotg210->itd_pool = NULL;
+
+       if (fotg210->periodic)
+               dma_free_coherent(fotg210_to_hcd(fotg210)->self.controller,
+                       fotg210->periodic_size * sizeof(u32),
+                       fotg210->periodic, fotg210->periodic_dma);
+       fotg210->periodic = NULL;
+
+       /* shadow periodic table */
+       kfree(fotg210->pshadow);
+       fotg210->pshadow = NULL;
+}
+
+/* remember to add cleanup code (above) if you add anything here */
+static int fotg210_mem_init(struct fotg210_hcd *fotg210, gfp_t flags)
+{
+       int i;
+
+       /* QTDs for control/bulk/intr transfers */
+       fotg210->qtd_pool = dma_pool_create("fotg210_qtd",
+                       fotg210_to_hcd(fotg210)->self.controller,
+                       sizeof(struct fotg210_qtd),
+                       32 /* byte alignment (for hw parts) */,
+                       4096 /* can't cross 4K */);
+       if (!fotg210->qtd_pool)
+               goto fail;
+
+       /* QHs for control/bulk/intr transfers */
+       fotg210->qh_pool = dma_pool_create("fotg210_qh",
+                       fotg210_to_hcd(fotg210)->self.controller,
+                       sizeof(struct fotg210_qh_hw),
+                       32 /* byte alignment (for hw parts) */,
+                       4096 /* can't cross 4K */);
+       if (!fotg210->qh_pool)
+               goto fail;
+
+       fotg210->async = fotg210_qh_alloc(fotg210, flags);
+       if (!fotg210->async)
+               goto fail;
+
+       /* ITD for high speed ISO transfers */
+       fotg210->itd_pool = dma_pool_create("fotg210_itd",
+                       fotg210_to_hcd(fotg210)->self.controller,
+                       sizeof(struct fotg210_itd),
+                       64 /* byte alignment (for hw parts) */,
+                       4096 /* can't cross 4K */);
+       if (!fotg210->itd_pool)
+               goto fail;
+
+       /* Hardware periodic table */
+       fotg210->periodic = (__le32 *)
+               dma_alloc_coherent(fotg210_to_hcd(fotg210)->self.controller,
+                       fotg210->periodic_size * sizeof(__le32),
+                       &fotg210->periodic_dma, 0);
+       if (fotg210->periodic == NULL)
+               goto fail;
+
+       for (i = 0; i < fotg210->periodic_size; i++)
+               fotg210->periodic[i] = FOTG210_LIST_END(fotg210);
+
+       /* software shadow of hardware table */
+       fotg210->pshadow = kcalloc(fotg210->periodic_size, sizeof(void *),
+                                  flags);
+       if (fotg210->pshadow != NULL)
+               return 0;
+
+fail:
+       fotg210_dbg(fotg210, "couldn't init memory\n");
+       fotg210_mem_cleanup(fotg210);
+       return -ENOMEM;
+}
+/*-------------------------------------------------------------------------*/
+/*
+ * EHCI hardware queue manipulation ... the core.  QH/QTD manipulation.
+ *
+ * Control, bulk, and interrupt traffic all use "qh" lists.  They list "qtd"
+ * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned
+ * buffers needed for the larger number).  We use one QH per endpoint, queue
+ * multiple urbs (all three types) per endpoint.  URBs may need several qtds.
+ *
+ * ISO traffic uses "ISO TD" (itd) records, and (along with
+ * interrupts) needs careful scheduling.  Performance improvements can be
+ * an ongoing challenge.  That's in "ehci-sched.c".
+ *
+ * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
+ * or otherwise through transaction translators (TTs) in USB 2.0 hubs using
+ * (b) special fields in qh entries or (c) split iso entries.  TTs will
+ * buffer low/full speed data so the host collects it at high speed.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* fill a qtd, returning how much of the buffer we were able to queue up */
+
+static int
+qtd_fill(struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd, dma_addr_t buf,
+                 size_t len, int token, int maxpacket)
+{
+       int     i, count;
+       u64     addr = buf;
+
+       /* one buffer entry per 4K ... first might be short or unaligned */
+       qtd->hw_buf[0] = cpu_to_hc32(fotg210, (u32)addr);
+       qtd->hw_buf_hi[0] = cpu_to_hc32(fotg210, (u32)(addr >> 32));
+       count = 0x1000 - (buf & 0x0fff);        /* rest of that page */
+       if (likely(len < count))                /* ... iff needed */
+               count = len;
+       else {
+               buf +=  0x1000;
+               buf &= ~0x0fff;
+
+               /* per-qtd limit: from 16K to 20K (best alignment) */
+               for (i = 1; count < len && i < 5; i++) {
+                       addr = buf;
+                       qtd->hw_buf[i] = cpu_to_hc32(fotg210, (u32)addr);
+                       qtd->hw_buf_hi[i] = cpu_to_hc32(fotg210,
+                                       (u32)(addr >> 32));
+                       buf += 0x1000;
+                       if ((count + 0x1000) < len)
+                               count += 0x1000;
+                       else
+                               count = len;
+               }
+
+               /* short packets may only terminate transfers */
+               if (count != len)
+                       count -= (count % maxpacket);
+       }
+       qtd->hw_token = cpu_to_hc32(fotg210, (count << 16) | token);
+       qtd->length = count;
+
+       return count;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline void
+qh_update(struct fotg210_hcd *fotg210, struct fotg210_qh *qh,
+         struct fotg210_qtd *qtd)
+{
+       struct fotg210_qh_hw *hw = qh->hw;
+
+       /* writes to an active overlay are unsafe */
+       BUG_ON(qh->qh_state != QH_STATE_IDLE);
+
+       hw->hw_qtd_next = QTD_NEXT(fotg210, qtd->qtd_dma);
+       hw->hw_alt_next = FOTG210_LIST_END(fotg210);
+
+       /* Except for control endpoints, we make hardware maintain data
+        * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
+        * and set the pseudo-toggle in udev. Only usb_clear_halt() will
+        * ever clear it.
+        */
+       if (!(hw->hw_info1 & cpu_to_hc32(fotg210, QH_TOGGLE_CTL))) {
+               unsigned        is_out, epnum;
+
+               is_out = qh->is_out;
+               epnum = (hc32_to_cpup(fotg210, &hw->hw_info1) >> 8) & 0x0f;
+               if (unlikely(!usb_gettoggle(qh->dev, epnum, is_out))) {
+                       hw->hw_token &= ~cpu_to_hc32(fotg210, QTD_TOGGLE);
+                       usb_settoggle(qh->dev, epnum, is_out, 1);
+               }
+       }
+
+       hw->hw_token &= cpu_to_hc32(fotg210, QTD_TOGGLE | QTD_STS_PING);
+}
+
+/* if it weren't for a common silicon quirk (writing the dummy into the qh
+ * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault
+ * recovery (including urb dequeue) would need software changes to a QH...
+ */
+static void
+qh_refresh(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+       struct fotg210_qtd *qtd;
+
+       if (list_empty(&qh->qtd_list))
+               qtd = qh->dummy;
+       else {
+               qtd = list_entry(qh->qtd_list.next,
+                               struct fotg210_qtd, qtd_list);
+               /*
+                * first qtd may already be partially processed.
+                * If we come here during unlink, the QH overlay region
+                * might have reference to the just unlinked qtd. The
+                * qtd is updated in qh_completions(). Update the QH
+                * overlay here.
+                */
+               if (cpu_to_hc32(fotg210, qtd->qtd_dma) == qh->hw->hw_current) {
+                       qh->hw->hw_qtd_next = qtd->hw_next;
+                       qtd = NULL;
+               }
+       }
+
+       if (qtd)
+               qh_update(fotg210, qh, qtd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
+
+static void fotg210_clear_tt_buffer_complete(struct usb_hcd *hcd,
+               struct usb_host_endpoint *ep)
+{
+       struct fotg210_hcd              *fotg210 = hcd_to_fotg210(hcd);
+       struct fotg210_qh               *qh = ep->hcpriv;
+       unsigned long           flags;
+
+       spin_lock_irqsave(&fotg210->lock, flags);
+       qh->clearing_tt = 0;
+       if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list)
+                       && fotg210->rh_state == FOTG210_RH_RUNNING)
+               qh_link_async(fotg210, qh);
+       spin_unlock_irqrestore(&fotg210->lock, flags);
+}
+
+static void fotg210_clear_tt_buffer(struct fotg210_hcd *fotg210,
+                                   struct fotg210_qh *qh,
+                                   struct urb *urb, u32 token)
+{
+
+       /* If an async split transaction gets an error or is unlinked,
+        * the TT buffer may be left in an indeterminate state.  We
+        * have to clear the TT buffer.
+        *
+        * Note: this routine is never called for Isochronous transfers.
+        */
+       if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) {
+#ifdef DEBUG
+               struct usb_device *tt = urb->dev->tt->hub;
+               dev_dbg(&tt->dev,
+                       "clear tt buffer port %d, a%d ep%d t%08x\n",
+                       urb->dev->ttport, urb->dev->devnum,
+                       usb_pipeendpoint(urb->pipe), token);
+#endif /* DEBUG */
+               if (urb->dev->tt->hub !=
+                   fotg210_to_hcd(fotg210)->self.root_hub) {
+                       if (usb_hub_clear_tt_buffer(urb) == 0)
+                               qh->clearing_tt = 1;
+               }
+       }
+}
+
+static int qtd_copy_status(
+       struct fotg210_hcd *fotg210,
+       struct urb *urb,
+       size_t length,
+       u32 token
+)
+{
+       int     status = -EINPROGRESS;
+
+       /* count IN/OUT bytes, not SETUP (even short packets) */
+       if (likely(QTD_PID(token) != 2))
+               urb->actual_length += length - QTD_LENGTH(token);
+
+       /* don't modify error codes */
+       if (unlikely(urb->unlinked))
+               return status;
+
+       /* force cleanup after short read; not always an error */
+       if (unlikely(IS_SHORT_READ(token)))
+               status = -EREMOTEIO;
+
+       /* serious "can't proceed" faults reported by the hardware */
+       if (token & QTD_STS_HALT) {
+               if (token & QTD_STS_BABBLE) {
+                       /* FIXME "must" disable babbling device's port too */
+                       status = -EOVERFLOW;
+               /* CERR nonzero + halt --> stall */
+               } else if (QTD_CERR(token)) {
+                       status = -EPIPE;
+
+               /* In theory, more than one of the following bits can be set
+                * since they are sticky and the transaction is retried.
+                * Which to test first is rather arbitrary.
+                */
+               } else if (token & QTD_STS_MMF) {
+                       /* fs/ls interrupt xfer missed the complete-split */
+                       status = -EPROTO;
+               } else if (token & QTD_STS_DBE) {
+                       status = (QTD_PID(token) == 1) /* IN ? */
+                               ? -ENOSR  /* hc couldn't read data */
+                               : -ECOMM; /* hc couldn't write data */
+               } else if (token & QTD_STS_XACT) {
+                       /* timeout, bad CRC, wrong PID, etc */
+                       fotg210_dbg(fotg210, "devpath %s ep%d%s 3strikes\n",
+                               urb->dev->devpath,
+                               usb_pipeendpoint(urb->pipe),
+                               usb_pipein(urb->pipe) ? "in" : "out");
+                       status = -EPROTO;
+               } else {        /* unknown */
+                       status = -EPROTO;
+               }
+
+               fotg210_vdbg(fotg210,
+                       "dev%d ep%d%s qtd token %08x --> status %d\n",
+                       usb_pipedevice(urb->pipe),
+                       usb_pipeendpoint(urb->pipe),
+                       usb_pipein(urb->pipe) ? "in" : "out",
+                       token, status);
+       }
+
+       return status;
+}
+
+static void
+fotg210_urb_done(struct fotg210_hcd *fotg210, struct urb *urb, int status)
+__releases(fotg210->lock)
+__acquires(fotg210->lock)
+{
+       if (likely(urb->hcpriv != NULL)) {
+               struct fotg210_qh       *qh = (struct fotg210_qh *) urb->hcpriv;
+
+               /* S-mask in a QH means it's an interrupt urb */
+               if ((qh->hw->hw_info2 & cpu_to_hc32(fotg210, QH_SMASK)) != 0) {
+
+                       /* ... update hc-wide periodic stats (for usbfs) */
+                       fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs--;
+               }
+       }
+
+       if (unlikely(urb->unlinked)) {
+               COUNT(fotg210->stats.unlink);
+       } else {
+               /* report non-error and short read status as zero */
+               if (status == -EINPROGRESS || status == -EREMOTEIO)
+                       status = 0;
+               COUNT(fotg210->stats.complete);
+       }
+
+#ifdef FOTG210_URB_TRACE
+       fotg210_dbg(fotg210,
+               "%s %s urb %p ep%d%s status %d len %d/%d\n",
+               __func__, urb->dev->devpath, urb,
+               usb_pipeendpoint(urb->pipe),
+               usb_pipein(urb->pipe) ? "in" : "out",
+               status,
+               urb->actual_length, urb->transfer_buffer_length);
+#endif
+
+       /* complete() can reenter this HCD */
+       usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
+       spin_unlock(&fotg210->lock);
+       usb_hcd_giveback_urb(fotg210_to_hcd(fotg210), urb, status);
+       spin_lock(&fotg210->lock);
+}
+
+static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
+
+/*
+ * Process and free completed qtds for a qh, returning URBs to drivers.
+ * Chases up to qh->hw_current.  Returns number of completions called,
+ * indicating how much "real" work we did.
+ */
+static unsigned
+qh_completions(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+       struct fotg210_qtd              *last, *end = qh->dummy;
+       struct list_head        *entry, *tmp;
+       int                     last_status;
+       int                     stopped;
+       unsigned                count = 0;
+       u8                      state;
+       struct fotg210_qh_hw    *hw = qh->hw;
+
+       if (unlikely(list_empty(&qh->qtd_list)))
+               return count;
+
+       /* completions (or tasks on other cpus) must never clobber HALT
+        * till we've gone through and cleaned everything up, even when
+        * they add urbs to this qh's queue or mark them for unlinking.
+        *
+        * NOTE:  unlinking expects to be done in queue order.
+        *
+        * It's a bug for qh->qh_state to be anything other than
+        * QH_STATE_IDLE, unless our caller is scan_async() or
+        * scan_intr().
+        */
+       state = qh->qh_state;
+       qh->qh_state = QH_STATE_COMPLETING;
+       stopped = (state == QH_STATE_IDLE);
+
+ rescan:
+       last = NULL;
+       last_status = -EINPROGRESS;
+       qh->needs_rescan = 0;
+
+       /* remove de-activated QTDs from front of queue.
+        * after faults (including short reads), cleanup this urb
+        * then let the queue advance.
+        * if queue is stopped, handles unlinks.
+        */
+       list_for_each_safe(entry, tmp, &qh->qtd_list) {
+               struct fotg210_qtd      *qtd;
+               struct urb      *urb;
+               u32             token = 0;
+
+               qtd = list_entry(entry, struct fotg210_qtd, qtd_list);
+               urb = qtd->urb;
+
+               /* clean up any state from previous QTD ...*/
+               if (last) {
+                       if (likely(last->urb != urb)) {
+                               fotg210_urb_done(fotg210, last->urb,
+                                                last_status);
+                               count++;
+                               last_status = -EINPROGRESS;
+                       }
+                       fotg210_qtd_free(fotg210, last);
+                       last = NULL;
+               }
+
+               /* ignore urbs submitted during completions we reported */
+               if (qtd == end)
+                       break;
+
+               /* hardware copies qtd out of qh overlay */
+               rmb();
+               token = hc32_to_cpu(fotg210, qtd->hw_token);
+
+               /* always clean up qtds the hc de-activated */
+ retry_xacterr:
+               if ((token & QTD_STS_ACTIVE) == 0) {
+
+                       /* Report Data Buffer Error: non-fatal but useful */
+                       if (token & QTD_STS_DBE)
+                               fotg210_dbg(fotg210,
+                                       "detected DataBufferErr for urb %p ep%d%s len %d, qtd %p [qh %p]\n",
+                                       urb,
+                                       usb_endpoint_num(&urb->ep->desc),
+                                       usb_endpoint_dir_in(&urb->ep->desc)
+                                               ? "in" : "out",
+                                       urb->transfer_buffer_length,
+                                       qtd,
+                                       qh);
+
+                       /* on STALL, error, and short reads this urb must
+                        * complete and all its qtds must be recycled.
+                        */
+                       if ((token & QTD_STS_HALT) != 0) {
+
+                               /* retry transaction errors until we
+                                * reach the software xacterr limit
+                                */
+                               if ((token & QTD_STS_XACT) &&
+                                       QTD_CERR(token) == 0 &&
+                                       ++qh->xacterrs < QH_XACTERR_MAX &&
+                                       !urb->unlinked) {
+                                       fotg210_dbg(fotg210,
+       "detected XactErr len %zu/%zu retry %d\n",
+       qtd->length - QTD_LENGTH(token), qtd->length, qh->xacterrs);
+
+                                       /* reset the token in the qtd and the
+                                        * qh overlay (which still contains
+                                        * the qtd) so that we pick up from
+                                        * where we left off
+                                        */
+                                       token &= ~QTD_STS_HALT;
+                                       token |= QTD_STS_ACTIVE |
+                                                (FOTG210_TUNE_CERR << 10);
+                                       qtd->hw_token = cpu_to_hc32(fotg210,
+                                                       token);
+                                       wmb();
+                                       hw->hw_token = cpu_to_hc32(fotg210,
+                                                       token);
+                                       goto retry_xacterr;
+                               }
+                               stopped = 1;
+
+                       /* magic dummy for some short reads; qh won't advance.
+                        * that silicon quirk can kick in with this dummy too.
+                        *
+                        * other short reads won't stop the queue, including
+                        * control transfers (status stage handles that) or
+                        * most other single-qtd reads ... the queue stops if
+                        * URB_SHORT_NOT_OK was set so the driver submitting
+                        * the urbs could clean it up.
+                        */
+                       } else if (IS_SHORT_READ(token)
+                                       && !(qtd->hw_alt_next
+                                               & FOTG210_LIST_END(fotg210))) {
+                               stopped = 1;
+                       }
+
+               /* stop scanning when we reach qtds the hc is using */
+               } else if (likely(!stopped
+                               && fotg210->rh_state >= FOTG210_RH_RUNNING)) {
+                       break;
+
+               /* scan the whole queue for unlinks whenever it stops */
+               } else {
+                       stopped = 1;
+
+                       /* cancel everything if we halt, suspend, etc */
+                       if (fotg210->rh_state < FOTG210_RH_RUNNING)
+                               last_status = -ESHUTDOWN;
+
+                       /* this qtd is active; skip it unless a previous qtd
+                        * for its urb faulted, or its urb was canceled.
+                        */
+                       else if (last_status == -EINPROGRESS && !urb->unlinked)
+                               continue;
+
+                       /* qh unlinked; token in overlay may be most current */
+                       if (state == QH_STATE_IDLE
+                                       && cpu_to_hc32(fotg210, qtd->qtd_dma)
+                                               == hw->hw_current) {
+                               token = hc32_to_cpu(fotg210, hw->hw_token);
+
+                               /* An unlink may leave an incomplete
+                                * async transaction in the TT buffer.
+                                * We have to clear it.
+                                */
+                               fotg210_clear_tt_buffer(fotg210, qh, urb,
+                                                       token);
+                       }
+               }
+
+               /* unless we already know the urb's status, collect qtd status
+                * and update count of bytes transferred.  in common short read
+                * cases with only one data qtd (including control transfers),
+                * queue processing won't halt.  but with two or more qtds (for
+                * example, with a 32 KB transfer), when the first qtd gets a
+                * short read the second must be removed by hand.
+                */
+               if (last_status == -EINPROGRESS) {
+                       last_status = qtd_copy_status(fotg210, urb,
+                                       qtd->length, token);
+                       if (last_status == -EREMOTEIO
+                                       && (qtd->hw_alt_next
+                                               & FOTG210_LIST_END(fotg210)))
+                               last_status = -EINPROGRESS;
+
+                       /* As part of low/full-speed endpoint-halt processing
+                        * we must clear the TT buffer (11.17.5).
+                        */
+                       if (unlikely(last_status != -EINPROGRESS &&
+                                       last_status != -EREMOTEIO)) {
+                               /* The TT's in some hubs malfunction when they
+                                * receive this request following a STALL (they
+                                * stop sending isochronous packets).  Since a
+                                * STALL can't leave the TT buffer in a busy
+                                * state (if you believe Figures 11-48 - 11-51
+                                * in the USB 2.0 spec), we won't clear the TT
+                                * buffer in this case.  Strictly speaking this
+                                * is a violation of the spec.
+                                */
+                               if (last_status != -EPIPE)
+                                       fotg210_clear_tt_buffer(fotg210, qh,
+                                                               urb, token);
+                       }
+               }
+
+               /* if we're removing something not at the queue head,
+                * patch the hardware queue pointer.
+                */
+               if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
+                       last = list_entry(qtd->qtd_list.prev,
+                                       struct fotg210_qtd, qtd_list);
+                       last->hw_next = qtd->hw_next;
+               }
+
+               /* remove qtd; it's recycled after possible urb completion */
+               list_del(&qtd->qtd_list);
+               last = qtd;
+
+               /* reinit the xacterr counter for the next qtd */
+               qh->xacterrs = 0;
+       }
+
+       /* last urb's completion might still need calling */
+       if (likely(last != NULL)) {
+               fotg210_urb_done(fotg210, last->urb, last_status);
+               count++;
+               fotg210_qtd_free(fotg210, last);
+       }
+
+       /* Do we need to rescan for URBs dequeued during a giveback? */
+       if (unlikely(qh->needs_rescan)) {
+               /* If the QH is already unlinked, do the rescan now. */
+               if (state == QH_STATE_IDLE)
+                       goto rescan;
+
+               /* Otherwise we have to wait until the QH is fully unlinked.
+                * Our caller will start an unlink if qh->needs_rescan is
+                * set.  But if an unlink has already started, nothing needs
+                * to be done.
+                */
+               if (state != QH_STATE_LINKED)
+                       qh->needs_rescan = 0;
+       }
+
+       /* restore original state; caller must unlink or relink */
+       qh->qh_state = state;
+
+       /* be sure the hardware's done with the qh before refreshing
+        * it after fault cleanup, or recovering from silicon wrongly
+        * overlaying the dummy qtd (which reduces DMA chatter).
+        */
+       if (stopped != 0 || hw->hw_qtd_next == FOTG210_LIST_END(fotg210)) {
+               switch (state) {
+               case QH_STATE_IDLE:
+                       qh_refresh(fotg210, qh);
+                       break;
+               case QH_STATE_LINKED:
+                       /* We won't refresh a QH that's linked (after the HC
+                        * stopped the queue).  That avoids a race:
+                        *  - HC reads first part of QH;
+                        *  - CPU updates that first part and the token;
+                        *  - HC reads rest of that QH, including token
+                        * Result:  HC gets an inconsistent image, and then
+                        * DMAs to/from the wrong memory (corrupting it).
+                        *
+                        * That should be rare for interrupt transfers,
+                        * except maybe high bandwidth ...
+                        */
+
+                       /* Tell the caller to start an unlink */
+                       qh->needs_rescan = 1;
+                       break;
+               /* otherwise, unlink already started */
+               }
+       }
+
+       return count;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+/* ... and packet size, for any kind of endpoint descriptor */
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
+
+/*
+ * reverse of qh_urb_transaction:  free a list of TDs.
+ * used for cleanup after errors, before HC sees an URB's TDs.
+ */
+static void qtd_list_free(
+       struct fotg210_hcd              *fotg210,
+       struct urb              *urb,
+       struct list_head        *qtd_list
+) {
+       struct list_head        *entry, *temp;
+
+       list_for_each_safe(entry, temp, qtd_list) {
+               struct fotg210_qtd      *qtd;
+
+               qtd = list_entry(entry, struct fotg210_qtd, qtd_list);
+               list_del(&qtd->qtd_list);
+               fotg210_qtd_free(fotg210, qtd);
+       }
+}
+
+/*
+ * create a list of filled qtds for this URB; won't link into qh.
+ */
+static struct list_head *
+qh_urb_transaction(
+       struct fotg210_hcd              *fotg210,
+       struct urb              *urb,
+       struct list_head        *head,
+       gfp_t                   flags
+) {
+       struct fotg210_qtd              *qtd, *qtd_prev;
+       dma_addr_t              buf;
+       int                     len, this_sg_len, maxpacket;
+       int                     is_input;
+       u32                     token;
+       int                     i;
+       struct scatterlist      *sg;
+
+       /*
+        * URBs map to sequences of QTDs:  one logical transaction
+        */
+       qtd = fotg210_qtd_alloc(fotg210, flags);
+       if (unlikely(!qtd))
+               return NULL;
+       list_add_tail(&qtd->qtd_list, head);
+       qtd->urb = urb;
+
+       token = QTD_STS_ACTIVE;
+       token |= (FOTG210_TUNE_CERR << 10);
+       /* for split transactions, SplitXState initialized to zero */
+
+       len = urb->transfer_buffer_length;
+       is_input = usb_pipein(urb->pipe);
+       if (usb_pipecontrol(urb->pipe)) {
+               /* SETUP pid */
+               qtd_fill(fotg210, qtd, urb->setup_dma,
+                               sizeof(struct usb_ctrlrequest),
+                               token | (2 /* "setup" */ << 8), 8);
+
+               /* ... and always at least one more pid */
+               token ^= QTD_TOGGLE;
+               qtd_prev = qtd;
+               qtd = fotg210_qtd_alloc(fotg210, flags);
+               if (unlikely(!qtd))
+                       goto cleanup;
+               qtd->urb = urb;
+               qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
+               list_add_tail(&qtd->qtd_list, head);
+
+               /* for zero length DATA stages, STATUS is always IN */
+               if (len == 0)
+                       token |= (1 /* "in" */ << 8);
+       }
+
+       /*
+        * data transfer stage:  buffer setup
+        */
+       i = urb->num_mapped_sgs;
+       if (len > 0 && i > 0) {
+               sg = urb->sg;
+               buf = sg_dma_address(sg);
+
+               /* urb->transfer_buffer_length may be smaller than the
+                * size of the scatterlist (or vice versa)
+                */
+               this_sg_len = min_t(int, sg_dma_len(sg), len);
+       } else {
+               sg = NULL;
+               buf = urb->transfer_dma;
+               this_sg_len = len;
+       }
+
+       if (is_input)
+               token |= (1 /* "in" */ << 8);
+       /* else it's already initted to "out" pid (0 << 8) */
+
+       maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input));
+
+       /*
+        * buffer gets wrapped in one or more qtds;
+        * last one may be "short" (including zero len)
+        * and may serve as a control status ack
+        */
+       for (;;) {
+               int this_qtd_len;
+
+               this_qtd_len = qtd_fill(fotg210, qtd, buf, this_sg_len, token,
+                               maxpacket);
+               this_sg_len -= this_qtd_len;
+               len -= this_qtd_len;
+               buf += this_qtd_len;
+
+               /*
+                * short reads advance to a "magic" dummy instead of the next
+                * qtd ... that forces the queue to stop, for manual cleanup.
+                * (this will usually be overridden later.)
+                */
+               if (is_input)
+                       qtd->hw_alt_next = fotg210->async->hw->hw_alt_next;
+
+               /* qh makes control packets use qtd toggle; maybe switch it */
+               if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
+                       token ^= QTD_TOGGLE;
+
+               if (likely(this_sg_len <= 0)) {
+                       if (--i <= 0 || len <= 0)
+                               break;
+                       sg = sg_next(sg);
+                       buf = sg_dma_address(sg);
+                       this_sg_len = min_t(int, sg_dma_len(sg), len);
+               }
+
+               qtd_prev = qtd;
+               qtd = fotg210_qtd_alloc(fotg210, flags);
+               if (unlikely(!qtd))
+                       goto cleanup;
+               qtd->urb = urb;
+               qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
+               list_add_tail(&qtd->qtd_list, head);
+       }
+
+       /*
+        * unless the caller requires manual cleanup after short reads,
+        * have the alt_next mechanism keep the queue running after the
+        * last data qtd (the only one, for control and most other cases).
+        */
+       if (likely((urb->transfer_flags & URB_SHORT_NOT_OK) == 0
+                               || usb_pipecontrol(urb->pipe)))
+               qtd->hw_alt_next = FOTG210_LIST_END(fotg210);
+
+       /*
+        * control requests may need a terminating data "status" ack;
+        * other OUT ones may need a terminating short packet
+        * (zero length).
+        */
+       if (likely(urb->transfer_buffer_length != 0)) {
+               int     one_more = 0;
+
+               if (usb_pipecontrol(urb->pipe)) {
+                       one_more = 1;
+                       token ^= 0x0100;        /* "in" <--> "out"  */
+                       token |= QTD_TOGGLE;    /* force DATA1 */
+               } else if (usb_pipeout(urb->pipe)
+                               && (urb->transfer_flags & URB_ZERO_PACKET)
+                               && !(urb->transfer_buffer_length % maxpacket)) {
+                       one_more = 1;
+               }
+               if (one_more) {
+                       qtd_prev = qtd;
+                       qtd = fotg210_qtd_alloc(fotg210, flags);
+                       if (unlikely(!qtd))
+                               goto cleanup;
+                       qtd->urb = urb;
+                       qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
+                       list_add_tail(&qtd->qtd_list, head);
+
+                       /* never any data in such packets */
+                       qtd_fill(fotg210, qtd, 0, 0, token, 0);
+               }
+       }
+
+       /* by default, enable interrupt on urb completion */
+       if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT)))
+               qtd->hw_token |= cpu_to_hc32(fotg210, QTD_IOC);
+       return head;
+
+cleanup:
+       qtd_list_free(fotg210, urb, head);
+       return NULL;
+}
+
+/*-------------------------------------------------------------------------*/
+/*
+ * Would be best to create all qh's from config descriptors,
+ * when each interface/altsetting is established.  Unlink
+ * any previous qh and cancel its urbs first; endpoints are
+ * implicitly reset then (data toggle too).
+ * That'd mean updating how usbcore talks to HCDs. (2.7?)
+*/
+
+
+/*
+ * Each QH holds a qtd list; a QH is used for everything except iso.
+ *
+ * For interrupt urbs, the scheduler must set the microframe scheduling
+ * mask(s) each time the QH gets scheduled.  For highspeed, that's
+ * just one microframe in the s-mask.  For split interrupt transactions
+ * there are additional complications: c-mask, maybe FSTNs.
+ */
+static struct fotg210_qh *
+qh_make(
+       struct fotg210_hcd              *fotg210,
+       struct urb              *urb,
+       gfp_t                   flags
+) {
+       struct fotg210_qh               *qh = fotg210_qh_alloc(fotg210, flags);
+       u32                     info1 = 0, info2 = 0;
+       int                     is_input, type;
+       int                     maxp = 0;
+       struct usb_tt           *tt = urb->dev->tt;
+       struct fotg210_qh_hw    *hw;
+
+       if (!qh)
+               return qh;
+
+       /*
+        * init endpoint/device data for this QH
+        */
+       info1 |= usb_pipeendpoint(urb->pipe) << 8;
+       info1 |= usb_pipedevice(urb->pipe) << 0;
+
+       is_input = usb_pipein(urb->pipe);
+       type = usb_pipetype(urb->pipe);
+       maxp = usb_maxpacket(urb->dev, urb->pipe, !is_input);
+
+       /* 1024 byte maxpacket is a hardware ceiling.  High bandwidth
+        * acts like up to 3KB, but is built from smaller packets.
+        */
+       if (max_packet(maxp) > 1024) {
+               fotg210_dbg(fotg210, "bogus qh maxpacket %d\n",
+                           max_packet(maxp));
+               goto done;
+       }
+
+       /* Compute interrupt scheduling parameters just once, and save.
+        * - allowing for high bandwidth, how many nsec/uframe are used?
+        * - split transactions need a second CSPLIT uframe; same question
+        * - splits also need a schedule gap (for full/low speed I/O)
+        * - qh has a polling interval
+        *
+        * For control/bulk requests, the HC or TT handles these.
+        */
+       if (type == PIPE_INTERRUPT) {
+               qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH,
+                               is_input, 0,
+                               hb_mult(maxp) * max_packet(maxp)));
+               qh->start = NO_FRAME;
+
+               if (urb->dev->speed == USB_SPEED_HIGH) {
+                       qh->c_usecs = 0;
+                       qh->gap_uf = 0;
+
+                       qh->period = urb->interval >> 3;
+                       if (qh->period == 0 && urb->interval != 1) {
+                               /* NOTE interval 2 or 4 uframes could work.
+                                * But interval 1 scheduling is simpler, and
+                                * includes high bandwidth.
+                                */
+                               urb->interval = 1;
+                       } else if (qh->period > fotg210->periodic_size) {
+                               qh->period = fotg210->periodic_size;
+                               urb->interval = qh->period << 3;
+                       }
+               } else {
+                       int             think_time;
+
+                       /* gap is f(FS/LS transfer times) */
+                       qh->gap_uf = 1 + usb_calc_bus_time(urb->dev->speed,
+                                       is_input, 0, maxp) / (125 * 1000);
+
+                       /* FIXME this just approximates SPLIT/CSPLIT times */
+                       if (is_input) {         /* SPLIT, gap, CSPLIT+DATA */
+                               qh->c_usecs = qh->usecs + HS_USECS(0);
+                               qh->usecs = HS_USECS(1);
+                       } else {                /* SPLIT+DATA, gap, CSPLIT */
+                               qh->usecs += HS_USECS(1);
+                               qh->c_usecs = HS_USECS(0);
+                       }
+
+                       think_time = tt ? tt->think_time : 0;
+                       qh->tt_usecs = NS_TO_US(think_time +
+                                       usb_calc_bus_time(urb->dev->speed,
+                                       is_input, 0, max_packet(maxp)));
+                       qh->period = urb->interval;
+                       if (qh->period > fotg210->periodic_size) {
+                               qh->period = fotg210->periodic_size;
+                               urb->interval = qh->period;
+                       }
+               }
+       }
+
+       /* support for tt scheduling, and access to toggles */
+       qh->dev = urb->dev;
+
+       /* using TT? */
+       switch (urb->dev->speed) {
+       case USB_SPEED_LOW:
+               info1 |= QH_LOW_SPEED;
+               /* FALL THROUGH */
+
+       case USB_SPEED_FULL:
+               /* EPS 0 means "full" */
+               if (type != PIPE_INTERRUPT)
+                       info1 |= (FOTG210_TUNE_RL_TT << 28);
+               if (type == PIPE_CONTROL) {
+                       info1 |= QH_CONTROL_EP;         /* for TT */
+                       info1 |= QH_TOGGLE_CTL;         /* toggle from qtd */
+               }
+               info1 |= maxp << 16;
+
+               info2 |= (FOTG210_TUNE_MULT_TT << 30);
+
+               /* Some Freescale processors have an erratum in which the
+                * port number in the queue head was 0..N-1 instead of 1..N.
+                */
+               if (fotg210_has_fsl_portno_bug(fotg210))
+                       info2 |= (urb->dev->ttport-1) << 23;
+               else
+                       info2 |= urb->dev->ttport << 23;
+
+               /* set the address of the TT; for TDI's integrated
+                * root hub tt, leave it zeroed.
+                */
+               if (tt && tt->hub != fotg210_to_hcd(fotg210)->self.root_hub)
+                       info2 |= tt->hub->devnum << 16;
+
+               /* NOTE:  if (PIPE_INTERRUPT) { scheduler sets c-mask } */
+
+               break;
+
+       case USB_SPEED_HIGH:            /* no TT involved */
+               info1 |= QH_HIGH_SPEED;
+               if (type == PIPE_CONTROL) {
+                       info1 |= (FOTG210_TUNE_RL_HS << 28);
+                       info1 |= 64 << 16;      /* usb2 fixed maxpacket */
+                       info1 |= QH_TOGGLE_CTL; /* toggle from qtd */
+                       info2 |= (FOTG210_TUNE_MULT_HS << 30);
+               } else if (type == PIPE_BULK) {
+                       info1 |= (FOTG210_TUNE_RL_HS << 28);
+                       /* The USB spec says that high speed bulk endpoints
+                        * always use 512 byte maxpacket.  But some device
+                        * vendors decided to ignore that, and MSFT is happy
+                        * to help them do so.  So now people expect to use
+                        * such nonconformant devices with Linux too; sigh.
+                        */
+                       info1 |= max_packet(maxp) << 16;
+                       info2 |= (FOTG210_TUNE_MULT_HS << 30);
+               } else {                /* PIPE_INTERRUPT */
+                       info1 |= max_packet(maxp) << 16;
+                       info2 |= hb_mult(maxp) << 30;
+               }
+               break;
+       default:
+               fotg210_dbg(fotg210, "bogus dev %p speed %d\n", urb->dev,
+                       urb->dev->speed);
+done:
+               qh_destroy(fotg210, qh);
+               return NULL;
+       }
+
+       /* NOTE:  if (PIPE_INTERRUPT) { scheduler sets s-mask } */
+
+       /* init as live, toggle clear, advance to dummy */
+       qh->qh_state = QH_STATE_IDLE;
+       hw = qh->hw;
+       hw->hw_info1 = cpu_to_hc32(fotg210, info1);
+       hw->hw_info2 = cpu_to_hc32(fotg210, info2);
+       qh->is_out = !is_input;
+       usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, 1);
+       qh_refresh(fotg210, qh);
+       return qh;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void enable_async(struct fotg210_hcd *fotg210)
+{
+       if (fotg210->async_count++)
+               return;
+
+       /* Stop waiting to turn off the async schedule */
+       fotg210->enabled_hrtimer_events &= ~BIT(FOTG210_HRTIMER_DISABLE_ASYNC);
+
+       /* Don't start the schedule until ASS is 0 */
+       fotg210_poll_ASS(fotg210);
+       turn_on_io_watchdog(fotg210);
+}
+
+static void disable_async(struct fotg210_hcd *fotg210)
+{
+       if (--fotg210->async_count)
+               return;
+
+       /* The async schedule and async_unlink list are supposed to be empty */
+       WARN_ON(fotg210->async->qh_next.qh || fotg210->async_unlink);
+
+       /* Don't turn off the schedule until ASS is 1 */
+       fotg210_poll_ASS(fotg210);
+}
+
+/* move qh (and its qtds) onto async queue; maybe enable queue.  */
+
+static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+       __hc32          dma = QH_NEXT(fotg210, qh->qh_dma);
+       struct fotg210_qh       *head;
+
+       /* Don't link a QH if there's a Clear-TT-Buffer pending */
+       if (unlikely(qh->clearing_tt))
+               return;
+
+       WARN_ON(qh->qh_state != QH_STATE_IDLE);
+
+       /* clear halt and/or toggle; and maybe recover from silicon quirk */
+       qh_refresh(fotg210, qh);
+
+       /* splice right after start */
+       head = fotg210->async;
+       qh->qh_next = head->qh_next;
+       qh->hw->hw_next = head->hw->hw_next;
+       wmb();
+
+       head->qh_next.qh = qh;
+       head->hw->hw_next = dma;
+
+       qh->xacterrs = 0;
+       qh->qh_state = QH_STATE_LINKED;
+       /* qtd completions reported later by interrupt */
+
+       enable_async(fotg210);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * For control/bulk/interrupt, return QH with these TDs appended.
+ * Allocates and initializes the QH if necessary.
+ * Returns null if it can't allocate a QH it needs to.
+ * If the QH has TDs (urbs) already, that's great.
+ */
+static struct fotg210_qh *qh_append_tds(
+       struct fotg210_hcd              *fotg210,
+       struct urb              *urb,
+       struct list_head        *qtd_list,
+       int                     epnum,
+       void                    **ptr
+)
+{
+       struct fotg210_qh               *qh = NULL;
+       __hc32                  qh_addr_mask = cpu_to_hc32(fotg210, 0x7f);
+
+       qh = (struct fotg210_qh *) *ptr;
+       if (unlikely(qh == NULL)) {
+               /* can't sleep here, we have fotg210->lock... */
+               qh = qh_make(fotg210, urb, GFP_ATOMIC);
+               *ptr = qh;
+       }
+       if (likely(qh != NULL)) {
+               struct fotg210_qtd      *qtd;
+
+               if (unlikely(list_empty(qtd_list)))
+                       qtd = NULL;
+               else
+                       qtd = list_entry(qtd_list->next, struct fotg210_qtd,
+                                       qtd_list);
+
+               /* control qh may need patching ... */
+               if (unlikely(epnum == 0)) {
+                       /* usb_reset_device() briefly reverts to address 0 */
+                       if (usb_pipedevice(urb->pipe) == 0)
+                               qh->hw->hw_info1 &= ~qh_addr_mask;
+               }
+
+               /* just one way to queue requests: swap with the dummy qtd.
+                * only hc or qh_refresh() ever modify the overlay.
+                */
+               if (likely(qtd != NULL)) {
+                       struct fotg210_qtd              *dummy;
+                       dma_addr_t              dma;
+                       __hc32                  token;
+
+                       /* to avoid racing the HC, use the dummy td instead of
+                        * the first td of our list (becomes new dummy).  both
+                        * tds stay deactivated until we're done, when the
+                        * HC is allowed to fetch the old dummy (4.10.2).
+                        */
+                       token = qtd->hw_token;
+                       qtd->hw_token = HALT_BIT(fotg210);
+
+                       dummy = qh->dummy;
+
+                       dma = dummy->qtd_dma;
+                       *dummy = *qtd;
+                       dummy->qtd_dma = dma;
+
+                       list_del(&qtd->qtd_list);
+                       list_add(&dummy->qtd_list, qtd_list);
+                       list_splice_tail(qtd_list, &qh->qtd_list);
+
+                       fotg210_qtd_init(fotg210, qtd, qtd->qtd_dma);
+                       qh->dummy = qtd;
+
+                       /* hc must see the new dummy at list end */
+                       dma = qtd->qtd_dma;
+                       qtd = list_entry(qh->qtd_list.prev,
+                                       struct fotg210_qtd, qtd_list);
+                       qtd->hw_next = QTD_NEXT(fotg210, dma);
+
+                       /* let the hc process these next qtds */
+                       wmb();
+                       dummy->hw_token = token;
+
+                       urb->hcpriv = qh;
+               }
+       }
+       return qh;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+submit_async(
+       struct fotg210_hcd              *fotg210,
+       struct urb              *urb,
+       struct list_head        *qtd_list,
+       gfp_t                   mem_flags
+) {
+       int                     epnum;
+       unsigned long           flags;
+       struct fotg210_qh               *qh = NULL;
+       int                     rc;
+
+       epnum = urb->ep->desc.bEndpointAddress;
+
+#ifdef FOTG210_URB_TRACE
+       {
+               struct fotg210_qtd *qtd;
+               qtd = list_entry(qtd_list->next, struct fotg210_qtd, qtd_list);
+               fotg210_dbg(fotg210,
+                        "%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n",
+                        __func__, urb->dev->devpath, urb,
+                        epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
+                        urb->transfer_buffer_length,
+                        qtd, urb->ep->hcpriv);
+       }
+#endif
+
+       spin_lock_irqsave(&fotg210->lock, flags);
+       if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
+               rc = -ESHUTDOWN;
+               goto done;
+       }
+       rc = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
+       if (unlikely(rc))
+               goto done;
+
+       qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv);
+       if (unlikely(qh == NULL)) {
+               usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
+               rc = -ENOMEM;
+               goto done;
+       }
+
+       /* Control/bulk operations through TTs don't need scheduling,
+        * the HC and TT handle it when the TT has a buffer ready.
+        */
+       if (likely(qh->qh_state == QH_STATE_IDLE))
+               qh_link_async(fotg210, qh);
+ done:
+       spin_unlock_irqrestore(&fotg210->lock, flags);
+       if (unlikely(qh == NULL))
+               qtd_list_free(fotg210, urb, qtd_list);
+       return rc;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void single_unlink_async(struct fotg210_hcd *fotg210,
+                               struct fotg210_qh *qh)
+{
+       struct fotg210_qh               *prev;
+
+       /* Add to the end of the list of QHs waiting for the next IAAD */
+       qh->qh_state = QH_STATE_UNLINK;
+       if (fotg210->async_unlink)
+               fotg210->async_unlink_last->unlink_next = qh;
+       else
+               fotg210->async_unlink = qh;
+       fotg210->async_unlink_last = qh;
+
+       /* Unlink it from the schedule */
+       prev = fotg210->async;
+       while (prev->qh_next.qh != qh)
+               prev = prev->qh_next.qh;
+
+       prev->hw->hw_next = qh->hw->hw_next;
+       prev->qh_next = qh->qh_next;
+       if (fotg210->qh_scan_next == qh)
+               fotg210->qh_scan_next = qh->qh_next.qh;
+}
+
+static void start_iaa_cycle(struct fotg210_hcd *fotg210, bool nested)
+{
+       /*
+        * Do nothing if an IAA cycle is already running or
+        * if one will be started shortly.
+        */
+       if (fotg210->async_iaa || fotg210->async_unlinking)
+               return;
+
+       /* Do all the waiting QHs at once */
+       fotg210->async_iaa = fotg210->async_unlink;
+       fotg210->async_unlink = NULL;
+
+       /* If the controller isn't running, we don't have to wait for it */
+       if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING)) {
+               if (!nested)            /* Avoid recursion */
+                       end_unlink_async(fotg210);
+
+       /* Otherwise start a new IAA cycle */
+       } else if (likely(fotg210->rh_state == FOTG210_RH_RUNNING)) {
+               /* Make sure the unlinks are all visible to the hardware */
+               wmb();
+
+               fotg210_writel(fotg210, fotg210->command | CMD_IAAD,
+                               &fotg210->regs->command);
+               fotg210_readl(fotg210, &fotg210->regs->command);
+               fotg210_enable_event(fotg210, FOTG210_HRTIMER_IAA_WATCHDOG,
+                                    true);
+       }
+}
+
+/* the async qh for the qtds being unlinked are now gone from the HC */
+
+static void end_unlink_async(struct fotg210_hcd *fotg210)
+{
+       struct fotg210_qh               *qh;
+
+       /* Process the idle QHs */
+ restart:
+       fotg210->async_unlinking = true;
+       while (fotg210->async_iaa) {
+               qh = fotg210->async_iaa;
+               fotg210->async_iaa = qh->unlink_next;
+               qh->unlink_next = NULL;
+
+               qh->qh_state = QH_STATE_IDLE;
+               qh->qh_next.qh = NULL;
+
+               qh_completions(fotg210, qh);
+               if (!list_empty(&qh->qtd_list) &&
+                               fotg210->rh_state == FOTG210_RH_RUNNING)
+                       qh_link_async(fotg210, qh);
+               disable_async(fotg210);
+       }
+       fotg210->async_unlinking = false;
+
+       /* Start a new IAA cycle if any QHs are waiting for it */
+       if (fotg210->async_unlink) {
+               start_iaa_cycle(fotg210, true);
+               if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING))
+                       goto restart;
+       }
+}
+
+static void unlink_empty_async(struct fotg210_hcd *fotg210)
+{
+       struct fotg210_qh *qh, *next;
+       bool stopped = (fotg210->rh_state < FOTG210_RH_RUNNING);
+       bool check_unlinks_later = false;
+
+       /* Unlink all the async QHs that have been empty for a timer cycle */
+       next = fotg210->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 ==
+                                       fotg210->async_unlink_cycle)
+                               check_unlinks_later = true;
+                       else
+                               single_unlink_async(fotg210, qh);
+               }
+       }
+
+       /* Start a new IAA cycle if any QHs are waiting for it */
+       if (fotg210->async_unlink)
+               start_iaa_cycle(fotg210, false);
+
+       /* QHs that haven't been empty for long enough will be handled later */
+       if (check_unlinks_later) {
+               fotg210_enable_event(fotg210, FOTG210_HRTIMER_ASYNC_UNLINKS,
+                                    true);
+               ++fotg210->async_unlink_cycle;
+       }
+}
+
+/* makes sure the async qh will become idle */
+/* caller must own fotg210->lock */
+
+static void start_unlink_async(struct fotg210_hcd *fotg210,
+                              struct fotg210_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;
+       }
+
+       single_unlink_async(fotg210, qh);
+       start_iaa_cycle(fotg210, false);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void scan_async(struct fotg210_hcd *fotg210)
+{
+       struct fotg210_qh               *qh;
+       bool                    check_unlinks_later = false;
+
+       fotg210->qh_scan_next = fotg210->async->qh_next.qh;
+       while (fotg210->qh_scan_next) {
+               qh = fotg210->qh_scan_next;
+               fotg210->qh_scan_next = qh->qh_next.qh;
+ 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 fotg210->qh_scan_next
+                        * always holds the next qh to scan; if the next qh
+                        * gets unlinked then fotg210->qh_scan_next is adjusted
+                        * in single_unlink_async().
+                        */
+                       temp = qh_completions(fotg210, qh);
+                       if (qh->needs_rescan) {
+                               start_unlink_async(fotg210, qh);
+                       } else if (list_empty(&qh->qtd_list)
+                                       && qh->qh_state == QH_STATE_LINKED) {
+                               qh->unlink_cycle = fotg210->async_unlink_cycle;
+                               check_unlinks_later = true;
+                       } else if (temp != 0)
+                               goto rescan;
+               }
+       }
+
+       /*
+        * 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 && fotg210->rh_state == FOTG210_RH_RUNNING &&
+                       !(fotg210->enabled_hrtimer_events &
+                               BIT(FOTG210_HRTIMER_ASYNC_UNLINKS))) {
+               fotg210_enable_event(fotg210,
+                                    FOTG210_HRTIMER_ASYNC_UNLINKS, true);
+               ++fotg210->async_unlink_cycle;
+       }
+}
+/*-------------------------------------------------------------------------*/
+/*
+ * EHCI scheduled transaction support:  interrupt, iso, split iso
+ * These are called "periodic" transactions in the EHCI spec.
+ *
+ * Note that for interrupt transfers, the QH/QTD manipulation is shared
+ * with the "asynchronous" transaction support (control/bulk transfers).
+ * The only real difference is in how interrupt transfers are scheduled.
+ *
+ * For ISO, we make an "iso_stream" head to serve the same role as a QH.
+ * It keeps track of every ITD (or SITD) that's linked, and holds enough
+ * pre-calculated schedule data to make appending to the queue be quick.
+ */
+
+static int fotg210_get_frame(struct usb_hcd *hcd);
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * periodic_next_shadow - return "next" pointer on shadow list
+ * @periodic: host pointer to qh/itd
+ * @tag: hardware tag for type of this record
+ */
+static union fotg210_shadow *
+periodic_next_shadow(struct fotg210_hcd *fotg210,
+                    union fotg210_shadow *periodic, __hc32 tag)
+{
+       switch (hc32_to_cpu(fotg210, tag)) {
+       case Q_TYPE_QH:
+               return &periodic->qh->qh_next;
+       case Q_TYPE_FSTN:
+               return &periodic->fstn->fstn_next;
+       default:
+               return &periodic->itd->itd_next;
+       }
+}
+
+static __hc32 *
+shadow_next_periodic(struct fotg210_hcd *fotg210,
+                    union fotg210_shadow *periodic, __hc32 tag)
+{
+       switch (hc32_to_cpu(fotg210, tag)) {
+       /* our fotg210_shadow.qh is actually software part */
+       case Q_TYPE_QH:
+               return &periodic->qh->hw->hw_next;
+       /* others are hw parts */
+       default:
+               return periodic->hw_next;
+       }
+}
+
+/* caller must hold fotg210->lock */
+static void periodic_unlink(struct fotg210_hcd *fotg210, unsigned frame,
+                           void *ptr)
+{
+       union fotg210_shadow    *prev_p = &fotg210->pshadow[frame];
+       __hc32                  *hw_p = &fotg210->periodic[frame];
+       union fotg210_shadow    here = *prev_p;
+
+       /* find predecessor of "ptr"; hw and shadow lists are in sync */
+       while (here.ptr && here.ptr != ptr) {
+               prev_p = periodic_next_shadow(fotg210, prev_p,
+                               Q_NEXT_TYPE(fotg210, *hw_p));
+               hw_p = shadow_next_periodic(fotg210, &here,
+                               Q_NEXT_TYPE(fotg210, *hw_p));
+               here = *prev_p;
+       }
+       /* an interrupt entry (at list end) could have been shared */
+       if (!here.ptr)
+               return;
+
+       /* update shadow and hardware lists ... the old "next" pointers
+        * from ptr may still be in use, the caller updates them.
+        */
+       *prev_p = *periodic_next_shadow(fotg210, &here,
+                       Q_NEXT_TYPE(fotg210, *hw_p));
+
+       *hw_p = *shadow_next_periodic(fotg210, &here,
+                               Q_NEXT_TYPE(fotg210, *hw_p));
+}
+
+/* how many of the uframe's 125 usecs are allocated? */
+static unsigned short
+periodic_usecs(struct fotg210_hcd *fotg210, unsigned frame, unsigned uframe)
+{
+       __hc32                  *hw_p = &fotg210->periodic[frame];
+       union fotg210_shadow    *q = &fotg210->pshadow[frame];
+       unsigned                usecs = 0;
+       struct fotg210_qh_hw    *hw;
+
+       while (q->ptr) {
+               switch (hc32_to_cpu(fotg210, Q_NEXT_TYPE(fotg210, *hw_p))) {
+               case Q_TYPE_QH:
+                       hw = q->qh->hw;
+                       /* is it in the S-mask? */
+                       if (hw->hw_info2 & cpu_to_hc32(fotg210, 1 << uframe))
+                               usecs += q->qh->usecs;
+                       /* ... or C-mask? */
+                       if (hw->hw_info2 & cpu_to_hc32(fotg210,
+                                       1 << (8 + uframe)))
+                               usecs += q->qh->c_usecs;
+                       hw_p = &hw->hw_next;
+                       q = &q->qh->qh_next;
+                       break;
+               /* case Q_TYPE_FSTN: */
+               default:
+                       /* for "save place" FSTNs, count the relevant INTR
+                        * bandwidth from the previous frame
+                        */
+                       if (q->fstn->hw_prev != FOTG210_LIST_END(fotg210))
+                               fotg210_dbg(fotg210, "ignoring FSTN cost ...\n");
+
+                       hw_p = &q->fstn->hw_next;
+                       q = &q->fstn->fstn_next;
+                       break;
+               case Q_TYPE_ITD:
+                       if (q->itd->hw_transaction[uframe])
+                               usecs += q->itd->stream->usecs;
+                       hw_p = &q->itd->hw_next;
+                       q = &q->itd->itd_next;
+                       break;
+               }
+       }
+#ifdef DEBUG
+       if (usecs > fotg210->uframe_periodic_max)
+               fotg210_err(fotg210, "uframe %d sched overrun: %d usecs\n",
+                       frame * 8 + uframe, usecs);
+#endif
+       return usecs;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int same_tt(struct usb_device *dev1, struct usb_device *dev2)
+{
+       if (!dev1->tt || !dev2->tt)
+               return 0;
+       if (dev1->tt != dev2->tt)
+               return 0;
+       if (dev1->tt->multi)
+               return dev1->ttport == dev2->ttport;
+       else
+               return 1;
+}
+
+/* return true iff the device's transaction translator is available
+ * for a periodic transfer starting at the specified frame, using
+ * all the uframes in the mask.
+ */
+static int tt_no_collision(
+       struct fotg210_hcd              *fotg210,
+       unsigned                period,
+       struct usb_device       *dev,
+       unsigned                frame,
+       u32                     uf_mask
+)
+{
+       if (period == 0)        /* error */
+               return 0;
+
+       /* note bandwidth wastage:  split never follows csplit
+        * (different dev or endpoint) until the next uframe.
+        * calling convention doesn't make that distinction.
+        */
+       for (; frame < fotg210->periodic_size; frame += period) {
+               union fotg210_shadow    here;
+               __hc32                  type;
+               struct fotg210_qh_hw    *hw;
+
+               here = fotg210->pshadow[frame];
+               type = Q_NEXT_TYPE(fotg210, fotg210->periodic[frame]);
+               while (here.ptr) {
+                       switch (hc32_to_cpu(fotg210, type)) {
+                       case Q_TYPE_ITD:
+                               type = Q_NEXT_TYPE(fotg210, here.itd->hw_next);
+                               here = here.itd->itd_next;
+                               continue;
+                       case Q_TYPE_QH:
+                               hw = here.qh->hw;
+                               if (same_tt(dev, here.qh->dev)) {
+                                       u32             mask;
+
+                                       mask = hc32_to_cpu(fotg210,
+                                                       hw->hw_info2);
+                                       /* "knows" no gap is needed */
+                                       mask |= mask >> 8;
+                                       if (mask & uf_mask)
+                                               break;
+                               }
+                               type = Q_NEXT_TYPE(fotg210, hw->hw_next);
+                               here = here.qh->qh_next;
+                               continue;
+                       /* case Q_TYPE_FSTN: */
+                       default:
+                               fotg210_dbg(fotg210,
+                                       "periodic frame %d bogus type %d\n",
+                                       frame, type);
+                       }
+
+                       /* collision or error */
+                       return 0;
+               }
+       }
+
+       /* no collision */
+       return 1;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void enable_periodic(struct fotg210_hcd *fotg210)
+{
+       if (fotg210->periodic_count++)
+               return;
+
+       /* Stop waiting to turn off the periodic schedule */
+       fotg210->enabled_hrtimer_events &=
+               ~BIT(FOTG210_HRTIMER_DISABLE_PERIODIC);
+
+       /* Don't start the schedule until PSS is 0 */
+       fotg210_poll_PSS(fotg210);
+       turn_on_io_watchdog(fotg210);
+}
+
+static void disable_periodic(struct fotg210_hcd *fotg210)
+{
+       if (--fotg210->periodic_count)
+               return;
+
+       /* Don't turn off the schedule until PSS is 1 */
+       fotg210_poll_PSS(fotg210);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* periodic schedule slots have iso tds (normal or split) first, then a
+ * sparse tree for active interrupt transfers.
+ *
+ * this just links in a qh; caller guarantees uframe masks are set right.
+ * no FSTN support (yet; fotg210 0.96+)
+ */
+static void qh_link_periodic(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+       unsigned        i;
+       unsigned        period = qh->period;
+
+       dev_dbg(&qh->dev->dev,
+               "link qh%d-%04x/%p start %d [%d/%d us]\n",
+               period, hc32_to_cpup(fotg210, &qh->hw->hw_info2)
+                       & (QH_CMASK | QH_SMASK),
+               qh, qh->start, qh->usecs, qh->c_usecs);
+
+       /* high bandwidth, or otherwise every microframe */
+       if (period == 0)
+               period = 1;
+
+       for (i = qh->start; i < fotg210->periodic_size; i += period) {
+               union fotg210_shadow    *prev = &fotg210->pshadow[i];
+               __hc32                  *hw_p = &fotg210->periodic[i];
+               union fotg210_shadow    here = *prev;
+               __hc32                  type = 0;
+
+               /* skip the iso nodes at list head */
+               while (here.ptr) {
+                       type = Q_NEXT_TYPE(fotg210, *hw_p);
+                       if (type == cpu_to_hc32(fotg210, Q_TYPE_QH))
+                               break;
+                       prev = periodic_next_shadow(fotg210, prev, type);
+                       hw_p = shadow_next_periodic(fotg210, &here, type);
+                       here = *prev;
+               }
+
+               /* sorting each branch by period (slow-->fast)
+                * enables sharing interior tree nodes
+                */
+               while (here.ptr && qh != here.qh) {
+                       if (qh->period > here.qh->period)
+                               break;
+                       prev = &here.qh->qh_next;
+                       hw_p = &here.qh->hw->hw_next;
+                       here = *prev;
+               }
+               /* link in this qh, unless some earlier pass did that */
+               if (qh != here.qh) {
+                       qh->qh_next = here;
+                       if (here.qh)
+                               qh->hw->hw_next = *hw_p;
+                       wmb();
+                       prev->qh = qh;
+                       *hw_p = QH_NEXT(fotg210, qh->qh_dma);
+               }
+       }
+       qh->qh_state = QH_STATE_LINKED;
+       qh->xacterrs = 0;
+
+       /* update per-qh bandwidth for usbfs */
+       fotg210_to_hcd(fotg210)->self.bandwidth_allocated += qh->period
+               ? ((qh->usecs + qh->c_usecs) / qh->period)
+               : (qh->usecs * 8);
+
+       list_add(&qh->intr_node, &fotg210->intr_qh_list);
+
+       /* maybe enable periodic schedule processing */
+       ++fotg210->intr_count;
+       enable_periodic(fotg210);
+}
+
+static void qh_unlink_periodic(struct fotg210_hcd *fotg210,
+                              struct fotg210_qh *qh)
+{
+       unsigned        i;
+       unsigned        period;
+
+       /*
+        * 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 */
+       period = qh->period;
+       if (!period)
+               period = 1;
+
+       for (i = qh->start; i < fotg210->periodic_size; i += period)
+               periodic_unlink(fotg210, i, qh);
+
+       /* update per-qh bandwidth for usbfs */
+       fotg210_to_hcd(fotg210)->self.bandwidth_allocated -= qh->period
+               ? ((qh->usecs + qh->c_usecs) / qh->period)
+               : (qh->usecs * 8);
+
+       dev_dbg(&qh->dev->dev,
+               "unlink qh%d-%04x/%p start %d [%d/%d us]\n",
+               qh->period,
+               hc32_to_cpup(fotg210, &qh->hw->hw_info2) &
+               (QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs, qh->c_usecs);
+
+       /* qh->qh_next still "live" to HC */
+       qh->qh_state = QH_STATE_UNLINK;
+       qh->qh_next.ptr = NULL;
+
+       if (fotg210->qh_scan_next == qh)
+               fotg210->qh_scan_next = list_entry(qh->intr_node.next,
+                               struct fotg210_qh, intr_node);
+       list_del(&qh->intr_node);
+}
+
+static void start_unlink_intr(struct fotg210_hcd *fotg210,
+                             struct fotg210_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;
+       }
+
+       qh_unlink_periodic(fotg210, qh);
+
+       /* 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.
+        */
+       qh->unlink_cycle = fotg210->intr_unlink_cycle;
+
+       /* New entries go at the end of the intr_unlink list */
+       if (fotg210->intr_unlink)
+               fotg210->intr_unlink_last->unlink_next = qh;
+       else
+               fotg210->intr_unlink = qh;
+       fotg210->intr_unlink_last = qh;
+
+       if (fotg210->intr_unlinking)
+               ;       /* Avoid recursive calls */
+       else if (fotg210->rh_state < FOTG210_RH_RUNNING)
+               fotg210_handle_intr_unlinks(fotg210);
+       else if (fotg210->intr_unlink == qh) {
+               fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR,
+                                    true);
+               ++fotg210->intr_unlink_cycle;
+       }
+}
+
+static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+       struct fotg210_qh_hw    *hw = qh->hw;
+       int                     rc;
+
+       qh->qh_state = QH_STATE_IDLE;
+       hw->hw_next = FOTG210_LIST_END(fotg210);
+
+       qh_completions(fotg210, qh);
+
+       /* reschedule QH iff another request is queued */
+       if (!list_empty(&qh->qtd_list) &&
+           fotg210->rh_state == FOTG210_RH_RUNNING) {
+               rc = qh_schedule(fotg210, qh);
+
+               /* An error here likely indicates handshake failure
+                * or no space left in the schedule.  Neither fault
+                * should happen often ...
+                *
+                * FIXME kill the now-dysfunctional queued urbs
+                */
+               if (rc != 0)
+                       fotg210_err(fotg210, "can't reschedule qh %p, err %d\n",
+                                       qh, rc);
+       }
+
+       /* maybe turn off periodic schedule */
+       --fotg210->intr_count;
+       disable_periodic(fotg210);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int check_period(
+       struct fotg210_hcd *fotg210,
+       unsigned        frame,
+       unsigned        uframe,
+       unsigned        period,
+       unsigned        usecs
+) {
+       int             claimed;
+
+       /* complete split running into next frame?
+        * given FSTN support, we could sometimes check...
+        */
+       if (uframe >= 8)
+               return 0;
+
+       /* convert "usecs we need" to "max already claimed" */
+       usecs = fotg210->uframe_periodic_max - usecs;
+
+       /* we "know" 2 and 4 uframe intervals were rejected; so
+        * for period 0, check _every_ microframe in the schedule.
+        */
+       if (unlikely(period == 0)) {
+               do {
+                       for (uframe = 0; uframe < 7; uframe++) {
+                               claimed = periodic_usecs(fotg210, frame,
+                                                        uframe);
+                               if (claimed > usecs)
+                                       return 0;
+                       }
+               } while ((frame += 1) < fotg210->periodic_size);
+
+       /* just check the specified uframe, at that period */
+       } else {
+               do {
+                       claimed = periodic_usecs(fotg210, frame, uframe);
+                       if (claimed > usecs)
+                               return 0;
+               } while ((frame += period) < fotg210->periodic_size);
+       }
+
+       /* success! */
+       return 1;
+}
+
+static int check_intr_schedule(
+       struct fotg210_hcd              *fotg210,
+       unsigned                frame,
+       unsigned                uframe,
+       const struct fotg210_qh *qh,
+       __hc32                  *c_maskp
+)
+{
+       int             retval = -ENOSPC;
+       u8              mask = 0;
+
+       if (qh->c_usecs && uframe >= 6)         /* FSTN territory? */
+               goto done;
+
+       if (!check_period(fotg210, frame, uframe, qh->period, qh->usecs))
+               goto done;
+       if (!qh->c_usecs) {
+               retval = 0;
+               *c_maskp = 0;
+               goto done;
+       }
+
+       /* Make sure this tt's buffer is also available for CSPLITs.
+        * We pessimize a bit; probably the typical full speed case
+        * doesn't need the second CSPLIT.
+        *
+        * NOTE:  both SPLIT and CSPLIT could be checked in just
+        * one smart pass...
+        */
+       mask = 0x03 << (uframe + qh->gap_uf);
+       *c_maskp = cpu_to_hc32(fotg210, mask << 8);
+
+       mask |= 1 << uframe;
+       if (tt_no_collision(fotg210, qh->period, qh->dev, frame, mask)) {
+               if (!check_period(fotg210, frame, uframe + qh->gap_uf + 1,
+                                       qh->period, qh->c_usecs))
+                       goto done;
+               if (!check_period(fotg210, frame, uframe + qh->gap_uf,
+                                       qh->period, qh->c_usecs))
+                       goto done;
+               retval = 0;
+       }
+done:
+       return retval;
+}
+
+/* "first fit" scheduling policy used the first time through,
+ * or when the previous schedule slot can't be re-used.
+ */
+static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+       int             status;
+       unsigned        uframe;
+       __hc32          c_mask;
+       unsigned        frame;          /* 0..(qh->period - 1), or NO_FRAME */
+       struct fotg210_qh_hw    *hw = qh->hw;
+
+       qh_refresh(fotg210, qh);
+       hw->hw_next = FOTG210_LIST_END(fotg210);
+       frame = qh->start;
+
+       /* reuse the previous schedule slots, if we can */
+       if (frame < qh->period) {
+               uframe = ffs(hc32_to_cpup(fotg210, &hw->hw_info2) & QH_SMASK);
+               status = check_intr_schedule(fotg210, frame, --uframe,
+                               qh, &c_mask);
+       } else {
+               uframe = 0;
+               c_mask = 0;
+               status = -ENOSPC;
+       }
+
+       /* else scan the schedule to find a group of slots such that all
+        * uframes have enough periodic bandwidth available.
+        */
+       if (status) {
+               /* "normal" case, uframing flexible except with splits */
+               if (qh->period) {
+                       int             i;
+
+                       for (i = qh->period; status && i > 0; --i) {
+                               frame = ++fotg210->random_frame % qh->period;
+                               for (uframe = 0; uframe < 8; uframe++) {
+                                       status = check_intr_schedule(fotg210,
+                                                       frame, uframe, qh,
+                                                       &c_mask);
+                                       if (status == 0)
+                                               break;
+                               }
+                       }
+
+               /* qh->period == 0 means every uframe */
+               } else {
+                       frame = 0;
+                       status = check_intr_schedule(fotg210, 0, 0, qh,
+                                                    &c_mask);
+               }
+               if (status)
+                       goto done;
+               qh->start = frame;
+
+               /* reset S-frame and (maybe) C-frame masks */
+               hw->hw_info2 &= cpu_to_hc32(fotg210, ~(QH_CMASK | QH_SMASK));
+               hw->hw_info2 |= qh->period
+                       ? cpu_to_hc32(fotg210, 1 << uframe)
+                       : cpu_to_hc32(fotg210, QH_SMASK);
+               hw->hw_info2 |= c_mask;
+       } else
+               fotg210_dbg(fotg210, "reused qh %p schedule\n", qh);
+
+       /* stuff into the periodic schedule */
+       qh_link_periodic(fotg210, qh);
+done:
+       return status;
+}
+
+static int intr_submit(
+       struct fotg210_hcd              *fotg210,
+       struct urb              *urb,
+       struct list_head        *qtd_list,
+       gfp_t                   mem_flags
+) {
+       unsigned                epnum;
+       unsigned long           flags;
+       struct fotg210_qh               *qh;
+       int                     status;
+       struct list_head        empty;
+
+       /* get endpoint and transfer/schedule data */
+       epnum = urb->ep->desc.bEndpointAddress;
+
+       spin_lock_irqsave(&fotg210->lock, flags);
+
+       if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
+               status = -ESHUTDOWN;
+               goto done_not_linked;
+       }
+       status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
+       if (unlikely(status))
+               goto done_not_linked;
+
+       /* get qh and force any scheduling errors */
+       INIT_LIST_HEAD(&empty);
+       qh = qh_append_tds(fotg210, urb, &empty, epnum, &urb->ep->hcpriv);
+       if (qh == NULL) {
+               status = -ENOMEM;
+               goto done;
+       }
+       if (qh->qh_state == QH_STATE_IDLE) {
+               status = qh_schedule(fotg210, qh);
+               if (status)
+                       goto done;
+       }
+
+       /* then queue the urb's tds to the qh */
+       qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv);
+       BUG_ON(qh == NULL);
+
+       /* ... update usbfs periodic stats */
+       fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs++;
+
+done:
+       if (unlikely(status))
+               usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
+done_not_linked:
+       spin_unlock_irqrestore(&fotg210->lock, flags);
+       if (status)
+               qtd_list_free(fotg210, urb, qtd_list);
+
+       return status;
+}
+
+static void scan_intr(struct fotg210_hcd *fotg210)
+{
+       struct fotg210_qh               *qh;
+
+       list_for_each_entry_safe(qh, fotg210->qh_scan_next,
+                                &fotg210->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 fotg210->qh_scan_next
+                        * always holds the next qh to scan; if the next qh
+                        * gets unlinked then fotg210->qh_scan_next is adjusted
+                        * in qh_unlink_periodic().
+                        */
+                       temp = qh_completions(fotg210, qh);
+                       if (unlikely(qh->needs_rescan ||
+                                       (list_empty(&qh->qtd_list) &&
+                                        qh->qh_state == QH_STATE_LINKED)))
+                               start_unlink_intr(fotg210, qh);
+                       else if (temp != 0)
+                               goto rescan;
+               }
+       }
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* fotg210_iso_stream ops work with both ITD and SITD */
+
+static struct fotg210_iso_stream *
+iso_stream_alloc(gfp_t mem_flags)
+{
+       struct fotg210_iso_stream *stream;
+
+       stream = kzalloc(sizeof(*stream), mem_flags);
+       if (likely(stream != NULL)) {
+               INIT_LIST_HEAD(&stream->td_list);
+               INIT_LIST_HEAD(&stream->free_list);
+               stream->next_uframe = -1;
+       }
+       return stream;
+}
+
+static void
+iso_stream_init(
+       struct fotg210_hcd              *fotg210,
+       struct fotg210_iso_stream       *stream,
+       struct usb_device       *dev,
+       int                     pipe,
+       unsigned                interval
+)
+{
+       u32                     buf1;
+       unsigned                epnum, maxp;
+       int                     is_input;
+       long                    bandwidth;
+       unsigned                multi;
+
+       /*
+        * this might be a "high bandwidth" highspeed endpoint,
+        * as encoded in the ep descriptor's wMaxPacket field
+        */
+       epnum = usb_pipeendpoint(pipe);
+       is_input = usb_pipein(pipe) ? USB_DIR_IN : 0;
+       maxp = usb_maxpacket(dev, pipe, !is_input);
+       if (is_input)
+               buf1 = (1 << 11);
+       else
+               buf1 = 0;
+
+       maxp = max_packet(maxp);
+       multi = hb_mult(maxp);
+       buf1 |= maxp;
+       maxp *= multi;
+
+       stream->buf0 = cpu_to_hc32(fotg210, (epnum << 8) | dev->devnum);
+       stream->buf1 = cpu_to_hc32(fotg210, buf1);
+       stream->buf2 = cpu_to_hc32(fotg210, multi);
+
+       /* usbfs wants to report the average usecs per frame tied up
+        * when transfers on this endpoint are scheduled ...
+        */
+       if (dev->speed == USB_SPEED_FULL) {
+               interval <<= 3;
+               stream->usecs = NS_TO_US(usb_calc_bus_time(dev->speed,
+                               is_input, 1, maxp));
+               stream->usecs /= 8;
+       } else {
+               stream->highspeed = 1;
+               stream->usecs = HS_USECS_ISO(maxp);
+       }
+       bandwidth = stream->usecs * 8;
+       bandwidth /= interval;
+
+       stream->bandwidth = bandwidth;
+       stream->udev = dev;
+       stream->bEndpointAddress = is_input | epnum;
+       stream->interval = interval;
+       stream->maxp = maxp;
+}
+
+static struct fotg210_iso_stream *
+iso_stream_find(struct fotg210_hcd *fotg210, struct urb *urb)
+{
+       unsigned                epnum;
+       struct fotg210_iso_stream       *stream;
+       struct usb_host_endpoint *ep;
+       unsigned long           flags;
+
+       epnum = usb_pipeendpoint(urb->pipe);
+       if (usb_pipein(urb->pipe))
+               ep = urb->dev->ep_in[epnum];
+       else
+               ep = urb->dev->ep_out[epnum];
+
+       spin_lock_irqsave(&fotg210->lock, flags);
+       stream = ep->hcpriv;
+
+       if (unlikely(stream == NULL)) {
+               stream = iso_stream_alloc(GFP_ATOMIC);
+               if (likely(stream != NULL)) {
+                       ep->hcpriv = stream;
+                       stream->ep = ep;
+                       iso_stream_init(fotg210, stream, urb->dev, urb->pipe,
+                                       urb->interval);
+               }
+
+       /* if dev->ep[epnum] is a QH, hw is set */
+       } else if (unlikely(stream->hw != NULL)) {
+               fotg210_dbg(fotg210, "dev %s ep%d%s, not iso??\n",
+                       urb->dev->devpath, epnum,
+                       usb_pipein(urb->pipe) ? "in" : "out");
+               stream = NULL;
+       }
+
+       spin_unlock_irqrestore(&fotg210->lock, flags);
+       return stream;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* fotg210_iso_sched ops can be ITD-only or SITD-only */
+
+static struct fotg210_iso_sched *
+iso_sched_alloc(unsigned packets, gfp_t mem_flags)
+{
+       struct fotg210_iso_sched        *iso_sched;
+       int                     size = sizeof(*iso_sched);
+
+       size += packets * sizeof(struct fotg210_iso_packet);
+       iso_sched = kzalloc(size, mem_flags);
+       if (likely(iso_sched != NULL))
+               INIT_LIST_HEAD(&iso_sched->td_list);
+
+       return iso_sched;
+}
+
+static inline void
+itd_sched_init(
+       struct fotg210_hcd              *fotg210,
+       struct fotg210_iso_sched        *iso_sched,
+       struct fotg210_iso_stream       *stream,
+       struct urb              *urb
+)
+{
+       unsigned        i;
+       dma_addr_t      dma = urb->transfer_dma;
+
+       /* how many uframes are needed for these transfers */
+       iso_sched->span = urb->number_of_packets * stream->interval;
+
+       /* figure out per-uframe itd fields that we'll need later
+        * when we fit new itds into the schedule.
+        */
+       for (i = 0; i < urb->number_of_packets; i++) {
+               struct fotg210_iso_packet       *uframe = &iso_sched->packet[i];
+               unsigned                length;
+               dma_addr_t              buf;
+               u32                     trans;
+
+               length = urb->iso_frame_desc[i].length;
+               buf = dma + urb->iso_frame_desc[i].offset;
+
+               trans = FOTG210_ISOC_ACTIVE;
+               trans |= buf & 0x0fff;
+               if (unlikely(((i + 1) == urb->number_of_packets))
+                               && !(urb->transfer_flags & URB_NO_INTERRUPT))
+                       trans |= FOTG210_ITD_IOC;
+               trans |= length << 16;
+               uframe->transaction = cpu_to_hc32(fotg210, trans);
+
+               /* might need to cross a buffer page within a uframe */
+               uframe->bufp = (buf & ~(u64)0x0fff);
+               buf += length;
+               if (unlikely((uframe->bufp != (buf & ~(u64)0x0fff))))
+                       uframe->cross = 1;
+       }
+}
+
+static void
+iso_sched_free(
+       struct fotg210_iso_stream       *stream,
+       struct fotg210_iso_sched        *iso_sched
+)
+{
+       if (!iso_sched)
+               return;
+       /* caller must hold fotg210->lock!*/
+       list_splice(&iso_sched->td_list, &stream->free_list);
+       kfree(iso_sched);
+}
+
+static int
+itd_urb_transaction(
+       struct fotg210_iso_stream       *stream,
+       struct fotg210_hcd              *fotg210,
+       struct urb              *urb,
+       gfp_t                   mem_flags
+)
+{
+       struct fotg210_itd              *itd;
+       dma_addr_t              itd_dma;
+       int                     i;
+       unsigned                num_itds;
+       struct fotg210_iso_sched        *sched;
+       unsigned long           flags;
+
+       sched = iso_sched_alloc(urb->number_of_packets, mem_flags);
+       if (unlikely(sched == NULL))
+               return -ENOMEM;
+
+       itd_sched_init(fotg210, sched, stream, urb);
+
+       if (urb->interval < 8)
+               num_itds = 1 + (sched->span + 7) / 8;
+       else
+               num_itds = urb->number_of_packets;
+
+       /* allocate/init ITDs */
+       spin_lock_irqsave(&fotg210->lock, flags);
+       for (i = 0; i < num_itds; i++) {
+
+               /*
+                * Use iTDs from the free list, but not iTDs that may
+                * still be in use by the hardware.
+                */
+               if (likely(!list_empty(&stream->free_list))) {
+                       itd = list_first_entry(&stream->free_list,
+                                       struct fotg210_itd, itd_list);
+                       if (itd->frame == fotg210->now_frame)
+                               goto alloc_itd;
+                       list_del(&itd->itd_list);
+                       itd_dma = itd->itd_dma;
+               } else {
+ alloc_itd:
+                       spin_unlock_irqrestore(&fotg210->lock, flags);
+                       itd = dma_pool_alloc(fotg210->itd_pool, mem_flags,
+                                       &itd_dma);
+                       spin_lock_irqsave(&fotg210->lock, flags);
+                       if (!itd) {
+                               iso_sched_free(stream, sched);
+                               spin_unlock_irqrestore(&fotg210->lock, flags);
+                               return -ENOMEM;
+                       }
+               }
+
+               memset(itd, 0, sizeof(*itd));
+               itd->itd_dma = itd_dma;
+               list_add(&itd->itd_list, &sched->td_list);
+       }
+       spin_unlock_irqrestore(&fotg210->lock, flags);
+
+       /* temporarily store schedule info in hcpriv */
+       urb->hcpriv = sched;
+       urb->error_count = 0;
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline int
+itd_slot_ok(
+       struct fotg210_hcd              *fotg210,
+       u32                     mod,
+       u32                     uframe,
+       u8                      usecs,
+       u32                     period
+)
+{
+       uframe %= period;
+       do {
+               /* can't commit more than uframe_periodic_max usec */
+               if (periodic_usecs(fotg210, uframe >> 3, uframe & 0x7)
+                               > (fotg210->uframe_periodic_max - usecs))
+                       return 0;
+
+               /* we know urb->interval is 2^N uframes */
+               uframe += period;
+       } while (uframe < mod);
+       return 1;
+}
+
+/*
+ * This scheduler plans almost as far into the future as it has actual
+ * periodic schedule slots.  (Affected by TUNE_FLS, which defaults to
+ * "as small as possible" to be cache-friendlier.)  That limits the size
+ * transfers you can stream reliably; avoid more than 64 msec per urb.
+ * Also avoid queue depths of less than fotg210's worst irq latency (affected
+ * by the per-urb URB_NO_INTERRUPT hint, the log2_irq_thresh module parameter,
+ * and other factors); or more than about 230 msec total (for portability,
+ * given FOTG210_TUNE_FLS and the slop).  Or, write a smarter scheduler!
+ */
+
+#define SCHEDULE_SLOP  80      /* microframes */
+
+static int
+iso_stream_schedule(
+       struct fotg210_hcd              *fotg210,
+       struct urb              *urb,
+       struct fotg210_iso_stream       *stream
+)
+{
+       u32                     now, next, start, period, span;
+       int                     status;
+       unsigned                mod = fotg210->periodic_size << 3;
+       struct fotg210_iso_sched        *sched = urb->hcpriv;
+
+       period = urb->interval;
+       span = sched->span;
+
+       if (span > mod - SCHEDULE_SLOP) {
+               fotg210_dbg(fotg210, "iso request %p too long\n", urb);
+               status = -EFBIG;
+               goto fail;
+       }
+
+       now = fotg210_read_frame_index(fotg210) & (mod - 1);
+
+       /* Typical case: reuse current schedule, stream is still active.
+        * Hopefully there are no gaps from the host falling behind
+        * (irq delays etc), but if there are we'll take the next
+        * slot in the schedule, implicitly assuming URB_ISO_ASAP.
+        */
+       if (likely(!list_empty(&stream->td_list))) {
+               u32     excess;
+
+               /* For high speed devices, allow scheduling within the
+                * isochronous scheduling threshold.  For full speed devices
+                * and Intel PCI-based controllers, don't (work around for
+                * Intel ICH9 bug).
+                */
+               if (!stream->highspeed && fotg210->fs_i_thresh)
+                       next = now + fotg210->i_thresh;
+               else
+                       next = now;
+
+               /* Fell behind (by up to twice the slop amount)?
+                * We decide based on the time of the last currently-scheduled
+                * slot, not the time of the next available slot.
+                */
+               excess = (stream->next_uframe - period - next) & (mod - 1);
+               if (excess >= mod - 2 * SCHEDULE_SLOP)
+                       start = next + excess - mod + period *
+                                       DIV_ROUND_UP(mod - excess, period);
+               else
+                       start = next + excess + period;
+               if (start - now >= mod) {
+                       fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n",
+                                       urb, start - now - period, period,
+                                       mod);
+                       status = -EFBIG;
+                       goto fail;
+               }
+       }
+
+       /* need to schedule; when's the next (u)frame we could start?
+        * this is bigger than fotg210->i_thresh allows; scheduling itself
+        * isn't free, the slop should handle reasonably slow cpus.  it
+        * can also help high bandwidth if the dma and irq loads don't
+        * jump until after the queue is primed.
+        */
+       else {
+               int done = 0;
+               start = SCHEDULE_SLOP + (now & ~0x07);
+
+               /* NOTE:  assumes URB_ISO_ASAP, to limit complexity/bugs */
+
+               /* find a uframe slot with enough bandwidth.
+                * Early uframes are more precious because full-speed
+                * iso IN transfers can't use late uframes,
+                * and therefore they should be allocated last.
+                */
+               next = start;
+               start += period;
+               do {
+                       start--;
+                       /* check schedule: enough space? */
+                       if (itd_slot_ok(fotg210, mod, start,
+                                       stream->usecs, period))
+                               done = 1;
+               } while (start > next && !done);
+
+               /* no room in the schedule */
+               if (!done) {
+                       fotg210_dbg(fotg210, "iso resched full %p (now %d max %d)\n",
+                               urb, now, now + mod);
+                       status = -ENOSPC;
+                       goto fail;
+               }
+       }
+
+       /* Tried to schedule too far into the future? */
+       if (unlikely(start - now + span - period
+                               >= mod - 2 * SCHEDULE_SLOP)) {
+               fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n",
+                               urb, start - now, span - period,
+                               mod - 2 * SCHEDULE_SLOP);
+               status = -EFBIG;
+               goto fail;
+       }
+
+       stream->next_uframe = start & (mod - 1);
+
+       /* report high speed start in uframes; full speed, in frames */
+       urb->start_frame = stream->next_uframe;
+       if (!stream->highspeed)
+               urb->start_frame >>= 3;
+
+       /* Make sure scan_isoc() sees these */
+       if (fotg210->isoc_count == 0)
+               fotg210->next_frame = now >> 3;
+       return 0;
+
+ fail:
+       iso_sched_free(stream, sched);
+       urb->hcpriv = NULL;
+       return status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline void
+itd_init(struct fotg210_hcd *fotg210, struct fotg210_iso_stream *stream,
+               struct fotg210_itd *itd)
+{
+       int i;
+
+       /* it's been recently zeroed */
+       itd->hw_next = FOTG210_LIST_END(fotg210);
+       itd->hw_bufp[0] = stream->buf0;
+       itd->hw_bufp[1] = stream->buf1;
+       itd->hw_bufp[2] = stream->buf2;
+
+       for (i = 0; i < 8; i++)
+               itd->index[i] = -1;
+
+       /* All other fields are filled when scheduling */
+}
+
+static inline void
+itd_patch(
+       struct fotg210_hcd              *fotg210,
+       struct fotg210_itd              *itd,
+       struct fotg210_iso_sched        *iso_sched,
+       unsigned                index,
+       u16                     uframe
+)
+{
+       struct fotg210_iso_packet       *uf = &iso_sched->packet[index];
+       unsigned                pg = itd->pg;
+
+       uframe &= 0x07;
+       itd->index[uframe] = index;
+
+       itd->hw_transaction[uframe] = uf->transaction;
+       itd->hw_transaction[uframe] |= cpu_to_hc32(fotg210, pg << 12);
+       itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, uf->bufp & ~(u32)0);
+       itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(uf->bufp >> 32));
+
+       /* iso_frame_desc[].offset must be strictly increasing */
+       if (unlikely(uf->cross)) {
+               u64     bufp = uf->bufp + 4096;
+
+               itd->pg = ++pg;
+               itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, bufp & ~(u32)0);
+               itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(bufp >> 32));
+       }
+}
+
+static inline void
+itd_link(struct fotg210_hcd *fotg210, unsigned frame, struct fotg210_itd *itd)
+{
+       union fotg210_shadow    *prev = &fotg210->pshadow[frame];
+       __hc32                  *hw_p = &fotg210->periodic[frame];
+       union fotg210_shadow    here = *prev;
+       __hc32                  type = 0;
+
+       /* skip any iso nodes which might belong to previous microframes */
+       while (here.ptr) {
+               type = Q_NEXT_TYPE(fotg210, *hw_p);
+               if (type == cpu_to_hc32(fotg210, Q_TYPE_QH))
+                       break;
+               prev = periodic_next_shadow(fotg210, prev, type);
+               hw_p = shadow_next_periodic(fotg210, &here, type);
+               here = *prev;
+       }
+
+       itd->itd_next = here;
+       itd->hw_next = *hw_p;
+       prev->itd = itd;
+       itd->frame = frame;
+       wmb();
+       *hw_p = cpu_to_hc32(fotg210, itd->itd_dma | Q_TYPE_ITD);
+}
+
+/* fit urb's itds into the selected schedule slot; activate as needed */
+static void itd_link_urb(
+       struct fotg210_hcd              *fotg210,
+       struct urb              *urb,
+       unsigned                mod,
+       struct fotg210_iso_stream       *stream
+)
+{
+       int                     packet;
+       unsigned                next_uframe, uframe, frame;
+       struct fotg210_iso_sched        *iso_sched = urb->hcpriv;
+       struct fotg210_itd              *itd;
+
+       next_uframe = stream->next_uframe & (mod - 1);
+
+       if (unlikely(list_empty(&stream->td_list))) {
+               fotg210_to_hcd(fotg210)->self.bandwidth_allocated
+                               += stream->bandwidth;
+               fotg210_vdbg(fotg210,
+                       "schedule devp %s ep%d%s-iso period %d start %d.%d\n",
+                       urb->dev->devpath, stream->bEndpointAddress & 0x0f,
+                       (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
+                       urb->interval,
+                       next_uframe >> 3, next_uframe & 0x7);
+       }
+
+       /* fill iTDs uframe by uframe */
+       for (packet = 0, itd = NULL; packet < urb->number_of_packets;) {
+               if (itd == NULL) {
+                       /* ASSERT:  we have all necessary itds */
+
+                       /* ASSERT:  no itds for this endpoint in this uframe */
+
+                       itd = list_entry(iso_sched->td_list.next,
+                                       struct fotg210_itd, itd_list);
+                       list_move_tail(&itd->itd_list, &stream->td_list);
+                       itd->stream = stream;
+                       itd->urb = urb;
+                       itd_init(fotg210, stream, itd);
+               }
+
+               uframe = next_uframe & 0x07;
+               frame = next_uframe >> 3;
+
+               itd_patch(fotg210, itd, iso_sched, packet, uframe);
+
+               next_uframe += stream->interval;
+               next_uframe &= mod - 1;
+               packet++;
+
+               /* link completed itds into the schedule */
+               if (((next_uframe >> 3) != frame)
+                               || packet == urb->number_of_packets) {
+                       itd_link(fotg210, frame & (fotg210->periodic_size - 1),
+                                itd);
+                       itd = NULL;
+               }
+       }
+       stream->next_uframe = next_uframe;
+
+       /* don't need that schedule data any more */
+       iso_sched_free(stream, iso_sched);
+       urb->hcpriv = NULL;
+
+       ++fotg210->isoc_count;
+       enable_periodic(fotg210);
+}
+
+#define        ISO_ERRS (FOTG210_ISOC_BUF_ERR | FOTG210_ISOC_BABBLE |\
+                 FOTG210_ISOC_XACTERR)
+
+/* Process and recycle a completed ITD.  Return true iff its urb completed,
+ * and hence its completion callback probably added things to the hardware
+ * schedule.
+ *
+ * Note that we carefully avoid recycling this descriptor until after any
+ * completion callback runs, so that it won't be reused quickly.  That is,
+ * assuming (a) no more than two urbs per frame on this endpoint, and also
+ * (b) only this endpoint's completions submit URBs.  It seems some silicon
+ * corrupts things if you reuse completed descriptors very quickly...
+ */
+static bool itd_complete(struct fotg210_hcd *fotg210, struct fotg210_itd *itd)
+{
+       struct urb                              *urb = itd->urb;
+       struct usb_iso_packet_descriptor        *desc;
+       u32                                     t;
+       unsigned                                uframe;
+       int                                     urb_index = -1;
+       struct fotg210_iso_stream                       *stream = itd->stream;
+       struct usb_device                       *dev;
+       bool                                    retval = false;
+
+       /* for each uframe with a packet */
+       for (uframe = 0; uframe < 8; uframe++) {
+               if (likely(itd->index[uframe] == -1))
+                       continue;
+               urb_index = itd->index[uframe];
+               desc = &urb->iso_frame_desc[urb_index];
+
+               t = hc32_to_cpup(fotg210, &itd->hw_transaction[uframe]);
+               itd->hw_transaction[uframe] = 0;
+
+               /* report transfer status */
+               if (unlikely(t & ISO_ERRS)) {
+                       urb->error_count++;
+                       if (t & FOTG210_ISOC_BUF_ERR)
+                               desc->status = usb_pipein(urb->pipe)
+                                       ? -ENOSR  /* hc couldn't read */
+                                       : -ECOMM; /* hc couldn't write */
+                       else if (t & FOTG210_ISOC_BABBLE)
+                               desc->status = -EOVERFLOW;
+                       else /* (t & FOTG210_ISOC_XACTERR) */
+                               desc->status = -EPROTO;
+
+                       /* HC need not update length with this error */
+                       if (!(t & FOTG210_ISOC_BABBLE)) {
+                               desc->actual_length =
+                                       fotg210_itdlen(urb, desc, t);
+                               urb->actual_length += desc->actual_length;
+                       }
+               } else if (likely((t & FOTG210_ISOC_ACTIVE) == 0)) {
+                       desc->status = 0;
+                       desc->actual_length = fotg210_itdlen(urb, desc, t);
+                       urb->actual_length += desc->actual_length;
+               } else {
+                       /* URB was too late */
+                       desc->status = -EXDEV;
+               }
+       }
+
+       /* handle completion now? */
+       if (likely((urb_index + 1) != urb->number_of_packets))
+               goto done;
+
+       /* ASSERT: it's really the last itd for this urb
+       list_for_each_entry (itd, &stream->td_list, itd_list)
+               BUG_ON (itd->urb == urb);
+        */
+
+       /* give urb back to the driver; completion often (re)submits */
+       dev = urb->dev;
+       fotg210_urb_done(fotg210, urb, 0);
+       retval = true;
+       urb = NULL;
+
+       --fotg210->isoc_count;
+       disable_periodic(fotg210);
+
+       if (unlikely(list_is_singular(&stream->td_list))) {
+               fotg210_to_hcd(fotg210)->self.bandwidth_allocated
+                               -= stream->bandwidth;
+               fotg210_vdbg(fotg210,
+                       "deschedule devp %s ep%d%s-iso\n",
+                       dev->devpath, stream->bEndpointAddress & 0x0f,
+                       (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
+       }
+
+done:
+       itd->urb = 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,
+                               &fotg210->cached_itd_list);
+               start_free_itds(fotg210);
+       }
+
+       return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int itd_submit(struct fotg210_hcd *fotg210, struct urb *urb,
+       gfp_t mem_flags)
+{
+       int                     status = -EINVAL;
+       unsigned long           flags;
+       struct fotg210_iso_stream       *stream;
+
+       /* Get iso_stream head */
+       stream = iso_stream_find(fotg210, urb);
+       if (unlikely(stream == NULL)) {
+               fotg210_dbg(fotg210, "can't get iso stream\n");
+               return -ENOMEM;
+       }
+       if (unlikely(urb->interval != stream->interval &&
+                     fotg210_port_speed(fotg210, 0) ==
+                               USB_PORT_STAT_HIGH_SPEED)) {
+                       fotg210_dbg(fotg210, "can't change iso interval %d --> %d\n",
+                               stream->interval, urb->interval);
+                       goto done;
+       }
+
+#ifdef FOTG210_URB_TRACE
+       fotg210_dbg(fotg210,
+               "%s %s urb %p ep%d%s len %d, %d pkts %d uframes[%p]\n",
+               __func__, urb->dev->devpath, urb,
+               usb_pipeendpoint(urb->pipe),
+               usb_pipein(urb->pipe) ? "in" : "out",
+               urb->transfer_buffer_length,
+               urb->number_of_packets, urb->interval,
+               stream);
+#endif
+
+       /* allocate ITDs w/o locking anything */
+       status = itd_urb_transaction(stream, fotg210, urb, mem_flags);
+       if (unlikely(status < 0)) {
+               fotg210_dbg(fotg210, "can't init itds\n");
+               goto done;
+       }
+
+       /* schedule ... need to lock */
+       spin_lock_irqsave(&fotg210->lock, flags);
+       if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
+               status = -ESHUTDOWN;
+               goto done_not_linked;
+       }
+       status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
+       if (unlikely(status))
+               goto done_not_linked;
+       status = iso_stream_schedule(fotg210, urb, stream);
+       if (likely(status == 0))
+               itd_link_urb(fotg210, urb, fotg210->periodic_size << 3, stream);
+       else
+               usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
+ done_not_linked:
+       spin_unlock_irqrestore(&fotg210->lock, flags);
+ done:
+       return status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void scan_isoc(struct fotg210_hcd *fotg210)
+{
+       unsigned        uf, now_frame, frame;
+       unsigned        fmask = fotg210->periodic_size - 1;
+       bool            modified, live;
+
+       /*
+        * When running, scan from last scan point up to "now"
+        * else clean up by scanning everything that's left.
+        * Touches as few pages as possible:  cache-friendly.
+        */
+       if (fotg210->rh_state >= FOTG210_RH_RUNNING) {
+               uf = fotg210_read_frame_index(fotg210);
+               now_frame = (uf >> 3) & fmask;
+               live = true;
+       } else  {
+               now_frame = (fotg210->next_frame - 1) & fmask;
+               live = false;
+       }
+       fotg210->now_frame = now_frame;
+
+       frame = fotg210->next_frame;
+       for (;;) {
+               union fotg210_shadow    q, *q_p;
+               __hc32                  type, *hw_p;
+
+restart:
+               /* scan each element in frame's queue for completions */
+               q_p = &fotg210->pshadow[frame];
+               hw_p = &fotg210->periodic[frame];
+               q.ptr = q_p->ptr;
+               type = Q_NEXT_TYPE(fotg210, *hw_p);
+               modified = false;
+
+               while (q.ptr != NULL) {
+                       switch (hc32_to_cpu(fotg210, type)) {
+                       case Q_TYPE_ITD:
+                               /* If this ITD is still active, leave it for
+                                * later processing ... check the next entry.
+                                * No need to check for activity unless the
+                                * frame is current.
+                                */
+                               if (frame == now_frame && live) {
+                                       rmb();
+                                       for (uf = 0; uf < 8; uf++) {
+                                               if (q.itd->hw_transaction[uf] &
+                                                           ITD_ACTIVE(fotg210))
+                                                       break;
+                                       }
+                                       if (uf < 8) {
+                                               q_p = &q.itd->itd_next;
+                                               hw_p = &q.itd->hw_next;
+                                               type = Q_NEXT_TYPE(fotg210,
+                                                       q.itd->hw_next);
+                                               q = *q_p;
+                                               break;
+                                       }
+                               }
+
+                               /* Take finished ITDs out of the schedule
+                                * and process them:  recycle, maybe report
+                                * URB completion.  HC won't cache the
+                                * pointer for much longer, if at all.
+                                */
+                               *q_p = q.itd->itd_next;
+                               *hw_p = q.itd->hw_next;
+                               type = Q_NEXT_TYPE(fotg210, q.itd->hw_next);
+                               wmb();
+                               modified = itd_complete(fotg210, q.itd);
+                               q = *q_p;
+                               break;
+                       default:
+                               fotg210_dbg(fotg210, "corrupt type %d frame %d shadow %p\n",
+                                       type, frame, q.ptr);
+                               /* FALL THROUGH */
+                       case Q_TYPE_QH:
+                       case Q_TYPE_FSTN:
+                               /* End of the iTDs and siTDs */
+                               q.ptr = NULL;
+                               break;
+                       }
+
+                       /* assume completion callbacks modify the queue */
+                       if (unlikely(modified && fotg210->isoc_count > 0))
+                               goto restart;
+               }
+
+               /* Stop when we have reached the current frame */
+               if (frame == now_frame)
+                       break;
+               frame = (frame + 1) & fmask;
+       }
+       fotg210->next_frame = now_frame;
+}
+/*-------------------------------------------------------------------------*/
+/*
+ * Display / Set uframe_periodic_max
+ */
+static ssize_t show_uframe_periodic_max(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct fotg210_hcd              *fotg210;
+       int                     n;
+
+       fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev)));
+       n = scnprintf(buf, PAGE_SIZE, "%d\n", fotg210->uframe_periodic_max);
+       return n;
+}
+
+
+static ssize_t store_uframe_periodic_max(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct fotg210_hcd      *fotg210;
+       unsigned                uframe_periodic_max;
+       unsigned                frame, uframe;
+       unsigned short          allocated_max;
+       unsigned long           flags;
+       ssize_t                 ret;
+
+       fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev)));
+       if (kstrtouint(buf, 0, &uframe_periodic_max) < 0)
+               return -EINVAL;
+
+       if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) {
+               fotg210_info(fotg210, "rejecting invalid request for uframe_periodic_max=%u\n",
+                            uframe_periodic_max);
+               return -EINVAL;
+       }
+
+       ret = -EINVAL;
+
+       /*
+        * lock, so that our checking does not race with possible periodic
+        * bandwidth allocation through submitting new urbs.
+        */
+       spin_lock_irqsave(&fotg210->lock, flags);
+
+       /*
+        * for request to decrease max periodic bandwidth, we have to check
+        * every microframe in the schedule to see whether the decrease is
+        * possible.
+        */
+       if (uframe_periodic_max < fotg210->uframe_periodic_max) {
+               allocated_max = 0;
+
+               for (frame = 0; frame < fotg210->periodic_size; ++frame)
+                       for (uframe = 0; uframe < 7; ++uframe)
+                               allocated_max = max(allocated_max,
+                                                   periodic_usecs(fotg210, frame, uframe));
+
+               if (allocated_max > uframe_periodic_max) {
+                       fotg210_info(fotg210,
+                               "cannot decrease uframe_periodic_max becase "
+                               "periodic bandwidth is already allocated "
+                               "(%u > %u)\n",
+                               allocated_max, uframe_periodic_max);
+                       goto out_unlock;
+               }
+       }
+
+       /* increasing is always ok */
+
+       fotg210_info(fotg210, "setting max periodic bandwidth to %u%% (== %u usec/uframe)\n",
+                    100 * uframe_periodic_max/125, uframe_periodic_max);
+
+       if (uframe_periodic_max != 100)
+               fotg210_warn(fotg210, "max periodic bandwidth set is non-standard\n");
+
+       fotg210->uframe_periodic_max = uframe_periodic_max;
+       ret = count;
+
+out_unlock:
+       spin_unlock_irqrestore(&fotg210->lock, flags);
+       return ret;
+}
+
+static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max,
+                  store_uframe_periodic_max);
+
+static inline int create_sysfs_files(struct fotg210_hcd *fotg210)
+{
+       struct device   *controller = fotg210_to_hcd(fotg210)->self.controller;
+       int     i = 0;
+
+       if (i)
+               goto out;
+
+       i = device_create_file(controller, &dev_attr_uframe_periodic_max);
+out:
+       return i;
+}
+
+static inline void remove_sysfs_files(struct fotg210_hcd *fotg210)
+{
+       struct device   *controller = fotg210_to_hcd(fotg210)->self.controller;
+
+       device_remove_file(controller, &dev_attr_uframe_periodic_max);
+}
+/*-------------------------------------------------------------------------*/
+
+/* On some systems, leaving remote wakeup enabled prevents system shutdown.
+ * The firmware seems to think that powering off is a wakeup event!
+ * This routine turns off remote wakeup and everything else, on all ports.
+ */
+static void fotg210_turn_off_all_ports(struct fotg210_hcd *fotg210)
+{
+       u32 __iomem *status_reg = &fotg210->regs->port_status;
+
+       fotg210_writel(fotg210, PORT_RWC_BITS, status_reg);
+}
+
+/*
+ * Halt HC, turn off all ports, and let the BIOS use the companion controllers.
+ * Must be called with interrupts enabled and the lock not held.
+ */
+static void fotg210_silence_controller(struct fotg210_hcd *fotg210)
+{
+       fotg210_halt(fotg210);
+
+       spin_lock_irq(&fotg210->lock);
+       fotg210->rh_state = FOTG210_RH_HALTED;
+       fotg210_turn_off_all_ports(fotg210);
+       spin_unlock_irq(&fotg210->lock);
+}
+
+/* fotg210_shutdown kick in for silicon on any bus (not just pci, etc).
+ * This forcibly disables dma and IRQs, helping kexec and other cases
+ * where the next system software may expect clean state.
+ */
+static void fotg210_shutdown(struct usb_hcd *hcd)
+{
+       struct fotg210_hcd      *fotg210 = hcd_to_fotg210(hcd);
+
+       spin_lock_irq(&fotg210->lock);
+       fotg210->shutdown = true;
+       fotg210->rh_state = FOTG210_RH_STOPPING;
+       fotg210->enabled_hrtimer_events = 0;
+       spin_unlock_irq(&fotg210->lock);
+
+       fotg210_silence_controller(fotg210);
+
+       hrtimer_cancel(&fotg210->hrtimer);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * fotg210_work is called from some interrupts, timers, and so on.
+ * it calls driver completion functions, after dropping fotg210->lock.
+ */
+static void fotg210_work(struct fotg210_hcd *fotg210)
+{
+       /* another CPU may drop fotg210->lock during a schedule scan while
+        * it reports urb completions.  this flag guards against bogus
+        * attempts at re-entrant schedule scanning.
+        */
+       if (fotg210->scanning) {
+               fotg210->need_rescan = true;
+               return;
+       }
+       fotg210->scanning = true;
+
+ rescan:
+       fotg210->need_rescan = false;
+       if (fotg210->async_count)
+               scan_async(fotg210);
+       if (fotg210->intr_count > 0)
+               scan_intr(fotg210);
+       if (fotg210->isoc_count > 0)
+               scan_isoc(fotg210);
+       if (fotg210->need_rescan)
+               goto rescan;
+       fotg210->scanning = false;
+
+       /* the IO watchdog guards against hardware or driver bugs that
+        * misplace IRQs, and should let us run completely without IRQs.
+        * such lossage has been observed on both VT6202 and VT8235.
+        */
+       turn_on_io_watchdog(fotg210);
+}
+
+/*
+ * Called when the fotg210_hcd module is removed.
+ */
+static void fotg210_stop(struct usb_hcd *hcd)
+{
+       struct fotg210_hcd              *fotg210 = hcd_to_fotg210(hcd);
+
+       fotg210_dbg(fotg210, "stop\n");
+
+       /* no more interrupts ... */
+
+       spin_lock_irq(&fotg210->lock);
+       fotg210->enabled_hrtimer_events = 0;
+       spin_unlock_irq(&fotg210->lock);
+
+       fotg210_quiesce(fotg210);
+       fotg210_silence_controller(fotg210);
+       fotg210_reset(fotg210);
+
+       hrtimer_cancel(&fotg210->hrtimer);
+       remove_sysfs_files(fotg210);
+       remove_debug_files(fotg210);
+
+       /* root hub is shut down separately (first, when possible) */
+       spin_lock_irq(&fotg210->lock);
+       end_free_itds(fotg210);
+       spin_unlock_irq(&fotg210->lock);
+       fotg210_mem_cleanup(fotg210);
+
+#ifdef FOTG210_STATS
+       fotg210_dbg(fotg210, "irq normal %ld err %ld iaa %ld (lost %ld)\n",
+               fotg210->stats.normal, fotg210->stats.error, fotg210->stats.iaa,
+               fotg210->stats.lost_iaa);
+       fotg210_dbg(fotg210, "complete %ld unlink %ld\n",
+               fotg210->stats.complete, fotg210->stats.unlink);
+#endif
+
+       dbg_status(fotg210, "fotg210_stop completed",
+                   fotg210_readl(fotg210, &fotg210->regs->status));
+}
+
+/* one-time init, only for memory state */
+static int hcd_fotg210_init(struct usb_hcd *hcd)
+{
+       struct fotg210_hcd              *fotg210 = hcd_to_fotg210(hcd);
+       u32                     temp;
+       int                     retval;
+       u32                     hcc_params;
+       struct fotg210_qh_hw    *hw;
+
+       spin_lock_init(&fotg210->lock);
+
+       /*
+        * keep io watchdog by default, those good HCDs could turn off it later
+        */
+       fotg210->need_io_watchdog = 1;
+
+       hrtimer_init(&fotg210->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+       fotg210->hrtimer.function = fotg210_hrtimer_func;
+       fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT;
+
+       hcc_params = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
+
+       /*
+        * by default set standard 80% (== 100 usec/uframe) max periodic
+        * bandwidth as required by USB 2.0
+        */
+       fotg210->uframe_periodic_max = 100;
+
+       /*
+        * hw default: 1K periodic list heads, one per frame.
+        * periodic_size can shrink by USBCMD update if hcc_params allows.
+        */
+       fotg210->periodic_size = DEFAULT_I_TDPS;
+       INIT_LIST_HEAD(&fotg210->intr_qh_list);
+       INIT_LIST_HEAD(&fotg210->cached_itd_list);
+
+       if (HCC_PGM_FRAMELISTLEN(hcc_params)) {
+               /* periodic schedule size can be smaller than default */
+               switch (FOTG210_TUNE_FLS) {
+               case 0:
+                       fotg210->periodic_size = 1024;
+                       break;
+               case 1:
+                       fotg210->periodic_size = 512;
+                       break;
+               case 2:
+                       fotg210->periodic_size = 256;
+                       break;
+               default:
+                       BUG();
+               }
+       }
+       retval = fotg210_mem_init(fotg210, GFP_KERNEL);
+       if (retval < 0)
+               return retval;
+
+       /* controllers may cache some of the periodic schedule ... */
+       fotg210->i_thresh = 2;
+
+       /*
+        * 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
+        * as the 'reclamation list head' too.
+        * its dummy is used in hw_alt_next of many tds, to prevent the qh
+        * from automatically advancing to the next td after short reads.
+        */
+       fotg210->async->qh_next.qh = NULL;
+       hw = fotg210->async->hw;
+       hw->hw_next = QH_NEXT(fotg210, fotg210->async->qh_dma);
+       hw->hw_info1 = cpu_to_hc32(fotg210, QH_HEAD);
+       hw->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT);
+       hw->hw_qtd_next = FOTG210_LIST_END(fotg210);
+       fotg210->async->qh_state = QH_STATE_LINKED;
+       hw->hw_alt_next = QTD_NEXT(fotg210, fotg210->async->dummy->qtd_dma);
+
+       /* clear interrupt enables, set irq latency */
+       if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
+               log2_irq_thresh = 0;
+       temp = 1 << (16 + log2_irq_thresh);
+       if (HCC_CANPARK(hcc_params)) {
+               /* HW default park == 3, on hardware that supports it (like
+                * NVidia and ALI silicon), maximizes throughput on the async
+                * schedule by avoiding QH fetches between transfers.
+                *
+                * With fast usb storage devices and NForce2, "park" seems to
+                * make problems:  throughput reduction (!), data errors...
+                */
+               if (park) {
+                       park = min_t(unsigned, park, 3);
+                       temp |= CMD_PARK;
+                       temp |= park << 8;
+               }
+               fotg210_dbg(fotg210, "park %d\n", park);
+       }
+       if (HCC_PGM_FRAMELISTLEN(hcc_params)) {
+               /* periodic schedule size can be smaller than default */
+               temp &= ~(3 << 2);
+               temp |= (FOTG210_TUNE_FLS << 2);
+       }
+       fotg210->command = temp;
+
+       /* Accept arbitrarily long scatter-gather lists */
+       if (!(hcd->driver->flags & HCD_LOCAL_MEM))
+               hcd->self.sg_tablesize = ~0;
+       return 0;
+}
+
+/* start HC running; it's halted, hcd_fotg210_init() has been run (once) */
+static int fotg210_run(struct usb_hcd *hcd)
+{
+       struct fotg210_hcd              *fotg210 = hcd_to_fotg210(hcd);
+       u32                     temp;
+       u32                     hcc_params;
+
+       hcd->uses_new_polling = 1;
+
+       /* EHCI spec section 4.1 */
+
+       fotg210_writel(fotg210, fotg210->periodic_dma,
+                      &fotg210->regs->frame_list);
+       fotg210_writel(fotg210, (u32)fotg210->async->qh_dma,
+                      &fotg210->regs->async_next);
+
+       /*
+        * hcc_params controls whether fotg210->regs->segment must (!!!)
+        * be used; it constrains QH/ITD/SITD and QTD locations.
+        * pci_pool consistent memory always uses segment zero.
+        * streaming mappings for I/O buffers, like pci_map_single(),
+        * can return segments above 4GB, if the device allows.
+        *
+        * NOTE:  the dma mask is visible through dma_supported(), so
+        * drivers can pass this info along ... like NETIF_F_HIGHDMA,
+        * Scsi_Host.highmem_io, and so forth.  It's readonly to all
+        * host side drivers though.
+        */
+       hcc_params = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
+
+       /*
+        * Philips, Intel, and maybe others need CMD_RUN before the
+        * root hub will detect new devices (why?); NEC doesn't
+        */
+       fotg210->command &= ~(CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
+       fotg210->command |= CMD_RUN;
+       fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
+       dbg_cmd(fotg210, "init", fotg210->command);
+
+       /*
+        * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
+        * are explicitly handed to companion controller(s), so no TT is
+        * involved with the root hub.  (Except where one is integrated,
+        * and there's no companion controller unless maybe for USB OTG.)
+        *
+        * Turning on the CF flag will transfer ownership of all ports
+        * from the companions to the EHCI controller.  If any of the
+        * companions are in the middle of a port reset at the time, it
+        * could cause trouble.  Write-locking ehci_cf_port_reset_rwsem
+        * guarantees that no resets are in progress.  After we set CF,
+        * a short delay lets the hardware catch up; new resets shouldn't
+        * be started before the port switching actions could complete.
+        */
+       down_write(&ehci_cf_port_reset_rwsem);
+       fotg210->rh_state = FOTG210_RH_RUNNING;
+       /* unblock posted writes */
+       fotg210_readl(fotg210, &fotg210->regs->command);
+       msleep(5);
+       up_write(&ehci_cf_port_reset_rwsem);
+       fotg210->last_periodic_enable = ktime_get_real();
+
+       temp = HC_VERSION(fotg210,
+                         fotg210_readl(fotg210, &fotg210->caps->hc_capbase));
+       fotg210_info(fotg210,
+               "USB %x.%x started, EHCI %x.%02x\n",
+               ((fotg210->sbrn & 0xf0)>>4), (fotg210->sbrn & 0x0f),
+               temp >> 8, temp & 0xff);
+
+       fotg210_writel(fotg210, INTR_MASK,
+                   &fotg210->regs->intr_enable); /* Turn On Interrupts */
+
+       /* GRR this is run-once init(), being done every time the HC starts.
+        * So long as they're part of class devices, we can't do it init()
+        * since the class device isn't created that early.
+        */
+       create_debug_files(fotg210);
+       create_sysfs_files(fotg210);
+
+       return 0;
+}
+
+static int fotg210_setup(struct usb_hcd *hcd)
+{
+       struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
+       int retval;
+
+       fotg210->regs = (void __iomem *)fotg210->caps +
+           HC_LENGTH(fotg210,
+                     fotg210_readl(fotg210, &fotg210->caps->hc_capbase));
+       dbg_hcs_params(fotg210, "reset");
+       dbg_hcc_params(fotg210, "reset");
+
+       /* cache this readonly data; minimize chip reads */
+       fotg210->hcs_params = fotg210_readl(fotg210,
+                                           &fotg210->caps->hcs_params);
+
+       fotg210->sbrn = HCD_USB2;
+
+       /* data structure init */
+       retval = hcd_fotg210_init(hcd);
+       if (retval)
+               return retval;
+
+       retval = fotg210_halt(fotg210);
+       if (retval)
+               return retval;
+
+       fotg210_reset(fotg210);
+
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static irqreturn_t fotg210_irq(struct usb_hcd *hcd)
+{
+       struct fotg210_hcd              *fotg210 = hcd_to_fotg210(hcd);
+       u32                     status, masked_status, pcd_status = 0, cmd;
+       int                     bh;
+
+       spin_lock(&fotg210->lock);
+
+       status = fotg210_readl(fotg210, &fotg210->regs->status);
+
+       /* e.g. cardbus physical eject */
+       if (status == ~(u32) 0) {
+               fotg210_dbg(fotg210, "device removed\n");
+               goto dead;
+       }
+
+       /*
+        * We don't use STS_FLR, but some controllers don't like it to
+        * remain on, so mask it out along with the other status bits.
+        */
+       masked_status = status & (INTR_MASK | STS_FLR);
+
+       /* Shared IRQ? */
+       if (!masked_status ||
+           unlikely(fotg210->rh_state == FOTG210_RH_HALTED)) {
+               spin_unlock(&fotg210->lock);
+               return IRQ_NONE;
+       }
+
+       /* clear (just) interrupts */
+       fotg210_writel(fotg210, masked_status, &fotg210->regs->status);
+       cmd = fotg210_readl(fotg210, &fotg210->regs->command);
+       bh = 0;
+
+#ifdef VERBOSE_DEBUG
+       /* unrequested/ignored: Frame List Rollover */
+       dbg_status(fotg210, "irq", status);
+#endif
+
+       /* INT, ERR, and IAA interrupt rates can be throttled */
+
+       /* normal [4.15.1.2] or error [4.15.1.1] completion */
+       if (likely((status & (STS_INT|STS_ERR)) != 0)) {
+               if (likely((status & STS_ERR) == 0))
+                       COUNT(fotg210->stats.normal);
+               else
+                       COUNT(fotg210->stats.error);
+               bh = 1;
+       }
+
+       /* complete the unlinking of some qh [4.15.2.3] */
+       if (status & STS_IAA) {
+
+               /* Turn off the IAA watchdog */
+               fotg210->enabled_hrtimer_events &=
+                       ~BIT(FOTG210_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 (fotg210->next_hrtimer_event == FOTG210_HRTIMER_IAA_WATCHDOG)
+                       ++fotg210->next_hrtimer_event;
+
+               /* guard against (alleged) silicon errata */
+               if (cmd & CMD_IAAD)
+                       fotg210_dbg(fotg210, "IAA with IAAD still set?\n");
+               if (fotg210->async_iaa) {
+                       COUNT(fotg210->stats.iaa);
+                       end_unlink_async(fotg210);
+               } else
+                       fotg210_dbg(fotg210, "IAA with nothing unlinked?\n");
+       }
+
+       /* remote wakeup [4.3.1] */
+       if (status & STS_PCD) {
+               int pstatus;
+               u32 __iomem *status_reg = &fotg210->regs->port_status;
+
+               /* kick root hub later */
+               pcd_status = status;
+
+               /* resume root hub? */
+               if (fotg210->rh_state == FOTG210_RH_SUSPENDED)
+                       usb_hcd_resume_root_hub(hcd);
+
+               pstatus = fotg210_readl(fotg210, status_reg);
+
+               if (test_bit(0, &fotg210->suspended_ports) &&
+                               ((pstatus & PORT_RESUME) ||
+                                       !(pstatus & PORT_SUSPEND)) &&
+                               (pstatus & PORT_PE) &&
+                               fotg210->reset_done[0] == 0) {
+
+                       /* start 20 msec resume signaling from this port,
+                        * and make khubd collect PORT_STAT_C_SUSPEND to
+                        * stop that signaling.  Use 5 ms extra for safety,
+                        * like usb_port_resume() does.
+                        */
+                       fotg210->reset_done[0] = jiffies + msecs_to_jiffies(25);
+                       set_bit(0, &fotg210->resuming_ports);
+                       fotg210_dbg(fotg210, "port 1 remote wakeup\n");
+                       mod_timer(&hcd->rh_timer, fotg210->reset_done[0]);
+               }
+       }
+
+       /* PCI errors [4.15.2.4] */
+       if (unlikely((status & STS_FATAL) != 0)) {
+               fotg210_err(fotg210, "fatal error\n");
+               dbg_cmd(fotg210, "fatal", cmd);
+               dbg_status(fotg210, "fatal", status);
+dead:
+               usb_hc_died(hcd);
+
+               /* Don't let the controller do anything more */
+               fotg210->shutdown = true;
+               fotg210->rh_state = FOTG210_RH_STOPPING;
+               fotg210->command &= ~(CMD_RUN | CMD_ASE | CMD_PSE);
+               fotg210_writel(fotg210, fotg210->command,
+                              &fotg210->regs->command);
+               fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
+               fotg210_handle_controller_death(fotg210);
+
+               /* Handle completions when the controller stops */
+               bh = 0;
+       }
+
+       if (bh)
+               fotg210_work(fotg210);
+       spin_unlock(&fotg210->lock);
+       if (pcd_status)
+               usb_hcd_poll_rh_status(hcd);
+       return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * non-error returns are a promise to giveback() the urb later
+ * we drop ownership so next owner (or urb unlink) can get it
+ *
+ * urb + dev is in hcd.self.controller.urb_list
+ * we're queueing TDs onto software and hardware lists
+ *
+ * hcd-specific init for hcpriv hasn't been done yet
+ *
+ * NOTE:  control, bulk, and interrupt share the same code to append TDs
+ * to a (possibly active) QH, and the same QH scanning code.
+ */
+static int fotg210_urb_enqueue(
+       struct usb_hcd  *hcd,
+       struct urb      *urb,
+       gfp_t           mem_flags
+) {
+       struct fotg210_hcd              *fotg210 = hcd_to_fotg210(hcd);
+       struct list_head        qtd_list;
+
+       INIT_LIST_HEAD(&qtd_list);
+
+       switch (usb_pipetype(urb->pipe)) {
+       case PIPE_CONTROL:
+               /* qh_completions() code doesn't handle all the fault cases
+                * in multi-TD control transfers.  Even 1KB is rare anyway.
+                */
+               if (urb->transfer_buffer_length > (16 * 1024))
+                       return -EMSGSIZE;
+               /* FALLTHROUGH */
+       /* case PIPE_BULK: */
+       default:
+               if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags))
+                       return -ENOMEM;
+               return submit_async(fotg210, urb, &qtd_list, mem_flags);
+
+       case PIPE_INTERRUPT:
+               if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags))
+                       return -ENOMEM;
+               return intr_submit(fotg210, urb, &qtd_list, mem_flags);
+
+       case PIPE_ISOCHRONOUS:
+               return itd_submit(fotg210, urb, mem_flags);
+       }
+}
+
+/* remove from hardware lists
+ * completions normally happen asynchronously
+ */
+
+static int fotg210_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+       struct fotg210_hcd              *fotg210 = hcd_to_fotg210(hcd);
+       struct fotg210_qh               *qh;
+       unsigned long           flags;
+       int                     rc;
+
+       spin_lock_irqsave(&fotg210->lock, flags);
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (rc)
+               goto done;
+
+       switch (usb_pipetype(urb->pipe)) {
+       /* case PIPE_CONTROL: */
+       /* case PIPE_BULK:*/
+       default:
+               qh = (struct fotg210_qh *) urb->hcpriv;
+               if (!qh)
+                       break;
+               switch (qh->qh_state) {
+               case QH_STATE_LINKED:
+               case QH_STATE_COMPLETING:
+                       start_unlink_async(fotg210, qh);
+                       break;
+               case QH_STATE_UNLINK:
+               case QH_STATE_UNLINK_WAIT:
+                       /* already started */
+                       break;
+               case QH_STATE_IDLE:
+                       /* QH might be waiting for a Clear-TT-Buffer */
+                       qh_completions(fotg210, qh);
+                       break;
+               }
+               break;
+
+       case PIPE_INTERRUPT:
+               qh = (struct fotg210_qh *) urb->hcpriv;
+               if (!qh)
+                       break;
+               switch (qh->qh_state) {
+               case QH_STATE_LINKED:
+               case QH_STATE_COMPLETING:
+                       start_unlink_intr(fotg210, qh);
+                       break;
+               case QH_STATE_IDLE:
+                       qh_completions(fotg210, qh);
+                       break;
+               default:
+                       fotg210_dbg(fotg210, "bogus qh %p state %d\n",
+                                       qh, qh->qh_state);
+                       goto done;
+               }
+               break;
+
+       case PIPE_ISOCHRONOUS:
+               /* itd... */
+
+               /* wait till next completion, do it then. */
+               /* completion irqs can wait up to 1024 msec, */
+               break;
+       }
+done:
+       spin_unlock_irqrestore(&fotg210->lock, flags);
+       return rc;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* bulk qh holds the data toggle */
+
+static void
+fotg210_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+       struct fotg210_hcd              *fotg210 = hcd_to_fotg210(hcd);
+       unsigned long           flags;
+       struct fotg210_qh               *qh, *tmp;
+
+       /* ASSERT:  any requests/urbs are being unlinked */
+       /* ASSERT:  nobody can be submitting urbs for this any more */
+
+rescan:
+       spin_lock_irqsave(&fotg210->lock, flags);
+       qh = ep->hcpriv;
+       if (!qh)
+               goto done;
+
+       /* endpoints can be iso streams.  for now, we don't
+        * accelerate iso completions ... so spin a while.
+        */
+       if (qh->hw == NULL) {
+               struct fotg210_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 (fotg210->rh_state < FOTG210_RH_RUNNING)
+               qh->qh_state = QH_STATE_IDLE;
+       switch (qh->qh_state) {
+       case QH_STATE_LINKED:
+       case QH_STATE_COMPLETING:
+               for (tmp = fotg210->async->qh_next.qh;
+                               tmp && tmp != qh;
+                               tmp = tmp->qh_next.qh)
+                       continue;
+               /* periodic qh self-unlinks on empty, and a COMPLETING qh
+                * may already be unlinked.
+                */
+               if (tmp)
+                       start_unlink_async(fotg210, qh);
+               /* FALL THROUGH */
+       case QH_STATE_UNLINK:           /* wait for hw to finish? */
+       case QH_STATE_UNLINK_WAIT:
+idle_timeout:
+               spin_unlock_irqrestore(&fotg210->lock, flags);
+               schedule_timeout_uninterruptible(1);
+               goto rescan;
+       case QH_STATE_IDLE:             /* fully unlinked */
+               if (qh->clearing_tt)
+                       goto idle_timeout;
+               if (list_empty(&qh->qtd_list)) {
+                       qh_destroy(fotg210, qh);
+                       break;
+               }
+               /* else FALL THROUGH */
+       default:
+               /* caller was supposed to have unlinked any requests;
+                * that's not our job.  just leak this memory.
+                */
+               fotg210_err(fotg210, "qh %p (#%02x) state %d%s\n",
+                       qh, ep->desc.bEndpointAddress, qh->qh_state,
+                       list_empty(&qh->qtd_list) ? "" : "(has tds)");
+               break;
+       }
+ done:
+       ep->hcpriv = NULL;
+       spin_unlock_irqrestore(&fotg210->lock, flags);
+}
+
+static void
+fotg210_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+       struct fotg210_hcd              *fotg210 = hcd_to_fotg210(hcd);
+       struct fotg210_qh               *qh;
+       int                     eptype = usb_endpoint_type(&ep->desc);
+       int                     epnum = usb_endpoint_num(&ep->desc);
+       int                     is_out = usb_endpoint_dir_out(&ep->desc);
+       unsigned long           flags;
+
+       if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT)
+               return;
+
+       spin_lock_irqsave(&fotg210->lock, flags);
+       qh = ep->hcpriv;
+
+       /* For Bulk and Interrupt endpoints we maintain the toggle state
+        * in the hardware; the toggle bits in udev aren't used at all.
+        * When an endpoint is reset by usb_clear_halt() we must reset
+        * the toggle bit in the QH.
+        */
+       if (qh) {
+               usb_settoggle(qh->dev, epnum, is_out, 0);
+               if (!list_empty(&qh->qtd_list)) {
+                       WARN_ONCE(1, "clear_halt for a busy endpoint\n");
+               } else if (qh->qh_state == QH_STATE_LINKED ||
+                               qh->qh_state == QH_STATE_COMPLETING) {
+
+                       /* The toggle value in the QH can't be updated
+                        * while the QH is active.  Unlink it now;
+                        * re-linking will call qh_refresh().
+                        */
+                       if (eptype == USB_ENDPOINT_XFER_BULK)
+                               start_unlink_async(fotg210, qh);
+                       else
+                               start_unlink_intr(fotg210, qh);
+               }
+       }
+       spin_unlock_irqrestore(&fotg210->lock, flags);
+}
+
+static int fotg210_get_frame(struct usb_hcd *hcd)
+{
+       struct fotg210_hcd              *fotg210 = hcd_to_fotg210(hcd);
+       return (fotg210_read_frame_index(fotg210) >> 3) %
+               fotg210->periodic_size;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * The EHCI in ChipIdea HDRC cannot be a separate module or device,
+ * because its registers (and irq) are shared between host/gadget/otg
+ * functions  and in order to facilitate role switching we cannot
+ * give the fotg210 driver exclusive access to those.
+ */
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+
+static const struct hc_driver fotg210_fotg210_hc_driver = {
+       .description            = hcd_name,
+       .product_desc           = "Faraday USB2.0 Host Controller",
+       .hcd_priv_size          = sizeof(struct fotg210_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq                    = fotg210_irq,
+       .flags                  = HCD_MEMORY | HCD_USB2,
+
+       /*
+        * basic lifecycle operations
+        */
+       .reset                  = hcd_fotg210_init,
+       .start                  = fotg210_run,
+       .stop                   = fotg210_stop,
+       .shutdown               = fotg210_shutdown,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue            = fotg210_urb_enqueue,
+       .urb_dequeue            = fotg210_urb_dequeue,
+       .endpoint_disable       = fotg210_endpoint_disable,
+       .endpoint_reset         = fotg210_endpoint_reset,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number       = fotg210_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data        = fotg210_hub_status_data,
+       .hub_control            = fotg210_hub_control,
+       .bus_suspend            = fotg210_bus_suspend,
+       .bus_resume             = fotg210_bus_resume,
+
+       .relinquish_port        = fotg210_relinquish_port,
+       .port_handed_over       = fotg210_port_handed_over,
+
+       .clear_tt_buffer_complete = fotg210_clear_tt_buffer_complete,
+};
+
+static void fotg210_init(struct fotg210_hcd *fotg210)
+{
+       u32 value;
+
+       iowrite32(GMIR_MDEV_INT | GMIR_MOTG_INT | GMIR_INT_POLARITY,
+                 &fotg210->regs->gmir);
+
+       value = ioread32(&fotg210->regs->otgcsr);
+       value &= ~OTGCSR_A_BUS_DROP;
+       value |= OTGCSR_A_BUS_REQ;
+       iowrite32(value, &fotg210->regs->otgcsr);
+}
+
+/**
+ * fotg210_hcd_probe - initialize faraday FOTG210 HCDs
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ */
+static int fotg210_hcd_probe(struct platform_device *pdev)
+{
+       struct device                   *dev = &pdev->dev;
+       struct usb_hcd                  *hcd;
+       struct resource                 *res;
+       int                             irq;
+       int                             retval = -ENODEV;
+       struct fotg210_hcd              *fotg210;
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       pdev->dev.power.power_state = PMSG_ON;
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res) {
+               dev_err(dev,
+                       "Found HC with no IRQ. Check %s setup!\n",
+                       dev_name(dev));
+               return -ENODEV;
+       }
+
+       irq = res->start;
+
+       hcd = usb_create_hcd(&fotg210_fotg210_hc_driver, dev,
+                       dev_name(dev));
+       if (!hcd) {
+               dev_err(dev, "failed to create hcd with err %d\n", retval);
+               retval = -ENOMEM;
+               goto fail_create_hcd;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev,
+                       "Found HC with no register addr. Check %s setup!\n",
+                       dev_name(dev));
+               retval = -ENODEV;
+               goto fail_request_resource;
+       }
+
+       hcd->rsrc_start = res->start;
+       hcd->rsrc_len = resource_size(res);
+       hcd->has_tt = 1;
+
+       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+                               fotg210_fotg210_hc_driver.description)) {
+               dev_dbg(dev, "controller already in use\n");
+               retval = -EBUSY;
+               goto fail_request_resource;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (!res) {
+               dev_err(dev,
+                       "Found HC with no register addr. Check %s setup!\n",
+                       dev_name(dev));
+               retval = -ENODEV;
+               goto fail_request_resource;
+       }
+
+       hcd->regs = ioremap_nocache(res->start, resource_size(res));
+       if (hcd->regs == NULL) {
+               dev_dbg(dev, "error mapping memory\n");
+               retval = -EFAULT;
+               goto fail_ioremap;
+       }
+
+       fotg210 = hcd_to_fotg210(hcd);
+
+       fotg210->caps = hcd->regs;
+
+       retval = fotg210_setup(hcd);
+       if (retval)
+               goto fail_add_hcd;
+
+       fotg210_init(fotg210);
+
+       retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
+       if (retval) {
+               dev_err(dev, "failed to add hcd with err %d\n", retval);
+               goto fail_add_hcd;
+       }
+
+       return retval;
+
+fail_add_hcd:
+       iounmap(hcd->regs);
+fail_ioremap:
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+fail_request_resource:
+       usb_put_hcd(hcd);
+fail_create_hcd:
+       dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval);
+       return retval;
+}
+
+/**
+ * fotg210_hcd_remove - shutdown processing for EHCI HCDs
+ * @dev: USB Host Controller being removed
+ *
+ */
+static int fotg210_hcd_remove(struct platform_device *pdev)
+{
+       struct device *dev      = &pdev->dev;
+       struct usb_hcd *hcd     = dev_get_drvdata(dev);
+
+       if (!hcd)
+               return 0;
+
+       usb_remove_hcd(hcd);
+       iounmap(hcd->regs);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+       usb_put_hcd(hcd);
+
+       return 0;
+}
+
+static struct platform_driver fotg210_hcd_driver = {
+       .driver = {
+               .name   = "fotg210-hcd",
+       },
+       .probe  = fotg210_hcd_probe,
+       .remove = fotg210_hcd_remove,
+};
+
+static int __init fotg210_hcd_init(void)
+{
+       int retval = 0;
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
+       set_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
+       if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) ||
+                       test_bit(USB_OHCI_LOADED, &usb_hcds_loaded))
+               pr_warn(KERN_WARNING "Warning! fotg210_hcd should always be loaded before uhci_hcd and ohci_hcd, not after\n");
+
+       pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd\n",
+                hcd_name,
+                sizeof(struct fotg210_qh), sizeof(struct fotg210_qtd),
+                sizeof(struct fotg210_itd));
+
+#ifdef DEBUG
+       fotg210_debug_root = debugfs_create_dir("fotg210", usb_debug_root);
+       if (!fotg210_debug_root) {
+               retval = -ENOENT;
+               goto err_debug;
+       }
+#endif
+
+       retval = platform_driver_register(&fotg210_hcd_driver);
+       if (retval < 0)
+               goto clean;
+       return retval;
+
+       platform_driver_unregister(&fotg210_hcd_driver);
+clean:
+#ifdef DEBUG
+       debugfs_remove(fotg210_debug_root);
+       fotg210_debug_root = NULL;
+err_debug:
+#endif
+       clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
+       return retval;
+}
+module_init(fotg210_hcd_init);
+
+static void __exit fotg210_hcd_cleanup(void)
+{
+       platform_driver_unregister(&fotg210_hcd_driver);
+#ifdef DEBUG
+       debugfs_remove(fotg210_debug_root);
+#endif
+       clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
+}
+module_exit(fotg210_hcd_cleanup);
diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h
new file mode 100644 (file)
index 0000000..8920f9d
--- /dev/null
@@ -0,0 +1,750 @@
+#ifndef __LINUX_FOTG210_H
+#define __LINUX_FOTG210_H
+
+/* definitions used for the EHCI driver */
+
+/*
+ * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
+ * __leXX (normally) or __beXX (given FOTG210_BIG_ENDIAN_DESC), depending on
+ * the host controller implementation.
+ *
+ * To facilitate the strongest possible byte-order checking from "sparse"
+ * and so on, we use __leXX unless that's not practical.
+ */
+#define __hc32 __le32
+#define __hc16 __le16
+
+/* statistics can be kept for tuning/monitoring */
+struct fotg210_stats {
+       /* irq usage */
+       unsigned long           normal;
+       unsigned long           error;
+       unsigned long           iaa;
+       unsigned long           lost_iaa;
+
+       /* termination of urbs from core */
+       unsigned long           complete;
+       unsigned long           unlink;
+};
+
+/* fotg210_hcd->lock guards shared data against other CPUs:
+ *   fotg210_hcd:      async, unlink, periodic (and shadow), ...
+ *   usb_host_endpoint: hcpriv
+ *   fotg210_qh:       qh_next, qtd_list
+ *   fotg210_qtd:      qtd_list
+ *
+ * Also, hold this lock when talking to HC registers or
+ * when updating hw_* fields in shared qh/qtd/... structures.
+ */
+
+#define        FOTG210_MAX_ROOT_PORTS  1               /* see HCS_N_PORTS */
+
+/*
+ * fotg210_rh_state values of FOTG210_RH_RUNNING or above mean that the
+ * controller may be doing DMA.  Lower values mean there's no DMA.
+ */
+enum fotg210_rh_state {
+       FOTG210_RH_HALTED,
+       FOTG210_RH_SUSPENDED,
+       FOTG210_RH_RUNNING,
+       FOTG210_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 fotg210_hrtimer_event {
+       FOTG210_HRTIMER_POLL_ASS,       /* Poll for async schedule off */
+       FOTG210_HRTIMER_POLL_PSS,       /* Poll for periodic schedule off */
+       FOTG210_HRTIMER_POLL_DEAD,      /* Wait for dead controller to stop */
+       FOTG210_HRTIMER_UNLINK_INTR,    /* Wait for interrupt QH unlink */
+       FOTG210_HRTIMER_FREE_ITDS,      /* Wait for unused iTDs and siTDs */
+       FOTG210_HRTIMER_ASYNC_UNLINKS,  /* Unlink empty async QHs */
+       FOTG210_HRTIMER_IAA_WATCHDOG,   /* Handle lost IAA interrupts */
+       FOTG210_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */
+       FOTG210_HRTIMER_DISABLE_ASYNC,  /* Wait to disable async sched */
+       FOTG210_HRTIMER_IO_WATCHDOG,    /* Check for missing IRQs */
+       FOTG210_HRTIMER_NUM_EVENTS      /* Must come last */
+};
+#define FOTG210_HRTIMER_NO_EVENT       99
+
+struct fotg210_hcd {                   /* one per controller */
+       /* timing support */
+       enum fotg210_hrtimer_event      next_hrtimer_event;
+       unsigned                enabled_hrtimer_events;
+       ktime_t                 hr_timeouts[FOTG210_HRTIMER_NUM_EVENTS];
+       struct hrtimer          hrtimer;
+
+       int                     PSS_poll_count;
+       int                     ASS_poll_count;
+       int                     died_poll_count;
+
+       /* glue to PCI and HCD framework */
+       struct fotg210_caps __iomem *caps;
+       struct fotg210_regs __iomem *regs;
+       struct fotg210_dbg_port __iomem *debug;
+
+       __u32                   hcs_params;     /* cached register copy */
+       spinlock_t              lock;
+       enum fotg210_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 fotg210_qh               *qh_scan_next;
+
+       /* async schedule support */
+       struct fotg210_qh               *async;
+       struct fotg210_qh               *dummy;         /* For AMD quirk use */
+       struct fotg210_qh               *async_unlink;
+       struct fotg210_qh               *async_unlink_last;
+       struct fotg210_qh               *async_iaa;
+       unsigned                async_unlink_cycle;
+       unsigned                async_count;    /* async activity count */
+
+       /* periodic schedule support */
+#define        DEFAULT_I_TDPS          1024            /* some HCs can do less */
+       unsigned                periodic_size;
+       __hc32                  *periodic;      /* hw periodic table */
+       dma_addr_t              periodic_dma;
+       struct list_head        intr_qh_list;
+       unsigned                i_thresh;       /* uframes HC might cache */
+
+       union fotg210_shadow    *pshadow;       /* mirror hw periodic table */
+       struct fotg210_qh               *intr_unlink;
+       struct fotg210_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 */
+       /* max periodic time per uframe */
+       unsigned                uframe_periodic_max;
+
+
+       /* list of itds completed while now_frame was still active */
+       struct list_head        cached_itd_list;
+       struct fotg210_itd      *last_itd_to_free;
+
+       /* per root hub port */
+       unsigned long           reset_done[FOTG210_MAX_ROOT_PORTS];
+
+       /* bit vectors (one bit per port) */
+       unsigned long           bus_suspended;          /* which ports were
+                       already suspended at the start of a bus suspend */
+       unsigned long           companion_ports;        /* which ports are
+                       dedicated to the companion controller */
+       unsigned long           owned_ports;            /* which ports are
+                       owned by the companion during a bus suspend */
+       unsigned long           port_c_suspend;         /* which ports have
+                       the change-suspend feature turned on */
+       unsigned long           suspended_ports;        /* which ports are
+                       suspended */
+       unsigned long           resuming_ports;         /* which ports have
+                       started to resume */
+
+       /* per-HC memory pools (could be per-bus, but ...) */
+       struct dma_pool         *qh_pool;       /* qh per active urb */
+       struct dma_pool         *qtd_pool;      /* one or more per qh */
+       struct dma_pool         *itd_pool;      /* itd per iso urb */
+
+       unsigned                random_frame;
+       unsigned long           next_statechange;
+       ktime_t                 last_periodic_enable;
+       u32                     command;
+
+       /* SILICON QUIRKS */
+       unsigned                need_io_watchdog:1;
+       unsigned                fs_i_thresh:1;  /* Intel iso scheduling */
+
+       u8                      sbrn;           /* packed release number */
+
+       /* irq statistics */
+#ifdef FOTG210_STATS
+       struct fotg210_stats    stats;
+#      define COUNT(x) ((x)++)
+#else
+#      define COUNT(x)
+#endif
+
+       /* debug files */
+#ifdef DEBUG
+       struct dentry           *debug_dir;
+#endif
+};
+
+/* convert between an HCD pointer and the corresponding FOTG210_HCD */
+static inline struct fotg210_hcd *hcd_to_fotg210(struct usb_hcd *hcd)
+{
+       return (struct fotg210_hcd *)(hcd->hcd_priv);
+}
+static inline struct usb_hcd *fotg210_to_hcd(struct fotg210_hcd *fotg210)
+{
+       return container_of((void *) fotg210, struct usb_hcd, hcd_priv);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
+
+/* Section 2.2 Host Controller Capability Registers */
+struct fotg210_caps {
+       /* these fields are specified as 8 and 16 bit registers,
+        * but some hosts can't perform 8 or 16 bit PCI accesses.
+        * some hosts treat caplength and hciversion as parts of a 32-bit
+        * register, others treat them as two separate registers, this
+        * affects the memory map for big endian controllers.
+        */
+       u32             hc_capbase;
+#define HC_LENGTH(fotg210, p)  (0x00ff&((p) >> /* bits 7:0 / offset 00h */ \
+                               (fotg210_big_endian_capbase(fotg210) ? 24 : 0)))
+#define HC_VERSION(fotg210, p) (0xffff&((p) >> /* bits 31:16 / offset 02h */ \
+                               (fotg210_big_endian_capbase(fotg210) ? 0 : 16)))
+       u32             hcs_params;     /* HCSPARAMS - offset 0x4 */
+#define HCS_N_PORTS(p)         (((p)>>0)&0xf)  /* bits 3:0, ports on HC */
+
+       u32             hcc_params;     /* HCCPARAMS - offset 0x8 */
+#define HCC_CANPARK(p)         ((p)&(1 << 2))  /* true: can park on async qh */
+#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1))  /* true: periodic_size changes*/
+       u8              portroute[8];    /* nibbles for routing - offset 0xC */
+};
+
+
+/* Section 2.3 Host Controller Operational Registers */
+struct fotg210_regs {
+
+       /* USBCMD: offset 0x00 */
+       u32             command;
+
+/* EHCI 1.1 addendum */
+/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
+#define CMD_PARK       (1<<11)         /* enable "park" on async qh */
+#define CMD_PARK_CNT(c)        (((c)>>8)&3)    /* how many transfers to park for */
+#define CMD_IAAD       (1<<6)          /* "doorbell" interrupt async advance */
+#define CMD_ASE                (1<<5)          /* async schedule enable */
+#define CMD_PSE                (1<<4)          /* periodic schedule enable */
+/* 3:2 is periodic frame list size */
+#define CMD_RESET      (1<<1)          /* reset HC not bus */
+#define CMD_RUN                (1<<0)          /* start/stop HC */
+
+       /* USBSTS: offset 0x04 */
+       u32             status;
+#define STS_ASS                (1<<15)         /* Async Schedule Status */
+#define STS_PSS                (1<<14)         /* Periodic Schedule Status */
+#define STS_RECL       (1<<13)         /* Reclamation */
+#define STS_HALT       (1<<12)         /* Not running (any reason) */
+/* some bits reserved */
+       /* these STS_* flags are also intr_enable bits (USBINTR) */
+#define STS_IAA                (1<<5)          /* Interrupted on async advance */
+#define STS_FATAL      (1<<4)          /* such as some PCI access errors */
+#define STS_FLR                (1<<3)          /* frame list rolled over */
+#define STS_PCD                (1<<2)          /* port change detect */
+#define STS_ERR                (1<<1)          /* "error" completion (overflow, ...) */
+#define STS_INT                (1<<0)          /* "normal" completion (short, ...) */
+
+       /* USBINTR: offset 0x08 */
+       u32             intr_enable;
+
+       /* FRINDEX: offset 0x0C */
+       u32             frame_index;    /* current microframe number */
+       /* CTRLDSSEGMENT: offset 0x10 */
+       u32             segment;        /* address bits 63:32 if needed */
+       /* PERIODICLISTBASE: offset 0x14 */
+       u32             frame_list;     /* points to periodic list */
+       /* ASYNCLISTADDR: offset 0x18 */
+       u32             async_next;     /* address of next async queue head */
+
+       u32     reserved1;
+       /* PORTSC: offset 0x20 */
+       u32     port_status;
+/* 31:23 reserved */
+#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10))       /* USB 1.1 device */
+#define PORT_RESET     (1<<8)          /* reset port */
+#define PORT_SUSPEND   (1<<7)          /* suspend port */
+#define PORT_RESUME    (1<<6)          /* resume it */
+#define PORT_PEC       (1<<3)          /* port enable change */
+#define PORT_PE                (1<<2)          /* port enable */
+#define PORT_CSC       (1<<1)          /* connect status change */
+#define PORT_CONNECT   (1<<0)          /* device connected */
+#define PORT_RWC_BITS   (PORT_CSC | PORT_PEC)
+       u32     reserved2[19];
+
+       /* OTGCSR: offet 0x70 */
+       u32     otgcsr;
+#define OTGCSR_HOST_SPD_TYP     (3 << 22)
+#define OTGCSR_A_BUS_DROP      (1 << 5)
+#define OTGCSR_A_BUS_REQ       (1 << 4)
+
+       /* OTGISR: offset 0x74 */
+       u32     otgisr;
+#define OTGISR_OVC     (1 << 10)
+
+       u32     reserved3[15];
+
+       /* GMIR: offset 0xB4 */
+       u32     gmir;
+#define GMIR_INT_POLARITY      (1 << 3) /*Active High*/
+#define GMIR_MHC_INT           (1 << 2)
+#define GMIR_MOTG_INT          (1 << 1)
+#define GMIR_MDEV_INT  (1 << 0)
+};
+
+/* Appendix C, Debug port ... intended for use with special "debug devices"
+ * that can help if there's no serial console.  (nonstandard enumeration.)
+ */
+struct fotg210_dbg_port {
+       u32     control;
+#define DBGP_OWNER     (1<<30)
+#define DBGP_ENABLED   (1<<28)
+#define DBGP_DONE      (1<<16)
+#define DBGP_INUSE     (1<<10)
+#define DBGP_ERRCODE(x)        (((x)>>7)&0x07)
+#      define DBGP_ERR_BAD     1
+#      define DBGP_ERR_SIGNAL  2
+#define DBGP_ERROR     (1<<6)
+#define DBGP_GO                (1<<5)
+#define DBGP_OUT       (1<<4)
+#define DBGP_LEN(x)    (((x)>>0)&0x0f)
+       u32     pids;
+#define DBGP_PID_GET(x)                (((x)>>16)&0xff)
+#define DBGP_PID_SET(data, tok)        (((data)<<8)|(tok))
+       u32     data03;
+       u32     data47;
+       u32     address;
+#define DBGP_EPADDR(dev, ep)   (((dev)<<8)|(ep))
+};
+
+#ifdef CONFIG_EARLY_PRINTK_DBGP
+#include <linux/init.h>
+extern int __init early_dbgp_init(char *s);
+extern struct console early_dbgp_console;
+#endif /* CONFIG_EARLY_PRINTK_DBGP */
+
+struct usb_hcd;
+
+static inline int xen_dbgp_reset_prep(struct usb_hcd *hcd)
+{
+       return 1; /* Shouldn't this be 0? */
+}
+
+static inline int xen_dbgp_external_startup(struct usb_hcd *hcd)
+{
+       return -1;
+}
+
+#ifdef CONFIG_EARLY_PRINTK_DBGP
+/* Call backs from fotg210 host driver to fotg210 debug driver */
+extern int dbgp_external_startup(struct usb_hcd *);
+extern int dbgp_reset_prep(struct usb_hcd *hcd);
+#else
+static inline int dbgp_reset_prep(struct usb_hcd *hcd)
+{
+       return xen_dbgp_reset_prep(hcd);
+}
+static inline int dbgp_external_startup(struct usb_hcd *hcd)
+{
+       return xen_dbgp_external_startup(hcd);
+}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#define        QTD_NEXT(fotg210, dma)  cpu_to_hc32(fotg210, (u32)dma)
+
+/*
+ * EHCI Specification 0.95 Section 3.5
+ * QTD: describe data transfer components (buffer, direction, ...)
+ * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
+ *
+ * These are associated only with "QH" (Queue Head) structures,
+ * used with control, bulk, and interrupt transfers.
+ */
+struct fotg210_qtd {
+       /* first part defined by EHCI spec */
+       __hc32                  hw_next;        /* see EHCI 3.5.1 */
+       __hc32                  hw_alt_next;    /* see EHCI 3.5.2 */
+       __hc32                  hw_token;       /* see EHCI 3.5.3 */
+#define        QTD_TOGGLE      (1 << 31)       /* data toggle */
+#define        QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
+#define        QTD_IOC         (1 << 15)       /* interrupt on complete */
+#define        QTD_CERR(tok)   (((tok)>>10) & 0x3)
+#define        QTD_PID(tok)    (((tok)>>8) & 0x3)
+#define        QTD_STS_ACTIVE  (1 << 7)        /* HC may execute this */
+#define        QTD_STS_HALT    (1 << 6)        /* halted on error */
+#define        QTD_STS_DBE     (1 << 5)        /* data buffer error (in HC) */
+#define        QTD_STS_BABBLE  (1 << 4)        /* device was babbling (qtd halted) */
+#define        QTD_STS_XACT    (1 << 3)        /* device gave illegal response */
+#define        QTD_STS_MMF     (1 << 2)        /* incomplete split transaction */
+#define        QTD_STS_STS     (1 << 1)        /* split transaction state */
+#define        QTD_STS_PING    (1 << 0)        /* issue PING? */
+
+#define ACTIVE_BIT(fotg210)    cpu_to_hc32(fotg210, QTD_STS_ACTIVE)
+#define HALT_BIT(fotg210)              cpu_to_hc32(fotg210, QTD_STS_HALT)
+#define STATUS_BIT(fotg210)    cpu_to_hc32(fotg210, QTD_STS_STS)
+
+       __hc32                  hw_buf[5];      /* see EHCI 3.5.4 */
+       __hc32                  hw_buf_hi[5];   /* Appendix B */
+
+       /* the rest is HCD-private */
+       dma_addr_t              qtd_dma;                /* qtd address */
+       struct list_head        qtd_list;               /* sw qtd list */
+       struct urb              *urb;                   /* qtd's urb */
+       size_t                  length;                 /* length of buffer */
+} __aligned(32);
+
+/* mask NakCnt+T in qh->hw_alt_next */
+#define QTD_MASK(fotg210)      cpu_to_hc32(fotg210, ~0x1f)
+
+#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1)
+
+/*-------------------------------------------------------------------------*/
+
+/* type tag from {qh,itd,fstn}->hw_next */
+#define Q_NEXT_TYPE(fotg210, dma)      ((dma) & cpu_to_hc32(fotg210, 3 << 1))
+
+/*
+ * Now the following defines are not converted using the
+ * cpu_to_le32() macro anymore, since we have to support
+ * "dynamic" switching between be and le support, so that the driver
+ * can be used on one system with SoC EHCI controller using big-endian
+ * descriptors as well as a normal little-endian PCI EHCI controller.
+ */
+/* values for that type tag */
+#define Q_TYPE_ITD     (0 << 1)
+#define Q_TYPE_QH      (1 << 1)
+#define Q_TYPE_SITD    (2 << 1)
+#define Q_TYPE_FSTN    (3 << 1)
+
+/* next async queue entry, or pointer to interrupt/periodic QH */
+#define QH_NEXT(fotg210, dma) \
+       (cpu_to_hc32(fotg210, (((u32)dma)&~0x01f)|Q_TYPE_QH))
+
+/* for periodic/async schedules and qtd lists, mark end of list */
+#define FOTG210_LIST_END(fotg210) \
+       cpu_to_hc32(fotg210, 1) /* "null pointer" to hw */
+
+/*
+ * Entries in periodic shadow table are pointers to one of four kinds
+ * of data structure.  That's dictated by the hardware; a type tag is
+ * encoded in the low bits of the hardware's periodic schedule.  Use
+ * Q_NEXT_TYPE to get the tag.
+ *
+ * For entries in the async schedule, the type tag always says "qh".
+ */
+union fotg210_shadow {
+       struct fotg210_qh       *qh;            /* Q_TYPE_QH */
+       struct fotg210_itd      *itd;           /* Q_TYPE_ITD */
+       struct fotg210_fstn     *fstn;          /* Q_TYPE_FSTN */
+       __hc32                  *hw_next;       /* (all types) */
+       void                    *ptr;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.6
+ * QH: describes control/bulk/interrupt endpoints
+ * See Fig 3-7 "Queue Head Structure Layout".
+ *
+ * These appear in both the async and (for interrupt) periodic schedules.
+ */
+
+/* first part defined by EHCI spec */
+struct fotg210_qh_hw {
+       __hc32                  hw_next;        /* see EHCI 3.6.1 */
+       __hc32                  hw_info1;       /* see EHCI 3.6.2 */
+#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 */
+#define        QH_SMASK        0x000000ff
+#define        QH_CMASK        0x0000ff00
+#define        QH_HUBADDR      0x007f0000
+#define        QH_HUBPORT      0x3f800000
+#define        QH_MULT         0xc0000000
+       __hc32                  hw_current;     /* qtd list - see EHCI 3.6.4 */
+
+       /* qtd overlay (hardware parts of a struct fotg210_qtd) */
+       __hc32                  hw_qtd_next;
+       __hc32                  hw_alt_next;
+       __hc32                  hw_token;
+       __hc32                  hw_buf[5];
+       __hc32                  hw_buf_hi[5];
+} __aligned(32);
+
+struct fotg210_qh {
+       struct fotg210_qh_hw    *hw;            /* Must come first */
+       /* the rest is HCD-private */
+       dma_addr_t              qh_dma;         /* address of qh */
+       union fotg210_shadow    qh_next;        /* ptr to qh; or periodic */
+       struct list_head        qtd_list;       /* sw qtd list */
+       struct list_head        intr_node;      /* list of intr QHs */
+       struct fotg210_qtd      *dummy;
+       struct fotg210_qh       *unlink_next;   /* next on unlink list */
+
+       unsigned                unlink_cycle;
+
+       u8                      needs_rescan;   /* Dequeue during giveback */
+       u8                      qh_state;
+#define        QH_STATE_LINKED         1               /* HC sees this */
+#define        QH_STATE_UNLINK         2               /* HC may still see this */
+#define        QH_STATE_IDLE           3               /* HC doesn't see this */
+#define        QH_STATE_UNLINK_WAIT    4               /* LINKED and on unlink q */
+#define        QH_STATE_COMPLETING     5               /* don't touch token.HALT */
+
+       u8                      xacterrs;       /* XactErr retry counter */
+#define        QH_XACTERR_MAX          32              /* XactErr retry limit */
+
+       /* periodic schedule info */
+       u8                      usecs;          /* intr bandwidth */
+       u8                      gap_uf;         /* uframes split/csplit gap */
+       u8                      c_usecs;        /* ... split completion bw */
+       u16                     tt_usecs;       /* tt downstream bandwidth */
+       unsigned short          period;         /* polling interval */
+       unsigned short          start;          /* where polling starts */
+#define NO_FRAME ((unsigned short)~0)                  /* pick new start */
+
+       struct usb_device       *dev;           /* access to TT */
+       unsigned                is_out:1;       /* bulk or intr OUT */
+       unsigned                clearing_tt:1;  /* Clear-TT-Buf in progress */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* description of one iso transaction (up to 3 KB data if highspeed) */
+struct fotg210_iso_packet {
+       /* These will be copied to iTD when scheduling */
+       u64                     bufp;           /* itd->hw_bufp{,_hi}[pg] |= */
+       __hc32                  transaction;    /* itd->hw_transaction[i] |= */
+       u8                      cross;          /* buf crosses pages */
+       /* for full speed OUT splits */
+       u32                     buf1;
+};
+
+/* temporary schedule data for packets from iso urbs (both speeds)
+ * each packet is one logical usb transaction to the device (not TT),
+ * beginning at stream->next_uframe
+ */
+struct fotg210_iso_sched {
+       struct list_head        td_list;
+       unsigned                span;
+       struct fotg210_iso_packet       packet[0];
+};
+
+/*
+ * fotg210_iso_stream - groups all (s)itds for this endpoint.
+ * acts like a qh would, if EHCI had them for ISO.
+ */
+struct fotg210_iso_stream {
+       /* first field matches fotg210_hq, but is NULL */
+       struct fotg210_qh_hw    *hw;
+
+       u8                      bEndpointAddress;
+       u8                      highspeed;
+       struct list_head        td_list;        /* queued itds */
+       struct list_head        free_list;      /* list of unused itds */
+       struct usb_device       *udev;
+       struct usb_host_endpoint *ep;
+
+       /* output of (re)scheduling */
+       int                     next_uframe;
+       __hc32                  splits;
+
+       /* the rest is derived from the endpoint descriptor,
+        * trusting urb->interval == f(epdesc->bInterval) and
+        * including the extra info for hw_bufp[0..2]
+        */
+       u8                      usecs, c_usecs;
+       u16                     interval;
+       u16                     tt_usecs;
+       u16                     maxp;
+       u16                     raw_mask;
+       unsigned                bandwidth;
+
+       /* This is used to initialize iTD's hw_bufp fields */
+       __hc32                  buf0;
+       __hc32                  buf1;
+       __hc32                  buf2;
+
+       /* this is used to initialize sITD's tt info */
+       __hc32                  address;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.3
+ * Fig 3-4 "Isochronous Transaction Descriptor (iTD)"
+ *
+ * Schedule records for high speed iso xfers
+ */
+struct fotg210_itd {
+       /* first part defined by EHCI spec */
+       __hc32                  hw_next;        /* see EHCI 3.3.1 */
+       __hc32                  hw_transaction[8]; /* see EHCI 3.3.2 */
+#define FOTG210_ISOC_ACTIVE    (1<<31) /* activate transfer this slot */
+#define FOTG210_ISOC_BUF_ERR   (1<<30) /* Data buffer error */
+#define FOTG210_ISOC_BABBLE    (1<<29) /* babble detected */
+#define FOTG210_ISOC_XACTERR   (1<<28) /* XactErr - transaction error */
+#define        FOTG210_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff)
+#define        FOTG210_ITD_IOC         (1 << 15)       /* interrupt on complete */
+
+#define ITD_ACTIVE(fotg210)    cpu_to_hc32(fotg210, FOTG210_ISOC_ACTIVE)
+
+       __hc32                  hw_bufp[7];     /* see EHCI 3.3.3 */
+       __hc32                  hw_bufp_hi[7];  /* Appendix B */
+
+       /* the rest is HCD-private */
+       dma_addr_t              itd_dma;        /* for this itd */
+       union fotg210_shadow    itd_next;       /* ptr to periodic q entry */
+
+       struct urb              *urb;
+       struct fotg210_iso_stream       *stream;        /* endpoint's queue */
+       struct list_head        itd_list;       /* list of stream's itds */
+
+       /* any/all hw_transactions here may be used by that urb */
+       unsigned                frame;          /* where scheduled */
+       unsigned                pg;
+       unsigned                index[8];       /* in urb->iso_frame_desc */
+} __aligned(32);
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.96 Section 3.7
+ * Periodic Frame Span Traversal Node (FSTN)
+ *
+ * Manages split interrupt transactions (using TT) that span frame boundaries
+ * into uframes 0/1; see 4.12.2.2.  In those uframes, a "save place" FSTN
+ * makes the HC jump (back) to a QH to scan for fs/ls QH completions until
+ * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
+ */
+struct fotg210_fstn {
+       __hc32                  hw_next;        /* any periodic q entry */
+       __hc32                  hw_prev;        /* qh or FOTG210_LIST_END */
+
+       /* the rest is HCD-private */
+       dma_addr_t              fstn_dma;
+       union fotg210_shadow    fstn_next;      /* ptr to periodic q entry */
+} __aligned(32);
+
+/*-------------------------------------------------------------------------*/
+
+/* Prepare the PORTSC wakeup flags during controller suspend/resume */
+
+#define fotg210_prepare_ports_for_controller_suspend(fotg210, do_wakeup) \
+               fotg210_adjust_port_wakeup_flags(fotg210, true, do_wakeup);
+
+#define fotg210_prepare_ports_for_controller_resume(fotg210)           \
+               fotg210_adjust_port_wakeup_flags(fotg210, false, false);
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Some EHCI controllers have a Transaction Translator built into the
+ * root hub. This is a non-standard feature.  Each controller will need
+ * to add code to the following inline functions, and call them as
+ * needed (mostly in root hub code).
+ */
+
+static inline unsigned int
+fotg210_get_speed(struct fotg210_hcd *fotg210, unsigned int portsc)
+{
+       return (readl(&fotg210->regs->otgcsr)
+               & OTGCSR_HOST_SPD_TYP) >> 22;
+}
+
+/* Returns the speed of a device attached to a port on the root hub. */
+static inline unsigned int
+fotg210_port_speed(struct fotg210_hcd *fotg210, unsigned int portsc)
+{
+       switch (fotg210_get_speed(fotg210, portsc)) {
+       case 0:
+               return 0;
+       case 1:
+               return USB_PORT_STAT_LOW_SPEED;
+       case 2:
+       default:
+               return USB_PORT_STAT_HIGH_SPEED;
+       }
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define        fotg210_has_fsl_portno_bug(e)           (0)
+
+/*
+ * While most USB host controllers implement their registers in
+ * little-endian format, a minority (celleb companion chip) implement
+ * them in big endian format.
+ *
+ * This attempts to support either format at compile time without a
+ * runtime penalty, or both formats with the additional overhead
+ * of checking a flag bit.
+ *
+ */
+
+#define fotg210_big_endian_mmio(e)     0
+#define fotg210_big_endian_capbase(e)  0
+
+static inline unsigned int fotg210_readl(const struct fotg210_hcd *fotg210,
+               __u32 __iomem *regs)
+{
+       return readl(regs);
+}
+
+static inline void fotg210_writel(const struct fotg210_hcd *fotg210,
+               const unsigned int val, __u32 __iomem *regs)
+{
+       writel(val, regs);
+}
+
+/* cpu to fotg210 */
+static inline __hc32 cpu_to_hc32(const struct fotg210_hcd *fotg210, const u32 x)
+{
+       return cpu_to_le32(x);
+}
+
+/* fotg210 to cpu */
+static inline u32 hc32_to_cpu(const struct fotg210_hcd *fotg210, const __hc32 x)
+{
+       return le32_to_cpu(x);
+}
+
+static inline u32 hc32_to_cpup(const struct fotg210_hcd *fotg210,
+                              const __hc32 *x)
+{
+       return le32_to_cpup(x);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline unsigned fotg210_read_frame_index(struct fotg210_hcd *fotg210)
+{
+       return fotg210_readl(fotg210, &fotg210->regs->frame_index);
+}
+
+#define fotg210_itdlen(urb, desc, t) ({                        \
+       usb_pipein((urb)->pipe) ?                               \
+       (desc)->length - FOTG210_ITD_LENGTH(t) :                        \
+       FOTG210_ITD_LENGTH(t);                                  \
+})
+/*-------------------------------------------------------------------------*/
+
+#ifndef DEBUG
+#define STUB_DEBUG_FILES
+#endif /* DEBUG */
+
+/*-------------------------------------------------------------------------*/
+
+#endif /* __LINUX_FOTG210_H */
index 11e0b79ff9d52a8d703c3b2134b8960768123246..cfbff7161828005c6ea3732f30e452563c238d9e 100644 (file)
@@ -258,7 +258,7 @@ static int fsl_usb2_mph_dr_of_remove(struct platform_device *ofdev)
 
 int fsl_usb2_mpc5121_init(struct platform_device *pdev)
 {
-       struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+       struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct clk *clk;
        char clk_name[10];
        int base, clk_num;
@@ -298,7 +298,7 @@ int fsl_usb2_mpc5121_init(struct platform_device *pdev)
 
 static void fsl_usb2_mpc5121_exit(struct platform_device *pdev)
 {
-       struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+       struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
        pdata->regs = NULL;
 
index 483990c716aa5938ce58e8b7b227e5ab9dec421c..5b86ffb88f1cb53205061a08e339c65620293a9f 100644 (file)
@@ -161,6 +161,13 @@ static int hwahc_op_start(struct usb_hcd *usb_hcd)
        usb_hcd->uses_new_polling = 1;
        set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags);
        usb_hcd->state = HC_STATE_RUNNING;
+
+       /*
+        * prevent USB core from suspending the root hub since
+        * bus_suspend and bus_resume are not yet supported.
+        */
+       pm_runtime_get_noresume(&usb_hcd->self.root_hub->dev);
+
        result = 0;
 out:
        mutex_unlock(&wusbhc->mutex);
index 03dc4d9cbeca811e156d8e5ed32c235a20129177..60a5de505ca1845609fe34278405e752ddf73226 100644 (file)
@@ -1860,7 +1860,7 @@ static int imx21_probe(struct platform_device *pdev)
        imx21 = hcd_to_imx21(hcd);
        imx21->hcd = hcd;
        imx21->dev = &pdev->dev;
-       imx21->pdata = pdev->dev.platform_data;
+       imx21->pdata = dev_get_platdata(&pdev->dev);
        if (!imx21->pdata)
                imx21->pdata = &default_pdata;
 
index b64e661618bb8842bea5ad02f3d8444453a71c9b..c7d0f8f231be6abcc136b7110a1150f7ca372751 100644 (file)
@@ -1626,7 +1626,7 @@ static int isp116x_probe(struct platform_device *pdev)
        isp116x->addr_reg = addr_reg;
        spin_lock_init(&isp116x->lock);
        INIT_LIST_HEAD(&isp116x->async);
-       isp116x->board = pdev->dev.platform_data;
+       isp116x->board = dev_get_platdata(&pdev->dev);
 
        if (!isp116x->board) {
                ERR("Platform data structure not initialized\n");
index 9a2c400e6090491b2727d722bf6c1f9701d63523..dd34b7a33965e5da69d87c5a4c71b039cfc591e7 100644 (file)
@@ -325,11 +325,7 @@ struct isp116x_ep {
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef DEBUG
-#define DBG(stuff...)          printk(KERN_DEBUG "116x: " stuff)
-#else
-#define DBG(stuff...)          do{}while(0)
-#endif
+#define DBG(stuff...)          pr_debug("116x: " stuff)
 
 #ifdef VERBOSE
 #    define VDBG               DBG
@@ -358,15 +354,8 @@ struct isp116x_ep {
 #define isp116x_check_platform_delay(h)        0
 #endif
 
-#if defined(DEBUG)
-#define        IRQ_TEST()      BUG_ON(!irqs_disabled())
-#else
-#define        IRQ_TEST()      do{}while(0)
-#endif
-
 static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg)
 {
-       IRQ_TEST();
        writew(reg & 0xff, isp116x->addr_reg);
        isp116x_delay(isp116x, 300);
 }
index b04e8ece4d35f448c6b8ac5b23b9c198b0702702..6f29abad6815578a6282eb6e6d9cbe3b6469a8d8 100644 (file)
  * recovery time (MSCx = 0x7f8c) with a memory clock of 99.53 MHz.
  */
 
-#ifdef CONFIG_USB_DEBUG
-# define ISP1362_DEBUG
-#else
-# undef ISP1362_DEBUG
-#endif
+#undef ISP1362_DEBUG
 
 /*
  * The PXA255 UDC apparently doesn't handle GET_STATUS, GET_CONFIG and
@@ -82,6 +78,8 @@
 #include <linux/io.h>
 #include <linux/bitmap.h>
 #include <linux/prefetch.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 
 #include <asm/irq.h>
 #include <asm/byteorder.h>
@@ -92,7 +90,6 @@ static int dbg_level;
 module_param(dbg_level, int, 0644);
 #else
 module_param(dbg_level, int, 0);
-#define        STUB_DEBUG_FILE
 #endif
 
 #include "../core/usb.h"
@@ -350,8 +347,6 @@ static void isp1362_write_ptd(struct isp1362_hcd *isp1362_hcd, struct isp1362_ep
        struct ptd *ptd = &ep->ptd;
        int len = PTD_GET_DIR(ptd) == PTD_DIR_IN ? 0 : ep->length;
 
-       _BUG_ON(ep->ptd_offset < 0);
-
        prefetch(ptd);
        isp1362_write_buffer(isp1362_hcd, ptd, ep->ptd_offset, PTD_HEADER_SIZE);
        if (len)
@@ -1575,12 +1570,12 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                DBG(0, "ClearHubFeature: ");
                switch (wValue) {
                case C_HUB_OVER_CURRENT:
-                       _DBG(0, "C_HUB_OVER_CURRENT\n");
+                       DBG(0, "C_HUB_OVER_CURRENT\n");
                        spin_lock_irqsave(&isp1362_hcd->lock, flags);
                        isp1362_write_reg32(isp1362_hcd, HCRHSTATUS, RH_HS_OCIC);
                        spin_unlock_irqrestore(&isp1362_hcd->lock, flags);
                case C_HUB_LOCAL_POWER:
-                       _DBG(0, "C_HUB_LOCAL_POWER\n");
+                       DBG(0, "C_HUB_LOCAL_POWER\n");
                        break;
                default:
                        goto error;
@@ -1591,7 +1586,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                switch (wValue) {
                case C_HUB_OVER_CURRENT:
                case C_HUB_LOCAL_POWER:
-                       _DBG(0, "C_HUB_OVER_CURRENT or C_HUB_LOCAL_POWER\n");
+                       DBG(0, "C_HUB_OVER_CURRENT or C_HUB_LOCAL_POWER\n");
                        break;
                default:
                        goto error;
@@ -1622,36 +1617,36 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 
                switch (wValue) {
                case USB_PORT_FEAT_ENABLE:
-                       _DBG(0, "USB_PORT_FEAT_ENABLE\n");
+                       DBG(0, "USB_PORT_FEAT_ENABLE\n");
                        tmp = RH_PS_CCS;
                        break;
                case USB_PORT_FEAT_C_ENABLE:
-                       _DBG(0, "USB_PORT_FEAT_C_ENABLE\n");
+                       DBG(0, "USB_PORT_FEAT_C_ENABLE\n");
                        tmp = RH_PS_PESC;
                        break;
                case USB_PORT_FEAT_SUSPEND:
-                       _DBG(0, "USB_PORT_FEAT_SUSPEND\n");
+                       DBG(0, "USB_PORT_FEAT_SUSPEND\n");
                        tmp = RH_PS_POCI;
                        break;
                case USB_PORT_FEAT_C_SUSPEND:
-                       _DBG(0, "USB_PORT_FEAT_C_SUSPEND\n");
+                       DBG(0, "USB_PORT_FEAT_C_SUSPEND\n");
                        tmp = RH_PS_PSSC;
                        break;
                case USB_PORT_FEAT_POWER:
-                       _DBG(0, "USB_PORT_FEAT_POWER\n");
+                       DBG(0, "USB_PORT_FEAT_POWER\n");
                        tmp = RH_PS_LSDA;
 
                        break;
                case USB_PORT_FEAT_C_CONNECTION:
-                       _DBG(0, "USB_PORT_FEAT_C_CONNECTION\n");
+                       DBG(0, "USB_PORT_FEAT_C_CONNECTION\n");
                        tmp = RH_PS_CSC;
                        break;
                case USB_PORT_FEAT_C_OVER_CURRENT:
-                       _DBG(0, "USB_PORT_FEAT_C_OVER_CURRENT\n");
+                       DBG(0, "USB_PORT_FEAT_C_OVER_CURRENT\n");
                        tmp = RH_PS_OCIC;
                        break;
                case USB_PORT_FEAT_C_RESET:
-                       _DBG(0, "USB_PORT_FEAT_C_RESET\n");
+                       DBG(0, "USB_PORT_FEAT_C_RESET\n");
                        tmp = RH_PS_PRSC;
                        break;
                default:
@@ -1671,7 +1666,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                wIndex--;
                switch (wValue) {
                case USB_PORT_FEAT_SUSPEND:
-                       _DBG(0, "USB_PORT_FEAT_SUSPEND\n");
+                       DBG(0, "USB_PORT_FEAT_SUSPEND\n");
                        spin_lock_irqsave(&isp1362_hcd->lock, flags);
                        isp1362_write_reg32(isp1362_hcd, HCRHPORT1 + wIndex, RH_PS_PSS);
                        isp1362_hcd->rhport[wIndex] =
@@ -1679,7 +1674,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        spin_unlock_irqrestore(&isp1362_hcd->lock, flags);
                        break;
                case USB_PORT_FEAT_POWER:
-                       _DBG(0, "USB_PORT_FEAT_POWER\n");
+                       DBG(0, "USB_PORT_FEAT_POWER\n");
                        spin_lock_irqsave(&isp1362_hcd->lock, flags);
                        isp1362_write_reg32(isp1362_hcd, HCRHPORT1 + wIndex, RH_PS_PPS);
                        isp1362_hcd->rhport[wIndex] =
@@ -1687,7 +1682,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        spin_unlock_irqrestore(&isp1362_hcd->lock, flags);
                        break;
                case USB_PORT_FEAT_RESET:
-                       _DBG(0, "USB_PORT_FEAT_RESET\n");
+                       DBG(0, "USB_PORT_FEAT_RESET\n");
                        spin_lock_irqsave(&isp1362_hcd->lock, flags);
 
                        t1 = jiffies + msecs_to_jiffies(USB_RESET_WIDTH);
@@ -1721,7 +1716,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
        default:
  error:
                /* "protocol stall" on error */
-               _DBG(0, "PROTOCOL STALL\n");
+               DBG(0, "PROTOCOL STALL\n");
                retval = -EPIPE;
        }
 
@@ -1913,20 +1908,6 @@ static int isp1362_bus_resume(struct usb_hcd *hcd)
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef STUB_DEBUG_FILE
-
-static inline void create_debug_file(struct isp1362_hcd *isp1362_hcd)
-{
-}
-static inline void remove_debug_file(struct isp1362_hcd *isp1362_hcd)
-{
-}
-
-#else
-
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-
 static void dump_irq(struct seq_file *s, char *label, u16 mask)
 {
        seq_printf(s, "%-15s %04x%s%s%s%s%s%s\n", label, mask,
@@ -2069,7 +2050,7 @@ static void dump_regs(struct seq_file *s, struct isp1362_hcd *isp1362_hcd)
                   isp1362_read_reg16(isp1362_hcd, HCATLDTCTO));
 }
 
-static int proc_isp1362_show(struct seq_file *s, void *unused)
+static int isp1362_show(struct seq_file *s, void *unused)
 {
        struct isp1362_hcd *isp1362_hcd = s->private;
        struct isp1362_ep *ep;
@@ -2173,41 +2154,31 @@ static int proc_isp1362_show(struct seq_file *s, void *unused)
        return 0;
 }
 
-static int proc_isp1362_open(struct inode *inode, struct file *file)
+static int isp1362_open(struct inode *inode, struct file *file)
 {
-       return single_open(file, proc_isp1362_show, PDE_DATA(inode));
+       return single_open(file, isp1362_show, inode);
 }
 
-static const struct file_operations proc_ops = {
-       .open = proc_isp1362_open,
+static const struct file_operations debug_ops = {
+       .open = isp1362_open,
        .read = seq_read,
        .llseek = seq_lseek,
        .release = single_release,
 };
 
 /* expect just one isp1362_hcd per system */
-static const char proc_filename[] = "driver/isp1362";
-
 static void create_debug_file(struct isp1362_hcd *isp1362_hcd)
 {
-       struct proc_dir_entry *pde;
-
-       pde = proc_create_data(proc_filename, 0, NULL, &proc_ops, isp1362_hcd);
-       if (pde == NULL) {
-               pr_warning("%s: Failed to create debug file '%s'\n", __func__, proc_filename);
-               return;
-       }
-       isp1362_hcd->pde = pde;
+       isp1362_hcd->debug_file = debugfs_create_file("isp1362", S_IRUGO,
+                                                     usb_debug_root,
+                                                     isp1362_hcd, &debug_ops);
 }
 
 static void remove_debug_file(struct isp1362_hcd *isp1362_hcd)
 {
-       if (isp1362_hcd->pde)
-               remove_proc_entry(proc_filename, NULL);
+       debugfs_remove(isp1362_hcd->debug_file);
 }
 
-#endif
-
 /*-------------------------------------------------------------------------*/
 
 static void __isp1362_sw_reset(struct isp1362_hcd *isp1362_hcd)
@@ -2754,7 +2725,7 @@ static int isp1362_probe(struct platform_device *pdev)
        INIT_LIST_HEAD(&isp1362_hcd->periodic);
        INIT_LIST_HEAD(&isp1362_hcd->isoc);
        INIT_LIST_HEAD(&isp1362_hcd->remove_list);
-       isp1362_hcd->board = pdev->dev.platform_data;
+       isp1362_hcd->board = dev_get_platdata(&pdev->dev);
 #if USE_PLATFORM_DELAY
        if (!isp1362_hcd->board->delay) {
                dev_err(hcd->self.controller, "No platform delay function given\n");
index 0f97820e65befebe6a01154c2b058ebde6a73c97..3b0b4847c3a95430b55ca825edf941b866095ac3 100644 (file)
@@ -76,14 +76,14 @@ static inline void delayed_insw(unsigned int addr, void *buf, int len)
 
 #define ISP1362_REG_WRITE_OFFSET       0x80
 
-#ifdef ISP1362_DEBUG
-typedef const unsigned int isp1362_reg_t;
-
 #define REG_WIDTH_16                   0x000
 #define REG_WIDTH_32                   0x100
 #define REG_WIDTH_MASK                 0x100
 #define REG_NO_MASK                    0x0ff
 
+#ifdef ISP1362_DEBUG
+typedef const unsigned int isp1362_reg_t;
+
 #define REG_ACCESS_R                   0x200
 #define REG_ACCESS_W                   0x400
 #define REG_ACCESS_RW                  0x600
@@ -91,9 +91,6 @@ typedef const unsigned int isp1362_reg_t;
 
 #define ISP1362_REG_NO(r)              ((r) & REG_NO_MASK)
 
-#define _BUG_ON(x)     BUG_ON(x)
-#define _WARN_ON(x)    WARN_ON(x)
-
 #define ISP1362_REG(name, addr, width, rw) \
 static isp1362_reg_t ISP1362_REG_##name = ((addr) | (width) | (rw))
 
@@ -102,8 +99,6 @@ static isp1362_reg_t ISP1362_REG_##name = ((addr) | (width) | (rw))
 #else
 typedef const unsigned char isp1362_reg_t;
 #define ISP1362_REG_NO(r)              (r)
-#define _BUG_ON(x)                     do {} while (0)
-#define _WARN_ON(x)                    do {} while (0)
 
 #define ISP1362_REG(name, addr, width, rw) \
 static isp1362_reg_t ISP1362_REG_##name = addr
@@ -485,7 +480,7 @@ struct isp1362_hcd {
 
        struct isp1362_platform_data *board;
 
-       struct proc_dir_entry   *pde;
+       struct dentry           *debug_file;
        unsigned long           stat1, stat2, stat4, stat8, stat16;
 
        /* HC registers */
@@ -587,21 +582,11 @@ static inline struct usb_hcd *isp1362_hcd_to_hcd(struct isp1362_hcd *isp1362_hcd
  * ISP1362 HW Interface
  */
 
-#ifdef ISP1362_DEBUG
 #define DBG(level, fmt...) \
        do { \
                if (dbg_level > level) \
                        pr_debug(fmt); \
        } while (0)
-#define _DBG(level, fmt...)    \
-       do { \
-               if (dbg_level > level) \
-                       printk(fmt); \
-       } while (0)
-#else
-#define DBG(fmt...)            do {} while (0)
-#define _DBG DBG
-#endif
 
 #ifdef VERBOSE
 #    define VDBG(fmt...)       DBG(3, fmt)
@@ -645,9 +630,7 @@ static inline struct usb_hcd *isp1362_hcd_to_hcd(struct isp1362_hcd *isp1362_hcd
  */
 static void isp1362_write_addr(struct isp1362_hcd *isp1362_hcd, isp1362_reg_t reg)
 {
-       /*_BUG_ON((reg & ISP1362_REG_WRITE_OFFSET) && !(reg & REG_ACCESS_W));*/
        REG_ACCESS_TEST(reg);
-       _BUG_ON(!irqs_disabled());
        DUMMY_DELAY_ACCESS;
        writew(ISP1362_REG_NO(reg), isp1362_hcd->addr_reg);
        DUMMY_DELAY_ACCESS;
@@ -656,7 +639,6 @@ static void isp1362_write_addr(struct isp1362_hcd *isp1362_hcd, isp1362_reg_t re
 
 static void isp1362_write_data16(struct isp1362_hcd *isp1362_hcd, u16 val)
 {
-       _BUG_ON(!irqs_disabled());
        DUMMY_DELAY_ACCESS;
        writew(val, isp1362_hcd->data_reg);
 }
@@ -665,7 +647,6 @@ static u16 isp1362_read_data16(struct isp1362_hcd *isp1362_hcd)
 {
        u16 val;
 
-       _BUG_ON(!irqs_disabled());
        DUMMY_DELAY_ACCESS;
        val = readw(isp1362_hcd->data_reg);
 
@@ -674,7 +655,6 @@ static u16 isp1362_read_data16(struct isp1362_hcd *isp1362_hcd)
 
 static void isp1362_write_data32(struct isp1362_hcd *isp1362_hcd, u32 val)
 {
-       _BUG_ON(!irqs_disabled());
 #if USE_32BIT
        DUMMY_DELAY_ACCESS;
        writel(val, isp1362_hcd->data_reg);
@@ -690,7 +670,6 @@ static u32 isp1362_read_data32(struct isp1362_hcd *isp1362_hcd)
 {
        u32 val;
 
-       _BUG_ON(!irqs_disabled());
 #if USE_32BIT
        DUMMY_DELAY_ACCESS;
        val = readl(isp1362_hcd->data_reg);
@@ -713,8 +692,6 @@ static void isp1362_read_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 le
        if (!len)
                return;
 
-       _BUG_ON(!irqs_disabled());
-
        RDBG("%s: Reading %d byte from fifo to mem @ %p\n", __func__, len, buf);
 #if USE_32BIT
        if (len >= 4) {
@@ -760,8 +737,6 @@ static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 l
                return;
        }
 
-       _BUG_ON(!irqs_disabled());
-
        RDBG("%s: Writing %d byte to fifo from memory @%p\n", __func__, len, buf);
 #if USE_32BIT
        if (len >= 4) {
@@ -854,7 +829,6 @@ static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 l
                isp1362_write_reg32(d, r, __v & ~m);    \
 }
 
-#ifdef ISP1362_DEBUG
 #define isp1362_show_reg(d, r) {                                                               \
        if ((ISP1362_REG_##r & REG_WIDTH_MASK) == REG_WIDTH_32)                 \
                DBG(0, "%-12s[%02x]: %08x\n", #r,                                       \
@@ -863,9 +837,6 @@ static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 l
                DBG(0, "%-12s[%02x]:     %04x\n", #r,                                   \
                        ISP1362_REG_NO(ISP1362_REG_##r), isp1362_read_reg16(d, r));     \
 }
-#else
-#define isp1362_show_reg(d, r) do {} while (0)
-#endif
 
 static void __attribute__((__unused__)) isp1362_show_regs(struct isp1362_hcd *isp1362_hcd)
 {
@@ -923,10 +894,6 @@ static void __attribute__((__unused__)) isp1362_show_regs(struct isp1362_hcd *is
 
 static void isp1362_write_diraddr(struct isp1362_hcd *isp1362_hcd, u16 offset, u16 len)
 {
-       _BUG_ON(offset & 1);
-       _BUG_ON(offset >= ISP1362_BUF_SIZE);
-       _BUG_ON(len > ISP1362_BUF_SIZE);
-       _BUG_ON(offset + len > ISP1362_BUF_SIZE);
        len = (len + 1) & ~1;
 
        isp1362_clr_mask16(isp1362_hcd, HCDMACFG, HCDMACFG_CTR_ENABLE);
@@ -936,42 +903,32 @@ static void isp1362_write_diraddr(struct isp1362_hcd *isp1362_hcd, u16 offset, u
 
 static void isp1362_read_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16 offset, int len)
 {
-       _BUG_ON(offset & 1);
-
        isp1362_write_diraddr(isp1362_hcd, offset, len);
 
        DBG(3, "%s: Reading %d byte from buffer @%04x to memory @ %p\n",
            __func__, len, offset, buf);
 
        isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
-       _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
 
        isp1362_write_addr(isp1362_hcd, ISP1362_REG_HCDIRDATA);
 
        isp1362_read_fifo(isp1362_hcd, buf, len);
-       _WARN_ON(!(isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
        isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
-       _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
 }
 
 static void isp1362_write_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16 offset, int len)
 {
-       _BUG_ON(offset & 1);
-
        isp1362_write_diraddr(isp1362_hcd, offset, len);
 
        DBG(3, "%s: Writing %d byte to buffer @%04x from memory @ %p\n",
            __func__, len, offset, buf);
 
        isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
-       _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
 
        isp1362_write_addr(isp1362_hcd, ISP1362_REG_HCDIRDATA | ISP1362_REG_WRITE_OFFSET);
        isp1362_write_fifo(isp1362_hcd, buf, len);
 
-       _WARN_ON(!(isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
        isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
-       _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
 }
 
 static void __attribute__((unused)) dump_data(char *buf, int len)
@@ -1002,7 +959,7 @@ static void __attribute__((unused)) dump_data(char *buf, int len)
        }
 }
 
-#if defined(ISP1362_DEBUG) && defined(PTD_TRACE)
+#if defined(PTD_TRACE)
 
 static void dump_ptd(struct ptd *ptd)
 {
index 3df49b169b531f730cfc4c0cf33c8d7dd27a42d6..df931e9ba5b5cfa682f8fab3272da16c5531dca4 100644 (file)
@@ -351,7 +351,7 @@ static int isp1760_plat_probe(struct platform_device *pdev)
        struct resource *mem_res;
        struct resource *irq_res;
        resource_size_t mem_size;
-       struct isp1760_platform_data *priv = pdev->dev.platform_data;
+       struct isp1760_platform_data *priv = dev_get_platdata(&pdev->dev);
        unsigned int devflags = 0;
        unsigned long irqflags = IRQF_SHARED;
 
index 9677f6831209709d8ea7c42b97c91af3959c000d..b3cdd1467521c0d40f7805d349b35e998b51a6cb 100644 (file)
@@ -31,8 +31,8 @@
 #define at91_for_each_port(index)      \
                for ((index) = 0; (index) < AT91_MAX_USBH_PORTS; (index)++)
 
-/* interface and function clocks; sometimes also an AHB clock */
-static struct clk *iclk, *fclk, *hclk;
+/* interface, function and usb clocks; sometimes also an AHB clock */
+static struct clk *iclk, *fclk, *uclk, *hclk;
 static int clocked;
 
 extern int usb_disabled(void);
@@ -41,6 +41,10 @@ extern int usb_disabled(void);
 
 static void at91_start_clock(void)
 {
+       if (IS_ENABLED(CONFIG_COMMON_CLK)) {
+               clk_set_rate(uclk, 48000000);
+               clk_prepare_enable(uclk);
+       }
        clk_prepare_enable(hclk);
        clk_prepare_enable(iclk);
        clk_prepare_enable(fclk);
@@ -52,6 +56,8 @@ static void at91_stop_clock(void)
        clk_disable_unprepare(fclk);
        clk_disable_unprepare(iclk);
        clk_disable_unprepare(hclk);
+       if (IS_ENABLED(CONFIG_COMMON_CLK))
+               clk_disable_unprepare(uclk);
        clocked = 0;
 }
 
@@ -162,6 +168,14 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
                retval = PTR_ERR(hclk);
                goto err5;
        }
+       if (IS_ENABLED(CONFIG_COMMON_CLK)) {
+               uclk = clk_get(&pdev->dev, "usb_clk");
+               if (IS_ERR(uclk)) {
+                       dev_err(&pdev->dev, "failed to get uclk\n");
+                       retval = PTR_ERR(uclk);
+                       goto err6;
+               }
+       }
 
        at91_start_hc(pdev);
        ohci_hcd_init(hcd_to_ohci(hcd));
@@ -173,6 +187,9 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
        /* Error handling */
        at91_stop_hc(pdev);
 
+       if (IS_ENABLED(CONFIG_COMMON_CLK))
+               clk_put(uclk);
+ err6:
        clk_put(hclk);
  err5:
        clk_put(fclk);
@@ -212,6 +229,8 @@ static void usb_hcd_at91_remove(struct usb_hcd *hcd,
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
 
+       if (IS_ENABLED(CONFIG_COMMON_CLK))
+               clk_put(uclk);
        clk_put(hclk);
        clk_put(fclk);
        clk_put(iclk);
@@ -225,7 +244,7 @@ static void usb_hcd_at91_remove(struct usb_hcd *hcd,
 static int
 ohci_at91_reset (struct usb_hcd *hcd)
 {
-       struct at91_usbh_data   *board = hcd->self.controller->platform_data;
+       struct at91_usbh_data   *board = dev_get_platdata(hcd->self.controller);
        struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
        int                     ret;
 
@@ -280,7 +299,7 @@ static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port)
  */
 static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf)
 {
-       struct at91_usbh_data *pdata = hcd->self.controller->platform_data;
+       struct at91_usbh_data *pdata = dev_get_platdata(hcd->self.controller);
        int length = ohci_hub_status_data(hcd, buf);
        int port;
 
@@ -301,7 +320,7 @@ static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf)
 static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                                 u16 wIndex, char *buf, u16 wLength)
 {
-       struct at91_usbh_data *pdata = hcd->self.controller->platform_data;
+       struct at91_usbh_data *pdata = dev_get_platdata(hcd->self.controller);
        struct usb_hub_descriptor *desc;
        int ret = -EINVAL;
        u32 *data = (u32 *)buf;
@@ -461,7 +480,7 @@ static const struct hc_driver ohci_at91_hc_driver = {
 static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data)
 {
        struct platform_device *pdev = data;
-       struct at91_usbh_data *pdata = pdev->dev.platform_data;
+       struct at91_usbh_data *pdata = dev_get_platdata(&pdev->dev);
        int val, gpio, port;
 
        /* From the GPIO notifying the over-current situation, find
@@ -567,7 +586,7 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
 
        if (pdata) {
                at91_for_each_port(i) {
@@ -643,7 +662,7 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
 
 static int ohci_hcd_at91_drv_remove(struct platform_device *pdev)
 {
-       struct at91_usbh_data   *pdata = pdev->dev.platform_data;
+       struct at91_usbh_data   *pdata = dev_get_platdata(&pdev->dev);
        int                     i;
 
        if (pdata) {
index 6aaa9c9c8eb00f90d3f99711196659991aca2f43..9be59f11e05101356c2b2e44b6b59c3cc7af88be 100644 (file)
@@ -85,7 +85,7 @@ static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub,
 static int ohci_da8xx_init(struct usb_hcd *hcd)
 {
        struct device *dev              = hcd->self.controller;
-       struct da8xx_ohci_root_hub *hub = dev->platform_data;
+       struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
        struct ohci_hcd *ohci           = hcd_to_ohci(hcd);
        int result;
        u32 rh_a;
@@ -171,7 +171,7 @@ static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                                  u16 wIndex, char *buf, u16 wLength)
 {
        struct device *dev              = hcd->self.controller;
-       struct da8xx_ohci_root_hub *hub = dev->platform_data;
+       struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
        int temp;
 
        switch (typeReq) {
@@ -292,7 +292,7 @@ static const struct hc_driver ohci_da8xx_hc_driver = {
 static int usb_hcd_da8xx_probe(const struct hc_driver *driver,
                               struct platform_device *pdev)
 {
-       struct da8xx_ohci_root_hub *hub = pdev->dev.platform_data;
+       struct da8xx_ohci_root_hub *hub = dev_get_platdata(&pdev->dev);
        struct usb_hcd  *hcd;
        struct resource *mem;
        int error, irq;
@@ -380,7 +380,7 @@ err0:
 static inline void
 usb_hcd_da8xx_remove(struct usb_hcd *hcd, struct platform_device *pdev)
 {
-       struct da8xx_ohci_root_hub *hub = pdev->dev.platform_data;
+       struct da8xx_ohci_root_hub *hub = dev_get_platdata(&pdev->dev);
 
        hub->ocic_notify(NULL);
        usb_remove_hcd(hcd);
index 8704e9fa5a8041146c79b027ad85ca0581121040..84a20d5223b962b869e0c99499eed28230497822 100644 (file)
 
 static struct clk *usb_host_clock;
 
-static void ep93xx_start_hc(struct device *dev)
-{
-       clk_enable(usb_host_clock);
-}
-
-static void ep93xx_stop_hc(struct device *dev)
-{
-       clk_disable(usb_host_clock);
-}
-
-static int usb_hcd_ep93xx_probe(const struct hc_driver *driver,
-                        struct platform_device *pdev)
-{
-       int retval;
-       struct usb_hcd *hcd;
-
-       if (pdev->resource[1].flags != IORESOURCE_IRQ) {
-               dev_dbg(&pdev->dev, "resource[1] is not IORESOURCE_IRQ\n");
-               return -ENOMEM;
-       }
-
-       hcd = usb_create_hcd(driver, &pdev->dev, "ep93xx");
-       if (hcd == NULL)
-               return -ENOMEM;
-
-       hcd->rsrc_start = pdev->resource[0].start;
-       hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-               usb_put_hcd(hcd);
-               retval = -EBUSY;
-               goto err1;
-       }
-
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
-       if (hcd->regs == NULL) {
-               dev_dbg(&pdev->dev, "ioremap failed\n");
-               retval = -ENOMEM;
-               goto err2;
-       }
-
-       usb_host_clock = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(usb_host_clock)) {
-               dev_dbg(&pdev->dev, "clk_get failed\n");
-               retval = PTR_ERR(usb_host_clock);
-               goto err3;
-       }
-
-       ep93xx_start_hc(&pdev->dev);
-
-       ohci_hcd_init(hcd_to_ohci(hcd));
-
-       retval = usb_add_hcd(hcd, pdev->resource[1].start, 0);
-       if (retval == 0)
-               return retval;
-
-       ep93xx_stop_hc(&pdev->dev);
-err3:
-       iounmap(hcd->regs);
-err2:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err1:
-       usb_put_hcd(hcd);
-
-       return retval;
-}
-
-static void usb_hcd_ep93xx_remove(struct usb_hcd *hcd,
-                       struct platform_device *pdev)
-{
-       usb_remove_hcd(hcd);
-       ep93xx_stop_hc(&pdev->dev);
-       clk_put(usb_host_clock);
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-       usb_put_hcd(hcd);
-}
-
 static int ohci_ep93xx_start(struct usb_hcd *hcd)
 {
        struct ohci_hcd *ohci = hcd_to_ohci(hcd);
@@ -147,15 +70,57 @@ static struct hc_driver ohci_ep93xx_hc_driver = {
        .start_port_reset       = ohci_start_port_reset,
 };
 
-extern int usb_disabled(void);
-
 static int ohci_hcd_ep93xx_drv_probe(struct platform_device *pdev)
 {
+       struct usb_hcd *hcd;
+       struct resource *res;
+       int irq;
        int ret;
 
-       ret = -ENODEV;
-       if (!usb_disabled())
-               ret = usb_hcd_ep93xx_probe(&ohci_ep93xx_hc_driver, pdev);
+       if (usb_disabled())
+               return -ENODEV;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENXIO;
+
+       hcd = usb_create_hcd(&ohci_ep93xx_hc_driver, &pdev->dev, "ep93xx");
+       if (!hcd)
+               return -ENOMEM;
+
+       hcd->rsrc_start = res->start;
+       hcd->rsrc_len = resource_size(res);
+
+       hcd->regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(hcd->regs)) {
+               ret = PTR_ERR(hcd->regs);
+               goto err_put_hcd;
+       }
+
+       usb_host_clock = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(usb_host_clock)) {
+               ret = PTR_ERR(usb_host_clock);
+               goto err_put_hcd;
+       }
+
+       clk_enable(usb_host_clock);
+
+       ohci_hcd_init(hcd_to_ohci(hcd));
+
+       ret = usb_add_hcd(hcd, irq, 0);
+       if (ret)
+               goto err_clk_disable;
+
+       return 0;
+
+err_clk_disable:
+       clk_disable(usb_host_clock);
+err_put_hcd:
+       usb_put_hcd(hcd);
 
        return ret;
 }
@@ -164,7 +129,9 @@ static int ohci_hcd_ep93xx_drv_remove(struct platform_device *pdev)
 {
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
-       usb_hcd_ep93xx_remove(hcd, pdev);
+       usb_remove_hcd(hcd);
+       clk_disable(usb_host_clock);
+       usb_put_hcd(hcd);
 
        return 0;
 }
@@ -179,7 +146,7 @@ static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_
                msleep(5);
        ohci->next_statechange = jiffies;
 
-       ep93xx_stop_hc(&pdev->dev);
+       clk_disable(usb_host_clock);
        return 0;
 }
 
@@ -192,7 +159,7 @@ static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev)
                msleep(5);
        ohci->next_statechange = jiffies;
 
-       ep93xx_start_hc(&pdev->dev);
+       clk_enable(usb_host_clock);
 
        ohci_resume(hcd, false);
        return 0;
index b0b542c14e3132a9f35eceb86ef1255b676e13ca..dc6ee9adacf58679305df6baa851167e34e61ed4 100644 (file)
@@ -100,7 +100,7 @@ static const struct hc_driver exynos_ohci_hc_driver = {
 
 static int exynos_ohci_probe(struct platform_device *pdev)
 {
-       struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
+       struct exynos4_ohci_platdata *pdata = dev_get_platdata(&pdev->dev);
        struct exynos_ohci_hcd *exynos_ohci;
        struct usb_hcd *hcd;
        struct ohci_hcd *ohci;
index a9d3437da220393e9a9454f8a94914692a4d0354..8f6b695af6a470c5f5d5a5ca6a278e3a1186dfcc 100644 (file)
@@ -938,8 +938,8 @@ static void ohci_stop (struct usb_hcd *hcd)
        if (quirk_nec(ohci))
                flush_work(&ohci->nec_work);
 
-       ohci_usb_reset (ohci);
        ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+       ohci_usb_reset(ohci);
        free_irq(hcd->irq, hcd);
        hcd->irq = 0;
 
index 8747fa6a51b7cf1c067bf7cf8264c442a0e330db..31d3a12eb4867e56872f71cbea9f61ef1431dba5 100644 (file)
@@ -191,7 +191,7 @@ static void start_hnp(struct ohci_hcd *ohci)
 static int ohci_omap_init(struct usb_hcd *hcd)
 {
        struct ohci_hcd         *ohci = hcd_to_ohci(hcd);
-       struct omap_usb_config  *config = hcd->self.controller->platform_data;
+       struct omap_usb_config  *config = dev_get_platdata(hcd->self.controller);
        int                     need_transceiver = (config->otg != 0);
        int                     ret;
 
@@ -427,7 +427,7 @@ ohci_omap_start (struct usb_hcd *hcd)
 
        if (!host_enabled)
                return 0;
-       config = hcd->self.controller->platform_data;
+       config = dev_get_platdata(hcd->self.controller);
        if (config->otg || config->rwc) {
                ohci->hc_control = OHCI_CTRL_RWC;
                writel(OHCI_CTRL_RWC, &ohci->regs->control);
index 8f713571a0b75b9a24266bf281c934a2dcaf93cd..a09af26f69ed4efdde274e028eb88110231cfc18 100644 (file)
@@ -231,14 +231,6 @@ static int ohci_hcd_omap3_remove(struct platform_device *pdev)
        return 0;
 }
 
-static void ohci_hcd_omap3_shutdown(struct platform_device *pdev)
-{
-       struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev);
-
-       if (hcd->driver->shutdown)
-               hcd->driver->shutdown(hcd);
-}
-
 static const struct of_device_id omap_ohci_dt_ids[] = {
        { .compatible = "ti,ohci-omap3" },
        { }
@@ -249,7 +241,7 @@ MODULE_DEVICE_TABLE(of, omap_ohci_dt_ids);
 static struct platform_driver ohci_hcd_omap3_driver = {
        .probe          = ohci_hcd_omap3_probe,
        .remove         = ohci_hcd_omap3_remove,
-       .shutdown       = ohci_hcd_omap3_shutdown,
+       .shutdown       = usb_hcd_platform_shutdown,
        .driver         = {
                .name   = "ohci-omap3",
                .of_match_table = omap_ohci_dt_ids,
index bc30475c3a236886e3784d47ccfdaa4fbd5b7fb3..a4c6410f0ed494bfb6fb492849d1ed5f3b4fb1d2 100644 (file)
@@ -33,7 +33,7 @@ static const char hcd_name[] = "ohci-platform";
 static int ohci_platform_reset(struct usb_hcd *hcd)
 {
        struct platform_device *pdev = to_platform_device(hcd->self.controller);
-       struct usb_ohci_pdata *pdata = pdev->dev.platform_data;
+       struct usb_ohci_pdata *pdata = dev_get_platdata(&pdev->dev);
        struct ohci_hcd *ohci = hcd_to_ohci(hcd);
 
        if (pdata->big_endian_desc)
@@ -59,7 +59,7 @@ static int ohci_platform_probe(struct platform_device *dev)
 {
        struct usb_hcd *hcd;
        struct resource *res_mem;
-       struct usb_ohci_pdata *pdata = dev->dev.platform_data;
+       struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
        int irq;
        int err = -ENOMEM;
 
@@ -124,7 +124,7 @@ err_power:
 static int ohci_platform_remove(struct platform_device *dev)
 {
        struct usb_hcd *hcd = platform_get_drvdata(dev);
-       struct usb_ohci_pdata *pdata = dev->dev.platform_data;
+       struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
 
        usb_remove_hcd(hcd);
        usb_put_hcd(hcd);
@@ -139,7 +139,7 @@ static int ohci_platform_remove(struct platform_device *dev)
 
 static int ohci_platform_suspend(struct device *dev)
 {
-       struct usb_ohci_pdata *pdata = dev->platform_data;
+       struct usb_ohci_pdata *pdata = dev_get_platdata(dev);
        struct platform_device *pdev =
                container_of(dev, struct platform_device, dev);
 
@@ -152,7 +152,7 @@ static int ohci_platform_suspend(struct device *dev)
 static int ohci_platform_resume(struct device *dev)
 {
        struct usb_hcd *hcd = dev_get_drvdata(dev);
-       struct usb_ohci_pdata *pdata = dev->platform_data;
+       struct usb_ohci_pdata *pdata = dev_get_platdata(dev);
        struct platform_device *pdev =
                container_of(dev, struct platform_device, dev);
 
index 8294e2fcc2f6288a35169181ee28bf499ff630fe..75f5a1e2f01e70b4295b25008aec142480664856 100644 (file)
@@ -200,15 +200,6 @@ static int ohci_hcd_ppc_of_remove(struct platform_device *op)
        return 0;
 }
 
-static void ohci_hcd_ppc_of_shutdown(struct platform_device *op)
-{
-       struct usb_hcd *hcd = platform_get_drvdata(op);
-
-        if (hcd->driver->shutdown)
-                hcd->driver->shutdown(hcd);
-}
-
-
 static const struct of_device_id ohci_hcd_ppc_of_match[] = {
 #ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
        {
@@ -243,7 +234,7 @@ MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
 static struct platform_driver ohci_hcd_ppc_of_driver = {
        .probe          = ohci_hcd_ppc_of_probe,
        .remove         = ohci_hcd_ppc_of_remove,
-       .shutdown       = ohci_hcd_ppc_of_shutdown,
+       .shutdown       = usb_hcd_platform_shutdown,
        .driver = {
                .name = "ppc-of-ohci",
                .owner = THIS_MODULE,
index 3a9c01d8b79c77b4fb607cbe003ab1b3ac6be6d5..93371a235e821fac080068f7522bc5a80576119c 100644 (file)
@@ -219,7 +219,7 @@ static int pxa27x_start_hc(struct pxa27x_ohci *ohci, struct device *dev)
        struct pxaohci_platform_data *inf;
        uint32_t uhchr;
 
-       inf = dev->platform_data;
+       inf = dev_get_platdata(dev);
 
        clk_prepare_enable(ohci->clk);
 
@@ -256,7 +256,7 @@ static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, struct device *dev)
        struct pxaohci_platform_data *inf;
        uint32_t uhccoms;
 
-       inf = dev->platform_data;
+       inf = dev_get_platdata(dev);
 
        if (cpu_is_pxa3xx())
                pxa3xx_u2d_stop_hc(&ohci_to_hcd(&ohci->ohci)->self);
@@ -364,7 +364,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
        if (retval)
                return retval;
 
-       inf = pdev->dev.platform_data;
+       inf = dev_get_platdata(&pdev->dev);
 
        if (!inf)
                return -ENODEV;
@@ -577,7 +577,7 @@ static int ohci_hcd_pxa27x_drv_resume(struct device *dev)
 {
        struct usb_hcd *hcd = dev_get_drvdata(dev);
        struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd);
-       struct pxaohci_platform_data *inf = dev->platform_data;
+       struct pxaohci_platform_data *inf = dev_get_platdata(dev);
        int status;
 
        if (time_before(jiffies, ohci->ohci.next_statechange))
index e125770b893c391ae59a6ab456f7ef80d19c32a9..4919afa4125e36eaeed297277da4631cb9cb5c7b 100644 (file)
@@ -38,12 +38,12 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc);
 
 static struct s3c2410_hcd_info *to_s3c2410_info(struct usb_hcd *hcd)
 {
-       return hcd->self.controller->platform_data;
+       return dev_get_platdata(hcd->self.controller);
 }
 
 static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd)
 {
-       struct s3c2410_hcd_info *info = dev->dev.platform_data;
+       struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev);
 
        dev_dbg(&dev->dev, "s3c2410_start_hc:\n");
 
@@ -63,7 +63,7 @@ static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd)
 
 static void s3c2410_stop_hc(struct platform_device *dev)
 {
-       struct s3c2410_hcd_info *info = dev->dev.platform_data;
+       struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev);
 
        dev_dbg(&dev->dev, "s3c2410_stop_hc:\n");
 
@@ -339,10 +339,11 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver,
                                  struct platform_device *dev)
 {
        struct usb_hcd *hcd = NULL;
+       struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev);
        int retval;
 
-       s3c2410_usb_set_power(dev->dev.platform_data, 1, 1);
-       s3c2410_usb_set_power(dev->dev.platform_data, 2, 1);
+       s3c2410_usb_set_power(info, 1, 1);
+       s3c2410_usb_set_power(info, 2, 1);
 
        hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx");
        if (hcd == NULL)
index 197d514fe0d163741d6b6ac3fbb8fa62404c06c5..22540ab71f555dd9c60b461216cd46b2bbfb82ee 100644 (file)
@@ -95,7 +95,7 @@ static const struct hc_driver ohci_tilegx_hc_driver = {
 static int ohci_hcd_tilegx_drv_probe(struct platform_device *pdev)
 {
        struct usb_hcd *hcd;
-       struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data;
+       struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
        pte_t pte = { 0 };
        int my_cpu = smp_processor_id();
        int ret;
@@ -175,7 +175,7 @@ err_hcd:
 static int ohci_hcd_tilegx_drv_remove(struct platform_device *pdev)
 {
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
-       struct tilegx_usb_platform_data* pdata = pdev->dev.platform_data;
+       struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
        usb_remove_hcd(hcd);
        usb_put_hcd(hcd);
index b9848e4d3d44c8788bfbc43ce196c3b48beae7b4..2c76ef1320eab679e1dd1aabd1c8466981392efc 100644 (file)
@@ -735,32 +735,6 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done,
        return -ETIMEDOUT;
 }
 
-#define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI    0x8C31
-#define PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI 0x9C31
-
-bool usb_is_intel_ppt_switchable_xhci(struct pci_dev *pdev)
-{
-       return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
-               pdev->vendor == PCI_VENDOR_ID_INTEL &&
-               pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI;
-}
-
-/* The Intel Lynx Point chipset also has switchable ports. */
-bool usb_is_intel_lpt_switchable_xhci(struct pci_dev *pdev)
-{
-       return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
-               pdev->vendor == PCI_VENDOR_ID_INTEL &&
-               (pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI ||
-                pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI);
-}
-
-bool usb_is_intel_switchable_xhci(struct pci_dev *pdev)
-{
-       return usb_is_intel_ppt_switchable_xhci(pdev) ||
-               usb_is_intel_lpt_switchable_xhci(pdev);
-}
-EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci);
-
 /*
  * Intel's Panther Point chipset has two host controllers (EHCI and xHCI) that
  * share some number of ports.  These ports can be switched between either
@@ -779,9 +753,23 @@ EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci);
  * terminations before switching the USB 2.0 wires over, so that USB 3.0
  * devices connect at SuperSpeed, rather than at USB 2.0 speeds.
  */
-void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
+void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev)
 {
        u32             ports_available;
+       bool            ehci_found = false;
+       struct pci_dev  *companion = NULL;
+
+       /* make sure an intel EHCI controller exists */
+       for_each_pci_dev(companion) {
+               if (companion->class == PCI_CLASS_SERIAL_USB_EHCI &&
+                   companion->vendor == PCI_VENDOR_ID_INTEL) {
+                       ehci_found = true;
+                       break;
+               }
+       }
+
+       if (!ehci_found)
+               return;
 
        /* Don't switchover the ports if the user hasn't compiled the xHCI
         * driver.  Otherwise they will see "dead" USB ports that don't power
@@ -840,7 +828,7 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
        dev_dbg(&xhci_pdev->dev, "USB 2.0 ports that are now switched over "
                        "to xHCI: 0x%x\n", ports_available);
 }
-EXPORT_SYMBOL_GPL(usb_enable_xhci_ports);
+EXPORT_SYMBOL_GPL(usb_enable_intel_xhci_ports);
 
 void usb_disable_xhci_ports(struct pci_dev *xhci_pdev)
 {
@@ -921,8 +909,8 @@ static void quirk_usb_handoff_xhci(struct pci_dev *pdev)
        writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
 
 hc_init:
-       if (usb_is_intel_switchable_xhci(pdev))
-               usb_enable_xhci_ports(pdev);
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL)
+               usb_enable_intel_xhci_ports(pdev);
 
        op_reg_base = base + XHCI_HC_LENGTH(readl(base));
 
index 978c849f9c9a1ef9631d86fa80ccea93371f61ea..ed6700d00fe6fd372f62b575b49075b5ede392f1 100644 (file)
@@ -8,8 +8,7 @@ int usb_amd_find_chipset_info(void);
 void usb_amd_dev_put(void);
 void usb_amd_quirk_pll_disable(void);
 void usb_amd_quirk_pll_enable(void);
-bool usb_is_intel_switchable_xhci(struct pci_dev *pdev);
-void usb_enable_xhci_ports(struct pci_dev *xhci_pdev);
+void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev);
 void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
 void sb800_prefetch(struct device *dev, int on);
 #else
index a6fd8f5371dfd9f7c534fbf73ff2cc815f1bbdb1..a9eef6822a24d8565f5b6b1f0bf71f59aaca2a92 100644 (file)
@@ -2467,7 +2467,7 @@ static int r8a66597_probe(struct platform_device *pdev)
        r8a66597 = hcd_to_r8a66597(hcd);
        memset(r8a66597, 0, sizeof(struct r8a66597));
        dev_set_drvdata(&pdev->dev, r8a66597);
-       r8a66597->pdata = pdev->dev.platform_data;
+       r8a66597->pdata = dev_get_platdata(&pdev->dev);
        r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
 
        if (r8a66597->pdata->on_chip) {
index b2ec7fe758ddcf3dba22f922493ca6cebdeaea10..5477bf5df2186549412612dc016e809fa6970124 100644 (file)
@@ -48,6 +48,8 @@
 #include <linux/usb/hcd.h>
 #include <linux/platform_device.h>
 #include <linux/prefetch.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -63,11 +65,6 @@ MODULE_ALIAS("platform:sl811-hcd");
 
 #define DRIVER_VERSION "19 May 2005"
 
-
-#ifndef DEBUG
-#      define  STUB_DEBUG_FILE
-#endif
-
 /* for now, use only one transfer register bank */
 #undef USE_B
 
@@ -100,7 +97,8 @@ static void port_power(struct sl811 *sl811, int is_on)
 
        if (sl811->board && sl811->board->port_power) {
                /* switch VBUS, at 500mA unless hub power budget gets set */
-               DBG("power %s\n", is_on ? "on" : "off");
+               dev_dbg(hcd->self.controller, "power %s\n",
+                       is_on ? "on" : "off");
                sl811->board->port_power(hcd->self.controller, is_on);
        }
 
@@ -282,7 +280,7 @@ static inline void sofirq_on(struct sl811 *sl811)
 {
        if (sl811->irq_enable & SL11H_INTMASK_SOFINTR)
                return;
-       VDBG("sof irq on\n");
+       dev_dbg(sl811_to_hcd(sl811)->self.controller, "sof irq on\n");
        sl811->irq_enable |= SL11H_INTMASK_SOFINTR;
 }
 
@@ -290,7 +288,7 @@ static inline void sofirq_off(struct sl811 *sl811)
 {
        if (!(sl811->irq_enable & SL11H_INTMASK_SOFINTR))
                return;
-       VDBG("sof irq off\n");
+       dev_dbg(sl811_to_hcd(sl811)->self.controller, "sof irq off\n");
        sl811->irq_enable &= ~SL11H_INTMASK_SOFINTR;
 }
 
@@ -338,7 +336,8 @@ static struct sl811h_ep     *start(struct sl811 *sl811, u8 bank)
        }
 
        if (unlikely(list_empty(&ep->hep->urb_list))) {
-               DBG("empty %p queue?\n", ep);
+               dev_dbg(sl811_to_hcd(sl811)->self.controller,
+                       "empty %p queue?\n", ep);
                return NULL;
        }
 
@@ -391,7 +390,8 @@ static struct sl811h_ep     *start(struct sl811 *sl811, u8 bank)
                status_packet(sl811, ep, urb, bank, control);
                break;
        default:
-               DBG("bad ep%p pid %02x\n", ep, ep->nextpid);
+               dev_dbg(sl811_to_hcd(sl811)->self.controller,
+                       "bad ep%p pid %02x\n", ep, ep->nextpid);
                ep = NULL;
        }
        return ep;
@@ -447,7 +447,8 @@ static void finish_request(
        }
 
        /* periodic deschedule */
-       DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+       dev_dbg(sl811_to_hcd(sl811)->self.controller,
+               "deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
        for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
                struct sl811h_ep        *temp;
                struct sl811h_ep        **prev = &sl811->periodic[i];
@@ -593,7 +594,8 @@ static inline u8 checkdone(struct sl811 *sl811)
                ctl = sl811_read(sl811, SL811_EP_A(SL11H_HOSTCTLREG));
                if (ctl & SL11H_HCTLMASK_ARM)
                        sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0);
-               DBG("%s DONE_A: ctrl %02x sts %02x\n",
+               dev_dbg(sl811_to_hcd(sl811)->self.controller,
+                       "%s DONE_A: ctrl %02x sts %02x\n",
                        (ctl & SL11H_HCTLMASK_ARM) ? "timeout" : "lost",
                        ctl,
                        sl811_read(sl811, SL811_EP_A(SL11H_PKTSTATREG)));
@@ -604,7 +606,8 @@ static inline u8 checkdone(struct sl811 *sl811)
                ctl = sl811_read(sl811, SL811_EP_B(SL11H_HOSTCTLREG));
                if (ctl & SL11H_HCTLMASK_ARM)
                        sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0);
-               DBG("%s DONE_B: ctrl %02x sts %02x\n",
+               dev_dbg(sl811_to_hcd(sl811)->self.controller,
+                       "%s DONE_B: ctrl %02x sts %02x\n",
                        (ctl & SL11H_HCTLMASK_ARM) ? "timeout" : "lost",
                        ctl,
                        sl811_read(sl811, SL811_EP_B(SL11H_PKTSTATREG)));
@@ -665,7 +668,7 @@ retry:
                 * this one has nothing scheduled.
                 */
                if (sl811->next_periodic) {
-                       // ERR("overrun to slot %d\n", index);
+                       // dev_err(hcd->self.controller, "overrun to slot %d\n", index);
                        sl811->stat_overrun++;
                }
                if (sl811->periodic[index])
@@ -723,7 +726,7 @@ retry:
 
        } else if (irqstat & SL11H_INTMASK_RD) {
                if (sl811->port1 & USB_PORT_STAT_SUSPEND) {
-                       DBG("wakeup\n");
+                       dev_dbg(hcd->self.controller, "wakeup\n");
                        sl811->port1 |= USB_PORT_STAT_C_SUSPEND << 16;
                        sl811->stat_wake++;
                } else
@@ -852,8 +855,9 @@ static int sl811h_urb_enqueue(
 
                if (ep->maxpacket > H_MAXPACKET) {
                        /* iso packets up to 240 bytes could work... */
-                       DBG("dev %d ep%d maxpacket %d\n",
-                               udev->devnum, epnum, ep->maxpacket);
+                       dev_dbg(hcd->self.controller,
+                               "dev %d ep%d maxpacket %d\n", udev->devnum,
+                               epnum, ep->maxpacket);
                        retval = -EINVAL;
                        kfree(ep);
                        goto fail;
@@ -917,7 +921,8 @@ static int sl811h_urb_enqueue(
                 * to share the faster parts of the tree without needing
                 * dummy/placeholder nodes
                 */
-               DBG("schedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+               dev_dbg(hcd->self.controller, "schedule qh%d/%p branch %d\n",
+                       ep->period, ep, ep->branch);
                for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
                        struct sl811h_ep        **prev = &sl811->periodic[i];
                        struct sl811h_ep        *here = *prev;
@@ -976,7 +981,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                } else if (sl811->active_a == ep) {
                        if (time_before_eq(sl811->jiffies_a, jiffies)) {
                                /* happens a lot with lowspeed?? */
-                               DBG("giveup on DONE_A: ctrl %02x sts %02x\n",
+                               dev_dbg(hcd->self.controller,
+                                       "giveup on DONE_A: ctrl %02x sts %02x\n",
                                        sl811_read(sl811,
                                                SL811_EP_A(SL11H_HOSTCTLREG)),
                                        sl811_read(sl811,
@@ -990,7 +996,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                } else if (sl811->active_b == ep) {
                        if (time_before_eq(sl811->jiffies_a, jiffies)) {
                                /* happens a lot with lowspeed?? */
-                               DBG("giveup on DONE_B: ctrl %02x sts %02x\n",
+                               dev_dbg(hcd->self.controller,
+                                       "giveup on DONE_B: ctrl %02x sts %02x\n",
                                        sl811_read(sl811,
                                                SL811_EP_B(SL11H_HOSTCTLREG)),
                                        sl811_read(sl811,
@@ -1008,7 +1015,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                if (urb)
                        finish_request(sl811, ep, urb, 0);
                else
-                       VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
+                       dev_dbg(sl811_to_hcd(sl811)->self.controller,
+                               "dequeue, urb %p active %s; wait4irq\n", urb,
                                (sl811->active_a == ep) ? "A" : "B");
        } else
                retval = -EINVAL;
@@ -1029,7 +1037,7 @@ sl811h_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
        if (!list_empty(&hep->urb_list))
                msleep(3);
        if (!list_empty(&hep->urb_list))
-               WARNING("ep %p not empty?\n", ep);
+               dev_warn(hcd->self.controller, "ep %p not empty?\n", ep);
 
        kfree(ep);
        hep->hcpriv = NULL;
@@ -1132,7 +1140,7 @@ sl811h_timer(unsigned long _sl811)
 
        switch (signaling) {
        case SL11H_CTL1MASK_SE0:
-               DBG("end reset\n");
+               dev_dbg(sl811_to_hcd(sl811)->self.controller, "end reset\n");
                sl811->port1 = (USB_PORT_STAT_C_RESET << 16)
                                 | USB_PORT_STAT_POWER;
                sl811->ctrl1 = 0;
@@ -1141,11 +1149,12 @@ sl811h_timer(unsigned long _sl811)
                        irqstat &= ~SL11H_INTMASK_RD;
                break;
        case SL11H_CTL1MASK_K:
-               DBG("end resume\n");
+               dev_dbg(sl811_to_hcd(sl811)->self.controller, "end resume\n");
                sl811->port1 &= ~USB_PORT_STAT_SUSPEND;
                break;
        default:
-               DBG("odd timer signaling: %02x\n", signaling);
+               dev_dbg(sl811_to_hcd(sl811)->self.controller,
+                       "odd timer signaling: %02x\n", signaling);
                break;
        }
        sl811_write(sl811, SL11H_IRQ_STATUS, irqstat);
@@ -1243,7 +1252,7 @@ sl811h_hub_control(
                                break;
 
                        /* 20 msec of resume/K signaling, other irqs blocked */
-                       DBG("start resume...\n");
+                       dev_dbg(hcd->self.controller, "start resume...\n");
                        sl811->irq_enable = 0;
                        sl811_write(sl811, SL11H_IRQ_ENABLE,
                                                sl811->irq_enable);
@@ -1281,7 +1290,8 @@ sl811h_hub_control(
 #ifndef        VERBOSE
        if (*(u16*)(buf+2))     /* only if wPortChange is interesting */
 #endif
-               DBG("GetPortStatus %08x\n", sl811->port1);
+               dev_dbg(hcd->self.controller, "GetPortStatus %08x\n",
+                       sl811->port1);
                break;
        case SetPortFeature:
                if (wIndex != 1 || wLength != 0)
@@ -1293,7 +1303,7 @@ sl811h_hub_control(
                        if (!(sl811->port1 & USB_PORT_STAT_ENABLE))
                                goto error;
 
-                       DBG("suspend...\n");
+                       dev_dbg(hcd->self.controller,"suspend...\n");
                        sl811->ctrl1 &= ~SL11H_CTL1MASK_SOF_ENA;
                        sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
                        break;
@@ -1338,7 +1348,7 @@ static int
 sl811h_bus_suspend(struct usb_hcd *hcd)
 {
        // SOFs off
-       DBG("%s\n", __func__);
+       dev_dbg(hcd->self.controller, "%s\n", __func__);
        return 0;
 }
 
@@ -1346,7 +1356,7 @@ static int
 sl811h_bus_resume(struct usb_hcd *hcd)
 {
        // SOFs on
-       DBG("%s\n", __func__);
+       dev_dbg(hcd->self.controller, "%s\n", __func__);
        return 0;
 }
 
@@ -1360,16 +1370,6 @@ sl811h_bus_resume(struct usb_hcd *hcd)
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef STUB_DEBUG_FILE
-
-static inline void create_debug_file(struct sl811 *sl811) { }
-static inline void remove_debug_file(struct sl811 *sl811) { }
-
-#else
-
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-
 static void dump_irq(struct seq_file *s, char *label, u8 mask)
 {
        seq_printf(s, "%s %02x%s%s%s%s%s%s\n", label, mask,
@@ -1381,7 +1381,7 @@ static void dump_irq(struct seq_file *s, char *label, u8 mask)
                (mask & SL11H_INTMASK_DP) ? " dp" : "");
 }
 
-static int proc_sl811h_show(struct seq_file *s, void *unused)
+static int sl811h_show(struct seq_file *s, void *unused)
 {
        struct sl811            *sl811 = s->private;
        struct sl811h_ep        *ep;
@@ -1492,34 +1492,31 @@ static int proc_sl811h_show(struct seq_file *s, void *unused)
        return 0;
 }
 
-static int proc_sl811h_open(struct inode *inode, struct file *file)
+static int sl811h_open(struct inode *inode, struct file *file)
 {
-       return single_open(file, proc_sl811h_show, PDE_DATA(inode));
+       return single_open(file, sl811h_show, inode->i_private);
 }
 
-static const struct file_operations proc_ops = {
-       .open           = proc_sl811h_open,
+static const struct file_operations debug_ops = {
+       .open           = sl811h_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
        .release        = single_release,
 };
 
 /* expect just one sl811 per system */
-static const char proc_filename[] = "driver/sl811h";
-
 static void create_debug_file(struct sl811 *sl811)
 {
-       sl811->pde = proc_create_data(proc_filename, 0, NULL, &proc_ops, sl811);
+       sl811->debug_file = debugfs_create_file("sl811h", S_IRUGO,
+                                               usb_debug_root, sl811,
+                                               &debug_ops);
 }
 
 static void remove_debug_file(struct sl811 *sl811)
 {
-       if (sl811->pde)
-               remove_proc_entry(proc_filename, NULL);
+       debugfs_remove(sl811->debug_file);
 }
 
-#endif
-
 /*-------------------------------------------------------------------------*/
 
 static void
@@ -1648,7 +1645,7 @@ sl811h_probe(struct platform_device *dev)
 
        /* refuse to confuse usbcore */
        if (dev->dev.dma_mask) {
-               DBG("no we won't dma\n");
+               dev_dbg(&dev->dev, "no we won't dma\n");
                return -EINVAL;
        }
 
@@ -1694,7 +1691,7 @@ sl811h_probe(struct platform_device *dev)
 
        spin_lock_init(&sl811->lock);
        INIT_LIST_HEAD(&sl811->async);
-       sl811->board = dev->dev.platform_data;
+       sl811->board = dev_get_platdata(&dev->dev);
        init_timer(&sl811->timer);
        sl811->timer.function = sl811h_timer;
        sl811->timer.data = (unsigned long) sl811;
@@ -1716,7 +1713,7 @@ sl811h_probe(struct platform_device *dev)
                break;
        default:
                /* reject case 0, SL11S is less functional */
-               DBG("chiprev %02x\n", tmp);
+               dev_dbg(&dev->dev, "chiprev %02x\n", tmp);
                retval = -ENXIO;
                goto err6;
        }
@@ -1747,7 +1744,7 @@ sl811h_probe(struct platform_device *dev)
        if (!ioaddr)
                iounmap(addr_reg);
  err2:
-       DBG("init error, %d\n", retval);
+       dev_dbg(&dev->dev, "init error, %d\n", retval);
        return retval;
 }
 
index b6b8c1f233dd8caa62caebf5b44c92a8480a9b37..1e23ef49bec15977ff8af019703627c7e85e2233 100644 (file)
@@ -122,7 +122,7 @@ struct sl811 {
        void __iomem            *addr_reg;
        void __iomem            *data_reg;
        struct sl811_platform_data      *board;
-       struct proc_dir_entry   *pde;
+       struct dentry           *debug_file;
 
        unsigned long           stat_insrmv;
        unsigned long           stat_wake;
@@ -242,25 +242,8 @@ sl811_read_buf(struct sl811 *sl811, int addr, void *buf, size_t count)
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef DEBUG
-#define DBG(stuff...)          printk(KERN_DEBUG "sl811: " stuff)
-#else
-#define DBG(stuff...)          do{}while(0)
-#endif
-
-#ifdef VERBOSE
-#    define VDBG               DBG
-#else
-#    define VDBG(stuff...)     do{}while(0)
-#endif
-
 #ifdef PACKET_TRACE
-#    define PACKET             VDBG
+#    define PACKET             pr_debug("sl811: "stuff)
 #else
 #    define PACKET(stuff...)   do{}while(0)
 #endif
-
-#define ERR(stuff...)          printk(KERN_ERR "sl811: " stuff)
-#define WARNING(stuff...)      printk(KERN_WARNING "sl811: " stuff)
-#define INFO(stuff...)         printk(KERN_INFO "sl811: " stuff)
-
index 5c124bf5d01869c727543b34240deace3d27d1cd..e402beb5a06952e00948853a1845695fe2db69d3 100644 (file)
@@ -1809,9 +1809,9 @@ static int u132_hcd_start(struct usb_hcd *hcd)
                struct platform_device *pdev =
                        to_platform_device(hcd->self.controller);
                u16 vendor = ((struct u132_platform_data *)
-                       (pdev->dev.platform_data))->vendor;
+                       dev_get_platdata(&pdev->dev))->vendor;
                u16 device = ((struct u132_platform_data *)
-                       (pdev->dev.platform_data))->device;
+                       dev_get_platdata(&pdev->dev))->device;
                mutex_lock(&u132->sw_lock);
                msleep(10);
                if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
@@ -3034,7 +3034,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
        int addrs = MAX_U132_ADDRS;
        int udevs = MAX_U132_UDEVS;
        int endps = MAX_U132_ENDPS;
-       u132->board = pdev->dev.platform_data;
+       u132->board = dev_get_platdata(&pdev->dev);
        u132->platform_dev = pdev;
        u132->power = 0;
        u132->reset = 0;
index 5d5e58fdeccc07604179a419c97414a71def5150..73503a81ee813ba371eefa606670a619bdd7a027 100644 (file)
@@ -580,3 +580,17 @@ void xhci_dbg_ctx(struct xhci_hcd *xhci,
        xhci_dbg_slot_ctx(xhci, ctx);
        xhci_dbg_ep_ctx(xhci, ctx, last_ep);
 }
+
+void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *),
+                       const char *fmt, ...)
+{
+       struct va_format vaf;
+       va_list args;
+
+       va_start(args, fmt);
+       vaf.fmt = fmt;
+       vaf.va = &args;
+       xhci_dbg(xhci, "%pV\n", &vaf);
+       trace(&vaf);
+       va_end(args);
+}
index 1d3545943c50a792de25a35a4cfc150b4c5ac347..fae697ed0b708352e06e6e6135a2b49ece4ea34a 100644 (file)
@@ -24,6 +24,7 @@
 #include <asm/unaligned.h>
 
 #include "xhci.h"
+#include "xhci-trace.h"
 
 #define        PORT_WAKE_BITS  (PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E)
 #define        PORT_RWC_BITS   (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
@@ -461,8 +462,15 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
        }
 }
 
+/* Updates Link Status for USB 2.1 port */
+static void xhci_hub_report_usb2_link_state(u32 *status, u32 status_reg)
+{
+       if ((status_reg & PORT_PLS_MASK) == XDEV_U2)
+               *status |= USB_PORT_STAT_L1;
+}
+
 /* Updates Link Status for super Speed port */
-static void xhci_hub_report_link_state(u32 *status, u32 status_reg)
+static void xhci_hub_report_usb3_link_state(u32 *status, u32 status_reg)
 {
        u32 pls = status_reg & PORT_PLS_MASK;
 
@@ -528,12 +536,128 @@ void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex)
                xhci->port_status_u0 |= 1 << wIndex;
                if (xhci->port_status_u0 == all_ports_seen_u0) {
                        del_timer_sync(&xhci->comp_mode_recovery_timer);
-                       xhci_dbg(xhci, "All USB3 ports have entered U0 already!\n");
-                       xhci_dbg(xhci, "Compliance Mode Recovery Timer Deleted.\n");
+                       xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "All USB3 ports have entered U0 already!");
+                       xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "Compliance Mode Recovery Timer Deleted.");
                }
        }
 }
 
+/*
+ * Converts a raw xHCI port status into the format that external USB 2.0 or USB
+ * 3.0 hubs use.
+ *
+ * Possible side effects:
+ *  - Mark a port as being done with device resume,
+ *    and ring the endpoint doorbells.
+ *  - Stop the Synopsys redriver Compliance Mode polling.
+ */
+static u32 xhci_get_port_status(struct usb_hcd *hcd,
+               struct xhci_bus_state *bus_state,
+               __le32 __iomem **port_array,
+               u16 wIndex, u32 raw_port_status)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       u32 status = 0;
+       int slot_id;
+
+       /* wPortChange bits */
+       if (raw_port_status & PORT_CSC)
+               status |= USB_PORT_STAT_C_CONNECTION << 16;
+       if (raw_port_status & PORT_PEC)
+               status |= USB_PORT_STAT_C_ENABLE << 16;
+       if ((raw_port_status & PORT_OCC))
+               status |= USB_PORT_STAT_C_OVERCURRENT << 16;
+       if ((raw_port_status & PORT_RC))
+               status |= USB_PORT_STAT_C_RESET << 16;
+       /* USB3.0 only */
+       if (hcd->speed == HCD_USB3) {
+               if ((raw_port_status & PORT_PLC))
+                       status |= USB_PORT_STAT_C_LINK_STATE << 16;
+               if ((raw_port_status & PORT_WRC))
+                       status |= USB_PORT_STAT_C_BH_RESET << 16;
+       }
+
+       if (hcd->speed != HCD_USB3) {
+               if ((raw_port_status & PORT_PLS_MASK) == XDEV_U3
+                               && (raw_port_status & PORT_POWER))
+                       status |= USB_PORT_STAT_SUSPEND;
+       }
+       if ((raw_port_status & PORT_PLS_MASK) == XDEV_RESUME &&
+                       !DEV_SUPERSPEED(raw_port_status)) {
+               if ((raw_port_status & PORT_RESET) ||
+                               !(raw_port_status & PORT_PE))
+                       return 0xffffffff;
+               if (time_after_eq(jiffies,
+                                       bus_state->resume_done[wIndex])) {
+                       xhci_dbg(xhci, "Resume USB2 port %d\n",
+                                       wIndex + 1);
+                       bus_state->resume_done[wIndex] = 0;
+                       clear_bit(wIndex, &bus_state->resuming_ports);
+                       xhci_set_link_state(xhci, port_array, wIndex,
+                                       XDEV_U0);
+                       xhci_dbg(xhci, "set port %d resume\n",
+                                       wIndex + 1);
+                       slot_id = xhci_find_slot_id_by_port(hcd, xhci,
+                                       wIndex + 1);
+                       if (!slot_id) {
+                               xhci_dbg(xhci, "slot_id is zero\n");
+                               return 0xffffffff;
+                       }
+                       xhci_ring_device(xhci, slot_id);
+                       bus_state->port_c_suspend |= 1 << wIndex;
+                       bus_state->suspended_ports &= ~(1 << wIndex);
+               } else {
+                       /*
+                        * The resume has been signaling for less than
+                        * 20ms. Report the port status as SUSPEND,
+                        * let the usbcore check port status again
+                        * and clear resume signaling later.
+                        */
+                       status |= USB_PORT_STAT_SUSPEND;
+               }
+       }
+       if ((raw_port_status & PORT_PLS_MASK) == XDEV_U0
+                       && (raw_port_status & PORT_POWER)
+                       && (bus_state->suspended_ports & (1 << wIndex))) {
+               bus_state->suspended_ports &= ~(1 << wIndex);
+               if (hcd->speed != HCD_USB3)
+                       bus_state->port_c_suspend |= 1 << wIndex;
+       }
+       if (raw_port_status & PORT_CONNECT) {
+               status |= USB_PORT_STAT_CONNECTION;
+               status |= xhci_port_speed(raw_port_status);
+       }
+       if (raw_port_status & PORT_PE)
+               status |= USB_PORT_STAT_ENABLE;
+       if (raw_port_status & PORT_OC)
+               status |= USB_PORT_STAT_OVERCURRENT;
+       if (raw_port_status & PORT_RESET)
+               status |= USB_PORT_STAT_RESET;
+       if (raw_port_status & PORT_POWER) {
+               if (hcd->speed == HCD_USB3)
+                       status |= USB_SS_PORT_STAT_POWER;
+               else
+                       status |= USB_PORT_STAT_POWER;
+       }
+       /* Update Port Link State */
+       if (hcd->speed == HCD_USB3) {
+               xhci_hub_report_usb3_link_state(&status, raw_port_status);
+               /*
+                * Verify if all USB3 Ports Have entered U0 already.
+                * Delete Compliance Mode Timer if so.
+                */
+               xhci_del_comp_mod_timer(xhci, raw_port_status, wIndex);
+       } else {
+               xhci_hub_report_usb2_link_state(&status, raw_port_status);
+       }
+       if (bus_state->port_c_suspend & (1 << wIndex))
+               status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+
+       return status;
+}
+
 int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                u16 wIndex, char *buf, u16 wLength)
 {
@@ -598,104 +722,20 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                if (!wIndex || wIndex > max_ports)
                        goto error;
                wIndex--;
-               status = 0;
                temp = xhci_readl(xhci, port_array[wIndex]);
                if (temp == 0xffffffff) {
                        retval = -ENODEV;
                        break;
                }
-               xhci_dbg(xhci, "get port status, actual port %d status  = 0x%x\n", wIndex, temp);
-
-               /* wPortChange bits */
-               if (temp & PORT_CSC)
-                       status |= USB_PORT_STAT_C_CONNECTION << 16;
-               if (temp & PORT_PEC)
-                       status |= USB_PORT_STAT_C_ENABLE << 16;
-               if ((temp & PORT_OCC))
-                       status |= USB_PORT_STAT_C_OVERCURRENT << 16;
-               if ((temp & PORT_RC))
-                       status |= USB_PORT_STAT_C_RESET << 16;
-               /* USB3.0 only */
-               if (hcd->speed == HCD_USB3) {
-                       if ((temp & PORT_PLC))
-                               status |= USB_PORT_STAT_C_LINK_STATE << 16;
-                       if ((temp & PORT_WRC))
-                               status |= USB_PORT_STAT_C_BH_RESET << 16;
-               }
+               status = xhci_get_port_status(hcd, bus_state, port_array,
+                               wIndex, temp);
+               if (status == 0xffffffff)
+                       goto error;
 
-               if (hcd->speed != HCD_USB3) {
-                       if ((temp & PORT_PLS_MASK) == XDEV_U3
-                                       && (temp & PORT_POWER))
-                               status |= USB_PORT_STAT_SUSPEND;
-               }
-               if ((temp & PORT_PLS_MASK) == XDEV_RESUME &&
-                               !DEV_SUPERSPEED(temp)) {
-                       if ((temp & PORT_RESET) || !(temp & PORT_PE))
-                               goto error;
-                       if (time_after_eq(jiffies,
-                                       bus_state->resume_done[wIndex])) {
-                               xhci_dbg(xhci, "Resume USB2 port %d\n",
-                                       wIndex + 1);
-                               bus_state->resume_done[wIndex] = 0;
-                               clear_bit(wIndex, &bus_state->resuming_ports);
-                               xhci_set_link_state(xhci, port_array, wIndex,
-                                                       XDEV_U0);
-                               xhci_dbg(xhci, "set port %d resume\n",
-                                       wIndex + 1);
-                               slot_id = xhci_find_slot_id_by_port(hcd, xhci,
-                                                                wIndex + 1);
-                               if (!slot_id) {
-                                       xhci_dbg(xhci, "slot_id is zero\n");
-                                       goto error;
-                               }
-                               xhci_ring_device(xhci, slot_id);
-                               bus_state->port_c_suspend |= 1 << wIndex;
-                               bus_state->suspended_ports &= ~(1 << wIndex);
-                       } else {
-                               /*
-                                * The resume has been signaling for less than
-                                * 20ms. Report the port status as SUSPEND,
-                                * let the usbcore check port status again
-                                * and clear resume signaling later.
-                                */
-                               status |= USB_PORT_STAT_SUSPEND;
-                       }
-               }
-               if ((temp & PORT_PLS_MASK) == XDEV_U0
-                       && (temp & PORT_POWER)
-                       && (bus_state->suspended_ports & (1 << wIndex))) {
-                       bus_state->suspended_ports &= ~(1 << wIndex);
-                       if (hcd->speed != HCD_USB3)
-                               bus_state->port_c_suspend |= 1 << wIndex;
-               }
-               if (temp & PORT_CONNECT) {
-                       status |= USB_PORT_STAT_CONNECTION;
-                       status |= xhci_port_speed(temp);
-               }
-               if (temp & PORT_PE)
-                       status |= USB_PORT_STAT_ENABLE;
-               if (temp & PORT_OC)
-                       status |= USB_PORT_STAT_OVERCURRENT;
-               if (temp & PORT_RESET)
-                       status |= USB_PORT_STAT_RESET;
-               if (temp & PORT_POWER) {
-                       if (hcd->speed == HCD_USB3)
-                               status |= USB_SS_PORT_STAT_POWER;
-                       else
-                               status |= USB_PORT_STAT_POWER;
-               }
-               /* Update Port Link State for super speed ports*/
-               if (hcd->speed == HCD_USB3) {
-                       xhci_hub_report_link_state(&status, temp);
-                       /*
-                        * Verify if all USB3 Ports Have entered U0 already.
-                        * Delete Compliance Mode Timer if so.
-                        */
-                       xhci_del_comp_mod_timer(xhci, temp, wIndex);
-               }
-               if (bus_state->port_c_suspend & (1 << wIndex))
-                       status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+               xhci_dbg(xhci, "get port status, actual port %d status  = 0x%x\n",
+                               wIndex, temp);
                xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
+
                put_unaligned(cpu_to_le32(status), (__le32 *) buf);
                break;
        case SetPortFeature:
index 6f8c2fd47675dc2432902f5fbf8b4cfec8a306de..53b972c2a09f10be38a474042d03757618bc76a4 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/dma-mapping.h>
 
 #include "xhci.h"
+#include "xhci-trace.h"
 
 /*
  * Allocates a generic ring segment from the ring pool, sets the dma address,
@@ -348,7 +349,8 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
                return -ENOMEM;
 
        xhci_link_rings(xhci, ring, first, last, num_segs);
-       xhci_dbg(xhci, "ring expansion succeed, now has %d segments\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_ring_expansion,
+                       "ring expansion succeed, now has %d segments",
                        ring->num_segs);
 
        return 0;
@@ -482,17 +484,6 @@ struct xhci_ring *xhci_dma_to_transfer_ring(
        return ep->ring;
 }
 
-/* Only use this when you know stream_info is valid */
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-static struct xhci_ring *dma_to_stream_ring(
-               struct xhci_stream_info *stream_info,
-               u64 address)
-{
-       return radix_tree_lookup(&stream_info->trb_address_map,
-                       address >> TRB_SEGMENT_SHIFT);
-}
-#endif /* CONFIG_USB_XHCI_HCD_DEBUGGING */
-
 struct xhci_ring *xhci_stream_id_to_ring(
                struct xhci_virt_device *dev,
                unsigned int ep_index,
@@ -510,58 +501,6 @@ struct xhci_ring *xhci_stream_id_to_ring(
        return ep->stream_info->stream_rings[stream_id];
 }
 
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-static int xhci_test_radix_tree(struct xhci_hcd *xhci,
-               unsigned int num_streams,
-               struct xhci_stream_info *stream_info)
-{
-       u32 cur_stream;
-       struct xhci_ring *cur_ring;
-       u64 addr;
-
-       for (cur_stream = 1; cur_stream < num_streams; cur_stream++) {
-               struct xhci_ring *mapped_ring;
-               int trb_size = sizeof(union xhci_trb);
-
-               cur_ring = stream_info->stream_rings[cur_stream];
-               for (addr = cur_ring->first_seg->dma;
-                               addr < cur_ring->first_seg->dma + TRB_SEGMENT_SIZE;
-                               addr += trb_size) {
-                       mapped_ring = dma_to_stream_ring(stream_info, addr);
-                       if (cur_ring != mapped_ring) {
-                               xhci_warn(xhci, "WARN: DMA address 0x%08llx "
-                                               "didn't map to stream ID %u; "
-                                               "mapped to ring %p\n",
-                                               (unsigned long long) addr,
-                                               cur_stream,
-                                               mapped_ring);
-                               return -EINVAL;
-                       }
-               }
-               /* One TRB after the end of the ring segment shouldn't return a
-                * pointer to the current ring (although it may be a part of a
-                * different ring).
-                */
-               mapped_ring = dma_to_stream_ring(stream_info, addr);
-               if (mapped_ring != cur_ring) {
-                       /* One TRB before should also fail */
-                       addr = cur_ring->first_seg->dma - trb_size;
-                       mapped_ring = dma_to_stream_ring(stream_info, addr);
-               }
-               if (mapped_ring == cur_ring) {
-                       xhci_warn(xhci, "WARN: Bad DMA address 0x%08llx "
-                                       "mapped to valid stream ID %u; "
-                                       "mapped ring = %p\n",
-                                       (unsigned long long) addr,
-                                       cur_stream,
-                                       mapped_ring);
-                       return -EINVAL;
-               }
-       }
-       return 0;
-}
-#endif /* CONFIG_USB_XHCI_HCD_DEBUGGING */
-
 /*
  * Change an endpoint's internal structure so it supports stream IDs.  The
  * number of requested streams includes stream 0, which cannot be used by device
@@ -688,13 +627,6 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
         * was any other way, the host controller would assume the ring is
         * "empty" and wait forever for data to be queued to that stream ID).
         */
-#if XHCI_DEBUG
-       /* Do a little test on the radix tree to make sure it returns the
-        * correct values.
-        */
-       if (xhci_test_radix_tree(xhci, num_streams, stream_info))
-               goto cleanup_rings;
-#endif
 
        return stream_info;
 
@@ -732,7 +664,8 @@ void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci,
         * fls(0) = 0, fls(0x1) = 1, fls(0x10) = 2, fls(0x100) = 3, etc.
         */
        max_primary_streams = fls(stream_info->num_stream_ctxs) - 2;
-       xhci_dbg(xhci, "Setting number of stream ctx array entries to %u\n",
+       xhci_dbg_trace(xhci,  trace_xhci_dbg_context_change,
+                       "Setting number of stream ctx array entries to %u",
                        1 << (max_primary_streams + 1));
        ep_ctx->ep_info &= cpu_to_le32(~EP_MAXPSTREAMS_MASK);
        ep_ctx->ep_info |= cpu_to_le32(EP_MAXPSTREAMS(max_primary_streams)
@@ -1614,7 +1547,8 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
        struct device *dev = xhci_to_hcd(xhci)->self.controller;
        int num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2);
 
-       xhci_dbg(xhci, "Allocating %d scratchpad buffers\n", num_sp);
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "Allocating %d scratchpad buffers", num_sp);
 
        if (!num_sp)
                return 0;
@@ -1771,11 +1705,11 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
                dma_free_coherent(&pdev->dev, size,
                                xhci->erst.entries, xhci->erst.erst_dma_addr);
        xhci->erst.entries = NULL;
-       xhci_dbg(xhci, "Freed ERST\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed ERST");
        if (xhci->event_ring)
                xhci_ring_free(xhci, xhci->event_ring);
        xhci->event_ring = NULL;
-       xhci_dbg(xhci, "Freed event ring\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed event ring");
 
        if (xhci->lpm_command)
                xhci_free_command(xhci, xhci->lpm_command);
@@ -1783,7 +1717,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
        if (xhci->cmd_ring)
                xhci_ring_free(xhci, xhci->cmd_ring);
        xhci->cmd_ring = NULL;
-       xhci_dbg(xhci, "Freed command ring\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed command ring");
        list_for_each_entry_safe(cur_cd, next_cd,
                        &xhci->cancel_cmd_list, cancel_cmd_list) {
                list_del(&cur_cd->cancel_cmd_list);
@@ -1796,22 +1730,24 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
        if (xhci->segment_pool)
                dma_pool_destroy(xhci->segment_pool);
        xhci->segment_pool = NULL;
-       xhci_dbg(xhci, "Freed segment pool\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed segment pool");
 
        if (xhci->device_pool)
                dma_pool_destroy(xhci->device_pool);
        xhci->device_pool = NULL;
-       xhci_dbg(xhci, "Freed device context pool\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed device context pool");
 
        if (xhci->small_streams_pool)
                dma_pool_destroy(xhci->small_streams_pool);
        xhci->small_streams_pool = NULL;
-       xhci_dbg(xhci, "Freed small stream array pool\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "Freed small stream array pool");
 
        if (xhci->medium_streams_pool)
                dma_pool_destroy(xhci->medium_streams_pool);
        xhci->medium_streams_pool = NULL;
-       xhci_dbg(xhci, "Freed medium stream array pool\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "Freed medium stream array pool");
 
        if (xhci->dcbaa)
                dma_free_coherent(&pdev->dev, sizeof(*xhci->dcbaa),
@@ -2037,8 +1973,9 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
         * there might be more events to service.
         */
        temp &= ~ERST_EHB;
-       xhci_dbg(xhci, "// Write event ring dequeue pointer, "
-                       "preserving EHB bit\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "// Write event ring dequeue pointer, "
+                       "preserving EHB bit");
        xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp,
                        &xhci->ir_set->erst_dequeue);
 }
@@ -2061,8 +1998,9 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
        temp = xhci_readl(xhci, addr + 2);
        port_offset = XHCI_EXT_PORT_OFF(temp);
        port_count = XHCI_EXT_PORT_COUNT(temp);
-       xhci_dbg(xhci, "Ext Cap %p, port offset = %u, "
-                       "count = %u, revision = 0x%x\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "Ext Cap %p, port offset = %u, "
+                       "count = %u, revision = 0x%x",
                        addr, port_offset, port_count, major_revision);
        /* Port count includes the current port offset */
        if (port_offset == 0 || (port_offset + port_count - 1) > num_ports)
@@ -2076,15 +2014,18 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
        /* Check the host's USB2 LPM capability */
        if ((xhci->hci_version == 0x96) && (major_revision != 0x03) &&
                        (temp & XHCI_L1C)) {
-               xhci_dbg(xhci, "xHCI 0.96: support USB2 software lpm\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                               "xHCI 0.96: support USB2 software lpm");
                xhci->sw_lpm_support = 1;
        }
 
        if ((xhci->hci_version >= 0x100) && (major_revision != 0x03)) {
-               xhci_dbg(xhci, "xHCI 1.0: support USB2 software lpm\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                               "xHCI 1.0: support USB2 software lpm");
                xhci->sw_lpm_support = 1;
                if (temp & XHCI_HLC) {
-                       xhci_dbg(xhci, "xHCI 1.0: support USB2 hardware lpm\n");
+                       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                                       "xHCI 1.0: support USB2 hardware lpm");
                        xhci->hw_lpm_support = 1;
                }
        }
@@ -2208,18 +2149,21 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
                xhci_warn(xhci, "No ports on the roothubs?\n");
                return -ENODEV;
        }
-       xhci_dbg(xhci, "Found %u USB 2.0 ports and %u USB 3.0 ports.\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "Found %u USB 2.0 ports and %u USB 3.0 ports.",
                        xhci->num_usb2_ports, xhci->num_usb3_ports);
 
        /* Place limits on the number of roothub ports so that the hub
         * descriptors aren't longer than the USB core will allocate.
         */
        if (xhci->num_usb3_ports > 15) {
-               xhci_dbg(xhci, "Limiting USB 3.0 roothub ports to 15.\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                               "Limiting USB 3.0 roothub ports to 15.");
                xhci->num_usb3_ports = 15;
        }
        if (xhci->num_usb2_ports > USB_MAXCHILDREN) {
-               xhci_dbg(xhci, "Limiting USB 2.0 roothub ports to %u.\n",
+               xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                               "Limiting USB 2.0 roothub ports to %u.",
                                USB_MAXCHILDREN);
                xhci->num_usb2_ports = USB_MAXCHILDREN;
        }
@@ -2244,8 +2188,9 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
                        xhci->usb2_ports[port_index] =
                                &xhci->op_regs->port_status_base +
                                NUM_PORT_REGS*i;
-                       xhci_dbg(xhci, "USB 2.0 port at index %u, "
-                                       "addr = %p\n", i,
+                       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                                       "USB 2.0 port at index %u, "
+                                       "addr = %p", i,
                                        xhci->usb2_ports[port_index]);
                        port_index++;
                        if (port_index == xhci->num_usb2_ports)
@@ -2264,8 +2209,9 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
                                xhci->usb3_ports[port_index] =
                                        &xhci->op_regs->port_status_base +
                                        NUM_PORT_REGS*i;
-                               xhci_dbg(xhci, "USB 3.0 port at index %u, "
-                                               "addr = %p\n", i,
+                               xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                                               "USB 3.0 port at index %u, "
+                                               "addr = %p", i,
                                                xhci->usb3_ports[port_index]);
                                port_index++;
                                if (port_index == xhci->num_usb3_ports)
@@ -2289,32 +2235,35 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
        INIT_LIST_HEAD(&xhci->cancel_cmd_list);
 
        page_size = xhci_readl(xhci, &xhci->op_regs->page_size);
-       xhci_dbg(xhci, "Supported page size register = 0x%x\n", page_size);
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "Supported page size register = 0x%x", page_size);
        for (i = 0; i < 16; i++) {
                if ((0x1 & page_size) != 0)
                        break;
                page_size = page_size >> 1;
        }
        if (i < 16)
-               xhci_dbg(xhci, "Supported page size of %iK\n", (1 << (i+12)) / 1024);
+               xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "Supported page size of %iK", (1 << (i+12)) / 1024);
        else
                xhci_warn(xhci, "WARN: no supported page size\n");
        /* Use 4K pages, since that's common and the minimum the HC supports */
        xhci->page_shift = 12;
        xhci->page_size = 1 << xhci->page_shift;
-       xhci_dbg(xhci, "HCD page size set to %iK\n", xhci->page_size / 1024);
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "HCD page size set to %iK", xhci->page_size / 1024);
 
        /*
         * Program the Number of Device Slots Enabled field in the CONFIG
         * register with the max value of slots the HC can handle.
         */
        val = HCS_MAX_SLOTS(xhci_readl(xhci, &xhci->cap_regs->hcs_params1));
-       xhci_dbg(xhci, "// xHC can handle at most %d device slots.\n",
-                       (unsigned int) val);
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "// xHC can handle at most %d device slots.", val);
        val2 = xhci_readl(xhci, &xhci->op_regs->config_reg);
        val |= (val2 & ~HCS_SLOTS_MASK);
-       xhci_dbg(xhci, "// Setting Max device slots reg = 0x%x.\n",
-                       (unsigned int) val);
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "// Setting Max device slots reg = 0x%x.", val);
        xhci_writel(xhci, val, &xhci->op_regs->config_reg);
 
        /*
@@ -2327,7 +2276,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
                goto fail;
        memset(xhci->dcbaa, 0, sizeof *(xhci->dcbaa));
        xhci->dcbaa->dma = dma;
-       xhci_dbg(xhci, "// Device context base array address = 0x%llx (DMA), %p (virt)\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "// Device context base array address = 0x%llx (DMA), %p (virt)",
                        (unsigned long long)xhci->dcbaa->dma, xhci->dcbaa);
        xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr);
 
@@ -2366,8 +2316,9 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
        xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags);
        if (!xhci->cmd_ring)
                goto fail;
-       xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring);
-       xhci_dbg(xhci, "First segment DMA is 0x%llx\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "Allocated command ring at %p", xhci->cmd_ring);
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "First segment DMA is 0x%llx",
                        (unsigned long long)xhci->cmd_ring->first_seg->dma);
 
        /* Set the address in the Command Ring Control register */
@@ -2375,7 +2326,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
        val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
                (xhci->cmd_ring->first_seg->dma & (u64) ~CMD_RING_RSVD_BITS) |
                xhci->cmd_ring->cycle_state;
-       xhci_dbg(xhci, "// Setting command ring address to 0x%x\n", val);
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "// Setting command ring address to 0x%x", val);
        xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
        xhci_dbg_cmd_ptrs(xhci);
 
@@ -2391,8 +2343,9 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
 
        val = xhci_readl(xhci, &xhci->cap_regs->db_off);
        val &= DBOFF_MASK;
-       xhci_dbg(xhci, "// Doorbell array is located at offset 0x%x"
-                       " from cap regs base addr\n", val);
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "// Doorbell array is located at offset 0x%x"
+                       " from cap regs base addr", val);
        xhci->dba = (void __iomem *) xhci->cap_regs + val;
        xhci_dbg_regs(xhci);
        xhci_print_run_regs(xhci);
@@ -2403,7 +2356,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
         * Event ring setup: Allocate a normal ring, but also setup
         * the event ring segment table (ERST).  Section 4.9.3.
         */
-       xhci_dbg(xhci, "// Allocating event ring\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring");
        xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
                                                flags);
        if (!xhci->event_ring)
@@ -2416,13 +2369,15 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
                        GFP_KERNEL);
        if (!xhci->erst.entries)
                goto fail;
-       xhci_dbg(xhci, "// Allocated event ring segment table at 0x%llx\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "// Allocated event ring segment table at 0x%llx",
                        (unsigned long long)dma);
 
        memset(xhci->erst.entries, 0, sizeof(struct xhci_erst_entry)*ERST_NUM_SEGS);
        xhci->erst.num_entries = ERST_NUM_SEGS;
        xhci->erst.erst_dma_addr = dma;
-       xhci_dbg(xhci, "Set ERST to 0; private num segs = %i, virt addr = %p, dma addr = 0x%llx\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "Set ERST to 0; private num segs = %i, virt addr = %p, dma addr = 0x%llx",
                        xhci->erst.num_entries,
                        xhci->erst.entries,
                        (unsigned long long)xhci->erst.erst_dma_addr);
@@ -2440,13 +2395,16 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
        val = xhci_readl(xhci, &xhci->ir_set->erst_size);
        val &= ERST_SIZE_MASK;
        val |= ERST_NUM_SEGS;
-       xhci_dbg(xhci, "// Write ERST size = %i to ir_set 0 (some bits preserved)\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "// Write ERST size = %i to ir_set 0 (some bits preserved)",
                        val);
        xhci_writel(xhci, val, &xhci->ir_set->erst_size);
 
-       xhci_dbg(xhci, "// Set ERST entries to point to event ring.\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "// Set ERST entries to point to event ring.");
        /* set the segment table base address */
-       xhci_dbg(xhci, "// Set ERST base address for ir_set 0 = 0x%llx\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "// Set ERST base address for ir_set 0 = 0x%llx",
                        (unsigned long long)xhci->erst.erst_dma_addr);
        val_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base);
        val_64 &= ERST_PTR_MASK;
@@ -2455,7 +2413,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
 
        /* Set the event ring dequeue address */
        xhci_set_hc_event_deq(xhci);
-       xhci_dbg(xhci, "Wrote ERST address to ir_set 0.\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "Wrote ERST address to ir_set 0.");
        xhci_print_ir_set(xhci, 0);
 
        /*
index f00cb203faea569b2e87e79e8371455a7abd77b4..c2d495057eb538a74db9a01fc69af12442ca8d45 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 
 #include "xhci.h"
+#include "xhci-trace.h"
 
 /* Device for a quirk */
 #define PCI_VENDOR_ID_FRESCO_LOGIC     0x1b73
@@ -64,16 +65,18 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK &&
                                pdev->revision == 0x0) {
                        xhci->quirks |= XHCI_RESET_EP_QUIRK;
-                       xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure"
-                                       " endpoint cmd after reset endpoint\n");
+                       xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "QUIRK: Fresco Logic xHC needs configure"
+                               " endpoint cmd after reset endpoint");
                }
                /* Fresco Logic confirms: all revisions of this chip do not
                 * support MSI, even though some of them claim to in their PCI
                 * capabilities.
                 */
                xhci->quirks |= XHCI_BROKEN_MSI;
-               xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u "
-                               "has broken MSI implementation\n",
+               xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "QUIRK: Fresco Logic revision %u "
+                               "has broken MSI implementation",
                                pdev->revision);
                xhci->quirks |= XHCI_TRUST_TX_LENGTH;
        }
@@ -110,7 +113,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
        if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
                        pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
                xhci->quirks |= XHCI_RESET_ON_RESUME;
-               xhci_dbg(xhci, "QUIRK: Resetting on resume\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "QUIRK: Resetting on resume");
                xhci->quirks |= XHCI_TRUST_TX_LENGTH;
        }
        if (pdev->vendor == PCI_VENDOR_ID_VIA)
@@ -249,13 +253,15 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
         * writers.
         *
         * Unconditionally switch the ports back to xHCI after a system resume.
-        * We can't tell whether the EHCI or xHCI controller will be resumed
-        * first, so we have to do the port switchover in both drivers.  Writing
-        * a '1' to the port switchover registers should have no effect if the
-        * port was already switched over.
+        * It should not matter whether the EHCI or xHCI controller is
+        * resumed first. It's enough to do the switchover in xHCI because
+        * USB core won't notice anything as the hub driver doesn't start
+        * running again until after all the devices (including both EHCI and
+        * xHCI host controllers) have been resumed.
         */
-       if (usb_is_intel_switchable_xhci(pdev))
-               usb_enable_xhci_ports(pdev);
+
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL)
+               usb_enable_intel_xhci_ports(pdev);
 
        retval = xhci_resume(xhci, hibernated);
        return retval;
index 51e22bf89505c2bcf360917b8088d5472ccd7ce6..be5e70d2300c8ba759b2f43486582ecc10798f0a 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/platform_device.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/dma-mapping.h>
 
 #include "xhci.h"
 
@@ -104,6 +106,15 @@ static int xhci_plat_probe(struct platform_device *pdev)
        if (!res)
                return -ENODEV;
 
+       /* Initialize dma_mask and coherent_dma_mask to 32-bits */
+       ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+       if (ret)
+               return ret;
+       if (!pdev->dev.dma_mask)
+               pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+       else
+               dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+
        hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
        if (!hcd)
                return -ENOMEM;
@@ -186,11 +197,46 @@ static int xhci_plat_remove(struct platform_device *dev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int xhci_plat_suspend(struct device *dev)
+{
+       struct usb_hcd  *hcd = dev_get_drvdata(dev);
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+       return xhci_suspend(xhci);
+}
+
+static int xhci_plat_resume(struct device *dev)
+{
+       struct usb_hcd  *hcd = dev_get_drvdata(dev);
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+       return xhci_resume(xhci, 0);
+}
+
+static const struct dev_pm_ops xhci_plat_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(xhci_plat_suspend, xhci_plat_resume)
+};
+#define DEV_PM_OPS     (&xhci_plat_pm_ops)
+#else
+#define DEV_PM_OPS     NULL
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_OF
+static const struct of_device_id usb_xhci_of_match[] = {
+       { .compatible = "xhci-platform" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
+#endif
+
 static struct platform_driver usb_xhci_driver = {
        .probe  = xhci_plat_probe,
        .remove = xhci_plat_remove,
        .driver = {
                .name = "xhci-hcd",
+               .pm = DEV_PM_OPS,
+               .of_match_table = of_match_ptr(usb_xhci_of_match),
        },
 };
 MODULE_ALIAS("platform:xhci-hcd");
index 5b08cd85f8e7fe9646228da946166dfb188c10d2..7b35af167e554ab1f9f3cf297d644427f25db6b7 100644 (file)
@@ -67,6 +67,7 @@
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include "xhci.h"
+#include "xhci-trace.h"
 
 static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
                struct xhci_virt_device *virt_dev,
@@ -555,7 +556,8 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
                return;
        }
        state->new_cycle_state = 0;
-       xhci_dbg(xhci, "Finding segment containing stopped TRB.\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                       "Finding segment containing stopped TRB.");
        state->new_deq_seg = find_trb_seg(cur_td->start_seg,
                        dev->eps[ep_index].stopped_trb,
                        &state->new_cycle_state);
@@ -565,12 +567,14 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
        }
 
        /* Dig out the cycle state saved by the xHC during the stop ep cmd */
-       xhci_dbg(xhci, "Finding endpoint context\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                       "Finding endpoint context");
        ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
        state->new_cycle_state = 0x1 & le64_to_cpu(ep_ctx->deq);
 
        state->new_deq_ptr = cur_td->last_trb;
-       xhci_dbg(xhci, "Finding segment containing last TRB in TD.\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                       "Finding segment containing last TRB in TD.");
        state->new_deq_seg = find_trb_seg(state->new_deq_seg,
                        state->new_deq_ptr,
                        &state->new_cycle_state);
@@ -597,13 +601,16 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
        if (ep_ring->first_seg == ep_ring->first_seg->next &&
                        state->new_deq_ptr < dev->eps[ep_index].stopped_trb)
                state->new_cycle_state ^= 0x1;
-       xhci_dbg(xhci, "Cycle state = 0x%x\n", state->new_cycle_state);
+       xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                       "Cycle state = 0x%x", state->new_cycle_state);
 
        /* Don't update the ring cycle state for the producer (us). */
-       xhci_dbg(xhci, "New dequeue segment = %p (virtual)\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                       "New dequeue segment = %p (virtual)",
                        state->new_deq_seg);
        addr = xhci_trb_virt_to_dma(state->new_deq_seg, state->new_deq_ptr);
-       xhci_dbg(xhci, "New dequeue pointer = 0x%llx (DMA)\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                       "New dequeue pointer = 0x%llx (DMA)",
                        (unsigned long long) addr);
 }
 
@@ -631,9 +638,11 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
                        if (flip_cycle)
                                cur_trb->generic.field[3] ^=
                                        cpu_to_le32(TRB_CYCLE);
-                       xhci_dbg(xhci, "Cancel (unchain) link TRB\n");
-                       xhci_dbg(xhci, "Address = %p (0x%llx dma); "
-                                       "in seg %p (0x%llx dma)\n",
+                       xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                                       "Cancel (unchain) link TRB");
+                       xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                                       "Address = %p (0x%llx dma); "
+                                       "in seg %p (0x%llx dma)",
                                        cur_trb,
                                        (unsigned long long)xhci_trb_virt_to_dma(cur_seg, cur_trb),
                                        cur_seg,
@@ -651,7 +660,8 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
                                        cpu_to_le32(TRB_CYCLE);
                        cur_trb->generic.field[3] |= cpu_to_le32(
                                TRB_TYPE(TRB_TR_NOOP));
-                       xhci_dbg(xhci, "TRB to noop at offset 0x%llx\n",
+                       xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                                       "TRB to noop at offset 0x%llx",
                                        (unsigned long long)
                                        xhci_trb_virt_to_dma(cur_seg, cur_trb));
                }
@@ -672,8 +682,9 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
 {
        struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
 
-       xhci_dbg(xhci, "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), "
-                       "new deq ptr = %p (0x%llx dma), new cycle = %u\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                       "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), "
+                       "new deq ptr = %p (0x%llx dma), new cycle = %u",
                        deq_state->new_deq_seg,
                        (unsigned long long)deq_state->new_deq_seg->dma,
                        deq_state->new_deq_ptr,
@@ -793,7 +804,8 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
         */
        list_for_each(entry, &ep->cancelled_td_list) {
                cur_td = list_entry(entry, struct xhci_td, cancelled_td_list);
-               xhci_dbg(xhci, "Removing canceled TD starting at 0x%llx (dma).\n",
+               xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                               "Removing canceled TD starting at 0x%llx (dma).",
                                (unsigned long long)xhci_trb_virt_to_dma(
                                        cur_td->start_seg, cur_td->first_trb));
                ep_ring = xhci_urb_to_transfer_ring(xhci, cur_td->urb);
@@ -913,14 +925,16 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
 
        ep->stop_cmds_pending--;
        if (xhci->xhc_state & XHCI_STATE_DYING) {
-               xhci_dbg(xhci, "Stop EP timer ran, but another timer marked "
-                               "xHCI as DYING, exiting.\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                               "Stop EP timer ran, but another timer marked "
+                               "xHCI as DYING, exiting.");
                spin_unlock_irqrestore(&xhci->lock, flags);
                return;
        }
        if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) {
-               xhci_dbg(xhci, "Stop EP timer ran, but no command pending, "
-                               "exiting.\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                               "Stop EP timer ran, but no command pending, "
+                               "exiting.");
                spin_unlock_irqrestore(&xhci->lock, flags);
                return;
        }
@@ -962,8 +976,9 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
                        ring = temp_ep->ring;
                        if (!ring)
                                continue;
-                       xhci_dbg(xhci, "Killing URBs for slot ID %u, "
-                                       "ep index %u\n", i, j);
+                       xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                                       "Killing URBs for slot ID %u, "
+                                       "ep index %u", i, j);
                        while (!list_empty(&ring->td_list)) {
                                cur_td = list_first_entry(&ring->td_list,
                                                struct xhci_td,
@@ -986,9 +1001,11 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
                }
        }
        spin_unlock_irqrestore(&xhci->lock, flags);
-       xhci_dbg(xhci, "Calling usb_hc_died()\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                       "Calling usb_hc_died()");
        usb_hc_died(xhci_to_hcd(xhci)->primary_hcd);
-       xhci_dbg(xhci, "xHCI host controller is dead.\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                       "xHCI host controller is dead.");
 }
 
 
@@ -1092,7 +1109,8 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,
                        ep_state &= EP_STATE_MASK;
                        slot_state = le32_to_cpu(slot_ctx->dev_state);
                        slot_state = GET_SLOT_STATE(slot_state);
-                       xhci_dbg(xhci, "Slot state = %u, EP state = %u\n",
+                       xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                                       "Slot state = %u, EP state = %u",
                                        slot_state, ep_state);
                        break;
                case COMP_EBADSLT:
@@ -1112,7 +1130,8 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,
                 * cancelling URBs, which might not be an error...
                 */
        } else {
-               xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq = @%08llx\n",
+               xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                       "Successful Set TR Deq Ptr cmd, deq = @%08llx",
                         le64_to_cpu(ep_ctx->deq));
                if (xhci_trb_virt_to_dma(dev->eps[ep_index].queued_deq_seg,
                                         dev->eps[ep_index].queued_deq_ptr) ==
@@ -1150,7 +1169,8 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci,
        /* This command will only fail if the endpoint wasn't halted,
         * but we don't care.
         */
-       xhci_dbg(xhci, "Ignoring reset ep completion code of %u\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
+               "Ignoring reset ep completion code of %u",
                 GET_COMP_CODE(le32_to_cpu(event->status)));
 
        /* HW with the reset endpoint quirk needs to have a configure endpoint
@@ -1158,7 +1178,8 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci,
         * because the HW can't handle two commands being queued in a row.
         */
        if (xhci->quirks & XHCI_RESET_EP_QUIRK) {
-               xhci_dbg(xhci, "Queueing configure endpoint command\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "Queueing configure endpoint command");
                xhci_queue_configure_endpoint(xhci,
                                xhci->devs[slot_id]->in_ctx->dma, slot_id,
                                false);
@@ -1377,6 +1398,9 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
                return;
        }
 
+       trace_xhci_cmd_completion(&xhci->cmd_ring->dequeue->generic,
+                                       (struct xhci_generic_trb *) event);
+
        if ((GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_ABORT) ||
                (GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_STOP)) {
                /* If the return value is 0, we think the trb pointed by
@@ -1444,8 +1468,9 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
                        ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state;
                        if (!(ep_state & EP_HALTED))
                                goto bandwidth_change;
-                       xhci_dbg(xhci, "Completed config ep cmd - "
-                                       "last ep index = %d, state = %d\n",
+                       xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                                       "Completed config ep cmd - "
+                                       "last ep index = %d, state = %d",
                                        ep_index, ep_state);
                        /* Clear internal halted state and restart ring(s) */
                        xhci->devs[slot_id]->eps[ep_index].ep_state &=
@@ -1454,7 +1479,8 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
                        break;
                }
 bandwidth_change:
-               xhci_dbg(xhci, "Completed config ep cmd\n");
+               xhci_dbg_trace(xhci,  trace_xhci_dbg_context_change,
+                               "Completed config ep cmd");
                xhci->devs[slot_id]->cmd_status =
                        GET_COMP_CODE(le32_to_cpu(event->status));
                complete(&xhci->devs[slot_id]->cmd_completion);
@@ -1497,7 +1523,8 @@ bandwidth_change:
                        xhci->error_bitmask |= 1 << 6;
                        break;
                }
-               xhci_dbg(xhci, "NEC firmware version %2x.%02x\n",
+               xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                       "NEC firmware version %2x.%02x",
                         NEC_FW_MAJOR(le32_to_cpu(event->status)),
                         NEC_FW_MINOR(le32_to_cpu(event->status)));
                break;
@@ -2877,8 +2904,8 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
                        return -ENOMEM;
                }
 
-               xhci_dbg(xhci, "ERROR no room on ep ring, "
-                                       "try ring expansion\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_ring_expansion,
+                               "ERROR no room on ep ring, try ring expansion");
                num_trbs_needed = num_trbs - ep_ring->num_trbs_free;
                if (xhci_ring_expansion(xhci, ep_ring, num_trbs_needed,
                                        mem_flags)) {
diff --git a/drivers/usb/host/xhci-trace.c b/drivers/usb/host/xhci-trace.c
new file mode 100644 (file)
index 0000000..7cf30c8
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * xHCI host controller driver
+ *
+ * Copyright (C) 2013 Xenia Ragiadakou
+ *
+ * Author: Xenia Ragiadakou
+ * Email : burzalodowa@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define CREATE_TRACE_POINTS
+#include "xhci-trace.h"
diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h
new file mode 100644 (file)
index 0000000..20364cc
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * xHCI host controller driver
+ *
+ * Copyright (C) 2013 Xenia Ragiadakou
+ *
+ * Author: Xenia Ragiadakou
+ * Email : burzalodowa@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM xhci-hcd
+
+#if !defined(__XHCI_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __XHCI_TRACE_H
+
+#include <linux/tracepoint.h>
+#include "xhci.h"
+
+#define XHCI_MSG_MAX   500
+
+DECLARE_EVENT_CLASS(xhci_log_msg,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf),
+       TP_STRUCT__entry(__dynamic_array(char, msg, XHCI_MSG_MAX)),
+       TP_fast_assign(
+               vsnprintf(__get_str(msg), XHCI_MSG_MAX, vaf->fmt, *vaf->va);
+       ),
+       TP_printk("%s", __get_str(msg))
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_address,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_context_change,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_quirks,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_reset_ep,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_cancel_urb,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_init,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_ring_expansion,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf)
+);
+
+DECLARE_EVENT_CLASS(xhci_log_ctx,
+       TP_PROTO(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx,
+                unsigned int ep_num),
+       TP_ARGS(xhci, ctx, ep_num),
+       TP_STRUCT__entry(
+               __field(int, ctx_64)
+               __field(unsigned, ctx_type)
+               __field(dma_addr_t, ctx_dma)
+               __field(u8 *, ctx_va)
+               __field(unsigned, ctx_ep_num)
+               __field(int, slot_id)
+               __dynamic_array(u32, ctx_data,
+                       ((HCC_64BYTE_CONTEXT(xhci->hcc_params) + 1) * 8) *
+                       ((ctx->type == XHCI_CTX_TYPE_INPUT) + ep_num + 1))
+       ),
+       TP_fast_assign(
+               struct usb_device *udev;
+
+               udev = to_usb_device(xhci_to_hcd(xhci)->self.controller);
+               __entry->ctx_64 = HCC_64BYTE_CONTEXT(xhci->hcc_params);
+               __entry->ctx_type = ctx->type;
+               __entry->ctx_dma = ctx->dma;
+               __entry->ctx_va = ctx->bytes;
+               __entry->slot_id = udev->slot_id;
+               __entry->ctx_ep_num = ep_num;
+               memcpy(__get_dynamic_array(ctx_data), ctx->bytes,
+                       ((HCC_64BYTE_CONTEXT(xhci->hcc_params) + 1) * 32) *
+                       ((ctx->type == XHCI_CTX_TYPE_INPUT) + ep_num + 1));
+       ),
+       TP_printk("\nctx_64=%d, ctx_type=%u, ctx_dma=@%llx, ctx_va=@%p",
+                       __entry->ctx_64, __entry->ctx_type,
+                       (unsigned long long) __entry->ctx_dma, __entry->ctx_va
+       )
+);
+
+DEFINE_EVENT(xhci_log_ctx, xhci_address_ctx,
+       TP_PROTO(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx,
+                unsigned int ep_num),
+       TP_ARGS(xhci, ctx, ep_num)
+);
+
+DECLARE_EVENT_CLASS(xhci_log_event,
+       TP_PROTO(void *trb_va, struct xhci_generic_trb *ev),
+       TP_ARGS(trb_va, ev),
+       TP_STRUCT__entry(
+               __field(void *, va)
+               __field(u64, dma)
+               __field(u32, status)
+               __field(u32, flags)
+               __dynamic_array(__le32, trb, 4)
+       ),
+       TP_fast_assign(
+               __entry->va = trb_va;
+               __entry->dma = le64_to_cpu(((u64)ev->field[1]) << 32 |
+                                               ev->field[0]);
+               __entry->status = le32_to_cpu(ev->field[2]);
+               __entry->flags = le32_to_cpu(ev->field[3]);
+               memcpy(__get_dynamic_array(trb), trb_va,
+                       sizeof(struct xhci_generic_trb));
+       ),
+       TP_printk("\ntrb_dma=@%llx, trb_va=@%p, status=%08x, flags=%08x",
+                       (unsigned long long) __entry->dma, __entry->va,
+                       __entry->status, __entry->flags
+       )
+);
+
+DEFINE_EVENT(xhci_log_event, xhci_cmd_completion,
+       TP_PROTO(void *trb_va, struct xhci_generic_trb *ev),
+       TP_ARGS(trb_va, ev)
+);
+
+#endif /* __XHCI_TRACE_H */
+
+/* this part must be outside header guard */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE xhci-trace
+
+#include <trace/define_trace.h>
index 9478caa2f71fb12912ddea1bfa06f37580e7c3ce..bf11af9a46991ce5f12a83970311bb8f73e6b142 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/dma-mapping.h>
 
 #include "xhci.h"
+#include "xhci-trace.h"
 
 #define DRIVER_AUTHOR "Sarah Sharp"
 #define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
@@ -101,7 +102,7 @@ void xhci_quiesce(struct xhci_hcd *xhci)
 int xhci_halt(struct xhci_hcd *xhci)
 {
        int ret;
-       xhci_dbg(xhci, "// Halt the HC\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Halt the HC");
        xhci_quiesce(xhci);
 
        ret = xhci_handshake(xhci, &xhci->op_regs->status,
@@ -125,7 +126,7 @@ static int xhci_start(struct xhci_hcd *xhci)
 
        temp = xhci_readl(xhci, &xhci->op_regs->command);
        temp |= (CMD_RUN);
-       xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Turn on HC, cmd = 0x%x.",
                        temp);
        xhci_writel(xhci, temp, &xhci->op_regs->command);
 
@@ -163,7 +164,7 @@ int xhci_reset(struct xhci_hcd *xhci)
                return 0;
        }
 
-       xhci_dbg(xhci, "// Reset the HC\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Reset the HC");
        command = xhci_readl(xhci, &xhci->op_regs->command);
        command |= CMD_RESET;
        xhci_writel(xhci, command, &xhci->op_regs->command);
@@ -173,7 +174,8 @@ int xhci_reset(struct xhci_hcd *xhci)
        if (ret)
                return ret;
 
-       xhci_dbg(xhci, "Wait for controller to be ready for doorbell rings\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                        "Wait for controller to be ready for doorbell rings");
        /*
         * xHCI cannot write to any doorbells or operational registers other
         * than status until the "Controller Not Ready" flag is cleared.
@@ -215,14 +217,16 @@ static int xhci_setup_msi(struct xhci_hcd *xhci)
 
        ret = pci_enable_msi(pdev);
        if (ret) {
-               xhci_dbg(xhci, "failed to allocate MSI entry\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                               "failed to allocate MSI entry");
                return ret;
        }
 
        ret = request_irq(pdev->irq, xhci_msi_irq,
                                0, "xhci_hcd", xhci_to_hcd(xhci));
        if (ret) {
-               xhci_dbg(xhci, "disable MSI interrupt\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                               "disable MSI interrupt");
                pci_disable_msi(pdev);
        }
 
@@ -285,7 +289,8 @@ static int xhci_setup_msix(struct xhci_hcd *xhci)
 
        ret = pci_enable_msix(pdev, xhci->msix_entries, xhci->msix_count);
        if (ret) {
-               xhci_dbg(xhci, "Failed to enable MSI-X\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                               "Failed to enable MSI-X");
                goto free_entries;
        }
 
@@ -301,7 +306,7 @@ static int xhci_setup_msix(struct xhci_hcd *xhci)
        return ret;
 
 disable_msix:
-       xhci_dbg(xhci, "disable MSI-X interrupt\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "disable MSI-X interrupt");
        xhci_free_irq(xhci);
        pci_disable_msix(pdev);
 free_entries:
@@ -418,9 +423,11 @@ static void compliance_mode_recovery(unsigned long arg)
                         * Compliance Mode Detected. Letting USB Core
                         * handle the Warm Reset
                         */
-                       xhci_dbg(xhci, "Compliance mode detected->port %d\n",
+                       xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                                       "Compliance mode detected->port %d",
                                        i + 1);
-                       xhci_dbg(xhci, "Attempting compliance mode recovery\n");
+                       xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                                       "Attempting compliance mode recovery");
                        hcd = xhci->shared_hcd;
 
                        if (hcd->state == HC_STATE_SUSPENDED)
@@ -458,7 +465,8 @@ static void compliance_mode_recovery_timer_init(struct xhci_hcd *xhci)
        set_timer_slack(&xhci->comp_mode_recovery_timer,
                        msecs_to_jiffies(COMP_MODE_RCVRY_MSECS));
        add_timer(&xhci->comp_mode_recovery_timer);
-       xhci_dbg(xhci, "Compliance mode recovery timer initialized\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                       "Compliance mode recovery timer initialized");
 }
 
 /*
@@ -506,16 +514,18 @@ int xhci_init(struct usb_hcd *hcd)
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
        int retval = 0;
 
-       xhci_dbg(xhci, "xhci_init\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_init");
        spin_lock_init(&xhci->lock);
        if (xhci->hci_version == 0x95 && link_quirk) {
-               xhci_dbg(xhci, "QUIRK: Not clearing Link TRB chain bits.\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "QUIRK: Not clearing Link TRB chain bits.");
                xhci->quirks |= XHCI_LINK_TRB_QUIRK;
        } else {
-               xhci_dbg(xhci, "xHCI doesn't need link TRB QUIRK\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                               "xHCI doesn't need link TRB QUIRK");
        }
        retval = xhci_mem_init(xhci, GFP_KERNEL);
-       xhci_dbg(xhci, "Finished xhci_init\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Finished xhci_init");
 
        /* Initializing Compliance Mode Recovery Data If Needed */
        if (xhci_compliance_mode_recovery_timer_quirk_check()) {
@@ -529,57 +539,6 @@ int xhci_init(struct usb_hcd *hcd)
 /*-------------------------------------------------------------------------*/
 
 
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-static void xhci_event_ring_work(unsigned long arg)
-{
-       unsigned long flags;
-       int temp;
-       u64 temp_64;
-       struct xhci_hcd *xhci = (struct xhci_hcd *) arg;
-       int i, j;
-
-       xhci_dbg(xhci, "Poll event ring: %lu\n", jiffies);
-
-       spin_lock_irqsave(&xhci->lock, flags);
-       temp = xhci_readl(xhci, &xhci->op_regs->status);
-       xhci_dbg(xhci, "op reg status = 0x%x\n", temp);
-       if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) ||
-                       (xhci->xhc_state & XHCI_STATE_HALTED)) {
-               xhci_dbg(xhci, "HW died, polling stopped.\n");
-               spin_unlock_irqrestore(&xhci->lock, flags);
-               return;
-       }
-
-       temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
-       xhci_dbg(xhci, "ir_set 0 pending = 0x%x\n", temp);
-       xhci_dbg(xhci, "HC error bitmask = 0x%x\n", xhci->error_bitmask);
-       xhci->error_bitmask = 0;
-       xhci_dbg(xhci, "Event ring:\n");
-       xhci_debug_segment(xhci, xhci->event_ring->deq_seg);
-       xhci_dbg_ring_ptrs(xhci, xhci->event_ring);
-       temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
-       temp_64 &= ~ERST_PTR_MASK;
-       xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64);
-       xhci_dbg(xhci, "Command ring:\n");
-       xhci_debug_segment(xhci, xhci->cmd_ring->deq_seg);
-       xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring);
-       xhci_dbg_cmd_ptrs(xhci);
-       for (i = 0; i < MAX_HC_SLOTS; ++i) {
-               if (!xhci->devs[i])
-                       continue;
-               for (j = 0; j < 31; ++j) {
-                       xhci_dbg_ep_rings(xhci, i, j, &xhci->devs[i]->eps[j]);
-               }
-       }
-       spin_unlock_irqrestore(&xhci->lock, flags);
-
-       if (!xhci->zombie)
-               mod_timer(&xhci->event_ring_timer, jiffies + POLL_TIMEOUT * HZ);
-       else
-               xhci_dbg(xhci, "Quit polling the event ring.\n");
-}
-#endif
-
 static int xhci_run_finished(struct xhci_hcd *xhci)
 {
        if (xhci_start(xhci)) {
@@ -592,7 +551,8 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
        if (xhci->quirks & XHCI_NEC_HOST)
                xhci_ring_cmd_db(xhci);
 
-       xhci_dbg(xhci, "Finished xhci_run for USB3 roothub\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "Finished xhci_run for USB3 roothub");
        return 0;
 }
 
@@ -623,23 +583,12 @@ int xhci_run(struct usb_hcd *hcd)
        if (!usb_hcd_is_primary_hcd(hcd))
                return xhci_run_finished(xhci);
 
-       xhci_dbg(xhci, "xhci_run\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_run");
 
        ret = xhci_try_enable_msi(hcd);
        if (ret)
                return ret;
 
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-       init_timer(&xhci->event_ring_timer);
-       xhci->event_ring_timer.data = (unsigned long) xhci;
-       xhci->event_ring_timer.function = xhci_event_ring_work;
-       /* Poll the event ring */
-       xhci->event_ring_timer.expires = jiffies + POLL_TIMEOUT * HZ;
-       xhci->zombie = 0;
-       xhci_dbg(xhci, "Setting event ring polling timer\n");
-       add_timer(&xhci->event_ring_timer);
-#endif
-
        xhci_dbg(xhci, "Command ring memory map follows:\n");
        xhci_debug_ring(xhci, xhci->cmd_ring);
        xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring);
@@ -652,9 +601,11 @@ int xhci_run(struct usb_hcd *hcd)
        xhci_dbg_ring_ptrs(xhci, xhci->event_ring);
        temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
        temp_64 &= ~ERST_PTR_MASK;
-       xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64);
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "ERST deq = 64'h%0lx", (long unsigned int) temp_64);
 
-       xhci_dbg(xhci, "// Set the interrupt modulation register\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "// Set the interrupt modulation register");
        temp = xhci_readl(xhci, &xhci->ir_set->irq_control);
        temp &= ~ER_IRQ_INTERVAL_MASK;
        temp |= (u32) 160;
@@ -663,12 +614,13 @@ int xhci_run(struct usb_hcd *hcd)
        /* Set the HCD state before we enable the irqs */
        temp = xhci_readl(xhci, &xhci->op_regs->command);
        temp |= (CMD_EIE);
-       xhci_dbg(xhci, "// Enable interrupts, cmd = 0x%x.\n",
-                       temp);
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "// Enable interrupts, cmd = 0x%x.", temp);
        xhci_writel(xhci, temp, &xhci->op_regs->command);
 
        temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
-       xhci_dbg(xhci, "// Enabling event ring interrupter %p by writing 0x%x to irq_pending\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "// Enabling event ring interrupter %p by writing 0x%x to irq_pending",
                        xhci->ir_set, (unsigned int) ER_IRQ_ENABLE(temp));
        xhci_writel(xhci, ER_IRQ_ENABLE(temp),
                        &xhci->ir_set->irq_pending);
@@ -678,7 +630,8 @@ int xhci_run(struct usb_hcd *hcd)
                xhci_queue_vendor_command(xhci, 0, 0, 0,
                                TRB_TYPE(TRB_NEC_GET_FW));
 
-       xhci_dbg(xhci, "Finished xhci_run for USB2 roothub\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "Finished xhci_run for USB2 roothub");
        return 0;
 }
 
@@ -726,24 +679,20 @@ void xhci_stop(struct usb_hcd *hcd)
 
        xhci_cleanup_msix(xhci);
 
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-       /* Tell the event ring poll function not to reschedule */
-       xhci->zombie = 1;
-       del_timer_sync(&xhci->event_ring_timer);
-#endif
-
        /* Deleting Compliance Mode Recovery Timer */
        if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
                        (!(xhci_all_ports_seen_u0(xhci)))) {
                del_timer_sync(&xhci->comp_mode_recovery_timer);
-               xhci_dbg(xhci, "%s: compliance mode recovery timer deleted\n",
+               xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "%s: compliance mode recovery timer deleted",
                                __func__);
        }
 
        if (xhci->quirks & XHCI_AMD_PLL_FIX)
                usb_amd_dev_put();
 
-       xhci_dbg(xhci, "// Disabling event ring interrupts\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "// Disabling event ring interrupts");
        temp = xhci_readl(xhci, &xhci->op_regs->status);
        xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status);
        temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
@@ -751,10 +700,11 @@ void xhci_stop(struct usb_hcd *hcd)
                        &xhci->ir_set->irq_pending);
        xhci_print_ir_set(xhci, 0);
 
-       xhci_dbg(xhci, "cleaning up memory\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory");
        xhci_mem_cleanup(xhci);
-       xhci_dbg(xhci, "xhci_stop completed - status = %x\n",
-                   xhci_readl(xhci, &xhci->op_regs->status));
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "xhci_stop completed - status = %x",
+                       xhci_readl(xhci, &xhci->op_regs->status));
 }
 
 /*
@@ -779,8 +729,9 @@ void xhci_shutdown(struct usb_hcd *hcd)
 
        xhci_cleanup_msix(xhci);
 
-       xhci_dbg(xhci, "xhci_shutdown completed - status = %x\n",
-                   xhci_readl(xhci, &xhci->op_regs->status));
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "xhci_shutdown completed - status = %x",
+                       xhci_readl(xhci, &xhci->op_regs->status));
 }
 
 #ifdef CONFIG_PM
@@ -821,7 +772,8 @@ static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
                                      xhci->cmd_ring->dequeue) &
                 (u64) ~CMD_RING_RSVD_BITS) |
                xhci->cmd_ring->cycle_state;
-       xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "// Setting command ring address to 0x%llx",
                        (long unsigned long) val_64);
        xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
 }
@@ -934,7 +886,8 @@ int xhci_suspend(struct xhci_hcd *xhci)
        if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
                        (!(xhci_all_ports_seen_u0(xhci)))) {
                del_timer_sync(&xhci->comp_mode_recovery_timer);
-               xhci_dbg(xhci, "%s: compliance mode recovery timer deleted\n",
+               xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "%s: compliance mode recovery timer deleted",
                                __func__);
        }
 
@@ -999,7 +952,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
                if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
                                !(xhci_all_ports_seen_u0(xhci))) {
                        del_timer_sync(&xhci->comp_mode_recovery_timer);
-                       xhci_dbg(xhci, "Compliance Mode Recovery Timer deleted!\n");
+                       xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "Compliance Mode Recovery Timer deleted!");
                }
 
                /* Let the USB core know _both_ roothubs lost power. */
@@ -1012,12 +966,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
                spin_unlock_irq(&xhci->lock);
                xhci_cleanup_msix(xhci);
 
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-               /* Tell the event ring poll function not to reschedule */
-               xhci->zombie = 1;
-               del_timer_sync(&xhci->event_ring_timer);
-#endif
-
                xhci_dbg(xhci, "// Disabling event ring interrupts\n");
                temp = xhci_readl(xhci, &xhci->op_regs->status);
                xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status);
@@ -1171,27 +1119,25 @@ static int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
        struct xhci_virt_device *virt_dev;
 
        if (!hcd || (check_ep && !ep) || !udev) {
-               printk(KERN_DEBUG "xHCI %s called with invalid args\n",
-                               func);
+               pr_debug("xHCI %s called with invalid args\n", func);
                return -EINVAL;
        }
        if (!udev->parent) {
-               printk(KERN_DEBUG "xHCI %s called for root hub\n",
-                               func);
+               pr_debug("xHCI %s called for root hub\n", func);
                return 0;
        }
 
        xhci = hcd_to_xhci(hcd);
        if (check_virt_dev) {
                if (!udev->slot_id || !xhci->devs[udev->slot_id]) {
-                       printk(KERN_DEBUG "xHCI %s called with unaddressed "
-                                               "device\n", func);
+                       xhci_dbg(xhci, "xHCI %s called with unaddressed device\n",
+                                       func);
                        return -EINVAL;
                }
 
                virt_dev = xhci->devs[udev->slot_id];
                if (virt_dev->udev != udev) {
-                       printk(KERN_DEBUG "xHCI %s called with udev and "
+                       xhci_dbg(xhci, "xHCI %s called with udev and "
                                          "virt_dev does not match\n", func);
                        return -EINVAL;
                }
@@ -1229,12 +1175,16 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
        hw_max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2));
        max_packet_size = usb_endpoint_maxp(&urb->dev->ep0.desc);
        if (hw_max_packet_size != max_packet_size) {
-               xhci_dbg(xhci, "Max Packet Size for ep 0 changed.\n");
-               xhci_dbg(xhci, "Max packet size in usb_device = %d\n",
+               xhci_dbg_trace(xhci,  trace_xhci_dbg_context_change,
+                               "Max Packet Size for ep 0 changed.");
+               xhci_dbg_trace(xhci,  trace_xhci_dbg_context_change,
+                               "Max packet size in usb_device = %d",
                                max_packet_size);
-               xhci_dbg(xhci, "Max packet size in xHCI HW = %d\n",
+               xhci_dbg_trace(xhci,  trace_xhci_dbg_context_change,
+                               "Max packet size in xHCI HW = %d",
                                hw_max_packet_size);
-               xhci_dbg(xhci, "Issuing evaluate context command.\n");
+               xhci_dbg_trace(xhci,  trace_xhci_dbg_context_change,
+                               "Issuing evaluate context command.");
 
                /* Set up the input context flags for the command */
                /* FIXME: This won't work if a non-default control endpoint
@@ -1499,7 +1449,8 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                goto done;
        temp = xhci_readl(xhci, &xhci->op_regs->status);
        if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) {
-               xhci_dbg(xhci, "HW died, freeing TD.\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                               "HW died, freeing TD.");
                urb_priv = urb->hcpriv;
                for (i = urb_priv->td_cnt; i < urb_priv->length; i++) {
                        td = urb_priv->td[i];
@@ -1517,8 +1468,9 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
        }
        if ((xhci->xhc_state & XHCI_STATE_DYING) ||
                        (xhci->xhc_state & XHCI_STATE_HALTED)) {
-               xhci_dbg(xhci, "Ep 0x%x: URB %p to be canceled on "
-                               "non-responsive xHCI host.\n",
+               xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                               "Ep 0x%x: URB %p to be canceled on "
+                               "non-responsive xHCI host.",
                                urb->ep->desc.bEndpointAddress, urb);
                /* Let the stop endpoint command watchdog timer (which set this
                 * state) finish cleaning up the endpoint TD lists.  We must
@@ -1539,8 +1491,9 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
        urb_priv = urb->hcpriv;
        i = urb_priv->td_cnt;
        if (i < urb_priv->length)
-               xhci_dbg(xhci, "Cancel URB %p, dev %s, ep 0x%x, "
-                               "starting at offset 0x%llx\n",
+               xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+                               "Cancel URB %p, dev %s, ep 0x%x, "
+                               "starting at offset 0x%llx",
                                urb, urb->dev->devpath,
                                urb->ep->desc.bEndpointAddress,
                                (unsigned long long) xhci_trb_virt_to_dma(
@@ -1852,7 +1805,8 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci,
                ret = -ENODEV;
                break;
        case COMP_SUCCESS:
-               dev_dbg(&udev->dev, "Successful Endpoint Configure command\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
+                               "Successful Endpoint Configure command");
                ret = 0;
                break;
        default:
@@ -1898,7 +1852,8 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci,
                ret = -EINVAL;
                break;
        case COMP_SUCCESS:
-               dev_dbg(&udev->dev, "Successful evaluate context command\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
+                               "Successful evaluate context command");
                ret = 0;
                break;
        default:
@@ -1964,14 +1919,16 @@ static int xhci_reserve_host_resources(struct xhci_hcd *xhci,
 
        added_eps = xhci_count_num_new_endpoints(xhci, ctrl_ctx);
        if (xhci->num_active_eps + added_eps > xhci->limit_active_eps) {
-               xhci_dbg(xhci, "Not enough ep ctxs: "
-                               "%u active, need to add %u, limit is %u.\n",
+               xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "Not enough ep ctxs: "
+                               "%u active, need to add %u, limit is %u.",
                                xhci->num_active_eps, added_eps,
                                xhci->limit_active_eps);
                return -ENOMEM;
        }
        xhci->num_active_eps += added_eps;
-       xhci_dbg(xhci, "Adding %u ep ctxs, %u now active.\n", added_eps,
+       xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                       "Adding %u ep ctxs, %u now active.", added_eps,
                        xhci->num_active_eps);
        return 0;
 }
@@ -1989,7 +1946,8 @@ static void xhci_free_host_resources(struct xhci_hcd *xhci,
 
        num_failed_eps = xhci_count_num_new_endpoints(xhci, ctrl_ctx);
        xhci->num_active_eps -= num_failed_eps;
-       xhci_dbg(xhci, "Removing %u failed ep ctxs, %u now active.\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                       "Removing %u failed ep ctxs, %u now active.",
                        num_failed_eps,
                        xhci->num_active_eps);
 }
@@ -2008,7 +1966,8 @@ static void xhci_finish_resource_reservation(struct xhci_hcd *xhci,
        num_dropped_eps = xhci_count_num_dropped_endpoints(xhci, ctrl_ctx);
        xhci->num_active_eps -= num_dropped_eps;
        if (num_dropped_eps)
-               xhci_dbg(xhci, "Removing %u dropped ep ctxs, %u now active.\n",
+               xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "Removing %u dropped ep ctxs, %u now active.",
                                num_dropped_eps,
                                xhci->num_active_eps);
 }
@@ -2169,18 +2128,21 @@ static int xhci_check_bw_table(struct xhci_hcd *xhci,
         * that the HS bus has enough bandwidth if we are activing a new TT.
         */
        if (virt_dev->tt_info) {
-               xhci_dbg(xhci, "Recalculating BW for rootport %u\n",
+               xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "Recalculating BW for rootport %u",
                                virt_dev->real_port);
                if (xhci_check_tt_bw_table(xhci, virt_dev, old_active_eps)) {
                        xhci_warn(xhci, "Not enough bandwidth on HS bus for "
                                        "newly activated TT.\n");
                        return -ENOMEM;
                }
-               xhci_dbg(xhci, "Recalculating BW for TT slot %u port %u\n",
+               xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "Recalculating BW for TT slot %u port %u",
                                virt_dev->tt_info->slot_id,
                                virt_dev->tt_info->ttport);
        } else {
-               xhci_dbg(xhci, "Recalculating BW for rootport %u\n",
+               xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "Recalculating BW for rootport %u",
                                virt_dev->real_port);
        }
 
@@ -2288,8 +2250,9 @@ static int xhci_check_bw_table(struct xhci_hcd *xhci,
                        xhci->rh_bw[port_index].num_active_tts;
        }
 
-       xhci_dbg(xhci, "Final bandwidth: %u, Limit: %u, Reserved: %u, "
-               "Available: %u " "percent\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+               "Final bandwidth: %u, Limit: %u, Reserved: %u, "
+               "Available: %u " "percent",
                bw_used, max_bandwidth, bw_reserved,
                (max_bandwidth - bw_used - bw_reserved) * 100 /
                max_bandwidth);
@@ -2659,7 +2622,8 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
                if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK))
                        xhci_free_host_resources(xhci, ctrl_ctx);
                spin_unlock_irqrestore(&xhci->lock, flags);
-               xhci_dbg(xhci, "FIXME allocate a new ring segment\n");
+               xhci_dbg_trace(xhci,  trace_xhci_dbg_context_change,
+                               "FIXME allocate a new ring segment");
                return -ENOMEM;
        }
        xhci_ring_cmd_db(xhci);
@@ -2872,7 +2836,8 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
        struct xhci_dequeue_state deq_state;
        struct xhci_virt_ep *ep;
 
-       xhci_dbg(xhci, "Cleaning up stalled endpoint ring\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
+                       "Cleaning up stalled endpoint ring");
        ep = &xhci->devs[udev->slot_id]->eps[ep_index];
        /* We need to move the HW's dequeue pointer past this TD,
         * or it will attempt to resend it on the next doorbell ring.
@@ -2885,7 +2850,8 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
         * issue a configure endpoint command later.
         */
        if (!(xhci->quirks & XHCI_RESET_EP_QUIRK)) {
-               xhci_dbg(xhci, "Queueing new dequeue state\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
+                               "Queueing new dequeue state");
                xhci_queue_new_dequeue_state(xhci, udev->slot_id,
                                ep_index, ep->stopped_stream, &deq_state);
        } else {
@@ -2894,8 +2860,9 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
                 * XXX: No idea how this hardware will react when stream rings
                 * are enabled.
                 */
-               xhci_dbg(xhci, "Setting up input context for "
-                               "configure endpoint command\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "Setting up input context for "
+                               "configure endpoint command");
                xhci_setup_input_ctx_for_quirk(xhci, udev->slot_id,
                                ep_index, &deq_state);
        }
@@ -2927,16 +2894,19 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,
        ep_index = xhci_get_endpoint_index(&ep->desc);
        virt_ep = &xhci->devs[udev->slot_id]->eps[ep_index];
        if (!virt_ep->stopped_td) {
-               xhci_dbg(xhci, "Endpoint 0x%x not halted, refusing to reset.\n",
-                               ep->desc.bEndpointAddress);
+               xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
+                       "Endpoint 0x%x not halted, refusing to reset.",
+                       ep->desc.bEndpointAddress);
                return;
        }
        if (usb_endpoint_xfer_control(&ep->desc)) {
-               xhci_dbg(xhci, "Control endpoint stall already handled.\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
+                               "Control endpoint stall already handled.");
                return;
        }
 
-       xhci_dbg(xhci, "Queueing reset endpoint command\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
+                       "Queueing reset endpoint command");
        spin_lock_irqsave(&xhci->lock, flags);
        ret = xhci_queue_reset_ep(xhci, udev->slot_id, ep_index);
        /*
@@ -3076,8 +3046,8 @@ static u32 xhci_calculate_no_streams_bitmask(struct xhci_hcd *xhci,
                /* Are streams already being freed for the endpoint? */
                if (ep_state & EP_GETTING_NO_STREAMS) {
                        xhci_warn(xhci, "WARN Can't disable streams for "
-                                       "endpoint 0x%x\n, "
-                                       "streams are being disabled already.",
+                                       "endpoint 0x%x, "
+                                       "streams are being disabled already\n",
                                        eps[i]->desc.bEndpointAddress);
                        return 0;
                }
@@ -3085,8 +3055,8 @@ static u32 xhci_calculate_no_streams_bitmask(struct xhci_hcd *xhci,
                if (!(ep_state & EP_HAS_STREAMS) &&
                                !(ep_state & EP_GETTING_STREAMS)) {
                        xhci_warn(xhci, "WARN Can't disable streams for "
-                                       "endpoint 0x%x\n, "
-                                       "streams are already disabled!",
+                                       "endpoint 0x%x, "
+                                       "streams are already disabled!\n",
                                        eps[i]->desc.bEndpointAddress);
                        xhci_warn(xhci, "WARN xhci_free_streams() called "
                                        "with non-streams endpoint\n");
@@ -3374,8 +3344,9 @@ void xhci_free_device_endpoint_resources(struct xhci_hcd *xhci,
        }
        xhci->num_active_eps -= num_dropped_eps;
        if (num_dropped_eps)
-               xhci_dbg(xhci, "Dropped %u ep ctxs, flags = 0x%x, "
-                               "%u now active.\n",
+               xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "Dropped %u ep ctxs, flags = 0x%x, "
+                               "%u now active.",
                                num_dropped_eps, drop_flags,
                                xhci->num_active_eps);
 }
@@ -3509,10 +3480,10 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
        switch (ret) {
        case COMP_EBADSLT: /* 0.95 completion code for bad slot ID */
        case COMP_CTX_STATE: /* 0.96 completion code for same thing */
-               xhci_info(xhci, "Can't reset device (slot ID %u) in %s state\n",
+               xhci_dbg(xhci, "Can't reset device (slot ID %u) in %s state\n",
                                slot_id,
                                xhci_get_slot_state(xhci, virt_dev->out_ctx));
-               xhci_info(xhci, "Not freeing device rings.\n");
+               xhci_dbg(xhci, "Not freeing device rings.\n");
                /* Don't treat this as an error.  May change my mind later. */
                ret = 0;
                goto command_cleanup;
@@ -3637,13 +3608,15 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
 static int xhci_reserve_host_control_ep_resources(struct xhci_hcd *xhci)
 {
        if (xhci->num_active_eps + 1 > xhci->limit_active_eps) {
-               xhci_dbg(xhci, "Not enough ep ctxs: "
-                               "%u active, need to add 1, limit is %u.\n",
+               xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                               "Not enough ep ctxs: "
+                               "%u active, need to add 1, limit is %u.",
                                xhci->num_active_eps, xhci->limit_active_eps);
                return -ENOMEM;
        }
        xhci->num_active_eps += 1;
-       xhci_dbg(xhci, "Adding 1 ep ctx, %u now active.\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+                       "Adding 1 ep ctx, %u now active.",
                        xhci->num_active_eps);
        return 0;
 }
@@ -3743,7 +3716,8 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
        union xhci_trb *cmd_trb;
 
        if (!udev->slot_id) {
-               xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id);
+               xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+                               "Bad Slot ID %d", udev->slot_id);
                return -EINVAL;
        }
 
@@ -3782,6 +3756,8 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
 
        xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
        xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
+       trace_xhci_address_ctx(xhci, virt_dev->in_ctx,
+                               slot_ctx->dev_info >> 27);
 
        spin_lock_irqsave(&xhci->lock, flags);
        cmd_trb = xhci->cmd_ring->dequeue;
@@ -3789,7 +3765,8 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
                                        udev->slot_id);
        if (ret) {
                spin_unlock_irqrestore(&xhci->lock, flags);
-               xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+                               "FIXME: allocate a command ring segment");
                return ret;
        }
        xhci_ring_cmd_db(xhci);
@@ -3829,13 +3806,15 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
                ret = -ENODEV;
                break;
        case COMP_SUCCESS:
-               xhci_dbg(xhci, "Successful Address Device command\n");
+               xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+                               "Successful Address Device command");
                break;
        default:
                xhci_err(xhci, "ERROR: unexpected command completion "
                                "code 0x%x.\n", virt_dev->cmd_status);
                xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id);
                xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2);
+               trace_xhci_address_ctx(xhci, virt_dev->out_ctx, 1);
                ret = -EINVAL;
                break;
        }
@@ -3843,16 +3822,21 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
                return ret;
        }
        temp_64 = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
-       xhci_dbg(xhci, "Op regs DCBAA ptr = %#016llx\n", temp_64);
-       xhci_dbg(xhci, "Slot ID %d dcbaa entry @%p = %#016llx\n",
-                udev->slot_id,
-                &xhci->dcbaa->dev_context_ptrs[udev->slot_id],
-                (unsigned long long)
-                le64_to_cpu(xhci->dcbaa->dev_context_ptrs[udev->slot_id]));
-       xhci_dbg(xhci, "Output Context DMA address = %#08llx\n",
+       xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+                       "Op regs DCBAA ptr = %#016llx", temp_64);
+       xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+               "Slot ID %d dcbaa entry @%p = %#016llx",
+               udev->slot_id,
+               &xhci->dcbaa->dev_context_ptrs[udev->slot_id],
+               (unsigned long long)
+               le64_to_cpu(xhci->dcbaa->dev_context_ptrs[udev->slot_id]));
+       xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+                       "Output Context DMA address = %#08llx",
                        (unsigned long long)virt_dev->out_ctx->dma);
        xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
        xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
+       trace_xhci_address_ctx(xhci, virt_dev->in_ctx,
+                               slot_ctx->dev_info >> 27);
        xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id);
        xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2);
        /*
@@ -3860,6 +3844,8 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
         * address given back to us by the HC.
         */
        slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
+       trace_xhci_address_ctx(xhci, virt_dev->out_ctx,
+                               slot_ctx->dev_info >> 27);
        /* Use kernel assigned address for devices; store xHC assigned
         * address locally. */
        virt_dev->address = (le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK)
@@ -3868,7 +3854,8 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
        ctrl_ctx->add_flags = 0;
        ctrl_ctx->drop_flags = 0;
 
-       xhci_dbg(xhci, "Internal device address = %d\n", virt_dev->address);
+       xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+                       "Internal device address = %d", virt_dev->address);
 
        return 0;
 }
@@ -3934,7 +3921,8 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci,
        slot_ctx->dev_info2 &= cpu_to_le32(~((u32) MAX_EXIT));
        slot_ctx->dev_info2 |= cpu_to_le32(max_exit_latency);
 
-       xhci_dbg(xhci, "Set up evaluate context for LPM MEL change.\n");
+       xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
+                       "Set up evaluate context for LPM MEL change.");
        xhci_dbg(xhci, "Slot %u Input Context:\n", udev->slot_id);
        xhci_dbg_ctx(xhci, command->in_ctx, 0);
 
@@ -4354,7 +4342,7 @@ static u16 xhci_get_timeout_no_hub_lpm(struct usb_device *udev,
                                state_name, sel);
        else
                dev_dbg(&udev->dev, "Device-initiated %s disabled "
-                               "due to long PEL %llu\n ms",
+                               "due to long PEL %llu ms\n",
                                state_name, pel);
        return USB3_LPM_DISABLED;
 }
@@ -4838,10 +4826,13 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
        struct xhci_hcd         *xhci;
        struct device           *dev = hcd->self.controller;
        int                     retval;
-       u32                     temp;
 
        /* Accept arbitrarily long scatter-gather lists */
        hcd->self.sg_tablesize = ~0;
+
+       /* support to build packet from discontinuous buffers */
+       hcd->self.no_sg_constraint = 1;
+
        /* XHCI controllers don't stop the ep queue on short packets :| */
        hcd->self.no_stop_on_short = 1;
 
@@ -4866,14 +4857,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
                /* xHCI private pointer was set in xhci_pci_probe for the second
                 * registered roothub.
                 */
-               xhci = hcd_to_xhci(hcd);
-               temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
-               if (HCC_64BIT_ADDR(temp)) {
-                       xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
-                       dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64));
-               } else {
-                       dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
-               }
                return 0;
        }
 
@@ -4912,12 +4895,12 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
                goto error;
        xhci_dbg(xhci, "Reset complete\n");
 
-       temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
-       if (HCC_64BIT_ADDR(temp)) {
+       /* Set dma_mask and coherent_dma_mask to 64-bits,
+        * if xHC supports 64-bit addressing */
+       if (HCC_64BIT_ADDR(xhci->hcc_params) &&
+                       !dma_set_mask(dev, DMA_BIT_MASK(64))) {
                xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
-               dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64));
-       } else {
-               dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
+               dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
        }
 
        xhci_dbg(xhci, "Calling HCD init\n");
@@ -4942,12 +4925,12 @@ static int __init xhci_hcd_init(void)
 
        retval = xhci_register_pci();
        if (retval < 0) {
-               printk(KERN_DEBUG "Problem registering PCI driver.");
+               pr_debug("Problem registering PCI driver.\n");
                return retval;
        }
        retval = xhci_register_plat();
        if (retval < 0) {
-               printk(KERN_DEBUG "Problem registering platform driver.");
+               pr_debug("Problem registering platform driver.\n");
                goto unreg_pci;
        }
        /*
index c338741a675d1e254b590e81810f9b48db943f15..d2045916531b4bb49d88098f02a8d8592af98969 100644 (file)
@@ -1490,11 +1490,6 @@ struct xhci_hcd {
        struct dma_pool *small_streams_pool;
        struct dma_pool *medium_streams_pool;
 
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-       /* Poll the rings - for debugging */
-       struct timer_list       event_ring_timer;
-       int                     zombie;
-#endif
        /* Host controller watchdog timer structures */
        unsigned int            xhc_state;
 
@@ -1579,16 +1574,8 @@ static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci)
        return xhci->main_hcd;
 }
 
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-#define XHCI_DEBUG     1
-#else
-#define XHCI_DEBUG     0
-#endif
-
 #define xhci_dbg(xhci, fmt, args...) \
-       do { if (XHCI_DEBUG) dev_dbg(xhci_to_hcd(xhci)->self.controller , fmt , ## args); } while (0)
-#define xhci_info(xhci, fmt, args...) \
-       do { if (XHCI_DEBUG) dev_info(xhci_to_hcd(xhci)->self.controller , fmt , ## args); } while (0)
+       dev_dbg(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
 #define xhci_err(xhci, fmt, args...) \
        dev_err(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
 #define xhci_warn(xhci, fmt, args...) \
@@ -1660,6 +1647,8 @@ char *xhci_get_slot_state(struct xhci_hcd *xhci,
 void xhci_dbg_ep_rings(struct xhci_hcd *xhci,
                unsigned int slot_id, unsigned int ep_index,
                struct xhci_virt_ep *ep);
+void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *),
+                       const char *fmt, ...);
 
 /* xHCI memory management */
 void xhci_mem_cleanup(struct xhci_hcd *xhci);
index a51e7d6afda97ab9bbf28a46fd788ca9c43602c6..e2b21c1d9c403088d704d12901c8049e329c360f 100644 (file)
@@ -200,6 +200,19 @@ config USB_TEST
          See <http://www.linux-usb.org/usbtest/> for more information,
          including sample test device firmware and "how to use it".
 
+config USB_EHSET_TEST_FIXTURE
+        tristate "USB EHSET Test Fixture driver"
+        help
+         Say Y here if you want to support the special test fixture device
+         used for the USB-IF Embedded Host High-Speed Electrical Test procedure.
+
+         When the test fixture is connected, it can enumerate as one of several
+         VID/PID pairs. This driver then initiates a corresponding test mode on
+         the downstream port to which the test fixture is attached.
+
+         See <http://www.usb.org/developers/onthego/EHSET_v1.01.pdf> for more
+         information.
+
 config USB_ISIGHTFW
        tristate "iSight firmware loading support"
        select FW_LOADER
@@ -233,5 +246,6 @@ config USB_EZUSB_FX2
 config USB_HSIC_USB3503
        tristate "USB3503 HSIC to USB20 Driver"
        depends on I2C
+       select REGMAP
        help
          This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver.
index 3e1bd70b06ea2c4b5a4b12bc6a6d85de6375e0ac..e748fd5dbe94e0f44f20f194cd7cc43756e2f821 100644 (file)
@@ -2,9 +2,6 @@
 # Makefile for the rest of the USB drivers
 # (the ones that don't fit into any other categories)
 #
-
-ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
-
 obj-$(CONFIG_USB_ADUTUX)               += adutux.o
 obj-$(CONFIG_USB_APPLEDISPLAY)         += appledisplay.o
 obj-$(CONFIG_USB_CYPRESS_CY7C63)       += cypress_cy7c63.o
@@ -22,6 +19,7 @@ obj-$(CONFIG_USB_LED)                 += usbled.o
 obj-$(CONFIG_USB_LEGOTOWER)            += legousbtower.o
 obj-$(CONFIG_USB_RIO500)               += rio500.o
 obj-$(CONFIG_USB_TEST)                 += usbtest.o
+obj-$(CONFIG_USB_EHSET_TEST_FIXTURE)    += ehset.o
 obj-$(CONFIG_USB_TRANCEVIBRATOR)       += trancevibrator.o
 obj-$(CONFIG_USB_USS720)               += uss720.o
 obj-$(CONFIG_USB_SEVSEG)               += usbsevseg.o
index eeb27208c0d153de863f16ba12e62d0222e8c5d3..3eaa83f05086f90dba7f58df3902610d02537e72 100644 (file)
@@ -18,6 +18,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
 
-#ifdef CONFIG_USB_DEBUG
-static int debug = 5;
-#else
-static int debug = 1;
-#endif
-
-/* Use our own dbg macro */
-#undef dbg
-#define dbg(lvl, format, arg...)       \
-do {                                                           \
-       if (debug >= lvl)                                               \
-               printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg); \
-} while (0)
-
-
 /* Version Information */
 #define DRIVER_VERSION "v0.0.13"
 #define DRIVER_AUTHOR "John Homppi"
 #define DRIVER_DESC "adutux (see www.ontrak.net)"
 
-/* Module parameters */
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
-
 /* Define these values to match your device */
 #define ADU_VENDOR_ID 0x0a07
 #define ADU_PRODUCT_ID 0x0064
@@ -124,19 +107,11 @@ static DEFINE_MUTEX(adutux_mutex);
 
 static struct usb_driver adu_driver;
 
-static void adu_debug_data(int level, const char *function, int size,
-                          const unsigned char *data)
+static inline void adu_debug_data(struct device *dev, const char *function,
+                                 int size, const unsigned char *data)
 {
-       int i;
-
-       if (debug < level)
-               return;
-
-       printk(KERN_DEBUG "%s: %s - length = %d, data = ",
-              __FILE__, function, size);
-       for (i = 0; i < size; ++i)
-               printk("%.2x ", data[i]);
-       printk("\n");
+       dev_dbg(dev, "%s - length = %d, data = %*ph\n",
+               function, size, size, data);
 }
 
 /**
@@ -147,12 +122,8 @@ static void adu_abort_transfers(struct adu_device *dev)
 {
        unsigned long flags;
 
-       dbg(2, " %s : enter", __func__);
-
-       if (dev->udev == NULL) {
-               dbg(1, " %s : udev is null", __func__);
-               goto exit;
-       }
+       if (dev->udev == NULL)
+               return;
 
        /* shutdown transfer */
 
@@ -170,15 +141,10 @@ static void adu_abort_transfers(struct adu_device *dev)
                usb_kill_urb(dev->interrupt_out_urb);
        } else
                spin_unlock_irqrestore(&dev->buflock, flags);
-
-exit:
-       dbg(2, " %s : leave", __func__);
 }
 
 static void adu_delete(struct adu_device *dev)
 {
-       dbg(2, "%s enter", __func__);
-
        /* free data structures */
        usb_free_urb(dev->interrupt_in_urb);
        usb_free_urb(dev->interrupt_out_urb);
@@ -187,8 +153,6 @@ static void adu_delete(struct adu_device *dev)
        kfree(dev->interrupt_in_buffer);
        kfree(dev->interrupt_out_buffer);
        kfree(dev);
-
-       dbg(2, "%s : leave", __func__);
 }
 
 static void adu_interrupt_in_callback(struct urb *urb)
@@ -196,17 +160,17 @@ static void adu_interrupt_in_callback(struct urb *urb)
        struct adu_device *dev = urb->context;
        int status = urb->status;
 
-       dbg(4, " %s : enter, status %d", __func__, status);
-       adu_debug_data(5, __func__, urb->actual_length,
-                      urb->transfer_buffer);
+       adu_debug_data(&dev->udev->dev, __func__,
+                      urb->actual_length, urb->transfer_buffer);
 
        spin_lock(&dev->buflock);
 
        if (status != 0) {
                if ((status != -ENOENT) && (status != -ECONNRESET) &&
                        (status != -ESHUTDOWN)) {
-                       dbg(1, " %s : nonzero status received: %d",
-                           __func__, status);
+                       dev_dbg(&dev->udev->dev,
+                               "%s : nonzero status received: %d\n",
+                               __func__, status);
                }
                goto exit;
        }
@@ -220,10 +184,11 @@ static void adu_interrupt_in_callback(struct urb *urb)
                                dev->interrupt_in_buffer, urb->actual_length);
 
                        dev->read_buffer_length += urb->actual_length;
-                       dbg(2, " %s reading  %d ", __func__,
-                           urb->actual_length);
+                       dev_dbg(&dev->udev->dev,"%s reading  %d\n", __func__,
+                               urb->actual_length);
                } else {
-                       dbg(1, " %s : read_buffer overflow", __func__);
+                       dev_dbg(&dev->udev->dev,"%s : read_buffer overflow\n",
+                               __func__);
                }
        }
 
@@ -232,9 +197,6 @@ exit:
        spin_unlock(&dev->buflock);
        /* always wake up so we recover from errors */
        wake_up_interruptible(&dev->read_wait);
-       adu_debug_data(5, __func__, urb->actual_length,
-                      urb->transfer_buffer);
-       dbg(4, " %s : leave, status %d", __func__, status);
 }
 
 static void adu_interrupt_out_callback(struct urb *urb)
@@ -242,27 +204,23 @@ static void adu_interrupt_out_callback(struct urb *urb)
        struct adu_device *dev = urb->context;
        int status = urb->status;
 
-       dbg(4, " %s : enter, status %d", __func__, status);
-       adu_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
+       adu_debug_data(&dev->udev->dev, __func__,
+                      urb->actual_length, urb->transfer_buffer);
 
        if (status != 0) {
                if ((status != -ENOENT) &&
                    (status != -ECONNRESET)) {
-                       dbg(1, " %s :nonzero status received: %d",
-                           __func__, status);
+                       dev_dbg(&dev->udev->dev,
+                               "%s :nonzero status received: %d\n", __func__,
+                               status);
                }
-               goto exit;
+               return;
        }
 
        spin_lock(&dev->buflock);
        dev->out_urb_finished = 1;
        wake_up(&dev->write_wait);
        spin_unlock(&dev->buflock);
-exit:
-
-       adu_debug_data(5, __func__, urb->actual_length,
-                      urb->transfer_buffer);
-       dbg(4, " %s : leave, status %d", __func__, status);
 }
 
 static int adu_open(struct inode *inode, struct file *file)
@@ -272,20 +230,16 @@ static int adu_open(struct inode *inode, struct file *file)
        int subminor;
        int retval;
 
-       dbg(2, "%s : enter", __func__);
-
        subminor = iminor(inode);
 
        retval = mutex_lock_interruptible(&adutux_mutex);
-       if (retval) {
-               dbg(2, "%s : mutex lock failed", __func__);
+       if (retval)
                goto exit_no_lock;
-       }
 
        interface = usb_find_interface(&adu_driver, subminor);
        if (!interface) {
-               printk(KERN_ERR "adutux: %s - error, can't find device for "
-                      "minor %d\n", __func__, subminor);
+               pr_err("%s - error, can't find device for minor %d\n",
+                      __func__, subminor);
                retval = -ENODEV;
                goto exit_no_device;
        }
@@ -303,7 +257,8 @@ static int adu_open(struct inode *inode, struct file *file)
        }
 
        ++dev->open_count;
-       dbg(2, "%s : open count %d", __func__, dev->open_count);
+       dev_dbg(&dev->udev->dev, "%s: open count %d\n", __func__,
+               dev->open_count);
 
        /* save device in the file's private structure */
        file->private_data = dev;
@@ -333,23 +288,19 @@ static int adu_open(struct inode *inode, struct file *file)
 exit_no_device:
        mutex_unlock(&adutux_mutex);
 exit_no_lock:
-       dbg(2, "%s : leave, return value %d ", __func__, retval);
        return retval;
 }
 
 static void adu_release_internal(struct adu_device *dev)
 {
-       dbg(2, " %s : enter", __func__);
-
        /* decrement our usage count for the device */
        --dev->open_count;
-       dbg(2, " %s : open count %d", __func__, dev->open_count);
+       dev_dbg(&dev->udev->dev, "%s : open count %d\n", __func__,
+               dev->open_count);
        if (dev->open_count <= 0) {
                adu_abort_transfers(dev);
                dev->open_count = 0;
        }
-
-       dbg(2, " %s : leave", __func__);
 }
 
 static int adu_release(struct inode *inode, struct file *file)
@@ -357,17 +308,13 @@ static int adu_release(struct inode *inode, struct file *file)
        struct adu_device *dev;
        int retval = 0;
 
-       dbg(2, " %s : enter", __func__);
-
        if (file == NULL) {
-               dbg(1, " %s : file is NULL", __func__);
                retval = -ENODEV;
                goto exit;
        }
 
        dev = file->private_data;
        if (dev == NULL) {
-               dbg(1, " %s : object is NULL", __func__);
                retval = -ENODEV;
                goto exit;
        }
@@ -375,7 +322,7 @@ static int adu_release(struct inode *inode, struct file *file)
        mutex_lock(&adutux_mutex); /* not interruptible */
 
        if (dev->open_count <= 0) {
-               dbg(1, " %s : device not opened", __func__);
+               dev_dbg(&dev->udev->dev, "%s : device not opened\n", __func__);
                retval = -ENODEV;
                goto unlock;
        }
@@ -389,7 +336,6 @@ static int adu_release(struct inode *inode, struct file *file)
 unlock:
        mutex_unlock(&adutux_mutex);
 exit:
-       dbg(2, " %s : leave, return value %d", __func__, retval);
        return retval;
 }
 
@@ -406,35 +352,32 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
        unsigned long flags;
        DECLARE_WAITQUEUE(wait, current);
 
-       dbg(2, " %s : enter, count = %Zd, file=%p", __func__, count, file);
-
        dev = file->private_data;
-       dbg(2, " %s : dev=%p", __func__, dev);
-
        if (mutex_lock_interruptible(&dev->mtx))
                return -ERESTARTSYS;
 
        /* verify that the device wasn't unplugged */
        if (dev->udev == NULL) {
                retval = -ENODEV;
-               printk(KERN_ERR "adutux: No device or device unplugged %d\n",
-                      retval);
+               pr_err("No device or device unplugged %d\n", retval);
                goto exit;
        }
 
        /* verify that some data was requested */
        if (count == 0) {
-               dbg(1, " %s : read request of 0 bytes", __func__);
+               dev_dbg(&dev->udev->dev, "%s : read request of 0 bytes\n",
+                       __func__);
                goto exit;
        }
 
        timeout = COMMAND_TIMEOUT;
-       dbg(2, " %s : about to start looping", __func__);
+       dev_dbg(&dev->udev->dev, "%s : about to start looping\n", __func__);
        while (bytes_to_read) {
                int data_in_secondary = dev->secondary_tail - dev->secondary_head;
-               dbg(2, " %s : while, data_in_secondary=%d, status=%d",
-                   __func__, data_in_secondary,
-                   dev->interrupt_in_urb->status);
+               dev_dbg(&dev->udev->dev,
+                       "%s : while, data_in_secondary=%d, status=%d\n",
+                       __func__, data_in_secondary,
+                       dev->interrupt_in_urb->status);
 
                if (data_in_secondary) {
                        /* drain secondary buffer */
@@ -457,8 +400,9 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
                        if (dev->read_buffer_length) {
                                /* we secure access to the primary */
                                char *tmp;
-                               dbg(2, " %s : swap, read_buffer_length = %d",
-                                   __func__, dev->read_buffer_length);
+                               dev_dbg(&dev->udev->dev,
+                                       "%s : swap, read_buffer_length = %d\n",
+                                       __func__, dev->read_buffer_length);
                                tmp = dev->read_buffer_secondary;
                                dev->read_buffer_secondary = dev->read_buffer_primary;
                                dev->read_buffer_primary = tmp;
@@ -473,10 +417,14 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
                                if (!dev->read_urb_finished) {
                                        /* somebody is doing IO */
                                        spin_unlock_irqrestore(&dev->buflock, flags);
-                                       dbg(2, " %s : submitted already", __func__);
+                                       dev_dbg(&dev->udev->dev,
+                                               "%s : submitted already\n",
+                                               __func__);
                                } else {
                                        /* we must initiate input */
-                                       dbg(2, " %s : initiate input", __func__);
+                                       dev_dbg(&dev->udev->dev,
+                                               "%s : initiate input\n",
+                                               __func__);
                                        dev->read_urb_finished = 0;
                                        spin_unlock_irqrestore(&dev->buflock, flags);
 
@@ -494,7 +442,9 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
                                                if (retval == -ENOMEM) {
                                                        retval = bytes_read ? bytes_read : -ENOMEM;
                                                }
-                                               dbg(2, " %s : submit failed", __func__);
+                                               dev_dbg(&dev->udev->dev,
+                                                       "%s : submit failed\n",
+                                                       __func__);
                                                goto exit;
                                        }
                                }
@@ -513,13 +463,16 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
                                remove_wait_queue(&dev->read_wait, &wait);
 
                                if (timeout <= 0) {
-                                       dbg(2, " %s : timeout", __func__);
+                                       dev_dbg(&dev->udev->dev,
+                                               "%s : timeout\n", __func__);
                                        retval = bytes_read ? bytes_read : -ETIMEDOUT;
                                        goto exit;
                                }
 
                                if (signal_pending(current)) {
-                                       dbg(2, " %s : signal pending", __func__);
+                                       dev_dbg(&dev->udev->dev,
+                                               "%s : signal pending\n",
+                                               __func__);
                                        retval = bytes_read ? bytes_read : -EINTR;
                                        goto exit;
                                }
@@ -552,7 +505,6 @@ exit:
        /* unlock the device */
        mutex_unlock(&dev->mtx);
 
-       dbg(2, " %s : leave, return value %d", __func__, retval);
        return retval;
 }
 
@@ -567,8 +519,6 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
        unsigned long flags;
        int retval;
 
-       dbg(2, " %s : enter, count = %Zd", __func__, count);
-
        dev = file->private_data;
 
        retval = mutex_lock_interruptible(&dev->mtx);
@@ -578,14 +528,14 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
        /* verify that the device wasn't unplugged */
        if (dev->udev == NULL) {
                retval = -ENODEV;
-               printk(KERN_ERR "adutux: No device or device unplugged %d\n",
-                      retval);
+               pr_err("No device or device unplugged %d\n", retval);
                goto exit;
        }
 
        /* verify that we actually have some data to write */
        if (count == 0) {
-               dbg(1, " %s : write request of 0 bytes", __func__);
+               dev_dbg(&dev->udev->dev, "%s : write request of 0 bytes\n",
+                       __func__);
                goto exit;
        }
 
@@ -598,13 +548,15 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
 
                        mutex_unlock(&dev->mtx);
                        if (signal_pending(current)) {
-                               dbg(1, " %s : interrupted", __func__);
+                               dev_dbg(&dev->udev->dev, "%s : interrupted\n",
+                                       __func__);
                                set_current_state(TASK_RUNNING);
                                retval = -EINTR;
                                goto exit_onqueue;
                        }
                        if (schedule_timeout(COMMAND_TIMEOUT) == 0) {
-                               dbg(1, "%s - command timed out.", __func__);
+                               dev_dbg(&dev->udev->dev,
+                                       "%s - command timed out.\n", __func__);
                                retval = -ETIMEDOUT;
                                goto exit_onqueue;
                        }
@@ -615,18 +567,22 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
                                goto exit_nolock;
                        }
 
-                       dbg(4, " %s : in progress, count = %Zd", __func__, count);
+                       dev_dbg(&dev->udev->dev,
+                               "%s : in progress, count = %Zd\n",
+                               __func__, count);
                } else {
                        spin_unlock_irqrestore(&dev->buflock, flags);
                        set_current_state(TASK_RUNNING);
                        remove_wait_queue(&dev->write_wait, &waita);
-                       dbg(4, " %s : sending, count = %Zd", __func__, count);
+                       dev_dbg(&dev->udev->dev, "%s : sending, count = %Zd\n",
+                               __func__, count);
 
                        /* write the data into interrupt_out_buffer from userspace */
                        buffer_size = usb_endpoint_maxp(dev->interrupt_out_endpoint);
                        bytes_to_write = count > buffer_size ? buffer_size : count;
-                       dbg(4, " %s : buffer_size = %Zd, count = %Zd, bytes_to_write = %Zd",
-                           __func__, buffer_size, count, bytes_to_write);
+                       dev_dbg(&dev->udev->dev,
+                               "%s : buffer_size = %Zd, count = %Zd, bytes_to_write = %Zd\n",
+                               __func__, buffer_size, count, bytes_to_write);
 
                        if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write) != 0) {
                                retval = -EFAULT;
@@ -665,7 +621,6 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
 exit:
        mutex_unlock(&dev->mtx);
 exit_nolock:
-       dbg(2, " %s : leave, return value %d", __func__, retval);
        return retval;
 
 exit_onqueue:
@@ -711,8 +666,6 @@ static int adu_probe(struct usb_interface *interface,
        int out_end_size;
        int i;
 
-       dbg(2, " %s : enter", __func__);
-
        if (udev == NULL) {
                dev_err(&interface->dev, "udev is NULL.\n");
                goto exit;
@@ -812,7 +765,7 @@ static int adu_probe(struct usb_interface *interface,
                dev_err(&interface->dev, "Could not retrieve serial number\n");
                goto error;
        }
-       dbg(2, " %s : serial_number=%s", __func__, dev->serial_number);
+       dev_dbg(&interface->dev,"serial_number=%s", dev->serial_number);
 
        /* we can register the device now, as it is ready */
        usb_set_intfdata(interface, dev);
@@ -833,8 +786,6 @@ static int adu_probe(struct usb_interface *interface,
                 le16_to_cpu(udev->descriptor.idProduct), dev->serial_number,
                 (dev->minor - ADU_MINOR_BASE));
 exit:
-       dbg(2, " %s : leave, return value %p (dev)", __func__, dev);
-
        return retval;
 
 error:
@@ -852,8 +803,6 @@ static void adu_disconnect(struct usb_interface *interface)
        struct adu_device *dev;
        int minor;
 
-       dbg(2, " %s : enter", __func__);
-
        dev = usb_get_intfdata(interface);
 
        mutex_lock(&dev->mtx);  /* not interruptible */
@@ -866,7 +815,8 @@ static void adu_disconnect(struct usb_interface *interface)
        usb_set_intfdata(interface, NULL);
 
        /* if the device is not opened, then we clean up right now */
-       dbg(2, " %s : open count %d", __func__, dev->open_count);
+       dev_dbg(&dev->udev->dev, "%s : open count %d\n",
+               __func__, dev->open_count);
        if (!dev->open_count)
                adu_delete(dev);
 
@@ -874,8 +824,6 @@ static void adu_disconnect(struct usb_interface *interface)
 
        dev_info(&interface->dev, "ADU device adutux%d now disconnected\n",
                 (minor - ADU_MINOR_BASE));
-
-       dbg(2, " %s : leave", __func__);
 }
 
 /* usb specific object needed to register this driver with the usb subsystem */
diff --git a/drivers/usb/misc/ehset.c b/drivers/usb/misc/ehset.c
new file mode 100644 (file)
index 0000000..c31b4a3
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/ch11.h>
+
+#define TEST_SE0_NAK_PID                       0x0101
+#define TEST_J_PID                             0x0102
+#define TEST_K_PID                             0x0103
+#define TEST_PACKET_PID                                0x0104
+#define TEST_HS_HOST_PORT_SUSPEND_RESUME       0x0106
+#define TEST_SINGLE_STEP_GET_DEV_DESC          0x0107
+#define TEST_SINGLE_STEP_SET_FEATURE           0x0108
+
+static int ehset_probe(struct usb_interface *intf,
+                      const struct usb_device_id *id)
+{
+       int ret = -EINVAL;
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct usb_device *hub_udev = dev->parent;
+       struct usb_device_descriptor *buf;
+       u8 portnum = dev->portnum;
+       u16 test_pid = le16_to_cpu(dev->descriptor.idProduct);
+
+       switch (test_pid) {
+       case TEST_SE0_NAK_PID:
+               ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+                                       USB_REQ_SET_FEATURE, USB_RT_PORT,
+                                       USB_PORT_FEAT_TEST,
+                                       (TEST_SE0_NAK << 8) | portnum,
+                                       NULL, 0, 1000);
+               break;
+       case TEST_J_PID:
+               ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+                                       USB_REQ_SET_FEATURE, USB_RT_PORT,
+                                       USB_PORT_FEAT_TEST,
+                                       (TEST_J << 8) | portnum,
+                                       NULL, 0, 1000);
+               break;
+       case TEST_K_PID:
+               ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+                                       USB_REQ_SET_FEATURE, USB_RT_PORT,
+                                       USB_PORT_FEAT_TEST,
+                                       (TEST_K << 8) | portnum,
+                                       NULL, 0, 1000);
+               break;
+       case TEST_PACKET_PID:
+               ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+                                       USB_REQ_SET_FEATURE, USB_RT_PORT,
+                                       USB_PORT_FEAT_TEST,
+                                       (TEST_PACKET << 8) | portnum,
+                                       NULL, 0, 1000);
+               break;
+       case TEST_HS_HOST_PORT_SUSPEND_RESUME:
+               /* Test: wait for 15secs -> suspend -> 15secs delay -> resume */
+               msleep(15 * 1000);
+               ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+                                       USB_REQ_SET_FEATURE, USB_RT_PORT,
+                                       USB_PORT_FEAT_SUSPEND, portnum,
+                                       NULL, 0, 1000);
+               if (ret < 0)
+                       break;
+
+               msleep(15 * 1000);
+               ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+                                       USB_REQ_CLEAR_FEATURE, USB_RT_PORT,
+                                       USB_PORT_FEAT_SUSPEND, portnum,
+                                       NULL, 0, 1000);
+               break;
+       case TEST_SINGLE_STEP_GET_DEV_DESC:
+               /* Test: wait for 15secs -> GetDescriptor request */
+               msleep(15 * 1000);
+               buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
+               if (!buf)
+                       return -ENOMEM;
+
+               ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                                       USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+                                       USB_DT_DEVICE << 8, 0,
+                                       buf, USB_DT_DEVICE_SIZE,
+                                       USB_CTRL_GET_TIMEOUT);
+               kfree(buf);
+               break;
+       case TEST_SINGLE_STEP_SET_FEATURE:
+               /*
+                * GetDescriptor SETUP request -> 15secs delay -> IN & STATUS
+                *
+                * Note, this test is only supported on root hubs since the
+                * SetPortFeature handling can only be done inside the HCD's
+                * hub_control callback function.
+                */
+               if (hub_udev != dev->bus->root_hub) {
+                       dev_err(&intf->dev, "SINGLE_STEP_SET_FEATURE test only supported on root hub\n");
+                       break;
+               }
+
+               ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+                                       USB_REQ_SET_FEATURE, USB_RT_PORT,
+                                       USB_PORT_FEAT_TEST,
+                                       (6 << 8) | portnum,
+                                       NULL, 0, 60 * 1000);
+
+               break;
+       default:
+               dev_err(&intf->dev, "%s: unsupported PID: 0x%x\n",
+                       __func__, test_pid);
+       }
+
+       return (ret < 0) ? ret : 0;
+}
+
+static void ehset_disconnect(struct usb_interface *intf)
+{
+}
+
+static const struct usb_device_id ehset_id_table[] = {
+       { USB_DEVICE(0x1a0a, TEST_SE0_NAK_PID) },
+       { USB_DEVICE(0x1a0a, TEST_J_PID) },
+       { USB_DEVICE(0x1a0a, TEST_K_PID) },
+       { USB_DEVICE(0x1a0a, TEST_PACKET_PID) },
+       { USB_DEVICE(0x1a0a, TEST_HS_HOST_PORT_SUSPEND_RESUME) },
+       { USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_GET_DEV_DESC) },
+       { USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_SET_FEATURE) },
+       { }                     /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, ehset_id_table);
+
+static struct usb_driver ehset_driver = {
+       .name =         "usb_ehset_test",
+       .probe =        ehset_probe,
+       .disconnect =   ehset_disconnect,
+       .id_table =     ehset_id_table,
+};
+
+module_usb_driver(ehset_driver);
+
+MODULE_DESCRIPTION("USB Driver for EHSET Test Fixture");
+MODULE_LICENSE("GPL v2");
index ac762299eaa88bce23509be8bd22a315824101f3..b1d59532ac2255e530a35f93d0055894f9f4fbfa 100644 (file)
@@ -129,19 +129,6 @@ MODULE_DESCRIPTION("LD USB Driver");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("LD USB Devices");
 
-#ifdef CONFIG_USB_DEBUG
-       static int debug = 1;
-#else
-       static int debug = 0;
-#endif
-
-/* Use our own dbg macro */
-#define dbg_info(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
-
-/* Module parameters */
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
-
 /* All interrupt in transfers are collected in a ring buffer to
  * avoid racing conditions and get better performance of the driver.
  */
@@ -256,8 +243,9 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
                    status == -ESHUTDOWN) {
                        goto exit;
                } else {
-                       dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
-                                __func__, status);
+                       dev_dbg(&dev->intf->dev,
+                               "%s: nonzero status received: %d\n", __func__,
+                               status);
                        spin_lock(&dev->rbsl);
                        goto resubmit; /* maybe we can recover */
                }
@@ -272,8 +260,8 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
                        *actual_buffer = urb->actual_length;
                        memcpy(actual_buffer+1, dev->interrupt_in_buffer, urb->actual_length);
                        dev->ring_head = next_ring_head;
-                       dbg_info(&dev->intf->dev, "%s: received %d bytes\n",
-                                __func__, urb->actual_length);
+                       dev_dbg(&dev->intf->dev, "%s: received %d bytes\n",
+                               __func__, urb->actual_length);
                } else {
                        dev_warn(&dev->intf->dev,
                                 "Ring buffer overflow, %d bytes dropped\n",
@@ -310,9 +298,9 @@ static void ld_usb_interrupt_out_callback(struct urb *urb)
        if (status && !(status == -ENOENT ||
                        status == -ECONNRESET ||
                        status == -ESHUTDOWN))
-               dbg_info(&dev->intf->dev,
-                        "%s - nonzero write interrupt status received: %d\n",
-                        __func__, status);
+               dev_dbg(&dev->intf->dev,
+                       "%s - nonzero write interrupt status received: %d\n",
+                       __func__, status);
 
        dev->interrupt_out_busy = 0;
        wake_up_interruptible(&dev->write_wait);
@@ -585,7 +573,8 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
        bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size);
        if (bytes_to_write < count)
                dev_warn(&dev->intf->dev, "Write buffer overflow, %zd bytes dropped\n",count-bytes_to_write);
-       dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", __func__, count, bytes_to_write);
+       dev_dbg(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n",
+               __func__, count, bytes_to_write);
 
        if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) {
                retval = -EFAULT;
index 80894791c02003fb8ee628e8ed722411bb174ee9..eb37c9542052846396c9c38ea7cc3da7079266ab 100644 (file)
@@ -75,6 +75,8 @@
  *   - move reset into open to clean out spurious data
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/poll.h>
 
 
-#ifdef CONFIG_USB_DEBUG
-       static int debug = 4;
-#else
-       static int debug = 0;
-#endif
-
-/* Use our own dbg macro */
-#undef dbg
-#define dbg(lvl, format, arg...)                                       \
-do {                                                                   \
-       if (debug >= lvl)                                               \
-               printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg); \
-} while (0)
-
 /* Version Information */
 #define DRIVER_VERSION "v0.96"
 #define DRIVER_AUTHOR "Juergen Stuber <starblue@sourceforge.net>"
 #define DRIVER_DESC "LEGO USB Tower Driver"
 
-/* Module parameters */
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
 
 /* The defaults are chosen to work with the latest versions of leJOS and NQC.
  */
@@ -298,18 +283,12 @@ static struct usb_driver tower_driver = {
 /**
  *     lego_usb_tower_debug_data
  */
-static inline void lego_usb_tower_debug_data (int level, const char *function, int size, const unsigned char *data)
+static inline void lego_usb_tower_debug_data(struct device *dev,
+                                            const char *function, int size,
+                                            const unsigned char *data)
 {
-       int i;
-
-       if (debug < level)
-               return;
-
-       printk (KERN_DEBUG "%s: %s - length = %d, data = ", __FILE__, function, size);
-       for (i = 0; i < size; ++i) {
-               printk ("%.2x ", data[i]);
-       }
-       printk ("\n");
+       dev_dbg(dev, "%s - length = %d, data = %*ph\n",
+               function, size, size, data);
 }
 
 
@@ -318,8 +297,6 @@ static inline void lego_usb_tower_debug_data (int level, const char *function, i
  */
 static inline void tower_delete (struct lego_usb_tower *dev)
 {
-       dbg(2, "%s: enter", __func__);
-
        tower_abort_transfers (dev);
 
        /* free data structures */
@@ -329,8 +306,6 @@ static inline void tower_delete (struct lego_usb_tower *dev)
        kfree (dev->interrupt_in_buffer);
        kfree (dev->interrupt_out_buffer);
        kfree (dev);
-
-       dbg(2, "%s: leave", __func__);
 }
 
 
@@ -346,16 +321,13 @@ static int tower_open (struct inode *inode, struct file *file)
        struct tower_reset_reply reset_reply;
        int result;
 
-       dbg(2, "%s: enter", __func__);
-
        nonseekable_open(inode, file);
        subminor = iminor(inode);
 
        interface = usb_find_interface (&tower_driver, subminor);
 
        if (!interface) {
-               printk(KERN_ERR "%s - error, can't find device for minor %d\n",
-                      __func__, subminor);
+               pr_err("error, can't find device for minor %d\n", subminor);
                retval = -ENODEV;
                goto exit;
        }
@@ -435,8 +407,6 @@ unlock_exit:
        mutex_unlock(&dev->lock);
 
 exit:
-       dbg(2, "%s: leave, return value %d ", __func__, retval);
-
        return retval;
 }
 
@@ -448,12 +418,9 @@ static int tower_release (struct inode *inode, struct file *file)
        struct lego_usb_tower *dev;
        int retval = 0;
 
-       dbg(2, "%s: enter", __func__);
-
        dev = file->private_data;
 
        if (dev == NULL) {
-               dbg(1, "%s: object is NULL", __func__);
                retval = -ENODEV;
                goto exit_nolock;
        }
@@ -465,7 +432,8 @@ static int tower_release (struct inode *inode, struct file *file)
        }
 
        if (dev->open_count != 1) {
-               dbg(1, "%s: device not opened exactly once", __func__);
+               dev_dbg(&dev->udev->dev, "%s: device not opened exactly once\n",
+                       __func__);
                retval = -ENODEV;
                goto unlock_exit;
        }
@@ -491,7 +459,6 @@ unlock_exit:
 exit:
        mutex_unlock(&open_disc_mutex);
 exit_nolock:
-       dbg(2, "%s: leave, return value %d", __func__, retval);
        return retval;
 }
 
@@ -502,12 +469,8 @@ exit_nolock:
  */
 static void tower_abort_transfers (struct lego_usb_tower *dev)
 {
-       dbg(2, "%s: enter", __func__);
-
-       if (dev == NULL) {
-               dbg(1, "%s: dev is null", __func__);
-               goto exit;
-       }
+       if (dev == NULL)
+               return;
 
        /* shutdown transfer */
        if (dev->interrupt_in_running) {
@@ -518,9 +481,6 @@ static void tower_abort_transfers (struct lego_usb_tower *dev)
        }
        if (dev->interrupt_out_busy && dev->udev)
                usb_kill_urb(dev->interrupt_out_urb);
-
-exit:
-       dbg(2, "%s: leave", __func__);
 }
 
 
@@ -553,8 +513,6 @@ static unsigned int tower_poll (struct file *file, poll_table *wait)
        struct lego_usb_tower *dev;
        unsigned int mask = 0;
 
-       dbg(2, "%s: enter", __func__);
-
        dev = file->private_data;
 
        if (!dev->udev)
@@ -571,8 +529,6 @@ static unsigned int tower_poll (struct file *file, poll_table *wait)
                mask |= POLLOUT | POLLWRNORM;
        }
 
-       dbg(2, "%s: leave, mask = %d", __func__, mask);
-
        return mask;
 }
 
@@ -597,8 +553,6 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count,
        int retval = 0;
        unsigned long timeout = 0;
 
-       dbg(2, "%s: enter, count = %Zd", __func__, count);
-
        dev = file->private_data;
 
        /* lock this object */
@@ -610,13 +564,13 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count,
        /* verify that the device wasn't unplugged */
        if (dev->udev == NULL) {
                retval = -ENODEV;
-               printk(KERN_ERR "legousbtower: No device or device unplugged %d\n", retval);
+               pr_err("No device or device unplugged %d\n", retval);
                goto unlock_exit;
        }
 
        /* verify that we actually have some data to read */
        if (count == 0) {
-               dbg(1, "%s: read request of 0 bytes", __func__);
+               dev_dbg(&dev->udev->dev, "read request of 0 bytes\n");
                goto unlock_exit;
        }
 
@@ -672,7 +626,6 @@ unlock_exit:
        mutex_unlock(&dev->lock);
 
 exit:
-       dbg(2, "%s: leave, return value %d", __func__, retval);
        return retval;
 }
 
@@ -686,8 +639,6 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
        size_t bytes_to_write;
        int retval = 0;
 
-       dbg(2, "%s: enter, count = %Zd", __func__, count);
-
        dev = file->private_data;
 
        /* lock this object */
@@ -699,13 +650,13 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
        /* verify that the device wasn't unplugged */
        if (dev->udev == NULL) {
                retval = -ENODEV;
-               printk(KERN_ERR "legousbtower: No device or device unplugged %d\n", retval);
+               pr_err("No device or device unplugged %d\n", retval);
                goto unlock_exit;
        }
 
        /* verify that we actually have some data to write */
        if (count == 0) {
-               dbg(1, "%s: write request of 0 bytes", __func__);
+               dev_dbg(&dev->udev->dev, "write request of 0 bytes\n");
                goto unlock_exit;
        }
 
@@ -723,7 +674,8 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
 
        /* write the data into interrupt_out_buffer from userspace */
        bytes_to_write = min_t(int, count, write_buffer_size);
-       dbg(4, "%s: count = %Zd, bytes_to_write = %Zd", __func__, count, bytes_to_write);
+       dev_dbg(&dev->udev->dev, "%s: count = %Zd, bytes_to_write = %Zd\n",
+               __func__, count, bytes_to_write);
 
        if (copy_from_user (dev->interrupt_out_buffer, buffer, bytes_to_write)) {
                retval = -EFAULT;
@@ -757,8 +709,6 @@ unlock_exit:
        mutex_unlock(&dev->lock);
 
 exit:
-       dbg(2, "%s: leave, return value %d", __func__, retval);
-
        return retval;
 }
 
@@ -772,9 +722,8 @@ static void tower_interrupt_in_callback (struct urb *urb)
        int status = urb->status;
        int retval;
 
-       dbg(4, "%s: enter, status %d", __func__, status);
-
-       lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
+       lego_usb_tower_debug_data(&dev->udev->dev, __func__,
+                                 urb->actual_length, urb->transfer_buffer);
 
        if (status) {
                if (status == -ENOENT ||
@@ -782,7 +731,9 @@ static void tower_interrupt_in_callback (struct urb *urb)
                    status == -ESHUTDOWN) {
                        goto exit;
                } else {
-                       dbg(1, "%s: nonzero status received: %d", __func__, status);
+                       dev_dbg(&dev->udev->dev,
+                               "%s: nonzero status received: %d\n", __func__,
+                               status);
                        goto resubmit; /* maybe we can recover */
                }
        }
@@ -795,9 +746,11 @@ static void tower_interrupt_in_callback (struct urb *urb)
                                urb->actual_length);
                        dev->read_buffer_length += urb->actual_length;
                        dev->read_last_arrival = jiffies;
-                       dbg(3, "%s: received %d bytes", __func__, urb->actual_length);
+                       dev_dbg(&dev->udev->dev, "%s: received %d bytes\n",
+                               __func__, urb->actual_length);
                } else {
-                       printk(KERN_WARNING "%s: read_buffer overflow, %d bytes dropped", __func__, urb->actual_length);
+                       pr_warn("read_buffer overflow, %d bytes dropped\n",
+                               urb->actual_length);
                }
                spin_unlock (&dev->read_buffer_lock);
        }
@@ -815,9 +768,6 @@ resubmit:
 exit:
        dev->interrupt_in_done = 1;
        wake_up_interruptible (&dev->read_wait);
-
-       lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
-       dbg(4, "%s: leave, status %d", __func__, status);
 }
 
 
@@ -829,22 +779,20 @@ static void tower_interrupt_out_callback (struct urb *urb)
        struct lego_usb_tower *dev = urb->context;
        int status = urb->status;
 
-       dbg(4, "%s: enter, status %d", __func__, status);
-       lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
+       lego_usb_tower_debug_data(&dev->udev->dev, __func__,
+                                 urb->actual_length, urb->transfer_buffer);
 
        /* sync/async unlink faults aren't errors */
        if (status && !(status == -ENOENT ||
                        status == -ECONNRESET ||
                        status == -ESHUTDOWN)) {
-               dbg(1, "%s - nonzero write bulk status received: %d",
-                   __func__, status);
+               dev_dbg(&dev->udev->dev,
+                       "%s: nonzero write bulk status received: %d\n", __func__,
+                       status);
        }
 
        dev->interrupt_out_busy = 0;
        wake_up_interruptible(&dev->write_wait);
-
-       lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
-       dbg(4, "%s: leave, status %d", __func__, status);
 }
 
 
@@ -866,8 +814,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
        int retval = -ENOMEM;
        int result;
 
-       dbg(2, "%s: enter", __func__);
-
        /* allocate memory for our device state and initialize it */
 
        dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL);
@@ -993,8 +939,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
 
 
 exit:
-       dbg(2, "%s: leave, return value 0x%.8lx (dev)", __func__, (long) dev);
-
        return retval;
 
 error:
@@ -1013,8 +957,6 @@ static void tower_disconnect (struct usb_interface *interface)
        struct lego_usb_tower *dev;
        int minor;
 
-       dbg(2, "%s: enter", __func__);
-
        dev = usb_get_intfdata (interface);
        mutex_lock(&open_disc_mutex);
        usb_set_intfdata (interface, NULL);
@@ -1041,8 +983,6 @@ static void tower_disconnect (struct usb_interface *interface)
 
        dev_info(&interface->dev, "LEGO USB Tower #%d now disconnected\n",
                 (minor - LEGO_USB_TOWER_MINOR_BASE));
-
-       dbg(2, "%s: leave", __func__);
 }
 
 module_usb_driver(tower_driver);
index c3578393ddeffc427906f362daa8d0ca39576e10..a31641e18d198fa12ffde7b5bbc32cac01ae1d73 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/platform_data/usb3503.h>
+#include <linux/regmap.h>
 
 #define USB3503_VIDL           0x00
 #define USB3503_VIDM           0x01
 #define USB3503_CFGP           0xee
 #define USB3503_CLKSUSP                (1 << 7)
 
+#define USB3503_RESET          0xff
+
 struct usb3503 {
        enum usb3503_mode       mode;
-       struct i2c_client       *client;
+       struct regmap           *regmap;
+       struct device           *dev;
        u8      port_off_mask;
        int     gpio_intn;
        int     gpio_reset;
        int     gpio_connect;
 };
 
-static int usb3503_write_register(struct i2c_client *client,
-               char reg, char data)
-{
-       return i2c_smbus_write_byte_data(client, reg, data);
-}
-
-static int usb3503_read_register(struct i2c_client *client, char reg)
-{
-       return i2c_smbus_read_byte_data(client, reg);
-}
-
-static int usb3503_set_bits(struct i2c_client *client, char reg, char req)
+static int usb3503_reset(struct usb3503 *hub, int state)
 {
-       int err;
-
-       err = usb3503_read_register(client, reg);
-       if (err < 0)
-               return err;
-
-       err = usb3503_write_register(client, reg, err | req);
-       if (err < 0)
-               return err;
-
-       return 0;
-}
-
-static int usb3503_clear_bits(struct i2c_client *client, char reg, char req)
-{
-       int err;
-
-       err = usb3503_read_register(client, reg);
-       if (err < 0)
-               return err;
-
-       err = usb3503_write_register(client, reg, err & ~req);
-       if (err < 0)
-               return err;
-
-       return 0;
-}
+       if (!state && gpio_is_valid(hub->gpio_connect))
+               gpio_set_value_cansleep(hub->gpio_connect, 0);
 
-static int usb3503_reset(int gpio_reset, int state)
-{
-       if (gpio_is_valid(gpio_reset))
-               gpio_set_value(gpio_reset, state);
+       if (gpio_is_valid(hub->gpio_reset))
+               gpio_set_value_cansleep(hub->gpio_reset, state);
 
        /* Wait T_HUBINIT == 4ms for hub logic to stabilize */
        if (state)
@@ -112,90 +78,105 @@ static int usb3503_reset(int gpio_reset, int state)
        return 0;
 }
 
-static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode)
+static int usb3503_connect(struct usb3503 *hub)
 {
-       struct i2c_client *i2c = hub->client;
-       int err = 0;
+       struct device *dev = hub->dev;
+       int err;
 
-       switch (mode) {
-       case USB3503_MODE_HUB:
-               usb3503_reset(hub->gpio_reset, 1);
+       usb3503_reset(hub, 1);
 
+       if (hub->regmap) {
                /* SP_ILOCK: set connect_n, config_n for config */
-               err = usb3503_write_register(i2c, USB3503_SP_ILOCK,
-                               (USB3503_SPILOCK_CONNECT
+               err = regmap_write(hub->regmap, USB3503_SP_ILOCK,
+                          (USB3503_SPILOCK_CONNECT
                                 | USB3503_SPILOCK_CONFIG));
                if (err < 0) {
-                       dev_err(&i2c->dev, "SP_ILOCK failed (%d)\n", err);
-                       goto err_hubmode;
+                       dev_err(dev, "SP_ILOCK failed (%d)\n", err);
+                       return err;
                }
 
                /* PDS : Disable For Self Powered Operation */
                if (hub->port_off_mask) {
-                       err = usb3503_set_bits(i2c, USB3503_PDS,
+                       err = regmap_update_bits(hub->regmap, USB3503_PDS,
+                                       hub->port_off_mask,
                                        hub->port_off_mask);
                        if (err < 0) {
-                               dev_err(&i2c->dev, "PDS failed (%d)\n", err);
-                               goto err_hubmode;
+                               dev_err(dev, "PDS failed (%d)\n", err);
+                               return err;
                        }
                }
 
                /* CFG1 : SELF_BUS_PWR -> Self-Powerd operation */
-               err = usb3503_set_bits(i2c, USB3503_CFG1, USB3503_SELF_BUS_PWR);
+               err = regmap_update_bits(hub->regmap, USB3503_CFG1,
+                                        USB3503_SELF_BUS_PWR,
+                                        USB3503_SELF_BUS_PWR);
                if (err < 0) {
-                       dev_err(&i2c->dev, "CFG1 failed (%d)\n", err);
-                       goto err_hubmode;
+                       dev_err(dev, "CFG1 failed (%d)\n", err);
+                       return err;
                }
 
                /* SP_LOCK: clear connect_n, config_n for hub connect */
-               err = usb3503_clear_bits(i2c, USB3503_SP_ILOCK,
-                               (USB3503_SPILOCK_CONNECT
-                                | USB3503_SPILOCK_CONFIG));
+               err = regmap_update_bits(hub->regmap, USB3503_SP_ILOCK,
+                                        (USB3503_SPILOCK_CONNECT
+                                         | USB3503_SPILOCK_CONFIG), 0);
                if (err < 0) {
-                       dev_err(&i2c->dev, "SP_ILOCK failed (%d)\n", err);
-                       goto err_hubmode;
+                       dev_err(dev, "SP_ILOCK failed (%d)\n", err);
+                       return err;
                }
+       }
 
-               hub->mode = mode;
-               dev_info(&i2c->dev, "switched to HUB mode\n");
+       if (gpio_is_valid(hub->gpio_connect))
+               gpio_set_value_cansleep(hub->gpio_connect, 1);
+
+       hub->mode = USB3503_MODE_HUB;
+       dev_info(dev, "switched to HUB mode\n");
+
+       return 0;
+}
+
+static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode)
+{
+       struct device *dev = hub->dev;
+       int err = 0;
+
+       switch (mode) {
+       case USB3503_MODE_HUB:
+               err = usb3503_connect(hub);
                break;
 
        case USB3503_MODE_STANDBY:
-               usb3503_reset(hub->gpio_reset, 0);
+               usb3503_reset(hub, 0);
 
                hub->mode = mode;
-               dev_info(&i2c->dev, "switched to STANDBY mode\n");
+               dev_info(dev, "switched to STANDBY mode\n");
                break;
 
        default:
-               dev_err(&i2c->dev, "unknown mode is request\n");
+               dev_err(dev, "unknown mode is requested\n");
                err = -EINVAL;
                break;
        }
 
-err_hubmode:
        return err;
 }
 
-static int usb3503_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+static const struct regmap_config usb3503_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = USB3503_RESET,
+};
+
+static int usb3503_probe(struct usb3503 *hub)
 {
-       struct usb3503_platform_data *pdata = i2c->dev.platform_data;
-       struct device_node *np = i2c->dev.of_node;
-       struct usb3503 *hub;
-       int err = -ENOMEM;
-       u32 mode = USB3503_MODE_UNKNOWN;
+       struct device *dev = hub->dev;
+       struct usb3503_platform_data *pdata = dev_get_platdata(dev);
+       struct device_node *np = dev->of_node;
+       int err;
+       u32 mode = USB3503_MODE_HUB;
        const u32 *property;
        int len;
 
-       hub = kzalloc(sizeof(struct usb3503), GFP_KERNEL);
-       if (!hub) {
-               dev_err(&i2c->dev, "private data alloc fail\n");
-               return err;
-       }
-
-       i2c_set_clientdata(i2c, hub);
-       hub->client = i2c;
-
        if (pdata) {
                hub->port_off_mask      = pdata->port_off_mask;
                hub->gpio_intn          = pdata->gpio_intn;
@@ -215,10 +196,10 @@ static int usb3503_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
                        }
                }
 
-               hub->gpio_intn  = of_get_named_gpio(np, "connect-gpios", 0);
+               hub->gpio_intn  = of_get_named_gpio(np, "intn-gpios", 0);
                if (hub->gpio_intn == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
-               hub->gpio_connect = of_get_named_gpio(np, "intn-gpios", 0);
+               hub->gpio_connect = of_get_named_gpio(np, "connect-gpios", 0);
                if (hub->gpio_connect == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
                hub->gpio_reset = of_get_named_gpio(np, "reset-gpios", 0);
@@ -228,72 +209,86 @@ static int usb3503_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
                hub->mode = mode;
        }
 
+       if (hub->port_off_mask && !hub->regmap)
+               dev_err(dev, "Ports disabled with no control interface\n");
+
        if (gpio_is_valid(hub->gpio_intn)) {
-               err = gpio_request_one(hub->gpio_intn,
+               err = devm_gpio_request_one(dev, hub->gpio_intn,
                                GPIOF_OUT_INIT_HIGH, "usb3503 intn");
                if (err) {
-                       dev_err(&i2c->dev,
-                                       "unable to request GPIO %d as connect pin (%d)\n",
-                                       hub->gpio_intn, err);
-                       goto err_out;
+                       dev_err(dev,
+                               "unable to request GPIO %d as connect pin (%d)\n",
+                               hub->gpio_intn, err);
+                       return err;
                }
        }
 
        if (gpio_is_valid(hub->gpio_connect)) {
-               err = gpio_request_one(hub->gpio_connect,
-                               GPIOF_OUT_INIT_HIGH, "usb3503 connect");
+               err = devm_gpio_request_one(dev, hub->gpio_connect,
+                               GPIOF_OUT_INIT_LOW, "usb3503 connect");
                if (err) {
-                       dev_err(&i2c->dev,
-                                       "unable to request GPIO %d as connect pin (%d)\n",
-                                       hub->gpio_connect, err);
-                       goto err_gpio_connect;
+                       dev_err(dev,
+                               "unable to request GPIO %d as connect pin (%d)\n",
+                               hub->gpio_connect, err);
+                       return err;
                }
        }
 
        if (gpio_is_valid(hub->gpio_reset)) {
-               err = gpio_request_one(hub->gpio_reset,
+               err = devm_gpio_request_one(dev, hub->gpio_reset,
                                GPIOF_OUT_INIT_LOW, "usb3503 reset");
                if (err) {
-                       dev_err(&i2c->dev,
-                                       "unable to request GPIO %d as reset pin (%d)\n",
-                                       hub->gpio_reset, err);
-                       goto err_gpio_reset;
+                       dev_err(dev,
+                               "unable to request GPIO %d as reset pin (%d)\n",
+                               hub->gpio_reset, err);
+                       return err;
                }
        }
 
        usb3503_switch_mode(hub, hub->mode);
 
-       dev_info(&i2c->dev, "%s: probed on  %s mode\n", __func__,
+       dev_info(dev, "%s: probed in %s mode\n", __func__,
                        (hub->mode == USB3503_MODE_HUB) ? "hub" : "standby");
 
        return 0;
+}
 
-err_gpio_reset:
-       if (gpio_is_valid(hub->gpio_connect))
-               gpio_free(hub->gpio_connect);
-err_gpio_connect:
-       if (gpio_is_valid(hub->gpio_intn))
-               gpio_free(hub->gpio_intn);
-err_out:
-       kfree(hub);
+static int usb3503_i2c_probe(struct i2c_client *i2c,
+                            const struct i2c_device_id *id)
+{
+       struct usb3503 *hub;
+       int err;
 
-       return err;
+       hub = devm_kzalloc(&i2c->dev, sizeof(struct usb3503), GFP_KERNEL);
+       if (!hub) {
+               dev_err(&i2c->dev, "private data alloc fail\n");
+               return -ENOMEM;
+       }
+
+       i2c_set_clientdata(i2c, hub);
+       hub->regmap = devm_regmap_init_i2c(i2c, &usb3503_regmap_config);
+       if (IS_ERR(hub->regmap)) {
+               err = PTR_ERR(hub->regmap);
+               dev_err(&i2c->dev, "Failed to initialise regmap: %d\n", err);
+               return err;
+       }
+       hub->dev = &i2c->dev;
+
+       return usb3503_probe(hub);
 }
 
-static int usb3503_remove(struct i2c_client *i2c)
+static int usb3503_platform_probe(struct platform_device *pdev)
 {
-       struct usb3503 *hub = i2c_get_clientdata(i2c);
-
-       if (gpio_is_valid(hub->gpio_intn))
-               gpio_free(hub->gpio_intn);
-       if (gpio_is_valid(hub->gpio_connect))
-               gpio_free(hub->gpio_connect);
-       if (gpio_is_valid(hub->gpio_reset))
-               gpio_free(hub->gpio_reset);
+       struct usb3503 *hub;
 
-       kfree(hub);
+       hub = devm_kzalloc(&pdev->dev, sizeof(struct usb3503), GFP_KERNEL);
+       if (!hub) {
+               dev_err(&pdev->dev, "private data alloc fail\n");
+               return -ENOMEM;
+       }
+       hub->dev = &pdev->dev;
 
-       return 0;
+       return usb3503_probe(hub);
 }
 
 static const struct i2c_device_id usb3503_id[] = {
@@ -305,22 +300,53 @@ MODULE_DEVICE_TABLE(i2c, usb3503_id);
 #ifdef CONFIG_OF
 static const struct of_device_id usb3503_of_match[] = {
        { .compatible = "smsc,usb3503", },
+       { .compatible = "smsc,usb3503a", },
        {},
 };
 MODULE_DEVICE_TABLE(of, usb3503_of_match);
 #endif
 
-static struct i2c_driver usb3503_driver = {
+static struct i2c_driver usb3503_i2c_driver = {
        .driver = {
                .name = USB3503_I2C_NAME,
                .of_match_table = of_match_ptr(usb3503_of_match),
        },
-       .probe          = usb3503_probe,
-       .remove         = usb3503_remove,
+       .probe          = usb3503_i2c_probe,
        .id_table       = usb3503_id,
 };
 
-module_i2c_driver(usb3503_driver);
+static struct platform_driver usb3503_platform_driver = {
+       .driver = {
+               .name = USB3503_I2C_NAME,
+               .of_match_table = of_match_ptr(usb3503_of_match),
+               .owner = THIS_MODULE,
+       },
+       .probe          = usb3503_platform_probe,
+};
+
+static int __init usb3503_init(void)
+{
+       int err;
+
+       err = i2c_register_driver(THIS_MODULE, &usb3503_i2c_driver);
+       if (err != 0)
+               pr_err("usb3503: Failed to register I2C driver: %d\n", err);
+
+       err = platform_driver_register(&usb3503_platform_driver);
+       if (err != 0)
+               pr_err("usb3503: Failed to register platform driver: %d\n",
+                      err);
+
+       return 0;
+}
+module_init(usb3503_init);
+
+static void __exit usb3503_exit(void)
+{
+       platform_driver_unregister(&usb3503_platform_driver);
+       i2c_del_driver(&usb3503_i2c_driver);
+}
+module_exit(usb3503_exit);
 
 MODULE_AUTHOR("Dongjin Kim <tobetter@gmail.com>");
 MODULE_DESCRIPTION("USB3503 USB HUB driver");
index 8b4ca1cb450aacce4dffaf67b0ca650b0cfa2544..aa28ac8c7607deeb49136340f0def4dd5f6fa05d 100644 (file)
@@ -747,9 +747,9 @@ static int ch9_postconfig(struct usbtest_dev *dev)
 
        /* [9.4.5] get_status always works */
        retval = usb_get_status(udev, USB_RECIP_DEVICE, 0, dev->buf);
-       if (retval != 2) {
+       if (retval) {
                dev_err(&iface->dev, "get dev status --> %d\n", retval);
-               return (retval < 0) ? retval : -EDOM;
+               return retval;
        }
 
        /* FIXME configuration.bmAttributes says if we could try to set/clear
@@ -758,9 +758,9 @@ static int ch9_postconfig(struct usbtest_dev *dev)
 
        retval = usb_get_status(udev, USB_RECIP_INTERFACE,
                        iface->altsetting[0].desc.bInterfaceNumber, dev->buf);
-       if (retval != 2) {
+       if (retval) {
                dev_err(&iface->dev, "get interface status --> %d\n", retval);
-               return (retval < 0) ? retval : -EDOM;
+               return retval;
        }
        /* FIXME get status for each endpoint in the interface */
 
@@ -1351,7 +1351,6 @@ static int verify_halted(struct usbtest_dev *tdev, int ep, struct urb *urb)
                                ep, retval);
                return retval;
        }
-       le16_to_cpus(&status);
        if (status != 1) {
                ERROR(tdev, "ep %02x bogus status: %04x != 1\n", ep, status);
                return -EINVAL;
index e129cf661223323bc88152fbd67f0ce4b6e8c321..40ef40affe8345e6a34557392719f6013c905d22 100644 (file)
@@ -75,7 +75,7 @@ struct uss720_async_request {
        struct list_head asynclist;
        struct completion compl;
        struct urb *urb;
-       struct usb_ctrlrequest dr;
+       struct usb_ctrlrequest *dr;
        __u8 reg[7];
 };
 
@@ -98,6 +98,7 @@ static void destroy_async(struct kref *kref)
 
        if (likely(rq->urb))
                usb_free_urb(rq->urb);
+       kfree(rq->dr);
        spin_lock_irqsave(&priv->asynclock, flags);
        list_del_init(&rq->asynclist);
        spin_unlock_irqrestore(&priv->asynclock, flags);
@@ -120,7 +121,7 @@ static void async_complete(struct urb *urb)
        if (status) {
                dev_err(&urb->dev->dev, "async_complete: urb error %d\n",
                        status);
-       } else if (rq->dr.bRequest == 3) {
+       } else if (rq->dr->bRequest == 3) {
                memcpy(priv->reg, rq->reg, sizeof(priv->reg));
 #if 0
                dev_dbg(&priv->usbdev->dev,
@@ -152,7 +153,7 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p
        usbdev = priv->usbdev;
        if (!usbdev)
                return NULL;
-       rq = kmalloc(sizeof(struct uss720_async_request), mem_flags);
+       rq = kzalloc(sizeof(struct uss720_async_request), mem_flags);
        if (!rq) {
                dev_err(&usbdev->dev, "submit_async_request out of memory\n");
                return NULL;
@@ -168,13 +169,18 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p
                dev_err(&usbdev->dev, "submit_async_request out of memory\n");
                return NULL;
        }
-       rq->dr.bRequestType = requesttype;
-       rq->dr.bRequest = request;
-       rq->dr.wValue = cpu_to_le16(value);
-       rq->dr.wIndex = cpu_to_le16(index);
-       rq->dr.wLength = cpu_to_le16((request == 3) ? sizeof(rq->reg) : 0);
+       rq->dr = kmalloc(sizeof(*rq->dr), mem_flags);
+       if (!rq->dr) {
+               kref_put(&rq->ref_count, destroy_async);
+               return NULL;
+       }
+       rq->dr->bRequestType = requesttype;
+       rq->dr->bRequest = request;
+       rq->dr->wValue = cpu_to_le16(value);
+       rq->dr->wIndex = cpu_to_le16(index);
+       rq->dr->wLength = cpu_to_le16((request == 3) ? sizeof(rq->reg) : 0);
        usb_fill_control_urb(rq->urb, usbdev, (requesttype & 0x80) ? usb_rcvctrlpipe(usbdev, 0) : usb_sndctrlpipe(usbdev, 0),
-                            (unsigned char *)&rq->dr,
+                            (unsigned char *)rq->dr,
                             (request == 3) ? rq->reg : NULL, (request == 3) ? sizeof(rq->reg) : 0, async_complete, rq);
        /* rq->urb->transfer_flags |= URB_ASYNC_UNLINK; */
        spin_lock_irqsave(&priv->asynclock, flags);
index 797e3fd455102b5365d4730db5659fce1f2ded43..c64ee09a7c0e30ad4f36cde52e1dce98e4d128b4 100644 (file)
@@ -83,6 +83,8 @@ config USB_MUSB_AM35X
 
 config USB_MUSB_DSPS
        tristate "TI DSPS platforms"
+       select USB_MUSB_AM335X_CHILD
+       depends on OF_IRQ
 
 config USB_MUSB_BLACKFIN
        tristate "Blackfin"
@@ -93,6 +95,9 @@ config USB_MUSB_UX500
 
 endchoice
 
+config USB_MUSB_AM335X_CHILD
+       tristate
+
 choice
        prompt 'MUSB DMA mode'
        default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM
@@ -125,6 +130,10 @@ config USB_TI_CPPI_DMA
        help
          Enable DMA transfers when TI CPPI DMA is available.
 
+config USB_TI_CPPI41_DMA
+       bool 'TI CPPI 4.1 (AM335x)'
+       depends on ARCH_OMAP
+
 config USB_TUSB_OMAP_DMA
        bool 'TUSB 6010'
        depends on USB_MUSB_TUSB6010
index 2b82ed7c85ca9baa0498d1dabd7a2aeca6b59e27..c5ea5c6dc1696337135420a22c73de67e9ce1a4f 100644 (file)
@@ -20,6 +20,9 @@ obj-$(CONFIG_USB_MUSB_DA8XX)                  += da8xx.o
 obj-$(CONFIG_USB_MUSB_BLACKFIN)                        += blackfin.o
 obj-$(CONFIG_USB_MUSB_UX500)                   += ux500.o
 
+
+obj-$(CONFIG_USB_MUSB_AM335X_CHILD)            += musb_am335x.o
+
 # the kconfig must guarantee that only one of the
 # possible I/O schemes will be enabled at a time ...
 # PIO only, or DMA (several potential schemes).
@@ -29,3 +32,4 @@ musb_hdrc-$(CONFIG_USB_INVENTRA_DMA)          += musbhsdma.o
 musb_hdrc-$(CONFIG_USB_TI_CPPI_DMA)            += cppi_dma.o
 musb_hdrc-$(CONFIG_USB_TUSB_OMAP_DMA)          += tusb6010_omap.o
 musb_hdrc-$(CONFIG_USB_UX500_DMA)              += ux500_dma.o
+musb_hdrc-$(CONFIG_USB_TI_CPPI41_DMA)          += musb_cppi41.o
index 2231850c062530765f49b761bd711e83bcde9579..5c310c664218dec6d1e71874ee8dc84f0232fa19 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 #include <linux/platform_data/usb-omap.h>
 
 #include "musb_core.h"
@@ -218,7 +218,7 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
        struct musb  *musb = hci;
        void __iomem *reg_base = musb->ctrl_base;
        struct device *dev = musb->controller;
-       struct musb_hdrc_platform_data *plat = dev->platform_data;
+       struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
        struct omap_musb_board_data *data = plat->board_data;
        struct usb_otg *otg = musb->xceiv->otg;
        unsigned long flags;
@@ -335,7 +335,7 @@ eoi:
 static int am35x_musb_set_mode(struct musb *musb, u8 musb_mode)
 {
        struct device *dev = musb->controller;
-       struct musb_hdrc_platform_data *plat = dev->platform_data;
+       struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
        struct omap_musb_board_data *data = plat->board_data;
        int     retval = 0;
 
@@ -350,7 +350,7 @@ static int am35x_musb_set_mode(struct musb *musb, u8 musb_mode)
 static int am35x_musb_init(struct musb *musb)
 {
        struct device *dev = musb->controller;
-       struct musb_hdrc_platform_data *plat = dev->platform_data;
+       struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
        struct omap_musb_board_data *data = plat->board_data;
        void __iomem *reg_base = musb->ctrl_base;
        u32 rev;
@@ -394,7 +394,7 @@ static int am35x_musb_init(struct musb *musb)
 static int am35x_musb_exit(struct musb *musb)
 {
        struct device *dev = musb->controller;
-       struct musb_hdrc_platform_data *plat = dev->platform_data;
+       struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
        struct omap_musb_board_data *data = plat->board_data;
 
        del_timer_sync(&otg_workaround);
@@ -456,7 +456,7 @@ static u64 am35x_dmamask = DMA_BIT_MASK(32);
 
 static int am35x_probe(struct platform_device *pdev)
 {
-       struct musb_hdrc_platform_data  *pdata = pdev->dev.platform_data;
+       struct musb_hdrc_platform_data  *pdata = dev_get_platdata(&pdev->dev);
        struct platform_device          *musb;
        struct am35x_glue               *glue;
 
@@ -577,7 +577,7 @@ static int am35x_remove(struct platform_device *pdev)
 static int am35x_suspend(struct device *dev)
 {
        struct am35x_glue       *glue = dev_get_drvdata(dev);
-       struct musb_hdrc_platform_data *plat = dev->platform_data;
+       struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
        struct omap_musb_board_data *data = plat->board_data;
 
        /* Shutdown the on-chip PHY and its PLL. */
@@ -593,7 +593,7 @@ static int am35x_suspend(struct device *dev)
 static int am35x_resume(struct device *dev)
 {
        struct am35x_glue       *glue = dev_get_drvdata(dev);
-       struct musb_hdrc_platform_data *plat = dev->platform_data;
+       struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
        struct omap_musb_board_data *data = plat->board_data;
        int                     ret;
 
index 6ba8439bd5a6e037d124a2fd5db152387fa3dd5a..72e2056b6082f4c4872b9a7d94c82f59193e00f4 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/prefetch.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 
 #include <asm/cacheflush.h>
 
@@ -451,7 +451,7 @@ static u64 bfin_dmamask = DMA_BIT_MASK(32);
 static int bfin_probe(struct platform_device *pdev)
 {
        struct resource musb_resources[2];
-       struct musb_hdrc_platform_data  *pdata = pdev->dev.platform_data;
+       struct musb_hdrc_platform_data  *pdata = dev_get_platdata(&pdev->dev);
        struct platform_device          *musb;
        struct bfin_glue                *glue;
 
index 9db211ee15b5350467fb8808a80c9d0575a9c4ff..904fb85d85a6c36811ce33ddbf0761beff21454c 100644 (file)
@@ -150,14 +150,11 @@ static void cppi_pool_free(struct cppi_channel *c)
        c->last_processed = NULL;
 }
 
-static int cppi_controller_start(struct dma_controller *c)
+static void cppi_controller_start(struct cppi *controller)
 {
-       struct cppi     *controller;
        void __iomem    *tibase;
        int             i;
 
-       controller = container_of(c, struct cppi, controller);
-
        /* do whatever is necessary to start controller */
        for (i = 0; i < ARRAY_SIZE(controller->tx); i++) {
                controller->tx[i].transmit = true;
@@ -212,8 +209,6 @@ static int cppi_controller_start(struct dma_controller *c)
        /* disable RNDIS mode, also host rx RNDIS autorequest */
        musb_writel(tibase, DAVINCI_RNDIS_REG, 0);
        musb_writel(tibase, DAVINCI_AUTOREQ_REG, 0);
-
-       return 0;
 }
 
 /*
@@ -222,14 +217,12 @@ static int cppi_controller_start(struct dma_controller *c)
  *  De-Init the DMA controller as necessary.
  */
 
-static int cppi_controller_stop(struct dma_controller *c)
+static void cppi_controller_stop(struct cppi *controller)
 {
-       struct cppi             *controller;
        void __iomem            *tibase;
        int                     i;
        struct musb             *musb;
 
-       controller = container_of(c, struct cppi, controller);
        musb = controller->musb;
 
        tibase = controller->tibase;
@@ -255,8 +248,6 @@ static int cppi_controller_stop(struct dma_controller *c)
        /*disable tx/rx cppi */
        musb_writel(tibase, DAVINCI_TXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE);
        musb_writel(tibase, DAVINCI_RXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE);
-
-       return 0;
 }
 
 /* While dma channel is allocated, we only want the core irqs active
@@ -1321,8 +1312,6 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *mr
        controller->tibase = mregs - DAVINCI_BASE_OFFSET;
 
        controller->musb = musb;
-       controller->controller.start = cppi_controller_start;
-       controller->controller.stop = cppi_controller_stop;
        controller->controller.channel_alloc = cppi_channel_allocate;
        controller->controller.channel_release = cppi_channel_release;
        controller->controller.channel_program = cppi_channel_program;
@@ -1351,6 +1340,7 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *mr
                controller->irq = irq;
        }
 
+       cppi_controller_start(controller);
        return &controller->controller;
 }
 
@@ -1363,6 +1353,8 @@ void dma_controller_destroy(struct dma_controller *c)
 
        cppi = container_of(c, struct cppi, controller);
 
+       cppi_controller_stop(cppi);
+
        if (cppi->irq)
                free_irq(cppi->irq, cppi->musb);
 
index 0da6f648a9fe1393faab16726bcc8d8725eb316c..d9ddf4122f37e6ddfd19661eb9cb1448306525b6 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 
 #include <mach/da8xx.h>
 #include <linux/platform_data/usb-davinci.h>
@@ -477,7 +477,7 @@ static u64 da8xx_dmamask = DMA_BIT_MASK(32);
 static int da8xx_probe(struct platform_device *pdev)
 {
        struct resource musb_resources[2];
-       struct musb_hdrc_platform_data  *pdata = pdev->dev.platform_data;
+       struct musb_hdrc_platform_data  *pdata = dev_get_platdata(&pdev->dev);
        struct platform_device          *musb;
        struct da8xx_glue               *glue;
 
index f8aeaf2e2cd1f88ba2526861b2b932b6d6081050..ed0834e2b72eeaa6c9dbe73bdb77c2f433282b42 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 
 #include <mach/cputype.h>
 #include <mach/hardware.h>
@@ -510,7 +510,7 @@ static u64 davinci_dmamask = DMA_BIT_MASK(32);
 static int davinci_probe(struct platform_device *pdev)
 {
        struct resource musb_resources[2];
-       struct musb_hdrc_platform_data  *pdata = pdev->dev.platform_data;
+       struct musb_hdrc_platform_data  *pdata = dev_get_platdata(&pdev->dev);
        struct platform_device          *musb;
        struct davinci_glue             *glue;
        struct clk                      *clk;
diff --git a/drivers/usb/musb/musb_am335x.c b/drivers/usb/musb/musb_am335x.c
new file mode 100644 (file)
index 0000000..41ac5b5
--- /dev/null
@@ -0,0 +1,55 @@
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+
+static int am335x_child_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       pm_runtime_enable(&pdev->dev);
+
+       ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       pm_runtime_disable(&pdev->dev);
+       return ret;
+}
+
+static int of_remove_populated_child(struct device *dev, void *d)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+
+       of_device_unregister(pdev);
+       return 0;
+}
+
+static int am335x_child_remove(struct platform_device *pdev)
+{
+       device_for_each_child(&pdev->dev, NULL, of_remove_populated_child);
+       pm_runtime_disable(&pdev->dev);
+       return 0;
+}
+
+static const struct of_device_id am335x_child_of_match[] = {
+       { .compatible = "ti,am33xx-usb" },
+       {  },
+};
+MODULE_DEVICE_TABLE(of, am335x_child_of_match);
+
+static struct platform_driver am335x_child_driver = {
+       .probe          = am335x_child_probe,
+       .remove         = am335x_child_remove,
+       .driver         = {
+               .name   = "am335x-usb-childs",
+               .of_match_table = of_match_ptr(am335x_child_of_match),
+       },
+};
+
+module_platform_driver(am335x_child_driver);
+MODULE_DESCRIPTION("AM33xx child devices");
+MODULE_LICENSE("GPL v2");
index 29a24ced67483d8942f943013ee27a3645902112..18e877ffe7b7d8c7393bdf43efdfd0d58e618011 100644 (file)
@@ -99,7 +99,6 @@
 #include <linux/prefetch.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <linux/idr.h>
 #include <linux/dma-mapping.h>
 
 #include "musb_core.h"
@@ -1764,12 +1763,8 @@ static void musb_free(struct musb *musb)
                        disable_irq_wake(musb->nIrq);
                free_irq(musb->nIrq, musb);
        }
-       if (is_dma_capable() && musb->dma_controller) {
-               struct dma_controller   *c = musb->dma_controller;
-
-               (void) c->stop(c);
-               dma_controller_destroy(c);
-       }
+       if (musb->dma_controller)
+               dma_controller_destroy(musb->dma_controller);
 
        musb_host_free(musb);
 }
@@ -1787,7 +1782,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
 {
        int                     status;
        struct musb             *musb;
-       struct musb_hdrc_platform_data *plat = dev->platform_data;
+       struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
 
        /* The driver might handle more features than the board; OK.
         * Fail when the board needs a feature that's not enabled.
@@ -1844,19 +1839,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
 
        pm_runtime_get_sync(musb->controller);
 
-#ifndef CONFIG_MUSB_PIO_ONLY
-       if (use_dma && dev->dma_mask) {
-               struct dma_controller   *c;
-
-               c = dma_controller_create(musb, musb->mregs);
-               musb->dma_controller = c;
-               if (c)
-                       (void) c->start(c);
-       }
-#endif
-       /* ideally this would be abstracted in platform setup */
-       if (!is_dma_capable() || !musb->dma_controller)
-               dev->dma_mask = NULL;
+       if (use_dma && dev->dma_mask)
+               musb->dma_controller = dma_controller_create(musb, musb->mregs);
 
        /* be sure interrupts are disabled before connecting ISR */
        musb_platform_disable(musb);
@@ -1944,6 +1928,8 @@ fail4:
        musb_gadget_cleanup(musb);
 
 fail3:
+       if (musb->dma_controller)
+               dma_controller_destroy(musb->dma_controller);
        pm_runtime_put_sync(musb->controller);
 
 fail2:
@@ -2002,9 +1988,6 @@ static int musb_remove(struct platform_device *pdev)
 
        musb_free(musb);
        device_init_wakeup(dev, 0);
-#ifndef CONFIG_MUSB_PIO_ONLY
-       dma_set_mask(dev, *dev->parent->dma_mask);
-#endif
        return 0;
 }
 
index 7d341c387eab94e4148cba0e8db0e2bf25130811..65f3917b4fc5fb55c95bf4157d70a1d7194a110d 100644 (file)
@@ -83,11 +83,6 @@ enum {
        MUSB_PORT_MODE_DUAL_ROLE,
 };
 
-#ifdef CONFIG_PROC_FS
-#include <linux/fs.h>
-#define MUSB_CONFIG_PROC_FS
-#endif
-
 /****************************** CONSTANTS ********************************/
 
 #ifndef MUSB_C_NUM_EPS
@@ -425,9 +420,6 @@ struct musb {
 
        struct musb_hdrc_config *config;
 
-#ifdef MUSB_CONFIG_PROC_FS
-       struct proc_dir_entry *proc_entry;
-#endif
        int                     xceiv_old_state;
 #ifdef CONFIG_DEBUG_FS
        struct dentry           *debugfs_root;
diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c
new file mode 100644 (file)
index 0000000..e64701d
--- /dev/null
@@ -0,0 +1,555 @@
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/sizes.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+
+#include "musb_core.h"
+
+#define RNDIS_REG(x) (0x80 + ((x - 1) * 4))
+
+#define EP_MODE_AUTOREG_NONE           0
+#define EP_MODE_AUTOREG_ALL_NEOP       1
+#define EP_MODE_AUTOREG_ALWAYS         3
+
+#define EP_MODE_DMA_TRANSPARENT                0
+#define EP_MODE_DMA_RNDIS              1
+#define EP_MODE_DMA_GEN_RNDIS          3
+
+#define USB_CTRL_TX_MODE       0x70
+#define USB_CTRL_RX_MODE       0x74
+#define USB_CTRL_AUTOREQ       0xd0
+#define USB_TDOWN              0xd8
+
+struct cppi41_dma_channel {
+       struct dma_channel channel;
+       struct cppi41_dma_controller *controller;
+       struct musb_hw_ep *hw_ep;
+       struct dma_chan *dc;
+       dma_cookie_t cookie;
+       u8 port_num;
+       u8 is_tx;
+       u8 is_allocated;
+       u8 usb_toggle;
+
+       dma_addr_t buf_addr;
+       u32 total_len;
+       u32 prog_len;
+       u32 transferred;
+       u32 packet_sz;
+};
+
+#define MUSB_DMA_NUM_CHANNELS 15
+
+struct cppi41_dma_controller {
+       struct dma_controller controller;
+       struct cppi41_dma_channel rx_channel[MUSB_DMA_NUM_CHANNELS];
+       struct cppi41_dma_channel tx_channel[MUSB_DMA_NUM_CHANNELS];
+       struct musb *musb;
+       u32 rx_mode;
+       u32 tx_mode;
+       u32 auto_req;
+};
+
+static void save_rx_toggle(struct cppi41_dma_channel *cppi41_channel)
+{
+       u16 csr;
+       u8 toggle;
+
+       if (cppi41_channel->is_tx)
+               return;
+       if (!is_host_active(cppi41_channel->controller->musb))
+               return;
+
+       csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR);
+       toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0;
+
+       cppi41_channel->usb_toggle = toggle;
+}
+
+static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel)
+{
+       u16 csr;
+       u8 toggle;
+
+       if (cppi41_channel->is_tx)
+               return;
+       if (!is_host_active(cppi41_channel->controller->musb))
+               return;
+
+       csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR);
+       toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0;
+
+       /*
+        * AM335x Advisory 1.0.13: Due to internal synchronisation error the
+        * data toggle may reset from DATA1 to DATA0 during receiving data from
+        * more than one endpoint.
+        */
+       if (!toggle && toggle == cppi41_channel->usb_toggle) {
+               csr |= MUSB_RXCSR_H_DATATOGGLE | MUSB_RXCSR_H_WR_DATATOGGLE;
+               musb_writew(cppi41_channel->hw_ep->regs, MUSB_RXCSR, csr);
+               dev_dbg(cppi41_channel->controller->musb->controller,
+                               "Restoring DATA1 toggle.\n");
+       }
+
+       cppi41_channel->usb_toggle = toggle;
+}
+
+static void cppi41_dma_callback(void *private_data)
+{
+       struct dma_channel *channel = private_data;
+       struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+       struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
+       struct musb *musb = hw_ep->musb;
+       unsigned long flags;
+       struct dma_tx_state txstate;
+       u32 transferred;
+
+       spin_lock_irqsave(&musb->lock, flags);
+
+       dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie,
+                       &txstate);
+       transferred = cppi41_channel->prog_len - txstate.residue;
+       cppi41_channel->transferred += transferred;
+
+       dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n",
+               hw_ep->epnum, cppi41_channel->transferred,
+               cppi41_channel->total_len);
+
+       update_rx_toggle(cppi41_channel);
+
+       if (cppi41_channel->transferred == cppi41_channel->total_len ||
+                       transferred < cppi41_channel->packet_sz) {
+
+               /* done, complete */
+               cppi41_channel->channel.actual_len =
+                       cppi41_channel->transferred;
+               cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE;
+               musb_dma_completion(musb, hw_ep->epnum, cppi41_channel->is_tx);
+       } else {
+               /* next iteration, reload */
+               struct dma_chan *dc = cppi41_channel->dc;
+               struct dma_async_tx_descriptor *dma_desc;
+               enum dma_transfer_direction direction;
+               u16 csr;
+               u32 remain_bytes;
+               void __iomem *epio = cppi41_channel->hw_ep->regs;
+
+               cppi41_channel->buf_addr += cppi41_channel->packet_sz;
+
+               remain_bytes = cppi41_channel->total_len;
+               remain_bytes -= cppi41_channel->transferred;
+               remain_bytes = min(remain_bytes, cppi41_channel->packet_sz);
+               cppi41_channel->prog_len = remain_bytes;
+
+               direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV
+                       : DMA_DEV_TO_MEM;
+               dma_desc = dmaengine_prep_slave_single(dc,
+                               cppi41_channel->buf_addr,
+                               remain_bytes,
+                               direction,
+                               DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+               if (WARN_ON(!dma_desc))
+                       return;
+
+               dma_desc->callback = cppi41_dma_callback;
+               dma_desc->callback_param = channel;
+               cppi41_channel->cookie = dma_desc->tx_submit(dma_desc);
+               dma_async_issue_pending(dc);
+
+               if (!cppi41_channel->is_tx) {
+                       csr = musb_readw(epio, MUSB_RXCSR);
+                       csr |= MUSB_RXCSR_H_REQPKT;
+                       musb_writew(epio, MUSB_RXCSR, csr);
+               }
+       }
+       spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+static u32 update_ep_mode(unsigned ep, unsigned mode, u32 old)
+{
+       unsigned shift;
+
+       shift = (ep - 1) * 2;
+       old &= ~(3 << shift);
+       old |= mode << shift;
+       return old;
+}
+
+static void cppi41_set_dma_mode(struct cppi41_dma_channel *cppi41_channel,
+               unsigned mode)
+{
+       struct cppi41_dma_controller *controller = cppi41_channel->controller;
+       u32 port;
+       u32 new_mode;
+       u32 old_mode;
+
+       if (cppi41_channel->is_tx)
+               old_mode = controller->tx_mode;
+       else
+               old_mode = controller->rx_mode;
+       port = cppi41_channel->port_num;
+       new_mode = update_ep_mode(port, mode, old_mode);
+
+       if (new_mode == old_mode)
+               return;
+       if (cppi41_channel->is_tx) {
+               controller->tx_mode = new_mode;
+               musb_writel(controller->musb->ctrl_base, USB_CTRL_TX_MODE,
+                               new_mode);
+       } else {
+               controller->rx_mode = new_mode;
+               musb_writel(controller->musb->ctrl_base, USB_CTRL_RX_MODE,
+                               new_mode);
+       }
+}
+
+static void cppi41_set_autoreq_mode(struct cppi41_dma_channel *cppi41_channel,
+               unsigned mode)
+{
+       struct cppi41_dma_controller *controller = cppi41_channel->controller;
+       u32 port;
+       u32 new_mode;
+       u32 old_mode;
+
+       old_mode = controller->auto_req;
+       port = cppi41_channel->port_num;
+       new_mode = update_ep_mode(port, mode, old_mode);
+
+       if (new_mode == old_mode)
+               return;
+       controller->auto_req = new_mode;
+       musb_writel(controller->musb->ctrl_base, USB_CTRL_AUTOREQ, new_mode);
+}
+
+static bool cppi41_configure_channel(struct dma_channel *channel,
+                               u16 packet_sz, u8 mode,
+                               dma_addr_t dma_addr, u32 len)
+{
+       struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+       struct dma_chan *dc = cppi41_channel->dc;
+       struct dma_async_tx_descriptor *dma_desc;
+       enum dma_transfer_direction direction;
+       struct musb *musb = cppi41_channel->controller->musb;
+       unsigned use_gen_rndis = 0;
+
+       dev_dbg(musb->controller,
+               "configure ep%d/%x packet_sz=%d, mode=%d, dma_addr=0x%llx, len=%d is_tx=%d\n",
+               cppi41_channel->port_num, RNDIS_REG(cppi41_channel->port_num),
+               packet_sz, mode, (unsigned long long) dma_addr,
+               len, cppi41_channel->is_tx);
+
+       cppi41_channel->buf_addr = dma_addr;
+       cppi41_channel->total_len = len;
+       cppi41_channel->transferred = 0;
+       cppi41_channel->packet_sz = packet_sz;
+
+       /*
+        * Due to AM335x' Advisory 1.0.13 we are not allowed to transfer more
+        * than max packet size at a time.
+        */
+       if (cppi41_channel->is_tx)
+               use_gen_rndis = 1;
+
+       if (use_gen_rndis) {
+               /* RNDIS mode */
+               if (len > packet_sz) {
+                       musb_writel(musb->ctrl_base,
+                               RNDIS_REG(cppi41_channel->port_num), len);
+                       /* gen rndis */
+                       cppi41_set_dma_mode(cppi41_channel,
+                                       EP_MODE_DMA_GEN_RNDIS);
+
+                       /* auto req */
+                       cppi41_set_autoreq_mode(cppi41_channel,
+                                       EP_MODE_AUTOREG_ALL_NEOP);
+               } else {
+                       musb_writel(musb->ctrl_base,
+                                       RNDIS_REG(cppi41_channel->port_num), 0);
+                       cppi41_set_dma_mode(cppi41_channel,
+                                       EP_MODE_DMA_TRANSPARENT);
+                       cppi41_set_autoreq_mode(cppi41_channel,
+                                       EP_MODE_AUTOREG_NONE);
+               }
+       } else {
+               /* fallback mode */
+               cppi41_set_dma_mode(cppi41_channel, EP_MODE_DMA_TRANSPARENT);
+               cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREG_NONE);
+               len = min_t(u32, packet_sz, len);
+       }
+       cppi41_channel->prog_len = len;
+       direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
+       dma_desc = dmaengine_prep_slave_single(dc, dma_addr, len, direction,
+                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!dma_desc)
+               return false;
+
+       dma_desc->callback = cppi41_dma_callback;
+       dma_desc->callback_param = channel;
+       cppi41_channel->cookie = dma_desc->tx_submit(dma_desc);
+
+       save_rx_toggle(cppi41_channel);
+       dma_async_issue_pending(dc);
+       return true;
+}
+
+static struct dma_channel *cppi41_dma_channel_allocate(struct dma_controller *c,
+                               struct musb_hw_ep *hw_ep, u8 is_tx)
+{
+       struct cppi41_dma_controller *controller = container_of(c,
+                       struct cppi41_dma_controller, controller);
+       struct cppi41_dma_channel *cppi41_channel = NULL;
+       u8 ch_num = hw_ep->epnum - 1;
+
+       if (ch_num >= MUSB_DMA_NUM_CHANNELS)
+               return NULL;
+
+       if (is_tx)
+               cppi41_channel = &controller->tx_channel[ch_num];
+       else
+               cppi41_channel = &controller->rx_channel[ch_num];
+
+       if (!cppi41_channel->dc)
+               return NULL;
+
+       if (cppi41_channel->is_allocated)
+               return NULL;
+
+       cppi41_channel->hw_ep = hw_ep;
+       cppi41_channel->is_allocated = 1;
+
+       return &cppi41_channel->channel;
+}
+
+static void cppi41_dma_channel_release(struct dma_channel *channel)
+{
+       struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+
+       if (cppi41_channel->is_allocated) {
+               cppi41_channel->is_allocated = 0;
+               channel->status = MUSB_DMA_STATUS_FREE;
+               channel->actual_len = 0;
+       }
+}
+
+static int cppi41_dma_channel_program(struct dma_channel *channel,
+                               u16 packet_sz, u8 mode,
+                               dma_addr_t dma_addr, u32 len)
+{
+       int ret;
+
+       BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
+               channel->status == MUSB_DMA_STATUS_BUSY);
+
+       channel->status = MUSB_DMA_STATUS_BUSY;
+       channel->actual_len = 0;
+       ret = cppi41_configure_channel(channel, packet_sz, mode, dma_addr, len);
+       if (!ret)
+               channel->status = MUSB_DMA_STATUS_FREE;
+
+       return ret;
+}
+
+static int cppi41_is_compatible(struct dma_channel *channel, u16 maxpacket,
+               void *buf, u32 length)
+{
+       struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+       struct cppi41_dma_controller *controller = cppi41_channel->controller;
+       struct musb *musb = controller->musb;
+
+       if (is_host_active(musb)) {
+               WARN_ON(1);
+               return 1;
+       }
+       if (cppi41_channel->is_tx)
+               return 1;
+       /* AM335x Advisory 1.0.13. No workaround for device RX mode */
+       return 0;
+}
+
+static int cppi41_dma_channel_abort(struct dma_channel *channel)
+{
+       struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+       struct cppi41_dma_controller *controller = cppi41_channel->controller;
+       struct musb *musb = controller->musb;
+       void __iomem *epio = cppi41_channel->hw_ep->regs;
+       int tdbit;
+       int ret;
+       unsigned is_tx;
+       u16 csr;
+
+       is_tx = cppi41_channel->is_tx;
+       dev_dbg(musb->controller, "abort channel=%d, is_tx=%d\n",
+                       cppi41_channel->port_num, is_tx);
+
+       if (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE)
+               return 0;
+
+       if (is_tx) {
+               csr = musb_readw(epio, MUSB_TXCSR);
+               csr &= ~MUSB_TXCSR_DMAENAB;
+               musb_writew(epio, MUSB_TXCSR, csr);
+       } else {
+               csr = musb_readw(epio, MUSB_RXCSR);
+               csr &= ~(MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_DMAENAB);
+               musb_writew(epio, MUSB_RXCSR, csr);
+
+               csr = musb_readw(epio, MUSB_RXCSR);
+               if (csr & MUSB_RXCSR_RXPKTRDY) {
+                       csr |= MUSB_RXCSR_FLUSHFIFO;
+                       musb_writew(epio, MUSB_RXCSR, csr);
+                       musb_writew(epio, MUSB_RXCSR, csr);
+               }
+       }
+
+       tdbit = 1 << cppi41_channel->port_num;
+       if (is_tx)
+               tdbit <<= 16;
+
+       do {
+               musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
+               ret = dmaengine_terminate_all(cppi41_channel->dc);
+       } while (ret == -EAGAIN);
+
+       musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
+
+       if (is_tx) {
+               csr = musb_readw(epio, MUSB_TXCSR);
+               if (csr & MUSB_TXCSR_TXPKTRDY) {
+                       csr |= MUSB_TXCSR_FLUSHFIFO;
+                       musb_writew(epio, MUSB_TXCSR, csr);
+               }
+       }
+
+       cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE;
+       return 0;
+}
+
+static void cppi41_release_all_dma_chans(struct cppi41_dma_controller *ctrl)
+{
+       struct dma_chan *dc;
+       int i;
+
+       for (i = 0; i < MUSB_DMA_NUM_CHANNELS; i++) {
+               dc = ctrl->tx_channel[i].dc;
+               if (dc)
+                       dma_release_channel(dc);
+               dc = ctrl->rx_channel[i].dc;
+               if (dc)
+                       dma_release_channel(dc);
+       }
+}
+
+static void cppi41_dma_controller_stop(struct cppi41_dma_controller *controller)
+{
+       cppi41_release_all_dma_chans(controller);
+}
+
+static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)
+{
+       struct musb *musb = controller->musb;
+       struct device *dev = musb->controller;
+       struct device_node *np = dev->of_node;
+       struct cppi41_dma_channel *cppi41_channel;
+       int count;
+       int i;
+       int ret;
+
+       count = of_property_count_strings(np, "dma-names");
+       if (count < 0)
+               return count;
+
+       for (i = 0; i < count; i++) {
+               struct dma_chan *dc;
+               struct dma_channel *musb_dma;
+               const char *str;
+               unsigned is_tx;
+               unsigned int port;
+
+               ret = of_property_read_string_index(np, "dma-names", i, &str);
+               if (ret)
+                       goto err;
+               if (!strncmp(str, "tx", 2))
+                       is_tx = 1;
+               else if (!strncmp(str, "rx", 2))
+                       is_tx = 0;
+               else {
+                       dev_err(dev, "Wrong dmatype %s\n", str);
+                       goto err;
+               }
+               ret = kstrtouint(str + 2, 0, &port);
+               if (ret)
+                       goto err;
+
+               if (port > MUSB_DMA_NUM_CHANNELS || !port)
+                       goto err;
+               if (is_tx)
+                       cppi41_channel = &controller->tx_channel[port - 1];
+               else
+                       cppi41_channel = &controller->rx_channel[port - 1];
+
+               cppi41_channel->controller = controller;
+               cppi41_channel->port_num = port;
+               cppi41_channel->is_tx = is_tx;
+
+               musb_dma = &cppi41_channel->channel;
+               musb_dma->private_data = cppi41_channel;
+               musb_dma->status = MUSB_DMA_STATUS_FREE;
+               musb_dma->max_len = SZ_4M;
+
+               dc = dma_request_slave_channel(dev, str);
+               if (!dc) {
+                       dev_err(dev, "Falied to request %s.\n", str);
+                       goto err;
+               }
+               cppi41_channel->dc = dc;
+       }
+       return 0;
+err:
+       cppi41_release_all_dma_chans(controller);
+       return -EINVAL;
+}
+
+void dma_controller_destroy(struct dma_controller *c)
+{
+       struct cppi41_dma_controller *controller = container_of(c,
+                       struct cppi41_dma_controller, controller);
+
+       cppi41_dma_controller_stop(controller);
+       kfree(controller);
+}
+
+struct dma_controller *dma_controller_create(struct musb *musb,
+                                       void __iomem *base)
+{
+       struct cppi41_dma_controller *controller;
+       int ret;
+
+       if (!musb->controller->of_node) {
+               dev_err(musb->controller, "Need DT for the DMA engine.\n");
+               return NULL;
+       }
+
+       controller = kzalloc(sizeof(*controller), GFP_KERNEL);
+       if (!controller)
+               goto kzalloc_fail;
+
+       controller->musb = musb;
+
+       controller->controller.channel_alloc = cppi41_dma_channel_allocate;
+       controller->controller.channel_release = cppi41_dma_channel_release;
+       controller->controller.channel_program = cppi41_dma_channel_program;
+       controller->controller.channel_abort = cppi41_dma_channel_abort;
+       controller->controller.is_compatible = cppi41_is_compatible;
+
+       ret = cppi41_dma_controller_start(controller);
+       if (ret)
+               goto plat_get_fail;
+       return &controller->controller;
+
+plat_get_fail:
+       kfree(controller);
+kzalloc_fail:
+       return NULL;
+}
index 1b6b827b769f5f9fb0398f54208d425bbaafc446..1345a4ff041a00380eb539f1a1c5bae2f9db13f4 100644 (file)
@@ -62,13 +62,13 @@ struct musb_hw_ep;
 
 #define        DMA_ADDR_INVALID        (~(dma_addr_t)0)
 
-#ifndef CONFIG_MUSB_PIO_ONLY
-#define        is_dma_capable()        (1)
-#else
+#ifdef CONFIG_MUSB_PIO_ONLY
 #define        is_dma_capable()        (0)
+#else
+#define        is_dma_capable()        (1)
 #endif
 
-#ifdef CONFIG_USB_TI_CPPI_DMA
+#if defined(CONFIG_USB_TI_CPPI_DMA) || defined(CONFIG_USB_TI_CPPI41_DMA)
 #define        is_cppi_enabled()       1
 #else
 #define        is_cppi_enabled()       0
@@ -159,8 +159,6 @@ dma_channel_status(struct dma_channel *c)
  * Controllers manage dma channels.
  */
 struct dma_controller {
-       int                     (*start)(struct dma_controller *);
-       int                     (*stop)(struct dma_controller *);
        struct dma_channel      *(*channel_alloc)(struct dma_controller *,
                                        struct musb_hw_ep *, u8 is_tx);
        void                    (*channel_release)(struct dma_channel *);
@@ -177,9 +175,20 @@ struct dma_controller {
 /* called after channel_program(), may indicate a fault */
 extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit);
 
+#ifdef CONFIG_MUSB_PIO_ONLY
+static inline struct dma_controller *dma_controller_create(struct musb *m,
+               void __iomem *io)
+{
+       return NULL;
+}
+
+static inline void dma_controller_destroy(struct dma_controller *d) { }
+
+#else
 
 extern struct dma_controller *dma_controller_create(struct musb *, void __iomem *);
 
 extern void dma_controller_destroy(struct dma_controller *);
+#endif
 
 #endif /* __MUSB_DMA_H__ */
index 5233804d66b11f4b4890d2c53c2be0f49a0dfe0d..4ffbaace791389c1b18ed821a9e3e243d70c1f58 100644 (file)
 #include <linux/dma-mapping.h>
 #include <linux/pm_runtime.h>
 #include <linux/module.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 #include <linux/platform_data/usb-omap.h>
 #include <linux/sizes.h>
 
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_address.h>
+#include <linux/of_irq.h>
 
 #include "musb_core.h"
 
-#ifdef CONFIG_OF
 static const struct of_device_id musb_dsps_of_match[];
-#endif
 
 /**
  * avoid using musb_readx()/musb_writex() as glue layer should not be
@@ -75,7 +74,6 @@ struct dsps_musb_wrapper {
        u16     revision;
        u16     control;
        u16     status;
-       u16     eoi;
        u16     epintr_set;
        u16     epintr_clear;
        u16     epintr_status;
@@ -108,10 +106,7 @@ struct dsps_musb_wrapper {
        /* bit positions for mode */
        unsigned        iddig:5;
        /* miscellaneous stuff */
-       u32             musb_core_offset;
        u8              poll_seconds;
-       /* number of musb instances */
-       u8              instances;
 };
 
 /**
@@ -119,53 +114,12 @@ struct dsps_musb_wrapper {
  */
 struct dsps_glue {
        struct device *dev;
-       struct platform_device *musb[2];        /* child musb pdev */
+       struct platform_device *musb;   /* child musb pdev */
        const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
-       struct timer_list timer[2];     /* otg_workaround timer */
-       unsigned long last_timer[2];    /* last timer data for each instance */
-       u32 __iomem *usb_ctrl[2];
+       struct timer_list timer;        /* otg_workaround timer */
+       unsigned long last_timer;    /* last timer data for each instance */
 };
 
-#define        DSPS_AM33XX_CONTROL_MODULE_PHYS_0       0x44e10620
-#define        DSPS_AM33XX_CONTROL_MODULE_PHYS_1       0x44e10628
-
-static const resource_size_t dsps_control_module_phys[] = {
-       DSPS_AM33XX_CONTROL_MODULE_PHYS_0,
-       DSPS_AM33XX_CONTROL_MODULE_PHYS_1,
-};
-
-#define USBPHY_CM_PWRDN                (1 << 0)
-#define USBPHY_OTG_PWRDN       (1 << 1)
-#define USBPHY_OTGVDET_EN      (1 << 19)
-#define USBPHY_OTGSESSEND_EN   (1 << 20)
-
-/**
- * musb_dsps_phy_control - phy on/off
- * @glue: struct dsps_glue *
- * @id: musb instance
- * @on: flag for phy to be switched on or off
- *
- * This is to enable the PHY using usb_ctrl register in system control
- * module space.
- *
- * XXX: This function will be removed once we have a seperate driver for
- * control module
- */
-static void musb_dsps_phy_control(struct dsps_glue *glue, u8 id, u8 on)
-{
-       u32 usbphycfg;
-
-       usbphycfg = readl(glue->usb_ctrl[id]);
-
-       if (on) {
-               usbphycfg &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN);
-               usbphycfg |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN;
-       } else {
-               usbphycfg |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN;
-       }
-
-       writel(usbphycfg, glue->usb_ctrl[id]);
-}
 /**
  * dsps_musb_enable - enable interrupts
  */
@@ -205,7 +159,6 @@ static void dsps_musb_disable(struct musb *musb)
        dsps_writel(reg_base, wrp->epintr_clear,
                         wrp->txep_bitmap | wrp->rxep_bitmap);
        dsps_writeb(musb->mregs, MUSB_DEVCTL, 0);
-       dsps_writel(reg_base, wrp->eoi, 0);
 }
 
 static void otg_timer(unsigned long _musb)
@@ -213,7 +166,6 @@ static void otg_timer(unsigned long _musb)
        struct musb *musb = (void *)_musb;
        void __iomem *mregs = musb->mregs;
        struct device *dev = musb->controller;
-       struct platform_device *pdev = to_platform_device(dev);
        struct dsps_glue *glue = dev_get_drvdata(dev->parent);
        const struct dsps_musb_wrapper *wrp = glue->wrp;
        u8 devctl;
@@ -250,7 +202,7 @@ static void otg_timer(unsigned long _musb)
        case OTG_STATE_B_IDLE:
                devctl = dsps_readb(mregs, MUSB_DEVCTL);
                if (devctl & MUSB_DEVCTL_BDEVICE)
-                       mod_timer(&glue->timer[pdev->id],
+                       mod_timer(&glue->timer,
                                        jiffies + wrp->poll_seconds * HZ);
                else
                        musb->xceiv->state = OTG_STATE_A_IDLE;
@@ -264,7 +216,6 @@ static void otg_timer(unsigned long _musb)
 static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
 {
        struct device *dev = musb->controller;
-       struct platform_device *pdev = to_platform_device(dev);
        struct dsps_glue *glue = dev_get_drvdata(dev->parent);
 
        if (timeout == 0)
@@ -275,23 +226,23 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
                                musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
                dev_dbg(musb->controller, "%s active, deleting timer\n",
                                usb_otg_state_string(musb->xceiv->state));
-               del_timer(&glue->timer[pdev->id]);
-               glue->last_timer[pdev->id] = jiffies;
+               del_timer(&glue->timer);
+               glue->last_timer = jiffies;
                return;
        }
 
-       if (time_after(glue->last_timer[pdev->id], timeout) &&
-                               timer_pending(&glue->timer[pdev->id])) {
+       if (time_after(glue->last_timer, timeout) &&
+                               timer_pending(&glue->timer)) {
                dev_dbg(musb->controller,
                        "Longer idle timer already pending, ignoring...\n");
                return;
        }
-       glue->last_timer[pdev->id] = timeout;
+       glue->last_timer = timeout;
 
        dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
                usb_otg_state_string(musb->xceiv->state),
                        jiffies_to_msecs(timeout - jiffies));
-       mod_timer(&glue->timer[pdev->id], timeout);
+       mod_timer(&glue->timer, timeout);
 }
 
 static irqreturn_t dsps_interrupt(int irq, void *hci)
@@ -299,7 +250,6 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
        struct musb  *musb = hci;
        void __iomem *reg_base = musb->ctrl_base;
        struct device *dev = musb->controller;
-       struct platform_device *pdev = to_platform_device(dev);
        struct dsps_glue *glue = dev_get_drvdata(dev->parent);
        const struct dsps_musb_wrapper *wrp = glue->wrp;
        unsigned long flags;
@@ -319,7 +269,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
        /* Get usb core interrupts */
        usbintr = dsps_readl(reg_base, wrp->coreintr_status);
        if (!usbintr && !epintr)
-               goto eoi;
+               goto out;
 
        musb->int_usb = (usbintr & wrp->usb_bitmap) >> wrp->usb_shift;
        if (usbintr)
@@ -359,7 +309,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
                         */
                        musb->int_usb &= ~MUSB_INTR_VBUSERROR;
                        musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
-                       mod_timer(&glue->timer[pdev->id],
+                       mod_timer(&glue->timer,
                                        jiffies + wrp->poll_seconds * HZ);
                        WARNING("VBUS error workaround (delay coming)\n");
                } else if (drvvbus) {
@@ -367,7 +317,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
                        MUSB_HST_MODE(musb);
                        musb->xceiv->otg->default_a = 1;
                        musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
-                       del_timer(&glue->timer[pdev->id]);
+                       del_timer(&glue->timer);
                } else {
                        musb->is_active = 0;
                        MUSB_DEV_MODE(musb);
@@ -387,16 +337,10 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
        if (musb->int_tx || musb->int_rx || musb->int_usb)
                ret |= musb_interrupt(musb);
 
- eoi:
-       /* EOI needs to be written for the IRQ to be re-asserted. */
-       if (ret == IRQ_HANDLED || epintr || usbintr)
-               dsps_writel(reg_base, wrp->eoi, 1);
-
        /* Poll for ID change */
        if (musb->xceiv->state == OTG_STATE_B_IDLE)
-               mod_timer(&glue->timer[pdev->id],
-                        jiffies + wrp->poll_seconds * HZ);
-
+               mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
+out:
        spin_unlock_irqrestore(&musb->lock, flags);
 
        return ret;
@@ -405,37 +349,38 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
 static int dsps_musb_init(struct musb *musb)
 {
        struct device *dev = musb->controller;
-       struct platform_device *pdev = to_platform_device(dev);
        struct dsps_glue *glue = dev_get_drvdata(dev->parent);
+       struct platform_device *parent = to_platform_device(dev->parent);
        const struct dsps_musb_wrapper *wrp = glue->wrp;
-       void __iomem *reg_base = musb->ctrl_base;
+       void __iomem *reg_base;
+       struct resource *r;
        u32 rev, val;
-       int status;
 
-       /* mentor core register starts at offset of 0x400 from musb base */
-       musb->mregs += wrp->musb_core_offset;
+       r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control");
+       if (!r)
+               return -EINVAL;
+
+       reg_base = devm_ioremap_resource(dev, r);
+       if (!musb->ctrl_base)
+               return -EINVAL;
+       musb->ctrl_base = reg_base;
 
        /* NOP driver needs change if supporting dual instance */
-       usb_nop_xceiv_register();
-       musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
-       if (IS_ERR_OR_NULL(musb->xceiv))
-               return -EPROBE_DEFER;
+       musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0);
+       if (IS_ERR(musb->xceiv))
+               return PTR_ERR(musb->xceiv);
 
        /* Returns zero if e.g. not clocked */
        rev = dsps_readl(reg_base, wrp->revision);
-       if (!rev) {
-               status = -ENODEV;
-               goto err0;
-       }
+       if (!rev)
+               return -ENODEV;
 
-       setup_timer(&glue->timer[pdev->id], otg_timer, (unsigned long) musb);
+       usb_phy_init(musb->xceiv);
+       setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
 
        /* Reset the musb */
        dsps_writel(reg_base, wrp->control, (1 << wrp->reset));
 
-       /* Start the on-chip PHY and its PLL. */
-       musb_dsps_phy_control(glue, pdev->id, 1);
-
        musb->isr = dsps_interrupt;
 
        /* reset the otgdisable bit, needed for host mode to work */
@@ -443,31 +388,17 @@ static int dsps_musb_init(struct musb *musb)
        val &= ~(1 << wrp->otg_disable);
        dsps_writel(musb->ctrl_base, wrp->phy_utmi, val);
 
-       /* clear level interrupt */
-       dsps_writel(reg_base, wrp->eoi, 0);
-
        return 0;
-err0:
-       usb_put_phy(musb->xceiv);
-       usb_nop_xceiv_unregister();
-       return status;
 }
 
 static int dsps_musb_exit(struct musb *musb)
 {
        struct device *dev = musb->controller;
-       struct platform_device *pdev = to_platform_device(dev);
        struct dsps_glue *glue = dev_get_drvdata(dev->parent);
 
-       del_timer_sync(&glue->timer[pdev->id]);
-
-       /* Shutdown the on-chip PHY and its PLL. */
-       musb_dsps_phy_control(glue, pdev->id, 0);
-
-       /* NOP driver needs change if supporting dual instance */
-       usb_put_phy(musb->xceiv);
-       usb_nop_xceiv_unregister();
+       del_timer_sync(&glue->timer);
 
+       usb_phy_shutdown(musb->xceiv);
        return 0;
 }
 
@@ -483,116 +414,98 @@ static struct musb_platform_ops dsps_ops = {
 
 static u64 musb_dmamask = DMA_BIT_MASK(32);
 
-static int dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
+static int get_int_prop(struct device_node *dn, const char *s)
 {
-       struct device *dev = glue->dev;
-       struct platform_device *pdev = to_platform_device(dev);
-       struct musb_hdrc_platform_data  *pdata = dev->platform_data;
-       struct device_node *np = pdev->dev.of_node;
-       struct musb_hdrc_config *config;
-       struct platform_device  *musb;
-       struct resource *res;
+       int ret;
+       u32 val;
+
+       ret = of_property_read_u32(dn, s, &val);
+       if (ret)
+               return 0;
+       return val;
+}
+
+static int dsps_create_musb_pdev(struct dsps_glue *glue,
+               struct platform_device *parent)
+{
+       struct musb_hdrc_platform_data pdata;
        struct resource resources[2];
-       char res_name[11];
+       struct device *dev = &parent->dev;
+       struct musb_hdrc_config *config;
+       struct platform_device *musb;
+       struct device_node *dn = parent->dev.of_node;
+       struct device_node *child_node;
        int ret;
 
-       resources[0].start = dsps_control_module_phys[id];
-       resources[0].end = resources[0].start + SZ_4 - 1;
-       resources[0].flags = IORESOURCE_MEM;
+       child_node = of_get_child_by_name(dn, "usb");
+       if (!child_node)
+               return -EINVAL;
 
-       glue->usb_ctrl[id] = devm_ioremap_resource(&pdev->dev, resources);
-       if (IS_ERR(glue->usb_ctrl[id])) {
-               ret = PTR_ERR(glue->usb_ctrl[id]);
-               goto err0;
+       memset(resources, 0, sizeof(resources));
+       ret = of_address_to_resource(child_node, 0, &resources[0]);
+       if (ret) {
+               dev_err(dev, "failed to get memory.\n");
+               return ret;
        }
 
-       /* first resource is for usbss, so start index from 1 */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, id + 1);
-       if (!res) {
-               dev_err(dev, "failed to get memory for instance %d\n", id);
-               ret = -ENODEV;
-               goto err0;
-       }
-       res->parent = NULL;
-       resources[0] = *res;
-
-       /* first resource is for usbss, so start index from 1 */
-       res = platform_get_resource(pdev, IORESOURCE_IRQ, id + 1);
-       if (!res) {
-               dev_err(dev, "failed to get irq for instance %d\n", id);
-               ret = -ENODEV;
-               goto err0;
+       ret = of_irq_to_resource(child_node, 0, &resources[1]);
+       if (ret == 0) {
+               dev_err(dev, "failed to get irq.\n");
+               ret = -EINVAL;
+               return ret;
        }
-       res->parent = NULL;
-       resources[1] = *res;
-       resources[1].name = "mc";
 
        /* allocate the child platform device */
        musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
        if (!musb) {
                dev_err(dev, "failed to allocate musb device\n");
-               ret = -ENOMEM;
-               goto err0;
+               return -ENOMEM;
        }
 
        musb->dev.parent                = dev;
        musb->dev.dma_mask              = &musb_dmamask;
        musb->dev.coherent_dma_mask     = musb_dmamask;
+       musb->dev.of_node               = of_node_get(child_node);
 
-       glue->musb[id]                  = musb;
+       glue->musb = musb;
 
-       ret = platform_device_add_resources(musb, resources, 2);
+       ret = platform_device_add_resources(musb, resources,
+                       ARRAY_SIZE(resources));
        if (ret) {
                dev_err(dev, "failed to add resources\n");
-               goto err2;
+               goto err;
        }
 
-       if (np) {
-               pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-               if (!pdata) {
-                       dev_err(&pdev->dev,
-                               "failed to allocate musb platform data\n");
-                       ret = -ENOMEM;
-                       goto err2;
-               }
-
-               config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
-               if (!config) {
-                       dev_err(&pdev->dev,
-                               "failed to allocate musb hdrc config\n");
-                       ret = -ENOMEM;
-                       goto err2;
-               }
-
-               of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
-               of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
-               snprintf(res_name, sizeof(res_name), "port%d-mode", id);
-               of_property_read_u32(np, res_name, (u32 *)&pdata->mode);
-               of_property_read_u32(np, "power", (u32 *)&pdata->power);
-               config->multipoint = of_property_read_bool(np, "multipoint");
-
-               pdata->config           = config;
+       config = devm_kzalloc(&parent->dev, sizeof(*config), GFP_KERNEL);
+       if (!config) {
+               dev_err(dev, "failed to allocate musb hdrc config\n");
+               ret = -ENOMEM;
+               goto err;
        }
+       pdata.config = config;
+       pdata.platform_ops = &dsps_ops;
 
-       pdata->platform_ops             = &dsps_ops;
+       config->num_eps = get_int_prop(child_node, "num-eps");
+       config->ram_bits = get_int_prop(child_node, "ram-bits");
+       pdata.mode = get_int_prop(child_node, "port-mode");
+       pdata.power = get_int_prop(child_node, "power");
+       config->multipoint = of_property_read_bool(child_node, "multipoint");
 
-       ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
+       ret = platform_device_add_data(musb, &pdata, sizeof(pdata));
        if (ret) {
                dev_err(dev, "failed to add platform_data\n");
-               goto err2;
+               goto err;
        }
 
        ret = platform_device_add(musb);
        if (ret) {
                dev_err(dev, "failed to register musb device\n");
-               goto err2;
+               goto err;
        }
-
        return 0;
 
-err2:
+err:
        platform_device_put(musb);
-err0:
        return ret;
 }
 
@@ -601,14 +514,12 @@ static int dsps_probe(struct platform_device *pdev)
        const struct of_device_id *match;
        const struct dsps_musb_wrapper *wrp;
        struct dsps_glue *glue;
-       struct resource *iomem;
-       int ret, i;
+       int ret;
 
        match = of_match_node(musb_dsps_of_match, pdev->dev.of_node);
        if (!match) {
                dev_err(&pdev->dev, "fail to get matching of_match struct\n");
-               ret = -EINVAL;
-               goto err0;
+               return -EINVAL;
        }
        wrp = match->data;
 
@@ -616,29 +527,13 @@ static int dsps_probe(struct platform_device *pdev)
        glue = kzalloc(sizeof(*glue), GFP_KERNEL);
        if (!glue) {
                dev_err(&pdev->dev, "unable to allocate glue memory\n");
-               ret = -ENOMEM;
-               goto err0;
-       }
-
-       /* get memory resource */
-       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!iomem) {
-               dev_err(&pdev->dev, "failed to get usbss mem resourse\n");
-               ret = -ENODEV;
-               goto err1;
+               return -ENOMEM;
        }
 
        glue->dev = &pdev->dev;
+       glue->wrp = wrp;
 
-       glue->wrp = kmemdup(wrp, sizeof(*wrp), GFP_KERNEL);
-       if (!glue->wrp) {
-               dev_err(&pdev->dev, "failed to duplicate wrapper struct memory\n");
-               ret = -ENOMEM;
-               goto err1;
-       }
        platform_set_drvdata(pdev, glue);
-
-       /* enable the usbss clocks */
        pm_runtime_enable(&pdev->dev);
 
        ret = pm_runtime_get_sync(&pdev->dev);
@@ -647,17 +542,9 @@ static int dsps_probe(struct platform_device *pdev)
                goto err2;
        }
 
-       /* create the child platform device for all instances of musb */
-       for (i = 0; i < wrp->instances ; i++) {
-               ret = dsps_create_musb_pdev(glue, i);
-               if (ret != 0) {
-                       dev_err(&pdev->dev, "failed to create child pdev\n");
-                       /* release resources of previously created instances */
-                       for (i--; i >= 0 ; i--)
-                               platform_device_unregister(glue->musb[i]);
-                       goto err3;
-               }
-       }
+       ret = dsps_create_musb_pdev(glue, pdev);
+       if (ret)
+               goto err3;
 
        return 0;
 
@@ -665,65 +552,27 @@ err3:
        pm_runtime_put(&pdev->dev);
 err2:
        pm_runtime_disable(&pdev->dev);
-       kfree(glue->wrp);
-err1:
        kfree(glue);
-err0:
        return ret;
 }
+
 static int dsps_remove(struct platform_device *pdev)
 {
        struct dsps_glue *glue = platform_get_drvdata(pdev);
-       const struct dsps_musb_wrapper *wrp = glue->wrp;
-       int i;
 
-       /* delete the child platform device */
-       for (i = 0; i < wrp->instances ; i++)
-               platform_device_unregister(glue->musb[i]);
+       platform_device_unregister(glue->musb);
 
        /* disable usbss clocks */
        pm_runtime_put(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
-       kfree(glue->wrp);
        kfree(glue);
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int dsps_suspend(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev->parent);
-       struct dsps_glue *glue = platform_get_drvdata(pdev);
-       const struct dsps_musb_wrapper *wrp = glue->wrp;
-       int i;
-
-       for (i = 0; i < wrp->instances; i++)
-               musb_dsps_phy_control(glue, i, 0);
-
-       return 0;
-}
-
-static int dsps_resume(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev->parent);
-       struct dsps_glue *glue = platform_get_drvdata(pdev);
-       const struct dsps_musb_wrapper *wrp = glue->wrp;
-       int i;
-
-       for (i = 0; i < wrp->instances; i++)
-               musb_dsps_phy_control(glue, i, 1);
-
-       return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume);
-
-static const struct dsps_musb_wrapper ti81xx_driver_data = {
+static const struct dsps_musb_wrapper am33xx_driver_data = {
        .revision               = 0x00,
        .control                = 0x14,
        .status                 = 0x18,
-       .eoi                    = 0x24,
        .epintr_set             = 0x38,
        .epintr_clear           = 0x40,
        .epintr_status          = 0x30,
@@ -745,38 +594,23 @@ static const struct dsps_musb_wrapper ti81xx_driver_data = {
        .rxep_shift             = 16,
        .rxep_mask              = 0xfffe,
        .rxep_bitmap            = (0xfffe << 16),
-       .musb_core_offset       = 0x400,
        .poll_seconds           = 2,
-       .instances              = 1,
-};
-
-static const struct platform_device_id musb_dsps_id_table[] = {
-       {
-               .name   = "musb-ti81xx",
-               .driver_data    = (kernel_ulong_t) &ti81xx_driver_data,
-       },
-       {  },   /* Terminating Entry */
 };
-MODULE_DEVICE_TABLE(platform, musb_dsps_id_table);
 
-#ifdef CONFIG_OF
 static const struct of_device_id musb_dsps_of_match[] = {
        { .compatible = "ti,musb-am33xx",
-               .data = (void *) &ti81xx_driver_data, },
+               .data = (void *) &am33xx_driver_data, },
        {  },
 };
 MODULE_DEVICE_TABLE(of, musb_dsps_of_match);
-#endif
 
 static struct platform_driver dsps_usbss_driver = {
        .probe          = dsps_probe,
        .remove         = dsps_remove,
        .driver         = {
                .name   = "musb-dsps",
-               .pm     = &dsps_pm_ops,
                .of_match_table = of_match_ptr(musb_dsps_of_match),
        },
-       .id_table       = musb_dsps_id_table,
 };
 
 MODULE_DESCRIPTION("TI DSPS MUSB Glue Layer");
@@ -784,14 +618,4 @@ MODULE_AUTHOR("Ravi B <ravibabu@ti.com>");
 MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>");
 MODULE_LICENSE("GPL v2");
 
-static int __init dsps_init(void)
-{
-       return platform_driver_register(&dsps_usbss_driver);
-}
-subsys_initcall(dsps_init);
-
-static void __exit dsps_exit(void)
-{
-       platform_driver_unregister(&dsps_usbss_driver);
-}
-module_exit(dsps_exit);
+module_platform_driver(dsps_usbss_driver);
index 0414bc19d0095258ab5e646858ce342a740f92c8..4376f51f5ef1b0b1b870d6a38bec99b8c5d38b76 100644 (file)
@@ -357,47 +357,49 @@ static void txstate(struct musb *musb, struct musb_request *req)
                        }
                }
 
-#elif defined(CONFIG_USB_TI_CPPI_DMA)
-               /* program endpoint CSR first, then setup DMA */
-               csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
-               csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE |
-                      MUSB_TXCSR_MODE;
-               musb_writew(epio, MUSB_TXCSR,
-                       (MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN)
-                               | csr);
-
-               /* ensure writebuffer is empty */
-               csr = musb_readw(epio, MUSB_TXCSR);
-
-               /* NOTE host side sets DMAENAB later than this; both are
-                * OK since the transfer dma glue (between CPPI and Mentor
-                * fifos) just tells CPPI it could start.  Data only moves
-                * to the USB TX fifo when both fifos are ready.
-                */
-
-               /* "mode" is irrelevant here; handle terminating ZLPs like
-                * PIO does, since the hardware RNDIS mode seems unreliable
-                * except for the last-packet-is-already-short case.
-                */
-               use_dma = use_dma && c->channel_program(
-                               musb_ep->dma, musb_ep->packet_sz,
-                               0,
-                               request->dma + request->actual,
-                               request_size);
-               if (!use_dma) {
-                       c->channel_release(musb_ep->dma);
-                       musb_ep->dma = NULL;
-                       csr &= ~MUSB_TXCSR_DMAENAB;
-                       musb_writew(epio, MUSB_TXCSR, csr);
-                       /* invariant: prequest->buf is non-null */
-               }
-#elif defined(CONFIG_USB_TUSB_OMAP_DMA)
-               use_dma = use_dma && c->channel_program(
-                               musb_ep->dma, musb_ep->packet_sz,
-                               request->zero,
-                               request->dma + request->actual,
-                               request_size);
 #endif
+               if (is_cppi_enabled()) {
+                       /* program endpoint CSR first, then setup DMA */
+                       csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
+                       csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE |
+                               MUSB_TXCSR_MODE;
+                       musb_writew(epio, MUSB_TXCSR, (MUSB_TXCSR_P_WZC_BITS &
+                                               ~MUSB_TXCSR_P_UNDERRUN) | csr);
+
+                       /* ensure writebuffer is empty */
+                       csr = musb_readw(epio, MUSB_TXCSR);
+
+                       /*
+                        * NOTE host side sets DMAENAB later than this; both are
+                        * OK since the transfer dma glue (between CPPI and
+                        * Mentor fifos) just tells CPPI it could start. Data
+                        * only moves to the USB TX fifo when both fifos are
+                        * ready.
+                        */
+                       /*
+                        * "mode" is irrelevant here; handle terminating ZLPs
+                        * like PIO does, since the hardware RNDIS mode seems
+                        * unreliable except for the
+                        * last-packet-is-already-short case.
+                        */
+                       use_dma = use_dma && c->channel_program(
+                                       musb_ep->dma, musb_ep->packet_sz,
+                                       0,
+                                       request->dma + request->actual,
+                                       request_size);
+                       if (!use_dma) {
+                               c->channel_release(musb_ep->dma);
+                               musb_ep->dma = NULL;
+                               csr &= ~MUSB_TXCSR_DMAENAB;
+                               musb_writew(epio, MUSB_TXCSR, csr);
+                               /* invariant: prequest->buf is non-null */
+                       }
+               } else if (tusb_dma_omap())
+                       use_dma = use_dma && c->channel_program(
+                                       musb_ep->dma, musb_ep->packet_sz,
+                                       request->zero,
+                                       request->dma + request->actual,
+                                       request_size);
        }
 #endif
 
@@ -1266,7 +1268,8 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
                dev_dbg(musb->controller, "req %p queued to %s while ep %s\n",
                                req, ep->name, "disabled");
                status = -ESHUTDOWN;
-               goto cleanup;
+               unmap_dma_buffer(request, musb);
+               goto unlock;
        }
 
        /* add request to the list */
@@ -1276,7 +1279,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
        if (!musb_ep->busy && &request->list == musb_ep->req_list.next)
                musb_ep_restart(musb, request);
 
-cleanup:
+unlock:
        spin_unlock_irqrestore(&musb->lock, lockflags);
        return status;
 }
index 3d1fd52a15a9958f2256fc78b71a440b06e80a81..e8e9f9aab203ac55ef139a86eaaa5a911067b249 100644 (file)
 #include "musb_core.h"
 #include "musbhsdma.h"
 
-static int dma_controller_start(struct dma_controller *c)
-{
-       /* nothing to do */
-       return 0;
-}
-
 static void dma_channel_release(struct dma_channel *channel);
 
-static int dma_controller_stop(struct dma_controller *c)
+static void dma_controller_stop(struct musb_dma_controller *controller)
 {
-       struct musb_dma_controller *controller = container_of(c,
-                       struct musb_dma_controller, controller);
        struct musb *musb = controller->private_data;
        struct dma_channel *channel;
        u8 bit;
@@ -67,8 +59,6 @@ static int dma_controller_stop(struct dma_controller *c)
                        }
                }
        }
-
-       return 0;
 }
 
 static struct dma_channel *dma_channel_allocate(struct dma_controller *c,
@@ -371,8 +361,7 @@ void dma_controller_destroy(struct dma_controller *c)
        struct musb_dma_controller *controller = container_of(c,
                        struct musb_dma_controller, controller);
 
-       if (!controller)
-               return;
+       dma_controller_stop(controller);
 
        if (controller->irq)
                free_irq(controller->irq, c);
@@ -400,8 +389,6 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba
        controller->private_data = musb;
        controller->base = base;
 
-       controller->controller.start = dma_controller_start;
-       controller->controller.stop = dma_controller_stop;
        controller->controller.channel_alloc = dma_channel_allocate;
        controller->controller.channel_release = dma_channel_release;
        controller->controller.channel_program = dma_channel_program;
index f44e8b5e00c94b3b22ddf06b632041e0c462b060..59d2245db1c81ce228d7607aa1176e56bbfb9082 100644 (file)
@@ -255,7 +255,7 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
 {
        struct musb *musb = glue_to_musb(glue);
        struct device *dev = musb->controller;
-       struct musb_hdrc_platform_data *pdata = dev->platform_data;
+       struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
        struct omap_musb_board_data *data = pdata->board_data;
        struct usb_otg *otg = musb->xceiv->otg;
 
@@ -341,7 +341,7 @@ static int omap2430_musb_init(struct musb *musb)
        int status = 0;
        struct device *dev = musb->controller;
        struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
-       struct musb_hdrc_platform_data *plat = dev->platform_data;
+       struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
        struct omap_musb_board_data *data = plat->board_data;
 
        /* We require some kind of external transceiver, hooked
@@ -412,7 +412,7 @@ static void omap2430_musb_enable(struct musb *musb)
        unsigned long timeout = jiffies + msecs_to_jiffies(1000);
        struct device *dev = musb->controller;
        struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
-       struct musb_hdrc_platform_data *pdata = dev->platform_data;
+       struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
        struct omap_musb_board_data *data = pdata->board_data;
 
        switch (glue->status) {
@@ -482,7 +482,7 @@ static u64 omap2430_dmamask = DMA_BIT_MASK(32);
 static int omap2430_probe(struct platform_device *pdev)
 {
        struct resource                 musb_resources[3];
-       struct musb_hdrc_platform_data  *pdata = pdev->dev.platform_data;
+       struct musb_hdrc_platform_data  *pdata = dev_get_platdata(&pdev->dev);
        struct omap_musb_board_data     *data;
        struct platform_device          *musb;
        struct omap2430_glue            *glue;
index 6f8a9ca96ae753f31b637d0f0c08c1d27a550699..b3b3ed723882ffab75829e7c9bc1b08b42e1605d 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 
 #include "musb_core.h"
 
@@ -1157,7 +1157,7 @@ static u64 tusb_dmamask = DMA_BIT_MASK(32);
 static int tusb_probe(struct platform_device *pdev)
 {
        struct resource musb_resources[3];
-       struct musb_hdrc_platform_data  *pdata = pdev->dev.platform_data;
+       struct musb_hdrc_platform_data  *pdata = dev_get_platdata(&pdev->dev);
        struct platform_device          *musb;
        struct tusb6010_glue            *glue;
 
index 98df17c984a898bee7786f8e07e6421a626f2a7c..b8794eb81e9ca3a483c7d3b52a633b8dffae4065 100644 (file)
@@ -66,28 +66,6 @@ struct tusb_omap_dma {
        unsigned                        multichannel:1;
 };
 
-static int tusb_omap_dma_start(struct dma_controller *c)
-{
-       struct tusb_omap_dma    *tusb_dma;
-
-       tusb_dma = container_of(c, struct tusb_omap_dma, controller);
-
-       /* dev_dbg(musb->controller, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */
-
-       return 0;
-}
-
-static int tusb_omap_dma_stop(struct dma_controller *c)
-{
-       struct tusb_omap_dma    *tusb_dma;
-
-       tusb_dma = container_of(c, struct tusb_omap_dma, controller);
-
-       /* dev_dbg(musb->controller, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */
-
-       return 0;
-}
-
 /*
  * Allocate dmareq0 to the current channel unless it's already taken
  */
@@ -695,8 +673,6 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba
        tusb_dma->dmareq = -1;
        tusb_dma->sync_dev = -1;
 
-       tusb_dma->controller.start = tusb_omap_dma_start;
-       tusb_dma->controller.stop = tusb_omap_dma_stop;
        tusb_dma->controller.channel_alloc = tusb_omap_dma_allocate;
        tusb_dma->controller.channel_release = tusb_omap_dma_release;
        tusb_dma->controller.channel_program = tusb_omap_dma_program;
index fce71b605936ed228bc104efd2d5d60c0959af2f..59256b12f7469fe9170ec0fa7db0bee3cbbed6da 100644 (file)
@@ -227,7 +227,7 @@ ux500_of_probe(struct platform_device *pdev, struct device_node *np)
 static int ux500_probe(struct platform_device *pdev)
 {
        struct resource musb_resources[2];
-       struct musb_hdrc_platform_data  *pdata = pdev->dev.platform_data;
+       struct musb_hdrc_platform_data  *pdata = dev_get_platdata(&pdev->dev);
        struct device_node              *np = pdev->dev.of_node;
        struct platform_device          *musb;
        struct ux500_glue               *glue;
index bfb7a65d83ccebbb9429a280e7091d4940019186..e51dd9b88e7102b9c54fc53317fe32e2b47be103 100644 (file)
@@ -254,10 +254,8 @@ static int ux500_dma_channel_abort(struct dma_channel *channel)
        return 0;
 }
 
-static int ux500_dma_controller_stop(struct dma_controller *c)
+static void ux500_dma_controller_stop(struct ux500_dma_controller *controller)
 {
-       struct ux500_dma_controller *controller = container_of(c,
-                       struct ux500_dma_controller, controller);
        struct ux500_dma_channel *ux500_channel;
        struct dma_channel *channel;
        u8 ch_num;
@@ -281,18 +279,14 @@ static int ux500_dma_controller_stop(struct dma_controller *c)
                if (ux500_channel->dma_chan)
                        dma_release_channel(ux500_channel->dma_chan);
        }
-
-       return 0;
 }
 
-static int ux500_dma_controller_start(struct dma_controller *c)
+static int ux500_dma_controller_start(struct ux500_dma_controller *controller)
 {
-       struct ux500_dma_controller *controller = container_of(c,
-                       struct ux500_dma_controller, controller);
        struct ux500_dma_channel *ux500_channel = NULL;
        struct musb *musb = controller->private_data;
        struct device *dev = musb->controller;
-       struct musb_hdrc_platform_data *plat = dev->platform_data;
+       struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
        struct ux500_musb_board_data *data;
        struct dma_channel *dma_channel = NULL;
        char **chan_names;
@@ -347,7 +341,7 @@ static int ux500_dma_controller_start(struct dma_controller *c)
                                        dir, ch_num);
 
                                /* Release already allocated channels */
-                               ux500_dma_controller_stop(c);
+                               ux500_dma_controller_stop(controller);
 
                                return -EBUSY;
                        }
@@ -369,6 +363,7 @@ void dma_controller_destroy(struct dma_controller *c)
        struct ux500_dma_controller *controller = container_of(c,
                        struct ux500_dma_controller, controller);
 
+       ux500_dma_controller_stop(controller);
        kfree(controller);
 }
 
@@ -378,6 +373,7 @@ struct dma_controller *dma_controller_create(struct musb *musb,
        struct ux500_dma_controller *controller;
        struct platform_device *pdev = to_platform_device(musb->controller);
        struct resource *iomem;
+       int ret;
 
        controller = kzalloc(sizeof(*controller), GFP_KERNEL);
        if (!controller)
@@ -394,14 +390,15 @@ struct dma_controller *dma_controller_create(struct musb *musb,
 
        controller->phy_base = (dma_addr_t) iomem->start;
 
-       controller->controller.start = ux500_dma_controller_start;
-       controller->controller.stop = ux500_dma_controller_stop;
        controller->controller.channel_alloc = ux500_dma_channel_allocate;
        controller->controller.channel_release = ux500_dma_channel_release;
        controller->controller.channel_program = ux500_dma_channel_program;
        controller->controller.channel_abort = ux500_dma_channel_abort;
        controller->controller.is_compatible = ux500_dma_is_compatible;
 
+       ret = ux500_dma_controller_start(controller);
+       if (ret)
+               goto plat_get_fail;
        return &controller->controller;
 
 plat_get_fail:
index 3622fff8b798adeeda9ba5a94f1b0b182d1fc839..d5589f9c60a92e3c96757c8a6ba1fd6a171e01b1 100644 (file)
@@ -1,22 +1,10 @@
 #
 # Physical Layer USB driver configuration
 #
-menuconfig USB_PHY
-       bool "USB Physical Layer drivers"
-       help
-         Most USB controllers have the physical layer signalling part
-         (commonly called a PHY) built in.  However, dual-role devices
-         (a.k.a. USB on-the-go) which support being USB master or slave
-         with the same connector often use an external PHY.
-
-         The drivers in this submenu add support for such PHY devices.
-         They are not needed for standard master-only (or the vast
-         majority of slave-only) USB interfaces.
+menu "USB Physical Layer drivers"
 
-         If you're not sure if this applies to you, it probably doesn't;
-         say N here.
-
-if USB_PHY
+config USB_PHY
+       def_bool n
 
 #
 # USB Transceiver Drivers
@@ -24,6 +12,7 @@ if USB_PHY
 config AB8500_USB
        tristate "AB8500 USB Transceiver Driver"
        depends on AB8500_CORE
+       select USB_PHY
        help
          Enable this to support the USB OTG transceiver in AB8500 chip.
          This transceiver supports high and full speed devices plus,
@@ -33,12 +22,14 @@ config FSL_USB2_OTG
        bool "Freescale USB OTG Transceiver Driver"
        depends on USB_EHCI_FSL && USB_FSL_USB2 && PM_RUNTIME
        select USB_OTG
+       select USB_PHY
        help
          Enable this to support Freescale USB OTG transceiver.
 
 config ISP1301_OMAP
        tristate "Philips ISP1301 with OMAP OTG"
        depends on I2C && ARCH_OMAP_OTG
+       select USB_PHY
        help
          If you say yes here you get support for the Philips ISP1301
          USB-On-The-Go transceiver working with the OMAP OTG controller.
@@ -52,12 +43,14 @@ config ISP1301_OMAP
 config MV_U3D_PHY
        bool "Marvell USB 3.0 PHY controller Driver"
        depends on CPU_MMP3
+       select USB_PHY
        help
          Enable this to support Marvell USB 3.0 phy controller for Marvell
          SoC.
 
 config NOP_USB_XCEIV
        tristate "NOP USB Transceiver Driver"
+       select USB_PHY
        help
          This driver is to be used by all the usb transceiver which are either
          built-in with usb ip or which are autonomous and doesn't require any
@@ -65,6 +58,7 @@ config NOP_USB_XCEIV
 
 config OMAP_CONTROL_USB
        tristate "OMAP CONTROL USB Driver"
+       depends on ARCH_OMAP2PLUS || COMPILE_TEST
        help
          Enable this to add support for the USB part present in the control
          module. This driver has API to power on the USB2 PHY and to write to
@@ -76,6 +70,7 @@ config OMAP_USB2
        tristate "OMAP USB2 PHY Driver"
        depends on ARCH_OMAP2PLUS
        select OMAP_CONTROL_USB
+       select USB_PHY
        help
          Enable this to support the transceiver that is part of SOC. This
          driver takes care of all the PHY functionality apart from comparator.
@@ -84,13 +79,27 @@ config OMAP_USB2
 
 config OMAP_USB3
        tristate "OMAP USB3 PHY Driver"
+       depends on ARCH_OMAP2PLUS || COMPILE_TEST
        select OMAP_CONTROL_USB
+       select USB_PHY
        help
          Enable this to support the USB3 PHY that is part of SOC. This
          driver takes care of all the PHY functionality apart from comparator.
          This driver interacts with the "OMAP Control USB Driver" to power
          on/off the PHY.
 
+config AM335X_CONTROL_USB
+       tristate
+
+config AM335X_PHY_USB
+       tristate "AM335x USB PHY Driver"
+       select USB_PHY
+       select AM335X_CONTROL_USB
+       select NOP_USB_XCEIV
+       help
+         This driver provides PHY support for that phy which part for the
+         AM335x SoC.
+
 config SAMSUNG_USBPHY
        tristate
        help
@@ -101,6 +110,7 @@ config SAMSUNG_USBPHY
 config SAMSUNG_USB2PHY
        tristate "Samsung USB 2.0 PHY controller Driver"
        select SAMSUNG_USBPHY
+       select USB_PHY
        help
          Enable this to support Samsung USB 2.0 (High Speed) PHY controller
          driver for Samsung SoCs.
@@ -108,6 +118,7 @@ config SAMSUNG_USB2PHY
 config SAMSUNG_USB3PHY
        tristate "Samsung USB 3.0 PHY controller Driver"
        select SAMSUNG_USBPHY
+       select USB_PHY
        help
          Enable this to support Samsung USB 3.0 (Super Speed) phy controller
          for samsung SoCs.
@@ -115,6 +126,7 @@ config SAMSUNG_USB3PHY
 config TWL4030_USB
        tristate "TWL4030 USB Transceiver Driver"
        depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
+       select USB_PHY
        help
          Enable this to support the USB OTG transceiver on TWL4030
          family chips (including the TWL5030 and TPS659x0 devices).
@@ -135,6 +147,7 @@ config TWL6030_USB
 config USB_GPIO_VBUS
        tristate "GPIO based peripheral-only VBUS sensing 'transceiver'"
        depends on GPIOLIB
+       select USB_PHY
        help
          Provides simple GPIO VBUS sensing for controllers with an
          internal transceiver via the usb_phy interface, and
@@ -145,6 +158,7 @@ config USB_ISP1301
        tristate "NXP ISP1301 USB transceiver support"
        depends on USB || USB_GADGET
        depends on I2C
+       select USB_PHY
        help
          Say Y here to add support for the NXP ISP1301 USB transceiver driver.
          This chip is typically used as USB transceiver for USB host, gadget
@@ -156,6 +170,7 @@ config USB_ISP1301
 config USB_MSM_OTG
        tristate "OTG support for Qualcomm on-chip USB controller"
        depends on (USB || USB_GADGET) && ARCH_MSM
+       select USB_PHY
        help
          Enable this to support the USB OTG transceiver on MSM chips. It
          handles PHY initialization, clock management, and workarounds
@@ -169,6 +184,7 @@ config USB_MV_OTG
        tristate "Marvell USB OTG support"
        depends on USB_EHCI_MV && USB_MV_UDC && PM_RUNTIME
        select USB_OTG
+       select USB_PHY
        help
          Say Y here if you want to build Marvell USB OTG transciever
          driver in kernel (including PXA and MMP series). This driver
@@ -180,6 +196,7 @@ config USB_MXS_PHY
        tristate "Freescale MXS USB PHY support"
        depends on ARCH_MXC || ARCH_MXS
        select STMP_DEVICE
+       select USB_PHY
        help
          Enable this to support the Freescale MXS USB PHY.
 
@@ -188,6 +205,7 @@ config USB_MXS_PHY
 config USB_RCAR_PHY
        tristate "Renesas R-Car USB PHY support"
        depends on USB || USB_GADGET
+       select USB_PHY
        help
          Say Y here to add support for the Renesas R-Car USB common PHY driver.
          This chip is typically used as USB PHY for USB host, gadget.
@@ -210,4 +228,4 @@ config USB_ULPI_VIEWPORT
          Provides read/write operations to the ULPI phy register set for
          controllers with a viewport register (e.g. Chipidea/ARC controllers).
 
-endif # USB_PHY
+endmenu
index 070eca3af18b756e416d5bc9475c18ee9aaa5460..2135e85f46eda29f104940467154a789db870683 100644 (file)
@@ -1,9 +1,6 @@
 #
 # Makefile for physical layer USB drivers
 #
-
-ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
-
 obj-$(CONFIG_USB_PHY)                  += phy.o
 obj-$(CONFIG_OF)                       += of.o
 
@@ -14,8 +11,10 @@ phy-fsl-usb2-objs                    := phy-fsl-usb.o phy-fsm-usb.o
 obj-$(CONFIG_FSL_USB2_OTG)             += phy-fsl-usb2.o
 obj-$(CONFIG_ISP1301_OMAP)             += phy-isp1301-omap.o
 obj-$(CONFIG_MV_U3D_PHY)               += phy-mv-u3d-usb.o
-obj-$(CONFIG_NOP_USB_XCEIV)            += phy-nop.o
+obj-$(CONFIG_NOP_USB_XCEIV)            += phy-generic.o
 obj-$(CONFIG_OMAP_CONTROL_USB)         += phy-omap-control.o
+obj-$(CONFIG_AM335X_CONTROL_USB)       += phy-am335x-control.o
+obj-$(CONFIG_AM335X_PHY_USB)           += phy-am335x.o
 obj-$(CONFIG_OMAP_USB2)                        += phy-omap-usb2.o
 obj-$(CONFIG_OMAP_USB3)                        += phy-omap-usb3.o
 obj-$(CONFIG_SAMSUNG_USBPHY)           += phy-samsung-usb.o
diff --git a/drivers/usb/phy/am35x-phy-control.h b/drivers/usb/phy/am35x-phy-control.h
new file mode 100644 (file)
index 0000000..b96594d
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _AM335x_PHY_CONTROL_H_
+#define _AM335x_PHY_CONTROL_H_
+
+struct phy_control {
+       void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on);
+       void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on);
+};
+
+static inline void phy_ctrl_power(struct phy_control *phy_ctrl, u32 id, bool on)
+{
+       phy_ctrl->phy_power(phy_ctrl, id, on);
+}
+
+static inline void phy_ctrl_wkup(struct phy_control *phy_ctrl, u32 id, bool on)
+{
+       phy_ctrl->phy_wkup(phy_ctrl, id, on);
+}
+
+struct phy_control *am335x_get_phy_control(struct device *dev);
+
+#endif
diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c
new file mode 100644 (file)
index 0000000..7597545
--- /dev/null
@@ -0,0 +1,137 @@
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/io.h>
+
+struct phy_control {
+       void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on);
+       void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on);
+};
+
+struct am335x_control_usb {
+       struct device *dev;
+       void __iomem *phy_reg;
+       void __iomem *wkup;
+       spinlock_t lock;
+       struct phy_control phy_ctrl;
+};
+
+#define AM335X_USB0_CTRL               0x0
+#define AM335X_USB1_CTRL               0x8
+#define AM335x_USB_WKUP                        0x0
+
+#define USBPHY_CM_PWRDN                (1 << 0)
+#define USBPHY_OTG_PWRDN       (1 << 1)
+#define USBPHY_OTGVDET_EN      (1 << 19)
+#define USBPHY_OTGSESSEND_EN   (1 << 20)
+
+static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on)
+{
+       struct am335x_control_usb *usb_ctrl;
+       u32 val;
+       u32 reg;
+
+       usb_ctrl = container_of(phy_ctrl, struct am335x_control_usb, phy_ctrl);
+
+       switch (id) {
+       case 0:
+               reg = AM335X_USB0_CTRL;
+               break;
+       case 1:
+               reg = AM335X_USB1_CTRL;
+               break;
+       default:
+               __WARN();
+                return;
+       }
+
+       val = readl(usb_ctrl->phy_reg + reg);
+       if (on) {
+               val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN);
+               val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN;
+       } else {
+               val |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN;
+       }
+
+       writel(val, usb_ctrl->phy_reg + reg);
+}
+
+static const struct phy_control ctrl_am335x = {
+       .phy_power = am335x_phy_power,
+};
+
+static const struct of_device_id omap_control_usb_id_table[] = {
+       { .compatible = "ti,am335x-usb-ctrl-module", .data = &ctrl_am335x },
+       {}
+};
+MODULE_DEVICE_TABLE(of, omap_control_usb_id_table);
+
+static struct platform_driver am335x_control_driver;
+static int match(struct device *dev, void *data)
+{
+       struct device_node *node = (struct device_node *)data;
+       return dev->of_node == node &&
+               dev->driver == &am335x_control_driver.driver;
+}
+
+struct phy_control *am335x_get_phy_control(struct device *dev)
+{
+       struct device_node *node;
+       struct am335x_control_usb *ctrl_usb;
+
+       node = of_parse_phandle(dev->of_node, "ti,ctrl_mod", 0);
+       if (!node)
+               return NULL;
+
+       dev = bus_find_device(&platform_bus_type, NULL, node, match);
+       ctrl_usb = dev_get_drvdata(dev);
+       if (!ctrl_usb)
+               return NULL;
+       return &ctrl_usb->phy_ctrl;
+}
+EXPORT_SYMBOL_GPL(am335x_get_phy_control);
+
+static int am335x_control_usb_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct am335x_control_usb *ctrl_usb;
+       const struct of_device_id *of_id;
+       const struct phy_control *phy_ctrl;
+
+       of_id = of_match_node(omap_control_usb_id_table, pdev->dev.of_node);
+       if (!of_id)
+               return -EINVAL;
+
+       phy_ctrl = of_id->data;
+
+       ctrl_usb = devm_kzalloc(&pdev->dev, sizeof(*ctrl_usb), GFP_KERNEL);
+       if (!ctrl_usb) {
+               dev_err(&pdev->dev, "unable to alloc memory for control usb\n");
+               return -ENOMEM;
+       }
+
+       ctrl_usb->dev = &pdev->dev;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl");
+       ctrl_usb->phy_reg = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(ctrl_usb->phy_reg))
+               return PTR_ERR(ctrl_usb->phy_reg);
+       spin_lock_init(&ctrl_usb->lock);
+       ctrl_usb->phy_ctrl = *phy_ctrl;
+
+       dev_set_drvdata(ctrl_usb->dev, ctrl_usb);
+       return 0;
+}
+
+static struct platform_driver am335x_control_driver = {
+       .probe          = am335x_control_usb_probe,
+       .driver         = {
+               .name   = "am335x-control-usb",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(omap_control_usb_id_table),
+       },
+};
+
+module_platform_driver(am335x_control_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c
new file mode 100644 (file)
index 0000000..c4d614d
--- /dev/null
@@ -0,0 +1,99 @@
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include "am35x-phy-control.h"
+#include "phy-generic.h"
+
+struct am335x_phy {
+       struct usb_phy_gen_xceiv usb_phy_gen;
+       struct phy_control *phy_ctrl;
+       int id;
+};
+
+static int am335x_init(struct usb_phy *phy)
+{
+       struct am335x_phy *am_phy = dev_get_drvdata(phy->dev);
+
+       phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, true);
+       return 0;
+}
+
+static void am335x_shutdown(struct usb_phy *phy)
+{
+       struct am335x_phy *am_phy = dev_get_drvdata(phy->dev);
+
+       phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false);
+}
+
+static int am335x_phy_probe(struct platform_device *pdev)
+{
+       struct am335x_phy *am_phy;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       am_phy = devm_kzalloc(dev, sizeof(*am_phy), GFP_KERNEL);
+       if (!am_phy)
+               return -ENOMEM;
+
+       am_phy->phy_ctrl = am335x_get_phy_control(dev);
+       if (!am_phy->phy_ctrl)
+               return -EPROBE_DEFER;
+       am_phy->id = of_alias_get_id(pdev->dev.of_node, "phy");
+       if (am_phy->id < 0) {
+               dev_err(&pdev->dev, "Missing PHY id: %d\n", am_phy->id);
+               return am_phy->id;
+       }
+
+       ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen,
+                       USB_PHY_TYPE_USB2, 0, false, false);
+       if (ret)
+               return ret;
+
+       ret = usb_add_phy_dev(&am_phy->usb_phy_gen.phy);
+       if (ret)
+               goto err_add;
+       am_phy->usb_phy_gen.phy.init = am335x_init;
+       am_phy->usb_phy_gen.phy.shutdown = am335x_shutdown;
+
+       platform_set_drvdata(pdev, am_phy);
+       return 0;
+
+err_add:
+       usb_phy_gen_cleanup_phy(&am_phy->usb_phy_gen);
+       return ret;
+}
+
+static int am335x_phy_remove(struct platform_device *pdev)
+{
+       struct am335x_phy *am_phy = platform_get_drvdata(pdev);
+
+       usb_remove_phy(&am_phy->usb_phy_gen.phy);
+       return 0;
+}
+
+static const struct of_device_id am335x_phy_ids[] = {
+       { .compatible = "ti,am335x-usb-phy" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, am335x_phy_ids);
+
+static struct platform_driver am335x_phy_driver = {
+       .probe          = am335x_phy_probe,
+       .remove         = am335x_phy_remove,
+       .driver         = {
+               .name   = "am335x-phy-driver",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(am335x_phy_ids),
+       },
+};
+
+module_platform_driver(am335x_phy_driver);
+MODULE_LICENSE("GPL v2");
index e771bafb9f1da3375f9f0492493c973fe0862484..fa7c9f9628b599e072b7062ff03270c35714161f 100644 (file)
@@ -611,7 +611,7 @@ static int fsl_otg_set_peripheral(struct usb_otg *otg,
        otg_dev->fsm.b_bus_req = 1;
 
        /* start the gadget right away if the ID pin says Mini-B */
-       DBG("ID pin=%d\n", otg_dev->fsm.id);
+       pr_debug("ID pin=%d\n", otg_dev->fsm.id);
        if (otg_dev->fsm.id == 1) {
                fsl_otg_start_host(&otg_dev->fsm, 0);
                otg_drv_vbus(&otg_dev->fsm, 0);
@@ -684,7 +684,7 @@ static int fsl_otg_start_hnp(struct usb_otg *otg)
        if (otg_dev != fsl_otg_dev)
                return -ENODEV;
 
-       DBG("start_hnp...n");
+       pr_debug("start_hnp...\n");
 
        /* clear a_bus_req to enter a_suspend state */
        otg_dev->fsm.a_bus_req = 0;
@@ -834,7 +834,7 @@ int usb_otg_start(struct platform_device *pdev)
        int status;
        struct resource *res;
        u32 temp;
-       struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+       struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
        p_otg = container_of(otg_trans, struct fsl_otg, phy);
        fsm = &p_otg->fsm;
@@ -941,7 +941,7 @@ int usb_otg_start(struct platform_device *pdev)
                p_otg->fsm.id = 0;
        }
 
-       DBG("initial ID pin=%d\n", p_otg->fsm.id);
+       pr_debug("initial ID pin=%d\n", p_otg->fsm.id);
 
        /* enable OTG ID pin interrupt */
        temp = fsl_readl(&p_otg->dr_mem_map->otgsc);
@@ -1105,7 +1105,7 @@ static int fsl_otg_probe(struct platform_device *pdev)
 {
        int ret;
 
-       if (!pdev->dev.platform_data)
+       if (!dev_get_platdata(&pdev->dev))
                return -ENODEV;
 
        /* configure the OTG */
@@ -1137,7 +1137,7 @@ static int fsl_otg_probe(struct platform_device *pdev)
 
 static int fsl_otg_remove(struct platform_device *pdev)
 {
-       struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+       struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
        usb_remove_phy(&fsl_otg_dev->phy);
        free_irq(fsl_otg_dev->irq, fsl_otg_dev);
index c30a2e1d9e4699f1017a0ba3000efb3cdbd6596d..fbe586206f33be707bf1bba33340d80a3f0f4437 100644 (file)
  * 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#undef DEBUG
 #undef VERBOSE
 
-#ifdef DEBUG
-#define DBG(fmt, args...) printk(KERN_DEBUG "[%s]  " fmt , \
-                                __func__, ## args)
-#else
-#define DBG(fmt, args...)      do {} while (0)
-#endif
-
 #ifdef VERBOSE
-#define VDBG           DBG
+#define VDBG(fmt, args...) pr_debug("[%s]  " fmt , \
+                                __func__, ## args)
 #else
 #define VDBG(stuff...) do {} while (0)
 #endif
diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
new file mode 100644 (file)
index 0000000..efe59f3
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * drivers/usb/otg/nop-usb-xceiv.c
+ *
+ * NOP USB transceiver for all USB transceiver which are either built-in
+ * into USB IP or which are mostly autonomous.
+ *
+ * Copyright (C) 2009 Texas Instruments Inc
+ * Author: Ajay Kumar Gupta <ajay.gupta@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Current status:
+ *     This provides a "nop" transceiver for PHYs which are
+ *     autonomous such as isp1504, isp1707, etc.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+
+#include "phy-generic.h"
+
+static struct platform_device *pd;
+
+void usb_nop_xceiv_register(void)
+{
+       if (pd)
+               return;
+       pd = platform_device_register_simple("usb_phy_gen_xceiv", -1, NULL, 0);
+       if (!pd) {
+               pr_err("Unable to register generic usb transceiver\n");
+               return;
+       }
+}
+EXPORT_SYMBOL(usb_nop_xceiv_register);
+
+void usb_nop_xceiv_unregister(void)
+{
+       platform_device_unregister(pd);
+       pd = NULL;
+}
+EXPORT_SYMBOL(usb_nop_xceiv_unregister);
+
+static int nop_set_suspend(struct usb_phy *x, int suspend)
+{
+       return 0;
+}
+
+int usb_gen_phy_init(struct usb_phy *phy)
+{
+       struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev);
+
+       if (!IS_ERR(nop->vcc)) {
+               if (regulator_enable(nop->vcc))
+                       dev_err(phy->dev, "Failed to enable power\n");
+       }
+
+       if (!IS_ERR(nop->clk))
+               clk_enable(nop->clk);
+
+       if (!IS_ERR(nop->reset)) {
+               /* De-assert RESET */
+               if (regulator_enable(nop->reset))
+                       dev_err(phy->dev, "Failed to de-assert reset\n");
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(usb_gen_phy_init);
+
+void usb_gen_phy_shutdown(struct usb_phy *phy)
+{
+       struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev);
+
+       if (!IS_ERR(nop->reset)) {
+               /* Assert RESET */
+               if (regulator_disable(nop->reset))
+                       dev_err(phy->dev, "Failed to assert reset\n");
+       }
+
+       if (!IS_ERR(nop->clk))
+               clk_disable(nop->clk);
+
+       if (!IS_ERR(nop->vcc)) {
+               if (regulator_disable(nop->vcc))
+                       dev_err(phy->dev, "Failed to disable power\n");
+       }
+}
+EXPORT_SYMBOL_GPL(usb_gen_phy_shutdown);
+
+static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
+{
+       if (!otg)
+               return -ENODEV;
+
+       if (!gadget) {
+               otg->gadget = NULL;
+               return -ENODEV;
+       }
+
+       otg->gadget = gadget;
+       otg->phy->state = OTG_STATE_B_IDLE;
+       return 0;
+}
+
+static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+       if (!otg)
+               return -ENODEV;
+
+       if (!host) {
+               otg->host = NULL;
+               return -ENODEV;
+       }
+
+       otg->host = host;
+       return 0;
+}
+
+int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
+               enum usb_phy_type type, u32 clk_rate, bool needs_vcc,
+               bool needs_reset)
+{
+       int err;
+
+       nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg),
+                       GFP_KERNEL);
+       if (!nop->phy.otg)
+               return -ENOMEM;
+
+       nop->clk = devm_clk_get(dev, "main_clk");
+       if (IS_ERR(nop->clk)) {
+               dev_dbg(dev, "Can't get phy clock: %ld\n",
+                                       PTR_ERR(nop->clk));
+       }
+
+       if (!IS_ERR(nop->clk) && clk_rate) {
+               err = clk_set_rate(nop->clk, clk_rate);
+               if (err) {
+                       dev_err(dev, "Error setting clock rate\n");
+                       return err;
+               }
+       }
+
+       if (!IS_ERR(nop->clk)) {
+               err = clk_prepare(nop->clk);
+               if (err) {
+                       dev_err(dev, "Error preparing clock\n");
+                       return err;
+               }
+       }
+
+       nop->vcc = devm_regulator_get(dev, "vcc");
+       if (IS_ERR(nop->vcc)) {
+               dev_dbg(dev, "Error getting vcc regulator: %ld\n",
+                                       PTR_ERR(nop->vcc));
+               if (needs_vcc)
+                       return -EPROBE_DEFER;
+       }
+
+       nop->reset = devm_regulator_get(dev, "reset");
+       if (IS_ERR(nop->reset)) {
+               dev_dbg(dev, "Error getting reset regulator: %ld\n",
+                                       PTR_ERR(nop->reset));
+               if (needs_reset)
+                       return -EPROBE_DEFER;
+       }
+
+       nop->dev                = dev;
+       nop->phy.dev            = nop->dev;
+       nop->phy.label          = "nop-xceiv";
+       nop->phy.set_suspend    = nop_set_suspend;
+       nop->phy.state          = OTG_STATE_UNDEFINED;
+       nop->phy.type           = type;
+
+       nop->phy.otg->phy               = &nop->phy;
+       nop->phy.otg->set_host          = nop_set_host;
+       nop->phy.otg->set_peripheral    = nop_set_peripheral;
+
+       ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy);
+
+void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop)
+{
+       if (!IS_ERR(nop->clk))
+               clk_unprepare(nop->clk);
+}
+EXPORT_SYMBOL_GPL(usb_phy_gen_cleanup_phy);
+
+static int usb_phy_gen_xceiv_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct usb_phy_gen_xceiv_platform_data *pdata =
+                       dev_get_platdata(&pdev->dev);
+       struct usb_phy_gen_xceiv        *nop;
+       enum usb_phy_type       type = USB_PHY_TYPE_USB2;
+       int err;
+       u32 clk_rate = 0;
+       bool needs_vcc = false;
+       bool needs_reset = false;
+
+       if (dev->of_node) {
+               struct device_node *node = dev->of_node;
+
+               if (of_property_read_u32(node, "clock-frequency", &clk_rate))
+                       clk_rate = 0;
+
+               needs_vcc = of_property_read_bool(node, "vcc-supply");
+               needs_reset = of_property_read_bool(node, "reset-supply");
+
+       } else if (pdata) {
+               type = pdata->type;
+               clk_rate = pdata->clk_rate;
+               needs_vcc = pdata->needs_vcc;
+               needs_reset = pdata->needs_reset;
+       }
+
+       nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL);
+       if (!nop)
+               return -ENOMEM;
+
+
+       err = usb_phy_gen_create_phy(dev, nop, type, clk_rate, needs_vcc,
+                       needs_reset);
+       if (err)
+               return err;
+
+       nop->phy.init           = usb_gen_phy_init;
+       nop->phy.shutdown       = usb_gen_phy_shutdown;
+
+       err = usb_add_phy_dev(&nop->phy);
+       if (err) {
+               dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
+                       err);
+               goto err_add;
+       }
+
+       platform_set_drvdata(pdev, nop);
+
+       return 0;
+
+err_add:
+       usb_phy_gen_cleanup_phy(nop);
+       return err;
+}
+
+static int usb_phy_gen_xceiv_remove(struct platform_device *pdev)
+{
+       struct usb_phy_gen_xceiv *nop = platform_get_drvdata(pdev);
+
+       usb_phy_gen_cleanup_phy(nop);
+       usb_remove_phy(&nop->phy);
+
+       return 0;
+}
+
+static const struct of_device_id nop_xceiv_dt_ids[] = {
+       { .compatible = "usb-nop-xceiv" },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids);
+
+static struct platform_driver usb_phy_gen_xceiv_driver = {
+       .probe          = usb_phy_gen_xceiv_probe,
+       .remove         = usb_phy_gen_xceiv_remove,
+       .driver         = {
+               .name   = "usb_phy_gen_xceiv",
+               .owner  = THIS_MODULE,
+               .of_match_table = nop_xceiv_dt_ids,
+       },
+};
+
+static int __init usb_phy_gen_xceiv_init(void)
+{
+       return platform_driver_register(&usb_phy_gen_xceiv_driver);
+}
+subsys_initcall(usb_phy_gen_xceiv_init);
+
+static void __exit usb_phy_gen_xceiv_exit(void)
+{
+       platform_driver_unregister(&usb_phy_gen_xceiv_driver);
+}
+module_exit(usb_phy_gen_xceiv_exit);
+
+MODULE_ALIAS("platform:usb_phy_gen_xceiv");
+MODULE_AUTHOR("Texas Instruments Inc");
+MODULE_DESCRIPTION("NOP USB Transceiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/phy/phy-generic.h b/drivers/usb/phy/phy-generic.h
new file mode 100644 (file)
index 0000000..61687d5
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _PHY_GENERIC_H_
+#define _PHY_GENERIC_H_
+
+struct usb_phy_gen_xceiv {
+       struct usb_phy phy;
+       struct device *dev;
+       struct clk *clk;
+       struct regulator *vcc;
+       struct regulator *reset;
+};
+
+int usb_gen_phy_init(struct usb_phy *phy);
+void usb_gen_phy_shutdown(struct usb_phy *phy);
+
+int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
+               enum usb_phy_type type, u32 clk_rate, bool needs_vcc,
+               bool needs_reset);
+void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop);
+
+#endif
index 8443335c2ea0260414ea183fe69c809b5b328d64..b2f29c9aebbfdb15e9e9be8004f2e8d7bf5ed60d 100644 (file)
@@ -101,7 +101,7 @@ static void gpio_vbus_work(struct work_struct *work)
 {
        struct gpio_vbus_data *gpio_vbus =
                container_of(work, struct gpio_vbus_data, work.work);
-       struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data;
+       struct gpio_vbus_mach_info *pdata = dev_get_platdata(gpio_vbus->dev);
        int gpio, status, vbus;
 
        if (!gpio_vbus->phy.otg->gadget)
@@ -155,7 +155,7 @@ static void gpio_vbus_work(struct work_struct *work)
 static irqreturn_t gpio_vbus_irq(int irq, void *data)
 {
        struct platform_device *pdev = data;
-       struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
+       struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev);
        struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
        struct usb_otg *otg = gpio_vbus->phy.otg;
 
@@ -182,7 +182,7 @@ static int gpio_vbus_set_peripheral(struct usb_otg *otg,
 
        gpio_vbus = container_of(otg->phy, struct gpio_vbus_data, phy);
        pdev = to_platform_device(gpio_vbus->dev);
-       pdata = gpio_vbus->dev->platform_data;
+       pdata = dev_get_platdata(gpio_vbus->dev);
        gpio = pdata->gpio_pullup;
 
        if (!gadget) {
@@ -243,7 +243,7 @@ static int gpio_vbus_set_suspend(struct usb_phy *phy, int suspend)
 
 static int __init gpio_vbus_probe(struct platform_device *pdev)
 {
-       struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
+       struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev);
        struct gpio_vbus_data *gpio_vbus;
        struct resource *res;
        int err, gpio, irq;
@@ -352,7 +352,7 @@ err_gpio:
 static int __exit gpio_vbus_remove(struct platform_device *pdev)
 {
        struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
-       struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
+       struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev);
        int gpio = pdata->gpio_vbus;
 
        device_init_wakeup(&pdev->dev, 0);
index ae481afcb3ece1358ffd8244ad6df9cbccb93081..d3a5160e4cc794f6e1ead500822d20157b06abd1 100644 (file)
@@ -40,9 +40,7 @@
 
 #include <mach/usb.h>
 
-#ifndef        DEBUG
-#undef VERBOSE
-#endif
+#undef VERBOSE
 
 
 #define        DRIVER_VERSION  "24 August 2004"
@@ -387,7 +385,6 @@ static void b_idle(struct isp1301 *isp, const char *tag)
 static void
 dump_regs(struct isp1301 *isp, const char *label)
 {
-#ifdef DEBUG
        u8      ctrl = isp1301_get_u8(isp, ISP1301_OTG_CONTROL_1);
        u8      status = isp1301_get_u8(isp, ISP1301_OTG_STATUS);
        u8      src = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE);
@@ -396,7 +393,6 @@ dump_regs(struct isp1301 *isp, const char *label)
                omap_readl(OTG_CTRL), label, state_name(isp),
                ctrl, status, src);
        /* mode control and irq enables don't change much */
-#endif
 }
 
 /*-------------------------------------------------------------------------*/
index d08f33435e96e67f9b61389e176f624d64a2f95d..e9d4cd960ecdee0c1363066d8ebac955a7f7266a 100644 (file)
@@ -1419,7 +1419,7 @@ static int __init msm_otg_probe(struct platform_device *pdev)
        struct usb_phy *phy;
 
        dev_info(&pdev->dev, "msm_otg probe\n");
-       if (!pdev->dev.platform_data) {
+       if (!dev_get_platdata(&pdev->dev)) {
                dev_err(&pdev->dev, "No platform data given. Bailing out\n");
                return -ENODEV;
        }
@@ -1436,7 +1436,7 @@ static int __init msm_otg_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-       motg->pdata = pdev->dev.platform_data;
+       motg->pdata = dev_get_platdata(&pdev->dev);
        phy = &motg->phy;
        phy->dev = &pdev->dev;
 
index 1568ea63e3380766be04a0491f891e5471bf9ba9..d317903022bf17b650d20e0cda83306898d63e64 100644 (file)
@@ -82,7 +82,7 @@ static void mv_u3d_phy_write(void __iomem *base, u32 reg, u32 value)
        writel_relaxed(value, data);
 }
 
-void mv_u3d_phy_shutdown(struct usb_phy *phy)
+static void mv_u3d_phy_shutdown(struct usb_phy *phy)
 {
        struct mv_u3d_phy *mv_u3d_phy;
        void __iomem *base;
@@ -271,7 +271,7 @@ static int mv_u3d_phy_probe(struct platform_device *pdev)
        void __iomem    *phy_base;
        int     ret;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        if (!pdata) {
                dev_err(&pdev->dev, "%s: no platform data defined\n", __func__);
                return -EINVAL;
index 4a6b03c738765814adc2eefe6bbbdef6eba8bf0b..98f6ac6a78eac16e5d6eab91cc64e17daeae8316 100644 (file)
@@ -653,7 +653,7 @@ static struct attribute_group inputs_attr_group = {
        .attrs = inputs_attrs,
 };
 
-int mv_otg_remove(struct platform_device *pdev)
+static int mv_otg_remove(struct platform_device *pdev)
 {
        struct mv_otg *mvotg = platform_get_drvdata(pdev);
 
@@ -673,7 +673,7 @@ int mv_otg_remove(struct platform_device *pdev)
 
 static int mv_otg_probe(struct platform_device *pdev)
 {
-       struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
+       struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct mv_otg *mvotg;
        struct usb_otg *otg;
        struct resource *r;
@@ -893,7 +893,7 @@ static int mv_otg_resume(struct platform_device *pdev)
 
 static struct platform_driver mv_otg_driver = {
        .probe = mv_otg_probe,
-       .remove = __exit_p(mv_otg_remove),
+       .remove = mv_otg_remove,
        .driver = {
                   .owner = THIS_MODULE,
                   .name = driver_name,
index bd601c537c8d434a3e33a7aa59d88d583472244f..fdd33b44dbd31b929eb13a2c0bd138570ccebc37 100644 (file)
@@ -41,11 +41,14 @@ struct mxs_phy {
 
 #define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
 
-static void mxs_phy_hw_init(struct mxs_phy *mxs_phy)
+static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
 {
+       int ret;
        void __iomem *base = mxs_phy->phy.io_priv;
 
-       stmp_reset_block(base + HW_USBPHY_CTRL);
+       ret = stmp_reset_block(base + HW_USBPHY_CTRL);
+       if (ret)
+               return ret;
 
        /* Power up the PHY */
        writel(0, base + HW_USBPHY_PWD);
@@ -54,6 +57,8 @@ static void mxs_phy_hw_init(struct mxs_phy *mxs_phy)
        writel(BM_USBPHY_CTRL_ENUTMILEVEL2 |
               BM_USBPHY_CTRL_ENUTMILEVEL3,
               base + HW_USBPHY_CTRL_SET);
+
+       return 0;
 }
 
 static int mxs_phy_init(struct usb_phy *phy)
@@ -61,9 +66,7 @@ static int mxs_phy_init(struct usb_phy *phy)
        struct mxs_phy *mxs_phy = to_mxs_phy(phy);
 
        clk_prepare_enable(mxs_phy->clk);
-       mxs_phy_hw_init(mxs_phy);
-
-       return 0;
+       return mxs_phy_hw_init(mxs_phy);
 }
 
 static void mxs_phy_shutdown(struct usb_phy *phy)
diff --git a/drivers/usb/phy/phy-nop.c b/drivers/usb/phy/phy-nop.c
deleted file mode 100644 (file)
index 55445e5..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * drivers/usb/otg/nop-usb-xceiv.c
- *
- * NOP USB transceiver for all USB transceiver which are either built-in
- * into USB IP or which are mostly autonomous.
- *
- * Copyright (C) 2009 Texas Instruments Inc
- * Author: Ajay Kumar Gupta <ajay.gupta@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Current status:
- *     This provides a "nop" transceiver for PHYs which are
- *     autonomous such as isp1504, isp1707, etc.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/nop-usb-xceiv.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-#include <linux/regulator/consumer.h>
-#include <linux/of.h>
-
-struct nop_usb_xceiv {
-       struct usb_phy phy;
-       struct device *dev;
-       struct clk *clk;
-       struct regulator *vcc;
-       struct regulator *reset;
-};
-
-static struct platform_device *pd;
-
-void usb_nop_xceiv_register(void)
-{
-       if (pd)
-               return;
-       pd = platform_device_register_simple("nop_usb_xceiv", -1, NULL, 0);
-       if (!pd) {
-               printk(KERN_ERR "Unable to register usb nop transceiver\n");
-               return;
-       }
-}
-EXPORT_SYMBOL(usb_nop_xceiv_register);
-
-void usb_nop_xceiv_unregister(void)
-{
-       platform_device_unregister(pd);
-       pd = NULL;
-}
-EXPORT_SYMBOL(usb_nop_xceiv_unregister);
-
-static int nop_set_suspend(struct usb_phy *x, int suspend)
-{
-       return 0;
-}
-
-static int nop_init(struct usb_phy *phy)
-{
-       struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
-
-       if (!IS_ERR(nop->vcc)) {
-               if (regulator_enable(nop->vcc))
-                       dev_err(phy->dev, "Failed to enable power\n");
-       }
-
-       if (!IS_ERR(nop->clk))
-               clk_enable(nop->clk);
-
-       if (!IS_ERR(nop->reset)) {
-               /* De-assert RESET */
-               if (regulator_enable(nop->reset))
-                       dev_err(phy->dev, "Failed to de-assert reset\n");
-       }
-
-       return 0;
-}
-
-static void nop_shutdown(struct usb_phy *phy)
-{
-       struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
-
-       if (!IS_ERR(nop->reset)) {
-               /* Assert RESET */
-               if (regulator_disable(nop->reset))
-                       dev_err(phy->dev, "Failed to assert reset\n");
-       }
-
-       if (!IS_ERR(nop->clk))
-               clk_disable(nop->clk);
-
-       if (!IS_ERR(nop->vcc)) {
-               if (regulator_disable(nop->vcc))
-                       dev_err(phy->dev, "Failed to disable power\n");
-       }
-}
-
-static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
-{
-       if (!otg)
-               return -ENODEV;
-
-       if (!gadget) {
-               otg->gadget = NULL;
-               return -ENODEV;
-       }
-
-       otg->gadget = gadget;
-       otg->phy->state = OTG_STATE_B_IDLE;
-       return 0;
-}
-
-static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
-{
-       if (!otg)
-               return -ENODEV;
-
-       if (!host) {
-               otg->host = NULL;
-               return -ENODEV;
-       }
-
-       otg->host = host;
-       return 0;
-}
-
-static int nop_usb_xceiv_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct nop_usb_xceiv_platform_data *pdata = pdev->dev.platform_data;
-       struct nop_usb_xceiv    *nop;
-       enum usb_phy_type       type = USB_PHY_TYPE_USB2;
-       int err;
-       u32 clk_rate = 0;
-       bool needs_vcc = false;
-       bool needs_reset = false;
-
-       nop = devm_kzalloc(&pdev->dev, sizeof(*nop), GFP_KERNEL);
-       if (!nop)
-               return -ENOMEM;
-
-       nop->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*nop->phy.otg),
-                                                       GFP_KERNEL);
-       if (!nop->phy.otg)
-               return -ENOMEM;
-
-       if (dev->of_node) {
-               struct device_node *node = dev->of_node;
-
-               if (of_property_read_u32(node, "clock-frequency", &clk_rate))
-                       clk_rate = 0;
-
-               needs_vcc = of_property_read_bool(node, "vcc-supply");
-               needs_reset = of_property_read_bool(node, "reset-supply");
-
-       } else if (pdata) {
-               type = pdata->type;
-               clk_rate = pdata->clk_rate;
-               needs_vcc = pdata->needs_vcc;
-               needs_reset = pdata->needs_reset;
-       }
-
-       nop->clk = devm_clk_get(&pdev->dev, "main_clk");
-       if (IS_ERR(nop->clk)) {
-               dev_dbg(&pdev->dev, "Can't get phy clock: %ld\n",
-                                       PTR_ERR(nop->clk));
-       }
-
-       if (!IS_ERR(nop->clk) && clk_rate) {
-               err = clk_set_rate(nop->clk, clk_rate);
-               if (err) {
-                       dev_err(&pdev->dev, "Error setting clock rate\n");
-                       return err;
-               }
-       }
-
-       if (!IS_ERR(nop->clk)) {
-               err = clk_prepare(nop->clk);
-               if (err) {
-                       dev_err(&pdev->dev, "Error preparing clock\n");
-                       return err;
-               }
-       }
-
-       nop->vcc = devm_regulator_get(&pdev->dev, "vcc");
-       if (IS_ERR(nop->vcc)) {
-               dev_dbg(&pdev->dev, "Error getting vcc regulator: %ld\n",
-                                       PTR_ERR(nop->vcc));
-               if (needs_vcc)
-                       return -EPROBE_DEFER;
-       }
-
-       nop->reset = devm_regulator_get(&pdev->dev, "reset");
-       if (IS_ERR(nop->reset)) {
-               dev_dbg(&pdev->dev, "Error getting reset regulator: %ld\n",
-                                       PTR_ERR(nop->reset));
-               if (needs_reset)
-                       return -EPROBE_DEFER;
-       }
-
-       nop->dev                = &pdev->dev;
-       nop->phy.dev            = nop->dev;
-       nop->phy.label          = "nop-xceiv";
-       nop->phy.set_suspend    = nop_set_suspend;
-       nop->phy.init           = nop_init;
-       nop->phy.shutdown       = nop_shutdown;
-       nop->phy.state          = OTG_STATE_UNDEFINED;
-       nop->phy.type           = type;
-
-       nop->phy.otg->phy               = &nop->phy;
-       nop->phy.otg->set_host          = nop_set_host;
-       nop->phy.otg->set_peripheral    = nop_set_peripheral;
-
-       err = usb_add_phy_dev(&nop->phy);
-       if (err) {
-               dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
-                       err);
-               goto err_add;
-       }
-
-       platform_set_drvdata(pdev, nop);
-
-       ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
-
-       return 0;
-
-err_add:
-       if (!IS_ERR(nop->clk))
-               clk_unprepare(nop->clk);
-       return err;
-}
-
-static int nop_usb_xceiv_remove(struct platform_device *pdev)
-{
-       struct nop_usb_xceiv *nop = platform_get_drvdata(pdev);
-
-       if (!IS_ERR(nop->clk))
-               clk_unprepare(nop->clk);
-
-       usb_remove_phy(&nop->phy);
-
-       return 0;
-}
-
-static const struct of_device_id nop_xceiv_dt_ids[] = {
-       { .compatible = "usb-nop-xceiv" },
-       { }
-};
-
-MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids);
-
-static struct platform_driver nop_usb_xceiv_driver = {
-       .probe          = nop_usb_xceiv_probe,
-       .remove         = nop_usb_xceiv_remove,
-       .driver         = {
-               .name   = "nop_usb_xceiv",
-               .owner  = THIS_MODULE,
-               .of_match_table = nop_xceiv_dt_ids,
-       },
-};
-
-static int __init nop_usb_xceiv_init(void)
-{
-       return platform_driver_register(&nop_usb_xceiv_driver);
-}
-subsys_initcall(nop_usb_xceiv_init);
-
-static void __exit nop_usb_xceiv_exit(void)
-{
-       platform_driver_unregister(&nop_usb_xceiv_driver);
-}
-module_exit(nop_usb_xceiv_exit);
-
-MODULE_ALIAS("platform:nop_usb_xceiv");
-MODULE_AUTHOR("Texas Instruments Inc");
-MODULE_DESCRIPTION("NOP USB Transceiver driver");
-MODULE_LICENSE("GPL");
index 1419ceda9759c591f5036dddda8c5c673a2d7fa4..a4dda8e1256257104cdfdd3d54707af57361ed8f 100644 (file)
@@ -197,7 +197,8 @@ static int omap_control_usb_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct device_node *np = pdev->dev.of_node;
-       struct omap_control_usb_platform_data *pdata = pdev->dev.platform_data;
+       struct omap_control_usb_platform_data *pdata =
+                       dev_get_platdata(&pdev->dev);
 
        control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb),
                GFP_KERNEL);
index a2fb30bbb971c41f76fc8ad1eb358449f0117657..fc15694d3031bbf83b76e932914e44251280d491 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/delay.h>
 #include <linux/usb/omap_control_usb.h>
 
-#define        NUM_SYS_CLKS            6
 #define        PLL_STATUS              0x00000004
 #define        PLL_GO                  0x00000008
 #define        PLL_CONFIGURATION1      0x0000000C
  */
 # define PLL_IDLE_TIME  100;
 
-enum sys_clk_rate {
-       CLK_RATE_UNDEFINED = -1,
-       CLK_RATE_12MHZ,
-       CLK_RATE_16MHZ,
-       CLK_RATE_19MHZ,
-       CLK_RATE_20MHZ,
-       CLK_RATE_26MHZ,
-       CLK_RATE_38MHZ
+struct usb_dpll_map {
+       unsigned long rate;
+       struct usb_dpll_params params;
 };
 
-static struct usb_dpll_params omap_usb3_dpll_params[NUM_SYS_CLKS] = {
-       {1250, 5, 4, 20, 0},            /* 12 MHz */
-       {3125, 20, 4, 20, 0},           /* 16.8 MHz */
-       {1172, 8, 4, 20, 65537},        /* 19.2 MHz */
-       {1000, 7, 4, 10, 0},            /* 20 MHz */
-       {1250, 12, 4, 20, 0},           /* 26 MHz */
-       {3125, 47, 4, 20, 92843},       /* 38.4 MHz */
-
+static struct usb_dpll_map dpll_map[] = {
+       {12000000, {1250, 5, 4, 20, 0} },       /* 12 MHz */
+       {16800000, {3125, 20, 4, 20, 0} },      /* 16.8 MHz */
+       {19200000, {1172, 8, 4, 20, 65537} },   /* 19.2 MHz */
+       {20000000, {1000, 7, 4, 10, 0} },       /* 20 MHz */
+       {26000000, {1250, 12, 4, 20, 0} },      /* 26 MHz */
+       {38400000, {3125, 47, 4, 20, 92843} },  /* 38.4 MHz */
 };
 
+static struct usb_dpll_params *omap_usb3_get_dpll_params(unsigned long rate)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(dpll_map); i++) {
+               if (rate == dpll_map[i].rate)
+                       return &dpll_map[i].params;
+       }
+
+       return 0;
+}
+
 static int omap_usb3_suspend(struct usb_phy *x, int suspend)
 {
        struct omap_usb *phy = phy_to_omapusb(x);
@@ -116,26 +121,6 @@ static int omap_usb3_suspend(struct usb_phy *x, int suspend)
        return 0;
 }
 
-static inline enum sys_clk_rate __get_sys_clk_index(unsigned long rate)
-{
-       switch (rate) {
-       case 12000000:
-               return CLK_RATE_12MHZ;
-       case 16800000:
-               return CLK_RATE_16MHZ;
-       case 19200000:
-               return CLK_RATE_19MHZ;
-       case 20000000:
-               return CLK_RATE_20MHZ;
-       case 26000000:
-               return CLK_RATE_26MHZ;
-       case 38400000:
-               return CLK_RATE_38MHZ;
-       default:
-               return CLK_RATE_UNDEFINED;
-       }
-}
-
 static void omap_usb_dpll_relock(struct omap_usb *phy)
 {
        u32             val;
@@ -155,39 +140,39 @@ static int omap_usb_dpll_lock(struct omap_usb *phy)
 {
        u32                     val;
        unsigned long           rate;
-       enum sys_clk_rate       clk_index;
-
-       rate            = clk_get_rate(phy->sys_clk);
-       clk_index       = __get_sys_clk_index(rate);
+       struct usb_dpll_params *dpll_params;
 
-       if (clk_index == CLK_RATE_UNDEFINED) {
-               pr_err("dpll cannot be locked for sys clk freq:%luHz\n", rate);
+       rate = clk_get_rate(phy->sys_clk);
+       dpll_params = omap_usb3_get_dpll_params(rate);
+       if (!dpll_params) {
+               dev_err(phy->dev,
+                         "No DPLL configuration for %lu Hz SYS CLK\n", rate);
                return -EINVAL;
        }
 
        val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
        val &= ~PLL_REGN_MASK;
-       val |= omap_usb3_dpll_params[clk_index].n << PLL_REGN_SHIFT;
+       val |= dpll_params->n << PLL_REGN_SHIFT;
        omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
 
        val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
        val &= ~PLL_SELFREQDCO_MASK;
-       val |= omap_usb3_dpll_params[clk_index].freq << PLL_SELFREQDCO_SHIFT;
+       val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
        omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
 
        val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
        val &= ~PLL_REGM_MASK;
-       val |= omap_usb3_dpll_params[clk_index].m << PLL_REGM_SHIFT;
+       val |= dpll_params->m << PLL_REGM_SHIFT;
        omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
 
        val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4);
        val &= ~PLL_REGM_F_MASK;
-       val |= omap_usb3_dpll_params[clk_index].mf << PLL_REGM_F_SHIFT;
+       val |= dpll_params->mf << PLL_REGM_F_SHIFT;
        omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val);
 
        val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3);
        val &= ~PLL_SD_MASK;
-       val |= omap_usb3_dpll_params[clk_index].sd << PLL_SD_SHIFT;
+       val |= dpll_params->sd << PLL_SD_SHIFT;
        omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val);
 
        omap_usb_dpll_relock(phy);
@@ -198,8 +183,12 @@ static int omap_usb_dpll_lock(struct omap_usb *phy)
 static int omap_usb3_init(struct usb_phy *x)
 {
        struct omap_usb *phy = phy_to_omapusb(x);
+       int ret;
+
+       ret = omap_usb_dpll_lock(phy);
+       if (ret)
+               return ret;
 
-       omap_usb_dpll_lock(phy);
        omap_control_usb3_phy_power(phy->control_dev, 1);
 
        return 0;
index ae909408958dcb8a9b0efcc2866d19d0cff7571b..33265a5b2cdf8fdca0fc6ba0b7752a6a54ae9c4f 100644 (file)
@@ -83,7 +83,7 @@ static int rcar_usb_phy_init(struct usb_phy *phy)
 {
        struct rcar_usb_phy_priv *priv = usb_phy_to_priv(phy);
        struct device *dev = phy->dev;
-       struct rcar_phy_platform_data *pdata = dev->platform_data;
+       struct rcar_phy_platform_data *pdata = dev_get_platdata(dev);
        void __iomem *reg0 = priv->reg0;
        void __iomem *reg1 = priv->reg1;
        static const u8 ovcn_act[] = { OVC0_ACT, OVC1_ACT, OVC2_ACT };
@@ -184,17 +184,12 @@ static int rcar_usb_phy_probe(struct platform_device *pdev)
        void __iomem *reg0, *reg1 = NULL;
        int ret;
 
-       if (!pdev->dev.platform_data) {
+       if (!dev_get_platdata(&pdev->dev)) {
                dev_err(dev, "No platform data\n");
                return -EINVAL;
        }
 
        res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res0) {
-               dev_err(dev, "Not enough platform resources\n");
-               return -EINVAL;
-       }
-
        reg0 = devm_ioremap_resource(dev, res0);
        if (IS_ERR(reg0))
                return PTR_ERR(reg0);
index 758b86d0fcb386af39561d2d25e8ad9983c97fbf..ff70e4b19b9705cc4b69b1ea0de7b5c1ecf23959 100644 (file)
@@ -359,7 +359,7 @@ static int samsung_usb2phy_probe(struct platform_device *pdev)
 {
        struct samsung_usbphy *sphy;
        struct usb_otg *otg;
-       struct samsung_usbphy_data *pdata = pdev->dev.platform_data;
+       struct samsung_usbphy_data *pdata = dev_get_platdata(&pdev->dev);
        const struct samsung_usbphy_drvdata *drv_data;
        struct device *dev = &pdev->dev;
        struct resource *phy_mem;
index 300e0cf5e31f4fdb7ada4034237750293335589d..c6eb22213de607c3a5997b7a80a92d814eb371bd 100644 (file)
@@ -231,7 +231,7 @@ static void samsung_usb3phy_shutdown(struct usb_phy *phy)
 static int samsung_usb3phy_probe(struct platform_device *pdev)
 {
        struct samsung_usbphy *sphy;
-       struct samsung_usbphy_data *pdata = pdev->dev.platform_data;
+       struct samsung_usbphy_data *pdata = dev_get_platdata(&pdev->dev);
        struct device *dev = &pdev->dev;
        struct resource *phy_mem;
        void __iomem    *phy_base;
index cec0855ed24852f3d33b7a38970bf7dc4c13a728..3bfb3d1957c1c08c4bf20b8aa5879c79c9aa1a0c 100644 (file)
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/ulpi.h>
+#include <linux/usb/of.h>
 #include <asm/mach-types.h>
 #include <linux/usb/ehci_def.h>
 #include <linux/usb/tegra_usb_phy.h>
+#include <linux/regulator/consumer.h>
 
 #define ULPI_VIEWPORT          0x170
 
-/* PORTSC registers */
+/* PORTSC PTS/PHCD bits, Tegra20 only */
 #define TEGRA_USB_PORTSC1                              0x184
 #define TEGRA_USB_PORTSC1_PTS(x)                       (((x) & 0x3) << 30)
 #define TEGRA_USB_PORTSC1_PHCD                         (1 << 23)
 
+/* HOSTPC1 PTS/PHCD bits, Tegra30 and above */
+#define TEGRA_USB_HOSTPC1_DEVLC                0x1b4
+#define TEGRA_USB_HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29)
+#define TEGRA_USB_HOSTPC1_DEVLC_PHCD   (1 << 22)
+
 /* Bits of PORTSC1, which will get cleared by writing 1 into them */
 #define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
 
 
 #define UTMIP_XCVR_CFG0                0x808
 #define   UTMIP_XCVR_SETUP(x)                  (((x) & 0xf) << 0)
+#define   UTMIP_XCVR_SETUP_MSB(x)              ((((x) & 0x70) >> 4) << 22)
 #define   UTMIP_XCVR_LSRSLEW(x)                        (((x) & 0x3) << 8)
 #define   UTMIP_XCVR_LSFSLEW(x)                        (((x) & 0x3) << 10)
 #define   UTMIP_FORCE_PD_POWERDOWN             (1 << 14)
 #define   UTMIP_FORCE_PD2_POWERDOWN            (1 << 16)
 #define   UTMIP_FORCE_PDZI_POWERDOWN           (1 << 18)
-#define   UTMIP_XCVR_HSSLEW_MSB(x)             (((x) & 0x7f) << 25)
+#define   UTMIP_XCVR_LSBIAS_SEL                        (1 << 21)
+#define   UTMIP_XCVR_HSSLEW(x)                 (((x) & 0x3) << 4)
+#define   UTMIP_XCVR_HSSLEW_MSB(x)             ((((x) & 0x1fc) >> 2) << 25)
 
 #define UTMIP_BIAS_CFG0                0x80c
 #define   UTMIP_OTGPD                  (1 << 11)
 #define   UTMIP_BIASPD                 (1 << 10)
+#define   UTMIP_HSSQUELCH_LEVEL(x)     (((x) & 0x3) << 0)
+#define   UTMIP_HSDISCON_LEVEL(x)      (((x) & 0x3) << 2)
+#define   UTMIP_HSDISCON_LEVEL_MSB(x)  ((((x) & 0x4) >> 2) << 24)
 
 #define UTMIP_HSRX_CFG0                0x810
 #define   UTMIP_ELASTIC_LIMIT(x)       (((x) & 0x1f) << 10)
 #define UTMIP_BIAS_CFG1                0x83c
 #define   UTMIP_BIAS_PDTRK_COUNT(x)    (((x) & 0x1f) << 3)
 
+/* For Tegra30 and above only, the address is different in Tegra20 */
+#define USB_USBMODE            0x1f8
+#define   USB_USBMODE_MASK             (3 << 0)
+#define   USB_USBMODE_HOST             (3 << 0)
+#define   USB_USBMODE_DEVICE           (2 << 0)
+
 static DEFINE_SPINLOCK(utmip_pad_lock);
 static int utmip_pad_count;
 
@@ -184,36 +204,22 @@ static const struct tegra_xtal_freq tegra_freq_table[] = {
        },
 };
 
-static struct tegra_utmip_config utmip_default[] = {
-       [0] = {
-               .hssync_start_delay = 9,
-               .idle_wait_delay = 17,
-               .elastic_limit = 16,
-               .term_range_adj = 6,
-               .xcvr_setup = 9,
-               .xcvr_lsfslew = 1,
-               .xcvr_lsrslew = 1,
-       },
-       [2] = {
-               .hssync_start_delay = 9,
-               .idle_wait_delay = 17,
-               .elastic_limit = 16,
-               .term_range_adj = 6,
-               .xcvr_setup = 9,
-               .xcvr_lsfslew = 2,
-               .xcvr_lsrslew = 2,
-       },
-};
-
 static void set_pts(struct tegra_usb_phy *phy, u8 pts_val)
 {
        void __iomem *base = phy->regs;
        unsigned long val;
 
-       val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS;
-       val &= ~TEGRA_USB_PORTSC1_PTS(3);
-       val |= TEGRA_USB_PORTSC1_PTS(pts_val & 3);
-       writel(val, base + TEGRA_USB_PORTSC1);
+       if (phy->soc_config->has_hostpc) {
+               val = readl(base + TEGRA_USB_HOSTPC1_DEVLC);
+               val &= ~TEGRA_USB_HOSTPC1_DEVLC_PTS(~0);
+               val |= TEGRA_USB_HOSTPC1_DEVLC_PTS(pts_val);
+               writel(val, base + TEGRA_USB_HOSTPC1_DEVLC);
+       } else {
+               val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS;
+               val &= ~TEGRA_USB_PORTSC1_PTS(~0);
+               val |= TEGRA_USB_PORTSC1_PTS(pts_val);
+               writel(val, base + TEGRA_USB_PORTSC1);
+       }
 }
 
 static void set_phcd(struct tegra_usb_phy *phy, bool enable)
@@ -221,17 +227,26 @@ static void set_phcd(struct tegra_usb_phy *phy, bool enable)
        void __iomem *base = phy->regs;
        unsigned long val;
 
-       val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS;
-       if (enable)
-               val |= TEGRA_USB_PORTSC1_PHCD;
-       else
-               val &= ~TEGRA_USB_PORTSC1_PHCD;
-       writel(val, base + TEGRA_USB_PORTSC1);
+       if (phy->soc_config->has_hostpc) {
+               val = readl(base + TEGRA_USB_HOSTPC1_DEVLC);
+               if (enable)
+                       val |= TEGRA_USB_HOSTPC1_DEVLC_PHCD;
+               else
+                       val &= ~TEGRA_USB_HOSTPC1_DEVLC_PHCD;
+               writel(val, base + TEGRA_USB_HOSTPC1_DEVLC);
+       } else {
+               val = readl(base + TEGRA_USB_PORTSC1) & ~PORT_RWC_BITS;
+               if (enable)
+                       val |= TEGRA_USB_PORTSC1_PHCD;
+               else
+                       val &= ~TEGRA_USB_PORTSC1_PHCD;
+               writel(val, base + TEGRA_USB_PORTSC1);
+       }
 }
 
 static int utmip_pad_open(struct tegra_usb_phy *phy)
 {
-       phy->pad_clk = devm_clk_get(phy->dev, "utmi-pads");
+       phy->pad_clk = devm_clk_get(phy->u_phy.dev, "utmi-pads");
        if (IS_ERR(phy->pad_clk)) {
                pr_err("%s: can't get utmip pad clock\n", __func__);
                return PTR_ERR(phy->pad_clk);
@@ -244,6 +259,7 @@ static void utmip_pad_power_on(struct tegra_usb_phy *phy)
 {
        unsigned long val, flags;
        void __iomem *base = phy->pad_regs;
+       struct tegra_utmip_config *config = phy->config;
 
        clk_prepare_enable(phy->pad_clk);
 
@@ -252,6 +268,16 @@ static void utmip_pad_power_on(struct tegra_usb_phy *phy)
        if (utmip_pad_count++ == 0) {
                val = readl(base + UTMIP_BIAS_CFG0);
                val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
+
+               if (phy->soc_config->requires_extra_tuning_parameters) {
+                       val &= ~(UTMIP_HSSQUELCH_LEVEL(~0) |
+                               UTMIP_HSDISCON_LEVEL(~0) |
+                               UTMIP_HSDISCON_LEVEL_MSB(~0));
+
+                       val |= UTMIP_HSSQUELCH_LEVEL(config->hssquelch_level);
+                       val |= UTMIP_HSDISCON_LEVEL(config->hsdiscon_level);
+                       val |= UTMIP_HSDISCON_LEVEL_MSB(config->hsdiscon_level);
+               }
                writel(val, base + UTMIP_BIAS_CFG0);
        }
 
@@ -361,7 +387,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
        }
 
        val = readl(base + UTMIP_TX_CFG0);
-       val &= ~UTMIP_FS_PREABMLE_J;
+       val |= UTMIP_FS_PREABMLE_J;
        writel(val, base + UTMIP_TX_CFG0);
 
        val = readl(base + UTMIP_HSRX_CFG0);
@@ -384,34 +410,56 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
        val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE;
        writel(val, base + UTMIP_MISC_CFG0);
 
-       val = readl(base + UTMIP_MISC_CFG1);
-       val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | UTMIP_PLLU_STABLE_COUNT(~0));
-       val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) |
-               UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count);
-       writel(val, base + UTMIP_MISC_CFG1);
-
-       val = readl(base + UTMIP_PLL_CFG1);
-       val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | UTMIP_PLLU_ENABLE_DLY_COUNT(~0));
-       val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) |
-               UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
-       writel(val, base + UTMIP_PLL_CFG1);
+       if (!phy->soc_config->utmi_pll_config_in_car_module) {
+               val = readl(base + UTMIP_MISC_CFG1);
+               val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) |
+                       UTMIP_PLLU_STABLE_COUNT(~0));
+               val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) |
+                       UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count);
+               writel(val, base + UTMIP_MISC_CFG1);
+
+               val = readl(base + UTMIP_PLL_CFG1);
+               val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) |
+                       UTMIP_PLLU_ENABLE_DLY_COUNT(~0));
+               val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) |
+                       UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
+               writel(val, base + UTMIP_PLL_CFG1);
+       }
 
-       if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
+       if (phy->mode == USB_DR_MODE_PERIPHERAL) {
                val = readl(base + USB_SUSP_CTRL);
                val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
                writel(val, base + USB_SUSP_CTRL);
+
+               val = readl(base + UTMIP_BAT_CHRG_CFG0);
+               val &= ~UTMIP_PD_CHRG;
+               writel(val, base + UTMIP_BAT_CHRG_CFG0);
+       } else {
+               val = readl(base + UTMIP_BAT_CHRG_CFG0);
+               val |= UTMIP_PD_CHRG;
+               writel(val, base + UTMIP_BAT_CHRG_CFG0);
        }
 
        utmip_pad_power_on(phy);
 
        val = readl(base + UTMIP_XCVR_CFG0);
        val &= ~(UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
-                UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_SETUP(~0) |
-                UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0) |
-                UTMIP_XCVR_HSSLEW_MSB(~0));
-       val |= UTMIP_XCVR_SETUP(config->xcvr_setup);
+                UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_LSBIAS_SEL |
+                UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_SETUP_MSB(~0) |
+                UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0));
+
+       if (!config->xcvr_setup_use_fuses) {
+               val |= UTMIP_XCVR_SETUP(config->xcvr_setup);
+               val |= UTMIP_XCVR_SETUP_MSB(config->xcvr_setup);
+       }
        val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew);
        val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew);
+
+       if (phy->soc_config->requires_extra_tuning_parameters) {
+               val &= ~(UTMIP_XCVR_HSSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0));
+               val |= UTMIP_XCVR_HSSLEW(config->xcvr_hsslew);
+               val |= UTMIP_XCVR_HSSLEW_MSB(config->xcvr_hsslew);
+       }
        writel(val, base + UTMIP_XCVR_CFG0);
 
        val = readl(base + UTMIP_XCVR_CFG1);
@@ -420,23 +468,19 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
        val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj);
        writel(val, base + UTMIP_XCVR_CFG1);
 
-       val = readl(base + UTMIP_BAT_CHRG_CFG0);
-       val &= ~UTMIP_PD_CHRG;
-       writel(val, base + UTMIP_BAT_CHRG_CFG0);
-
        val = readl(base + UTMIP_BIAS_CFG1);
        val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
        val |= UTMIP_BIAS_PDTRK_COUNT(0x5);
        writel(val, base + UTMIP_BIAS_CFG1);
 
-       if (phy->is_legacy_phy) {
-               val = readl(base + UTMIP_SPARE_CFG0);
-               if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE)
-                       val &= ~FUSE_SETUP_SEL;
-               else
-                       val |= FUSE_SETUP_SEL;
-               writel(val, base + UTMIP_SPARE_CFG0);
-       } else {
+       val = readl(base + UTMIP_SPARE_CFG0);
+       if (config->xcvr_setup_use_fuses)
+               val |= FUSE_SETUP_SEL;
+       else
+               val &= ~FUSE_SETUP_SEL;
+       writel(val, base + UTMIP_SPARE_CFG0);
+
+       if (!phy->is_legacy_phy) {
                val = readl(base + USB_SUSP_CTRL);
                val |= UTMIP_PHY_ENABLE;
                writel(val, base + USB_SUSP_CTRL);
@@ -459,6 +503,16 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
 
        utmi_phy_clk_enable(phy);
 
+       if (phy->soc_config->requires_usbmode_setup) {
+               val = readl(base + USB_USBMODE);
+               val &= ~USB_USBMODE_MASK;
+               if (phy->mode == USB_DR_MODE_HOST)
+                       val |= USB_USBMODE_HOST;
+               else
+                       val |= USB_USBMODE_DEVICE;
+               writel(val, base + USB_USBMODE);
+       }
+
        if (!phy->is_legacy_phy)
                set_pts(phy, 0);
 
@@ -472,7 +526,7 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy)
 
        utmi_phy_clk_disable(phy);
 
-       if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
+       if (phy->mode == USB_DR_MODE_PERIPHERAL) {
                val = readl(base + USB_SUSP_CTRL);
                val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0);
                val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5);
@@ -560,13 +614,15 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
 
        ret = gpio_direction_output(phy->reset_gpio, 0);
        if (ret < 0) {
-               dev_err(phy->dev, "gpio %d not set to 0\n", phy->reset_gpio);
+               dev_err(phy->u_phy.dev, "gpio %d not set to 0\n",
+                       phy->reset_gpio);
                return ret;
        }
        msleep(5);
        ret = gpio_direction_output(phy->reset_gpio, 1);
        if (ret < 0) {
-               dev_err(phy->dev, "gpio %d not set to 1\n", phy->reset_gpio);
+               dev_err(phy->u_phy.dev, "gpio %d not set to 1\n",
+                       phy->reset_gpio);
                return ret;
        }
 
@@ -634,6 +690,9 @@ static void tegra_usb_phy_close(struct usb_phy *x)
 {
        struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
 
+       if (!IS_ERR(phy->vbus))
+               regulator_disable(phy->vbus);
+
        clk_disable_unprepare(phy->pll_u);
 }
 
@@ -666,29 +725,30 @@ static int ulpi_open(struct tegra_usb_phy *phy)
 {
        int err;
 
-       phy->clk = devm_clk_get(phy->dev, "ulpi-link");
+       phy->clk = devm_clk_get(phy->u_phy.dev, "ulpi-link");
        if (IS_ERR(phy->clk)) {
                pr_err("%s: can't get ulpi clock\n", __func__);
                return PTR_ERR(phy->clk);
        }
 
-       err = devm_gpio_request(phy->dev, phy->reset_gpio, "ulpi_phy_reset_b");
+       err = devm_gpio_request(phy->u_phy.dev, phy->reset_gpio,
+               "ulpi_phy_reset_b");
        if (err < 0) {
-               dev_err(phy->dev, "request failed for gpio: %d\n",
+               dev_err(phy->u_phy.dev, "request failed for gpio: %d\n",
                       phy->reset_gpio);
                return err;
        }
 
        err = gpio_direction_output(phy->reset_gpio, 0);
        if (err < 0) {
-               dev_err(phy->dev, "gpio %d direction not set to output\n",
+               dev_err(phy->u_phy.dev, "gpio %d direction not set to output\n",
                       phy->reset_gpio);
                return err;
        }
 
        phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
        if (!phy->ulpi) {
-               dev_err(phy->dev, "otg_ulpi_create returned NULL\n");
+               dev_err(phy->u_phy.dev, "otg_ulpi_create returned NULL\n");
                err = -ENOMEM;
                return err;
        }
@@ -703,14 +763,7 @@ static int tegra_usb_phy_init(struct tegra_usb_phy *phy)
        int i;
        int err;
 
-       if (!phy->is_ulpi_phy) {
-               if (phy->is_legacy_phy)
-                       phy->config = &utmip_default[0];
-               else
-                       phy->config = &utmip_default[2];
-       }
-
-       phy->pll_u = devm_clk_get(phy->dev, "pll_u");
+       phy->pll_u = devm_clk_get(phy->u_phy.dev, "pll_u");
        if (IS_ERR(phy->pll_u)) {
                pr_err("Can't get pll_u clock\n");
                return PTR_ERR(phy->pll_u);
@@ -733,6 +786,16 @@ static int tegra_usb_phy_init(struct tegra_usb_phy *phy)
                goto fail;
        }
 
+       if (!IS_ERR(phy->vbus)) {
+               err = regulator_enable(phy->vbus);
+               if (err) {
+                       dev_err(phy->u_phy.dev,
+                               "failed to enable usb vbus regulator: %d\n",
+                               err);
+                       goto fail;
+               }
+       }
+
        if (phy->is_ulpi_phy)
                err = ulpi_open(phy);
        else
@@ -784,11 +847,138 @@ void tegra_ehci_phy_restore_end(struct usb_phy *x)
 }
 EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end);
 
+static int read_utmi_param(struct platform_device *pdev, const char *param,
+                          u8 *dest)
+{
+       u32 value;
+       int err = of_property_read_u32(pdev->dev.of_node, param, &value);
+       *dest = (u8)value;
+       if (err < 0)
+               dev_err(&pdev->dev, "Failed to read USB UTMI parameter %s: %d\n",
+                       param, err);
+       return err;
+}
+
+static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy,
+                         struct platform_device *pdev)
+{
+       struct resource *res;
+       int err;
+       struct tegra_utmip_config *config;
+
+       tegra_phy->is_ulpi_phy = false;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res) {
+               dev_err(&pdev->dev, "Failed to get UTMI Pad regs\n");
+               return  -ENXIO;
+       }
+
+       tegra_phy->pad_regs = devm_ioremap(&pdev->dev, res->start,
+               resource_size(res));
+       if (!tegra_phy->regs) {
+               dev_err(&pdev->dev, "Failed to remap UTMI Pad regs\n");
+               return -ENOMEM;
+       }
+
+       tegra_phy->config = devm_kzalloc(&pdev->dev,
+               sizeof(*tegra_phy->config), GFP_KERNEL);
+       if (!tegra_phy->config) {
+               dev_err(&pdev->dev,
+                       "unable to allocate memory for USB UTMIP config\n");
+               return -ENOMEM;
+       }
+
+       config = tegra_phy->config;
+
+       err = read_utmi_param(pdev, "nvidia,hssync-start-delay",
+               &config->hssync_start_delay);
+       if (err < 0)
+               return err;
+
+       err = read_utmi_param(pdev, "nvidia,elastic-limit",
+               &config->elastic_limit);
+       if (err < 0)
+               return err;
+
+       err = read_utmi_param(pdev, "nvidia,idle-wait-delay",
+               &config->idle_wait_delay);
+       if (err < 0)
+               return err;
+
+       err = read_utmi_param(pdev, "nvidia,term-range-adj",
+               &config->term_range_adj);
+       if (err < 0)
+               return err;
+
+       err = read_utmi_param(pdev, "nvidia,xcvr-lsfslew",
+               &config->xcvr_lsfslew);
+       if (err < 0)
+               return err;
+
+       err = read_utmi_param(pdev, "nvidia,xcvr-lsrslew",
+               &config->xcvr_lsrslew);
+       if (err < 0)
+               return err;
+
+       if (tegra_phy->soc_config->requires_extra_tuning_parameters) {
+               err = read_utmi_param(pdev, "nvidia,xcvr-hsslew",
+                       &config->xcvr_hsslew);
+               if (err < 0)
+                       return err;
+
+               err = read_utmi_param(pdev, "nvidia,hssquelch-level",
+                       &config->hssquelch_level);
+               if (err < 0)
+                       return err;
+
+               err = read_utmi_param(pdev, "nvidia,hsdiscon-level",
+                       &config->hsdiscon_level);
+               if (err < 0)
+                       return err;
+       }
+
+       config->xcvr_setup_use_fuses = of_property_read_bool(
+               pdev->dev.of_node, "nvidia,xcvr-setup-use-fuses");
+
+       if (!config->xcvr_setup_use_fuses) {
+               err = read_utmi_param(pdev, "nvidia,xcvr-setup",
+                       &config->xcvr_setup);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static const struct tegra_phy_soc_config tegra20_soc_config = {
+       .utmi_pll_config_in_car_module = false,
+       .has_hostpc = false,
+       .requires_usbmode_setup = false,
+       .requires_extra_tuning_parameters = false,
+};
+
+static const struct tegra_phy_soc_config tegra30_soc_config = {
+       .utmi_pll_config_in_car_module = true,
+       .has_hostpc = true,
+       .requires_usbmode_setup = true,
+       .requires_extra_tuning_parameters = true,
+};
+
+static struct of_device_id tegra_usb_phy_id_table[] = {
+       { .compatible = "nvidia,tegra30-usb-phy", .data = &tegra30_soc_config },
+       { .compatible = "nvidia,tegra20-usb-phy", .data = &tegra20_soc_config },
+       { },
+};
+MODULE_DEVICE_TABLE(of, tegra_usb_phy_id_table);
+
 static int tegra_usb_phy_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *match;
        struct resource *res;
        struct tegra_usb_phy *tegra_phy = NULL;
        struct device_node *np = pdev->dev.of_node;
+       enum usb_phy_interface phy_type;
        int err;
 
        tegra_phy = devm_kzalloc(&pdev->dev, sizeof(*tegra_phy), GFP_KERNEL);
@@ -797,6 +987,13 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       match = of_match_device(tegra_usb_phy_id_table, &pdev->dev);
+       if (!match) {
+               dev_err(&pdev->dev, "Error: No device match found\n");
+               return -ENODEV;
+       }
+       tegra_phy->soc_config = match->data;
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_err(&pdev->dev, "Failed to get I/O memory\n");
@@ -813,23 +1010,15 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
        tegra_phy->is_legacy_phy =
                of_property_read_bool(np, "nvidia,has-legacy-mode");
 
-       err = of_property_match_string(np, "phy_type", "ulpi");
-       if (err < 0) {
-               tegra_phy->is_ulpi_phy = false;
-
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-               if (!res) {
-                       dev_err(&pdev->dev, "Failed to get UTMI Pad regs\n");
-                       return  -ENXIO;
-               }
+       phy_type = of_usb_get_phy_mode(np);
+       switch (phy_type) {
+       case USBPHY_INTERFACE_MODE_UTMI:
+               err = utmi_phy_probe(tegra_phy, pdev);
+               if (err < 0)
+                       return err;
+               break;
 
-               tegra_phy->pad_regs = devm_ioremap(&pdev->dev, res->start,
-                       resource_size(res));
-               if (!tegra_phy->regs) {
-                       dev_err(&pdev->dev, "Failed to remap UTMI Pad regs\n");
-                       return -ENOMEM;
-               }
-       } else {
+       case USBPHY_INTERFACE_MODE_ULPI:
                tegra_phy->is_ulpi_phy = true;
 
                tegra_phy->reset_gpio =
@@ -839,19 +1028,35 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
                                tegra_phy->reset_gpio);
                        return tegra_phy->reset_gpio;
                }
+               tegra_phy->config = NULL;
+               break;
+
+       default:
+               dev_err(&pdev->dev, "phy_type is invalid or unsupported\n");
+               return -EINVAL;
        }
 
-       err = of_property_match_string(np, "dr_mode", "otg");
-       if (err < 0) {
-               err = of_property_match_string(np, "dr_mode", "peripheral");
-               if (err < 0)
-                       tegra_phy->mode = TEGRA_USB_PHY_MODE_HOST;
-               else
-                       tegra_phy->mode = TEGRA_USB_PHY_MODE_DEVICE;
-       } else
-               tegra_phy->mode = TEGRA_USB_PHY_MODE_OTG;
+       if (of_find_property(np, "dr_mode", NULL))
+               tegra_phy->mode = of_usb_get_dr_mode(np);
+       else
+               tegra_phy->mode = USB_DR_MODE_HOST;
 
-       tegra_phy->dev = &pdev->dev;
+       if (tegra_phy->mode == USB_DR_MODE_UNKNOWN) {
+               dev_err(&pdev->dev, "dr_mode is invalid\n");
+               return -EINVAL;
+       }
+
+       /* On some boards, the VBUS regulator doesn't need to be controlled */
+       if (of_find_property(np, "vbus-supply", NULL)) {
+               tegra_phy->vbus = devm_regulator_get(&pdev->dev, "vbus");
+               if (IS_ERR(tegra_phy->vbus))
+                       return PTR_ERR(tegra_phy->vbus);
+       } else {
+               dev_notice(&pdev->dev, "no vbus regulator");
+               tegra_phy->vbus = ERR_PTR(-ENODEV);
+       }
+
+       tegra_phy->u_phy.dev = &pdev->dev;
        err = tegra_usb_phy_init(tegra_phy);
        if (err < 0)
                return err;
@@ -860,17 +1065,28 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
        tegra_phy->u_phy.set_suspend = tegra_usb_phy_suspend;
 
        dev_set_drvdata(&pdev->dev, tegra_phy);
+
+       err = usb_add_phy_dev(&tegra_phy->u_phy);
+       if (err < 0) {
+               tegra_usb_phy_close(&tegra_phy->u_phy);
+               return err;
+       }
+
        return 0;
 }
 
-static struct of_device_id tegra_usb_phy_id_table[] = {
-       { .compatible = "nvidia,tegra20-usb-phy", },
-       { },
-};
-MODULE_DEVICE_TABLE(of, tegra_usb_phy_id_table);
+static int tegra_usb_phy_remove(struct platform_device *pdev)
+{
+       struct tegra_usb_phy *tegra_phy = platform_get_drvdata(pdev);
+
+       usb_remove_phy(&tegra_phy->u_phy);
+
+       return 0;
+}
 
 static struct platform_driver tegra_usb_phy_driver = {
        .probe          = tegra_usb_phy_probe,
+       .remove         = tegra_usb_phy_remove,
        .driver         = {
                .name   = "tegra-phy",
                .owner  = THIS_MODULE,
@@ -879,29 +1095,5 @@ static struct platform_driver tegra_usb_phy_driver = {
 };
 module_platform_driver(tegra_usb_phy_driver);
 
-static int tegra_usb_phy_match(struct device *dev, void *data)
-{
-       struct tegra_usb_phy *tegra_phy = dev_get_drvdata(dev);
-       struct device_node *dn = data;
-
-       return (tegra_phy->dev->of_node == dn) ? 1 : 0;
-}
-
-struct usb_phy *tegra_usb_get_phy(struct device_node *dn)
-{
-       struct device *dev;
-       struct tegra_usb_phy *tegra_phy;
-
-       dev = driver_find_device(&tegra_usb_phy_driver.driver, NULL, dn,
-                                tegra_usb_phy_match);
-       if (!dev)
-               return ERR_PTR(-EPROBE_DEFER);
-
-       tegra_phy = dev_get_drvdata(dev);
-
-       return &tegra_phy->u_phy;
-}
-EXPORT_SYMBOL_GPL(tegra_usb_get_phy);
-
 MODULE_DESCRIPTION("Tegra USB PHY driver");
 MODULE_LICENSE("GPL v2");
index 8f78d2d40722ebb2412415a33d369666a3c9167a..90730c8762b8f8ee850a8a153ad757a4b5b3337e 100644 (file)
@@ -648,7 +648,7 @@ static int twl4030_set_host(struct usb_otg *otg, struct usb_bus *host)
 
 static int twl4030_usb_probe(struct platform_device *pdev)
 {
-       struct twl4030_usb_data *pdata = pdev->dev.platform_data;
+       struct twl4030_usb_data *pdata = dev_get_platdata(&pdev->dev);
        struct twl4030_usb      *twl;
        int                     status, err;
        struct usb_otg          *otg;
index 1753bd367e0ab7aa36b433fc3d77cac2a5b6b9e2..16dbc93826789dc22d0a2d955bc4c880cf9196c5 100644 (file)
@@ -324,7 +324,7 @@ static int twl6030_usb_probe(struct platform_device *pdev)
        int                     status, err;
        struct device_node      *np = pdev->dev.of_node;
        struct device           *dev = &pdev->dev;
-       struct twl4030_usb_data *pdata = dev->platform_data;
+       struct twl4030_usb_data *pdata = dev_get_platdata(dev);
 
        twl = devm_kzalloc(dev, sizeof *twl, GFP_KERNEL);
        if (!twl)
index cfd205036aba66303736baa5643f60e988eabb17..3b39757c13bc8961d95a321aacd8db9f230fab1e 100644 (file)
@@ -416,7 +416,7 @@ static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)
  */
 static int usbhs_probe(struct platform_device *pdev)
 {
-       struct renesas_usbhs_platform_info *info = pdev->dev.platform_data;
+       struct renesas_usbhs_platform_info *info = dev_get_platdata(&pdev->dev);
        struct renesas_usbhs_driver_callback *dfunc;
        struct usbhs_priv *priv;
        struct resource *res, *irq_res;
@@ -558,7 +558,7 @@ probe_end_pipe_exit:
 static int usbhs_remove(struct platform_device *pdev)
 {
        struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
-       struct renesas_usbhs_platform_info *info = pdev->dev.platform_data;
+       struct renesas_usbhs_platform_info *info = dev_get_platdata(&pdev->dev);
        struct renesas_usbhs_driver_callback *dfunc = &info->driver_callback;
 
        dev_dbg(&pdev->dev, "usb remove\n");
index 805940c373532bd4d548b5cf4d868ce4d75024ad..3385aeb5a3642d7a1e6b6be4de8b97d78a564a0b 100644 (file)
@@ -77,9 +77,9 @@ struct usbhsg_recip_handle {
                struct usbhsg_gpriv, mod)
 
 #define __usbhsg_for_each_uep(start, pos, g, i)        \
-       for (i = start, pos = (g)->uep + i;     \
-            i < (g)->uep_size;                 \
-            i++, pos = (g)->uep + i)
+       for ((i) = start;                                       \
+            ((i) < (g)->uep_size) && ((pos) = (g)->uep + (i)); \
+            (i)++)
 
 #define usbhsg_for_each_uep(pos, gpriv, i)     \
        __usbhsg_for_each_uep(1, pos, gpriv, i)
index b86815421c8d4b6bbf86a54f39bd0e83c82d8bda..e40f565004d04bd6941e71559dd70d9d331d0215 100644 (file)
@@ -111,9 +111,9 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host";
        container_of(usbhs_mod_get(priv, USBHS_HOST), struct usbhsh_hpriv, mod)
 
 #define __usbhsh_for_each_udev(start, pos, h, i)       \
-       for (i = start, pos = (h)->udev + i;            \
-            i < USBHSH_DEVICE_MAX;                     \
-            i++, pos = (h)->udev + i)
+       for ((i) = start;                                               \
+            ((i) < USBHSH_DEVICE_MAX) && ((pos) = (h)->udev + (i));    \
+            (i)++)
 
 #define usbhsh_for_each_udev(pos, hpriv, i)    \
        __usbhsh_for_each_udev(1, pos, hpriv, i)
index b476fde955bf0ca71c4fb952565506c4f6aecb17..3e5349879838c581e48db1661e5e66b318c742a0 100644 (file)
@@ -54,9 +54,9 @@ struct usbhs_pipe_info {
  * pipe list
  */
 #define __usbhs_for_each_pipe(start, pos, info, i)     \
-       for (i = start, pos = (info)->pipe + i;         \
-            i < (info)->size;                          \
-            i++, pos = (info)->pipe + i)
+       for ((i) = start;                                               \
+            ((i) < (info)->size) && ((pos) = (info)->pipe + (i));      \
+            (i)++)
 
 #define usbhs_for_each_pipe(pos, priv, i)                      \
        __usbhs_for_each_pipe(1, pos, &((priv)->pipe_info), i)
index 7eef9b33fde66c78405509adf6ca8b461f8045c7..c454bfa22a106184bbaee567e4f49fbad5d8d057 100644 (file)
@@ -51,6 +51,24 @@ config USB_SERIAL_GENERIC
          support" be compiled as a module for this driver to be used
          properly.
 
+config USB_SERIAL_SIMPLE
+       tristate "USB Serial Simple Driver"
+       help
+         Say Y here to use the USB serial "simple" driver.  This driver
+         handles a wide range of very simple devices, all in one
+         driver.  Specifically, it supports:
+               - Suunto ANT+ USB device.
+               - Fundamental Software dongle.
+               - HP4x calculators
+               - a number of Motoroloa phones
+               - Siemens USB/MPI adapter.
+               - ViVOtech ViVOpay USB device.
+               - Infineon Modem Flashloader USB interface
+               - ZIO Motherboard USB serial interface
+
+         To compile this driver as a module, choose M here: the module
+         will be called usb-serial-simple.
+
 config USB_SERIAL_AIRCABLE
        tristate "USB AIRcable Bluetooth Dongle Driver"
        help
@@ -158,14 +176,6 @@ config USB_SERIAL_FTDI_SIO
          To compile this driver as a module, choose M here: the
          module will be called ftdi_sio.
 
-config USB_SERIAL_FUNSOFT
-       tristate "USB Fundamental Software Dongle Driver"
-       ---help---
-         Say Y here if you want to use the Fundamental Software dongle.
-
-         To compile this driver as a module, choose M here: the
-         module will be called funsoft.
-
 config USB_SERIAL_VISOR
        tristate "USB Handspring Visor / Palm m50x / Sony Clie Driver"
        help
@@ -462,15 +472,6 @@ config USB_SERIAL_MOS7840
          To compile this driver as a module, choose M here: the
          module will be called mos7840.  If unsure, choose N.
 
-config USB_SERIAL_MOTOROLA
-       tristate "USB Motorola Phone modem driver"
-       ---help---
-         Say Y here if you want to use a Motorola phone with a USB
-         connector as a modem link.
-
-         To compile this driver as a module, choose M here: the
-         module will be called moto_modem.  If unsure, choose N.
-
 config USB_SERIAL_NAVMAN
        tristate "USB Navman GPS device"
        help
@@ -525,14 +526,6 @@ config USB_SERIAL_SPCP8X5
          To compile this driver as a module, choose M here: the
          module will be called spcp8x5.
 
-config USB_SERIAL_HP4X
-        tristate "USB HP4x Calculators support"
-        help
-          Say Y here if you want to use an Hewlett-Packard 4x Calculator.
-
-          To compile this driver as a module, choose M here: the
-          module will be called hp4x.
-
 config USB_SERIAL_SAFE
        tristate "USB Safe Serial (Encapsulated) Driver"
 
@@ -540,14 +533,6 @@ config USB_SERIAL_SAFE_PADDED
        bool "USB Secure Encapsulated Driver - Padded"
        depends on USB_SERIAL_SAFE
 
-config USB_SERIAL_SIEMENS_MPI
-       tristate "USB Siemens MPI driver"
-       help
-         Say M here if you want to use a Siemens USB/MPI adapter.
-
-         To compile this driver as a module, choose M here: the
-         module will be called siemens_mpi.
-
 config USB_SERIAL_SIERRAWIRELESS
        tristate "USB Sierra Wireless Driver"
        help
@@ -639,14 +624,6 @@ config USB_SERIAL_OPTICON
          To compile this driver as a module, choose M here: the
          module will be called opticon.
 
-config USB_SERIAL_VIVOPAY_SERIAL
-        tristate "USB ViVOpay serial interface driver"
-        help
-          Say Y here if you want to use a ViVOtech ViVOpay USB device.
-
-          To compile this driver as a module, choose M here: the
-          module will be called vivopay-serial.
-
 config USB_SERIAL_XSENS_MT
        tristate "Xsens motion tracker serial interface driver"
        help
@@ -659,14 +636,6 @@ config USB_SERIAL_XSENS_MT
          To compile this driver as a module, choose M here: the
          module will be called xsens_mt.
 
-config USB_SERIAL_ZIO
-       tristate "ZIO Motherboard USB serial interface driver"
-       help
-         Say Y here if you want to use ZIO Motherboard.
-
-         To compile this driver as a module, choose M here: the
-         module will be called zio.
-
 config USB_SERIAL_WISHBONE
        tristate "USB-Wishbone adapter interface driver"
        help
@@ -710,23 +679,6 @@ config USB_SERIAL_QT2
          To compile this driver as a module, choose M here: the
          module will be called quatech-serial.
 
-config USB_SERIAL_FLASHLOADER
-       tristate "Infineon Modem Flashloader USB interface driver"
-       help
-         Say Y here if you want to download Infineon Modem
-         via USB Flashloader serial driver.
-
-         To compile this driver as a module, choose M here: the
-         module will be called flashloader.
-
-config USB_SERIAL_SUUNTO
-       tristate "USB Suunto ANT+ driver"
-       help
-         Say Y here if you want to use the Suunto ANT+ USB device.
-
-         To compile this driver as a module, choose M here: the
-         module will be called suunto.
-
 config USB_SERIAL_DEBUG
        tristate "USB Debugging Device"
        help
index a14a870d993fe3bc1ea60001c9f1dcb6637c620a..42670f0b5bc0e0e85354cd758a9ed0adce655afe 100644 (file)
@@ -24,9 +24,7 @@ obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI)          += io_ti.o
 obj-$(CONFIG_USB_SERIAL_EMPEG)                 += empeg.o
 obj-$(CONFIG_USB_SERIAL_F81232)                        += f81232.o
 obj-$(CONFIG_USB_SERIAL_FTDI_SIO)              += ftdi_sio.o
-obj-$(CONFIG_USB_SERIAL_FUNSOFT)               += funsoft.o
 obj-$(CONFIG_USB_SERIAL_GARMIN)                        += garmin_gps.o
-obj-$(CONFIG_USB_SERIAL_HP4X)                  += hp4x.o
 obj-$(CONFIG_USB_SERIAL_IPAQ)                  += ipaq.o
 obj-$(CONFIG_USB_SERIAL_IPW)                   += ipw.o
 obj-$(CONFIG_USB_SERIAL_IR)                    += ir-usb.o
@@ -39,7 +37,6 @@ obj-$(CONFIG_USB_SERIAL_MCT_U232)             += mct_u232.o
 obj-$(CONFIG_USB_SERIAL_METRO)                 += metro-usb.o
 obj-$(CONFIG_USB_SERIAL_MOS7720)               += mos7720.o
 obj-$(CONFIG_USB_SERIAL_MOS7840)               += mos7840.o
-obj-$(CONFIG_USB_SERIAL_MOTOROLA)              += moto_modem.o
 obj-$(CONFIG_USB_SERIAL_NAVMAN)                        += navman.o
 obj-$(CONFIG_USB_SERIAL_OMNINET)               += omninet.o
 obj-$(CONFIG_USB_SERIAL_OPTICON)               += opticon.o
@@ -50,11 +47,10 @@ obj-$(CONFIG_USB_SERIAL_QCAUX)                      += qcaux.o
 obj-$(CONFIG_USB_SERIAL_QUALCOMM)              += qcserial.o
 obj-$(CONFIG_USB_SERIAL_QT2)                   += quatech2.o
 obj-$(CONFIG_USB_SERIAL_SAFE)                  += safe_serial.o
-obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI)           += siemens_mpi.o
 obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS)                += sierra.o
+obj-$(CONFIG_USB_SERIAL_SIMPLE)                        += usb-serial-simple.o
 obj-$(CONFIG_USB_SERIAL_SPCP8X5)               += spcp8x5.o
 obj-$(CONFIG_USB_SERIAL_SSU100)                        += ssu100.o
-obj-$(CONFIG_USB_SERIAL_SUUNTO)                        += suunto.o
 obj-$(CONFIG_USB_SERIAL_SYMBOL)                        += symbolserial.o
 obj-$(CONFIG_USB_SERIAL_WWAN)                  += usb_wwan.o
 obj-$(CONFIG_USB_SERIAL_TI)                    += ti_usb_3410_5052.o
@@ -62,8 +58,5 @@ obj-$(CONFIG_USB_SERIAL_VISOR)                        += visor.o
 obj-$(CONFIG_USB_SERIAL_WISHBONE)              += wishbone-serial.o
 obj-$(CONFIG_USB_SERIAL_WHITEHEAT)             += whiteheat.o
 obj-$(CONFIG_USB_SERIAL_XIRCOM)                        += keyspan_pda.o
-obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL)                += vivopay-serial.o
 obj-$(CONFIG_USB_SERIAL_XSENS_MT)              += xsens_mt.o
-obj-$(CONFIG_USB_SERIAL_ZIO)                   += zio.o
 obj-$(CONFIG_USB_SERIAL_ZTE)                   += zte_ev.o
-obj-$(CONFIG_USB_SERIAL_FLASHLOADER)           += flashloader.o
index afb50eab2049126fe73bbc13df6880f6324271b9..c69bb50d46635dfb2148f580739f99b46c5602dc 100644 (file)
@@ -151,11 +151,7 @@ static int usb_console_setup(struct console *co, char *options)
 
                /* only call the device specific open if this
                 * is the first time the port is opened */
-               if (serial->type->open)
-                       retval = serial->type->open(NULL, port);
-               else
-                       retval = usb_serial_generic_open(NULL, port);
-
+               retval = serial->type->open(NULL, port);
                if (retval) {
                        dev_err(&port->dev, "could not open USB console port\n");
                        goto fail;
@@ -210,10 +206,10 @@ static void usb_console_write(struct console *co,
        if (count == 0)
                return;
 
-       pr_debug("%s - minor %d, %d byte(s)\n", __func__, port->minor, count);
+       dev_dbg(&port->dev, "%s - %d byte(s)\n", __func__, count);
 
        if (!port->port.console) {
-               pr_debug("%s - port not opened\n", __func__);
+               dev_dbg(&port->dev, "%s - port not opened\n", __func__);
                return;
        }
 
@@ -230,21 +226,14 @@ static void usb_console_write(struct console *co,
                }
                /* pass on to the driver specific version of this function if
                   it is available */
-               if (serial->type->write)
-                       retval = serial->type->write(NULL, port, buf, i);
-               else
-                       retval = usb_serial_generic_write(NULL, port, buf, i);
-               pr_debug("%s - return value : %d\n", __func__, retval);
+               retval = serial->type->write(NULL, port, buf, i);
+               dev_dbg(&port->dev, "%s - write: %d\n", __func__, retval);
                if (lf) {
                        /* append CR after LF */
                        unsigned char cr = 13;
-                       if (serial->type->write)
-                               retval = serial->type->write(NULL,
-                                                               port, &cr, 1);
-                       else
-                               retval = usb_serial_generic_write(NULL,
-                                                               port, &cr, 1);
-                       pr_debug("%s - return value : %d\n", __func__, retval);
+                       retval = serial->type->write(NULL, port, &cr, 1);
+                       dev_dbg(&port->dev, "%s - write cr: %d\n",
+                                                       __func__, retval);
                }
                buf += i;
                count -= i;
index 0eae4ba3760ed87f633b0d449a833f1e5109107d..6987b535aa9896b1b8da93757412109adf0769d0 100644 (file)
@@ -670,9 +670,6 @@ static void cp210x_set_termios(struct tty_struct *tty,
        unsigned int bits;
        unsigned int modem_ctl[4];
 
-       if (!tty)
-               return;
-
        cflag = tty->termios.c_cflag;
        old_cflag = old_termios->c_cflag;
 
index e948dc02795d4ede34c7c132d9fb03a1142cf0f5..558605d646f34432766b736c9b3d430e8a32a871 100644 (file)
@@ -495,6 +495,8 @@ static int cypress_generic_port_probe(struct usb_serial_port *port)
        }
        usb_set_serial_port_data(port, priv);
 
+       port->port.drain_delay = 256;
+
        return 0;
 }
 
@@ -625,7 +627,7 @@ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port)
                                                        __func__, result);
                cypress_set_dead(port);
        }
-       port->port.drain_delay = 256;
+
        return result;
 } /* cypress_open */
 
index 75e85cbf9e8b38032c8d174963c7b831b515369a..639a18fb67e694e49d1ae6409fda5bb4f528a57f 100644 (file)
@@ -207,7 +207,6 @@ static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port)
                return result;
        }
 
-       port->port.drain_delay = 256;
        return 0;
 }
 
@@ -322,6 +321,8 @@ static int f81232_port_probe(struct usb_serial_port *port)
 
        usb_set_serial_port_data(port, priv);
 
+       port->port.drain_delay = 256;
+
        return 0;
 }
 
diff --git a/drivers/usb/serial/flashloader.c b/drivers/usb/serial/flashloader.c
deleted file mode 100644 (file)
index e6f5c10..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Infineon Flashloader driver
- *
- * Copyright (C) 2013 Wei Shuai <cpuwolf@gmail.com>
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License version
- *     2 as published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-#include <linux/uaccess.h>
-
-static const struct usb_device_id id_table[] = {
-       { USB_DEVICE(0x8087, 0x0716) },
-       { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver flashloader_device = {
-       .driver = {
-               .owner =        THIS_MODULE,
-               .name =         "flashloader",
-       },
-       .id_table =             id_table,
-       .num_ports =            1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-       &flashloader_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-MODULE_LICENSE("GPL");
index b65e657c641da56a1545be79e22a13a9fdad653c..dbf2f2818823c41637d0510bc0d8219b62d2c9b6 100644 (file)
@@ -51,8 +51,6 @@
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr, Johan Hovold <jhovold@gmail.com>"
 #define DRIVER_DESC "USB FTDI Serial Converters Driver"
 
-static __u16 vendor = FTDI_VID;
-static __u16 product;
 
 struct ftdi_private {
        enum ftdi_chip_type chip_type;
@@ -144,8 +142,8 @@ static struct ftdi_sio_quirk ftdi_8u2232c_quirk = {
 
 
 /*
- * Device ID not listed? Test via module params product/vendor or
- * /sys/bus/usb/ftdi_sio/new_id, then send patch/report!
+ * Device ID not listed? Test it using
+ * /sys/bus/usb-serial/drivers/ftdi_sio/new_id and send a patch or report.
  */
 static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) },
@@ -906,7 +904,6 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) },
        /* Crucible Devices */
        { USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) },
-       { },                                    /* Optional parameter entry */
        { }                                     /* Terminating entry */
 };
 
@@ -930,9 +927,6 @@ static const char *ftdi_chip_name[] = {
 #define FTDI_STATUS_B1_MASK    (FTDI_RS_BI)
 /* End TIOCMIWAIT */
 
-#define FTDI_IMPL_ASYNC_FLAGS = (ASYNC_SPD_HI | ASYNC_SPD_VHI \
- | ASYNC_SPD_CUST | ASYNC_SPD_SHI | ASYNC_SPD_WARP)
-
 /* function prototypes for a FTDI serial converter */
 static int  ftdi_sio_probe(struct usb_serial *serial,
                                        const struct usb_device_id *id);
@@ -999,10 +993,6 @@ static struct usb_serial_driver * const serial_drivers[] = {
 #define WDR_TIMEOUT 5000 /* default urb timeout */
 #define WDR_SHORT_TIMEOUT 1000 /* shorter urb timeout */
 
-/* High and low are for DTR, RTS etc etc */
-#define HIGH 1
-#define LOW 0
-
 /*
  * ***************************************************************************
  * Utility functions
@@ -1867,7 +1857,6 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
 
 static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
-       struct ktermios dummy;
        struct usb_device *dev = port->serial->dev;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
 
@@ -1883,10 +1872,8 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
           This is same behaviour as serial.c/rs_open() - Kuba */
 
        /* ftdi_set_termios  will send usb control messages */
-       if (tty) {
-               memset(&dummy, 0, sizeof(dummy));
-               ftdi_set_termios(tty, port, &dummy);
-       }
+       if (tty)
+               ftdi_set_termios(tty, port, NULL);
 
        return usb_serial_generic_open(tty, port);
 }
@@ -2215,7 +2202,7 @@ no_data_parity_stop_changes:
                        dev_err(ddev, "%s urb failed to set baudrate\n", __func__);
                mutex_unlock(&priv->cfg_lock);
                /* Ensure RTS and DTR are raised when baudrate changed from 0 */
-               if (!old_termios || (old_termios->c_cflag & CBAUD) == B0)
+               if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
                        set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
        }
 
@@ -2405,38 +2392,11 @@ static int ftdi_ioctl(struct tty_struct *tty,
        return -ENOIOCTLCMD;
 }
 
-static int __init ftdi_init(void)
-{
-       if (vendor > 0 && product > 0) {
-               /* Add user specified VID/PID to reserved element of table. */
-               int i;
-               for (i = 0; id_table_combined[i].idVendor; i++)
-                       ;
-               id_table_combined[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
-               id_table_combined[i].idVendor = vendor;
-               id_table_combined[i].idProduct = product;
-       }
-       return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table_combined);
-}
-
-static void __exit ftdi_exit(void)
-{
-       usb_serial_deregister_drivers(serial_drivers);
-}
-
-
-module_init(ftdi_init);
-module_exit(ftdi_exit);
+module_usb_serial_driver(serial_drivers, id_table_combined);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-module_param(vendor, ushort, 0);
-MODULE_PARM_DESC(vendor, "User specified vendor ID (default="
-               __MODULE_STRING(FTDI_VID)")");
-module_param(product, ushort, 0);
-MODULE_PARM_DESC(product, "User specified product ID");
-
 module_param(ndi_latency_timer, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ndi_latency_timer, "NDI device latency timer override");
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
deleted file mode 100644 (file)
index 9362f8f..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Funsoft Serial USB driver
- *
- * Copyright (C) 2006 Greg Kroah-Hartman <gregkh@suse.de>
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License version
- *     2 as published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-#include <linux/uaccess.h>
-
-static const struct usb_device_id id_table[] = {
-       { USB_DEVICE(0x1404, 0xcddc) },
-       { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver funsoft_device = {
-       .driver = {
-               .owner =        THIS_MODULE,
-               .name =         "funsoft",
-       },
-       .id_table =             id_table,
-       .num_ports =            1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-       &funsoft_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-
-MODULE_LICENSE("GPL");
index ba45170c78e5f601ec6b2c57f5f05600247803f4..1f31e6b4c2518f262a263bbefdddf5fda6ba9cb6 100644 (file)
@@ -460,12 +460,7 @@ static bool usb_serial_generic_msr_changed(struct tty_struct *tty,
        /*
         * Use tty-port initialised flag to detect all hangups including the
         * one generated at USB-device disconnect.
-        *
-        * FIXME: Remove hupping check once tty_port_hangup calls shutdown
-        *        (which clears the initialised flag) before wake up.
         */
-       if (test_bit(TTY_HUPPING, &tty->flags))
-               return true;
        if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
                return true;
 
@@ -496,12 +491,8 @@ int usb_serial_generic_tiocmiwait(struct tty_struct *tty, unsigned long arg)
 
        ret = wait_event_interruptible(port->port.delta_msr_wait,
                        usb_serial_generic_msr_changed(tty, arg, &cnow));
-       if (!ret) {
-               if (test_bit(TTY_HUPPING, &tty->flags))
-                       ret = -EIO;
-               if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
-                       ret = -EIO;
-       }
+       if (!ret && !test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+               ret = -EIO;
 
        return ret;
 }
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
deleted file mode 100644 (file)
index 2cba60d..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * HP4x Calculators Serial USB driver
- *
- * Copyright (C) 2005 Arthur Huillet (ahuillet@users.sf.net)
- * Copyright (C) 2001-2005 Greg Kroah-Hartman (greg@kroah.com)
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- *
- * See Documentation/usb/usb-serial.txt for more information on using this
- * driver
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-#define DRIVER_DESC "HP4x (48/49) Generic Serial driver"
-
-#define HP_VENDOR_ID 0x03f0
-#define HP49GP_PRODUCT_ID 0x0121
-
-static const struct usb_device_id id_table[] = {
-       { USB_DEVICE(HP_VENDOR_ID, HP49GP_PRODUCT_ID) },
-       { }                                     /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver hp49gp_device = {
-       .driver = {
-               .owner =        THIS_MODULE,
-               .name =         "hp4X",
-       },
-       .id_table =             id_table,
-       .num_ports =            1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-       &hp49gp_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
index dc2803b5eb09c35fa25c75fd376474e42a327b03..c91481d74a144fd2ae2810a2f778b30a63e78310 100644 (file)
@@ -56,9 +56,7 @@
 
 #define MAX_NAME_LEN           64
 
-#define CHASE_TIMEOUT          (5*HZ)          /* 5 seconds */
 #define OPEN_TIMEOUT           (5*HZ)          /* 5 seconds */
-#define COMMAND_TIMEOUT                (5*HZ)          /* 5 seconds */
 
 /* receive port state */
 enum RXSTATE {
index 60054e72b75ba1fc015a7d6fb778b02f104aae9d..9c18f5985c8dbb73c0e4ba1b7eac8f8630eae53e 100644 (file)
@@ -64,8 +64,6 @@
 
 #define EDGE_CLOSING_WAIT      4000    /* in .01 sec */
 
-#define EDGE_OUT_BUF_SIZE      1024
-
 
 /* Product information read from the Edgeport */
 struct product_info {
@@ -93,7 +91,6 @@ struct edgeport_port {
        spinlock_t ep_lock;
        int ep_read_urb_state;
        int ep_write_urb_in_use;
-       struct kfifo write_fifo;
 };
 
 struct edgeport_serial {
@@ -1732,22 +1729,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
                return -ENODEV;
 
        port_number = port->port_number;
-       switch (port_number) {
-       case 0:
-               edge_port->uart_base = UMPMEM_BASE_UART1;
-               edge_port->dma_address = UMPD_OEDB1_ADDRESS;
-               break;
-       case 1:
-               edge_port->uart_base = UMPMEM_BASE_UART2;
-               edge_port->dma_address = UMPD_OEDB2_ADDRESS;
-               break;
-       default:
-               dev_err(&port->dev, "Unknown port number!!!\n");
-               return -ENODEV;
-       }
-
-       dev_dbg(&port->dev, "%s - port_number = %d, uart_base = %04x, dma_address = %04x\n",
-               __func__, port_number, edge_port->uart_base, edge_port->dma_address);
 
        dev = port->serial->dev;
 
@@ -1872,8 +1853,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
 
        ++edge_serial->num_ports_open;
 
-       port->port.drain_delay = 1;
-
        goto release_es_lock;
 
 unlink_int_urb:
@@ -1905,7 +1884,7 @@ static void edge_close(struct usb_serial_port *port)
        usb_kill_urb(port->write_urb);
        edge_port->ep_write_urb_in_use = 0;
        spin_lock_irqsave(&edge_port->ep_lock, flags);
-       kfifo_reset_out(&edge_port->write_fifo);
+       kfifo_reset_out(&port->write_fifo);
        spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 
        dev_dbg(&port->dev, "%s - send umpc_close_port\n", __func__);
@@ -1939,7 +1918,7 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port,
        if (edge_port->close_pending == 1)
                return -ENODEV;
 
-       count = kfifo_in_locked(&edge_port->write_fifo, data, count,
+       count = kfifo_in_locked(&port->write_fifo, data, count,
                                                        &edge_port->ep_lock);
        edge_send(port, tty);
 
@@ -1959,7 +1938,7 @@ static void edge_send(struct usb_serial_port *port, struct tty_struct *tty)
                return;
        }
 
-       count = kfifo_out(&edge_port->write_fifo,
+       count = kfifo_out(&port->write_fifo,
                                port->write_urb->transfer_buffer,
                                port->bulk_out_size);
 
@@ -2007,7 +1986,7 @@ static int edge_write_room(struct tty_struct *tty)
                return 0;
 
        spin_lock_irqsave(&edge_port->ep_lock, flags);
-       room = kfifo_avail(&edge_port->write_fifo);
+       room = kfifo_avail(&port->write_fifo);
        spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 
        dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
@@ -2024,7 +2003,7 @@ static int edge_chars_in_buffer(struct tty_struct *tty)
                return 0;
 
        spin_lock_irqsave(&edge_port->ep_lock, flags);
-       chars = kfifo_len(&edge_port->write_fifo);
+       chars = kfifo_len(&port->write_fifo);
        spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 
        dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
@@ -2451,30 +2430,45 @@ static int edge_port_probe(struct usb_serial_port *port)
        if (!edge_port)
                return -ENOMEM;
 
-       ret = kfifo_alloc(&edge_port->write_fifo, EDGE_OUT_BUF_SIZE,
-                                                               GFP_KERNEL);
-       if (ret) {
-               kfree(edge_port);
-               return -ENOMEM;
-       }
-
        spin_lock_init(&edge_port->ep_lock);
        edge_port->port = port;
        edge_port->edge_serial = usb_get_serial_data(port->serial);
        edge_port->bUartMode = default_uart_mode;
 
+       switch (port->port_number) {
+       case 0:
+               edge_port->uart_base = UMPMEM_BASE_UART1;
+               edge_port->dma_address = UMPD_OEDB1_ADDRESS;
+               break;
+       case 1:
+               edge_port->uart_base = UMPMEM_BASE_UART2;
+               edge_port->dma_address = UMPD_OEDB2_ADDRESS;
+               break;
+       default:
+               dev_err(&port->dev, "unknown port number\n");
+               ret = -ENODEV;
+               goto err;
+       }
+
+       dev_dbg(&port->dev,
+               "%s - port_number = %d, uart_base = %04x, dma_address = %04x\n",
+               __func__, port->port_number, edge_port->uart_base,
+               edge_port->dma_address);
+
        usb_set_serial_port_data(port, edge_port);
 
        ret = edge_create_sysfs_attrs(port);
-       if (ret) {
-               kfifo_free(&edge_port->write_fifo);
-               kfree(edge_port);
-               return ret;
-       }
+       if (ret)
+               goto err;
 
        port->port.closing_wait = msecs_to_jiffies(closing_wait * 10);
+       port->port.drain_delay = 1;
 
        return 0;
+err:
+       kfree(edge_port);
+
+       return ret;
 }
 
 static int edge_port_remove(struct usb_serial_port *port)
@@ -2483,7 +2477,6 @@ static int edge_port_remove(struct usb_serial_port *port)
 
        edge_port = usb_get_serial_port_data(port);
        edge_remove_sysfs_attrs(port);
-       kfifo_free(&edge_port->write_fifo);
        kfree(edge_port);
 
        return 0;
index 58c17fdc85eb77ea40718e7791475d341d34d0d8..d6960aebe246f24b623132c1c2eeca5f6484832e 100644 (file)
 #define INSTAT_BUFLEN  32
 #define GLOCONT_BUFLEN 64
 #define INDAT49W_BUFLEN        512
+#define IN_BUFLEN      64
+#define OUT_BUFLEN     64
+#define INACK_BUFLEN   1
+#define OUTCONT_BUFLEN 64
 
        /* Per device and per port private data */
 struct keyspan_serial_private {
        const struct keyspan_device_details     *device_details;
 
        struct urb      *instat_urb;
-       char            instat_buf[INSTAT_BUFLEN];
+       char            *instat_buf;
 
        /* added to support 49wg, where data from all 4 ports comes in
           on 1 EP and high-speed supported */
        struct urb      *indat_urb;
-       char            indat_buf[INDAT49W_BUFLEN];
+       char            *indat_buf;
 
        /* XXX this one probably will need a lock */
        struct urb      *glocont_urb;
-       char            glocont_buf[GLOCONT_BUFLEN];
-       char            ctrl_buf[8];    /* for EP0 control message */
+       char            *glocont_buf;
+       char            *ctrl_buf;      /* for EP0 control message */
 };
 
 struct keyspan_port_private {
@@ -81,18 +85,18 @@ struct keyspan_port_private {
 
        /* Input endpoints and buffer for this port */
        struct urb      *in_urbs[2];
-       char            in_buffer[2][64];
+       char            *in_buffer[2];
        /* Output endpoints and buffer for this port */
        struct urb      *out_urbs[2];
-       char            out_buffer[2][64];
+       char            *out_buffer[2];
 
        /* Input ack endpoint */
        struct urb      *inack_urb;
-       char            inack_buffer[1];
+       char            *inack_buffer;
 
        /* Output control endpoint */
        struct urb      *outcont_urb;
-       char            outcont_buffer[64];
+       char            *outcont_buffer;
 
        /* Settings for the port */
        int             baud;
@@ -2313,6 +2317,22 @@ static int keyspan_startup(struct usb_serial *serial)
                return -ENOMEM;
        }
 
+       s_priv->instat_buf = kzalloc(INSTAT_BUFLEN, GFP_KERNEL);
+       if (!s_priv->instat_buf)
+               goto err_instat_buf;
+
+       s_priv->indat_buf = kzalloc(INDAT49W_BUFLEN, GFP_KERNEL);
+       if (!s_priv->indat_buf)
+               goto err_indat_buf;
+
+       s_priv->glocont_buf = kzalloc(GLOCONT_BUFLEN, GFP_KERNEL);
+       if (!s_priv->glocont_buf)
+               goto err_glocont_buf;
+
+       s_priv->ctrl_buf = kzalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+       if (!s_priv->ctrl_buf)
+               goto err_ctrl_buf;
+
        s_priv->device_details = d_details;
        usb_set_serial_data(serial, s_priv);
 
@@ -2330,6 +2350,17 @@ static int keyspan_startup(struct usb_serial *serial)
        }
 
        return 0;
+
+err_ctrl_buf:
+       kfree(s_priv->glocont_buf);
+err_glocont_buf:
+       kfree(s_priv->indat_buf);
+err_indat_buf:
+       kfree(s_priv->instat_buf);
+err_instat_buf:
+       kfree(s_priv);
+
+       return -ENOMEM;
 }
 
 static void keyspan_disconnect(struct usb_serial *serial)
@@ -2353,6 +2384,11 @@ static void keyspan_release(struct usb_serial *serial)
        usb_free_urb(s_priv->indat_urb);
        usb_free_urb(s_priv->glocont_urb);
 
+       kfree(s_priv->ctrl_buf);
+       kfree(s_priv->glocont_buf);
+       kfree(s_priv->indat_buf);
+       kfree(s_priv->instat_buf);
+
        kfree(s_priv);
 }
 
@@ -2374,6 +2410,26 @@ static int keyspan_port_probe(struct usb_serial_port *port)
        if (!p_priv)
                return -ENOMEM;
 
+       for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) {
+               p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL);
+               if (!p_priv->in_buffer[i])
+                       goto err_in_buffer;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) {
+               p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL);
+               if (!p_priv->out_buffer[i])
+                       goto err_out_buffer;
+       }
+
+       p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL);
+       if (!p_priv->inack_buffer)
+               goto err_inack_buffer;
+
+       p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL);
+       if (!p_priv->outcont_buffer)
+               goto err_outcont_buffer;
+
        p_priv->device_details = d_details;
 
        /* Setup values for the various callback routines */
@@ -2386,7 +2442,8 @@ static int keyspan_port_probe(struct usb_serial_port *port)
        for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) {
                p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp,
                                                USB_DIR_IN, port,
-                                               p_priv->in_buffer[i], 64,
+                                               p_priv->in_buffer[i],
+                                               IN_BUFLEN,
                                                cback->indat_callback);
        }
        /* outdat endpoints also have flip */
@@ -2394,25 +2451,41 @@ static int keyspan_port_probe(struct usb_serial_port *port)
        for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) {
                p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp,
                                                USB_DIR_OUT, port,
-                                               p_priv->out_buffer[i], 64,
+                                               p_priv->out_buffer[i],
+                                               OUT_BUFLEN,
                                                cback->outdat_callback);
        }
        /* inack endpoint */
        p_priv->inack_urb = keyspan_setup_urb(serial,
                                        d_details->inack_endpoints[port_num],
                                        USB_DIR_IN, port,
-                                       p_priv->inack_buffer, 1,
+                                       p_priv->inack_buffer,
+                                       INACK_BUFLEN,
                                        cback->inack_callback);
        /* outcont endpoint */
        p_priv->outcont_urb = keyspan_setup_urb(serial,
                                        d_details->outcont_endpoints[port_num],
                                        USB_DIR_OUT, port,
-                                       p_priv->outcont_buffer, 64,
+                                       p_priv->outcont_buffer,
+                                       OUTCONT_BUFLEN,
                                         cback->outcont_callback);
 
        usb_set_serial_port_data(port, p_priv);
 
        return 0;
+
+err_outcont_buffer:
+       kfree(p_priv->inack_buffer);
+err_inack_buffer:
+       for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
+               kfree(p_priv->out_buffer[i]);
+err_out_buffer:
+       for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
+               kfree(p_priv->in_buffer[i]);
+err_in_buffer:
+       kfree(p_priv);
+
+       return -ENOMEM;
 }
 
 static int keyspan_port_remove(struct usb_serial_port *port)
@@ -2436,6 +2509,13 @@ static int keyspan_port_remove(struct usb_serial_port *port)
                usb_free_urb(p_priv->out_urbs[i]);
        }
 
+       kfree(p_priv->outcont_buffer);
+       kfree(p_priv->inack_buffer);
+       for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
+               kfree(p_priv->out_buffer[i]);
+       for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
+               kfree(p_priv->in_buffer[i]);
+
        kfree(p_priv);
 
        return 0;
index 3bac4693c03829c9d5ca23d280e8c9b580548e66..fdf953539c62b4943a5ef1c6f93eab52cd53e463 100644 (file)
@@ -221,7 +221,6 @@ struct moschip_port {
        __u8 shadowMCR;         /* last MCR value received */
        char open;
        char open_ports;
-       wait_queue_head_t wait_chase;   /* for handling sleeping while waiting for chase to finish */
        struct usb_serial_port *port;   /* loop back to the owner of this object */
 
        /* Offsets */
@@ -1100,9 +1099,6 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
                mos7840_port->read_urb_busy = false;
        }
 
-       /* initialize our wait queues */
-       init_waitqueue_head(&mos7840_port->wait_chase);
-
        /* initialize our port settings */
        /* Must set to enable ints! */
        mos7840_port->shadowMCR = MCR_MASTER_IE;
@@ -1228,47 +1224,6 @@ static void mos7840_close(struct usb_serial_port *port)
        mos7840_port->open = 0;
 }
 
-/************************************************************************
- *
- * mos7840_block_until_chase_response
- *
- *     This function will block the close until one of the following:
- *             1. Response to our Chase comes from mos7840
- *             2. A timeout of 10 seconds without activity has expired
- *                (1K of mos7840 data @ 2400 baud ==> 4 sec to empty)
- *
- ************************************************************************/
-
-static void mos7840_block_until_chase_response(struct tty_struct *tty,
-                                       struct moschip_port *mos7840_port)
-{
-       int timeout = msecs_to_jiffies(1000);
-       int wait = 10;
-       int count;
-
-       while (1) {
-               count = mos7840_chars_in_buffer(tty);
-
-               /* Check for Buffer status */
-               if (count <= 0)
-                       return;
-
-               /* Block the thread for a while */
-               interruptible_sleep_on_timeout(&mos7840_port->wait_chase,
-                                              timeout);
-               /* No activity.. count down section */
-               wait--;
-               if (wait == 0) {
-                       dev_dbg(&mos7840_port->port->dev, "%s - TIMEOUT\n", __func__);
-                       return;
-               } else {
-                       /* Reset timeout value back to seconds */
-                       wait = 10;
-               }
-       }
-
-}
-
 /*****************************************************************************
  * mos7840_break
  *     this function sends a break to the port
@@ -1292,9 +1247,6 @@ static void mos7840_break(struct tty_struct *tty, int break_state)
        if (mos7840_port == NULL)
                return;
 
-       /* flush and block until tx is empty */
-       mos7840_block_until_chase_response(tty, mos7840_port);
-
        if (break_state == -1)
                data = mos7840_port->shadowLCR | LCR_SET_BREAK;
        else
diff --git a/drivers/usb/serial/moto_modem.c b/drivers/usb/serial/moto_modem.c
deleted file mode 100644 (file)
index c5ff6c7..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Motorola USB Phone driver
- *
- * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- *
- * {sigh}
- * Motorola should be using the CDC ACM USB spec, but instead
- * they try to just "do their own thing"...  This driver should handle a
- * few phones in which a basic "dumb serial connection" is needed to be
- * able to get a connection through to them.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-static const struct usb_device_id id_table[] = {
-       { USB_DEVICE(0x05c6, 0x3197) }, /* unknown Motorola phone */
-       { USB_DEVICE(0x0c44, 0x0022) }, /* unknown Mororola phone */
-       { USB_DEVICE(0x22b8, 0x2a64) }, /* Motorola KRZR K1m */
-       { USB_DEVICE(0x22b8, 0x2c84) }, /* Motorola VE240 phone */
-       { USB_DEVICE(0x22b8, 0x2c64) }, /* Motorola V950 phone */
-       { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver moto_device = {
-       .driver = {
-               .owner =        THIS_MODULE,
-               .name =         "moto-modem",
-       },
-       .id_table =             id_table,
-       .num_ports =            1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-       &moto_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-MODULE_LICENSE("GPL");
index 7e3e0782e51fe48ccb91e3e9e28eb42a380a0932..a2080ac7b7e5d696d89bee64f6b2ab72af1add3a 100644 (file)
@@ -343,6 +343,8 @@ static int oti6858_port_probe(struct usb_serial_port *port)
 
        usb_set_serial_port_data(port, priv);
 
+       port->port.drain_delay = 256;   /* FIXME: check the FIFO length */
+
        return 0;
 }
 
@@ -411,9 +413,6 @@ static void oti6858_set_termios(struct tty_struct *tty,
        __le16 divisor;
        int br;
 
-       if (!tty)
-               return;
-
        cflag = tty->termios.c_cflag;
 
        spin_lock_irqsave(&priv->lock, flags);
@@ -509,7 +508,6 @@ static void oti6858_set_termios(struct tty_struct *tty,
 static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
        struct oti6858_private *priv = usb_get_serial_port_data(port);
-       struct ktermios tmp_termios;
        struct usb_serial *serial = port->serial;
        struct oti6858_control_pkt *buf;
        unsigned long flags;
@@ -560,8 +558,8 @@ static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port)
 
        /* setup termios */
        if (tty)
-               oti6858_set_termios(tty, port, &tmp_termios);
-       port->port.drain_delay = 256;   /* FIXME: check the FIFO length */
+               oti6858_set_termios(tty, port, NULL);
+
        return 0;
 }
 
index cb6bbed374f26ffd25b69442bc8fcd9356b8889d..e7a84f0f517969fec4bbb59ac270eeb97fbf22d3 100644 (file)
@@ -4,6 +4,11 @@
  * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com)
  * Copyright (C) 2003 IBM Corp.
  *
+ * Copyright (C) 2009, 2013 Frank Schäfer <fschaefer.oss@googlemail.com>
+ *  - fixes, improvements and documentation for the baud rate encoding methods
+ * Copyright (C) 2013 Reinhard Max <max@suse.de>
+ *  - fixes and improvements for the divisor based baud rate encoding method
+ *
  * Original driver for 2.2.x by anonymous
  *
  *     This program is free software; you can redistribute it and/or
@@ -29,6 +34,7 @@
 #include <linux/uaccess.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
+#include <asm/unaligned.h>
 #include "pl2303.h"
 
 /*
@@ -128,10 +134,17 @@ MODULE_DEVICE_TABLE(usb, id_table);
 
 
 enum pl2303_type {
-       type_0,         /* don't know the difference between type 0 and */
-       type_1,         /* type 1, until someone from prolific tells us... */
-       HX,             /* HX version of the pl2303 chip */
+       type_0,         /* H version ? */
+       type_1,         /* H version ? */
+       HX_TA,          /* HX(A) / X(A) / TA version  */ /* TODO: improve */
+       HXD_EA_RA_SA,   /* HXD / EA / RA / SA version */ /* TODO: improve */
+       TB,             /* TB version */
 };
+/*
+ * NOTE: don't know the difference between type 0 and type 1,
+ * until someone from Prolific tells us...
+ * TODO: distinguish between X/HX, TA and HXD, EA, RA, SA variants
+ */
 
 struct pl2303_serial_private {
        enum pl2303_type type;
@@ -171,6 +184,7 @@ static int pl2303_startup(struct usb_serial *serial)
 {
        struct pl2303_serial_private *spriv;
        enum pl2303_type type = type_0;
+       char *type_str = "unknown (treating as type_0)";
        unsigned char *buf;
 
        spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
@@ -183,15 +197,38 @@ static int pl2303_startup(struct usb_serial *serial)
                return -ENOMEM;
        }
 
-       if (serial->dev->descriptor.bDeviceClass == 0x02)
+       if (serial->dev->descriptor.bDeviceClass == 0x02) {
                type = type_0;
-       else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
-               type = HX;
-       else if (serial->dev->descriptor.bDeviceClass == 0x00)
-               type = type_1;
-       else if (serial->dev->descriptor.bDeviceClass == 0xFF)
+               type_str = "type_0";
+       } else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) {
+               /*
+                * NOTE: The bcdDevice version is the only difference between
+                * the device descriptors of the X/HX, HXD, EA, RA, SA, TA, TB
+                */
+               if (le16_to_cpu(serial->dev->descriptor.bcdDevice) == 0x300) {
+                       type = HX_TA;
+                       type_str = "X/HX/TA";
+               } else if (le16_to_cpu(serial->dev->descriptor.bcdDevice)
+                                                                    == 0x400) {
+                       type = HXD_EA_RA_SA;
+                       type_str = "HXD/EA/RA/SA";
+               } else if (le16_to_cpu(serial->dev->descriptor.bcdDevice)
+                                                                    == 0x500) {
+                       type = TB;
+                       type_str = "TB";
+               } else {
+                       dev_info(&serial->interface->dev,
+                                          "unknown/unsupported device type\n");
+                       kfree(spriv);
+                       kfree(buf);
+                       return -ENODEV;
+               }
+       } else if (serial->dev->descriptor.bDeviceClass == 0x00
+                  || serial->dev->descriptor.bDeviceClass == 0xFF) {
                type = type_1;
-       dev_dbg(&serial->interface->dev, "device type: %d\n", type);
+               type_str = "type_1";
+       }
+       dev_dbg(&serial->interface->dev, "device type: %s\n", type_str);
 
        spriv->type = type;
        usb_set_serial_data(serial, spriv);
@@ -206,10 +243,10 @@ static int pl2303_startup(struct usb_serial *serial)
        pl2303_vendor_read(0x8383, 0, serial, buf);
        pl2303_vendor_write(0, 1, serial);
        pl2303_vendor_write(1, 0, serial);
-       if (type == HX)
-               pl2303_vendor_write(2, 0x44, serial);
-       else
+       if (type == type_0 || type == type_1)
                pl2303_vendor_write(2, 0x24, serial);
+       else
+               pl2303_vendor_write(2, 0x44, serial);
 
        kfree(buf);
        return 0;
@@ -235,6 +272,8 @@ static int pl2303_port_probe(struct usb_serial_port *port)
 
        usb_set_serial_port_data(port, priv);
 
+       port->port.drain_delay = 256;
+
        return 0;
 }
 
@@ -261,6 +300,175 @@ static int pl2303_set_control_lines(struct usb_serial_port *port, u8 value)
        return retval;
 }
 
+static int pl2303_baudrate_encode_direct(int baud, enum pl2303_type type,
+                                                                     u8 buf[4])
+{
+       /*
+        * NOTE: Only the values defined in baud_sup are supported !
+        *       => if unsupported values are set, the PL2303 seems to
+        *          use 9600 baud (at least my PL2303X always does)
+        */
+       const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
+                                4800, 7200, 9600, 14400, 19200, 28800, 38400,
+                                57600, 115200, 230400, 460800, 614400, 921600,
+                                1228800, 2457600, 3000000, 6000000, 12000000 };
+       /*
+        * NOTE: With the exception of type_0/1 devices, the following
+        * additional baud rates are supported (tested with HX rev. 3A only):
+        * 110*, 56000*, 128000, 134400, 161280, 201600, 256000*, 268800,
+        * 403200, 806400.      (*: not HX)
+        *
+        * Maximum values: HXD, TB: 12000000; HX, TA: 6000000;
+        *                 type_0+1: 1228800; RA: 921600; SA: 115200
+        *
+        * As long as we are not using this encoding method for anything else
+        * than the type_0+1 and HX chips, there is no point in complicating
+        * the code to support them.
+        */
+       int i;
+
+       /* Set baudrate to nearest supported value */
+       for (i = 0; i < ARRAY_SIZE(baud_sup); ++i) {
+               if (baud_sup[i] > baud)
+                       break;
+       }
+       if (i == ARRAY_SIZE(baud_sup))
+               baud = baud_sup[i - 1];
+       else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1]))
+               baud = baud_sup[i - 1];
+       else
+               baud = baud_sup[i];
+       /* Respect the chip type specific baud rate limits */
+       /*
+        * FIXME: as long as we don't know how to distinguish between the
+        * HXD, EA, RA, and SA chip variants, allow the max. value of 12M.
+        */
+       if (type == HX_TA)
+               baud = min_t(int, baud, 6000000);
+       else if (type == type_0 || type == type_1)
+               baud = min_t(int, baud, 1228800);
+       /* Direct (standard) baud rate encoding method */
+       put_unaligned_le32(baud, buf);
+
+       return baud;
+}
+
+static int pl2303_baudrate_encode_divisor(int baud, enum pl2303_type type,
+                                                                     u8 buf[4])
+{
+       /*
+        * Divisor based baud rate encoding method
+        *
+        * NOTE: it's not clear if the type_0/1 chips support this method
+        *
+        * divisor = 12MHz * 32 / baudrate = 2^A * B
+        *
+        * with
+        *
+        * A = buf[1] & 0x0e
+        * B = buf[0]  +  (buf[1] & 0x01) << 8
+        *
+        * Special cases:
+        * => 8 < B < 16: device seems to work not properly
+        * => B <= 8: device uses the max. value B = 512 instead
+        */
+       unsigned int A, B;
+
+       /*
+        * NOTE: The Windows driver allows maximum baud rates of 110% of the
+        * specified maximium value.
+        * Quick tests with early (2004) HX (rev. A) chips suggest, that even
+        * higher baud rates (up to the maximum of 24M baud !) are working fine,
+        * but that should really be tested carefully in "real life" scenarios
+        * before removing the upper limit completely.
+        * Baud rates smaller than the specified 75 baud are definitely working
+        * fine.
+        */
+       if (type == type_0 || type == type_1)
+               baud = min_t(int, baud, 1228800 * 1.1);
+       else if (type == HX_TA)
+               baud = min_t(int, baud, 6000000 * 1.1);
+       else if (type == HXD_EA_RA_SA)
+               /* HXD, EA: 12Mbps; RA: 1Mbps; SA: 115200 bps */
+               /*
+                * FIXME: as long as we don't know how to distinguish between
+                * these chip variants, allow the max. of these values
+                */
+               baud = min_t(int, baud, 12000000 * 1.1);
+       else if (type == TB)
+               baud = min_t(int, baud, 12000000 * 1.1);
+       /* Determine factors A and B */
+       A = 0;
+       B = 12000000 * 32 / baud;  /* 12MHz */
+       B <<= 1; /* Add one bit for rounding */
+       while (B > (512 << 1) && A <= 14) {
+               A += 2;
+               B >>= 2;
+       }
+       if (A > 14) { /* max. divisor = min. baudrate reached */
+               A = 14;
+               B = 512;
+               /* => ~45.78 baud */
+       } else {
+               B = (B + 1) >> 1; /* Round the last bit */
+       }
+       /* Handle special cases */
+       if (B == 512)
+               B = 0; /* also: 1 to 8 */
+       else if (B < 16)
+               /*
+                * NOTE: With the current algorithm this happens
+                * only for A=0 and means that the min. divisor
+                * (respectively: the max. baudrate) is reached.
+                */
+               B = 16;         /* => 24 MBaud */
+       /* Encode the baud rate */
+       buf[3] = 0x80;     /* Select divisor encoding method */
+       buf[2] = 0;
+       buf[1] = (A & 0x0e);            /* A */
+       buf[1] |= ((B & 0x100) >> 8);   /* MSB of B */
+       buf[0] = B & 0xff;              /* 8 LSBs of B */
+       /* Calculate the actual/resulting baud rate */
+       if (B <= 8)
+               B = 512;
+       baud = 12000000 * 32 / ((1 << A) * B);
+
+       return baud;
+}
+
+static void pl2303_encode_baudrate(struct tty_struct *tty,
+                                       struct usb_serial_port *port,
+                                       enum pl2303_type type,
+                                       u8 buf[4])
+{
+       int baud;
+
+       baud = tty_get_baud_rate(tty);
+       dev_dbg(&port->dev, "baud requested = %d\n", baud);
+       if (!baud)
+               return;
+       /*
+        * There are two methods for setting/encoding the baud rate
+        * 1) Direct method: encodes the baud rate value directly
+        *    => supported by all chip types
+        * 2) Divisor based method: encodes a divisor to a base value (12MHz*32)
+        *    => supported by HX chips (and likely not by type_0/1 chips)
+        *
+        * NOTE: Although the divisor based baud rate encoding method is much
+        * more flexible, some of the standard baud rate values can not be
+        * realized exactly. But the difference is very small (max. 0.2%) and
+        * the device likely uses the same baud rate generator for both methods
+        * so that there is likley no difference.
+        */
+       if (type == type_0 || type == type_1)
+               baud = pl2303_baudrate_encode_direct(baud, type, buf);
+       else
+               baud = pl2303_baudrate_encode_divisor(baud, type, buf);
+       /* Save resulting baud rate */
+       tty_encode_baud_rate(tty, baud, baud);
+       dev_dbg(&port->dev, "baud set = %d\n", baud);
+}
+
 static void pl2303_set_termios(struct tty_struct *tty,
                struct usb_serial_port *port, struct ktermios *old_termios)
 {
@@ -268,27 +476,18 @@ static void pl2303_set_termios(struct tty_struct *tty,
        struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
        struct pl2303_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
-       unsigned int cflag;
        unsigned char *buf;
-       int baud;
        int i;
        u8 control;
-       const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
-                                4800, 7200, 9600, 14400, 19200, 28800, 38400,
-                                57600, 115200, 230400, 460800, 500000, 614400,
-                                921600, 1228800, 2457600, 3000000, 6000000 };
-       int baud_floor, baud_ceil;
-       int k;
-
-       /* The PL2303 is reported to lose bytes if you change
-          serial settings even to the same values as before. Thus
-          we actually need to filter in this specific case */
 
+       /*
+        * The PL2303 is reported to lose bytes if you change serial settings
+        * even to the same values as before. Thus we actually need to filter
+        * in this specific case.
+        */
        if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
                return;
 
-       cflag = tty->termios.c_cflag;
-
        buf = kzalloc(7, GFP_KERNEL);
        if (!buf) {
                dev_err(&port->dev, "%s - out of memory.\n", __func__);
@@ -303,8 +502,8 @@ static void pl2303_set_termios(struct tty_struct *tty,
                            0, 0, buf, 7, 100);
        dev_dbg(&port->dev, "0xa1:0x21:0:0  %d - %7ph\n", i, buf);
 
-       if (cflag & CSIZE) {
-               switch (cflag & CSIZE) {
+       if (C_CSIZE(tty)) {
+               switch (C_CSIZE(tty)) {
                case CS5:
                        buf[6] = 5;
                        break;
@@ -317,73 +516,22 @@ static void pl2303_set_termios(struct tty_struct *tty,
                default:
                case CS8:
                        buf[6] = 8;
-                       break;
                }
                dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
        }
 
-       /* For reference buf[0]:buf[3] baud rate value */
-       /* NOTE: Only the values defined in baud_sup are supported !
-        *       => if unsupported values are set, the PL2303 seems to use
-        *          9600 baud (at least my PL2303X always does)
-        */
-       baud = tty_get_baud_rate(tty);
-       dev_dbg(&port->dev, "baud requested = %d\n", baud);
-       if (baud) {
-               /* Set baudrate to nearest supported value */
-               for (k=0; k<ARRAY_SIZE(baud_sup); k++) {
-                       if (baud_sup[k] / baud) {
-                               baud_ceil = baud_sup[k];
-                               if (k==0) {
-                                       baud = baud_ceil;
-                               } else {
-                                       baud_floor = baud_sup[k-1];
-                                       if ((baud_ceil % baud)
-                                           > (baud % baud_floor))
-                                               baud = baud_floor;
-                                       else
-                                               baud = baud_ceil;
-                               }
-                               break;
-                       }
-               }
-               if (baud > 1228800) {
-                       /* type_0, type_1 only support up to 1228800 baud */
-                       if (spriv->type != HX)
-                               baud = 1228800;
-                       else if (baud > 6000000)
-                               baud = 6000000;
-               }
-               dev_dbg(&port->dev, "baud set = %d\n", baud);
-               if (baud <= 115200) {
-                       buf[0] = baud & 0xff;
-                       buf[1] = (baud >> 8) & 0xff;
-                       buf[2] = (baud >> 16) & 0xff;
-                       buf[3] = (baud >> 24) & 0xff;
-               } else {
-                       /* apparently the formula for higher speeds is:
-                        * baudrate = 12M * 32 / (2^buf[1]) / buf[0]
-                        */
-                       unsigned tmp = 12*1000*1000*32 / baud;
-                       buf[3] = 0x80;
-                       buf[2] = 0;
-                       buf[1] = (tmp >= 256);
-                       while (tmp >= 256) {
-                               tmp >>= 2;
-                               buf[1] <<= 1;
-                       }
-                       buf[0] = tmp;
-               }
-       }
+       /* For reference:   buf[0]:buf[3] baud rate value */
+       pl2303_encode_baudrate(tty, port, spriv->type, buf);
 
        /* For reference buf[4]=0 is 1 stop bits */
        /* For reference buf[4]=1 is 1.5 stop bits */
        /* For reference buf[4]=2 is 2 stop bits */
-       if (cflag & CSTOPB) {
-               /* NOTE: Comply with "real" UARTs / RS232:
+       if (C_CSTOPB(tty)) {
+               /*
+                * NOTE: Comply with "real" UARTs / RS232:
                 *       use 1.5 instead of 2 stop bits with 5 data bits
                 */
-               if ((cflag & CSIZE) == CS5) {
+               if (C_CSIZE(tty) == CS5) {
                        buf[4] = 1;
                        dev_dbg(&port->dev, "stop bits = 1.5\n");
                } else {
@@ -395,14 +543,14 @@ static void pl2303_set_termios(struct tty_struct *tty,
                dev_dbg(&port->dev, "stop bits = 1\n");
        }
 
-       if (cflag & PARENB) {
+       if (C_PARENB(tty)) {
                /* For reference buf[5]=0 is none parity */
                /* For reference buf[5]=1 is odd parity */
                /* For reference buf[5]=2 is even parity */
                /* For reference buf[5]=3 is mark parity */
                /* For reference buf[5]=4 is space parity */
-               if (cflag & PARODD) {
-                       if (cflag & CMSPAR) {
+               if (C_PARODD(tty)) {
+                       if (tty->termios.c_cflag & CMSPAR) {
                                buf[5] = 3;
                                dev_dbg(&port->dev, "parity = mark\n");
                        } else {
@@ -410,7 +558,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
                                dev_dbg(&port->dev, "parity = odd\n");
                        }
                } else {
-                       if (cflag & CMSPAR) {
+                       if (tty->termios.c_cflag & CMSPAR) {
                                buf[5] = 4;
                                dev_dbg(&port->dev, "parity = space\n");
                        } else {
@@ -431,7 +579,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
        /* change control lines if we are switching to or from B0 */
        spin_lock_irqsave(&priv->lock, flags);
        control = priv->line_control;
-       if ((cflag & CBAUD) == B0)
+       if (C_BAUD(tty) == B0)
                priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
        else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
                priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
@@ -443,26 +591,21 @@ static void pl2303_set_termios(struct tty_struct *tty,
                spin_unlock_irqrestore(&priv->lock, flags);
        }
 
-       buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
-
+       memset(buf, 0, 7);
        i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
                            GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
                            0, 0, buf, 7, 100);
        dev_dbg(&port->dev, "0xa1:0x21:0:0  %d - %7ph\n", i, buf);
 
-       if (cflag & CRTSCTS) {
-               if (spriv->type == HX)
-                       pl2303_vendor_write(0x0, 0x61, serial);
-               else
+       if (C_CRTSCTS(tty)) {
+               if (spriv->type == type_0 || spriv->type == type_1)
                        pl2303_vendor_write(0x0, 0x41, serial);
+               else
+                       pl2303_vendor_write(0x0, 0x61, serial);
        } else {
                pl2303_vendor_write(0x0, 0x0, serial);
        }
 
-       /* Save resulting baud rate */
-       if (baud)
-               tty_encode_baud_rate(tty, baud, baud);
-
        kfree(buf);
 }
 
@@ -495,7 +638,7 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
        struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
        int result;
 
-       if (spriv->type != HX) {
+       if (spriv->type == type_0 || spriv->type == type_1) {
                usb_clear_halt(serial->dev, port->write_urb->pipe);
                usb_clear_halt(serial->dev, port->read_urb->pipe);
        } else {
@@ -521,7 +664,6 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
                return result;
        }
 
-       port->port.drain_delay = 256;
        return 0;
 }
 
@@ -789,8 +931,10 @@ static void pl2303_process_read_urb(struct urb *urb)
                tty_flag = TTY_PARITY;
        else if (line_status & UART_FRAME_ERROR)
                tty_flag = TTY_FRAME;
-       dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
 
+       if (tty_flag != TTY_NORMAL)
+               dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__,
+                                                               tty_flag);
        /* overrun is special, not associated with a char */
        if (line_status & UART_OVERRUN_ERROR)
                tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
index d99743290fc13c2e81feec43c8bcc5623b4c7c11..a24d59ae403277b0f474458c2387e28a7a234577 100644 (file)
@@ -62,6 +62,7 @@
 #define  MAX_BAUD_RATE              921600
 #define  DEFAULT_BAUD_RATE          9600
 
+#define QT2_READ_BUFFER_SIZE    512  /* size of read buffer */
 #define QT2_WRITE_BUFFER_SIZE   512  /* size of write buffer */
 #define QT2_WRITE_CONTROL_SIZE  5    /* control bytes used for a write */
 
@@ -112,7 +113,7 @@ struct qt2_serial_private {
        unsigned char current_port;  /* current port for incoming data */
 
        struct urb      *read_urb;   /* shared among all ports */
-       char            read_buffer[512];
+       char            *read_buffer;
 };
 
 struct qt2_port_private {
@@ -121,7 +122,7 @@ struct qt2_port_private {
        spinlock_t urb_lock;
        bool       urb_in_use;
        struct urb *write_urb;
-       char       write_buffer[QT2_WRITE_BUFFER_SIZE];
+       char       *write_buffer;
 
        spinlock_t  lock;
        u8          shadowLSR;
@@ -142,6 +143,7 @@ static void qt2_release(struct usb_serial *serial)
        serial_priv = usb_get_serial_data(serial);
 
        usb_free_urb(serial_priv->read_urb);
+       kfree(serial_priv->read_buffer);
        kfree(serial_priv);
 }
 
@@ -683,7 +685,7 @@ static int qt2_setup_urbs(struct usb_serial *serial)
                          usb_rcvbulkpipe(serial->dev,
                                          port0->bulk_in_endpointAddress),
                          serial_priv->read_buffer,
-                         sizeof(serial_priv->read_buffer),
+                         QT2_READ_BUFFER_SIZE,
                          qt2_read_bulk_callback, serial);
 
        status = usb_submit_urb(serial_priv->read_urb, GFP_KERNEL);
@@ -718,6 +720,12 @@ static int qt2_attach(struct usb_serial *serial)
                return -ENOMEM;
        }
 
+       serial_priv->read_buffer = kmalloc(QT2_READ_BUFFER_SIZE, GFP_KERNEL);
+       if (!serial_priv->read_buffer) {
+               status = -ENOMEM;
+               goto err_buf;
+       }
+
        usb_set_serial_data(serial, serial_priv);
 
        status = qt2_setup_urbs(serial);
@@ -727,6 +735,8 @@ static int qt2_attach(struct usb_serial *serial)
        return 0;
 
 attach_failed:
+       kfree(serial_priv->read_buffer);
+err_buf:
        kfree(serial_priv);
        return status;
 }
@@ -745,21 +755,29 @@ static int qt2_port_probe(struct usb_serial_port *port)
        spin_lock_init(&port_priv->urb_lock);
        port_priv->port = port;
 
+       port_priv->write_buffer = kmalloc(QT2_WRITE_BUFFER_SIZE, GFP_KERNEL);
+       if (!port_priv->write_buffer)
+               goto err_buf;
+
        port_priv->write_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!port_priv->write_urb) {
-               kfree(port_priv);
-               return -ENOMEM;
-       }
+       if (!port_priv->write_urb)
+               goto err_urb;
+
        bEndpointAddress = serial->port[0]->bulk_out_endpointAddress;
        usb_fill_bulk_urb(port_priv->write_urb, serial->dev,
                                usb_sndbulkpipe(serial->dev, bEndpointAddress),
                                port_priv->write_buffer,
-                               sizeof(port_priv->write_buffer),
+                               QT2_WRITE_BUFFER_SIZE,
                                qt2_write_bulk_callback, port);
 
        usb_set_serial_port_data(port, port_priv);
 
        return 0;
+err_urb:
+       kfree(port_priv->write_buffer);
+err_buf:
+       kfree(port_priv);
+       return -ENOMEM;
 }
 
 static int qt2_port_remove(struct usb_serial_port *port)
@@ -768,6 +786,7 @@ static int qt2_port_remove(struct usb_serial_port *port)
 
        port_priv = usb_get_serial_port_data(port);
        usb_free_urb(port_priv->write_urb);
+       kfree(port_priv->write_buffer);
        kfree(port_priv);
 
        return 0;
index 21cd7bf2a8cc90322044596fda6a58af5d3e67f6..ba895989d8c4b89231cf34a431e7f894a5ab4268 100644 (file)
@@ -92,13 +92,6 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-static __u16 vendor;           /* no default */
-static __u16 product;          /* no default */
-module_param(vendor, ushort, 0);
-MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)");
-module_param(product, ushort, 0);
-MODULE_PARM_DESC(product, "User specified USB idProduct (required)");
-
 module_param(safe, bool, 0);
 MODULE_PARM_DESC(safe, "Turn Safe Encapsulation On/Off");
 
@@ -140,8 +133,6 @@ static struct usb_device_id id_table[] = {
        {MY_USB_DEVICE(0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},   /* Collie */
        {MY_USB_DEVICE(0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},   /* Collie */
        {MY_USB_DEVICE(0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},   /* Sharp tmp */
-       /* extra null entry for module vendor/produc parameters */
-       {MY_USB_DEVICE(0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
        {}                      /* terminating entry  */
 };
 
@@ -272,7 +263,19 @@ static int safe_prepare_write_buffer(struct usb_serial_port *port,
 
 static int safe_startup(struct usb_serial *serial)
 {
-       switch (serial->interface->cur_altsetting->desc.bInterfaceProtocol) {
+       struct usb_interface_descriptor *desc;
+
+       if (serial->dev->descriptor.bDeviceClass != CDC_DEVICE_CLASS)
+               return -ENODEV;
+
+       desc = &serial->interface->cur_altsetting->desc;
+
+       if (desc->bInterfaceClass != LINEO_INTERFACE_CLASS)
+               return -ENODEV;
+       if (desc->bInterfaceSubClass != LINEO_INTERFACE_SUBCLASS_SAFESERIAL)
+               return -ENODEV;
+
+       switch (desc->bInterfaceProtocol) {
        case LINEO_SAFESERIAL_CRC:
                break;
        case LINEO_SAFESERIAL_CRC_PADDED:
@@ -300,30 +303,4 @@ static struct usb_serial_driver * const serial_drivers[] = {
        &safe_device, NULL
 };
 
-static int __init safe_init(void)
-{
-       int i;
-
-       /* if we have vendor / product parameters patch them into id list */
-       if (vendor || product) {
-               pr_info("vendor: %x product: %x\n", vendor, product);
-
-               for (i = 0; i < ARRAY_SIZE(id_table); i++) {
-                       if (!id_table[i].idVendor && !id_table[i].idProduct) {
-                               id_table[i].idVendor = vendor;
-                               id_table[i].idProduct = product;
-                               break;
-                       }
-               }
-       }
-
-       return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table);
-}
-
-static void __exit safe_exit(void)
-{
-       usb_serial_deregister_drivers(serial_drivers);
-}
-
-module_init(safe_init);
-module_exit(safe_exit);
+module_usb_serial_driver(serial_drivers, id_table);
diff --git a/drivers/usb/serial/siemens_mpi.c b/drivers/usb/serial/siemens_mpi.c
deleted file mode 100644 (file)
index a76b1ae..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Siemens USB-MPI Serial USB driver
- *
- * Copyright (C) 2005 Thomas Hergenhahn <thomas.hergenhahn@suse.de>
- * Copyright (C) 2005,2008 Greg Kroah-Hartman <gregkh@suse.de>
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License version
- *     2 as published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-#define DRIVER_AUTHOR "Thomas Hergenhahn@web.de http://libnodave.sf.net"
-#define DRIVER_DESC "Driver for Siemens USB/MPI adapter"
-
-
-static const struct usb_device_id id_table[] = {
-       /* Vendor and product id for 6ES7-972-0CB20-0XA0 */
-       { USB_DEVICE(0x908, 0x0004) },
-       { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver siemens_usb_mpi_device = {
-       .driver = {
-               .owner =        THIS_MODULE,
-               .name =         "siemens_mpi",
-       },
-       .id_table =             id_table,
-       .num_ports =            1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-       &siemens_usb_mpi_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
index ddf6c47137dc4e557630b70156ad146f82d441c7..4abac28b5992a1f128005f5f7df103118a39b081 100644 (file)
@@ -169,6 +169,8 @@ static int spcp8x5_port_probe(struct usb_serial_port *port)
 
        usb_set_serial_port_data(port, priv);
 
+       port->port.drain_delay = 256;
+
        return 0;
 }
 
@@ -411,8 +413,6 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
        if (tty)
                spcp8x5_set_termios(tty, port, NULL);
 
-       port->port.drain_delay = 256;
-
        return usb_serial_generic_open(tty, port);
 }
 
diff --git a/drivers/usb/serial/suunto.c b/drivers/usb/serial/suunto.c
deleted file mode 100644 (file)
index 2248e7a..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Suunto ANT+ USB Driver
- *
- * Copyright (C) 2013 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
- * Copyright (C) 2013 Linux Foundation
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation only.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-#include <linux/uaccess.h>
-
-static const struct usb_device_id id_table[] = {
-       { USB_DEVICE(0x0fcf, 0x1008) },
-       { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver suunto_device = {
-       .driver = {
-               .owner =        THIS_MODULE,
-               .name =         KBUILD_MODNAME,
-       },
-       .id_table =             id_table,
-       .num_ports =            1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-       &suunto_device,
-       NULL,
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-MODULE_LICENSE("GPL");
index 5c9f9b1d7736d0b7fade9780920d8916477c81fa..760b78560f67fd7e7d905d53dff2cb7a46f2919f 100644 (file)
@@ -45,8 +45,6 @@
 
 #define TI_FIRMWARE_BUF_SIZE   16284
 
-#define TI_WRITE_BUF_SIZE      1024
-
 #define TI_TRANSFER_TIMEOUT    2
 
 #define TI_DEFAULT_CLOSING_WAIT        4000            /* in .01 secs */
@@ -71,13 +69,11 @@ struct ti_port {
        __u8                    tp_uart_mode;   /* 232 or 485 modes */
        unsigned int            tp_uart_base_addr;
        int                     tp_flags;
-       wait_queue_head_t       tp_write_wait;
        struct ti_device        *tp_tdev;
        struct usb_serial_port  *tp_port;
        spinlock_t              tp_lock;
        int                     tp_read_urb_state;
        int                     tp_write_urb_in_use;
-       struct kfifo            write_fifo;
 };
 
 struct ti_device {
@@ -145,20 +141,9 @@ static int ti_download_firmware(struct ti_device *tdev);
 
 /* module parameters */
 static int closing_wait = TI_DEFAULT_CLOSING_WAIT;
-static ushort vendor_3410[TI_EXTRA_VID_PID_COUNT];
-static unsigned int vendor_3410_count;
-static ushort product_3410[TI_EXTRA_VID_PID_COUNT];
-static unsigned int product_3410_count;
-static ushort vendor_5052[TI_EXTRA_VID_PID_COUNT];
-static unsigned int vendor_5052_count;
-static ushort product_5052[TI_EXTRA_VID_PID_COUNT];
-static unsigned int product_5052_count;
 
 /* supported devices */
-/* the array dimension is the number of default entries plus */
-/* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */
-/* null entry */
-static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = {
+static struct usb_device_id ti_id_table_3410[] = {
        { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
        { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
@@ -175,16 +160,18 @@ static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = {
        { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STEREO_PLUG_ID) },
        { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
+       { }     /* terminator */
 };
 
-static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = {
+static struct usb_device_id ti_id_table_5052[] = {
        { USB_DEVICE(TI_VENDOR_ID, TI_5052_BOOT_PRODUCT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) },
+       { }     /* terminator */
 };
 
-static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1] = {
+static struct usb_device_id ti_id_table_combined[] = {
        { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
        { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
@@ -204,7 +191,7 @@ static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1]
        { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) },
        { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
-       { }
+       { }     /* terminator */
 };
 
 static struct usb_serial_driver ti_1port_device = {
@@ -293,61 +280,12 @@ module_param(closing_wait, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(closing_wait,
     "Maximum wait for data to drain in close, in .01 secs, default is 4000");
 
-module_param_array(vendor_3410, ushort, &vendor_3410_count, S_IRUGO);
-MODULE_PARM_DESC(vendor_3410,
-               "Vendor ids for 3410 based devices, 1-5 short integers");
-module_param_array(product_3410, ushort, &product_3410_count, S_IRUGO);
-MODULE_PARM_DESC(product_3410,
-               "Product ids for 3410 based devices, 1-5 short integers");
-module_param_array(vendor_5052, ushort, &vendor_5052_count, S_IRUGO);
-MODULE_PARM_DESC(vendor_5052,
-               "Vendor ids for 5052 based devices, 1-5 short integers");
-module_param_array(product_5052, ushort, &product_5052_count, S_IRUGO);
-MODULE_PARM_DESC(product_5052,
-               "Product ids for 5052 based devices, 1-5 short integers");
-
 MODULE_DEVICE_TABLE(usb, ti_id_table_combined);
 
+module_usb_serial_driver(serial_drivers, ti_id_table_combined);
 
 /* Functions */
 
-static int __init ti_init(void)
-{
-       int i, j, c;
-
-       /* insert extra vendor and product ids */
-       c = ARRAY_SIZE(ti_id_table_combined) - 2 * TI_EXTRA_VID_PID_COUNT - 1;
-       j = ARRAY_SIZE(ti_id_table_3410) - TI_EXTRA_VID_PID_COUNT - 1;
-       for (i = 0; i < min(vendor_3410_count, product_3410_count); i++, j++, c++) {
-               ti_id_table_3410[j].idVendor = vendor_3410[i];
-               ti_id_table_3410[j].idProduct = product_3410[i];
-               ti_id_table_3410[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
-               ti_id_table_combined[c].idVendor = vendor_3410[i];
-               ti_id_table_combined[c].idProduct = product_3410[i];
-               ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
-       }
-       j = ARRAY_SIZE(ti_id_table_5052) - TI_EXTRA_VID_PID_COUNT - 1;
-       for (i = 0; i < min(vendor_5052_count, product_5052_count); i++, j++, c++) {
-               ti_id_table_5052[j].idVendor = vendor_5052[i];
-               ti_id_table_5052[j].idProduct = product_5052[i];
-               ti_id_table_5052[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
-               ti_id_table_combined[c].idVendor = vendor_5052[i];
-               ti_id_table_combined[c].idProduct = product_5052[i];
-               ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
-       }
-
-       return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ti_id_table_combined);
-}
-
-static void __exit ti_exit(void)
-{
-       usb_serial_deregister_drivers(serial_drivers);
-}
-
-module_init(ti_init);
-module_exit(ti_exit);
-
-
 static int ti_startup(struct usb_serial *serial)
 {
        struct ti_device *tdev;
@@ -430,17 +368,14 @@ static int ti_port_probe(struct usb_serial_port *port)
        else
                tport->tp_uart_base_addr = TI_UART2_BASE_ADDR;
        port->port.closing_wait = msecs_to_jiffies(10 * closing_wait);
-       init_waitqueue_head(&tport->tp_write_wait);
-       if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE, GFP_KERNEL)) {
-               kfree(tport);
-               return -ENOMEM;
-       }
        tport->tp_port = port;
        tport->tp_tdev = usb_get_serial_data(port->serial);
        tport->tp_uart_mode = 0;        /* default is RS232 */
 
        usb_set_serial_port_data(port, tport);
 
+       port->port.drain_delay = 3;
+
        return 0;
 }
 
@@ -449,7 +384,6 @@ static int ti_port_remove(struct usb_serial_port *port)
        struct ti_port *tport;
 
        tport = usb_get_serial_port_data(port);
-       kfifo_free(&tport->write_fifo);
        kfree(tport);
 
        return 0;
@@ -582,8 +516,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
        tport->tp_is_open = 1;
        ++tdev->td_open_port_count;
 
-       port->port.drain_delay = 3;
-
        goto release_lock;
 
 unlink_int_urb:
@@ -616,7 +548,7 @@ static void ti_close(struct usb_serial_port *port)
        usb_kill_urb(port->write_urb);
        tport->tp_write_urb_in_use = 0;
        spin_lock_irqsave(&tport->tp_lock, flags);
-       kfifo_reset_out(&tport->write_fifo);
+       kfifo_reset_out(&port->write_fifo);
        spin_unlock_irqrestore(&tport->tp_lock, flags);
 
        port_number = port->port_number;
@@ -655,7 +587,7 @@ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port,
        if (tport == NULL || !tport->tp_is_open)
                return -ENODEV;
 
-       count = kfifo_in_locked(&tport->write_fifo, data, count,
+       count = kfifo_in_locked(&port->write_fifo, data, count,
                                                        &tport->tp_lock);
        ti_send(tport);
 
@@ -674,7 +606,7 @@ static int ti_write_room(struct tty_struct *tty)
                return 0;
 
        spin_lock_irqsave(&tport->tp_lock, flags);
-       room = kfifo_avail(&tport->write_fifo);
+       room = kfifo_avail(&port->write_fifo);
        spin_unlock_irqrestore(&tport->tp_lock, flags);
 
        dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
@@ -693,7 +625,7 @@ static int ti_chars_in_buffer(struct tty_struct *tty)
                return 0;
 
        spin_lock_irqsave(&tport->tp_lock, flags);
-       chars = kfifo_len(&tport->write_fifo);
+       chars = kfifo_len(&port->write_fifo);
        spin_unlock_irqrestore(&tport->tp_lock, flags);
 
        dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
@@ -1090,13 +1022,11 @@ static void ti_bulk_in_callback(struct urb *urb)
        case -ESHUTDOWN:
                dev_dbg(dev, "%s - urb shutting down, %d\n", __func__, status);
                tport->tp_tdev->td_urb_error = 1;
-               wake_up_interruptible(&tport->tp_write_wait);
                return;
        default:
                dev_err(dev, "%s - nonzero urb status, %d\n",
                        __func__, status);
                tport->tp_tdev->td_urb_error = 1;
-               wake_up_interruptible(&tport->tp_write_wait);
        }
 
        if (status == -EPIPE)
@@ -1152,13 +1082,11 @@ static void ti_bulk_out_callback(struct urb *urb)
        case -ESHUTDOWN:
                dev_dbg(&port->dev, "%s - urb shutting down, %d\n", __func__, status);
                tport->tp_tdev->td_urb_error = 1;
-               wake_up_interruptible(&tport->tp_write_wait);
                return;
        default:
                dev_err_console(port, "%s - nonzero urb status, %d\n",
                        __func__, status);
                tport->tp_tdev->td_urb_error = 1;
-               wake_up_interruptible(&tport->tp_write_wait);
        }
 
        /* send any buffered data */
@@ -1197,7 +1125,7 @@ static void ti_send(struct ti_port *tport)
        if (tport->tp_write_urb_in_use)
                goto unlock;
 
-       count = kfifo_out(&tport->write_fifo,
+       count = kfifo_out(&port->write_fifo,
                                port->write_urb->transfer_buffer,
                                port->bulk_out_size);
 
@@ -1232,7 +1160,6 @@ static void ti_send(struct ti_port *tport)
        /* more room in the buffer for new writes, wakeup */
        tty_port_tty_wakeup(&port->port);
 
-       wake_up_interruptible(&tport->tp_write_wait);
        return;
 unlock:
        spin_unlock_irqrestore(&tport->tp_lock, flags);
@@ -1312,7 +1239,7 @@ static int ti_get_serial_info(struct ti_port *tport,
        ret_serial.line = port->minor;
        ret_serial.port = port->port_number;
        ret_serial.flags = tport->tp_flags;
-       ret_serial.xmit_fifo_size = TI_WRITE_BUF_SIZE;
+       ret_serial.xmit_fifo_size = kfifo_size(&port->write_fifo);
        ret_serial.baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800;
        ret_serial.closing_wait = cwait;
 
diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c
new file mode 100644 (file)
index 0000000..52eb91f
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * USB Serial "Simple" driver
+ *
+ * Copyright (C) 2001-2006,2008,2013 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2005 Arthur Huillet (ahuillet@users.sf.net)
+ * Copyright (C) 2005 Thomas Hergenhahn <thomas.hergenhahn@suse.de>
+ * Copyright (C) 2009 Outpost Embedded, LLC
+ * Copyright (C) 2010 Zilogic Systems <code@zilogic.com>
+ * Copyright (C) 2013 Wei Shuai <cpuwolf@gmail.com>
+ * Copyright (C) 2013 Linux Foundation
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License version
+ *     2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+#define DEVICE(vendor, IDS)                                    \
+static const struct usb_device_id vendor##_id_table[] = {      \
+       IDS(),                                                  \
+       { },                                                    \
+};                                                             \
+static struct usb_serial_driver vendor##_device = {            \
+       .driver = {                                             \
+               .owner =        THIS_MODULE,                    \
+               .name =         #vendor,                        \
+       },                                                      \
+       .id_table =             vendor##_id_table,              \
+       .num_ports =            1,                              \
+};
+
+
+/* ZIO Motherboard USB driver */
+#define ZIO_IDS()                      \
+       { USB_DEVICE(0x1CBE, 0x0103) }
+DEVICE(zio, ZIO_IDS);
+
+/* Funsoft Serial USB driver */
+#define FUNSOFT_IDS()                  \
+       { USB_DEVICE(0x1404, 0xcddc) }
+DEVICE(funsoft, FUNSOFT_IDS);
+
+/* Infineon Flashloader driver */
+#define FLASHLOADER_IDS()              \
+       { USB_DEVICE(0x8087, 0x0716) }
+DEVICE(flashloader, FLASHLOADER_IDS);
+
+/* ViVOpay USB Serial Driver */
+#define VIVOPAY_IDS()                  \
+       { USB_DEVICE(0x1d5f, 0x1004) }  /* ViVOpay 8800 */
+DEVICE(vivopay, VIVOPAY_IDS);
+
+/* Motorola USB Phone driver */
+#define MOTO_IDS()                     \
+       { USB_DEVICE(0x05c6, 0x3197) }, /* unknown Motorola phone */    \
+       { USB_DEVICE(0x0c44, 0x0022) }, /* unknown Mororola phone */    \
+       { USB_DEVICE(0x22b8, 0x2a64) }, /* Motorola KRZR K1m */         \
+       { USB_DEVICE(0x22b8, 0x2c84) }, /* Motorola VE240 phone */      \
+       { USB_DEVICE(0x22b8, 0x2c64) }  /* Motorola V950 phone */
+DEVICE(moto_modem, MOTO_IDS);
+
+/* HP4x (48/49) Generic Serial driver */
+#define HP4X_IDS()                     \
+       { USB_DEVICE(0x03f0, 0x0121) }
+DEVICE(hp4x, HP4X_IDS);
+
+/* Suunto ANT+ USB Driver */
+#define SUUNTO_IDS()                   \
+       { USB_DEVICE(0x0fcf, 0x1008) }
+DEVICE(suunto, SUUNTO_IDS);
+
+/* Siemens USB/MPI adapter */
+#define SIEMENS_IDS()                  \
+       { USB_DEVICE(0x908, 0x0004) }
+DEVICE(siemens_mpi, SIEMENS_IDS);
+
+/* All of the above structures mushed into two lists */
+static struct usb_serial_driver * const serial_drivers[] = {
+       &zio_device,
+       &funsoft_device,
+       &flashloader_device,
+       &vivopay_device,
+       &moto_modem_device,
+       &hp4x_device,
+       &suunto_device,
+       &siemens_mpi_device,
+       NULL
+};
+
+static const struct usb_device_id id_table[] = {
+       ZIO_IDS(),
+       FUNSOFT_IDS(),
+       FLASHLOADER_IDS(),
+       VIVOPAY_IDS(),
+       MOTO_IDS(),
+       HP4X_IDS(),
+       SUUNTO_IDS(),
+       SIEMENS_IDS(),
+       { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+module_usb_serial_driver(serial_drivers, id_table);
+MODULE_LICENSE("GPL");
index cb27fcb2fc905fddb23e4ef7021ed2a20377132e..6091bd5a1f4f255eca73b48dfcce56cfbf88de7b 100644 (file)
@@ -681,20 +681,10 @@ static int serial_port_carrier_raised(struct tty_port *port)
 static void serial_port_dtr_rts(struct tty_port *port, int on)
 {
        struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
-       struct usb_serial *serial = p->serial;
-       struct usb_serial_driver *drv = serial->type;
+       struct usb_serial_driver *drv = p->serial->type;
 
-       if (!drv->dtr_rts)
-               return;
-       /*
-        * Work-around bug in the tty-layer which can result in dtr_rts
-        * being called after a disconnect (and tty_unregister_device
-        * has returned). Remove once bug has been squashed.
-        */
-       mutex_lock(&serial->disc_mutex);
-       if (!serial->disconnected)
+       if (drv->dtr_rts)
                drv->dtr_rts(p, on);
-       mutex_unlock(&serial->disc_mutex);
 }
 
 static const struct tty_port_operations serial_port_ops = {
diff --git a/drivers/usb/serial/vivopay-serial.c b/drivers/usb/serial/vivopay-serial.c
deleted file mode 100644 (file)
index 6299526..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2001-2005 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (C) 2009 Outpost Embedded, LLC
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-#define DRIVER_DESC "ViVOpay USB Serial Driver"
-
-#define VIVOPAY_VENDOR_ID 0x1d5f
-
-
-static struct usb_device_id id_table [] = {
-       /* ViVOpay 8800 */
-       { USB_DEVICE(VIVOPAY_VENDOR_ID, 0x1004) },
-       { },
-};
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver vivopay_serial_device = {
-       .driver = {
-               .owner =        THIS_MODULE,
-               .name =         "vivopay-serial",
-       },
-       .id_table =             id_table,
-       .num_ports =            1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-       &vivopay_serial_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-
-MODULE_AUTHOR("Forest Bond <forest.bond@outpostembedded.com>");
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/zio.c b/drivers/usb/serial/zio.c
deleted file mode 100644 (file)
index c043aa8..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * ZIO Motherboard USB driver
- *
- * Copyright (C) 2010 Zilogic Systems <code@zilogic.com>
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License version
- *     2 as published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-#include <linux/uaccess.h>
-
-static const struct usb_device_id id_table[] = {
-       { USB_DEVICE(0x1CBE, 0x0103) },
-       { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver zio_device = {
-       .driver = {
-               .owner =        THIS_MODULE,
-               .name =         "zio",
-       },
-       .id_table =             id_table,
-       .num_ports =            1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-       &zio_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-MODULE_LICENSE("GPL");
index 675384dabfe987f59d2e8678875e4801ceda488b..d771870a819e52ff23220490c80de43697c508f2 100644 (file)
@@ -43,20 +43,20 @@ const char *usb_otg_state_string(enum usb_otg_state state)
 }
 EXPORT_SYMBOL_GPL(usb_otg_state_string);
 
+static const char *const speed_names[] = {
+       [USB_SPEED_UNKNOWN] = "UNKNOWN",
+       [USB_SPEED_LOW] = "low-speed",
+       [USB_SPEED_FULL] = "full-speed",
+       [USB_SPEED_HIGH] = "high-speed",
+       [USB_SPEED_WIRELESS] = "wireless",
+       [USB_SPEED_SUPER] = "super-speed",
+};
+
 const char *usb_speed_string(enum usb_device_speed speed)
 {
-       static const char *const names[] = {
-               [USB_SPEED_UNKNOWN] = "UNKNOWN",
-               [USB_SPEED_LOW] = "low-speed",
-               [USB_SPEED_FULL] = "full-speed",
-               [USB_SPEED_HIGH] = "high-speed",
-               [USB_SPEED_WIRELESS] = "wireless",
-               [USB_SPEED_SUPER] = "super-speed",
-       };
-
-       if (speed < 0 || speed >= ARRAY_SIZE(names))
+       if (speed < 0 || speed >= ARRAY_SIZE(speed_names))
                speed = USB_SPEED_UNKNOWN;
-       return names[speed];
+       return speed_names[speed];
 }
 EXPORT_SYMBOL_GPL(usb_speed_string);
 
@@ -112,6 +112,33 @@ enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np)
        return USB_DR_MODE_UNKNOWN;
 }
 EXPORT_SYMBOL_GPL(of_usb_get_dr_mode);
+
+/**
+ * of_usb_get_maximum_speed - Get maximum requested speed for a given USB
+ * controller.
+ * @np: Pointer to the given device_node
+ *
+ * The function gets the maximum speed string from property "maximum-speed",
+ * and returns the corresponding enum usb_device_speed.
+ */
+enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np)
+{
+       const char *maximum_speed;
+       int err;
+       int i;
+
+       err = of_property_read_string(np, "maximum-speed", &maximum_speed);
+       if (err < 0)
+               return USB_SPEED_UNKNOWN;
+
+       for (i = 0; i < ARRAY_SIZE(speed_names); i++)
+               if (strcmp(maximum_speed, speed_names[i]) == 0)
+                       return i;
+
+       return USB_SPEED_UNKNOWN;
+}
+EXPORT_SYMBOL_GPL(of_usb_get_maximum_speed);
+
 #endif
 
 MODULE_LICENSE("GPL");
index 7ed3b039dbe878a8a7c7db038e6150c3395e5bec..ff97652343a34fdde446f981f14b01ec1c65280c 100644 (file)
@@ -325,9 +325,8 @@ retry:
                rv = skel_do_read_io(dev, count);
                if (rv < 0)
                        goto exit;
-               else if (!(file->f_flags & O_NONBLOCK))
+               else
                        goto retry;
-               rv = -EAGAIN;
        }
 exit:
        mutex_unlock(&dev->io_mutex);
index bdb0cc3046b5f598d5e6540155bcfea4982bc0f1..fe8bc777ab887bd1bc51d132eae33c669dffe394 100644 (file)
@@ -141,18 +141,26 @@ static int wusbhc_rh_port_reset(struct wusbhc *wusbhc, u8 port_idx)
 int wusbhc_rh_status_data(struct usb_hcd *usb_hcd, char *_buf)
 {
        struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       size_t cnt, size;
-       unsigned long *buf = (unsigned long *) _buf;
+       size_t cnt, size, bits_set = 0;
 
        /* WE DON'T LOCK, see comment */
-       size = wusbhc->ports_max + 1 /* hub bit */;
-       size = (size + 8 - 1) / 8;      /* round to bytes */
-       for (cnt = 0; cnt < wusbhc->ports_max; cnt++)
-               if (wusb_port_by_idx(wusbhc, cnt)->change)
-                       set_bit(cnt + 1, buf);
-               else
-                       clear_bit(cnt + 1, buf);
-       return size;
+       /* round up to bytes.  Hub bit is bit 0 so add 1. */
+       size = DIV_ROUND_UP(wusbhc->ports_max + 1, 8);
+
+       /* clear the output buffer. */
+       memset(_buf, 0, size);
+       /* set the bit for each changed port. */
+       for (cnt = 0; cnt < wusbhc->ports_max; cnt++) {
+
+               if (wusb_port_by_idx(wusbhc, cnt)->change) {
+                       const int bitpos = cnt+1;
+
+                       _buf[bitpos/8] |= (1 << (bitpos % 8));
+                       bits_set++;
+               }
+       }
+
+       return bits_set ? size : 0;
 }
 EXPORT_SYMBOL_GPL(wusbhc_rh_status_data);
 
index d6bea3e0b54a3c3493bb4b6106aad0d80c294770..cf250c21e946bcab938baafc6ca3f48ca2f1a2d3 100644 (file)
@@ -91,6 +91,7 @@
 struct wusbhc;
 struct wahc;
 extern void wa_urb_enqueue_run(struct work_struct *ws);
+extern void wa_process_errored_transfers_run(struct work_struct *ws);
 
 /**
  * RPipe instance
@@ -190,8 +191,14 @@ struct wahc {
 
        struct list_head xfer_list;
        struct list_head xfer_delayed_list;
+       struct list_head xfer_errored_list;
+       /*
+        * lock for the above xfer lists.  Can be taken while a xfer->lock is
+        * held but not in the reverse order.
+        */
        spinlock_t xfer_list_lock;
-       struct work_struct xfer_work;
+       struct work_struct xfer_enqueue_work;
+       struct work_struct xfer_error_work;
        atomic_t xfer_id_count;
 };
 
@@ -244,8 +251,10 @@ static inline void wa_init(struct wahc *wa)
        edc_init(&wa->dti_edc);
        INIT_LIST_HEAD(&wa->xfer_list);
        INIT_LIST_HEAD(&wa->xfer_delayed_list);
+       INIT_LIST_HEAD(&wa->xfer_errored_list);
        spin_lock_init(&wa->xfer_list_lock);
-       INIT_WORK(&wa->xfer_work, wa_urb_enqueue_run);
+       INIT_WORK(&wa->xfer_enqueue_work, wa_urb_enqueue_run);
+       INIT_WORK(&wa->xfer_error_work, wa_process_errored_transfers_run);
        atomic_set(&wa->xfer_id_count, 1);
 }
 
@@ -269,6 +278,8 @@ static inline void rpipe_put(struct wa_rpipe *rpipe)
 
 }
 extern void rpipe_ep_disable(struct wahc *, struct usb_host_endpoint *);
+extern void rpipe_clear_feature_stalled(struct wahc *,
+                       struct usb_host_endpoint *);
 extern int wa_rpipes_create(struct wahc *);
 extern void wa_rpipes_destroy(struct wahc *);
 static inline void rpipe_avail_dec(struct wa_rpipe *rpipe)
index 9a595c1ed867ddbe29fb1d4aa9995b025262eff7..fd4f1ce6256ac7a60fd2a9d5745e88b6f3c98d63 100644 (file)
@@ -527,3 +527,24 @@ void rpipe_ep_disable(struct wahc *wa, struct usb_host_endpoint *ep)
        mutex_unlock(&wa->rpipe_mutex);
 }
 EXPORT_SYMBOL_GPL(rpipe_ep_disable);
+
+/* Clear the stalled status of an RPIPE. */
+void rpipe_clear_feature_stalled(struct wahc *wa, struct usb_host_endpoint *ep)
+{
+       struct wa_rpipe *rpipe;
+
+       mutex_lock(&wa->rpipe_mutex);
+       rpipe = ep->hcpriv;
+       if (rpipe != NULL) {
+               u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex);
+
+               usb_control_msg(
+                       wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0),
+                       USB_REQ_CLEAR_FEATURE,
+                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
+                       RPIPE_STALL, index, NULL, 0, 1000);
+       }
+       mutex_unlock(&wa->rpipe_mutex);
+}
+EXPORT_SYMBOL_GPL(rpipe_clear_feature_stalled);
+
index d3493ca0525d4c727ed8d0fb86223fde6cb001e7..6ad02f57c366706e85ab4e3d03fa2d6cdc006a79 100644 (file)
@@ -125,10 +125,13 @@ struct wa_seg {
        u8 xfer_extra[];                /* xtra space for xfer_hdr_ctl */
 };
 
-static void wa_seg_init(struct wa_seg *seg)
+static inline void wa_seg_init(struct wa_seg *seg)
 {
-       /* usb_init_urb() repeats a lot of work, so we do it here */
-       kref_init(&seg->urb.kref);
+       usb_init_urb(&seg->urb);
+
+       /* set the remaining memory to 0. */
+       memset(((void *)seg) + sizeof(seg->urb), 0,
+               sizeof(*seg) - sizeof(seg->urb));
 }
 
 /*
@@ -166,8 +169,8 @@ static inline void wa_xfer_init(struct wa_xfer *xfer)
 /*
  * Destroy a transfer structure
  *
- * Note that the xfer->seg[index] thingies follow the URB life cycle,
- * so we need to put them, not free them.
+ * Note that freeing xfer->seg[cnt]->urb will free the containing
+ * xfer->seg[cnt] memory that was allocated by __wa_xfer_setup_segs.
  */
 static void wa_xfer_destroy(struct kref *_xfer)
 {
@@ -175,9 +178,8 @@ static void wa_xfer_destroy(struct kref *_xfer)
        if (xfer->seg) {
                unsigned cnt;
                for (cnt = 0; cnt < xfer->segs; cnt++) {
-                       if (xfer->is_inbound)
-                               usb_put_urb(xfer->seg[cnt]->dto_urb);
-                       usb_put_urb(&xfer->seg[cnt]->urb);
+                       usb_free_urb(xfer->seg[cnt]->dto_urb);
+                       usb_free_urb(&xfer->seg[cnt]->urb);
                }
        }
        kfree(xfer);
@@ -732,9 +734,9 @@ static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)
        buf_itr = 0;
        buf_size = xfer->urb->transfer_buffer_length;
        for (cnt = 0; cnt < xfer->segs; cnt++) {
-               seg = xfer->seg[cnt] = kzalloc(alloc_size, GFP_ATOMIC);
+               seg = xfer->seg[cnt] = kmalloc(alloc_size, GFP_ATOMIC);
                if (seg == NULL)
-                       goto error_seg_kzalloc;
+                       goto error_seg_kmalloc;
                wa_seg_init(seg);
                seg->xfer = xfer;
                seg->index = cnt;
@@ -804,15 +806,17 @@ static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)
        return 0;
 
 error_sg_alloc:
-       kfree(seg->dto_urb);
+       usb_free_urb(xfer->seg[cnt]->dto_urb);
 error_dto_alloc:
        kfree(xfer->seg[cnt]);
        cnt--;
-error_seg_kzalloc:
+error_seg_kmalloc:
        /* use the fact that cnt is left at were it failed */
        for (; cnt >= 0; cnt--) {
-               if (xfer->seg[cnt] && xfer->is_inbound == 0)
+               if (xfer->seg[cnt] && xfer->is_inbound == 0) {
                        usb_free_urb(xfer->seg[cnt]->dto_urb);
+                       kfree(xfer->seg[cnt]->dto_urb->sg);
+               }
                kfree(xfer->seg[cnt]);
        }
 error_segs_kzalloc:
@@ -928,7 +932,7 @@ static void wa_xfer_delayed_run(struct wa_rpipe *rpipe)
        spin_lock_irqsave(&rpipe->seg_lock, flags);
        while (atomic_read(&rpipe->segs_available) > 0
              && !list_empty(&rpipe->seg_list)) {
-               seg = list_entry(rpipe->seg_list.next, struct wa_seg,
+               seg = list_first_entry(&(rpipe->seg_list), struct wa_seg,
                                 list_node);
                list_del(&seg->list_node);
                xfer = seg->xfer;
@@ -1093,33 +1097,81 @@ error_xfer_submit:
  *
  * We need to be careful here, as dequeue() could be called in the
  * middle.  That's why we do the whole thing under the
- * wa->xfer_list_lock. If dequeue() jumps in, it first locks urb->lock
+ * wa->xfer_list_lock. If dequeue() jumps in, it first locks xfer->lock
  * and then checks the list -- so as we would be acquiring in inverse
- * order, we just drop the lock once we have the xfer and reacquire it
- * later.
+ * order, we move the delayed list to a separate list while locked and then
+ * submit them without the list lock held.
  */
 void wa_urb_enqueue_run(struct work_struct *ws)
 {
-       struct wahc *wa = container_of(ws, struct wahc, xfer_work);
+       struct wahc *wa = container_of(ws, struct wahc, xfer_enqueue_work);
        struct wa_xfer *xfer, *next;
        struct urb *urb;
+       LIST_HEAD(tmp_list);
 
+       /* Create a copy of the wa->xfer_delayed_list while holding the lock */
        spin_lock_irq(&wa->xfer_list_lock);
-       list_for_each_entry_safe(xfer, next, &wa->xfer_delayed_list,
-                                list_node) {
+       list_cut_position(&tmp_list, &wa->xfer_delayed_list,
+                       wa->xfer_delayed_list.prev);
+       spin_unlock_irq(&wa->xfer_list_lock);
+
+       /*
+        * enqueue from temp list without list lock held since wa_urb_enqueue_b
+        * can take xfer->lock as well as lock mutexes.
+        */
+       list_for_each_entry_safe(xfer, next, &tmp_list, list_node) {
                list_del_init(&xfer->list_node);
-               spin_unlock_irq(&wa->xfer_list_lock);
 
                urb = xfer->urb;
                wa_urb_enqueue_b(xfer);
                usb_put_urb(urb);       /* taken when queuing */
-
-               spin_lock_irq(&wa->xfer_list_lock);
        }
-       spin_unlock_irq(&wa->xfer_list_lock);
 }
 EXPORT_SYMBOL_GPL(wa_urb_enqueue_run);
 
+/*
+ * Process the errored transfers on the Wire Adapter outside of interrupt.
+ */
+void wa_process_errored_transfers_run(struct work_struct *ws)
+{
+       struct wahc *wa = container_of(ws, struct wahc, xfer_error_work);
+       struct wa_xfer *xfer, *next;
+       LIST_HEAD(tmp_list);
+
+       pr_info("%s: Run delayed STALL processing.\n", __func__);
+
+       /* Create a copy of the wa->xfer_errored_list while holding the lock */
+       spin_lock_irq(&wa->xfer_list_lock);
+       list_cut_position(&tmp_list, &wa->xfer_errored_list,
+                       wa->xfer_errored_list.prev);
+       spin_unlock_irq(&wa->xfer_list_lock);
+
+       /*
+        * run rpipe_clear_feature_stalled from temp list without list lock
+        * held.
+        */
+       list_for_each_entry_safe(xfer, next, &tmp_list, list_node) {
+               struct usb_host_endpoint *ep;
+               unsigned long flags;
+               struct wa_rpipe *rpipe;
+
+               spin_lock_irqsave(&xfer->lock, flags);
+               ep = xfer->ep;
+               rpipe = ep->hcpriv;
+               spin_unlock_irqrestore(&xfer->lock, flags);
+
+               /* clear RPIPE feature stalled without holding a lock. */
+               rpipe_clear_feature_stalled(wa, ep);
+
+               /* complete the xfer. This removes it from the tmp list. */
+               wa_xfer_completion(xfer);
+
+               /* check for work. */
+               wa_xfer_delayed_run(rpipe);
+       }
+}
+EXPORT_SYMBOL_GPL(wa_process_errored_transfers_run);
+
 /*
  * Submit a transfer to the Wire Adapter in a delayed way
  *
@@ -1175,7 +1227,7 @@ int wa_urb_enqueue(struct wahc *wa, struct usb_host_endpoint *ep,
                spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
                list_add_tail(&xfer->list_node, &wa->xfer_delayed_list);
                spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
-               queue_work(wusbd, &wa->xfer_work);
+               queue_work(wusbd, &wa->xfer_enqueue_work);
        } else {
                wa_urb_enqueue_b(xfer);
        }
@@ -1217,7 +1269,8 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb)
 
        xfer = urb->hcpriv;
        if (xfer == NULL) {
-               /* NOthing setup yet enqueue will see urb->status !=
+               /*
+                * Nothing setup yet enqueue will see urb->status !=
                 * -EINPROGRESS (by hcd layer) and bail out with
                 * error, no need to do completion
                 */
@@ -1361,7 +1414,7 @@ static int wa_xfer_status_to_errno(u8 status)
  *
  * inbound transfers: need to schedule a DTI read
  *
- * FIXME: this functio needs to be broken up in parts
+ * FIXME: this function needs to be broken up in parts
  */
 static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer)
 {
@@ -1483,17 +1536,37 @@ error_submit_buf_in:
        seg->result = result;
        kfree(wa->buf_in_urb->sg);
 error_sg_alloc:
+       __wa_xfer_abort(xfer);
 error_complete:
        seg->status = WA_SEG_ERROR;
        xfer->segs_done++;
        rpipe_ready = rpipe_avail_inc(rpipe);
-       __wa_xfer_abort(xfer);
        done = __wa_xfer_is_done(xfer);
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       if (done)
-               wa_xfer_completion(xfer);
-       if (rpipe_ready)
-               wa_xfer_delayed_run(rpipe);
+       /*
+        * queue work item to clear STALL for control endpoints.
+        * Otherwise, let endpoint_reset take care of it.
+        */
+       if (((usb_status & 0x3f) == WA_XFER_STATUS_HALTED) &&
+               usb_endpoint_xfer_control(&xfer->ep->desc) &&
+               done) {
+
+               dev_info(dev, "Control EP stall.  Queue delayed work.\n");
+               spin_lock_irq(&wa->xfer_list_lock);
+               /* remove xfer from xfer_list. */
+               list_del(&xfer->list_node);
+               /* add xfer to xfer_errored_list. */
+               list_add_tail(&xfer->list_node, &wa->xfer_errored_list);
+               spin_unlock_irq(&wa->xfer_list_lock);
+               spin_unlock_irqrestore(&xfer->lock, flags);
+               queue_work(wusbd, &wa->xfer_error_work);
+       } else {
+               spin_unlock_irqrestore(&xfer->lock, flags);
+               if (done)
+                       wa_xfer_completion(xfer);
+               if (rpipe_ready)
+                       wa_xfer_delayed_run(rpipe);
+       }
+
        return;
 
 error_bad_seg:
index 0621abef9b4a0e2ecb1291eda1650f7529a64d8c..0257f35cfb9d01983fa738358b54f4b600af568c 100644 (file)
@@ -611,7 +611,16 @@ static
 int hwarc_reset(struct uwb_rc *uwb_rc)
 {
        struct hwarc *hwarc = uwb_rc->priv;
-       return usb_reset_device(hwarc->usb_dev);
+       int result;
+
+       /* device lock must be held when calling usb_reset_device. */
+       result = usb_lock_device_for_reset(hwarc->usb_dev, NULL);
+       if (result >= 0) {
+               result = usb_reset_device(hwarc->usb_dev);
+               usb_unlock_device(hwarc->usb_dev);
+       }
+
+       return result;
 }
 
 /**
@@ -709,8 +718,10 @@ static int hwarc_neep_init(struct uwb_rc *rc)
 
 error_neep_submit:
        usb_free_urb(hwarc->neep_urb);
+       hwarc->neep_urb = NULL;
 error_urb_alloc:
        free_page((unsigned long)hwarc->rd_buffer);
+       hwarc->rd_buffer = NULL;
 error_rd_buffer:
        return -ENOMEM;
 }
@@ -723,7 +734,10 @@ static void hwarc_neep_release(struct uwb_rc *rc)
 
        usb_kill_urb(hwarc->neep_urb);
        usb_free_urb(hwarc->neep_urb);
+       hwarc->neep_urb = NULL;
+
        free_page((unsigned long)hwarc->rd_buffer);
+       hwarc->rd_buffer = NULL;
 }
 
 /**
index 690577d2a35bf3494f3e9886c7f9ca4fd21fb17c..c1304b8d498530124c7ca30319c12cc823e84d6e 100644 (file)
@@ -68,8 +68,40 @@ int uwb_pal_register(struct uwb_pal *pal)
 }
 EXPORT_SYMBOL_GPL(uwb_pal_register);
 
+static int find_rc(struct device *dev, const void *data)
+{
+       const struct uwb_rc *target_rc = data;
+       struct uwb_rc *rc = dev_get_drvdata(dev);
+
+       if (rc == NULL) {
+               WARN_ON(1);
+               return 0;
+       }
+       if (rc == target_rc) {
+               if (rc->ready == 0)
+                       return 0;
+               else
+                       return 1;
+       }
+       return 0;
+}
+
+/**
+ * Given a radio controller descriptor see if it is registered.
+ *
+ * @returns false if the rc does not exist or is quiescing; true otherwise.
+ */
+static bool uwb_rc_class_device_exists(struct uwb_rc *target_rc)
+{
+       struct device *dev;
+
+       dev = class_find_device(&uwb_rc_class, NULL, target_rc, find_rc);
+
+       return (dev != NULL);
+}
+
 /**
- * uwb_pal_register - unregister a UWB PAL
+ * uwb_pal_unregister - unregister a UWB PAL
  * @pal: the PAL
  */
 void uwb_pal_unregister(struct uwb_pal *pal)
@@ -85,7 +117,11 @@ void uwb_pal_unregister(struct uwb_pal *pal)
        debugfs_remove(pal->debugfs_dir);
 
        if (pal->device) {
-               sysfs_remove_link(&rc->uwb_dev.dev.kobj, pal->name);
+               /* remove link to the PAL in the UWB device's directory. */
+               if (uwb_rc_class_device_exists(rc))
+                       sysfs_remove_link(&rc->uwb_dev.dev.kobj, pal->name);
+
+               /* remove link to uwb_rc in the PAL device's directory. */
                sysfs_remove_link(&pal->device->kobj, "uwb_rc");
        }
 }
diff --git a/include/linux/platform_data/tegra_usb.h b/include/linux/platform_data/tegra_usb.h
deleted file mode 100644 (file)
index 66c673f..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2010 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
-
-#ifndef _TEGRA_USB_H_
-#define _TEGRA_USB_H_
-
-enum tegra_usb_operating_modes {
-       TEGRA_USB_DEVICE,
-       TEGRA_USB_HOST,
-       TEGRA_USB_OTG,
-};
-
-struct tegra_ehci_platform_data {
-       enum tegra_usb_operating_modes operating_mode;
-       /* power down the phy on bus suspend */
-       int power_down_on_bus_suspend;
-       void *phy_config;
-       int vbus_gpio;
-};
-
-#endif /* _TEGRA_USB_H_ */
index 0eec2689b9556bee0c3aae530a3035ccbbe29d2a..001629cd1a97b831f2eb448013c114b3a76f0de7 100644 (file)
@@ -337,6 +337,7 @@ struct usb_bus {
                                         * the ep queue on a short transfer
                                         * with the URB_SHORT_NOT_OK flag set.
                                         */
+       unsigned no_sg_constraint:1;    /* no sg constraint */
        unsigned sg_tablesize;          /* 0 or largest number of sg list entries */
 
        int devnum_next;                /* Next open device number in
@@ -684,6 +685,11 @@ static inline bool usb_device_supports_ltm(struct usb_device *udev)
        return udev->bos->ss_cap->bmAttributes & USB_LTM_SUPPORT;
 }
 
+static inline bool usb_device_no_sg_constraint(struct usb_device *udev)
+{
+       return udev && udev->bus && udev->bus->no_sg_constraint;
+}
+
 
 /*-------------------------------------------------------------------------*/
 
@@ -708,7 +714,10 @@ extern int usb_driver_claim_interface(struct usb_driver *driver,
  * usb_interface_claimed - returns true iff an interface is claimed
  * @iface: the interface being checked
  *
- * Returns true (nonzero) iff the interface is claimed, else false (zero).
+ * Return: %true (nonzero) iff the interface is claimed, else %false
+ * (zero).
+ *
+ * Note:
  * Callers must own the driver model's usb bus readlock.  So driver
  * probe() entries don't need extra locking, but other call contexts
  * may need to explicitly claim that lock.
@@ -745,8 +754,9 @@ extern struct usb_host_interface *usb_find_alt_setting(
  * @buf: where to put the string
  * @size: how big is "buf"?
  *
- * Returns length of the string (> 0) or negative if size was too small.
+ * Return: Length of the string (> 0) or negative if size was too small.
  *
+ * Note:
  * This identifier is intended to be "stable", reflecting physical paths in
  * hardware such as physical bus addresses for host controllers or ports on
  * USB hubs.  That makes it stay the same until systems are physically
@@ -1247,7 +1257,9 @@ typedef void (*usb_complete_t)(struct urb *);
  *     the device driver is saying that it provided this DMA address,
  *     which the host controller driver should use in preference to the
  *     transfer_buffer.
- * @sg: scatter gather buffer list
+ * @sg: scatter gather buffer list, the buffer size of each element in
+ *     the list (except the last) must be divisible by the endpoint's
+ *     max packet size if no_sg_constraint isn't set in 'struct usb_bus'
  * @num_mapped_sgs: (internal) number of mapped sg entries
  * @num_sgs: number of entries in the sg list
  * @transfer_buffer_length: How big is transfer_buffer.  The transfer may
@@ -1534,10 +1546,16 @@ static inline void usb_fill_int_urb(struct urb *urb,
        urb->transfer_buffer_length = buffer_length;
        urb->complete = complete_fn;
        urb->context = context;
-       if (dev->speed == USB_SPEED_HIGH || dev->speed == USB_SPEED_SUPER)
+
+       if (dev->speed == USB_SPEED_HIGH || dev->speed == USB_SPEED_SUPER) {
+               /* make sure interval is within allowed range */
+               interval = clamp(interval, 1, 16);
+
                urb->interval = 1 << (interval - 1);
-       else
+       } else {
                urb->interval = interval;
+       }
+
        urb->start_frame = -1;
 }
 
@@ -1570,7 +1588,7 @@ extern int usb_anchor_empty(struct usb_anchor *anchor);
  * usb_urb_dir_in - check if an URB describes an IN transfer
  * @urb: URB to be checked
  *
- * Returns 1 if @urb describes an IN transfer (device-to-host),
+ * Return: 1 if @urb describes an IN transfer (device-to-host),
  * otherwise 0.
  */
 static inline int usb_urb_dir_in(struct urb *urb)
@@ -1582,7 +1600,7 @@ static inline int usb_urb_dir_in(struct urb *urb)
  * usb_urb_dir_out - check if an URB describes an OUT transfer
  * @urb: URB to be checked
  *
- * Returns 1 if @urb describes an OUT transfer (host-to-device),
+ * Return: 1 if @urb describes an OUT transfer (host-to-device),
  * otherwise 0.
  */
 static inline int usb_urb_dir_out(struct urb *urb)
index 25629948c84280a67cb304b707013bc9f383b503..7d399671a566ac58afbb3fd17991eb40b069f76d 100644 (file)
@@ -18,12 +18,17 @@ struct ci_hdrc_platform_data {
        unsigned long    flags;
 #define CI_HDRC_REGS_SHARED            BIT(0)
 #define CI_HDRC_REQUIRE_TRANSCEIVER    BIT(1)
-#define CI_HDRC_PULLUP_ON_VBUS         BIT(2)
 #define CI_HDRC_DISABLE_STREAMING      BIT(3)
+       /*
+        * Only set it when DCCPARAMS.DC==1 and DCCPARAMS.HC==1,
+        * but otg is not supported (no register otgsc).
+        */
+#define CI_HDRC_DUAL_ROLE_NOT_OTG      BIT(4)
        enum usb_dr_mode        dr_mode;
 #define CI_HDRC_CONTROLLER_RESET_EVENT         0
 #define CI_HDRC_CONTROLLER_STOPPED_EVENT       1
        void    (*notify_event) (struct ci_hdrc *ci, unsigned event);
+       struct regulator        *reg_vbus;
 };
 
 /* Default offset of capability registers */
index f1b0dca60f127116113361da7ff61d726d0fa26a..942ef5e053bf37e7104ef3bc68e551509faa9aa4 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/slab.h>
 #include <linux/scatterlist.h>
 #include <linux/types.h>
+#include <linux/workqueue.h>
 #include <linux/usb/ch9.h>
 
 struct usb_ep;
@@ -475,6 +476,7 @@ struct usb_gadget_ops {
 
 /**
  * struct usb_gadget - represents a usb slave device
+ * @work: (internal use) Workqueue to be used for sysfs_notify()
  * @ops: Function pointers used to access hardware-specific operations.
  * @ep0: Endpoint zero, used when reading or writing responses to
  *     driver setup() requests
@@ -520,6 +522,7 @@ struct usb_gadget_ops {
  * device is acting as a B-Peripheral (so is_a_peripheral is false).
  */
 struct usb_gadget {
+       struct work_struct              work;
        /* readonly to gadget driver */
        const struct usb_gadget_ops     *ops;
        struct usb_ep                   *ep0;
@@ -538,6 +541,7 @@ struct usb_gadget {
        unsigned                        out_epnum;
        unsigned                        in_epnum;
 };
+#define work_to_gadget(w)      (container_of((w), struct usb_gadget, work))
 
 static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
        { dev_set_drvdata(&gadget->dev, data); }
index 1e88377e22f4fd6e2bec2be90df8b07eba5d89fc..a9c7d44bd2edda3ca14863dd1b5962470d50707b 100644 (file)
@@ -22,6 +22,7 @@
 #ifdef __KERNEL__
 
 #include <linux/rwsem.h>
+#include <linux/interrupt.h>
 
 #define MAX_TOPO_LEVEL         6
 
 
 /*-------------------------------------------------------------------------*/
 
+struct giveback_urb_bh {
+       bool running;
+       spinlock_t lock;
+       struct list_head  head;
+       struct tasklet_struct bh;
+};
+
 struct usb_hcd {
 
        /*
@@ -139,6 +147,9 @@ struct usb_hcd {
        resource_size_t         rsrc_len;       /* memory/io resource length */
        unsigned                power_budget;   /* in mA, 0 = no limit */
 
+       struct giveback_urb_bh  high_prio_bh;
+       struct giveback_urb_bh  low_prio_bh;
+
        /* bandwidth_mutex should be taken before adding or removing
         * any new bus bandwidth constraints:
         *   1. Before adding a configuration for a new device.
@@ -221,6 +232,7 @@ struct hc_driver {
 #define        HCD_USB25       0x0030          /* Wireless USB 1.0 (USB 2.5)*/
 #define        HCD_USB3        0x0040          /* USB 3.0 */
 #define        HCD_MASK        0x0070
+#define        HCD_BH          0x0100          /* URB complete in BH context */
 
        /* called to init HCD and root hub */
        int     (*reset) (struct usb_hcd *hcd);
@@ -361,6 +373,11 @@ struct hc_driver {
        int     (*find_raw_port_number)(struct usb_hcd *, int);
 };
 
+static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)
+{
+       return hcd->driver->flags & HCD_BH;
+}
+
 extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
 extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
                int status);
diff --git a/include/linux/usb/nop-usb-xceiv.h b/include/linux/usb/nop-usb-xceiv.h
deleted file mode 100644 (file)
index 148d351..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __LINUX_USB_NOP_XCEIV_H
-#define __LINUX_USB_NOP_XCEIV_H
-
-#include <linux/usb/otg.h>
-
-struct nop_usb_xceiv_platform_data {
-       enum usb_phy_type type;
-       unsigned long clk_rate;
-
-       /* if set fails with -EPROBE_DEFER if can't get regulator */
-       unsigned int needs_vcc:1;
-       unsigned int needs_reset:1;
-};
-
-#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE))
-/* sometimes transceivers are accessed only through e.g. ULPI */
-extern void usb_nop_xceiv_register(void);
-extern void usb_nop_xceiv_unregister(void);
-#else
-static inline void usb_nop_xceiv_register(void)
-{
-}
-
-static inline void usb_nop_xceiv_unregister(void)
-{
-}
-#endif
-
-#endif /* __LINUX_USB_NOP_XCEIV_H */
index a0ef405368b8ab2edbb62d228fafe1e00c3c4871..8c38aa26b3bb6dba5a1ef37b6104d701cc03fcdb 100644 (file)
@@ -7,19 +7,27 @@
 #ifndef __LINUX_USB_OF_H
 #define __LINUX_USB_OF_H
 
+#include <linux/usb/ch9.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/phy.h>
 
 #if IS_ENABLED(CONFIG_OF)
 enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np);
+enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np);
 #else
 static inline enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np)
 {
        return USB_DR_MODE_UNKNOWN;
 }
+
+static inline enum usb_device_speed
+of_usb_get_maximum_speed(struct device_node *np)
+{
+       return USB_SPEED_UNKNOWN;
+}
 #endif
 
-#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_PHY)
+#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_SUPPORT)
 enum usb_phy_interface of_usb_get_phy_mode(struct device_node *np);
 #else
 static inline enum usb_phy_interface of_usb_get_phy_mode(struct device_node *np)
index 44036808bf0fdd1c2d9fd126ad2616536d3f23a1..6c0b1c513db72ce9632396223ed99aca20ff3efb 100644 (file)
@@ -142,7 +142,7 @@ extern void usb_remove_phy(struct usb_phy *);
 /* helpers for direct access thru low-level io interface */
 static inline int usb_phy_io_read(struct usb_phy *x, u32 reg)
 {
-       if (x->io_ops && x->io_ops->read)
+       if (x && x->io_ops && x->io_ops->read)
                return x->io_ops->read(x, reg);
 
        return -EINVAL;
@@ -150,7 +150,7 @@ static inline int usb_phy_io_read(struct usb_phy *x, u32 reg)
 
 static inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg)
 {
-       if (x->io_ops && x->io_ops->write)
+       if (x && x->io_ops && x->io_ops->write)
                return x->io_ops->write(x, val, reg);
 
        return -EINVAL;
@@ -159,7 +159,7 @@ static inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg)
 static inline int
 usb_phy_init(struct usb_phy *x)
 {
-       if (x->init)
+       if (x && x->init)
                return x->init(x);
 
        return 0;
@@ -168,14 +168,14 @@ usb_phy_init(struct usb_phy *x)
 static inline void
 usb_phy_shutdown(struct usb_phy *x)
 {
-       if (x->shutdown)
+       if (x && x->shutdown)
                x->shutdown(x);
 }
 
 static inline int
 usb_phy_vbus_on(struct usb_phy *x)
 {
-       if (!x->set_vbus)
+       if (!x || !x->set_vbus)
                return 0;
 
        return x->set_vbus(x, true);
@@ -184,7 +184,7 @@ usb_phy_vbus_on(struct usb_phy *x)
 static inline int
 usb_phy_vbus_off(struct usb_phy *x)
 {
-       if (!x->set_vbus)
+       if (!x || !x->set_vbus)
                return 0;
 
        return x->set_vbus(x, false);
@@ -258,7 +258,7 @@ usb_phy_set_power(struct usb_phy *x, unsigned mA)
 static inline int
 usb_phy_set_suspend(struct usb_phy *x, int suspend)
 {
-       if (x->set_suspend != NULL)
+       if (x && x->set_suspend != NULL)
                return x->set_suspend(x, suspend);
        else
                return 0;
@@ -267,7 +267,7 @@ usb_phy_set_suspend(struct usb_phy *x, int suspend)
 static inline int
 usb_phy_notify_connect(struct usb_phy *x, enum usb_device_speed speed)
 {
-       if (x->notify_connect)
+       if (x && x->notify_connect)
                return x->notify_connect(x, speed);
        else
                return 0;
@@ -276,7 +276,7 @@ usb_phy_notify_connect(struct usb_phy *x, enum usb_device_speed speed)
 static inline int
 usb_phy_notify_disconnect(struct usb_phy *x, enum usb_device_speed speed)
 {
-       if (x->notify_disconnect)
+       if (x && x->notify_disconnect)
                return x->notify_disconnect(x, speed);
        else
                return 0;
index d2ca919a5b738387b28293918ce9d2e47ccc053c..1de16c324ec88698d3b9bfc1d7242d915ca506a8 100644 (file)
 #include <linux/clk.h>
 #include <linux/usb/otg.h>
 
+/*
+ * utmi_pll_config_in_car_module: true if the UTMI PLL configuration registers
+ *     should be set up by clk-tegra, false if by the PHY code
+ * has_hostpc: true if the USB controller has the HOSTPC extension, which
+ *     changes the location of the PHCD and PTS fields
+ * requires_usbmode_setup: true if the USBMODE register needs to be set to
+ *      enter host mode
+ * requires_extra_tuning_parameters: true if xcvr_hsslew, hssquelch_level
+ *      and hsdiscon_level should be set for adequate signal quality
+ */
+
+struct tegra_phy_soc_config {
+       bool utmi_pll_config_in_car_module;
+       bool has_hostpc;
+       bool requires_usbmode_setup;
+       bool requires_extra_tuning_parameters;
+};
+
 struct tegra_utmip_config {
        u8 hssync_start_delay;
        u8 elastic_limit;
        u8 idle_wait_delay;
        u8 term_range_adj;
+       bool xcvr_setup_use_fuses;
        u8 xcvr_setup;
        u8 xcvr_lsfslew;
        u8 xcvr_lsrslew;
-};
-
-struct tegra_ulpi_config {
-       int reset_gpio;
-       const char *clk;
+       u8 xcvr_hsslew;
+       u8 hssquelch_level;
+       u8 hsdiscon_level;
 };
 
 enum tegra_usb_phy_port_speed {
@@ -39,12 +56,6 @@ enum tegra_usb_phy_port_speed {
        TEGRA_USB_PHY_PORT_SPEED_HIGH,
 };
 
-enum tegra_usb_phy_mode {
-       TEGRA_USB_PHY_MODE_DEVICE,
-       TEGRA_USB_PHY_MODE_HOST,
-       TEGRA_USB_PHY_MODE_OTG,
-};
-
 struct tegra_xtal_freq;
 
 struct tegra_usb_phy {
@@ -55,18 +66,17 @@ struct tegra_usb_phy {
        struct clk *clk;
        struct clk *pll_u;
        struct clk *pad_clk;
-       enum tegra_usb_phy_mode mode;
+       struct regulator *vbus;
+       enum usb_dr_mode mode;
        void *config;
+       const struct tegra_phy_soc_config *soc_config;
        struct usb_phy *ulpi;
        struct usb_phy u_phy;
-       struct device *dev;
        bool is_legacy_phy;
        bool is_ulpi_phy;
        int reset_gpio;
 };
 
-struct usb_phy *tegra_usb_get_phy(struct device_node *dn);
-
 void tegra_usb_phy_preresume(struct usb_phy *phy);
 
 void tegra_usb_phy_postresume(struct usb_phy *phy);
diff --git a/include/linux/usb/usb_phy_gen_xceiv.h b/include/linux/usb/usb_phy_gen_xceiv.h
new file mode 100644 (file)
index 0000000..f9a7e7b
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __LINUX_USB_NOP_XCEIV_H
+#define __LINUX_USB_NOP_XCEIV_H
+
+#include <linux/usb/otg.h>
+
+struct usb_phy_gen_xceiv_platform_data {
+       enum usb_phy_type type;
+       unsigned long clk_rate;
+
+       /* if set fails with -EPROBE_DEFER if can't get regulator */
+       unsigned int needs_vcc:1;
+       unsigned int needs_reset:1;
+};
+
+#if IS_ENABLED(CONFIG_NOP_USB_XCEIV)
+/* sometimes transceivers are accessed only through e.g. ULPI */
+extern void usb_nop_xceiv_register(void);
+extern void usb_nop_xceiv_unregister(void);
+#else
+static inline void usb_nop_xceiv_register(void)
+{
+}
+
+static inline void usb_nop_xceiv_unregister(void)
+{
+}
+#endif
+
+#endif /* __LINUX_USB_NOP_XCEIV_H */
index f18d64129f99982f966f3c2fe733cd85260dc625..2b47e6364e3697ff1fbd684b923da5cd6ec65e82 100644 (file)
@@ -34,6 +34,7 @@ struct usbnet {
        struct mutex            phy_mutex;
        unsigned char           suspend_count;
        unsigned char           pkt_cnt, pkt_err;
+       unsigned                can_dma_sg:1;
 
        /* i/o info: pipes etc */
        unsigned                in, out;
index 6be985b2a4342fc7ebabc1df2245cb3460aa71cb..4ff744e2b678a27f051649b86f1c8ee4eb8210d1 100644 (file)
@@ -66,6 +66,7 @@ enum {
        WA_ENABLE = 0x01,
        WA_RESET = 0x02,
        RPIPE_PAUSE = 0x1,
+       RPIPE_STALL = 0x2,
 };
 
 /* Responses from Get Status request ([WUSB] section 8.3.1.6) */