Merge 5.10-rc7 into usb-next
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 7 Dec 2020 09:20:51 +0000 (10:20 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 7 Dec 2020 09:20:51 +0000 (10:20 +0100)
We want the USB fixes in here as well.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
82 files changed:
Documentation/ABI/testing/sysfs-class-typec
Documentation/devicetree/bindings/connector/usb-connector.yaml
Documentation/devicetree/bindings/usb/brcm,usb-pinmap.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/usb/maxim,max33359.yaml [new file with mode: 0644]
MAINTAINERS
arch/arm/mach-omap1/board-h2.c
drivers/platform/chrome/cros_ec_typec.c
drivers/usb/Makefile
drivers/usb/atm/usbatm.c
drivers/usb/common/ulpi.c
drivers/usb/core/buffer.c
drivers/usb/core/config.c
drivers/usb/core/endpoint.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/port.c
drivers/usb/core/sysfs.c
drivers/usb/core/usb.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_loopback.c
drivers/usb/gadget/function/f_sourcesink.c
drivers/usb/gadget/udc/core.c
drivers/usb/gadget/udc/dummy_hcd.c
drivers/usb/gadget/udc/pxa27x_udc.c
drivers/usb/host/Kconfig
drivers/usb/host/Makefile
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-mxc.c [deleted file]
drivers/usb/host/ehci-pmcmsp.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/fotg210-hcd.c
drivers/usb/host/imx21-dbg.c [deleted file]
drivers/usb/host/imx21-hcd.c [deleted file]
drivers/usb/host/imx21-hcd.h [deleted file]
drivers/usb/host/isp116x-hcd.c
drivers/usb/host/isp1362.h
drivers/usb/host/max3421-hcd.c
drivers/usb/host/ohci-at91.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-hub.c
drivers/usb/host/ohci-omap.c
drivers/usb/host/ohci-pxa27x.c
drivers/usb/host/ohci-s3c2410.c
drivers/usb/host/oxu210hp-hcd.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/misc/Kconfig
drivers/usb/misc/Makefile
drivers/usb/misc/apple-mfi-fastcharge.c
drivers/usb/misc/brcmstb-usb-pinmap.c [new file with mode: 0644]
drivers/usb/misc/iowarrior.c
drivers/usb/misc/sisusbvga/Kconfig
drivers/usb/misc/yurex.c
drivers/usb/mtu3/mtu3_debug.h
drivers/usb/musb/tusb6010.c
drivers/usb/phy/phy-isp1301-omap.c
drivers/usb/storage/ene_ub6250.c
drivers/usb/storage/freecom.c
drivers/usb/storage/transport.c
drivers/usb/storage/uas.c
drivers/usb/typec/class.c
drivers/usb/typec/mux/intel_pmc_mux.c
drivers/usb/typec/tcpm/tcpci.c
drivers/usb/typec/tcpm/tcpci.h
drivers/usb/typec/tcpm/tcpci_maxim.c
drivers/usb/typec/tcpm/tcpm.c
drivers/usb/typec/ucsi/ucsi.c
drivers/usb/typec/ucsi/ucsi.h
drivers/usb/typec/ucsi/ucsi_acpi.c
drivers/usb/usbip/usbip_common.c
include/dt-bindings/usb/pd.h
include/linux/platform_data/usb-ehci-mxc.h [deleted file]
include/linux/usb/hcd.h
include/linux/usb/pd.h
include/linux/usb/pd_vdo.h
include/linux/usb/tcpm.h
include/linux/usb/typec.h
include/linux/usb/typec_tbt.h

index b7794e0..8eab41e 100644 (file)
@@ -139,6 +139,49 @@ Description:
                Shows if the partner supports USB Power Delivery communication:
                Valid values: yes, no
 
+What:          /sys/class/typec/<port>-partner/number_of_alternate_modes
+Date:          November 2020
+Contact:       Prashant Malani <pmalani@chromium.org>
+Description:
+               Shows the number of alternate modes which are advertised by the partner
+               during Power Delivery discovery. This file remains hidden until a value
+               greater than or equal to 0 is set by Type C port driver.
+
+What:          /sys/class/typec/<port>-partner/type
+Date:          December 2020
+Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Description:   USB Power Delivery Specification defines a set of product types
+               for the partner devices. This file will show the product type of
+               the partner if it is known. Dual-role capable partners will have
+               both UFP and DFP product types defined, but only one that
+               matches the current role will be active at the time. If the
+               product type of the partner is not visible to the device driver,
+               this file will not exist.
+
+               When the partner product type is detected, or changed with role
+               swap, uvevent is also raised that contains PRODUCT_TYPE=<product
+               type> (for example PRODUCT_TYPE=hub).
+
+               Valid values:
+
+               UFP / device role
+               ======================  ==========================
+               undefined               -
+               hub                     PDUSB Hub
+               peripheral              PDUSB Peripheral
+               psd                     Power Bank
+               ama                     Alternate Mode Adapter
+               ======================  ==========================
+
+               DFP / host role
+               ======================  ==========================
+               undefined               -
+               hub                     PDUSB Hub
+               host                    PDUSB Host
+               power_brick             Power Brick
+               amc                     Alternate Mode Controller
+               ======================  ==========================
+
 What:          /sys/class/typec/<port>-partner>/identity/
 Date:          April 2017
 Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
@@ -151,31 +194,6 @@ Description:
                directory exists, it will have an attribute file for every VDO
                in Discover Identity command result.
 
-What:          /sys/class/typec/<port>-partner/identity/id_header
-Date:          April 2017
-Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
-Description:
-               ID Header VDO part of Discover Identity command result. The
-               value will show 0 until Discover Identity command result becomes
-               available. The value can be polled.
-
-What:          /sys/class/typec/<port>-partner/identity/cert_stat
-Date:          April 2017
-Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
-Description:
-               Cert Stat VDO part of Discover Identity command result. The
-               value will show 0 until Discover Identity command result becomes
-               available. The value can be polled.
-
-What:          /sys/class/typec/<port>-partner/identity/product
-Date:          April 2017
-Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
-Description:
-               Product VDO part of Discover Identity command result. The value
-               will show 0 until Discover Identity command result becomes
-               available. The value can be polled.
-
-
 USB Type-C cable devices (eg. /sys/class/typec/port0-cable/)
 
 Note: Electronically Marked Cables will have a device also for one cable plug
@@ -187,9 +205,21 @@ described in USB Type-C and USB Power Delivery specifications.
 What:          /sys/class/typec/<port>-cable/type
 Date:          April 2017
 Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
-Description:
-               Shows if the cable is active.
-               Valid values: active, passive
+Description:   USB Power Delivery Specification defines a set of product types
+               for the cables. This file will show the product type of the
+               cable if it is known. If the product type of the cable is not
+               visible to the device driver, this file will not exist.
+
+               When the cable product type is detected, uvevent is also raised
+               with PRODUCT_TYPE showing the product type of the cable.
+
+               Valid values:
+
+               ======================  ==========================
+               undefined               -
+               active                  Active Cable
+               passive                 Passive Cable
+               ======================  ==========================
 
 What:          /sys/class/typec/<port>-cable/plug_type
 Date:          April 2017
@@ -202,17 +232,37 @@ Description:
                - type-c
                - captive
 
-What:          /sys/class/typec/<port>-cable/identity/
+What:          /sys/class/typec/<port>-<plug>/number_of_alternate_modes
+Date:          November 2020
+Contact:       Prashant Malani <pmalani@chromium.org>
+Description:
+               Shows the number of alternate modes which are advertised by the plug
+               associated with a particular cable during Power Delivery discovery.
+               This file remains hidden until a value greater than or equal to 0
+               is set by Type C port driver.
+
+
+USB Type-C partner/cable Power Delivery Identity objects
+
+NOTE: The following attributes will be applicable to both
+partner (e.g /sys/class/typec/port0-partner/) and
+cable (e.g /sys/class/typec/port0-cable/) devices. Consequently, the example file
+paths below are prefixed with "/sys/class/typec/<port>-{partner|cable}/" to
+reflect this.
+
+What:          /sys/class/typec/<port>-{partner|cable}/identity/
 Date:          April 2017
 Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
 Description:
                This directory appears only if the port device driver is capable
                of showing the result of Discover Identity USB power delivery
                command. That will not always be possible even when USB power
-               delivery is supported. If the directory exists, it will have an
-               attribute for every VDO returned by Discover Identity command.
+               delivery is supported, for example when USB power delivery
+               communication for the port is mostly handled in firmware. If the
+               directory exists, it will have an attribute file for every VDO
+               in Discover Identity command result.
 
-What:          /sys/class/typec/<port>-cable/identity/id_header
+What:          /sys/class/typec/<port>-{partner|cable}/identity/id_header
 Date:          April 2017
 Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
 Description:
@@ -220,7 +270,7 @@ Description:
                value will show 0 until Discover Identity command result becomes
                available. The value can be polled.
 
-What:          /sys/class/typec/<port>-cable/identity/cert_stat
+What:          /sys/class/typec/<port>-{partner|cable}/identity/cert_stat
 Date:          April 2017
 Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
 Description:
@@ -228,7 +278,7 @@ Description:
                value will show 0 until Discover Identity command result becomes
                available. The value can be polled.
 
-What:          /sys/class/typec/<port>-cable/identity/product
+What:          /sys/class/typec/<port>-{partner|cable}/identity/product
 Date:          April 2017
 Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
 Description:
@@ -236,6 +286,30 @@ Description:
                will show 0 until Discover Identity command result becomes
                available. The value can be polled.
 
+What:          /sys/class/typec/<port>-{partner|cable}/identity/product_type_vdo1
+Date:          October 2020
+Contact:       Prashant Malani <pmalani@chromium.org>
+Description:
+               1st Product Type VDO of Discover Identity command result.
+               The value will show 0 until Discover Identity command result becomes
+               available and a valid Product Type VDO is returned.
+
+What:          /sys/class/typec/<port>-{partner|cable}/identity/product_type_vdo2
+Date:          October 2020
+Contact:       Prashant Malani <pmalani@chromium.org>
+Description:
+               2nd Product Type VDO of Discover Identity command result.
+               The value will show 0 until Discover Identity command result becomes
+               available and a valid Product Type VDO is returned.
+
+What:          /sys/class/typec/<port>-{partner|cable}/identity/product_type_vdo3
+Date:          October 2020
+Contact:       Prashant Malani <pmalani@chromium.org>
+Description:
+               3rd Product Type VDO of Discover Identity command result.
+               The value will show 0 until Discover Identity command result becomes
+               available and a valid Product Type VDO is returned.
+
 
 USB Type-C port alternate mode devices.
 
index 728f82d..6278151 100644 (file)
@@ -147,6 +147,25 @@ properties:
     required:
       - port@0
 
+  new-source-frs-typec-current:
+    description: Initial current capability of the new source when vSafe5V
+      is applied during PD3.0 Fast Role Swap. "Table 6-14 Fixed Supply PDO - Sink"
+      of "USB Power Delivery Specification Revision 3.0, Version 1.2" provides the
+      different power levels and "6.4.1.3.1.6 Fast Role Swap USB Type-C Current"
+      provides a detailed description of the field. The sink PDO from current source
+      reflects the current source's(i.e. transmitter of the FRS signal) power
+      requirement during fr swap. The current sink (i.e. receiver of the FRS signal),
+      a.k.a new source, should check if it will be able to satisfy the current source's,
+      new sink's, requirement during frswap before enabling the frs signal reception.
+      This property refers to maximum current capability that the current sink can
+      satisfy. During FRS, VBUS voltage is at 5V, as the partners are in implicit
+      contract, hence, the power level is only a function of the current capability.
+      "1" refers to default USB power level as described by "Table 6-14 Fixed Supply PDO - Sink".
+      "2" refers to 1.5A@5V.
+      "3" refers to 3.0A@5V.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [1, 2, 3]
+
 required:
   - compatible
 
diff --git a/Documentation/devicetree/bindings/usb/brcm,usb-pinmap.yaml b/Documentation/devicetree/bindings/usb/brcm,usb-pinmap.yaml
new file mode 100644 (file)
index 0000000..ffa148b
--- /dev/null
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/brcm,usb-pinmap.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Broadcom USB pin map Controller Device Tree Bindings
+
+maintainers:
+  - Al Cooper <alcooperx@gmail.com>
+
+properties:
+  compatible:
+    items:
+      - const: brcm,usb-pinmap
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+    description: Interrupt for signals mirrored to out-gpios.
+
+  in-gpios:
+    description: Array of one or two GPIO pins used for input signals.
+
+  brcm,in-functions:
+    $ref: /schemas/types.yaml#/definitions/string-array
+    description: Array of input signal names, one per gpio in in-gpios.
+
+  brcm,in-masks:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: Array of enable and mask pairs, one per gpio in-gpios.
+
+  out-gpios:
+    description: Array of one GPIO pin used for output signals.
+
+  brcm,out-functions:
+    $ref: /schemas/types.yaml#/definitions/string-array
+    description: Array of output signal names, one per gpio in out-gpios.
+
+  brcm,out-masks:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: Array of enable, value, changed and clear masks, one
+      per gpio in out-gpios.
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+dependencies:
+  in-gpios: [ interrupts ]
+
+examples:
+  - |
+    usb_pinmap: usb-pinmap@22000d0 {
+        compatible = "brcm,usb-pinmap";
+        reg = <0x22000d0 0x4>;
+        in-gpios = <&gpio 18 0>, <&gpio 19 0>;
+        brcm,in-functions = "VBUS", "PWRFLT";
+        brcm,in-masks = <0x8000 0x40000 0x10000 0x80000>;
+        out-gpios = <&gpio 20 0>;
+        brcm,out-functions = "PWRON";
+        brcm,out-masks = <0x20000 0x800000 0x400000 0x200000>;
+        interrupts = <0x0 0xb2 0x4>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/usb/maxim,max33359.yaml b/Documentation/devicetree/bindings/usb/maxim,max33359.yaml
new file mode 100644 (file)
index 0000000..93a19ed
--- /dev/null
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/usb/maxim,max33359.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Maxim TCPCI Type-C PD controller DT bindings
+
+maintainers:
+  - Badhri Jagan Sridharan <badhri@google.com>
+
+description: Maxim TCPCI Type-C PD controller
+
+properties:
+  compatible:
+    enum:
+      - maxim,max33359
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  connector:
+    type: object
+    $ref: ../connector/usb-connector.yaml#
+    description:
+      Properties for usb c connector.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - connector
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/usb/pd.h>
+    i2c0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        maxtcpc@25 {
+            compatible = "maxim,max33359";
+            reg = <0x25>;
+            interrupt-parent = <&gpa8>;
+            interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+
+            connector {
+                compatible = "usb-c-connector";
+                label = "USB-C";
+                data-role = "dual";
+                power-role = "dual";
+                try-power-role = "sink";
+                self-powered;
+                op-sink-microwatt = <2600000>;
+                new-source-frs-typec-current = <FRS_5V_1P5A>;
+                source-pdos = <PDO_FIXED(5000, 900,
+                                         PDO_FIXED_SUSPEND |
+                                         PDO_FIXED_USB_COMM |
+                                         PDO_FIXED_DATA_SWAP |
+                                         PDO_FIXED_DUAL_ROLE)>;
+                sink-pdos = <PDO_FIXED(5000, 3000,
+                                       PDO_FIXED_USB_COMM |
+                                       PDO_FIXED_DATA_SWAP |
+                                       PDO_FIXED_DUAL_ROLE)
+                                       PDO_FIXED(9000, 2000, 0)>;
+            };
+        };
+    };
+...
index 6f47415..6462c9b 100644 (file)
@@ -3570,6 +3570,14 @@ S:       Maintained
 F:     Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml
 F:     drivers/usb/host/ehci-brcm.*
 
+BROADCOM BRCMSTB USB PIN MAP DRIVER
+M:     Al Cooper <alcooperx@gmail.com>
+L:     linux-usb@vger.kernel.org
+L:     bcm-kernel-feedback-list@broadcom.com
+S:     Maintained
+F:     Documentation/devicetree/bindings/usb/brcm,usb-pinmap.yaml
+F:     drivers/usb/misc/brcmstb-usb-pinmap.c
+
 BROADCOM BRCMSTB USB2 and USB3 PHY DRIVER
 M:     Al Cooper <alcooperx@gmail.com>
 L:     linux-kernel@vger.kernel.org
index cb7ce62..c40cf5e 100644 (file)
@@ -16,6 +16,7 @@
  * Copyright (C) 2004 Nokia Corporation by Imre Deak <imre.deak@nokia.com>
  */
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
@@ -46,6 +47,9 @@
 #include "common.h"
 #include "board-h2.h"
 
+/* The first 16 SoC GPIO lines are on this GPIO chip */
+#define OMAP_GPIO_LABEL                        "gpio-0-15"
+
 /* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */
 #define OMAP1610_ETHR_START            0x04000300
 
@@ -334,7 +338,19 @@ static struct i2c_board_info __initdata h2_i2c_board_info[] = {
                I2C_BOARD_INFO("tps65010", 0x48),
                .platform_data  = &tps_board,
        }, {
-               I2C_BOARD_INFO("isp1301_omap", 0x2d),
+               .type = "isp1301_omap",
+               .addr = 0x2d,
+               .dev_name = "isp1301",
+       },
+};
+
+static struct gpiod_lookup_table isp1301_gpiod_table = {
+       .dev_id = "isp1301",
+       .table = {
+               /* Active low since the irq triggers on falling edge */
+               GPIO_LOOKUP(OMAP_GPIO_LABEL, 2,
+                           NULL, GPIO_ACTIVE_LOW),
+               { },
        },
 };
 
@@ -406,8 +422,10 @@ static void __init h2_init(void)
        h2_smc91x_resources[1].end = gpio_to_irq(0);
        platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
        omap_serial_init();
+
+       /* ISP1301 IRQ wired at M14 */
+       omap_cfg_reg(M14_1510_GPIO2);
        h2_i2c_board_info[0].irq = gpio_to_irq(58);
-       h2_i2c_board_info[1].irq = gpio_to_irq(2);
        omap_register_i2c_bus(1, 100, h2_i2c_board_info,
                              ARRAY_SIZE(h2_i2c_board_info));
        omap1_usb_init(&h2_usb_config);
index 31be311..8111ed1 100644 (file)
@@ -438,8 +438,7 @@ static int cros_typec_enable_tbt(struct cros_typec_data *typec,
        if (pd_ctrl->control_flags & USB_PD_CTRL_ACTIVE_LINK_UNIDIR)
                data.cable_mode |= TBT_CABLE_LINK_TRAINING;
 
-       if (pd_ctrl->cable_gen)
-               data.cable_mode |= TBT_CABLE_ROUNDED;
+       data.cable_mode |= TBT_SET_CABLE_ROUNDED(pd_ctrl->cable_gen);
 
        /* Enter Mode VDO */
        data.enter_vdo = TBT_SET_CABLE_SPEED(pd_ctrl->cable_speed);
index 1c1c1d6..ba5706c 100644 (file)
@@ -30,7 +30,6 @@ obj-$(CONFIG_USB_ISP1362_HCD) += host/
 obj-$(CONFIG_USB_U132_HCD)     += host/
 obj-$(CONFIG_USB_R8A66597_HCD) += host/
 obj-$(CONFIG_USB_HWA_HCD)      += host/
-obj-$(CONFIG_USB_IMX21_HCD)    += host/
 obj-$(CONFIG_USB_FSL_USB2)     += host/
 obj-$(CONFIG_USB_FOTG210_HCD)  += host/
 obj-$(CONFIG_USB_MAX3421_HCD)  += host/
index 56fe30d..f49792f 100644 (file)
@@ -249,7 +249,7 @@ static void usbatm_complete(struct urb *urb)
        /* vdbg("%s: urb 0x%p, status %d, actual_length %d",
             __func__, urb, status, urb->actual_length); */
 
-       /* usually in_interrupt(), but not always */
+       /* Can be invoked from task context, protect against interrupts */
        spin_lock_irqsave(&channel->lock, flags);
 
        /* must add to the back when receiving; doesn't matter when sending */
index a18d7c4..ce5e6f6 100644 (file)
@@ -118,7 +118,7 @@ static struct attribute *ulpi_dev_attrs[] = {
        NULL
 };
 
-static struct attribute_group ulpi_dev_attr_group = {
+static const struct attribute_group ulpi_dev_attr_group = {
        .attrs = ulpi_dev_attrs,
 };
 
index 6cf22c2..fbb087b 100644 (file)
@@ -51,7 +51,8 @@ void __init usb_init_pool_max(void)
 /**
  * hcd_buffer_create - initialize buffer pools
  * @hcd: the bus whose buffer pools are to be initialized
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep
  *
  * Call this as part of initializing a host controller that uses the dma
  * memory allocators.  It initializes some pools of dma-coherent memory that
@@ -88,7 +89,8 @@ int hcd_buffer_create(struct usb_hcd *hcd)
 /**
  * hcd_buffer_destroy - deallocate buffer pools
  * @hcd: the bus whose buffer pools are to be destroyed
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep
  *
  * This frees the buffer pools created by hcd_buffer_create().
  */
index 562a730..b199eb6 100644 (file)
@@ -1076,6 +1076,7 @@ int usb_get_bos_descriptor(struct usb_device *dev)
                case USB_PTM_CAP_TYPE:
                        dev->bos->ptm_cap =
                                (struct usb_ptm_cap_descriptor *)buffer;
+                       break;
                default:
                        break;
                }
index 1c2c040..903426b 100644 (file)
@@ -153,7 +153,7 @@ static struct attribute *ep_dev_attrs[] = {
        &dev_attr_direction.attr,
        NULL,
 };
-static struct attribute_group ep_dev_attr_grp = {
+static const struct attribute_group ep_dev_attr_grp = {
        .attrs = ep_dev_attrs,
 };
 static const struct attribute_group *ep_dev_groups[] = {
index ec0d6c5..d630ccc 100644 (file)
@@ -160,7 +160,8 @@ static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd,
  * @dev: USB Host Controller being probed
  * @id: pci hotplug id connecting controller to HCD framework
  * @driver: USB HC driver handle
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep
  *
  * Allocates basic PCI resources for this USB host controller, and
  * then invokes the start() method for the HCD associated with it
@@ -304,7 +305,8 @@ EXPORT_SYMBOL_GPL(usb_hcd_pci_probe);
 /**
  * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs
  * @dev: USB Host Controller being removed
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep
  *
  * Reverses the effect of usb_hcd_pci_probe(), first invoking
  * the HCD's stop() method.  It is always called from a thread
index 2c6b957..60886a7 100644 (file)
@@ -747,8 +747,7 @@ error:
  * driver requests it; otherwise the driver is responsible for
  * calling usb_hcd_poll_rh_status() when an event occurs.
  *
- * Completions are called in_interrupt(), but they may or may not
- * be in_irq().
+ * Completion handler may not sleep. See usb_hcd_giveback_urb() for details.
  */
 void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
 {
@@ -904,7 +903,8 @@ static void usb_bus_init (struct usb_bus *bus)
 /**
  * usb_register_bus - registers the USB host controller with the usb core
  * @bus: pointer to the bus to register
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep.
  *
  * Assigns a bus number, and links the controller into usbcore data
  * structures so that it can be seen by scanning the bus list.
@@ -939,7 +939,8 @@ error_find_busnum:
 /**
  * usb_deregister_bus - deregisters the USB host controller
  * @bus: pointer to the bus to deregister
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep.
  *
  * Recycles the bus number, and unlinks the controller from usbcore data
  * structures so that it won't be seen by scanning the bus list.
@@ -1646,9 +1647,16 @@ static void __usb_hcd_giveback_urb(struct urb *urb)
 
        /* pass ownership to the completion handler */
        urb->status = status;
-       kcov_remote_start_usb((u64)urb->dev->bus->busnum);
+       /*
+        * This function can be called in task context inside another remote
+        * coverage collection section, but KCOV doesn't support that kind of
+        * recursion yet. Only collect coverage in softirq context for now.
+        */
+       if (in_serving_softirq())
+               kcov_remote_start_usb((u64)urb->dev->bus->busnum);
        urb->complete(urb);
-       kcov_remote_stop();
+       if (in_serving_softirq())
+               kcov_remote_stop();
 
        usb_anchor_resume_wakeups(anchor);
        atomic_dec(&urb->use_count);
@@ -1691,7 +1699,11 @@ static void usb_giveback_urb_bh(struct tasklet_struct *t)
  * @hcd: host controller returning the URB
  * @urb: urb being returned to the USB device driver.
  * @status: completion status code for the URB.
- * Context: in_interrupt()
+ *
+ * Context: atomic. The completion callback is invoked in caller's context.
+ * For HCDs with HCD_BH flag set, the completion callback is invoked in tasklet
+ * context (except for URBs submitted to the root hub which always complete in
+ * caller's context).
  *
  * This hands the URB from HCD to its USB device driver, using its
  * completion function.  The HCD has freed all per-urb resources
@@ -2268,7 +2280,7 @@ EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
  * usb_bus_start_enum - start immediate enumeration (for OTG)
  * @bus: the bus (must use hcd framework)
  * @port_num: 1-based number of port; usually bus->otg_port
- * Context: in_interrupt()
+ * Context: atomic
  *
  * Starts enumeration, with an immediate reset followed later by
  * hub_wq identifying and possibly configuring the device.
@@ -2474,7 +2486,8 @@ EXPORT_SYMBOL_GPL(__usb_create_hcd);
  * @bus_name: value to store in hcd->self.bus_name
  * @primary_hcd: a pointer to the usb_hcd structure that is sharing the
  *              PCI device.  Only allocate certain resources for the primary HCD
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep.
  *
  * Allocate a struct usb_hcd, with extra space at the end for the
  * HC driver's private data.  Initialize the generic members of the
@@ -2496,7 +2509,8 @@ EXPORT_SYMBOL_GPL(usb_create_shared_hcd);
  * @driver: HC driver that will use this hcd
  * @dev: device for this HC, stored in hcd->self.controller
  * @bus_name: value to store in hcd->self.bus_name
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep.
  *
  * Allocate a struct usb_hcd, with extra space at the end for the
  * HC driver's private data.  Initialize the generic members of the
@@ -2830,7 +2844,8 @@ EXPORT_SYMBOL_GPL(usb_add_hcd);
 /**
  * usb_remove_hcd - shutdown processing for generic HCDs
  * @hcd: the usb_hcd structure to remove
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep.
  *
  * Disconnects the root hub, then reverses the effects of usb_add_hcd(),
  * invoking the HCD's stop() method.
index 17202b2..7f71218 100644 (file)
@@ -2171,7 +2171,8 @@ static void hub_disconnect_children(struct usb_device *udev)
 /**
  * usb_disconnect - disconnect a device (usbcore-internal)
  * @pdev: pointer to device being disconnected
- * Context: !in_interrupt ()
+ *
+ * Context: task context, might sleep
  *
  * Something got disconnected. Get rid of it and all of its children.
  *
index 19ebb54..d92a04d 100644 (file)
@@ -119,7 +119,7 @@ static int usb_internal_control_msg(struct usb_device *usb_dev,
  * @timeout: time in msecs to wait for the message to complete before timing
  *     out (if 0 the wait is forever)
  *
- * Context: !in_interrupt ()
+ * Context: task context, might sleep.
  *
  * This function sends a simple control message to a specified endpoint and
  * waits for the message to complete, or timeout.
@@ -219,9 +219,8 @@ int usb_control_msg_send(struct usb_device *dev, __u8 endpoint, __u8 request,
 
        if (ret < 0)
                return ret;
-       if (ret == size)
-               return 0;
-       return -EINVAL;
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(usb_control_msg_send);
 
@@ -290,7 +289,7 @@ int usb_control_msg_recv(struct usb_device *dev, __u8 endpoint, __u8 request,
                memcpy(driver_data, data, size);
                ret = 0;
        } else {
-               ret = -EINVAL;
+               ret = -EREMOTEIO;
        }
 
 exit:
@@ -310,7 +309,7 @@ EXPORT_SYMBOL_GPL(usb_control_msg_recv);
  * @timeout: time in msecs to wait for the message to complete before
  *     timing out (if 0 the wait is forever)
  *
- * Context: !in_interrupt ()
+ * Context: task context, might sleep.
  *
  * This function sends a simple interrupt message to a specified endpoint and
  * waits for the message to complete, or timeout.
@@ -343,7 +342,7 @@ EXPORT_SYMBOL_GPL(usb_interrupt_msg);
  * @timeout: time in msecs to wait for the message to complete before
  *     timing out (if 0 the wait is forever)
  *
- * Context: !in_interrupt ()
+ * Context: task context, might sleep.
  *
  * This function sends a simple bulk message to a specified endpoint
  * and waits for the message to complete, or timeout.
@@ -610,7 +609,8 @@ EXPORT_SYMBOL_GPL(usb_sg_init);
  * usb_sg_wait - synchronously execute scatter/gather request
  * @io: request block handle, as initialized with usb_sg_init().
  *     some fields become accessible when this call returns.
- * Context: !in_interrupt ()
+ *
+ * Context: task context, might sleep.
  *
  * This function blocks until the specified I/O operation completes.  It
  * leverages the grouping of the related I/O requests to get good transfer
@@ -764,7 +764,8 @@ EXPORT_SYMBOL_GPL(usb_sg_cancel);
  * @index: the number of the descriptor
  * @buf: where to put the descriptor
  * @size: how big is "buf"?
- * Context: !in_interrupt ()
+ *
+ * Context: task context, might sleep.
  *
  * Gets a USB descriptor.  Convenience functions exist to simplify
  * getting some types of descriptors.  Use
@@ -812,7 +813,8 @@ EXPORT_SYMBOL_GPL(usb_get_descriptor);
  * @index: the number of the descriptor
  * @buf: where to put the string
  * @size: how big is "buf"?
- * Context: !in_interrupt ()
+ *
+ * Context: task context, might sleep.
  *
  * Retrieves a string, encoded using UTF-16LE (Unicode, 16 bits per character,
  * in little-endian byte order).
@@ -947,7 +949,8 @@ static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf)
  * @index: the number of the descriptor
  * @buf: where to put the string
  * @size: how big is "buf"?
- * Context: !in_interrupt ()
+ *
+ * Context: task context, might sleep.
  *
  * This converts the UTF-16LE encoded strings returned by devices, from
  * usb_get_string_descriptor(), to null-terminated UTF-8 encoded ones
@@ -1036,7 +1039,8 @@ char *usb_cache_string(struct usb_device *udev, int index)
  * usb_get_device_descriptor - (re)reads the device descriptor (usbcore)
  * @dev: the device whose device descriptor is being updated
  * @size: how much of the descriptor to read
- * Context: !in_interrupt ()
+ *
+ * Context: task context, might sleep.
  *
  * Updates the copy of the device descriptor stored in the device structure,
  * which dedicates space for this purpose.
@@ -1071,7 +1075,7 @@ int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
 /*
  * usb_set_isoch_delay - informs the device of the packet transmit delay
  * @dev: the device whose delay is to be informed
- * Context: !in_interrupt()
+ * Context: task context, might sleep
  *
  * Since this is an optional request, we don't bother if it fails.
  */
@@ -1100,7 +1104,8 @@ int usb_set_isoch_delay(struct usb_device *dev)
  * @type: USB_STATUS_TYPE_*; for standard or PTM status types
  * @target: zero (for device), else interface or endpoint number
  * @data: pointer to two bytes of bitmap data
- * Context: !in_interrupt ()
+ *
+ * Context: task context, might sleep.
  *
  * Returns device, interface, or endpoint status.  Normally only of
  * interest to see if the device is self powered, or has enabled the
@@ -1177,7 +1182,8 @@ EXPORT_SYMBOL_GPL(usb_get_status);
  * usb_clear_halt - tells device to clear endpoint halt/stall condition
  * @dev: device whose endpoint is halted
  * @pipe: endpoint "pipe" being cleared
- * Context: !in_interrupt ()
+ *
+ * Context: task context, might sleep.
  *
  * This is used to clear halt conditions for bulk and interrupt endpoints,
  * as reported by URB completion status.  Endpoints that are halted are
@@ -1481,7 +1487,8 @@ void usb_enable_interface(struct usb_device *dev,
  * @dev: the device whose interface is being updated
  * @interface: the interface being updated
  * @alternate: the setting being chosen.
- * Context: !in_interrupt ()
+ *
+ * Context: task context, might sleep.
  *
  * This is used to enable data transfers on interfaces that may not
  * be enabled by default.  Not all devices support such configurability.
@@ -1902,7 +1909,8 @@ static void __usb_queue_reset_device(struct work_struct *ws)
  * usb_set_configuration - Makes a particular device setting be current
  * @dev: the device whose configuration is being updated
  * @configuration: the configuration being chosen.
- * Context: !in_interrupt(), caller owns the device lock
+ *
+ * Context: task context, might sleep. Caller holds device lock.
  *
  * This is used to enable non-default device modes.  Not all devices
  * use this kind of configurability; many devices only have one
index 235a7c6..dfcca9c 100644 (file)
@@ -155,7 +155,7 @@ static struct attribute *port_dev_attrs[] = {
        NULL,
 };
 
-static struct attribute_group port_dev_attr_grp = {
+static const struct attribute_group port_dev_attr_grp = {
        .attrs = port_dev_attrs,
 };
 
@@ -169,7 +169,7 @@ static struct attribute *port_dev_usb3_attrs[] = {
        NULL,
 };
 
-static struct attribute_group port_dev_usb3_attr_grp = {
+static const struct attribute_group port_dev_usb3_attr_grp = {
        .attrs = port_dev_usb3_attrs,
 };
 
index 8d13419..d85699b 100644 (file)
@@ -641,7 +641,7 @@ static struct attribute *usb2_hardware_lpm_attr[] = {
        &dev_attr_usb2_lpm_besl.attr,
        NULL,
 };
-static struct attribute_group usb2_hardware_lpm_attr_group = {
+static const struct attribute_group usb2_hardware_lpm_attr_group = {
        .name   = power_group_name,
        .attrs  = usb2_hardware_lpm_attr,
 };
@@ -651,7 +651,7 @@ static struct attribute *usb3_hardware_lpm_attr[] = {
        &dev_attr_usb3_hardware_lpm_u2.attr,
        NULL,
 };
-static struct attribute_group usb3_hardware_lpm_attr_group = {
+static const struct attribute_group usb3_hardware_lpm_attr_group = {
        .name   = power_group_name,
        .attrs  = usb3_hardware_lpm_attr,
 };
@@ -663,7 +663,7 @@ static struct attribute *power_attrs[] = {
        &dev_attr_active_duration.attr,
        NULL,
 };
-static struct attribute_group power_attr_group = {
+static const struct attribute_group power_attr_group = {
        .name   = power_group_name,
        .attrs  = power_attrs,
 };
@@ -832,7 +832,7 @@ static struct attribute *dev_attrs[] = {
 #endif
        NULL,
 };
-static struct attribute_group dev_attr_grp = {
+static const struct attribute_group dev_attr_grp = {
        .attrs = dev_attrs,
 };
 
@@ -865,7 +865,7 @@ static umode_t dev_string_attrs_are_visible(struct kobject *kobj,
        return a->mode;
 }
 
-static struct attribute_group dev_string_attr_grp = {
+static const struct attribute_group dev_string_attr_grp = {
        .attrs =        dev_string_attrs,
        .is_visible =   dev_string_attrs_are_visible,
 };
@@ -1222,7 +1222,7 @@ static struct attribute *intf_attrs[] = {
        &dev_attr_interface_authorized.attr,
        NULL,
 };
-static struct attribute_group intf_attr_grp = {
+static const struct attribute_group intf_attr_grp = {
        .attrs = intf_attrs,
 };
 
@@ -1246,7 +1246,7 @@ static umode_t intf_assoc_attrs_are_visible(struct kobject *kobj,
        return a->mode;
 }
 
-static struct attribute_group intf_assoc_attr_grp = {
+static const struct attribute_group intf_assoc_attr_grp = {
        .attrs =        intf_assoc_attrs,
        .is_visible =   intf_assoc_attrs_are_visible,
 };
index 9b4ac44..8f07b05 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/string.h>
 #include <linux/bitops.h>
 #include <linux/slab.h>
-#include <linux/interrupt.h>  /* for in_interrupt() */
 #include <linux/kmod.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
@@ -561,7 +560,8 @@ static bool usb_dev_authorized(struct usb_device *dev, struct usb_hcd *hcd)
  * @parent: hub to which device is connected; null to allocate a root hub
  * @bus: bus used to access the device
  * @port1: one-based index of port; ignored for root hubs
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep.
  *
  * Only hub drivers (including virtual root hub drivers for host
  * controllers) should ever call this.
index c727cb5..8f5ceac 100644 (file)
@@ -678,6 +678,8 @@ static __poll_t ffs_ep0_poll(struct file *file, poll_table *wait)
                        mask |= (EPOLLIN | EPOLLOUT);
                        break;
                }
+               break;
+
        case FFS_CLOSING:
                break;
        case FFS_DEACTIVATED:
index 1803646..b56ad7c 100644 (file)
@@ -274,7 +274,7 @@ static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
        default:
                ERROR(cdev, "%s loop complete --> %d, %d/%d\n", ep->name,
                                status, req->actual, req->length);
-               /* FALLTHROUGH */
+               fallthrough;
 
        /* NOTE:  since this driver doesn't maintain an explicit record
         * of requests it submitted (just maintains qlen count), we
index ed68a48..5a201ba 100644 (file)
@@ -559,6 +559,7 @@ static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
 #if 1
                DBG(cdev, "%s complete --> %d, %d/%d\n", ep->name,
                                status, req->actual, req->length);
+               break;
 #endif
        case -EREMOTEIO:                /* short read */
                break;
index debf542..5b5cfeb 100644 (file)
@@ -897,8 +897,6 @@ EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
  * @ep: the endpoint to be used with with the request
  * @req: the request being given back
  *
- * Context: in_interrupt()
- *
  * This is called by device controller drivers in order to return the
  * completed request back to the gadget layer.
  */
index 53a2272..f6b4077 100644 (file)
@@ -553,6 +553,7 @@ static int dummy_enable(struct usb_ep *_ep,
                                /* we'll fake any legal size */
                                break;
                        /* save a return statement */
+                       fallthrough;
                default:
                        goto done;
                }
@@ -595,6 +596,7 @@ static int dummy_enable(struct usb_ep *_ep,
                        if (max <= 1023)
                                break;
                        /* save a return statement */
+                       fallthrough;
                default:
                        goto done;
                }
@@ -1754,8 +1756,10 @@ static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
        return ret_val;
 }
 
-/* drive both sides of the transfers; looks like irq handlers to
- * both drivers except the callbacks aren't in_irq().
+/*
+ * Drive both sides of the transfers; looks like irq handlers to both
+ * drivers except that the callbacks are invoked from soft interrupt
+ * context.
  */
 static void dummy_timer(struct timer_list *t)
 {
index cfaeca4..ce57961 100644 (file)
@@ -304,7 +304,7 @@ static struct pxa_ep *find_pxa_ep(struct pxa_udc *udc,
  * update_pxa_ep_matches - update pxa_ep cached values in all udc_usb_ep
  * @udc: pxa udc
  *
- * Context: in_interrupt()
+ * Context: interrupt handler
  *
  * Updates all pxa_ep fields in udc_usb_ep structures, if this field was
  * previously set up (and is not NULL). The update is necessary is a
@@ -859,7 +859,7 @@ static int write_packet(struct pxa_ep *ep, struct pxa27x_request *req,
  * @ep: pxa physical endpoint
  * @req: usb request
  *
- * Context: callable when in_interrupt()
+ * Context: interrupt handler
  *
  * Unload as many packets as possible from the fifo we use for usb OUT
  * transfers and put them into the request. Caller should have made sure
@@ -997,7 +997,7 @@ static int read_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
  * @ep: control endpoint
  * @req: request
  *
- * Context: callable when in_interrupt()
+ * Context: interrupt handler
  *
  * Sends a request (or a part of the request) to the control endpoint (ep0 in).
  * If the request doesn't fit, the remaining part will be sent from irq.
@@ -1036,8 +1036,8 @@ static int write_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
  * @_req: usb request
  * @gfp_flags: flags
  *
- * Context: normally called when !in_interrupt, but callable when in_interrupt()
- * in the special case of ep0 setup :
+ * Context: thread context or from the interrupt handler in the
+ * special case of ep0 setup :
  *   (irq->handle_ep0_ctrl_req->gadget_setup->pxa_ep_queue)
  *
  * Returns 0 if succedeed, error otherwise
@@ -1512,7 +1512,8 @@ static int should_disable_udc(struct pxa_udc *udc)
  * pxa_udc_pullup - Offer manual D+ pullup control
  * @_gadget: usb gadget using the control
  * @is_active: 0 if disconnect, else connect D+ pullup resistor
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep
  *
  * Returns 0 if OK, -EOPNOTSUPP if udc driver doesn't handle D+ pullup
  */
@@ -1560,7 +1561,7 @@ static int pxa_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
  * @_gadget: usb gadget
  * @mA: current drawn
  *
- * Context: !in_interrupt()
+ * Context: task context, might sleep
  *
  * Called after a configuration was chosen by a USB host, to inform how much
  * current can be drawn by the device from VBus line.
@@ -1886,7 +1887,7 @@ stall:
  * @fifo_irq: 1 if triggered by fifo service type irq
  * @opc_irq: 1 if triggered by output packet complete type irq
  *
- * Context : when in_interrupt() or with ep->lock held
+ * Context : interrupt handler
  *
  * Tries to transfer all pending request data into the endpoint and/or
  * transfer all pending data in the endpoint into usb requests.
@@ -2011,7 +2012,7 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
  * Tries to transfer all pending request data into the endpoint and/or
  * transfer all pending data in the endpoint into usb requests.
  *
- * Is always called when in_interrupt() and with ep->lock released.
+ * Is always called from the interrupt handler. ep->lock must not be held.
  */
 static void handle_ep(struct pxa_ep *ep)
 {
index ab12c4b..31e5930 100644 (file)
@@ -213,13 +213,6 @@ config USB_EHCI_FSL
        help
          Variation of ARC USB block used in some Freescale chips.
 
-config USB_EHCI_MXC
-       tristate "Support for Freescale i.MX on-chip EHCI USB controller"
-       depends on ARCH_MXC || COMPILE_TEST
-       select USB_EHCI_ROOT_HUB_TT
-       help
-         Variation of ARC USB block used in some Freescale chips.
-
 config USB_EHCI_HCD_NPCM7XX
        tristate "Support for Nuvoton NPCM7XX on-chip EHCI USB controller"
        depends on (USB_EHCI_HCD && ARCH_NPCM7XX) || COMPILE_TEST
@@ -741,16 +734,6 @@ config USB_RENESAS_USBHS_HCD
          To compile this driver as a module, choose M here: the
          module will be called renesas-usbhs.
 
-config USB_IMX21_HCD
-       tristate "i.MX21 HCD support"
-       depends on ARM && ARCH_MXC
-       help
-         This driver enables support for the on-chip USB host in the
-         i.MX21 processor.
-
-         To compile this driver as a module, choose M here: the
-         module will be called "imx21-hcd".
-
 config USB_HCD_BCMA
        tristate "BCMA usb host driver"
        depends on BCMA
index bc73133..c1b0870 100644 (file)
@@ -40,7 +40,6 @@ obj-$(CONFIG_USB_PCI) += pci-quirks.o
 obj-$(CONFIG_USB_EHCI_HCD)     += ehci-hcd.o
 obj-$(CONFIG_USB_EHCI_PCI)     += ehci-pci.o
 obj-$(CONFIG_USB_EHCI_HCD_PLATFORM)    += ehci-platform.o
-obj-$(CONFIG_USB_EHCI_MXC)     += ehci-mxc.o
 obj-$(CONFIG_USB_EHCI_HCD_NPCM7XX)     += ehci-npcm7xx.o
 obj-$(CONFIG_USB_EHCI_HCD_OMAP)        += ehci-omap.o
 obj-$(CONFIG_USB_EHCI_HCD_ORION)       += ehci-orion.o
@@ -81,7 +80,6 @@ obj-$(CONFIG_USB_SL811_HCD)   += sl811-hcd.o
 obj-$(CONFIG_USB_SL811_CS)     += sl811_cs.o
 obj-$(CONFIG_USB_U132_HCD)     += u132-hcd.o
 obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
-obj-$(CONFIG_USB_IMX21_HCD)    += imx21-hcd.o
 obj-$(CONFIG_USB_FSL_USB2)     += fsl-mph-dr-of.o
 obj-$(CONFIG_USB_EHCI_FSL)     += fsl-mph-dr-of.o
 obj-$(CONFIG_USB_EHCI_FSL)     += ehci-fsl.o
index 1e8b59a..6f7bd66 100644 (file)
@@ -39,10 +39,10 @@ static struct hc_driver __read_mostly fsl_ehci_hc_driver;
 /*
  * fsl_ehci_drv_probe - initialize FSL-based HCDs
  * @pdev: USB Host Controller being probed
- * Context: !in_interrupt()
  *
- * Allocates basic resources for this USB host controller.
+ * Context: task context, might sleep
  *
+ * Allocates basic resources for this USB host controller.
  */
 static int fsl_ehci_drv_probe(struct platform_device *pdev)
 {
@@ -684,12 +684,11 @@ static const struct ehci_driver_overrides ehci_fsl_overrides __initconst = {
 /**
  * fsl_ehci_drv_remove - shutdown processing for FSL-based HCDs
  * @pdev: USB Host Controller being removed
- * Context: !in_interrupt()
  *
- * Reverses the effect of usb_hcd_fsl_probe().
+ * Context: task context, might sleep
  *
+ * Reverses the effect of usb_hcd_fsl_probe().
  */
-
 static int fsl_ehci_drv_remove(struct platform_device *pdev)
 {
        struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
index 3575b72..e358ae1 100644 (file)
@@ -867,7 +867,7 @@ static int ehci_urb_enqueue (
                 */
                if (urb->transfer_buffer_length > (16 * 1024))
                        return -EMSGSIZE;
-               /* FALLTHROUGH */
+               fallthrough;
        /* case PIPE_BULK: */
        default:
                if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
deleted file mode 100644 (file)
index dc26763..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/ulpi.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/usb/hcd.h>
-#include <linux/platform_data/usb-ehci-mxc.h>
-#include "ehci.h"
-
-#define DRIVER_DESC "Freescale On-Chip EHCI Host driver"
-
-static const char hcd_name[] = "ehci-mxc";
-
-#define ULPI_VIEWPORT_OFFSET   0x170
-
-struct ehci_mxc_priv {
-       struct clk *usbclk, *ahbclk, *phyclk;
-};
-
-static struct hc_driver __read_mostly ehci_mxc_hc_driver;
-
-static const struct ehci_driver_overrides ehci_mxc_overrides __initconst = {
-       .extra_priv_size =      sizeof(struct ehci_mxc_priv),
-};
-
-static int ehci_mxc_drv_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct mxc_usbh_platform_data *pdata = dev_get_platdata(dev);
-       struct usb_hcd *hcd;
-       struct resource *res;
-       int irq, ret;
-       struct ehci_mxc_priv *priv;
-       struct ehci_hcd *ehci;
-
-       if (!pdata) {
-               dev_err(dev, "No platform data given, bailing out.\n");
-               return -EINVAL;
-       }
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
-
-       hcd = usb_create_hcd(&ehci_mxc_hc_driver, dev, dev_name(dev));
-       if (!hcd)
-               return -ENOMEM;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       hcd->regs = devm_ioremap_resource(dev, res);
-       if (IS_ERR(hcd->regs)) {
-               ret = PTR_ERR(hcd->regs);
-               goto err_alloc;
-       }
-       hcd->rsrc_start = res->start;
-       hcd->rsrc_len = resource_size(res);
-
-       hcd->has_tt = 1;
-       ehci = hcd_to_ehci(hcd);
-       priv = (struct ehci_mxc_priv *) ehci->priv;
-
-       /* enable clocks */
-       priv->usbclk = devm_clk_get(dev, "ipg");
-       if (IS_ERR(priv->usbclk)) {
-               ret = PTR_ERR(priv->usbclk);
-               goto err_alloc;
-       }
-       clk_prepare_enable(priv->usbclk);
-
-       priv->ahbclk = devm_clk_get(dev, "ahb");
-       if (IS_ERR(priv->ahbclk)) {
-               ret = PTR_ERR(priv->ahbclk);
-               goto err_clk_ahb;
-       }
-       clk_prepare_enable(priv->ahbclk);
-
-       /* "dr" device has its own clock on i.MX51 */
-       priv->phyclk = devm_clk_get(dev, "phy");
-       if (IS_ERR(priv->phyclk))
-               priv->phyclk = NULL;
-       if (priv->phyclk)
-               clk_prepare_enable(priv->phyclk);
-
-       /* call platform specific init function */
-       if (pdata->init) {
-               ret = pdata->init(pdev);
-               if (ret) {
-                       dev_err(dev, "platform init failed\n");
-                       goto err_init;
-               }
-               /* platforms need some time to settle changed IO settings */
-               mdelay(10);
-       }
-
-       /* EHCI registers start at offset 0x100 */
-       ehci->caps = hcd->regs + 0x100;
-       ehci->regs = hcd->regs + 0x100 +
-               HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-
-       /* set up the PORTSCx register */
-       ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
-
-       /* is this really needed? */
-       msleep(10);
-
-       /* Initialize the transceiver */
-       if (pdata->otg) {
-               pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET;
-               ret = usb_phy_init(pdata->otg);
-               if (ret) {
-                       dev_err(dev, "unable to init transceiver, probably missing\n");
-                       ret = -ENODEV;
-                       goto err_add;
-               }
-               ret = otg_set_vbus(pdata->otg->otg, 1);
-               if (ret) {
-                       dev_err(dev, "unable to enable vbus on transceiver\n");
-                       goto err_add;
-               }
-       }
-
-       platform_set_drvdata(pdev, hcd);
-
-       ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
-       if (ret)
-               goto err_add;
-
-       device_wakeup_enable(hcd->self.controller);
-       return 0;
-
-err_add:
-       if (pdata && pdata->exit)
-               pdata->exit(pdev);
-err_init:
-       if (priv->phyclk)
-               clk_disable_unprepare(priv->phyclk);
-
-       clk_disable_unprepare(priv->ahbclk);
-err_clk_ahb:
-       clk_disable_unprepare(priv->usbclk);
-err_alloc:
-       usb_put_hcd(hcd);
-       return ret;
-}
-
-static int ehci_mxc_drv_remove(struct platform_device *pdev)
-{
-       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;
-
-       usb_remove_hcd(hcd);
-
-       if (pdata && pdata->exit)
-               pdata->exit(pdev);
-
-       if (pdata && pdata->otg)
-               usb_phy_shutdown(pdata->otg);
-
-       clk_disable_unprepare(priv->usbclk);
-       clk_disable_unprepare(priv->ahbclk);
-
-       if (priv->phyclk)
-               clk_disable_unprepare(priv->phyclk);
-
-       usb_put_hcd(hcd);
-       return 0;
-}
-
-MODULE_ALIAS("platform:mxc-ehci");
-
-static struct platform_driver ehci_mxc_driver = {
-       .probe = ehci_mxc_drv_probe,
-       .remove = ehci_mxc_drv_remove,
-       .shutdown = usb_hcd_platform_shutdown,
-       .driver = {
-                  .name = "mxc-ehci",
-       },
-};
-
-static int __init ehci_mxc_init(void)
-{
-       if (usb_disabled())
-               return -ENODEV;
-
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-
-       ehci_init_driver(&ehci_mxc_hc_driver, &ehci_mxc_overrides);
-       return platform_driver_register(&ehci_mxc_driver);
-}
-module_init(ehci_mxc_init);
-
-static void __exit ehci_mxc_cleanup(void)
-{
-       platform_driver_unregister(&ehci_mxc_driver);
-}
-module_exit(ehci_mxc_cleanup);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Sascha Hauer");
-MODULE_LICENSE("GPL");
index 2d462fb..5fb92b9 100644 (file)
@@ -147,12 +147,14 @@ err1:
 
 /**
  * usb_hcd_msp_probe - initialize PMC MSP-based HCDs
- * Context: !in_interrupt()
+ * @driver:    Pointer to hc driver instance
+ * @dev:       USB controller to probe
+ *
+ * Context: task context, might sleep
  *
  * 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.
- *
  */
 int usb_hcd_msp_probe(const struct hc_driver *driver,
                          struct platform_device *dev)
@@ -223,8 +225,9 @@ err1:
 
 /**
  * usb_hcd_msp_remove - shutdown processing for PMC MSP-based HCDs
- * @dev: USB Host Controller being removed
- * Context: !in_interrupt()
+ * @hcd: USB Host Controller being removed
+ *
+ * Context: task context, might sleep
  *
  * Reverses the effect of usb_hcd_msp_probe(), first invoking
  * the HCD's stop() method.  It is always called from a thread
@@ -233,7 +236,7 @@ err1:
  * may be called without controller electrically present
  * may be called with controller, bus, and devices active
  */
-void usb_hcd_msp_remove(struct usb_hcd *hcd, struct platform_device *dev)
+static void usb_hcd_msp_remove(struct usb_hcd *hcd)
 {
        usb_remove_hcd(hcd);
        iounmap(hcd->regs);
@@ -306,7 +309,7 @@ static int ehci_hcd_msp_drv_remove(struct platform_device *pdev)
 {
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
-       usb_hcd_msp_remove(hcd, pdev);
+       usb_hcd_msp_remove(hcd);
 
        /* free TWI GPIO USB_HOST_DEV pin */
        gpio_free(MSP_PIN_USB0_HOST_DEV);
index 6dfb242..0f85aa9 100644 (file)
@@ -244,6 +244,12 @@ static void reserve_release_intr_bandwidth(struct ehci_hcd *ehci,
 
        /* FS/LS bus bandwidth */
        if (tt_usecs) {
+               /*
+                * find_tt() will not return any error here as we have
+                * already called find_tt() before calling this function
+                * and checked for any error return. The previous call
+                * would have created the data structure.
+                */
                tt = find_tt(qh->ps.udev);
                if (sign > 0)
                        list_add_tail(&qh->ps.ps_list, &tt->ps_list);
@@ -1337,6 +1343,12 @@ static void reserve_release_iso_bandwidth(struct ehci_hcd *ehci,
                        }
                }
 
+               /*
+                * find_tt() will not return any error here as we have
+                * already called find_tt() before calling this function
+                * and checked for any error return. The previous call
+                * would have created the data structure.
+                */
                tt = find_tt(stream->ps.udev);
                if (sign > 0)
                        list_add_tail(&stream->ps.ps_list, &tt->ps_list);
index 1d94fcf..0451943 100644 (file)
@@ -5276,7 +5276,7 @@ static int fotg210_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
                 */
                if (urb->transfer_buffer_length > (16 * 1024))
                        return -EMSGSIZE;
-               /* FALLTHROUGH */
+               fallthrough;
        /* case PIPE_BULK: */
        default:
                if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags))
diff --git a/drivers/usb/host/imx21-dbg.c b/drivers/usb/host/imx21-dbg.c
deleted file mode 100644 (file)
index 02a1344..0000000
+++ /dev/null
@@ -1,439 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (c) 2009 by Martin Fuzzey
- */
-
-/* this file is part of imx21-hcd.c */
-
-#ifdef CONFIG_DYNAMIC_DEBUG
-#define DEBUG
-#endif
-
-#ifndef DEBUG
-
-static inline void create_debug_files(struct imx21 *imx21) { }
-static inline void remove_debug_files(struct imx21 *imx21) { }
-static inline void debug_urb_submitted(struct imx21 *imx21, struct urb *urb) {}
-static inline void debug_urb_completed(struct imx21 *imx21, struct urb *urb,
-       int status) {}
-static inline void debug_urb_unlinked(struct imx21 *imx21, struct urb *urb) {}
-static inline void debug_urb_queued_for_etd(struct imx21 *imx21,
-       struct urb *urb) {}
-static inline void debug_urb_queued_for_dmem(struct imx21 *imx21,
-       struct urb *urb) {}
-static inline void debug_etd_allocated(struct imx21 *imx21) {}
-static inline void debug_etd_freed(struct imx21 *imx21) {}
-static inline void debug_dmem_allocated(struct imx21 *imx21, int size) {}
-static inline void debug_dmem_freed(struct imx21 *imx21, int size) {}
-static inline void debug_isoc_submitted(struct imx21 *imx21,
-       int frame, struct td *td) {}
-static inline void debug_isoc_completed(struct imx21 *imx21,
-       int frame, struct td *td, int cc, int len) {}
-
-#else
-
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-
-static const char *dir_labels[] = {
-       "TD 0",
-       "OUT",
-       "IN",
-       "TD 1"
-};
-
-static const char *speed_labels[] = {
-       "Full",
-       "Low"
-};
-
-static const char *format_labels[] = {
-       "Control",
-       "ISO",
-       "Bulk",
-       "Interrupt"
-};
-
-static inline struct debug_stats *stats_for_urb(struct imx21 *imx21,
-       struct urb *urb)
-{
-       return usb_pipeisoc(urb->pipe) ?
-               &imx21->isoc_stats : &imx21->nonisoc_stats;
-}
-
-static void debug_urb_submitted(struct imx21 *imx21, struct urb *urb)
-{
-       stats_for_urb(imx21, urb)->submitted++;
-}
-
-static void debug_urb_completed(struct imx21 *imx21, struct urb *urb, int st)
-{
-       if (st)
-               stats_for_urb(imx21, urb)->completed_failed++;
-       else
-               stats_for_urb(imx21, urb)->completed_ok++;
-}
-
-static void debug_urb_unlinked(struct imx21 *imx21, struct urb *urb)
-{
-       stats_for_urb(imx21, urb)->unlinked++;
-}
-
-static void debug_urb_queued_for_etd(struct imx21 *imx21, struct urb *urb)
-{
-       stats_for_urb(imx21, urb)->queue_etd++;
-}
-
-static void debug_urb_queued_for_dmem(struct imx21 *imx21, struct urb *urb)
-{
-       stats_for_urb(imx21, urb)->queue_dmem++;
-}
-
-static inline void debug_etd_allocated(struct imx21 *imx21)
-{
-       imx21->etd_usage.maximum = max(
-                       ++(imx21->etd_usage.value),
-                       imx21->etd_usage.maximum);
-}
-
-static inline void debug_etd_freed(struct imx21 *imx21)
-{
-       imx21->etd_usage.value--;
-}
-
-static inline void debug_dmem_allocated(struct imx21 *imx21, int size)
-{
-       imx21->dmem_usage.value += size;
-       imx21->dmem_usage.maximum = max(
-                       imx21->dmem_usage.value,
-                       imx21->dmem_usage.maximum);
-}
-
-static inline void debug_dmem_freed(struct imx21 *imx21, int size)
-{
-       imx21->dmem_usage.value -= size;
-}
-
-
-static void debug_isoc_submitted(struct imx21 *imx21,
-       int frame, struct td *td)
-{
-       struct debug_isoc_trace *trace = &imx21->isoc_trace[
-               imx21->isoc_trace_index++];
-
-       imx21->isoc_trace_index %= ARRAY_SIZE(imx21->isoc_trace);
-       trace->schedule_frame = td->frame;
-       trace->submit_frame = frame;
-       trace->request_len = td->len;
-       trace->td = td;
-}
-
-static inline void debug_isoc_completed(struct imx21 *imx21,
-       int frame, struct td *td, int cc, int len)
-{
-       struct debug_isoc_trace *trace, *trace_failed;
-       int i;
-       int found = 0;
-
-       trace = imx21->isoc_trace;
-       for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace); i++, trace++) {
-               if (trace->td == td) {
-                       trace->done_frame = frame;
-                       trace->done_len = len;
-                       trace->cc = cc;
-                       trace->td = NULL;
-                       found = 1;
-                       break;
-               }
-       }
-
-       if (found && cc) {
-               trace_failed = &imx21->isoc_trace_failed[
-                                       imx21->isoc_trace_index_failed++];
-
-               imx21->isoc_trace_index_failed %= ARRAY_SIZE(
-                                               imx21->isoc_trace_failed);
-               *trace_failed = *trace;
-       }
-}
-
-
-static char *format_ep(struct usb_host_endpoint *ep, char *buf, int bufsize)
-{
-       if (ep)
-               snprintf(buf, bufsize, "ep_%02x (type:%02X kaddr:%p)",
-                       ep->desc.bEndpointAddress,
-                       usb_endpoint_type(&ep->desc),
-                       ep);
-       else
-               snprintf(buf, bufsize, "none");
-       return buf;
-}
-
-static char *format_etd_dword0(u32 value, char *buf, int bufsize)
-{
-       snprintf(buf, bufsize,
-               "addr=%d ep=%d dir=%s speed=%s format=%s halted=%d",
-               value & 0x7F,
-               (value >> DW0_ENDPNT) & 0x0F,
-               dir_labels[(value >> DW0_DIRECT) & 0x03],
-               speed_labels[(value >> DW0_SPEED) & 0x01],
-               format_labels[(value >> DW0_FORMAT) & 0x03],
-               (value >> DW0_HALTED) & 0x01);
-       return buf;
-}
-
-static int debug_status_show(struct seq_file *s, void *v)
-{
-       struct imx21 *imx21 = s->private;
-       int etds_allocated = 0;
-       int etds_sw_busy = 0;
-       int etds_hw_busy = 0;
-       int dmem_blocks = 0;
-       int queued_for_etd = 0;
-       int queued_for_dmem = 0;
-       unsigned int dmem_bytes = 0;
-       int i;
-       struct etd_priv *etd;
-       u32 etd_enable_mask;
-       unsigned long flags;
-       struct imx21_dmem_area *dmem;
-       struct ep_priv *ep_priv;
-
-       spin_lock_irqsave(&imx21->lock, flags);
-
-       etd_enable_mask = readl(imx21->regs + USBH_ETDENSET);
-       for (i = 0, etd = imx21->etd; i < USB_NUM_ETD; i++, etd++) {
-               if (etd->alloc)
-                       etds_allocated++;
-               if (etd->urb)
-                       etds_sw_busy++;
-               if (etd_enable_mask & (1<<i))
-                       etds_hw_busy++;
-       }
-
-       list_for_each_entry(dmem, &imx21->dmem_list, list) {
-               dmem_bytes += dmem->size;
-               dmem_blocks++;
-       }
-
-       list_for_each_entry(ep_priv, &imx21->queue_for_etd, queue)
-               queued_for_etd++;
-
-       list_for_each_entry(etd, &imx21->queue_for_dmem, queue)
-               queued_for_dmem++;
-
-       spin_unlock_irqrestore(&imx21->lock, flags);
-
-       seq_printf(s,
-               "Frame: %d\n"
-               "ETDs allocated: %d/%d (max=%d)\n"
-               "ETDs in use sw: %d\n"
-               "ETDs in use hw: %d\n"
-               "DMEM allocated: %d/%d (max=%d)\n"
-               "DMEM blocks: %d\n"
-               "Queued waiting for ETD: %d\n"
-               "Queued waiting for DMEM: %d\n",
-               readl(imx21->regs + USBH_FRMNUB) & 0xFFFF,
-               etds_allocated, USB_NUM_ETD, imx21->etd_usage.maximum,
-               etds_sw_busy,
-               etds_hw_busy,
-               dmem_bytes, DMEM_SIZE, imx21->dmem_usage.maximum,
-               dmem_blocks,
-               queued_for_etd,
-               queued_for_dmem);
-
-       return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(debug_status);
-
-static int debug_dmem_show(struct seq_file *s, void *v)
-{
-       struct imx21 *imx21 = s->private;
-       struct imx21_dmem_area *dmem;
-       unsigned long flags;
-       char ep_text[40];
-
-       spin_lock_irqsave(&imx21->lock, flags);
-
-       list_for_each_entry(dmem, &imx21->dmem_list, list)
-               seq_printf(s,
-                       "%04X: size=0x%X "
-                       "ep=%s\n",
-                       dmem->offset, dmem->size,
-                       format_ep(dmem->ep, ep_text, sizeof(ep_text)));
-
-       spin_unlock_irqrestore(&imx21->lock, flags);
-
-       return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(debug_dmem);
-
-static int debug_etd_show(struct seq_file *s, void *v)
-{
-       struct imx21 *imx21 = s->private;
-       struct etd_priv *etd;
-       char buf[60];
-       u32 dword;
-       int i, j;
-       unsigned long flags;
-
-       spin_lock_irqsave(&imx21->lock, flags);
-
-       for (i = 0, etd = imx21->etd; i < USB_NUM_ETD; i++, etd++) {
-               int state = -1;
-               struct urb_priv *urb_priv;
-               if (etd->urb) {
-                       urb_priv = etd->urb->hcpriv;
-                       if (urb_priv)
-                               state = urb_priv->state;
-               }
-
-               seq_printf(s,
-                       "etd_num: %d\n"
-                       "ep: %s\n"
-                       "alloc: %d\n"
-                       "len: %d\n"
-                       "busy sw: %d\n"
-                       "busy hw: %d\n"
-                       "urb state: %d\n"
-                       "current urb: %p\n",
-
-                       i,
-                       format_ep(etd->ep, buf, sizeof(buf)),
-                       etd->alloc,
-                       etd->len,
-                       etd->urb != NULL,
-                       (readl(imx21->regs + USBH_ETDENSET) & (1 << i)) > 0,
-                       state,
-                       etd->urb);
-
-               for (j = 0; j < 4; j++) {
-                       dword = etd_readl(imx21, i, j);
-                       switch (j) {
-                       case 0:
-                               format_etd_dword0(dword, buf, sizeof(buf));
-                               break;
-                       case 2:
-                               snprintf(buf, sizeof(buf),
-                                       "cc=0X%02X", dword >> DW2_COMPCODE);
-                               break;
-                       default:
-                               *buf = 0;
-                               break;
-                       }
-                       seq_printf(s,
-                               "dword %d: submitted=%08X cur=%08X [%s]\n",
-                               j,
-                               etd->submitted_dwords[j],
-                               dword,
-                               buf);
-               }
-               seq_printf(s, "\n");
-       }
-
-       spin_unlock_irqrestore(&imx21->lock, flags);
-
-       return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(debug_etd);
-
-static void debug_statistics_show_one(struct seq_file *s,
-       const char *name, struct debug_stats *stats)
-{
-       seq_printf(s, "%s:\n"
-               "submitted URBs: %lu\n"
-               "completed OK: %lu\n"
-               "completed failed: %lu\n"
-               "unlinked: %lu\n"
-               "queued for ETD: %lu\n"
-               "queued for DMEM: %lu\n\n",
-               name,
-               stats->submitted,
-               stats->completed_ok,
-               stats->completed_failed,
-               stats->unlinked,
-               stats->queue_etd,
-               stats->queue_dmem);
-}
-
-static int debug_statistics_show(struct seq_file *s, void *v)
-{
-       struct imx21 *imx21 = s->private;
-       unsigned long flags;
-
-       spin_lock_irqsave(&imx21->lock, flags);
-
-       debug_statistics_show_one(s, "nonisoc", &imx21->nonisoc_stats);
-       debug_statistics_show_one(s, "isoc", &imx21->isoc_stats);
-       seq_printf(s, "unblock kludge triggers: %lu\n", imx21->debug_unblocks);
-       spin_unlock_irqrestore(&imx21->lock, flags);
-
-       return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(debug_statistics);
-
-static void debug_isoc_show_one(struct seq_file *s,
-       const char *name, int index,    struct debug_isoc_trace *trace)
-{
-       seq_printf(s, "%s %d:\n"
-               "cc=0X%02X\n"
-               "scheduled frame %d (%d)\n"
-               "submitted frame %d (%d)\n"
-               "completed frame %d (%d)\n"
-               "requested length=%d\n"
-               "completed length=%d\n\n",
-               name, index,
-               trace->cc,
-               trace->schedule_frame, trace->schedule_frame & 0xFFFF,
-               trace->submit_frame, trace->submit_frame & 0xFFFF,
-               trace->done_frame, trace->done_frame & 0xFFFF,
-               trace->request_len,
-               trace->done_len);
-}
-
-static int debug_isoc_show(struct seq_file *s, void *v)
-{
-       struct imx21 *imx21 = s->private;
-       struct debug_isoc_trace *trace;
-       unsigned long flags;
-       int i;
-
-       spin_lock_irqsave(&imx21->lock, flags);
-
-       trace = imx21->isoc_trace_failed;
-       for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace_failed); i++, trace++)
-               debug_isoc_show_one(s, "isoc failed", i, trace);
-
-       trace = imx21->isoc_trace;
-       for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace); i++, trace++)
-               debug_isoc_show_one(s, "isoc", i, trace);
-
-       spin_unlock_irqrestore(&imx21->lock, flags);
-
-       return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(debug_isoc);
-
-static void create_debug_files(struct imx21 *imx21)
-{
-       struct dentry *root;
-
-       root = debugfs_create_dir(dev_name(imx21->dev), usb_debug_root);
-       imx21->debug_root = root;
-
-       debugfs_create_file("status", S_IRUGO, root, imx21, &debug_status_fops);
-       debugfs_create_file("dmem", S_IRUGO, root, imx21, &debug_dmem_fops);
-       debugfs_create_file("etd", S_IRUGO, root, imx21, &debug_etd_fops);
-       debugfs_create_file("statistics", S_IRUGO, root, imx21,
-                           &debug_statistics_fops);
-       debugfs_create_file("isoc", S_IRUGO, root, imx21, &debug_isoc_fops);
-}
-
-static void remove_debug_files(struct imx21 *imx21)
-{
-       debugfs_remove_recursive(imx21->debug_root);
-}
-
-#endif
-
diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c
deleted file mode 100644 (file)
index b2716cb..0000000
+++ /dev/null
@@ -1,1933 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * USB Host Controller Driver for IMX21
- *
- * Copyright (C) 2006 Loping Dog Embedded Systems
- * Copyright (C) 2009 Martin Fuzzey
- * Originally written by Jay Monkman <jtm@lopingdog.com>
- * Ported to 2.6.30, debugged and enhanced by Martin Fuzzey
- */
-
-
- /*
-  * The i.MX21 USB hardware contains
-  *    * 32 transfer descriptors (called ETDs)
-  *    * 4Kb of Data memory
-  *
-  * The data memory is shared between the host and function controllers
-  * (but this driver only supports the host controller)
-  *
-  * So setting up a transfer involves:
-  *    * Allocating a ETD
-  *    * Fill in ETD with appropriate information
-  *    * Allocating data memory (and putting the offset in the ETD)
-  *    * Activate the ETD
-  *    * Get interrupt when done.
-  *
-  * An ETD is assigned to each active endpoint.
-  *
-  * Low resource (ETD and Data memory) situations are handled differently for
-  * isochronous and non insosynchronous transactions :
-  *
-  * Non ISOC transfers are queued if either ETDs or Data memory are unavailable
-  *
-  * ISOC transfers use 2 ETDs per endpoint to achieve double buffering.
-  * They allocate both ETDs and Data memory during URB submission
-  * (and fail if unavailable).
-  */
-
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/usb/hcd.h>
-#include <linux/dma-mapping.h>
-#include <linux/module.h>
-
-#include "imx21-hcd.h"
-
-#ifdef CONFIG_DYNAMIC_DEBUG
-#define DEBUG
-#endif
-
-#ifdef DEBUG
-#define DEBUG_LOG_FRAME(imx21, etd, event) \
-       (etd)->event##_frame = readl((imx21)->regs + USBH_FRMNUB)
-#else
-#define DEBUG_LOG_FRAME(imx21, etd, event) do { } while (0)
-#endif
-
-static const char hcd_name[] = "imx21-hcd";
-
-static inline struct imx21 *hcd_to_imx21(struct usb_hcd *hcd)
-{
-       return (struct imx21 *)hcd->hcd_priv;
-}
-
-
-/* =========================================== */
-/* Hardware access helpers                     */
-/* =========================================== */
-
-static inline void set_register_bits(struct imx21 *imx21, u32 offset, u32 mask)
-{
-       void __iomem *reg = imx21->regs + offset;
-       writel(readl(reg) | mask, reg);
-}
-
-static inline void clear_register_bits(struct imx21 *imx21,
-       u32 offset, u32 mask)
-{
-       void __iomem *reg = imx21->regs + offset;
-       writel(readl(reg) & ~mask, reg);
-}
-
-static inline void clear_toggle_bit(struct imx21 *imx21, u32 offset, u32 mask)
-{
-       void __iomem *reg = imx21->regs + offset;
-
-       if (readl(reg) & mask)
-               writel(mask, reg);
-}
-
-static inline void set_toggle_bit(struct imx21 *imx21, u32 offset, u32 mask)
-{
-       void __iomem *reg = imx21->regs + offset;
-
-       if (!(readl(reg) & mask))
-               writel(mask, reg);
-}
-
-static void etd_writel(struct imx21 *imx21, int etd_num, int dword, u32 value)
-{
-       writel(value, imx21->regs + USB_ETD_DWORD(etd_num, dword));
-}
-
-static u32 etd_readl(struct imx21 *imx21, int etd_num, int dword)
-{
-       return readl(imx21->regs + USB_ETD_DWORD(etd_num, dword));
-}
-
-static inline int wrap_frame(int counter)
-{
-       return counter & 0xFFFF;
-}
-
-static inline int frame_after(int frame, int after)
-{
-       /* handle wrapping like jiffies time_afer */
-       return (s16)((s16)after - (s16)frame) < 0;
-}
-
-static int imx21_hc_get_frame(struct usb_hcd *hcd)
-{
-       struct imx21 *imx21 = hcd_to_imx21(hcd);
-
-       return wrap_frame(readl(imx21->regs + USBH_FRMNUB));
-}
-
-static inline bool unsuitable_for_dma(dma_addr_t addr)
-{
-       return (addr & 3) != 0;
-}
-
-#include "imx21-dbg.c"
-
-static void nonisoc_urb_completed_for_etd(
-       struct imx21 *imx21, struct etd_priv *etd, int status);
-static void schedule_nonisoc_etd(struct imx21 *imx21, struct urb *urb);
-static void free_dmem(struct imx21 *imx21, struct etd_priv *etd);
-
-/* =========================================== */
-/* ETD management                              */
-/* =========================================== */
-
-static int alloc_etd(struct imx21 *imx21)
-{
-       int i;
-       struct etd_priv *etd = imx21->etd;
-
-       for (i = 0; i < USB_NUM_ETD; i++, etd++) {
-               if (etd->alloc == 0) {
-                       memset(etd, 0, sizeof(imx21->etd[0]));
-                       etd->alloc = 1;
-                       debug_etd_allocated(imx21);
-                       return i;
-               }
-       }
-       return -1;
-}
-
-static void disactivate_etd(struct imx21 *imx21, int num)
-{
-       int etd_mask = (1 << num);
-       struct etd_priv *etd = &imx21->etd[num];
-
-       writel(etd_mask, imx21->regs + USBH_ETDENCLR);
-       clear_register_bits(imx21, USBH_ETDDONEEN, etd_mask);
-       writel(etd_mask, imx21->regs + USB_ETDDMACHANLCLR);
-       clear_toggle_bit(imx21, USBH_ETDDONESTAT, etd_mask);
-
-       etd->active_count = 0;
-
-       DEBUG_LOG_FRAME(imx21, etd, disactivated);
-}
-
-static void reset_etd(struct imx21 *imx21, int num)
-{
-       struct etd_priv *etd = imx21->etd + num;
-       int i;
-
-       disactivate_etd(imx21, num);
-
-       for (i = 0; i < 4; i++)
-               etd_writel(imx21, num, i, 0);
-       etd->urb = NULL;
-       etd->ep = NULL;
-       etd->td = NULL;
-       etd->bounce_buffer = NULL;
-}
-
-static void free_etd(struct imx21 *imx21, int num)
-{
-       if (num < 0)
-               return;
-
-       if (num >= USB_NUM_ETD) {
-               dev_err(imx21->dev, "BAD etd=%d!\n", num);
-               return;
-       }
-       if (imx21->etd[num].alloc == 0) {
-               dev_err(imx21->dev, "ETD %d already free!\n", num);
-               return;
-       }
-
-       debug_etd_freed(imx21);
-       reset_etd(imx21, num);
-       memset(&imx21->etd[num], 0, sizeof(imx21->etd[0]));
-}
-
-
-static void setup_etd_dword0(struct imx21 *imx21,
-       int etd_num, struct urb *urb,  u8 dir, u16 maxpacket)
-{
-       etd_writel(imx21, etd_num, 0,
-               ((u32) usb_pipedevice(urb->pipe)) <<  DW0_ADDRESS |
-               ((u32) usb_pipeendpoint(urb->pipe) << DW0_ENDPNT) |
-               ((u32) dir << DW0_DIRECT) |
-               ((u32) ((urb->dev->speed == USB_SPEED_LOW) ?
-                       1 : 0) << DW0_SPEED) |
-               ((u32) fmt_urb_to_etd[usb_pipetype(urb->pipe)] << DW0_FORMAT) |
-               ((u32) maxpacket << DW0_MAXPKTSIZ));
-}
-
-/*
- * Copy buffer to data controller data memory.
- * We cannot use memcpy_toio() because the hardware requires 32bit writes
- */
-static void copy_to_dmem(
-       struct imx21 *imx21, int dmem_offset, void *src, int count)
-{
-       void __iomem *dmem = imx21->regs + USBOTG_DMEM + dmem_offset;
-       u32 word = 0;
-       u8 *p = src;
-       int byte = 0;
-       int i;
-
-       for (i = 0; i < count; i++) {
-               byte = i % 4;
-               word += (*p++ << (byte * 8));
-               if (byte == 3) {
-                       writel(word, dmem);
-                       dmem += 4;
-                       word = 0;
-               }
-       }
-
-       if (count && byte != 3)
-               writel(word, dmem);
-}
-
-static void activate_etd(struct imx21 *imx21, int etd_num, u8 dir)
-{
-       u32 etd_mask = 1 << etd_num;
-       struct etd_priv *etd = &imx21->etd[etd_num];
-
-       if (etd->dma_handle && unsuitable_for_dma(etd->dma_handle)) {
-               /* For non aligned isoc the condition below is always true */
-               if (etd->len <= etd->dmem_size) {
-                       /* Fits into data memory, use PIO */
-                       if (dir != TD_DIR_IN) {
-                               copy_to_dmem(imx21,
-                                               etd->dmem_offset,
-                                               etd->cpu_buffer, etd->len);
-                       }
-                       etd->dma_handle = 0;
-
-               } else {
-                       /* Too big for data memory, use bounce buffer */
-                       enum dma_data_direction dmadir;
-
-                       if (dir == TD_DIR_IN) {
-                               dmadir = DMA_FROM_DEVICE;
-                               etd->bounce_buffer = kmalloc(etd->len,
-                                                               GFP_ATOMIC);
-                       } else {
-                               dmadir = DMA_TO_DEVICE;
-                               etd->bounce_buffer = kmemdup(etd->cpu_buffer,
-                                                               etd->len,
-                                                               GFP_ATOMIC);
-                       }
-                       if (!etd->bounce_buffer) {
-                               dev_err(imx21->dev, "failed bounce alloc\n");
-                               goto err_bounce_alloc;
-                       }
-
-                       etd->dma_handle =
-                               dma_map_single(imx21->dev,
-                                               etd->bounce_buffer,
-                                               etd->len,
-                                               dmadir);
-                       if (dma_mapping_error(imx21->dev, etd->dma_handle)) {
-                               dev_err(imx21->dev, "failed bounce map\n");
-                               goto err_bounce_map;
-                       }
-               }
-       }
-
-       clear_toggle_bit(imx21, USBH_ETDDONESTAT, etd_mask);
-       set_register_bits(imx21, USBH_ETDDONEEN, etd_mask);
-       clear_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
-       clear_toggle_bit(imx21, USBH_YFILLSTAT, etd_mask);
-
-       if (etd->dma_handle) {
-               set_register_bits(imx21, USB_ETDDMACHANLCLR, etd_mask);
-               clear_toggle_bit(imx21, USBH_XBUFSTAT, etd_mask);
-               clear_toggle_bit(imx21, USBH_YBUFSTAT, etd_mask);
-               writel(etd->dma_handle, imx21->regs + USB_ETDSMSA(etd_num));
-               set_register_bits(imx21, USB_ETDDMAEN, etd_mask);
-       } else {
-               if (dir != TD_DIR_IN) {
-                       /* need to set for ZLP and PIO */
-                       set_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
-                       set_toggle_bit(imx21, USBH_YFILLSTAT, etd_mask);
-               }
-       }
-
-       DEBUG_LOG_FRAME(imx21, etd, activated);
-
-#ifdef DEBUG
-       if (!etd->active_count) {
-               int i;
-               etd->activated_frame = readl(imx21->regs + USBH_FRMNUB);
-               etd->disactivated_frame = -1;
-               etd->last_int_frame = -1;
-               etd->last_req_frame = -1;
-
-               for (i = 0; i < 4; i++)
-                       etd->submitted_dwords[i] = etd_readl(imx21, etd_num, i);
-       }
-#endif
-
-       etd->active_count = 1;
-       writel(etd_mask, imx21->regs + USBH_ETDENSET);
-       return;
-
-err_bounce_map:
-       kfree(etd->bounce_buffer);
-
-err_bounce_alloc:
-       free_dmem(imx21, etd);
-       nonisoc_urb_completed_for_etd(imx21, etd, -ENOMEM);
-}
-
-/* =========================================== */
-/* Data memory management                      */
-/* =========================================== */
-
-static int alloc_dmem(struct imx21 *imx21, unsigned int size,
-                     struct usb_host_endpoint *ep)
-{
-       unsigned int offset = 0;
-       struct imx21_dmem_area *area;
-       struct imx21_dmem_area *tmp;
-
-       size += (~size + 1) & 0x3; /* Round to 4 byte multiple */
-
-       if (size > DMEM_SIZE) {
-               dev_err(imx21->dev, "size=%d > DMEM_SIZE(%d)\n",
-                       size, DMEM_SIZE);
-               return -EINVAL;
-       }
-
-       list_for_each_entry(tmp, &imx21->dmem_list, list) {
-               if ((size + offset) < offset)
-                       goto fail;
-               if ((size + offset) <= tmp->offset)
-                       break;
-               offset = tmp->size + tmp->offset;
-               if ((offset + size) > DMEM_SIZE)
-                       goto fail;
-       }
-
-       area = kmalloc(sizeof(struct imx21_dmem_area), GFP_ATOMIC);
-       if (area == NULL)
-               return -ENOMEM;
-
-       area->ep = ep;
-       area->offset = offset;
-       area->size = size;
-       list_add_tail(&area->list, &tmp->list);
-       debug_dmem_allocated(imx21, size);
-       return offset;
-
-fail:
-       return -ENOMEM;
-}
-
-/* Memory now available for a queued ETD - activate it */
-static void activate_queued_etd(struct imx21 *imx21,
-       struct etd_priv *etd, u32 dmem_offset)
-{
-       struct urb_priv *urb_priv = etd->urb->hcpriv;
-       int etd_num = etd - &imx21->etd[0];
-       u32 maxpacket = etd_readl(imx21, etd_num, 1) >> DW1_YBUFSRTAD;
-       u8 dir = (etd_readl(imx21, etd_num, 2) >> DW2_DIRPID) & 0x03;
-
-       dev_dbg(imx21->dev, "activating queued ETD %d now DMEM available\n",
-               etd_num);
-       etd_writel(imx21, etd_num, 1,
-           ((dmem_offset + maxpacket) << DW1_YBUFSRTAD) | dmem_offset);
-
-       etd->dmem_offset = dmem_offset;
-       urb_priv->active = 1;
-       activate_etd(imx21, etd_num, dir);
-}
-
-static void free_dmem(struct imx21 *imx21, struct etd_priv *etd)
-{
-       struct imx21_dmem_area *area;
-       struct etd_priv *tmp;
-       int found = 0;
-       int offset;
-
-       if (!etd->dmem_size)
-               return;
-       etd->dmem_size = 0;
-
-       offset = etd->dmem_offset;
-       list_for_each_entry(area, &imx21->dmem_list, list) {
-               if (area->offset == offset) {
-                       debug_dmem_freed(imx21, area->size);
-                       list_del(&area->list);
-                       kfree(area);
-                       found = 1;
-                       break;
-               }
-       }
-
-       if (!found)  {
-               dev_err(imx21->dev,
-                       "Trying to free unallocated DMEM %d\n", offset);
-               return;
-       }
-
-       /* Try again to allocate memory for anything we've queued */
-       list_for_each_entry_safe(etd, tmp, &imx21->queue_for_dmem, queue) {
-               offset = alloc_dmem(imx21, etd->dmem_size, etd->ep);
-               if (offset >= 0) {
-                       list_del(&etd->queue);
-                       activate_queued_etd(imx21, etd, (u32)offset);
-               }
-       }
-}
-
-static void free_epdmem(struct imx21 *imx21, struct usb_host_endpoint *ep)
-{
-       struct imx21_dmem_area *area, *tmp;
-
-       list_for_each_entry_safe(area, tmp, &imx21->dmem_list, list) {
-               if (area->ep == ep) {
-                       dev_err(imx21->dev,
-                               "Active DMEM %d for disabled ep=%p\n",
-                               area->offset, ep);
-                       list_del(&area->list);
-                       kfree(area);
-               }
-       }
-}
-
-
-/* =========================================== */
-/* End handling                                */
-/* =========================================== */
-
-/* Endpoint now idle - release its ETD(s) or assign to queued request */
-static void ep_idle(struct imx21 *imx21, struct ep_priv *ep_priv)
-{
-       int i;
-
-       for (i = 0; i < NUM_ISO_ETDS; i++) {
-               int etd_num = ep_priv->etd[i];
-               struct etd_priv *etd;
-               if (etd_num < 0)
-                       continue;
-
-               etd = &imx21->etd[etd_num];
-               ep_priv->etd[i] = -1;
-
-               free_dmem(imx21, etd); /* for isoc */
-
-               if (list_empty(&imx21->queue_for_etd)) {
-                       free_etd(imx21, etd_num);
-                       continue;
-               }
-
-               dev_dbg(imx21->dev,
-                       "assigning idle etd %d for queued request\n", etd_num);
-               ep_priv = list_first_entry(&imx21->queue_for_etd,
-                       struct ep_priv, queue);
-               list_del(&ep_priv->queue);
-               reset_etd(imx21, etd_num);
-               ep_priv->waiting_etd = 0;
-               ep_priv->etd[i] = etd_num;
-
-               if (list_empty(&ep_priv->ep->urb_list)) {
-                       dev_err(imx21->dev, "No urb for queued ep!\n");
-                       continue;
-               }
-               schedule_nonisoc_etd(imx21, list_first_entry(
-                       &ep_priv->ep->urb_list, struct urb, urb_list));
-       }
-}
-
-static void urb_done(struct usb_hcd *hcd, struct urb *urb, int status)
-__releases(imx21->lock)
-__acquires(imx21->lock)
-{
-       struct imx21 *imx21 = hcd_to_imx21(hcd);
-       struct ep_priv *ep_priv = urb->ep->hcpriv;
-       struct urb_priv *urb_priv = urb->hcpriv;
-
-       debug_urb_completed(imx21, urb, status);
-       dev_vdbg(imx21->dev, "urb %p done %d\n", urb, status);
-
-       kfree(urb_priv->isoc_td);
-       kfree(urb->hcpriv);
-       urb->hcpriv = NULL;
-       usb_hcd_unlink_urb_from_ep(hcd, urb);
-       spin_unlock(&imx21->lock);
-       usb_hcd_giveback_urb(hcd, urb, status);
-       spin_lock(&imx21->lock);
-       if (list_empty(&ep_priv->ep->urb_list))
-               ep_idle(imx21, ep_priv);
-}
-
-static void nonisoc_urb_completed_for_etd(
-       struct imx21 *imx21, struct etd_priv *etd, int status)
-{
-       struct usb_host_endpoint *ep = etd->ep;
-
-       urb_done(imx21->hcd, etd->urb, status);
-       etd->urb = NULL;
-
-       if (!list_empty(&ep->urb_list)) {
-               struct urb *urb = list_first_entry(
-                                       &ep->urb_list, struct urb, urb_list);
-
-               dev_vdbg(imx21->dev, "next URB %p\n", urb);
-               schedule_nonisoc_etd(imx21, urb);
-       }
-}
-
-
-/* =========================================== */
-/* ISOC Handling ...                           */
-/* =========================================== */
-
-static void schedule_isoc_etds(struct usb_hcd *hcd,
-       struct usb_host_endpoint *ep)
-{
-       struct imx21 *imx21 = hcd_to_imx21(hcd);
-       struct ep_priv *ep_priv = ep->hcpriv;
-       struct etd_priv *etd;
-       struct urb_priv *urb_priv;
-       struct td *td;
-       int etd_num;
-       int i;
-       int cur_frame;
-       u8 dir;
-
-       for (i = 0; i < NUM_ISO_ETDS; i++) {
-too_late:
-               if (list_empty(&ep_priv->td_list))
-                       break;
-
-               etd_num = ep_priv->etd[i];
-               if (etd_num < 0)
-                       break;
-
-               etd = &imx21->etd[etd_num];
-               if (etd->urb)
-                       continue;
-
-               td = list_entry(ep_priv->td_list.next, struct td, list);
-               list_del(&td->list);
-               urb_priv = td->urb->hcpriv;
-
-               cur_frame = imx21_hc_get_frame(hcd);
-               if (frame_after(cur_frame, td->frame)) {
-                       dev_dbg(imx21->dev, "isoc too late frame %d > %d\n",
-                               cur_frame, td->frame);
-                       urb_priv->isoc_status = -EXDEV;
-                       td->urb->iso_frame_desc[
-                               td->isoc_index].actual_length = 0;
-                       td->urb->iso_frame_desc[td->isoc_index].status = -EXDEV;
-                       if (--urb_priv->isoc_remaining == 0)
-                               urb_done(hcd, td->urb, urb_priv->isoc_status);
-                       goto too_late;
-               }
-
-               urb_priv->active = 1;
-               etd->td = td;
-               etd->ep = td->ep;
-               etd->urb = td->urb;
-               etd->len = td->len;
-               etd->dma_handle = td->dma_handle;
-               etd->cpu_buffer = td->cpu_buffer;
-
-               debug_isoc_submitted(imx21, cur_frame, td);
-
-               dir = usb_pipeout(td->urb->pipe) ? TD_DIR_OUT : TD_DIR_IN;
-               setup_etd_dword0(imx21, etd_num, td->urb, dir, etd->dmem_size);
-               etd_writel(imx21, etd_num, 1, etd->dmem_offset);
-               etd_writel(imx21, etd_num, 2,
-                       (TD_NOTACCESSED << DW2_COMPCODE) |
-                       ((td->frame & 0xFFFF) << DW2_STARTFRM));
-               etd_writel(imx21, etd_num, 3,
-                       (TD_NOTACCESSED << DW3_COMPCODE0) |
-                       (td->len << DW3_PKTLEN0));
-
-               activate_etd(imx21, etd_num, dir);
-       }
-}
-
-static void isoc_etd_done(struct usb_hcd *hcd, int etd_num)
-{
-       struct imx21 *imx21 = hcd_to_imx21(hcd);
-       int etd_mask = 1 << etd_num;
-       struct etd_priv *etd = imx21->etd + etd_num;
-       struct urb *urb = etd->urb;
-       struct urb_priv *urb_priv = urb->hcpriv;
-       struct td *td = etd->td;
-       struct usb_host_endpoint *ep = etd->ep;
-       int isoc_index = td->isoc_index;
-       unsigned int pipe = urb->pipe;
-       int dir_in = usb_pipein(pipe);
-       int cc;
-       int bytes_xfrd;
-
-       disactivate_etd(imx21, etd_num);
-
-       cc = (etd_readl(imx21, etd_num, 3) >> DW3_COMPCODE0) & 0xf;
-       bytes_xfrd = etd_readl(imx21, etd_num, 3) & 0x3ff;
-
-       /* Input doesn't always fill the buffer, don't generate an error
-        * when this happens.
-        */
-       if (dir_in && (cc == TD_DATAUNDERRUN))
-               cc = TD_CC_NOERROR;
-
-       if (cc == TD_NOTACCESSED)
-               bytes_xfrd = 0;
-
-       debug_isoc_completed(imx21,
-               imx21_hc_get_frame(hcd), td, cc, bytes_xfrd);
-       if (cc) {
-               urb_priv->isoc_status = -EXDEV;
-               dev_dbg(imx21->dev,
-                       "bad iso cc=0x%X frame=%d sched frame=%d "
-                       "cnt=%d len=%d urb=%p etd=%d index=%d\n",
-                       cc,  imx21_hc_get_frame(hcd), td->frame,
-                       bytes_xfrd, td->len, urb, etd_num, isoc_index);
-       }
-
-       if (dir_in) {
-               clear_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
-               if (!etd->dma_handle)
-                       memcpy_fromio(etd->cpu_buffer,
-                               imx21->regs + USBOTG_DMEM + etd->dmem_offset,
-                               bytes_xfrd);
-       }
-
-       urb->actual_length += bytes_xfrd;
-       urb->iso_frame_desc[isoc_index].actual_length = bytes_xfrd;
-       urb->iso_frame_desc[isoc_index].status = cc_to_error[cc];
-
-       etd->td = NULL;
-       etd->urb = NULL;
-       etd->ep = NULL;
-
-       if (--urb_priv->isoc_remaining == 0)
-               urb_done(hcd, urb, urb_priv->isoc_status);
-
-       schedule_isoc_etds(hcd, ep);
-}
-
-static struct ep_priv *alloc_isoc_ep(
-       struct imx21 *imx21, struct usb_host_endpoint *ep)
-{
-       struct ep_priv *ep_priv;
-       int i;
-
-       ep_priv = kzalloc(sizeof(struct ep_priv), GFP_ATOMIC);
-       if (!ep_priv)
-               return NULL;
-
-       for (i = 0; i < NUM_ISO_ETDS; i++)
-               ep_priv->etd[i] = -1;
-
-       INIT_LIST_HEAD(&ep_priv->td_list);
-       ep_priv->ep = ep;
-       ep->hcpriv = ep_priv;
-       return ep_priv;
-}
-
-static int alloc_isoc_etds(struct imx21 *imx21, struct ep_priv *ep_priv)
-{
-       int i, j;
-       int etd_num;
-
-       /* Allocate the ETDs if required */
-       for (i = 0; i < NUM_ISO_ETDS; i++) {
-               if (ep_priv->etd[i] < 0) {
-                       etd_num = alloc_etd(imx21);
-                       if (etd_num < 0)
-                               goto alloc_etd_failed;
-
-                       ep_priv->etd[i] = etd_num;
-                       imx21->etd[etd_num].ep = ep_priv->ep;
-               }
-       }
-       return 0;
-
-alloc_etd_failed:
-       dev_err(imx21->dev, "isoc: Couldn't allocate etd\n");
-       for (j = 0; j < i; j++) {
-               free_etd(imx21, ep_priv->etd[j]);
-               ep_priv->etd[j] = -1;
-       }
-       return -ENOMEM;
-}
-
-static int imx21_hc_urb_enqueue_isoc(struct usb_hcd *hcd,
-                                    struct usb_host_endpoint *ep,
-                                    struct urb *urb, gfp_t mem_flags)
-{
-       struct imx21 *imx21 = hcd_to_imx21(hcd);
-       struct urb_priv *urb_priv;
-       unsigned long flags;
-       struct ep_priv *ep_priv;
-       struct td *td = NULL;
-       int i;
-       int ret;
-       int cur_frame;
-       u16 maxpacket;
-
-       urb_priv = kzalloc(sizeof(struct urb_priv), mem_flags);
-       if (urb_priv == NULL)
-               return -ENOMEM;
-
-       urb_priv->isoc_td = kcalloc(urb->number_of_packets, sizeof(struct td),
-                                   mem_flags);
-       if (urb_priv->isoc_td == NULL) {
-               ret = -ENOMEM;
-               goto alloc_td_failed;
-       }
-
-       spin_lock_irqsave(&imx21->lock, flags);
-
-       if (ep->hcpriv == NULL) {
-               ep_priv = alloc_isoc_ep(imx21, ep);
-               if (ep_priv == NULL) {
-                       ret = -ENOMEM;
-                       goto alloc_ep_failed;
-               }
-       } else {
-               ep_priv = ep->hcpriv;
-       }
-
-       ret = alloc_isoc_etds(imx21, ep_priv);
-       if (ret)
-               goto alloc_etd_failed;
-
-       ret = usb_hcd_link_urb_to_ep(hcd, urb);
-       if (ret)
-               goto link_failed;
-
-       urb->status = -EINPROGRESS;
-       urb->actual_length = 0;
-       urb->error_count = 0;
-       urb->hcpriv = urb_priv;
-       urb_priv->ep = ep;
-
-       /* allocate data memory for largest packets if not already done */
-       maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-       for (i = 0; i < NUM_ISO_ETDS; i++) {
-               struct etd_priv *etd = &imx21->etd[ep_priv->etd[i]];
-
-               if (etd->dmem_size > 0 && etd->dmem_size < maxpacket) {
-                       /* not sure if this can really occur.... */
-                       dev_err(imx21->dev, "increasing isoc buffer %d->%d\n",
-                               etd->dmem_size, maxpacket);
-                       ret = -EMSGSIZE;
-                       goto alloc_dmem_failed;
-               }
-
-               if (etd->dmem_size == 0) {
-                       etd->dmem_offset = alloc_dmem(imx21, maxpacket, ep);
-                       if (etd->dmem_offset < 0) {
-                               dev_dbg(imx21->dev, "failed alloc isoc dmem\n");
-                               ret = -EAGAIN;
-                               goto alloc_dmem_failed;
-                       }
-                       etd->dmem_size = maxpacket;
-               }
-       }
-
-       /* calculate frame */
-       cur_frame = imx21_hc_get_frame(hcd);
-       i = 0;
-       if (list_empty(&ep_priv->td_list)) {
-               urb->start_frame = wrap_frame(cur_frame + 5);
-       } else {
-               urb->start_frame = wrap_frame(list_entry(ep_priv->td_list.prev,
-                               struct td, list)->frame + urb->interval);
-
-               if (frame_after(cur_frame, urb->start_frame)) {
-                       dev_dbg(imx21->dev,
-                               "enqueue: adjusting iso start %d (cur=%d) asap=%d\n",
-                               urb->start_frame, cur_frame,
-                               (urb->transfer_flags & URB_ISO_ASAP) != 0);
-                       i = DIV_ROUND_UP(wrap_frame(
-                                       cur_frame - urb->start_frame),
-                                       urb->interval);
-
-                       /* Treat underruns as if URB_ISO_ASAP was set */
-                       if ((urb->transfer_flags & URB_ISO_ASAP) ||
-                                       i >= urb->number_of_packets) {
-                               urb->start_frame = wrap_frame(urb->start_frame
-                                               + i * urb->interval);
-                               i = 0;
-                       }
-               }
-       }
-
-       /* set up transfers */
-       urb_priv->isoc_remaining = urb->number_of_packets - i;
-       td = urb_priv->isoc_td;
-       for (; i < urb->number_of_packets; i++, td++) {
-               unsigned int offset = urb->iso_frame_desc[i].offset;
-               td->ep = ep;
-               td->urb = urb;
-               td->len = urb->iso_frame_desc[i].length;
-               td->isoc_index = i;
-               td->frame = wrap_frame(urb->start_frame + urb->interval * i);
-               td->dma_handle = urb->transfer_dma + offset;
-               td->cpu_buffer = urb->transfer_buffer + offset;
-               list_add_tail(&td->list, &ep_priv->td_list);
-       }
-
-       dev_vdbg(imx21->dev, "setup %d packets for iso frame %d->%d\n",
-               urb->number_of_packets, urb->start_frame, td->frame);
-
-       debug_urb_submitted(imx21, urb);
-       schedule_isoc_etds(hcd, ep);
-
-       spin_unlock_irqrestore(&imx21->lock, flags);
-       return 0;
-
-alloc_dmem_failed:
-       usb_hcd_unlink_urb_from_ep(hcd, urb);
-
-link_failed:
-alloc_etd_failed:
-alloc_ep_failed:
-       spin_unlock_irqrestore(&imx21->lock, flags);
-       kfree(urb_priv->isoc_td);
-
-alloc_td_failed:
-       kfree(urb_priv);
-       return ret;
-}
-
-static void dequeue_isoc_urb(struct imx21 *imx21,
-       struct urb *urb, struct ep_priv *ep_priv)
-{
-       struct urb_priv *urb_priv = urb->hcpriv;
-       struct td *td, *tmp;
-       int i;
-
-       if (urb_priv->active) {
-               for (i = 0; i < NUM_ISO_ETDS; i++) {
-                       int etd_num = ep_priv->etd[i];
-                       if (etd_num != -1 && imx21->etd[etd_num].urb == urb) {
-                               struct etd_priv *etd = imx21->etd + etd_num;
-
-                               reset_etd(imx21, etd_num);
-                               free_dmem(imx21, etd);
-                       }
-               }
-       }
-
-       list_for_each_entry_safe(td, tmp, &ep_priv->td_list, list) {
-               if (td->urb == urb) {
-                       dev_vdbg(imx21->dev, "removing td %p\n", td);
-                       list_del(&td->list);
-               }
-       }
-}
-
-/* =========================================== */
-/* NON ISOC Handling ...                       */
-/* =========================================== */
-
-static void schedule_nonisoc_etd(struct imx21 *imx21, struct urb *urb)
-{
-       unsigned int pipe = urb->pipe;
-       struct urb_priv *urb_priv = urb->hcpriv;
-       struct ep_priv *ep_priv = urb_priv->ep->hcpriv;
-       int state = urb_priv->state;
-       int etd_num = ep_priv->etd[0];
-       struct etd_priv *etd;
-       u32 count;
-       u16 etd_buf_size;
-       u16 maxpacket;
-       u8 dir;
-       u8 bufround;
-       u8 datatoggle;
-       u8 interval = 0;
-       u8 relpolpos = 0;
-
-       if (etd_num < 0) {
-               dev_err(imx21->dev, "No valid ETD\n");
-               return;
-       }
-       if (readl(imx21->regs + USBH_ETDENSET) & (1 << etd_num))
-               dev_err(imx21->dev, "submitting to active ETD %d\n", etd_num);
-
-       etd = &imx21->etd[etd_num];
-       maxpacket = usb_maxpacket(urb->dev, pipe, usb_pipeout(pipe));
-       if (!maxpacket)
-               maxpacket = 8;
-
-       if (usb_pipecontrol(pipe) && (state != US_CTRL_DATA)) {
-               if (state == US_CTRL_SETUP) {
-                       dir = TD_DIR_SETUP;
-                       if (unsuitable_for_dma(urb->setup_dma))
-                               usb_hcd_unmap_urb_setup_for_dma(imx21->hcd,
-                                       urb);
-                       etd->dma_handle = urb->setup_dma;
-                       etd->cpu_buffer = urb->setup_packet;
-                       bufround = 0;
-                       count = 8;
-                       datatoggle = TD_TOGGLE_DATA0;
-               } else {        /* US_CTRL_ACK */
-                       dir = usb_pipeout(pipe) ? TD_DIR_IN : TD_DIR_OUT;
-                       bufround = 0;
-                       count = 0;
-                       datatoggle = TD_TOGGLE_DATA1;
-               }
-       } else {
-               dir = usb_pipeout(pipe) ? TD_DIR_OUT : TD_DIR_IN;
-               bufround = (dir == TD_DIR_IN) ? 1 : 0;
-               if (unsuitable_for_dma(urb->transfer_dma))
-                       usb_hcd_unmap_urb_for_dma(imx21->hcd, urb);
-
-               etd->dma_handle = urb->transfer_dma;
-               etd->cpu_buffer = urb->transfer_buffer;
-               if (usb_pipebulk(pipe) && (state == US_BULK0))
-                       count = 0;
-               else
-                       count = urb->transfer_buffer_length;
-
-               if (usb_pipecontrol(pipe)) {
-                       datatoggle = TD_TOGGLE_DATA1;
-               } else {
-                       if (usb_gettoggle(
-                                       urb->dev,
-                                       usb_pipeendpoint(urb->pipe),
-                                       usb_pipeout(urb->pipe)))
-                               datatoggle = TD_TOGGLE_DATA1;
-                       else
-                               datatoggle = TD_TOGGLE_DATA0;
-               }
-       }
-
-       etd->urb = urb;
-       etd->ep = urb_priv->ep;
-       etd->len = count;
-
-       if (usb_pipeint(pipe)) {
-               interval = urb->interval;
-               relpolpos = (readl(imx21->regs + USBH_FRMNUB) + 1) & 0xff;
-       }
-
-       /* Write ETD to device memory */
-       setup_etd_dword0(imx21, etd_num, urb, dir, maxpacket);
-
-       etd_writel(imx21, etd_num, 2,
-               (u32) interval << DW2_POLINTERV |
-               ((u32) relpolpos << DW2_RELPOLPOS) |
-               ((u32) dir << DW2_DIRPID) |
-               ((u32) bufround << DW2_BUFROUND) |
-               ((u32) datatoggle << DW2_DATATOG) |
-               ((u32) TD_NOTACCESSED << DW2_COMPCODE));
-
-       /* DMA will always transfer buffer size even if TOBYCNT in DWORD3
-          is smaller. Make sure we don't overrun the buffer!
-        */
-       if (count && count < maxpacket)
-               etd_buf_size = count;
-       else
-               etd_buf_size = maxpacket;
-
-       etd_writel(imx21, etd_num, 3,
-               ((u32) (etd_buf_size - 1) << DW3_BUFSIZE) | (u32) count);
-
-       if (!count)
-               etd->dma_handle = 0;
-
-       /* allocate x and y buffer space at once */
-       etd->dmem_size = (count > maxpacket) ? maxpacket * 2 : maxpacket;
-       etd->dmem_offset = alloc_dmem(imx21, etd->dmem_size, urb_priv->ep);
-       if (etd->dmem_offset < 0) {
-               /* Setup everything we can in HW and update when we get DMEM */
-               etd_writel(imx21, etd_num, 1, (u32)maxpacket << 16);
-
-               dev_dbg(imx21->dev, "Queuing etd %d for DMEM\n", etd_num);
-               debug_urb_queued_for_dmem(imx21, urb);
-               list_add_tail(&etd->queue, &imx21->queue_for_dmem);
-               return;
-       }
-
-       etd_writel(imx21, etd_num, 1,
-               (((u32) etd->dmem_offset + (u32) maxpacket) << DW1_YBUFSRTAD) |
-               (u32) etd->dmem_offset);
-
-       urb_priv->active = 1;
-
-       /* enable the ETD to kick off transfer */
-       dev_vdbg(imx21->dev, "Activating etd %d for %d bytes %s\n",
-               etd_num, count, dir != TD_DIR_IN ? "out" : "in");
-       activate_etd(imx21, etd_num, dir);
-
-}
-
-static void nonisoc_etd_done(struct usb_hcd *hcd, int etd_num)
-{
-       struct imx21 *imx21 = hcd_to_imx21(hcd);
-       struct etd_priv *etd = &imx21->etd[etd_num];
-       struct urb *urb = etd->urb;
-       u32 etd_mask = 1 << etd_num;
-       struct urb_priv *urb_priv = urb->hcpriv;
-       int dir;
-       int cc;
-       u32 bytes_xfrd;
-       int etd_done;
-
-       disactivate_etd(imx21, etd_num);
-
-       dir = (etd_readl(imx21, etd_num, 0) >> DW0_DIRECT) & 0x3;
-       cc = (etd_readl(imx21, etd_num, 2) >> DW2_COMPCODE) & 0xf;
-       bytes_xfrd = etd->len - (etd_readl(imx21, etd_num, 3) & 0x1fffff);
-
-       /* save toggle carry */
-       usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-                     usb_pipeout(urb->pipe),
-                     (etd_readl(imx21, etd_num, 0) >> DW0_TOGCRY) & 0x1);
-
-       if (dir == TD_DIR_IN) {
-               clear_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
-               clear_toggle_bit(imx21, USBH_YFILLSTAT, etd_mask);
-
-               if (etd->bounce_buffer) {
-                       memcpy(etd->cpu_buffer, etd->bounce_buffer, bytes_xfrd);
-                       dma_unmap_single(imx21->dev,
-                               etd->dma_handle, etd->len, DMA_FROM_DEVICE);
-               } else if (!etd->dma_handle && bytes_xfrd) {/* PIO */
-                       memcpy_fromio(etd->cpu_buffer,
-                               imx21->regs + USBOTG_DMEM + etd->dmem_offset,
-                               bytes_xfrd);
-               }
-       }
-
-       kfree(etd->bounce_buffer);
-       etd->bounce_buffer = NULL;
-       free_dmem(imx21, etd);
-
-       urb->error_count = 0;
-       if (!(urb->transfer_flags & URB_SHORT_NOT_OK)
-                       && (cc == TD_DATAUNDERRUN))
-               cc = TD_CC_NOERROR;
-
-       if (cc != 0)
-               dev_vdbg(imx21->dev, "cc is 0x%x\n", cc);
-
-       etd_done = (cc_to_error[cc] != 0);      /* stop if error */
-
-       switch (usb_pipetype(urb->pipe)) {
-       case PIPE_CONTROL:
-               switch (urb_priv->state) {
-               case US_CTRL_SETUP:
-                       if (urb->transfer_buffer_length > 0)
-                               urb_priv->state = US_CTRL_DATA;
-                       else
-                               urb_priv->state = US_CTRL_ACK;
-                       break;
-               case US_CTRL_DATA:
-                       urb->actual_length += bytes_xfrd;
-                       urb_priv->state = US_CTRL_ACK;
-                       break;
-               case US_CTRL_ACK:
-                       etd_done = 1;
-                       break;
-               default:
-                       dev_err(imx21->dev,
-                               "Invalid pipe state %d\n", urb_priv->state);
-                       etd_done = 1;
-                       break;
-               }
-               break;
-
-       case PIPE_BULK:
-               urb->actual_length += bytes_xfrd;
-               if ((urb_priv->state == US_BULK)
-                   && (urb->transfer_flags & URB_ZERO_PACKET)
-                   && urb->transfer_buffer_length > 0
-                   && ((urb->transfer_buffer_length %
-                        usb_maxpacket(urb->dev, urb->pipe,
-                                      usb_pipeout(urb->pipe))) == 0)) {
-                       /* need a 0-packet */
-                       urb_priv->state = US_BULK0;
-               } else {
-                       etd_done = 1;
-               }
-               break;
-
-       case PIPE_INTERRUPT:
-               urb->actual_length += bytes_xfrd;
-               etd_done = 1;
-               break;
-       }
-
-       if (etd_done)
-               nonisoc_urb_completed_for_etd(imx21, etd, cc_to_error[cc]);
-       else {
-               dev_vdbg(imx21->dev, "next state=%d\n", urb_priv->state);
-               schedule_nonisoc_etd(imx21, urb);
-       }
-}
-
-
-static struct ep_priv *alloc_ep(void)
-{
-       int i;
-       struct ep_priv *ep_priv;
-
-       ep_priv = kzalloc(sizeof(struct ep_priv), GFP_ATOMIC);
-       if (!ep_priv)
-               return NULL;
-
-       for (i = 0; i < NUM_ISO_ETDS; ++i)
-               ep_priv->etd[i] = -1;
-
-       return ep_priv;
-}
-
-static int imx21_hc_urb_enqueue(struct usb_hcd *hcd,
-                               struct urb *urb, gfp_t mem_flags)
-{
-       struct imx21 *imx21 = hcd_to_imx21(hcd);
-       struct usb_host_endpoint *ep = urb->ep;
-       struct urb_priv *urb_priv;
-       struct ep_priv *ep_priv;
-       struct etd_priv *etd;
-       int ret;
-       unsigned long flags;
-
-       dev_vdbg(imx21->dev,
-               "enqueue urb=%p ep=%p len=%d "
-               "buffer=%p dma=%pad setupBuf=%p setupDma=%pad\n",
-               urb, ep,
-               urb->transfer_buffer_length,
-               urb->transfer_buffer, &urb->transfer_dma,
-               urb->setup_packet, &urb->setup_dma);
-
-       if (usb_pipeisoc(urb->pipe))
-               return imx21_hc_urb_enqueue_isoc(hcd, ep, urb, mem_flags);
-
-       urb_priv = kzalloc(sizeof(struct urb_priv), mem_flags);
-       if (!urb_priv)
-               return -ENOMEM;
-
-       spin_lock_irqsave(&imx21->lock, flags);
-
-       ep_priv = ep->hcpriv;
-       if (ep_priv == NULL) {
-               ep_priv = alloc_ep();
-               if (!ep_priv) {
-                       ret = -ENOMEM;
-                       goto failed_alloc_ep;
-               }
-               ep->hcpriv = ep_priv;
-               ep_priv->ep = ep;
-       }
-
-       ret = usb_hcd_link_urb_to_ep(hcd, urb);
-       if (ret)
-               goto failed_link;
-
-       urb->status = -EINPROGRESS;
-       urb->actual_length = 0;
-       urb->error_count = 0;
-       urb->hcpriv = urb_priv;
-       urb_priv->ep = ep;
-
-       switch (usb_pipetype(urb->pipe)) {
-       case PIPE_CONTROL:
-               urb_priv->state = US_CTRL_SETUP;
-               break;
-       case PIPE_BULK:
-               urb_priv->state = US_BULK;
-               break;
-       }
-
-       debug_urb_submitted(imx21, urb);
-       if (ep_priv->etd[0] < 0) {
-               if (ep_priv->waiting_etd) {
-                       dev_dbg(imx21->dev,
-                               "no ETD available already queued %p\n",
-                               ep_priv);
-                       debug_urb_queued_for_etd(imx21, urb);
-                       goto out;
-               }
-               ep_priv->etd[0] = alloc_etd(imx21);
-               if (ep_priv->etd[0] < 0) {
-                       dev_dbg(imx21->dev,
-                               "no ETD available queueing %p\n", ep_priv);
-                       debug_urb_queued_for_etd(imx21, urb);
-                       list_add_tail(&ep_priv->queue, &imx21->queue_for_etd);
-                       ep_priv->waiting_etd = 1;
-                       goto out;
-               }
-       }
-
-       /* Schedule if no URB already active for this endpoint */
-       etd = &imx21->etd[ep_priv->etd[0]];
-       if (etd->urb == NULL) {
-               DEBUG_LOG_FRAME(imx21, etd, last_req);
-               schedule_nonisoc_etd(imx21, urb);
-       }
-
-out:
-       spin_unlock_irqrestore(&imx21->lock, flags);
-       return 0;
-
-failed_link:
-failed_alloc_ep:
-       spin_unlock_irqrestore(&imx21->lock, flags);
-       kfree(urb_priv);
-       return ret;
-}
-
-static int imx21_hc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
-                               int status)
-{
-       struct imx21 *imx21 = hcd_to_imx21(hcd);
-       unsigned long flags;
-       struct usb_host_endpoint *ep;
-       struct ep_priv *ep_priv;
-       struct urb_priv *urb_priv = urb->hcpriv;
-       int ret = -EINVAL;
-
-       dev_vdbg(imx21->dev, "dequeue urb=%p iso=%d status=%d\n",
-               urb, usb_pipeisoc(urb->pipe), status);
-
-       spin_lock_irqsave(&imx21->lock, flags);
-
-       ret = usb_hcd_check_unlink_urb(hcd, urb, status);
-       if (ret)
-               goto fail;
-       ep = urb_priv->ep;
-       ep_priv = ep->hcpriv;
-
-       debug_urb_unlinked(imx21, urb);
-
-       if (usb_pipeisoc(urb->pipe)) {
-               dequeue_isoc_urb(imx21, urb, ep_priv);
-               schedule_isoc_etds(hcd, ep);
-       } else if (urb_priv->active) {
-               int etd_num = ep_priv->etd[0];
-               if (etd_num != -1) {
-                       struct etd_priv *etd = &imx21->etd[etd_num];
-
-                       disactivate_etd(imx21, etd_num);
-                       free_dmem(imx21, etd);
-                       etd->urb = NULL;
-                       kfree(etd->bounce_buffer);
-                       etd->bounce_buffer = NULL;
-               }
-       }
-
-       urb_done(hcd, urb, status);
-
-       spin_unlock_irqrestore(&imx21->lock, flags);
-       return 0;
-
-fail:
-       spin_unlock_irqrestore(&imx21->lock, flags);
-       return ret;
-}
-
-/* =========================================== */
-/* Interrupt dispatch                          */
-/* =========================================== */
-
-static void process_etds(struct usb_hcd *hcd, struct imx21 *imx21, int sof)
-{
-       int etd_num;
-       int enable_sof_int = 0;
-       unsigned long flags;
-
-       spin_lock_irqsave(&imx21->lock, flags);
-
-       for (etd_num = 0; etd_num < USB_NUM_ETD; etd_num++) {
-               u32 etd_mask = 1 << etd_num;
-               u32 enabled = readl(imx21->regs + USBH_ETDENSET) & etd_mask;
-               u32 done = readl(imx21->regs + USBH_ETDDONESTAT) & etd_mask;
-               struct etd_priv *etd = &imx21->etd[etd_num];
-
-
-               if (done) {
-                       DEBUG_LOG_FRAME(imx21, etd, last_int);
-               } else {
-/*
- * Kludge warning!
- *
- * When multiple transfers are using the bus we sometimes get into a state
- * where the transfer has completed (the CC field of the ETD is != 0x0F),
- * the ETD has self disabled but the ETDDONESTAT flag is not set
- * (and hence no interrupt occurs).
- * This causes the transfer in question to hang.
- * The kludge below checks for this condition at each SOF and processes any
- * blocked ETDs (after an arbitrary 10 frame wait)
- *
- * With a single active transfer the usbtest test suite will run for days
- * without the kludge.
- * With other bus activity (eg mass storage) even just test1 will hang without
- * the kludge.
- */
-                       u32 dword0;
-                       int cc;
-
-                       if (etd->active_count && !enabled) /* suspicious... */
-                               enable_sof_int = 1;
-
-                       if (!sof || enabled || !etd->active_count)
-                               continue;
-
-                       cc = etd_readl(imx21, etd_num, 2) >> DW2_COMPCODE;
-                       if (cc == TD_NOTACCESSED)
-                               continue;
-
-                       if (++etd->active_count < 10)
-                               continue;
-
-                       dword0 = etd_readl(imx21, etd_num, 0);
-                       dev_dbg(imx21->dev,
-                               "unblock ETD %d dev=0x%X ep=0x%X cc=0x%02X!\n",
-                               etd_num, dword0 & 0x7F,
-                               (dword0 >> DW0_ENDPNT) & 0x0F,
-                               cc);
-
-#ifdef DEBUG
-                       dev_dbg(imx21->dev,
-                               "frame: act=%d disact=%d"
-                               " int=%d req=%d cur=%d\n",
-                               etd->activated_frame,
-                               etd->disactivated_frame,
-                               etd->last_int_frame,
-                               etd->last_req_frame,
-                               readl(imx21->regs + USBH_FRMNUB));
-                       imx21->debug_unblocks++;
-#endif
-                       etd->active_count = 0;
-/* End of kludge */
-               }
-
-               if (etd->ep == NULL || etd->urb == NULL) {
-                       dev_dbg(imx21->dev,
-                               "Interrupt for unexpected etd %d"
-                               " ep=%p urb=%p\n",
-                               etd_num, etd->ep, etd->urb);
-                       disactivate_etd(imx21, etd_num);
-                       continue;
-               }
-
-               if (usb_pipeisoc(etd->urb->pipe))
-                       isoc_etd_done(hcd, etd_num);
-               else
-                       nonisoc_etd_done(hcd, etd_num);
-       }
-
-       /* only enable SOF interrupt if it may be needed for the kludge */
-       if (enable_sof_int)
-               set_register_bits(imx21, USBH_SYSIEN, USBH_SYSIEN_SOFINT);
-       else
-               clear_register_bits(imx21, USBH_SYSIEN, USBH_SYSIEN_SOFINT);
-
-
-       spin_unlock_irqrestore(&imx21->lock, flags);
-}
-
-static irqreturn_t imx21_irq(struct usb_hcd *hcd)
-{
-       struct imx21 *imx21 = hcd_to_imx21(hcd);
-       u32 ints = readl(imx21->regs + USBH_SYSISR);
-
-       if (ints & USBH_SYSIEN_HERRINT)
-               dev_dbg(imx21->dev, "Scheduling error\n");
-
-       if (ints & USBH_SYSIEN_SORINT)
-               dev_dbg(imx21->dev, "Scheduling overrun\n");
-
-       if (ints & (USBH_SYSISR_DONEINT | USBH_SYSISR_SOFINT))
-               process_etds(hcd, imx21, ints & USBH_SYSISR_SOFINT);
-
-       writel(ints, imx21->regs + USBH_SYSISR);
-       return IRQ_HANDLED;
-}
-
-static void imx21_hc_endpoint_disable(struct usb_hcd *hcd,
-                                     struct usb_host_endpoint *ep)
-{
-       struct imx21 *imx21 = hcd_to_imx21(hcd);
-       unsigned long flags;
-       struct ep_priv *ep_priv;
-       int i;
-
-       if (ep == NULL)
-               return;
-
-       spin_lock_irqsave(&imx21->lock, flags);
-       ep_priv = ep->hcpriv;
-       dev_vdbg(imx21->dev, "disable ep=%p, ep->hcpriv=%p\n", ep, ep_priv);
-
-       if (!list_empty(&ep->urb_list))
-               dev_dbg(imx21->dev, "ep's URB list is not empty\n");
-
-       if (ep_priv != NULL) {
-               for (i = 0; i < NUM_ISO_ETDS; i++) {
-                       if (ep_priv->etd[i] > -1)
-                               dev_dbg(imx21->dev, "free etd %d for disable\n",
-                                       ep_priv->etd[i]);
-
-                       free_etd(imx21, ep_priv->etd[i]);
-               }
-               kfree(ep_priv);
-               ep->hcpriv = NULL;
-       }
-
-       for (i = 0; i < USB_NUM_ETD; i++) {
-               if (imx21->etd[i].alloc && imx21->etd[i].ep == ep) {
-                       dev_err(imx21->dev,
-                               "Active etd %d for disabled ep=%p!\n", i, ep);
-                       free_etd(imx21, i);
-               }
-       }
-       free_epdmem(imx21, ep);
-       spin_unlock_irqrestore(&imx21->lock, flags);
-}
-
-/* =========================================== */
-/* Hub handling                                        */
-/* =========================================== */
-
-static int get_hub_descriptor(struct usb_hcd *hcd,
-                             struct usb_hub_descriptor *desc)
-{
-       struct imx21 *imx21 = hcd_to_imx21(hcd);
-       desc->bDescriptorType = USB_DT_HUB; /* HUB descriptor */
-       desc->bHubContrCurrent = 0;
-
-       desc->bNbrPorts = readl(imx21->regs + USBH_ROOTHUBA)
-               & USBH_ROOTHUBA_NDNSTMPRT_MASK;
-       desc->bDescLength = 9;
-       desc->bPwrOn2PwrGood = 0;
-       desc->wHubCharacteristics = (__force __u16) cpu_to_le16(
-               HUB_CHAR_NO_LPSM |      /* No power switching */
-               HUB_CHAR_NO_OCPM);      /* No over current protection */
-
-       desc->u.hs.DeviceRemovable[0] = 1 << 1;
-       desc->u.hs.DeviceRemovable[1] = ~0;
-       return 0;
-}
-
-static int imx21_hc_hub_status_data(struct usb_hcd *hcd, char *buf)
-{
-       struct imx21 *imx21 = hcd_to_imx21(hcd);
-       int ports;
-       int changed = 0;
-       int i;
-       unsigned long flags;
-
-       spin_lock_irqsave(&imx21->lock, flags);
-       ports = readl(imx21->regs + USBH_ROOTHUBA)
-               & USBH_ROOTHUBA_NDNSTMPRT_MASK;
-       if (ports > 7) {
-               ports = 7;
-               dev_err(imx21->dev, "ports %d > 7\n", ports);
-       }
-       for (i = 0; i < ports; i++) {
-               if (readl(imx21->regs + USBH_PORTSTAT(i)) &
-                       (USBH_PORTSTAT_CONNECTSC |
-                       USBH_PORTSTAT_PRTENBLSC |
-                       USBH_PORTSTAT_PRTSTATSC |
-                       USBH_PORTSTAT_OVRCURIC |
-                       USBH_PORTSTAT_PRTRSTSC)) {
-
-                       changed = 1;
-                       buf[0] |= 1 << (i + 1);
-               }
-       }
-       spin_unlock_irqrestore(&imx21->lock, flags);
-
-       if (changed)
-               dev_info(imx21->dev, "Hub status changed\n");
-       return changed;
-}
-
-static int imx21_hc_hub_control(struct usb_hcd *hcd,
-                               u16 typeReq,
-                               u16 wValue, u16 wIndex, char *buf, u16 wLength)
-{
-       struct imx21 *imx21 = hcd_to_imx21(hcd);
-       int rc = 0;
-       u32 status_write = 0;
-
-       switch (typeReq) {
-       case ClearHubFeature:
-               dev_dbg(imx21->dev, "ClearHubFeature\n");
-               switch (wValue) {
-               case C_HUB_OVER_CURRENT:
-                       dev_dbg(imx21->dev, "    OVER_CURRENT\n");
-                       break;
-               case C_HUB_LOCAL_POWER:
-                       dev_dbg(imx21->dev, "    LOCAL_POWER\n");
-                       break;
-               default:
-                       dev_dbg(imx21->dev, "    unknown\n");
-                       rc = -EINVAL;
-                       break;
-               }
-               break;
-
-       case ClearPortFeature:
-               dev_dbg(imx21->dev, "ClearPortFeature\n");
-               switch (wValue) {
-               case USB_PORT_FEAT_ENABLE:
-                       dev_dbg(imx21->dev, "    ENABLE\n");
-                       status_write = USBH_PORTSTAT_CURCONST;
-                       break;
-               case USB_PORT_FEAT_SUSPEND:
-                       dev_dbg(imx21->dev, "    SUSPEND\n");
-                       status_write = USBH_PORTSTAT_PRTOVRCURI;
-                       break;
-               case USB_PORT_FEAT_POWER:
-                       dev_dbg(imx21->dev, "    POWER\n");
-                       status_write = USBH_PORTSTAT_LSDEVCON;
-                       break;
-               case USB_PORT_FEAT_C_ENABLE:
-                       dev_dbg(imx21->dev, "    C_ENABLE\n");
-                       status_write = USBH_PORTSTAT_PRTENBLSC;
-                       break;
-               case USB_PORT_FEAT_C_SUSPEND:
-                       dev_dbg(imx21->dev, "    C_SUSPEND\n");
-                       status_write = USBH_PORTSTAT_PRTSTATSC;
-                       break;
-               case USB_PORT_FEAT_C_CONNECTION:
-                       dev_dbg(imx21->dev, "    C_CONNECTION\n");
-                       status_write = USBH_PORTSTAT_CONNECTSC;
-                       break;
-               case USB_PORT_FEAT_C_OVER_CURRENT:
-                       dev_dbg(imx21->dev, "    C_OVER_CURRENT\n");
-                       status_write = USBH_PORTSTAT_OVRCURIC;
-                       break;
-               case USB_PORT_FEAT_C_RESET:
-                       dev_dbg(imx21->dev, "    C_RESET\n");
-                       status_write = USBH_PORTSTAT_PRTRSTSC;
-                       break;
-               default:
-                       dev_dbg(imx21->dev, "    unknown\n");
-                       rc = -EINVAL;
-                       break;
-               }
-
-               break;
-
-       case GetHubDescriptor:
-               dev_dbg(imx21->dev, "GetHubDescriptor\n");
-               rc = get_hub_descriptor(hcd, (void *)buf);
-               break;
-
-       case GetHubStatus:
-               dev_dbg(imx21->dev, "  GetHubStatus\n");
-               *(__le32 *) buf = 0;
-               break;
-
-       case GetPortStatus:
-               dev_dbg(imx21->dev, "GetPortStatus: port: %d, 0x%x\n",
-                   wIndex, USBH_PORTSTAT(wIndex - 1));
-               *(__le32 *) buf = readl(imx21->regs +
-                       USBH_PORTSTAT(wIndex - 1));
-               break;
-
-       case SetHubFeature:
-               dev_dbg(imx21->dev, "SetHubFeature\n");
-               switch (wValue) {
-               case C_HUB_OVER_CURRENT:
-                       dev_dbg(imx21->dev, "    OVER_CURRENT\n");
-                       break;
-
-               case C_HUB_LOCAL_POWER:
-                       dev_dbg(imx21->dev, "    LOCAL_POWER\n");
-                       break;
-               default:
-                       dev_dbg(imx21->dev, "    unknown\n");
-                       rc = -EINVAL;
-                       break;
-               }
-
-               break;
-
-       case SetPortFeature:
-               dev_dbg(imx21->dev, "SetPortFeature\n");
-               switch (wValue) {
-               case USB_PORT_FEAT_SUSPEND:
-                       dev_dbg(imx21->dev, "    SUSPEND\n");
-                       status_write = USBH_PORTSTAT_PRTSUSPST;
-                       break;
-               case USB_PORT_FEAT_POWER:
-                       dev_dbg(imx21->dev, "    POWER\n");
-                       status_write = USBH_PORTSTAT_PRTPWRST;
-                       break;
-               case USB_PORT_FEAT_RESET:
-                       dev_dbg(imx21->dev, "    RESET\n");
-                       status_write = USBH_PORTSTAT_PRTRSTST;
-                       break;
-               default:
-                       dev_dbg(imx21->dev, "    unknown\n");
-                       rc = -EINVAL;
-                       break;
-               }
-               break;
-
-       default:
-               dev_dbg(imx21->dev, "  unknown\n");
-               rc = -EINVAL;
-               break;
-       }
-
-       if (status_write)
-               writel(status_write, imx21->regs + USBH_PORTSTAT(wIndex - 1));
-       return rc;
-}
-
-/* =========================================== */
-/* Host controller management                  */
-/* =========================================== */
-
-static int imx21_hc_reset(struct usb_hcd *hcd)
-{
-       struct imx21 *imx21 = hcd_to_imx21(hcd);
-       unsigned long timeout;
-       unsigned long flags;
-
-       spin_lock_irqsave(&imx21->lock, flags);
-
-       /* Reset the Host controller modules */
-       writel(USBOTG_RST_RSTCTRL | USBOTG_RST_RSTRH |
-               USBOTG_RST_RSTHSIE | USBOTG_RST_RSTHC,
-               imx21->regs + USBOTG_RST_CTRL);
-
-       /* Wait for reset to finish */
-       timeout = jiffies + HZ;
-       while (readl(imx21->regs + USBOTG_RST_CTRL) != 0) {
-               if (time_after(jiffies, timeout)) {
-                       spin_unlock_irqrestore(&imx21->lock, flags);
-                       dev_err(imx21->dev, "timeout waiting for reset\n");
-                       return -ETIMEDOUT;
-               }
-               spin_unlock_irq(&imx21->lock);
-               schedule_timeout_uninterruptible(1);
-               spin_lock_irq(&imx21->lock);
-       }
-       spin_unlock_irqrestore(&imx21->lock, flags);
-       return 0;
-}
-
-static int imx21_hc_start(struct usb_hcd *hcd)
-{
-       struct imx21 *imx21 = hcd_to_imx21(hcd);
-       unsigned long flags;
-       int i, j;
-       u32 hw_mode = USBOTG_HWMODE_CRECFG_HOST;
-       u32 usb_control = 0;
-
-       hw_mode |= ((imx21->pdata->host_xcvr << USBOTG_HWMODE_HOSTXCVR_SHIFT) &
-                       USBOTG_HWMODE_HOSTXCVR_MASK);
-       hw_mode |= ((imx21->pdata->otg_xcvr << USBOTG_HWMODE_OTGXCVR_SHIFT) &
-                       USBOTG_HWMODE_OTGXCVR_MASK);
-
-       if (imx21->pdata->host1_txenoe)
-               usb_control |= USBCTRL_HOST1_TXEN_OE;
-
-       if (!imx21->pdata->host1_xcverless)
-               usb_control |= USBCTRL_HOST1_BYP_TLL;
-
-       if (imx21->pdata->otg_ext_xcvr)
-               usb_control |= USBCTRL_OTC_RCV_RXDP;
-
-
-       spin_lock_irqsave(&imx21->lock, flags);
-
-       writel((USBOTG_CLK_CTRL_HST | USBOTG_CLK_CTRL_MAIN),
-               imx21->regs + USBOTG_CLK_CTRL);
-       writel(hw_mode, imx21->regs + USBOTG_HWMODE);
-       writel(usb_control, imx21->regs + USBCTRL);
-       writel(USB_MISCCONTROL_SKPRTRY  | USB_MISCCONTROL_ARBMODE,
-               imx21->regs + USB_MISCCONTROL);
-
-       /* Clear the ETDs */
-       for (i = 0; i < USB_NUM_ETD; i++)
-               for (j = 0; j < 4; j++)
-                       etd_writel(imx21, i, j, 0);
-
-       /* Take the HC out of reset */
-       writel(USBH_HOST_CTRL_HCUSBSTE_OPERATIONAL | USBH_HOST_CTRL_CTLBLKSR_1,
-               imx21->regs + USBH_HOST_CTRL);
-
-       /* Enable ports */
-       if (imx21->pdata->enable_otg_host)
-               writel(USBH_PORTSTAT_PRTPWRST | USBH_PORTSTAT_PRTENABST,
-                       imx21->regs + USBH_PORTSTAT(0));
-
-       if (imx21->pdata->enable_host1)
-               writel(USBH_PORTSTAT_PRTPWRST | USBH_PORTSTAT_PRTENABST,
-                       imx21->regs + USBH_PORTSTAT(1));
-
-       if (imx21->pdata->enable_host2)
-               writel(USBH_PORTSTAT_PRTPWRST | USBH_PORTSTAT_PRTENABST,
-                       imx21->regs + USBH_PORTSTAT(2));
-
-
-       hcd->state = HC_STATE_RUNNING;
-
-       /* Enable host controller interrupts */
-       set_register_bits(imx21, USBH_SYSIEN,
-               USBH_SYSIEN_HERRINT |
-               USBH_SYSIEN_DONEINT | USBH_SYSIEN_SORINT);
-       set_register_bits(imx21, USBOTG_CINT_STEN, USBOTG_HCINT);
-
-       spin_unlock_irqrestore(&imx21->lock, flags);
-
-       return 0;
-}
-
-static void imx21_hc_stop(struct usb_hcd *hcd)
-{
-       struct imx21 *imx21 = hcd_to_imx21(hcd);
-       unsigned long flags;
-
-       spin_lock_irqsave(&imx21->lock, flags);
-
-       writel(0, imx21->regs + USBH_SYSIEN);
-       clear_register_bits(imx21, USBOTG_CINT_STEN, USBOTG_HCINT);
-       clear_register_bits(imx21, USBOTG_CLK_CTRL_HST | USBOTG_CLK_CTRL_MAIN,
-                                       USBOTG_CLK_CTRL);
-       spin_unlock_irqrestore(&imx21->lock, flags);
-}
-
-/* =========================================== */
-/* Driver glue                                 */
-/* =========================================== */
-
-static const struct hc_driver imx21_hc_driver = {
-       .description = hcd_name,
-       .product_desc = "IMX21 USB Host Controller",
-       .hcd_priv_size = sizeof(struct imx21),
-
-       .flags = HCD_DMA | HCD_USB11,
-       .irq = imx21_irq,
-
-       .reset = imx21_hc_reset,
-       .start = imx21_hc_start,
-       .stop = imx21_hc_stop,
-
-       /* I/O requests */
-       .urb_enqueue = imx21_hc_urb_enqueue,
-       .urb_dequeue = imx21_hc_urb_dequeue,
-       .endpoint_disable = imx21_hc_endpoint_disable,
-
-       /* scheduling support */
-       .get_frame_number = imx21_hc_get_frame,
-
-       /* Root hub support */
-       .hub_status_data = imx21_hc_hub_status_data,
-       .hub_control = imx21_hc_hub_control,
-
-};
-
-static struct mx21_usbh_platform_data default_pdata = {
-       .host_xcvr = MX21_USBXCVR_TXDIF_RXDIF,
-       .otg_xcvr = MX21_USBXCVR_TXDIF_RXDIF,
-       .enable_host1 = 1,
-       .enable_host2 = 1,
-       .enable_otg_host = 1,
-
-};
-
-static int imx21_remove(struct platform_device *pdev)
-{
-       struct usb_hcd *hcd = platform_get_drvdata(pdev);
-       struct imx21 *imx21 = hcd_to_imx21(hcd);
-       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-       remove_debug_files(imx21);
-       usb_remove_hcd(hcd);
-
-       if (res != NULL) {
-               clk_disable_unprepare(imx21->clk);
-               clk_put(imx21->clk);
-               iounmap(imx21->regs);
-               release_mem_region(res->start, resource_size(res));
-       }
-
-       kfree(hcd);
-       return 0;
-}
-
-
-static int imx21_probe(struct platform_device *pdev)
-{
-       struct usb_hcd *hcd;
-       struct imx21 *imx21;
-       struct resource *res;
-       int ret;
-       int irq;
-
-       printk(KERN_INFO "%s\n", imx21_hc_driver.product_desc);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
-
-       hcd = usb_create_hcd(&imx21_hc_driver,
-               &pdev->dev, dev_name(&pdev->dev));
-       if (hcd == NULL) {
-               dev_err(&pdev->dev, "Cannot create hcd (%s)\n",
-                   dev_name(&pdev->dev));
-               return -ENOMEM;
-       }
-
-       imx21 = hcd_to_imx21(hcd);
-       imx21->hcd = hcd;
-       imx21->dev = &pdev->dev;
-       imx21->pdata = dev_get_platdata(&pdev->dev);
-       if (!imx21->pdata)
-               imx21->pdata = &default_pdata;
-
-       spin_lock_init(&imx21->lock);
-       INIT_LIST_HEAD(&imx21->dmem_list);
-       INIT_LIST_HEAD(&imx21->queue_for_etd);
-       INIT_LIST_HEAD(&imx21->queue_for_dmem);
-       create_debug_files(imx21);
-
-       res = request_mem_region(res->start, resource_size(res), hcd_name);
-       if (!res) {
-               ret = -EBUSY;
-               goto failed_request_mem;
-       }
-
-       imx21->regs = ioremap(res->start, resource_size(res));
-       if (imx21->regs == NULL) {
-               dev_err(imx21->dev, "Cannot map registers\n");
-               ret = -ENOMEM;
-               goto failed_ioremap;
-       }
-
-       /* Enable clocks source */
-       imx21->clk = clk_get(imx21->dev, NULL);
-       if (IS_ERR(imx21->clk)) {
-               dev_err(imx21->dev, "no clock found\n");
-               ret = PTR_ERR(imx21->clk);
-               goto failed_clock_get;
-       }
-
-       ret = clk_set_rate(imx21->clk, clk_round_rate(imx21->clk, 48000000));
-       if (ret)
-               goto failed_clock_set;
-       ret = clk_prepare_enable(imx21->clk);
-       if (ret)
-               goto failed_clock_enable;
-
-       dev_info(imx21->dev, "Hardware HC revision: 0x%02X\n",
-               (readl(imx21->regs + USBOTG_HWMODE) >> 16) & 0xFF);
-
-       ret = usb_add_hcd(hcd, irq, 0);
-       if (ret != 0) {
-               dev_err(imx21->dev, "usb_add_hcd() returned %d\n", ret);
-               goto failed_add_hcd;
-       }
-       device_wakeup_enable(hcd->self.controller);
-
-       return 0;
-
-failed_add_hcd:
-       clk_disable_unprepare(imx21->clk);
-failed_clock_enable:
-failed_clock_set:
-       clk_put(imx21->clk);
-failed_clock_get:
-       iounmap(imx21->regs);
-failed_ioremap:
-       release_mem_region(res->start, resource_size(res));
-failed_request_mem:
-       remove_debug_files(imx21);
-       usb_put_hcd(hcd);
-       return ret;
-}
-
-static struct platform_driver imx21_hcd_driver = {
-       .driver = {
-                  .name = hcd_name,
-                  },
-       .probe = imx21_probe,
-       .remove = imx21_remove,
-       .suspend = NULL,
-       .resume = NULL,
-};
-
-module_platform_driver(imx21_hcd_driver);
-
-MODULE_DESCRIPTION("i.MX21 USB Host controller");
-MODULE_AUTHOR("Martin Fuzzey");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx21-hcd");
diff --git a/drivers/usb/host/imx21-hcd.h b/drivers/usb/host/imx21-hcd.h
deleted file mode 100644 (file)
index 96d1675..0000000
+++ /dev/null
@@ -1,431 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Macros and prototypes for i.MX21
- *
- * Copyright (C) 2006 Loping Dog Embedded Systems
- * Copyright (C) 2009 Martin Fuzzey
- * Originally written by Jay Monkman <jtm@lopingdog.com>
- * Ported to 2.6.30, debugged and enhanced by Martin Fuzzey
- */
-
-#ifndef __LINUX_IMX21_HCD_H__
-#define __LINUX_IMX21_HCD_H__
-
-#ifdef CONFIG_DYNAMIC_DEBUG
-#define DEBUG
-#endif
-
-#include <linux/platform_data/usb-mx2.h>
-
-#define NUM_ISO_ETDS   2
-#define USB_NUM_ETD    32
-#define DMEM_SIZE      4096
-
-/* Register definitions */
-#define USBOTG_HWMODE          0x00
-#define USBOTG_HWMODE_ANASDBEN         (1 << 14)
-#define USBOTG_HWMODE_OTGXCVR_SHIFT    6
-#define USBOTG_HWMODE_OTGXCVR_MASK     (3 << 6)
-#define USBOTG_HWMODE_OTGXCVR_TD_RD    (0 << 6)
-#define USBOTG_HWMODE_OTGXCVR_TS_RD    (2 << 6)
-#define USBOTG_HWMODE_OTGXCVR_TD_RS    (1 << 6)
-#define USBOTG_HWMODE_OTGXCVR_TS_RS    (3 << 6)
-#define USBOTG_HWMODE_HOSTXCVR_SHIFT   4
-#define USBOTG_HWMODE_HOSTXCVR_MASK    (3 << 4)
-#define USBOTG_HWMODE_HOSTXCVR_TD_RD   (0 << 4)
-#define USBOTG_HWMODE_HOSTXCVR_TS_RD   (2 << 4)
-#define USBOTG_HWMODE_HOSTXCVR_TD_RS   (1 << 4)
-#define USBOTG_HWMODE_HOSTXCVR_TS_RS   (3 << 4)
-#define USBOTG_HWMODE_CRECFG_MASK      (3 << 0)
-#define USBOTG_HWMODE_CRECFG_HOST      (1 << 0)
-#define USBOTG_HWMODE_CRECFG_FUNC      (2 << 0)
-#define USBOTG_HWMODE_CRECFG_HNP       (3 << 0)
-
-#define USBOTG_CINT_STAT       0x04
-#define USBOTG_CINT_STEN       0x08
-#define USBOTG_ASHNPINT                        (1 << 5)
-#define USBOTG_ASFCINT                 (1 << 4)
-#define USBOTG_ASHCINT                 (1 << 3)
-#define USBOTG_SHNPINT                 (1 << 2)
-#define USBOTG_FCINT                   (1 << 1)
-#define USBOTG_HCINT                   (1 << 0)
-
-#define USBOTG_CLK_CTRL                0x0c
-#define USBOTG_CLK_CTRL_FUNC           (1 << 2)
-#define USBOTG_CLK_CTRL_HST            (1 << 1)
-#define USBOTG_CLK_CTRL_MAIN           (1 << 0)
-
-#define USBOTG_RST_CTRL                0x10
-#define USBOTG_RST_RSTI2C              (1 << 15)
-#define USBOTG_RST_RSTCTRL             (1 << 5)
-#define USBOTG_RST_RSTFC               (1 << 4)
-#define USBOTG_RST_RSTFSKE             (1 << 3)
-#define USBOTG_RST_RSTRH               (1 << 2)
-#define USBOTG_RST_RSTHSIE             (1 << 1)
-#define USBOTG_RST_RSTHC               (1 << 0)
-
-#define USBOTG_FRM_INTVL       0x14
-#define USBOTG_FRM_REMAIN      0x18
-#define USBOTG_HNP_CSR         0x1c
-#define USBOTG_HNP_ISR         0x2c
-#define USBOTG_HNP_IEN         0x30
-
-#define USBOTG_I2C_TXCVR_REG(x)        (0x100 + (x))
-#define USBOTG_I2C_XCVR_DEVAD          0x118
-#define USBOTG_I2C_SEQ_OP_REG          0x119
-#define USBOTG_I2C_SEQ_RD_STARTAD      0x11a
-#define USBOTG_I2C_OP_CTRL_REG         0x11b
-#define USBOTG_I2C_SCLK_TO_SCK_HPER    0x11e
-#define USBOTG_I2C_MASTER_INT_REG      0x11f
-
-#define USBH_HOST_CTRL         0x80
-#define USBH_HOST_CTRL_HCRESET                 (1 << 31)
-#define USBH_HOST_CTRL_SCHDOVR(x)              ((x) << 16)
-#define USBH_HOST_CTRL_RMTWUEN                 (1 << 4)
-#define USBH_HOST_CTRL_HCUSBSTE_RESET          (0 << 2)
-#define USBH_HOST_CTRL_HCUSBSTE_RESUME         (1 << 2)
-#define USBH_HOST_CTRL_HCUSBSTE_OPERATIONAL    (2 << 2)
-#define USBH_HOST_CTRL_HCUSBSTE_SUSPEND        (3 << 2)
-#define USBH_HOST_CTRL_CTLBLKSR_1              (0 << 0)
-#define USBH_HOST_CTRL_CTLBLKSR_2              (1 << 0)
-#define USBH_HOST_CTRL_CTLBLKSR_3              (2 << 0)
-#define USBH_HOST_CTRL_CTLBLKSR_4              (3 << 0)
-
-#define USBH_SYSISR            0x88
-#define USBH_SYSISR_PSCINT             (1 << 6)
-#define USBH_SYSISR_FMOFINT            (1 << 5)
-#define USBH_SYSISR_HERRINT            (1 << 4)
-#define USBH_SYSISR_RESDETINT          (1 << 3)
-#define USBH_SYSISR_SOFINT             (1 << 2)
-#define USBH_SYSISR_DONEINT            (1 << 1)
-#define USBH_SYSISR_SORINT             (1 << 0)
-
-#define USBH_SYSIEN            0x8c
-#define USBH_SYSIEN_PSCINT             (1 << 6)
-#define USBH_SYSIEN_FMOFINT            (1 << 5)
-#define USBH_SYSIEN_HERRINT            (1 << 4)
-#define USBH_SYSIEN_RESDETINT          (1 << 3)
-#define USBH_SYSIEN_SOFINT             (1 << 2)
-#define USBH_SYSIEN_DONEINT            (1 << 1)
-#define USBH_SYSIEN_SORINT             (1 << 0)
-
-#define USBH_XBUFSTAT          0x98
-#define USBH_YBUFSTAT          0x9c
-#define USBH_XYINTEN           0xa0
-#define USBH_XFILLSTAT         0xa8
-#define USBH_YFILLSTAT         0xac
-#define USBH_ETDENSET          0xc0
-#define USBH_ETDENCLR          0xc4
-#define USBH_IMMEDINT          0xcc
-#define USBH_ETDDONESTAT       0xd0
-#define USBH_ETDDONEEN         0xd4
-#define USBH_FRMNUB            0xe0
-#define USBH_LSTHRESH          0xe4
-
-#define USBH_ROOTHUBA          0xe8
-#define USBH_ROOTHUBA_PWRTOGOOD_MASK   (0xff)
-#define USBH_ROOTHUBA_PWRTOGOOD_SHIFT  (24)
-#define USBH_ROOTHUBA_NOOVRCURP        (1 << 12)
-#define USBH_ROOTHUBA_OVRCURPM         (1 << 11)
-#define USBH_ROOTHUBA_DEVTYPE          (1 << 10)
-#define USBH_ROOTHUBA_PWRSWTMD         (1 << 9)
-#define USBH_ROOTHUBA_NOPWRSWT         (1 << 8)
-#define USBH_ROOTHUBA_NDNSTMPRT_MASK   (0xff)
-
-#define USBH_ROOTHUBB          0xec
-#define USBH_ROOTHUBB_PRTPWRCM(x)      (1 << ((x) + 16))
-#define USBH_ROOTHUBB_DEVREMOVE(x)     (1 << (x))
-
-#define USBH_ROOTSTAT          0xf0
-#define USBH_ROOTSTAT_CLRRMTWUE        (1 << 31)
-#define USBH_ROOTSTAT_OVRCURCHG        (1 << 17)
-#define USBH_ROOTSTAT_DEVCONWUE        (1 << 15)
-#define USBH_ROOTSTAT_OVRCURI          (1 << 1)
-#define USBH_ROOTSTAT_LOCPWRS          (1 << 0)
-
-#define USBH_PORTSTAT(x)       (0xf4 + ((x) * 4))
-#define USBH_PORTSTAT_PRTRSTSC         (1 << 20)
-#define USBH_PORTSTAT_OVRCURIC         (1 << 19)
-#define USBH_PORTSTAT_PRTSTATSC        (1 << 18)
-#define USBH_PORTSTAT_PRTENBLSC        (1 << 17)
-#define USBH_PORTSTAT_CONNECTSC        (1 << 16)
-#define USBH_PORTSTAT_LSDEVCON         (1 << 9)
-#define USBH_PORTSTAT_PRTPWRST         (1 << 8)
-#define USBH_PORTSTAT_PRTRSTST         (1 << 4)
-#define USBH_PORTSTAT_PRTOVRCURI       (1 << 3)
-#define USBH_PORTSTAT_PRTSUSPST        (1 << 2)
-#define USBH_PORTSTAT_PRTENABST        (1 << 1)
-#define USBH_PORTSTAT_CURCONST         (1 << 0)
-
-#define USB_DMAREV             0x800
-#define USB_DMAINTSTAT         0x804
-#define USB_DMAINTSTAT_EPERR           (1 << 1)
-#define USB_DMAINTSTAT_ETDERR          (1 << 0)
-
-#define USB_DMAINTEN           0x808
-#define USB_DMAINTEN_EPERRINTEN        (1 << 1)
-#define USB_DMAINTEN_ETDERRINTEN       (1 << 0)
-
-#define USB_ETDDMAERSTAT       0x80c
-#define USB_EPDMAERSTAT                0x810
-#define USB_ETDDMAEN           0x820
-#define USB_EPDMAEN            0x824
-#define USB_ETDDMAXTEN         0x828
-#define USB_EPDMAXTEN          0x82c
-#define USB_ETDDMAENXYT                0x830
-#define USB_EPDMAENXYT         0x834
-#define USB_ETDDMABST4EN       0x838
-#define USB_EPDMABST4EN                0x83c
-
-#define USB_MISCCONTROL                0x840
-#define USB_MISCCONTROL_ISOPREVFRM     (1 << 3)
-#define USB_MISCCONTROL_SKPRTRY        (1 << 2)
-#define USB_MISCCONTROL_ARBMODE        (1 << 1)
-#define USB_MISCCONTROL_FILTCC         (1 << 0)
-
-#define USB_ETDDMACHANLCLR     0x848
-#define USB_EPDMACHANLCLR      0x84c
-#define USB_ETDSMSA(x)         (0x900 + ((x) * 4))
-#define USB_EPSMSA(x)          (0x980 + ((x) * 4))
-#define USB_ETDDMABUFPTR(x)    (0xa00 + ((x) * 4))
-#define USB_EPDMABUFPTR(x)     (0xa80 + ((x) * 4))
-
-#define USB_ETD_DWORD(x, w)    (0x200 + ((x) * 16) + ((w) * 4))
-#define DW0_ADDRESS    0
-#define        DW0_ENDPNT      7
-#define        DW0_DIRECT      11
-#define        DW0_SPEED       13
-#define DW0_FORMAT     14
-#define DW0_MAXPKTSIZ  16
-#define DW0_HALTED     27
-#define        DW0_TOGCRY      28
-#define        DW0_SNDNAK      30
-
-#define DW1_XBUFSRTAD  0
-#define DW1_YBUFSRTAD  16
-
-#define DW2_RTRYDELAY  0
-#define DW2_POLINTERV  0
-#define DW2_STARTFRM   0
-#define DW2_RELPOLPOS  8
-#define DW2_DIRPID     16
-#define        DW2_BUFROUND    18
-#define DW2_DELAYINT   19
-#define DW2_DATATOG    22
-#define DW2_ERRORCNT   24
-#define        DW2_COMPCODE    28
-
-#define DW3_TOTBYECNT  0
-#define DW3_PKTLEN0    0
-#define DW3_COMPCODE0  12
-#define DW3_PKTLEN1    16
-#define DW3_BUFSIZE    21
-#define DW3_COMPCODE1  28
-
-#define USBCTRL                        0x600
-#define USBCTRL_I2C_WU_INT_STAT        (1 << 27)
-#define USBCTRL_OTG_WU_INT_STAT        (1 << 26)
-#define USBCTRL_HOST_WU_INT_STAT       (1 << 25)
-#define USBCTRL_FNT_WU_INT_STAT        (1 << 24)
-#define USBCTRL_I2C_WU_INT_EN          (1 << 19)
-#define USBCTRL_OTG_WU_INT_EN          (1 << 18)
-#define USBCTRL_HOST_WU_INT_EN         (1 << 17)
-#define USBCTRL_FNT_WU_INT_EN          (1 << 16)
-#define USBCTRL_OTC_RCV_RXDP           (1 << 13)
-#define USBCTRL_HOST1_BYP_TLL          (1 << 12)
-#define USBCTRL_OTG_BYP_VAL(x)         ((x) << 10)
-#define USBCTRL_HOST1_BYP_VAL(x)       ((x) << 8)
-#define USBCTRL_OTG_PWR_MASK           (1 << 6)
-#define USBCTRL_HOST1_PWR_MASK         (1 << 5)
-#define USBCTRL_HOST2_PWR_MASK         (1 << 4)
-#define USBCTRL_USB_BYP                        (1 << 2)
-#define USBCTRL_HOST1_TXEN_OE          (1 << 1)
-
-#define USBOTG_DMEM            0x1000
-
-/* Values in TD blocks */
-#define TD_DIR_SETUP       0
-#define TD_DIR_OUT         1
-#define TD_DIR_IN          2
-#define TD_FORMAT_CONTROL   0
-#define TD_FORMAT_ISO      1
-#define TD_FORMAT_BULK     2
-#define TD_FORMAT_INT      3
-#define TD_TOGGLE_CARRY            0
-#define TD_TOGGLE_DATA0            2
-#define TD_TOGGLE_DATA1            3
-
-/* control transfer states */
-#define US_CTRL_SETUP  2
-#define US_CTRL_DATA   1
-#define US_CTRL_ACK    0
-
-/* bulk transfer main state and 0-length packet */
-#define US_BULK                1
-#define US_BULK0       0
-
-/*ETD format description*/
-#define IMX_FMT_CTRL   0x0
-#define IMX_FMT_ISO    0x1
-#define IMX_FMT_BULK   0x2
-#define IMX_FMT_INT    0x3
-
-static char fmt_urb_to_etd[4] = {
-/*PIPE_ISOCHRONOUS*/ IMX_FMT_ISO,
-/*PIPE_INTERRUPT*/ IMX_FMT_INT,
-/*PIPE_CONTROL*/ IMX_FMT_CTRL,
-/*PIPE_BULK*/ IMX_FMT_BULK
-};
-
-/* condition (error) CC codes and mapping (OHCI like) */
-
-#define TD_CC_NOERROR          0x00
-#define TD_CC_CRC              0x01
-#define TD_CC_BITSTUFFING      0x02
-#define TD_CC_DATATOGGLEM      0x03
-#define TD_CC_STALL            0x04
-#define TD_DEVNOTRESP          0x05
-#define TD_PIDCHECKFAIL                0x06
-/*#define TD_UNEXPECTEDPID     0x07 - reserved, not active on MX2*/
-#define TD_DATAOVERRUN         0x08
-#define TD_DATAUNDERRUN                0x09
-#define TD_BUFFEROVERRUN       0x0C
-#define TD_BUFFERUNDERRUN      0x0D
-#define        TD_SCHEDULEOVERRUN      0x0E
-#define TD_NOTACCESSED         0x0F
-
-static const int cc_to_error[16] = {
-       /* No  Error  */ 0,
-       /* CRC Error  */ -EILSEQ,
-       /* Bit Stuff  */ -EPROTO,
-       /* Data Togg  */ -EILSEQ,
-       /* Stall      */ -EPIPE,
-       /* DevNotResp */ -ETIMEDOUT,
-       /* PIDCheck   */ -EPROTO,
-       /* UnExpPID   */ -EPROTO,
-       /* DataOver   */ -EOVERFLOW,
-       /* DataUnder  */ -EREMOTEIO,
-       /* (for hw)   */ -EIO,
-       /* (for hw)   */ -EIO,
-       /* BufferOver */ -ECOMM,
-       /* BuffUnder  */ -ENOSR,
-       /* (for HCD)  */ -ENOSPC,
-       /* (for HCD)  */ -EALREADY
-};
-
-/* HCD data associated with a usb core URB */
-struct urb_priv {
-       struct urb *urb;
-       struct usb_host_endpoint *ep;
-       int active;
-       int state;
-       struct td *isoc_td;
-       int isoc_remaining;
-       int isoc_status;
-};
-
-/* HCD data associated with a usb core endpoint */
-struct ep_priv {
-       struct usb_host_endpoint *ep;
-       struct list_head td_list;
-       struct list_head queue;
-       int etd[NUM_ISO_ETDS];
-       int waiting_etd;
-};
-
-/* isoc packet */
-struct td {
-       struct list_head list;
-       struct urb *urb;
-       struct usb_host_endpoint *ep;
-       dma_addr_t dma_handle;
-       void *cpu_buffer;
-       int len;
-       int frame;
-       int isoc_index;
-};
-
-/* HCD data associated with a hardware ETD */
-struct etd_priv {
-       struct usb_host_endpoint *ep;
-       struct urb *urb;
-       struct td *td;
-       struct list_head queue;
-       dma_addr_t dma_handle;
-       void *cpu_buffer;
-       void *bounce_buffer;
-       int alloc;
-       int len;
-       int dmem_size;
-       int dmem_offset;
-       int active_count;
-#ifdef DEBUG
-       int activated_frame;
-       int disactivated_frame;
-       int last_int_frame;
-       int last_req_frame;
-       u32 submitted_dwords[4];
-#endif
-};
-
-/* Hardware data memory info */
-struct imx21_dmem_area {
-       struct usb_host_endpoint *ep;
-       unsigned int offset;
-       unsigned int size;
-       struct list_head list;
-};
-
-#ifdef DEBUG
-struct debug_usage_stats {
-       unsigned int value;
-       unsigned int maximum;
-};
-
-struct debug_stats {
-       unsigned long submitted;
-       unsigned long completed_ok;
-       unsigned long completed_failed;
-       unsigned long unlinked;
-       unsigned long queue_etd;
-       unsigned long queue_dmem;
-};
-
-struct debug_isoc_trace {
-       int schedule_frame;
-       int submit_frame;
-       int request_len;
-       int done_frame;
-       int done_len;
-       int cc;
-       struct td *td;
-};
-#endif
-
-/* HCD data structure */
-struct imx21 {
-       spinlock_t lock;
-       struct device *dev;
-       struct usb_hcd *hcd;
-       struct mx21_usbh_platform_data *pdata;
-       struct list_head dmem_list;
-       struct list_head queue_for_etd; /* eps queued due to etd shortage */
-       struct list_head queue_for_dmem; /* etds queued due to dmem shortage */
-       struct etd_priv etd[USB_NUM_ETD];
-       struct clk *clk;
-       void __iomem *regs;
-#ifdef DEBUG
-       struct dentry *debug_root;
-       struct debug_stats nonisoc_stats;
-       struct debug_stats isoc_stats;
-       struct debug_usage_stats etd_usage;
-       struct debug_usage_stats dmem_usage;
-       struct debug_isoc_trace isoc_trace[20];
-       struct debug_isoc_trace isoc_trace_failed[20];
-       unsigned long debug_unblocks;
-       int isoc_trace_index;
-       int isoc_trace_index_failed;
-#endif
-};
-
-#endif
index 3055d9a..8544a2a 100644 (file)
@@ -1447,6 +1447,7 @@ static int isp116x_bus_resume(struct usb_hcd *hcd)
                val &= ~HCCONTROL_HCFS;
                val |= HCCONTROL_USB_RESUME;
                isp116x_write_reg32(isp116x, HCCONTROL, val);
+               break;
        case HCCONTROL_USB_RESUME:
                break;
        case HCCONTROL_USB_OPER:
index 9bbfcc3..208705b 100644 (file)
@@ -793,60 +793,6 @@ static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 l
                        ISP1362_REG_NO(ISP1362_REG_##r), isp1362_read_reg16(d, r));     \
 }
 
-static void __attribute__((__unused__)) isp1362_show_regs(struct isp1362_hcd *isp1362_hcd)
-{
-       isp1362_show_reg(isp1362_hcd, HCREVISION);
-       isp1362_show_reg(isp1362_hcd, HCCONTROL);
-       isp1362_show_reg(isp1362_hcd, HCCMDSTAT);
-       isp1362_show_reg(isp1362_hcd, HCINTSTAT);
-       isp1362_show_reg(isp1362_hcd, HCINTENB);
-       isp1362_show_reg(isp1362_hcd, HCFMINTVL);
-       isp1362_show_reg(isp1362_hcd, HCFMREM);
-       isp1362_show_reg(isp1362_hcd, HCFMNUM);
-       isp1362_show_reg(isp1362_hcd, HCLSTHRESH);
-       isp1362_show_reg(isp1362_hcd, HCRHDESCA);
-       isp1362_show_reg(isp1362_hcd, HCRHDESCB);
-       isp1362_show_reg(isp1362_hcd, HCRHSTATUS);
-       isp1362_show_reg(isp1362_hcd, HCRHPORT1);
-       isp1362_show_reg(isp1362_hcd, HCRHPORT2);
-
-       isp1362_show_reg(isp1362_hcd, HCHWCFG);
-       isp1362_show_reg(isp1362_hcd, HCDMACFG);
-       isp1362_show_reg(isp1362_hcd, HCXFERCTR);
-       isp1362_show_reg(isp1362_hcd, HCuPINT);
-
-       if (in_interrupt())
-               DBG(0, "%-12s[%02x]:     %04x\n", "HCuPINTENB",
-                        ISP1362_REG_NO(ISP1362_REG_HCuPINTENB), isp1362_hcd->irqenb);
-       else
-               isp1362_show_reg(isp1362_hcd, HCuPINTENB);
-       isp1362_show_reg(isp1362_hcd, HCCHIPID);
-       isp1362_show_reg(isp1362_hcd, HCSCRATCH);
-       isp1362_show_reg(isp1362_hcd, HCBUFSTAT);
-       isp1362_show_reg(isp1362_hcd, HCDIRADDR);
-       /* Access would advance fifo
-        * isp1362_show_reg(isp1362_hcd, HCDIRDATA);
-        */
-       isp1362_show_reg(isp1362_hcd, HCISTLBUFSZ);
-       isp1362_show_reg(isp1362_hcd, HCISTLRATE);
-       isp1362_show_reg(isp1362_hcd, HCINTLBUFSZ);
-       isp1362_show_reg(isp1362_hcd, HCINTLBLKSZ);
-       isp1362_show_reg(isp1362_hcd, HCINTLDONE);
-       isp1362_show_reg(isp1362_hcd, HCINTLSKIP);
-       isp1362_show_reg(isp1362_hcd, HCINTLLAST);
-       isp1362_show_reg(isp1362_hcd, HCINTLCURR);
-       isp1362_show_reg(isp1362_hcd, HCATLBUFSZ);
-       isp1362_show_reg(isp1362_hcd, HCATLBLKSZ);
-       /* only valid after ATL_DONE interrupt
-        * isp1362_show_reg(isp1362_hcd, HCATLDONE);
-        */
-       isp1362_show_reg(isp1362_hcd, HCATLSKIP);
-       isp1362_show_reg(isp1362_hcd, HCATLLAST);
-       isp1362_show_reg(isp1362_hcd, HCATLCURR);
-       isp1362_show_reg(isp1362_hcd, HCATLDTC);
-       isp1362_show_reg(isp1362_hcd, HCATLDTCTO);
-}
-
 static void isp1362_write_diraddr(struct isp1362_hcd *isp1362_hcd, u16 offset, u16 len)
 {
        len = (len + 1) & ~1;
index 0894f6c..afd9174 100644 (file)
@@ -1537,6 +1537,7 @@ max3421_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
                                __func__, urb->interval);
                        return -EINVAL;
                }
+               break;
        default:
                break;
        }
@@ -1847,7 +1848,7 @@ max3421_probe(struct spi_device *spi)
        struct max3421_hcd *max3421_hcd;
        struct usb_hcd *hcd = NULL;
        struct max3421_hcd_platform_data *pdata = NULL;
-       int retval = -ENOMEM;
+       int retval;
 
        if (spi_setup(spi) < 0) {
                dev_err(&spi->dev, "Unable to setup SPI bus");
@@ -1889,6 +1890,7 @@ max3421_probe(struct spi_device *spi)
                goto error;
        }
 
+       retval = -ENOMEM;
        hcd = usb_create_hcd(&max3421_hcd_desc, &spi->dev,
                             dev_name(&spi->dev));
        if (!hcd) {
index 0487a4b..9bbd7dd 100644 (file)
@@ -155,7 +155,10 @@ static struct regmap *at91_dt_syscon_sfr(void)
 
 /*
  * usb_hcd_at91_probe - initialize AT91-based HCDs
- * Context: !in_interrupt()
+ * @driver:    Pointer to hc driver instance
+ * @pdev:      USB controller to probe
+ *
+ * Context: task context, might sleep
  *
  * Allocates basic resources for this USB host controller, and
  * then invokes the start() method for the HCD associated with it
@@ -246,12 +249,14 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
 
 /*
  * usb_hcd_at91_remove - shutdown processing for AT91-based HCDs
- * Context: !in_interrupt()
+ * @hcd:       USB controller to remove
+ * @pdev:      Platform device required for cleanup
+ *
+ * Context: task context, might sleep
  *
  * Reverses the effect of usb_hcd_at91_probe(), first invoking
  * the HCD's stop() method.  It is always called from a thread
  * context, "rmmod" or something similar.
- *
  */
 static void usb_hcd_at91_remove(struct usb_hcd *hcd,
                                struct platform_device *pdev)
index 73e13e7..1f5e693 100644 (file)
@@ -171,7 +171,7 @@ static int ohci_urb_enqueue (
 
                        /* 1 TD for setup, 1 for ACK, plus ... */
                        size = 2;
-                       /* FALLTHROUGH */
+                       fallthrough;
                // case PIPE_INTERRUPT:
                // case PIPE_BULK:
                default:
index 44504c1..f474f2f 100644 (file)
@@ -692,6 +692,7 @@ int ohci_hub_control(
                case C_HUB_OVER_CURRENT:
                        ohci_writel (ohci, RH_HS_OCIC,
                                        &ohci->regs->roothub.status);
+                       break;
                case C_HUB_LOCAL_POWER:
                        break;
                default:
index 6374501..0b37227 100644 (file)
@@ -285,7 +285,9 @@ static int ohci_omap_reset(struct usb_hcd *hcd)
 
 /**
  * ohci_hcd_omap_probe - initialize OMAP-based HCDs
- * Context: !in_interrupt()
+ * @pdev:      USB controller to probe
+ *
+ * Context: task context, might sleep
  *
  * Allocates basic resources for this USB host controller, and
  * then invokes the start() method for the HCD associated with it
@@ -399,8 +401,9 @@ err_put_hcd:
 
 /**
  * ohci_hcd_omap_remove - shutdown processing for OMAP-based HCDs
- * @dev: USB Host Controller being removed
- * Context: !in_interrupt()
+ * @pdev: USB Host Controller being removed
+ *
+ * Context: task context, might sleep
  *
  * Reverses the effect of ohci_hcd_omap_probe(), first invoking
  * the HCD's stop() method.  It is always called from a thread
index 7679fb5..54aa5c7 100644 (file)
@@ -410,12 +410,13 @@ static int ohci_pxa_of_init(struct platform_device *pdev)
 
 /**
  * ohci_hcd_pxa27x_probe - initialize pxa27x-based HCDs
- * Context: !in_interrupt()
+ * @pdev:      USB Host controller to probe
+ *
+ * Context: task context, might sleep
  *
  * 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 ohci_hcd_pxa27x_probe(struct platform_device *pdev)
 {
@@ -509,13 +510,13 @@ static int ohci_hcd_pxa27x_probe(struct platform_device *pdev)
 
 /**
  * ohci_hcd_pxa27x_remove - shutdown processing for pxa27x-based HCDs
- * @dev: USB Host Controller being removed
- * Context: !in_interrupt()
+ * @pdev: USB Host Controller being removed
+ *
+ * Context: task context, might sleep
  *
  * Reverses the effect of ohci_hcd_pxa27x_probe(), first invoking
  * the HCD's stop() method.  It is always called from a thread
  * context, normally "rmmod", "apmd", or something similar.
- *
  */
 static int ohci_hcd_pxa27x_remove(struct platform_device *pdev)
 {
index de5e570..1bec9b5 100644 (file)
@@ -324,14 +324,13 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc)
 /*
  * ohci_hcd_s3c2410_remove - shutdown processing for HCD
  * @dev: USB Host Controller being removed
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep
  *
  * Reverses the effect of ohci_hcd_3c2410_probe(), first invoking
  * the HCD's stop() method.  It is always called from a thread
  * context, normally "rmmod", "apmd", or something similar.
- *
-*/
-
+ */
 static int
 ohci_hcd_s3c2410_remove(struct platform_device *dev)
 {
@@ -345,12 +344,13 @@ ohci_hcd_s3c2410_remove(struct platform_device *dev)
 
 /*
  * ohci_hcd_s3c2410_probe - initialize S3C2410-based HCDs
- * Context: !in_interrupt()
+ * @dev: USB Host Controller to be probed
+ *
+ * Context: task context, might sleep
  *
  * 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 ohci_hcd_s3c2410_probe(struct platform_device *dev)
 {
index 27dbbe1..aa42df3 100644 (file)
@@ -1365,6 +1365,7 @@ __acquires(oxu->lock)
        switch (urb->status) {
        case -EINPROGRESS:              /* success */
                urb->status = 0;
+               break;
        default:                        /* fault */
                break;
        case -EREMOTEIO:                /* fault or normal */
index 138ba45..3589b49 100644 (file)
@@ -1144,7 +1144,6 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
        case USB_SPEED_WIRELESS:
                xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
                return -EINVAL;
-               break;
        default:
                /* Speed was set earlier, this shouldn't happen. */
                return -EINVAL;
@@ -2110,7 +2109,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
 
        deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
                        xhci->event_ring->dequeue);
-       if (deq == 0 && !in_interrupt())
+       if (!deq)
                xhci_warn(xhci, "WARN something wrong with SW event ring "
                                "dequeue ptr.\n");
        /* Update HC event ring dequeue pointer */
index 167dae1..eac43a7 100644 (file)
@@ -2418,6 +2418,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                        xhci_warn_ratelimited(xhci,
                                              "WARN Successful completion on short TX for slot %u ep %u: needs XHCI_TRUST_TX_LENGTH quirk?\n",
                                              slot_id, ep_index);
+               break;
        case COMP_SHORT_PACKET:
                break;
        /* Completion codes for endpoint stopped state */
@@ -2962,6 +2963,7 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
                return -EINVAL;
        case EP_STATE_HALTED:
                xhci_dbg(xhci, "WARN halted endpoint, queueing URB anyway.\n");
+               break;
        case EP_STATE_STOPPED:
        case EP_STATE_RUNNING:
                break;
index d4a8d0e..7f3ef84 100644 (file)
@@ -1476,11 +1476,9 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
        ep_index = xhci_get_endpoint_index(&urb->ep->desc);
        ep_state = &xhci->devs[slot_id]->eps[ep_index].ep_state;
 
-       if (!HCD_HW_ACCESSIBLE(hcd)) {
-               if (!in_interrupt())
-                       xhci_dbg(xhci, "urb submitted during PCI suspend\n");
+       if (!HCD_HW_ACCESSIBLE(hcd))
                return -ESHUTDOWN;
-       }
+
        if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR) {
                xhci_dbg(xhci, "Can't queue urb, port error, link inactive\n");
                return -ENODEV;
index 6818ea6..8f11443 100644 (file)
@@ -275,3 +275,12 @@ config USB_CHAOSKEY
 
          To compile this driver as a module, choose M here: the
          module will be called chaoskey.
+
+config BRCM_USB_PINMAP
+       tristate "Broadcom pinmap driver support"
+       depends on (ARCH_BRCMSTB && PHY_BRCM_USB) || COMPILE_TEST
+       default ARCH_BRCMSTB && PHY_BRCM_USB
+       help
+         This option enables support for remapping some USB external
+         signals, which are typically on dedicated pins on the chip,
+         to any gpio.
index da39bdd..5f4e598 100644 (file)
@@ -31,3 +31,4 @@ obj-$(CONFIG_USB_CHAOSKEY)            += chaoskey.o
 
 obj-$(CONFIG_USB_SISUSBVGA)            += sisusbvga/
 obj-$(CONFIG_USB_LINK_LAYER_TEST)      += lvstest.o
+obj-$(CONFIG_BRCM_USB_PINMAP)          += brcmstb-usb-pinmap.o
index 9de0171..ac86951 100644 (file)
@@ -184,10 +184,8 @@ static int mfi_fc_probe(struct usb_device *udev)
                return -ENODEV;
 
        mfi = kzalloc(sizeof(struct mfi_device), GFP_KERNEL);
-       if (!mfi) {
-               err = -ENOMEM;
-               goto error;
-       }
+       if (!mfi)
+               return -ENOMEM;
 
        battery_cfg.drv_data = mfi;
 
@@ -198,17 +196,14 @@ static int mfi_fc_probe(struct usb_device *udev)
        if (IS_ERR(mfi->battery)) {
                dev_err(&udev->dev, "Can't register battery\n");
                err = PTR_ERR(mfi->battery);
-               goto error;
+               kfree(mfi);
+               return err;
        }
 
        mfi->udev = usb_get_dev(udev);
        dev_set_drvdata(&udev->dev, mfi);
 
        return 0;
-
-error:
-       kfree(mfi);
-       return err;
 }
 
 static void mfi_fc_disconnect(struct usb_device *udev)
diff --git a/drivers/usb/misc/brcmstb-usb-pinmap.c b/drivers/usb/misc/brcmstb-usb-pinmap.c
new file mode 100644 (file)
index 0000000..b3cfe86
--- /dev/null
@@ -0,0 +1,351 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2020, Broadcom */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/kernel.h>
+#include <linux/kdebug.h>
+#include <linux/gpio/consumer.h>
+
+struct out_pin {
+       u32 enable_mask;
+       u32 value_mask;
+       u32 changed_mask;
+       u32 clr_changed_mask;
+       struct gpio_desc *gpiod;
+       const char *name;
+};
+
+struct in_pin {
+       u32 enable_mask;
+       u32 value_mask;
+       struct gpio_desc *gpiod;
+       const char *name;
+       struct brcmstb_usb_pinmap_data *pdata;
+};
+
+struct brcmstb_usb_pinmap_data {
+       void __iomem *regs;
+       int in_count;
+       struct in_pin *in_pins;
+       int out_count;
+       struct out_pin *out_pins;
+};
+
+
+static void pinmap_set(void __iomem *reg, u32 mask)
+{
+       u32 val;
+
+       val = readl(reg);
+       val |= mask;
+       writel(val, reg);
+}
+
+static void pinmap_unset(void __iomem *reg, u32 mask)
+{
+       u32 val;
+
+       val = readl(reg);
+       val &= ~mask;
+       writel(val, reg);
+}
+
+static void sync_in_pin(struct in_pin *pin)
+{
+       u32 val;
+
+       val = gpiod_get_value(pin->gpiod);
+       if (val)
+               pinmap_set(pin->pdata->regs, pin->value_mask);
+       else
+               pinmap_unset(pin->pdata->regs, pin->value_mask);
+}
+
+/*
+ * Interrupt from override register, propagate from override bit
+ * to GPIO.
+ */
+static irqreturn_t brcmstb_usb_pinmap_ovr_isr(int irq, void *dev_id)
+{
+       struct brcmstb_usb_pinmap_data *pdata = dev_id;
+       struct out_pin *pout;
+       u32 val;
+       u32 bit;
+       int x;
+
+       pr_debug("%s: reg: 0x%x\n", __func__, readl(pdata->regs));
+       pout = pdata->out_pins;
+       for (x = 0; x < pdata->out_count; x++) {
+               val = readl(pdata->regs);
+               if (val & pout->changed_mask) {
+                       pinmap_set(pdata->regs, pout->clr_changed_mask);
+                       pinmap_unset(pdata->regs, pout->clr_changed_mask);
+                       bit = val & pout->value_mask;
+                       gpiod_set_value(pout->gpiod, bit ? 1 : 0);
+                       pr_debug("%s: %s bit changed state to %d\n",
+                                __func__, pout->name, bit ? 1 : 0);
+               }
+       }
+       return IRQ_HANDLED;
+}
+
+/*
+ * Interrupt from GPIO, propagate from GPIO to override bit.
+ */
+static irqreturn_t brcmstb_usb_pinmap_gpio_isr(int irq, void *dev_id)
+{
+       struct in_pin *pin = dev_id;
+
+       pr_debug("%s: %s pin changed state\n", __func__, pin->name);
+       sync_in_pin(pin);
+       return IRQ_HANDLED;
+}
+
+
+static void get_pin_counts(struct device_node *dn, int *in_count,
+                          int *out_count)
+{
+       int in;
+       int out;
+
+       *in_count = 0;
+       *out_count = 0;
+       in = of_property_count_strings(dn, "brcm,in-functions");
+       if (in < 0)
+               return;
+       out = of_property_count_strings(dn, "brcm,out-functions");
+       if (out < 0)
+               return;
+       *in_count = in;
+       *out_count = out;
+}
+
+static int parse_pins(struct device *dev, struct device_node *dn,
+                     struct brcmstb_usb_pinmap_data *pdata)
+{
+       struct out_pin *pout;
+       struct in_pin *pin;
+       int index;
+       int res;
+       int x;
+
+       pin = pdata->in_pins;
+       for (x = 0, index = 0; x < pdata->in_count; x++) {
+               pin->gpiod = devm_gpiod_get_index(dev, "in", x, GPIOD_IN);
+               if (IS_ERR(pin->gpiod)) {
+                       dev_err(dev, "Error getting gpio %s\n", pin->name);
+                       return PTR_ERR(pin->gpiod);
+
+               }
+               res = of_property_read_string_index(dn, "brcm,in-functions", x,
+                                                   &pin->name);
+               if (res < 0) {
+                       dev_err(dev, "Error getting brcm,in-functions for %s\n",
+                               pin->name);
+                       return res;
+               }
+               res = of_property_read_u32_index(dn, "brcm,in-masks", index++,
+                                                &pin->enable_mask);
+               if (res < 0) {
+                       dev_err(dev, "Error getting 1st brcm,in-masks for %s\n",
+                               pin->name);
+                       return res;
+               }
+               res = of_property_read_u32_index(dn, "brcm,in-masks", index++,
+                                                &pin->value_mask);
+               if (res < 0) {
+                       dev_err(dev, "Error getting 2nd brcm,in-masks for %s\n",
+                               pin->name);
+                       return res;
+               }
+               pin->pdata = pdata;
+               pin++;
+       }
+       pout = pdata->out_pins;
+       for (x = 0, index = 0; x < pdata->out_count; x++) {
+               pout->gpiod = devm_gpiod_get_index(dev, "out", x,
+                                                  GPIOD_OUT_HIGH);
+               if (IS_ERR(pout->gpiod)) {
+                       dev_err(dev, "Error getting gpio %s\n", pin->name);
+                       return PTR_ERR(pout->gpiod);
+               }
+               res = of_property_read_string_index(dn, "brcm,out-functions", x,
+                                                   &pout->name);
+               if (res < 0) {
+                       dev_err(dev, "Error getting brcm,out-functions for %s\n",
+                               pout->name);
+                       return res;
+               }
+               res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
+                                                &pout->enable_mask);
+               if (res < 0) {
+                       dev_err(dev, "Error getting 1st brcm,out-masks for %s\n",
+                               pout->name);
+                       return res;
+               }
+               res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
+                                                &pout->value_mask);
+               if (res < 0) {
+                       dev_err(dev, "Error getting 2nd brcm,out-masks for %s\n",
+                               pout->name);
+                       return res;
+               }
+               res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
+                                                &pout->changed_mask);
+               if (res < 0) {
+                       dev_err(dev, "Error getting 3rd brcm,out-masks for %s\n",
+                               pout->name);
+                       return res;
+               }
+               res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
+                                                &pout->clr_changed_mask);
+               if (res < 0) {
+                       dev_err(dev, "Error getting 4th out-masks for %s\n",
+                               pout->name);
+                       return res;
+               }
+               pout++;
+       }
+       return 0;
+}
+
+static void sync_all_pins(struct brcmstb_usb_pinmap_data *pdata)
+{
+       struct out_pin *pout;
+       struct in_pin *pin;
+       int val;
+       int x;
+
+       /*
+        * Enable the override, clear any changed condition and
+        * propagate the state to the GPIO for all out pins.
+        */
+       pout = pdata->out_pins;
+       for (x = 0; x < pdata->out_count; x++) {
+               pinmap_set(pdata->regs, pout->enable_mask);
+               pinmap_set(pdata->regs, pout->clr_changed_mask);
+               pinmap_unset(pdata->regs, pout->clr_changed_mask);
+               val = readl(pdata->regs) & pout->value_mask;
+               gpiod_set_value(pout->gpiod, val ? 1 : 0);
+               pout++;
+       }
+
+       /* sync and enable all in pins. */
+       pin = pdata->in_pins;
+       for (x = 0; x < pdata->in_count; x++) {
+               sync_in_pin(pin);
+               pinmap_set(pdata->regs, pin->enable_mask);
+               pin++;
+       }
+}
+
+static int __init brcmstb_usb_pinmap_probe(struct platform_device *pdev)
+{
+       struct device_node *dn = pdev->dev.of_node;
+       struct brcmstb_usb_pinmap_data *pdata;
+       struct in_pin *pin;
+       struct resource *r;
+       int out_count;
+       int in_count;
+       int err;
+       int irq;
+       int x;
+
+       get_pin_counts(dn, &in_count, &out_count);
+       if ((in_count + out_count) == 0)
+               return -EINVAL;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       pdata = devm_kzalloc(&pdev->dev,
+                            sizeof(*pdata) +
+                            (sizeof(struct in_pin) * in_count) +
+                            (sizeof(struct out_pin) * out_count), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+
+       pdata->in_count = in_count;
+       pdata->out_count = out_count;
+       pdata->in_pins = (struct in_pin *)(pdata + 1);
+       pdata->out_pins = (struct out_pin *)(pdata->in_pins + in_count);
+
+       pdata->regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+       if (!pdata->regs)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, pdata);
+
+       err = parse_pins(&pdev->dev, dn, pdata);
+       if (err)
+               return err;
+
+       sync_all_pins(pdata);
+
+       if (out_count) {
+
+               /* Enable interrupt for out pins */
+               irq = platform_get_irq(pdev, 0);
+               err = devm_request_irq(&pdev->dev, irq,
+                                      brcmstb_usb_pinmap_ovr_isr,
+                                      IRQF_TRIGGER_RISING,
+                                      pdev->name, pdata);
+               if (err < 0) {
+                       dev_err(&pdev->dev, "Error requesting IRQ\n");
+                       return err;
+               }
+       }
+
+       for (x = 0, pin = pdata->in_pins; x < pdata->in_count; x++, pin++) {
+               irq = gpiod_to_irq(pin->gpiod);
+               if (irq < 0) {
+                       dev_err(&pdev->dev, "Error getting IRQ for %s pin\n",
+                               pin->name);
+                       return irq;
+               }
+               err = devm_request_irq(&pdev->dev, irq,
+                                      brcmstb_usb_pinmap_gpio_isr,
+                                      IRQF_SHARED | IRQF_TRIGGER_RISING |
+                                      IRQF_TRIGGER_FALLING,
+                                      pdev->name, pin);
+               if (err < 0) {
+                       dev_err(&pdev->dev, "Error requesting IRQ for %s pin\n",
+                               pin->name);
+                       return err;
+               }
+       }
+
+       dev_dbg(&pdev->dev, "Driver probe succeeded\n");
+       dev_dbg(&pdev->dev, "In pin count: %d, out pin count: %d\n",
+               pdata->in_count, pdata->out_count);
+       return 0;
+}
+
+
+static const struct of_device_id brcmstb_usb_pinmap_of_match[] = {
+       { .compatible = "brcm,usb-pinmap" },
+       { },
+};
+
+static struct platform_driver brcmstb_usb_pinmap_driver = {
+       .driver = {
+               .name   = "brcm-usb-pinmap",
+               .of_match_table = brcmstb_usb_pinmap_of_match,
+       },
+};
+
+static int __init brcmstb_usb_pinmap_init(void)
+{
+       return platform_driver_probe(&brcmstb_usb_pinmap_driver,
+                                    brcmstb_usb_pinmap_probe);
+}
+
+module_init(brcmstb_usb_pinmap_init);
+MODULE_AUTHOR("Al Cooper <alcooperx@gmail.com>");
+MODULE_DESCRIPTION("Broadcom USB Pinmap Driver");
+MODULE_LICENSE("GPL");
index 70ec296..efbd317 100644 (file)
@@ -384,7 +384,6 @@ static ssize_t iowarrior_write(struct file *file,
                retval = usb_set_report(dev->interface, 2, 0, buf, count);
                kfree(buf);
                goto exit;
-               break;
        case USB_DEVICE_ID_CODEMERCS_IOW56:
        case USB_DEVICE_ID_CODEMERCS_IOW56AM:
        case USB_DEVICE_ID_CODEMERCS_IOW28:
@@ -454,14 +453,12 @@ static ssize_t iowarrior_write(struct file *file,
                retval = count;
                usb_free_urb(int_out_urb);
                goto exit;
-               break;
        default:
                /* what do we have here ? An unsupported Product-ID ? */
                dev_err(&dev->interface->dev, "%s - not supported for product=0x%x\n",
                        __func__, dev->product_id);
                retval = -EFAULT;
                goto exit;
-               break;
        }
 error:
        usb_free_coherent(dev->udev, dev->report_size, buf,
index 655d9cb..c12cdd0 100644 (file)
@@ -16,7 +16,7 @@ config USB_SISUSBVGA
 
 config USB_SISUSBVGA_CON
        bool "Text console and mode switching support" if USB_SISUSBVGA
-       depends on VT
+       depends on VT && BROKEN
        select FONT_8x16
        help
          Say Y here if you want a VGA text console via the USB dongle or
index e3165d7..73ebfa6 100644 (file)
@@ -137,6 +137,7 @@ static void yurex_interrupt(struct urb *urb)
                dev_err(&dev->interface->dev,
                        "%s - overflow with length %d, actual length is %d\n",
                        __func__, YUREX_BUF_SIZE, dev->urb->actual_length);
+               return;
        case -ECONNRESET:
        case -ENOENT:
        case -ESHUTDOWN:
index 3084c46..9a36134 100644 (file)
@@ -19,7 +19,6 @@ struct ssusb_mtk;
 struct mtu3_regset {
        char name[MTU3_DEBUGFS_NAME_LEN];
        struct debugfs_regset32 regset;
-       size_t nregs;
 };
 
 struct mtu3_file_map {
index c26683a..c429376 100644 (file)
@@ -467,6 +467,7 @@ static void musb_do_idle(struct timer_list *t)
                fallthrough;
        case OTG_STATE_A_IDLE:
                tusb_musb_set_vbus(musb, 0);
+               break;
        default:
                break;
        }
index 4a6462c..00506fb 100644 (file)
@@ -1208,9 +1208,6 @@ static int isp1301_remove(struct i2c_client *i2c)
 #ifdef CONFIG_USB_OTG
        otg_unbind(isp);
 #endif
-       if (machine_is_omap_h2())
-               gpio_free(2);
-
        set_bit(WORK_STOP, &isp->todo);
        del_timer_sync(&isp->timer);
        flush_work(&isp->work);
@@ -1480,6 +1477,7 @@ isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 {
        int                     status;
        struct isp1301          *isp;
+       int irq;
 
        if (the_transceiver)
                return 0;
@@ -1543,20 +1541,27 @@ isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 #endif
 
        if (machine_is_omap_h2()) {
+               struct gpio_desc *gpiod;
+
                /* full speed signaling by default */
                isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1,
                        MC1_SPEED);
                isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2,
                        MC2_SPD_SUSP_CTRL);
 
-               /* IRQ wired at M14 */
-               omap_cfg_reg(M14_1510_GPIO2);
-               if (gpio_request(2, "isp1301") == 0)
-                       gpio_direction_input(2);
+               gpiod = devm_gpiod_get(&i2c->dev, NULL, GPIOD_IN);
+               if (IS_ERR(gpiod)) {
+                       dev_err(&i2c->dev, "cannot obtain H2 GPIO\n");
+                       goto fail;
+               }
+               gpiod_set_consumer_name(gpiod, "isp1301");
+               irq = gpiod_to_irq(gpiod);
                isp->irq_type = IRQF_TRIGGER_FALLING;
+       } else {
+               irq = i2c->irq;
        }
 
-       status = request_irq(i2c->irq, isp1301_irq,
+       status = request_irq(irq, isp1301_irq,
                        isp->irq_type, DRIVER_NAME, isp);
        if (status < 0) {
                dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
index 98c1aa5..5f7d678 100644 (file)
@@ -861,6 +861,7 @@ static int ms_count_freeblock(struct us_data *us, u16 PhyBlock)
                case MS_LB_NOT_USED:
                case MS_LB_NOT_USED_ERASED:
                        Count++;
+                       break;
                default:
                        break;
                }
index 3d5f7d0..2b098b5 100644 (file)
@@ -431,7 +431,6 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
                             us->srb->sc_data_direction);
                /* Return fail, SCSI seems to handle this better. */
                return USB_STOR_TRANSPORT_FAILED;
-               break;
        }
 
        return USB_STOR_TRANSPORT_GOOD;
index 238a808..5eb895b 100644 (file)
@@ -416,7 +416,7 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
 
        /* don't submit s-g requests during abort processing */
        if (test_bit(US_FLIDX_ABORTING, &us->dflags))
-               return USB_STOR_XFER_ERROR;
+               goto usb_stor_xfer_error;
 
        /* initialize the scatter-gather request block */
        usb_stor_dbg(us, "xfer %u bytes, %d entries\n", length, num_sg);
@@ -424,7 +424,7 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
                        sg, num_sg, length, GFP_NOIO);
        if (result) {
                usb_stor_dbg(us, "usb_sg_init returned %d\n", result);
-               return USB_STOR_XFER_ERROR;
+               goto usb_stor_xfer_error;
        }
 
        /*
@@ -452,6 +452,11 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
                *act_len = us->current_sg.bytes;
        return interpret_urb_result(us, pipe, length, result,
                        us->current_sg.bytes);
+
+usb_stor_xfer_error:
+       if (act_len)
+               *act_len = 0;
+       return USB_STOR_XFER_ERROR;
 }
 
 /*
index 652d6d6..56422c4 100644 (file)
@@ -690,6 +690,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
                fallthrough;
        case DMA_TO_DEVICE:
                cmdinfo->state |= ALLOC_DATA_OUT_URB | SUBMIT_DATA_OUT_URB;
+               break;
        case DMA_NONE:
                break;
        }
index 35eec70..4f6e58d 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mutex.h>
 #include <linux/property.h>
 #include <linux/slab.h>
+#include <linux/usb/pd_vdo.h>
 
 #include "bus.h"
 
@@ -18,6 +19,7 @@ struct typec_plug {
        struct device                   dev;
        enum typec_plug_index           index;
        struct ida                      mode_ids;
+       int                             num_altmodes;
 };
 
 struct typec_cable {
@@ -33,6 +35,7 @@ struct typec_partner {
        struct usb_pd_identity          *identity;
        enum typec_accessory            accessory;
        struct ida                      mode_ids;
+       int                             num_altmodes;
 };
 
 struct typec_port {
@@ -81,6 +84,29 @@ static const char * const typec_accessory_modes[] = {
        [TYPEC_ACCESSORY_DEBUG]         = "debug",
 };
 
+/* Product types defined in USB PD Specification R3.0 V2.0 */
+static const char * const product_type_ufp[8] = {
+       [IDH_PTYPE_UNDEF]               = "undefined",
+       [IDH_PTYPE_HUB]                 = "hub",
+       [IDH_PTYPE_PERIPH]              = "peripheral",
+       [IDH_PTYPE_PSD]                 = "psd",
+       [IDH_PTYPE_AMA]                 = "ama",
+};
+
+static const char * const product_type_dfp[8] = {
+       [IDH_PTYPE_DFP_UNDEF]           = "undefined",
+       [IDH_PTYPE_DFP_HUB]             = "hub",
+       [IDH_PTYPE_DFP_HOST]            = "host",
+       [IDH_PTYPE_DFP_PB]              = "power_brick",
+       [IDH_PTYPE_DFP_AMC]             = "amc",
+};
+
+static const char * const product_type_cable[8] = {
+       [IDH_PTYPE_UNDEF]               = "undefined",
+       [IDH_PTYPE_PCABLE]              = "passive",
+       [IDH_PTYPE_ACABLE]              = "active",
+};
+
 static struct usb_pd_identity *get_pd_identity(struct device *dev)
 {
        if (is_typec_partner(dev)) {
@@ -95,6 +121,32 @@ static struct usb_pd_identity *get_pd_identity(struct device *dev)
        return NULL;
 }
 
+static const char *get_pd_product_type(struct device *dev)
+{
+       struct typec_port *port = to_typec_port(dev->parent);
+       struct usb_pd_identity *id = get_pd_identity(dev);
+       const char *ptype = NULL;
+
+       if (is_typec_partner(dev)) {
+               if (!id)
+                       return NULL;
+
+               if (port->data_role == TYPEC_HOST)
+                       ptype = product_type_ufp[PD_IDH_PTYPE(id->id_header)];
+               else
+                       ptype = product_type_dfp[PD_IDH_DFP_PTYPE(id->id_header)];
+       } else if (is_typec_cable(dev)) {
+               if (id)
+                       ptype = product_type_cable[PD_IDH_PTYPE(id->id_header)];
+               else
+                       ptype = to_typec_cable(dev)->active ?
+                               product_type_cable[IDH_PTYPE_ACABLE] :
+                               product_type_cable[IDH_PTYPE_PCABLE];
+       }
+
+       return ptype;
+}
+
 static ssize_t id_header_show(struct device *dev, struct device_attribute *attr,
                              char *buf)
 {
@@ -122,10 +174,40 @@ static ssize_t product_show(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RO(product);
 
+static ssize_t product_type_vdo1_show(struct device *dev, struct device_attribute *attr,
+                                     char *buf)
+{
+       struct usb_pd_identity *id = get_pd_identity(dev);
+
+       return sysfs_emit(buf, "0x%08x\n", id->vdo[0]);
+}
+static DEVICE_ATTR_RO(product_type_vdo1);
+
+static ssize_t product_type_vdo2_show(struct device *dev, struct device_attribute *attr,
+                                     char *buf)
+{
+       struct usb_pd_identity *id = get_pd_identity(dev);
+
+       return sysfs_emit(buf, "0x%08x\n", id->vdo[1]);
+}
+static DEVICE_ATTR_RO(product_type_vdo2);
+
+static ssize_t product_type_vdo3_show(struct device *dev, struct device_attribute *attr,
+                                     char *buf)
+{
+       struct usb_pd_identity *id = get_pd_identity(dev);
+
+       return sysfs_emit(buf, "0x%08x\n", id->vdo[2]);
+}
+static DEVICE_ATTR_RO(product_type_vdo3);
+
 static struct attribute *usb_pd_id_attrs[] = {
        &dev_attr_id_header.attr,
        &dev_attr_cert_stat.attr,
        &dev_attr_product.attr,
+       &dev_attr_product_type_vdo1.attr,
+       &dev_attr_product_type_vdo2.attr,
+       &dev_attr_product_type_vdo3.attr,
        NULL
 };
 
@@ -139,13 +221,49 @@ static const struct attribute_group *usb_pd_id_groups[] = {
        NULL,
 };
 
+static void typec_product_type_notify(struct device *dev)
+{
+       char *envp[2] = { };
+       const char *ptype;
+
+       ptype = get_pd_product_type(dev);
+       if (!ptype)
+               return;
+
+       sysfs_notify(&dev->kobj, NULL, "type");
+
+       envp[0] = kasprintf(GFP_KERNEL, "PRODUCT_TYPE=%s", ptype);
+       if (!envp[0])
+               return;
+
+       kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
+       kfree(envp[0]);
+}
+
 static void typec_report_identity(struct device *dev)
 {
        sysfs_notify(&dev->kobj, "identity", "id_header");
        sysfs_notify(&dev->kobj, "identity", "cert_stat");
        sysfs_notify(&dev->kobj, "identity", "product");
+       sysfs_notify(&dev->kobj, "identity", "product_type_vdo1");
+       sysfs_notify(&dev->kobj, "identity", "product_type_vdo2");
+       sysfs_notify(&dev->kobj, "identity", "product_type_vdo3");
+       typec_product_type_notify(dev);
 }
 
+static ssize_t
+type_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       const char *ptype;
+
+       ptype = get_pd_product_type(dev);
+       if (!ptype)
+               return 0;
+
+       return sysfs_emit(buf, "%s\n", ptype);
+}
+static DEVICE_ATTR_RO(type);
+
 /* ------------------------------------------------------------------------- */
 /* Alternate Modes */
 
@@ -382,7 +500,7 @@ static umode_t typec_altmode_attr_is_visible(struct kobject *kobj,
        return attr->mode;
 }
 
-static struct attribute_group typec_altmode_group = {
+static const struct attribute_group typec_altmode_group = {
        .is_visible = typec_altmode_attr_is_visible,
        .attrs = typec_altmode_attrs,
 };
@@ -532,12 +650,60 @@ static ssize_t supports_usb_power_delivery_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(supports_usb_power_delivery);
 
+static ssize_t number_of_alternate_modes_show(struct device *dev, struct device_attribute *attr,
+                                             char *buf)
+{
+       struct typec_partner *partner;
+       struct typec_plug *plug;
+       int num_altmodes;
+
+       if (is_typec_partner(dev)) {
+               partner = to_typec_partner(dev);
+               num_altmodes = partner->num_altmodes;
+       } else if (is_typec_plug(dev)) {
+               plug = to_typec_plug(dev);
+               num_altmodes = plug->num_altmodes;
+       } else {
+               return 0;
+       }
+
+       return sysfs_emit(buf, "%d\n", num_altmodes);
+}
+static DEVICE_ATTR_RO(number_of_alternate_modes);
+
 static struct attribute *typec_partner_attrs[] = {
        &dev_attr_accessory_mode.attr,
        &dev_attr_supports_usb_power_delivery.attr,
+       &dev_attr_number_of_alternate_modes.attr,
+       &dev_attr_type.attr,
+       NULL
+};
+
+static umode_t typec_partner_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
+{
+       struct typec_partner *partner = to_typec_partner(kobj_to_dev(kobj));
+
+       if (attr == &dev_attr_number_of_alternate_modes.attr) {
+               if (partner->num_altmodes < 0)
+                       return 0;
+       }
+
+       if (attr == &dev_attr_type.attr)
+               if (!get_pd_product_type(kobj_to_dev(kobj)))
+                       return 0;
+
+       return attr->mode;
+}
+
+static const struct attribute_group typec_partner_group = {
+       .is_visible = typec_partner_attr_is_visible,
+       .attrs = typec_partner_attrs
+};
+
+static const struct attribute_group *typec_partner_groups[] = {
+       &typec_partner_group,
        NULL
 };
-ATTRIBUTE_GROUPS(typec_partner);
 
 static void typec_partner_release(struct device *dev)
 {
@@ -570,6 +736,37 @@ int typec_partner_set_identity(struct typec_partner *partner)
 }
 EXPORT_SYMBOL_GPL(typec_partner_set_identity);
 
+/**
+ * typec_partner_set_num_altmodes - Set the number of available partner altmodes
+ * @partner: The partner to be updated.
+ * @num_altmodes: The number of altmodes we want to specify as available.
+ *
+ * This routine is used to report the number of alternate modes supported by the
+ * partner. This value is *not* enforced in alternate mode registration routines.
+ *
+ * @partner.num_altmodes is set to -1 on partner registration, denoting that
+ * a valid value has not been set for it yet.
+ *
+ * Returns 0 on success or negative error number on failure.
+ */
+int typec_partner_set_num_altmodes(struct typec_partner *partner, int num_altmodes)
+{
+       int ret;
+
+       if (num_altmodes < 0)
+               return -EINVAL;
+
+       partner->num_altmodes = num_altmodes;
+       ret = sysfs_update_group(&partner->dev.kobj, &typec_partner_group);
+       if (ret < 0)
+               return ret;
+
+       sysfs_notify(&partner->dev.kobj, NULL, "number_of_alternate_modes");
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(typec_partner_set_num_altmodes);
+
 /**
  * typec_partner_register_altmode - Register USB Type-C Partner Alternate Mode
  * @partner: USB Type-C Partner that supports the alternate mode
@@ -612,6 +809,7 @@ struct typec_partner *typec_register_partner(struct typec_port *port,
        ida_init(&partner->mode_ids);
        partner->usb_pd = desc->usb_pd;
        partner->accessory = desc->accessory;
+       partner->num_altmodes = -1;
 
        if (desc->identity) {
                /*
@@ -662,11 +860,70 @@ static void typec_plug_release(struct device *dev)
        kfree(plug);
 }
 
+static struct attribute *typec_plug_attrs[] = {
+       &dev_attr_number_of_alternate_modes.attr,
+       NULL
+};
+
+static umode_t typec_plug_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
+{
+       struct typec_plug *plug = to_typec_plug(kobj_to_dev(kobj));
+
+       if (attr == &dev_attr_number_of_alternate_modes.attr) {
+               if (plug->num_altmodes < 0)
+                       return 0;
+       }
+
+       return attr->mode;
+}
+
+static const struct attribute_group typec_plug_group = {
+       .is_visible = typec_plug_attr_is_visible,
+       .attrs = typec_plug_attrs
+};
+
+static const struct attribute_group *typec_plug_groups[] = {
+       &typec_plug_group,
+       NULL
+};
+
 static const struct device_type typec_plug_dev_type = {
        .name = "typec_plug",
+       .groups = typec_plug_groups,
        .release = typec_plug_release,
 };
 
+/**
+ * typec_plug_set_num_altmodes - Set the number of available plug altmodes
+ * @plug: The plug to be updated.
+ * @num_altmodes: The number of altmodes we want to specify as available.
+ *
+ * This routine is used to report the number of alternate modes supported by the
+ * plug. This value is *not* enforced in alternate mode registration routines.
+ *
+ * @plug.num_altmodes is set to -1 on plug registration, denoting that
+ * a valid value has not been set for it yet.
+ *
+ * Returns 0 on success or negative error number on failure.
+ */
+int typec_plug_set_num_altmodes(struct typec_plug *plug, int num_altmodes)
+{
+       int ret;
+
+       if (num_altmodes < 0)
+               return -EINVAL;
+
+       plug->num_altmodes = num_altmodes;
+       ret = sysfs_update_group(&plug->dev.kobj, &typec_plug_group);
+       if (ret < 0)
+               return ret;
+
+       sysfs_notify(&plug->dev.kobj, NULL, "number_of_alternate_modes");
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(typec_plug_set_num_altmodes);
+
 /**
  * typec_plug_register_altmode - Register USB Type-C Cable Plug Alternate Mode
  * @plug: USB Type-C Cable Plug that supports the alternate mode
@@ -712,6 +969,7 @@ struct typec_plug *typec_register_plug(struct typec_cable *cable,
        sprintf(name, "plug%d", desc->index);
 
        ida_init(&plug->mode_ids);
+       plug->num_altmodes = -1;
        plug->index = desc->index;
        plug->dev.class = typec_class;
        plug->dev.parent = &cable->dev;
@@ -744,15 +1002,6 @@ EXPORT_SYMBOL_GPL(typec_unregister_plug);
 
 /* Type-C Cables */
 
-static ssize_t
-type_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct typec_cable *cable = to_typec_cable(dev);
-
-       return sprintf(buf, "%s\n", cable->active ? "active" : "passive");
-}
-static DEVICE_ATTR_RO(type);
-
 static const char * const typec_plug_types[] = {
        [USB_PLUG_NONE]         = "unknown",
        [USB_PLUG_TYPE_A]       = "type-a",
@@ -1309,7 +1558,7 @@ static umode_t typec_attr_is_visible(struct kobject *kobj,
        return attr->mode;
 }
 
-static struct attribute_group typec_group = {
+static const struct attribute_group typec_group = {
        .is_visible = typec_attr_is_visible,
        .attrs = typec_attrs,
 };
@@ -1352,6 +1601,11 @@ const struct device_type typec_port_dev_type = {
 /* --------------------------------------- */
 /* Driver callbacks to report role updates */
 
+static int partner_match(struct device *dev, void *data)
+{
+       return is_typec_partner(dev);
+}
+
 /**
  * typec_set_data_role - Report data role change
  * @port: The USB Type-C Port where the role was changed
@@ -1361,12 +1615,23 @@ const struct device_type typec_port_dev_type = {
  */
 void typec_set_data_role(struct typec_port *port, enum typec_data_role role)
 {
+       struct device *partner_dev;
+
        if (port->data_role == role)
                return;
 
        port->data_role = role;
        sysfs_notify(&port->dev.kobj, NULL, "data_role");
        kobject_uevent(&port->dev.kobj, KOBJ_CHANGE);
+
+       partner_dev = device_find_child(&port->dev, NULL, partner_match);
+       if (!partner_dev)
+               return;
+
+       if (to_typec_partner(partner_dev)->identity)
+               typec_product_type_notify(partner_dev);
+
+       put_device(partner_dev);
 }
 EXPORT_SYMBOL_GPL(typec_set_data_role);
 
@@ -1407,11 +1672,6 @@ void typec_set_vconn_role(struct typec_port *port, enum typec_role role)
 }
 EXPORT_SYMBOL_GPL(typec_set_vconn_role);
 
-static int partner_match(struct device *dev, void *data)
-{
-       return is_typec_partner(dev);
-}
-
 /**
  * typec_set_pwr_opmode - Report changed power operation mode
  * @port: The USB Type-C Port where the mode was changed
index d7f63b7..aa3211f 100644 (file)
@@ -256,6 +256,7 @@ static int
 pmc_usb_mux_tbt(struct pmc_usb_port *port, struct typec_mux_state *state)
 {
        struct typec_thunderbolt_data *data = state->data;
+       u8 cable_rounded = TBT_CABLE_ROUNDED_SUPPORT(data->cable_mode);
        u8 cable_speed = TBT_CABLE_SPEED(data->cable_mode);
        struct altmode_req req = { };
 
@@ -284,6 +285,8 @@ pmc_usb_mux_tbt(struct pmc_usb_port *port, struct typec_mux_state *state)
 
        req.mode_data |= PMC_USB_ALTMODE_CABLE_SPD(cable_speed);
 
+       req.mode_data |= PMC_USB_ALTMODE_TBT_GEN(cable_rounded);
+
        return pmc_usb_command(port, (void *)&req, sizeof(req));
 }
 
index f9f0af6..12d983a 100644 (file)
 
 #include "tcpci.h"
 
-#define PD_RETRY_COUNT 3
+#define        PD_RETRY_COUNT                          3
+#define        AUTO_DISCHARGE_DEFAULT_THRESHOLD_MV     3500
+#define        AUTO_DISCHARGE_PD_HEADROOM_MV           850
+#define        AUTO_DISCHARGE_PPS_HEADROOM_MV          1250
 
 struct tcpci {
        struct device *dev;
@@ -268,6 +271,58 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable)
                                enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0);
 }
 
+static int tcpci_enable_auto_vbus_discharge(struct tcpc_dev *dev, bool enable)
+{
+       struct tcpci *tcpci = tcpc_to_tcpci(dev);
+       int ret;
+
+       ret = regmap_update_bits(tcpci->regmap, TCPC_POWER_CTRL, TCPC_POWER_CTRL_AUTO_DISCHARGE,
+                                enable ? TCPC_POWER_CTRL_AUTO_DISCHARGE : 0);
+       return ret;
+}
+
+static int tcpci_set_auto_vbus_discharge_threshold(struct tcpc_dev *dev, enum typec_pwr_opmode mode,
+                                                  bool pps_active, u32 requested_vbus_voltage_mv)
+{
+       struct tcpci *tcpci = tcpc_to_tcpci(dev);
+       unsigned int pwr_ctrl, threshold = 0;
+       int ret;
+
+       /*
+        * Indicates that vbus is going to go away due PR_SWAP, hard reset etc.
+        * Do not discharge vbus here.
+        */
+       if (requested_vbus_voltage_mv == 0)
+               goto write_thresh;
+
+       ret = regmap_read(tcpci->regmap, TCPC_POWER_CTRL, &pwr_ctrl);
+       if (ret < 0)
+               return ret;
+
+       if (pwr_ctrl & TCPC_FAST_ROLE_SWAP_EN) {
+               /* To prevent disconnect when the source is fast role swap is capable. */
+               threshold = AUTO_DISCHARGE_DEFAULT_THRESHOLD_MV;
+       } else if (mode == TYPEC_PWR_MODE_PD) {
+               if (pps_active)
+                       threshold = (95 * requested_vbus_voltage_mv / 100) -
+                               AUTO_DISCHARGE_PD_HEADROOM_MV;
+               else
+                       threshold = (95 * requested_vbus_voltage_mv / 100) -
+                               AUTO_DISCHARGE_PPS_HEADROOM_MV;
+       } else {
+               /* 3.5V for non-pd sink */
+               threshold = AUTO_DISCHARGE_DEFAULT_THRESHOLD_MV;
+       }
+
+       threshold = threshold / TCPC_VBUS_SINK_DISCONNECT_THRESH_LSB_MV;
+
+       if (threshold > TCPC_VBUS_SINK_DISCONNECT_THRESH_MAX)
+               return -EINVAL;
+
+write_thresh:
+       return tcpci_write16(tcpci, TCPC_VBUS_SINK_DISCONNECT_THRESH, threshold);
+}
+
 static int tcpci_enable_frs(struct tcpc_dev *dev, bool enable)
 {
        struct tcpci *tcpci = tcpc_to_tcpci(dev);
@@ -284,6 +339,14 @@ static int tcpci_enable_frs(struct tcpc_dev *dev, bool enable)
        return ret;
 }
 
+static void tcpci_frs_sourcing_vbus(struct tcpc_dev *dev)
+{
+       struct tcpci *tcpci = tcpc_to_tcpci(dev);
+
+       if (tcpci->data->frs_sourcing_vbus)
+               tcpci->data->frs_sourcing_vbus(tcpci, tcpci->data);
+}
+
 static int tcpci_set_bist_data(struct tcpc_dev *tcpc, bool enable)
 {
        struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
@@ -628,6 +691,13 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
        tcpci->tcpc.pd_transmit = tcpci_pd_transmit;
        tcpci->tcpc.set_bist_data = tcpci_set_bist_data;
        tcpci->tcpc.enable_frs = tcpci_enable_frs;
+       tcpci->tcpc.frs_sourcing_vbus = tcpci_frs_sourcing_vbus;
+
+       if (tcpci->data->auto_discharge_disconnect) {
+               tcpci->tcpc.enable_auto_vbus_discharge = tcpci_enable_auto_vbus_discharge;
+               tcpci->tcpc.set_auto_vbus_discharge_threshold =
+                       tcpci_set_auto_vbus_discharge_threshold;
+       }
 
        err = tcpci_parse_config(tcpci);
        if (err < 0)
index 5ef07a5..3fe3136 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef __LINUX_USB_TCPCI_H
 #define __LINUX_USB_TCPCI_H
 
+#include <linux/usb/typec.h>
+
 #define TCPC_VENDOR_ID                 0x0
 #define TCPC_PRODUCT_ID                        0x2
 #define TCPC_BCD_DEV                   0x4
@@ -67,6 +69,7 @@
 
 #define TCPC_POWER_CTRL                        0x1c
 #define TCPC_POWER_CTRL_VCONN_ENABLE   BIT(0)
+#define TCPC_POWER_CTRL_AUTO_DISCHARGE BIT(4)
 #define TCPC_FAST_ROLE_SWAP_EN         BIT(7)
 
 #define TCPC_CC_STATUS                 0x1d
 
 #define TCPC_VBUS_VOLTAGE                      0x70
 #define TCPC_VBUS_SINK_DISCONNECT_THRESH       0x72
+#define TCPC_VBUS_SINK_DISCONNECT_THRESH_LSB_MV        25
+#define TCPC_VBUS_SINK_DISCONNECT_THRESH_MAX   0x3ff
 #define TCPC_VBUS_STOP_DISCHARGE_THRESH                0x74
 #define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG         0x76
 #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG         0x78
 /* I2C_WRITE_BYTE_COUNT + 1 when TX_BUF_BYTE_x is only accessible I2C_WRITE_BYTE_COUNT */
 #define TCPC_TRANSMIT_BUFFER_MAX_LEN           31
 
+struct tcpci;
+
 /*
- * @TX_BUF_BYTE_x_hidden
+ * @TX_BUF_BYTE_x_hidden:
  *             optional; Set when TX_BUF_BYTE_x can only be accessed through I2C_WRITE_BYTE_COUNT.
+ * @frs_sourcing_vbus:
+ *             Optional; Callback to perform chip specific operations when FRS
+ *             is sourcing vbus.
+ * @auto_discharge_disconnect:
+ *             Optional; Enables TCPC to autonously discharge vbus on disconnect.
  */
-struct tcpci;
 struct tcpci_data {
        struct regmap *regmap;
        unsigned char TX_BUF_BYTE_x_hidden:1;
+       unsigned char auto_discharge_disconnect:1;
+
        int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
        int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
                         bool enable);
        int (*start_drp_toggling)(struct tcpci *tcpci, struct tcpci_data *data,
                                  enum typec_cc_status cc);
        int (*set_vbus)(struct tcpci *tcpci, struct tcpci_data *data, bool source, bool sink);
+       void (*frs_sourcing_vbus)(struct tcpci *tcpci, struct tcpci_data *data);
 };
 
 struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data);
index 723d7dd..c179723 100644 (file)
@@ -238,23 +238,22 @@ static void process_power_status(struct max_tcpci_chip *chip)
        if (ret < 0)
                return;
 
-       if (pwr_status == 0xff) {
+       if (pwr_status == 0xff)
                max_tcpci_init_regs(chip);
-       } else if (pwr_status & TCPC_POWER_STATUS_SOURCING_VBUS) {
+       else if (pwr_status & TCPC_POWER_STATUS_SOURCING_VBUS)
                tcpm_sourcing_vbus(chip->port);
-               /*
-                * Alawys re-enable boost here.
-                * In normal case, when say an headset is attached, TCPM would
-                * have instructed to TCPC to enable boost, so the call is a
-                * no-op.
-                * But for Fast Role Swap case, Boost turns on autonomously without
-                * AP intervention, but, needs AP to enable source mode explicitly
-                * for AP to regain control.
-                */
-               max_tcpci_set_vbus(chip->tcpci, &chip->data, true, false);
-       } else {
+       else
                tcpm_vbus_change(chip->port);
-       }
+}
+
+static void max_tcpci_frs_sourcing_vbus(struct tcpci *tcpci, struct tcpci_data *tdata)
+{
+       /*
+        * For Fast Role Swap case, Boost turns on autonomously without
+        * AP intervention, but, needs AP to enable source mode explicitly
+        * for AP to regain control.
+        */
+       max_tcpci_set_vbus(tcpci, tdata, true, false);
 }
 
 static void process_tx(struct max_tcpci_chip *chip, u16 status)
@@ -344,7 +343,7 @@ static irqreturn_t max_tcpci_irq(int irq, void *dev_id)
 {
        struct max_tcpci_chip *chip = dev_id;
        u16 status;
-       irqreturn_t irq_return;
+       irqreturn_t irq_return = IRQ_HANDLED;
        int ret;
 
        if (!chip->port)
@@ -441,10 +440,12 @@ static int max_tcpci_probe(struct i2c_client *client, const struct i2c_device_id
        chip->data.start_drp_toggling = max_tcpci_start_toggling;
        chip->data.TX_BUF_BYTE_x_hidden = true;
        chip->data.init = tcpci_init;
+       chip->data.frs_sourcing_vbus = max_tcpci_frs_sourcing_vbus;
+       chip->data.auto_discharge_disconnect = true;
 
        max_tcpci_init_regs(chip);
        chip->tcpci = tcpci_register_port(chip->dev, &chip->data);
-       if (IS_ERR_OR_NULL(chip->tcpci)) {
+       if (IS_ERR(chip->tcpci)) {
                dev_err(&client->dev, "TCPCI port registration failed");
                ret = PTR_ERR(chip->tcpci);
                return PTR_ERR(chip->tcpci);
@@ -481,7 +482,7 @@ MODULE_DEVICE_TABLE(i2c, max_tcpci_id);
 
 #ifdef CONFIG_OF
 static const struct of_device_id max_tcpci_of_match[] = {
-       { .compatible = "maxim,tcpc", },
+       { .compatible = "maxim,max33359", },
        {},
 };
 MODULE_DEVICE_TABLE(of, max_tcpci_of_match);
index a6fae1f..3bbc1f1 100644 (file)
@@ -363,8 +363,8 @@ struct tcpm_port {
        /* port belongs to a self powered device */
        bool self_powered;
 
-       /* FRS */
-       enum frs_typec_current frs_current;
+       /* Sink FRS */
+       enum frs_typec_current new_source_frs_current;
 
        /* Sink caps have been queried */
        bool sink_cap_done;
@@ -1706,6 +1706,24 @@ static void tcpm_handle_alert(struct tcpm_port *port, const __le32 *payload,
        }
 }
 
+static int tcpm_set_auto_vbus_discharge_threshold(struct tcpm_port *port,
+                                                 enum typec_pwr_opmode mode, bool pps_active,
+                                                 u32 requested_vbus_voltage)
+{
+       int ret;
+
+       if (!port->tcpc->set_auto_vbus_discharge_threshold)
+               return 0;
+
+       ret = port->tcpc->set_auto_vbus_discharge_threshold(port->tcpc, mode, pps_active,
+                                                           requested_vbus_voltage);
+       tcpm_log_force(port,
+                      "set_auto_vbus_discharge_threshold mode:%d pps_active:%c vbus:%u ret:%d",
+                      mode, pps_active ? 'y' : 'n', requested_vbus_voltage, ret);
+
+       return ret;
+}
+
 static void tcpm_pd_data_request(struct tcpm_port *port,
                                 const struct pd_message *msg)
 {
@@ -1713,7 +1731,7 @@ static void tcpm_pd_data_request(struct tcpm_port *port,
        unsigned int cnt = pd_header_cnt_le(msg->header);
        unsigned int rev = pd_header_rev_le(msg->header);
        unsigned int i;
-       enum frs_typec_current frs_current;
+       enum frs_typec_current partner_frs_current;
        bool frs_enable;
        int ret;
 
@@ -1786,12 +1804,13 @@ static void tcpm_pd_data_request(struct tcpm_port *port,
                for (i = 0; i < cnt; i++)
                        port->sink_caps[i] = le32_to_cpu(msg->payload[i]);
 
-               frs_current = (port->sink_caps[0] & PDO_FIXED_FRS_CURR_MASK) >>
+               partner_frs_current = (port->sink_caps[0] & PDO_FIXED_FRS_CURR_MASK) >>
                        PDO_FIXED_FRS_CURR_SHIFT;
-               frs_enable = frs_current && (frs_current <= port->frs_current);
+               frs_enable = partner_frs_current && (partner_frs_current <=
+                                                    port->new_source_frs_current);
                tcpm_log(port,
                         "Port partner FRS capable partner_frs_current:%u port_frs_current:%u enable:%c",
-                        frs_current, port->frs_current, frs_enable ? 'y' : 'n');
+                        partner_frs_current, port->new_source_frs_current, frs_enable ? 'y' : 'n');
                if (frs_enable) {
                        ret  = port->tcpc->enable_frs(port->tcpc, true);
                        tcpm_log(port, "Enable FRS %s, ret:%d\n", ret ? "fail" : "success", ret);
@@ -1875,6 +1894,10 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
                                                       port->current_limit,
                                                       port->supply_voltage);
                                port->explicit_contract = true;
+                               tcpm_set_auto_vbus_discharge_threshold(port,
+                                                                      TYPEC_PWR_MODE_PD,
+                                                                      port->pps_data.active,
+                                                                      port->supply_voltage);
                                tcpm_set_state(port, SNK_READY, 0);
                        } else {
                                /*
@@ -2789,8 +2812,12 @@ static int tcpm_src_attach(struct tcpm_port *port)
        if (ret < 0)
                return ret;
 
-       ret = tcpm_set_roles(port, true, TYPEC_SOURCE,
-                            tcpm_data_role_for_source(port));
+       if (port->tcpc->enable_auto_vbus_discharge) {
+               ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, true);
+               tcpm_log_force(port, "enable vbus discharge ret:%d", ret);
+       }
+
+       ret = tcpm_set_roles(port, true, TYPEC_SOURCE, tcpm_data_role_for_source(port));
        if (ret < 0)
                return ret;
 
@@ -2857,6 +2884,12 @@ static void tcpm_unregister_altmodes(struct tcpm_port *port)
 
 static void tcpm_reset_port(struct tcpm_port *port)
 {
+       int ret;
+
+       if (port->tcpc->enable_auto_vbus_discharge) {
+               ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, false);
+               tcpm_log_force(port, "Disable vbus discharge ret:%d", ret);
+       }
        tcpm_unregister_altmodes(port);
        tcpm_typec_disconnect(port);
        port->attached = false;
@@ -2921,8 +2954,13 @@ static int tcpm_snk_attach(struct tcpm_port *port)
        if (ret < 0)
                return ret;
 
-       ret = tcpm_set_roles(port, true, TYPEC_SINK,
-                            tcpm_data_role_for_sink(port));
+       if (port->tcpc->enable_auto_vbus_discharge) {
+               tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, VSAFE5V);
+               ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, true);
+               tcpm_log_force(port, "enable vbus discharge ret:%d", ret);
+       }
+
+       ret = tcpm_set_roles(port, true, TYPEC_SINK, tcpm_data_role_for_sink(port));
        if (ret < 0)
                return ret;
 
@@ -3086,15 +3124,13 @@ static void run_state_machine(struct tcpm_port *port)
                break;
        case SNK_TRY_WAIT_DEBOUNCE:
                tcpm_set_state(port, SNK_TRY_WAIT_DEBOUNCE_CHECK_VBUS,
-                              PD_T_PD_DEBOUNCE);
+                              PD_T_TRY_CC_DEBOUNCE);
                break;
        case SNK_TRY_WAIT_DEBOUNCE_CHECK_VBUS:
-               if (port->vbus_present && tcpm_port_is_sink(port)) {
+               if (port->vbus_present && tcpm_port_is_sink(port))
                        tcpm_set_state(port, SNK_ATTACHED, 0);
-               } else {
-                       tcpm_set_state(port, SRC_TRYWAIT, 0);
+               else
                        port->max_wait = 0;
-               }
                break;
        case SRC_TRYWAIT:
                tcpm_set_cc(port, tcpm_rp_cc(port));
@@ -3506,6 +3542,8 @@ static void run_state_machine(struct tcpm_port *port)
                tcpm_set_state(port, SRC_UNATTACHED, PD_T_PS_SOURCE_ON);
                break;
        case SNK_HARD_RESET_SINK_OFF:
+               /* Do not discharge/disconnect during hard reseet */
+               tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, 0);
                memset(&port->pps_data, 0, sizeof(port->pps_data));
                tcpm_set_vconn(port, false);
                if (port->pd_capable)
@@ -3548,6 +3586,7 @@ static void run_state_machine(struct tcpm_port *port)
                        tcpm_set_charge(port, true);
                }
                tcpm_set_attached_state(port, true);
+               tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, VSAFE5V);
                tcpm_set_state(port, SNK_STARTUP, 0);
                break;
 
@@ -3649,6 +3688,10 @@ static void run_state_machine(struct tcpm_port *port)
                        tcpm_set_state(port, PR_SWAP_SNK_SRC_SINK_OFF, 0);
                break;
        case PR_SWAP_SRC_SNK_TRANSITION_OFF:
+               /*
+                * Prevent vbus discharge circuit from turning on during PR_SWAP
+                * as this is not a disconnect.
+                */
                tcpm_set_vbus(port, false);
                port->explicit_contract = false;
                /* allow time for Vbus discharge, must be < tSrcSwapStdby */
@@ -3677,9 +3720,17 @@ static void run_state_machine(struct tcpm_port *port)
                tcpm_set_state_cond(port, SNK_UNATTACHED, PD_T_PS_SOURCE_ON);
                break;
        case PR_SWAP_SRC_SNK_SINK_ON:
+               /* Set the vbus disconnect threshold for implicit contract */
+               tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, VSAFE5V);
                tcpm_set_state(port, SNK_STARTUP, 0);
                break;
        case PR_SWAP_SNK_SRC_SINK_OFF:
+               /*
+                * Prevent vbus discharge circuit from turning on during PR_SWAP
+                * as this is not a disconnect.
+                */
+               tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB,
+                                                      port->pps_data.active, 0);
                tcpm_set_charge(port, false);
                tcpm_set_state(port, hard_reset_state(port),
                               PD_T_PS_SOURCE_OFF);
@@ -4000,6 +4051,12 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1,
                if (!tcpm_port_is_sink(port))
                        tcpm_set_state(port, SNK_TRYWAIT_DEBOUNCE, 0);
                break;
+       case SNK_TRY_WAIT_DEBOUNCE_CHECK_VBUS:
+               if (!tcpm_port_is_sink(port))
+                       tcpm_set_state(port, SRC_TRYWAIT, PD_T_TRY_CC_DEBOUNCE);
+               else
+                       tcpm_set_state(port, SNK_TRY_WAIT_DEBOUNCE_CHECK_VBUS, 0);
+               break;
        case SNK_TRYWAIT:
                /* Do nothing, waiting for tCCDebounce */
                break;
@@ -4086,11 +4143,24 @@ static void _tcpm_pd_vbus_on(struct tcpm_port *port)
        case SNK_TRYWAIT_DEBOUNCE:
                /* Do nothing, waiting for Rp */
                break;
+       case SNK_TRY_WAIT_DEBOUNCE_CHECK_VBUS:
+               if (port->vbus_present && tcpm_port_is_sink(port))
+                       tcpm_set_state(port, SNK_ATTACHED, 0);
+               break;
        case SRC_TRY_WAIT:
        case SRC_TRY_DEBOUNCE:
                /* Do nothing, waiting for sink detection */
                break;
+       case FR_SWAP_SEND:
+       case FR_SWAP_SEND_TIMEOUT:
+       case FR_SWAP_SNK_SRC_TRANSITION_TO_OFF:
+       case FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED:
+               if (port->tcpc->frs_sourcing_vbus)
+                       port->tcpc->frs_sourcing_vbus(port->tcpc);
+               break;
        case FR_SWAP_SNK_SRC_NEW_SINK_READY:
+               if (port->tcpc->frs_sourcing_vbus)
+                       port->tcpc->frs_sourcing_vbus(port->tcpc);
                tcpm_set_state(port, FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED, 0);
                break;
 
@@ -4156,6 +4226,14 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)
                /* Do nothing, expected */
                break;
 
+       case PR_SWAP_SNK_SRC_SOURCE_ON:
+               /*
+                * Do nothing when vbus off notification is received.
+                * TCPM can wait for PD_T_NEWSRC in PR_SWAP_SNK_SRC_SOURCE_ON
+                * for the vbus source to ramp up.
+                */
+               break;
+
        case PORT_RESET_WAIT_OFF:
                tcpm_set_state(port, tcpm_default_state(port), 0);
                break;
@@ -4808,9 +4886,10 @@ sink:
 
        /* FRS can only be supported byb DRP ports */
        if (port->port_type == TYPEC_PORT_DRP) {
-               ret = fwnode_property_read_u32(fwnode, "frs-typec-current", &frs_current);
+               ret = fwnode_property_read_u32(fwnode, "new-source-frs-typec-current",
+                                              &frs_current);
                if (ret >= 0 && frs_current <= FRS_5V_3A)
-                       port->frs_current = frs_current;
+                       port->new_source_frs_current = frs_current;
        }
 
        return 0;
index 51a570d..f029589 100644 (file)
@@ -53,7 +53,7 @@ static int ucsi_acknowledge_connector_change(struct ucsi *ucsi)
        ctrl = UCSI_ACK_CC_CI;
        ctrl |= UCSI_ACK_CONNECTOR_CHANGE;
 
-       return ucsi->ops->async_write(ucsi, UCSI_CONTROL, &ctrl, sizeof(ctrl));
+       return ucsi->ops->sync_write(ucsi, UCSI_CONTROL, &ctrl, sizeof(ctrl));
 }
 
 static int ucsi_exec_command(struct ucsi *ucsi, u64 command);
@@ -625,21 +625,113 @@ static void ucsi_handle_connector_change(struct work_struct *work)
        struct ucsi_connector *con = container_of(work, struct ucsi_connector,
                                                  work);
        struct ucsi *ucsi = con->ucsi;
+       struct ucsi_connector_status pre_ack_status;
+       struct ucsi_connector_status post_ack_status;
        enum typec_role role;
+       u16 inferred_changes;
+       u16 changed_flags;
        u64 command;
        int ret;
 
        mutex_lock(&con->lock);
 
+       /*
+        * Some/many PPMs have an issue where all fields in the change bitfield
+        * are cleared when an ACK is send. This will causes any change
+        * between GET_CONNECTOR_STATUS and ACK to be lost.
+        *
+        * We work around this by re-fetching the connector status afterwards.
+        * We then infer any changes that we see have happened but that may not
+        * be represented in the change bitfield.
+        *
+        * Also, even though we don't need to know the currently supported alt
+        * modes, we run the GET_CAM_SUPPORTED command to ensure the PPM does
+        * not get stuck in case it assumes we do.
+        * Always do this, rather than relying on UCSI_CONSTAT_CAM_CHANGE to be
+        * set in the change bitfield.
+        *
+        * We end up with the following actions:
+        *  1. UCSI_GET_CONNECTOR_STATUS, store result, update unprocessed_changes
+        *  2. UCSI_GET_CAM_SUPPORTED, discard result
+        *  3. ACK connector change
+        *  4. UCSI_GET_CONNECTOR_STATUS, store result
+        *  5. Infere lost changes by comparing UCSI_GET_CONNECTOR_STATUS results
+        *  6. If PPM reported a new change, then restart in order to ACK
+        *  7. Process everything as usual.
+        *
+        * We may end up seeing a change twice, but we can only miss extremely
+        * short transitional changes.
+        */
+
+       /* 1. First UCSI_GET_CONNECTOR_STATUS */
+       command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num);
+       ret = ucsi_send_command(ucsi, command, &pre_ack_status,
+                               sizeof(pre_ack_status));
+       if (ret < 0) {
+               dev_err(ucsi->dev, "%s: GET_CONNECTOR_STATUS failed (%d)\n",
+                       __func__, ret);
+               goto out_unlock;
+       }
+       con->unprocessed_changes |= pre_ack_status.change;
+
+       /* 2. Run UCSI_GET_CAM_SUPPORTED and discard the result. */
+       command = UCSI_GET_CAM_SUPPORTED;
+       command |= UCSI_CONNECTOR_NUMBER(con->num);
+       ucsi_send_command(con->ucsi, command, NULL, 0);
+
+       /* 3. ACK connector change */
+       clear_bit(EVENT_PENDING, &ucsi->flags);
+       ret = ucsi_acknowledge_connector_change(ucsi);
+       if (ret) {
+               dev_err(ucsi->dev, "%s: ACK failed (%d)", __func__, ret);
+               goto out_unlock;
+       }
+
+       /* 4. Second UCSI_GET_CONNECTOR_STATUS */
        command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num);
-       ret = ucsi_send_command(ucsi, command, &con->status,
-                               sizeof(con->status));
+       ret = ucsi_send_command(ucsi, command, &post_ack_status,
+                               sizeof(post_ack_status));
        if (ret < 0) {
                dev_err(ucsi->dev, "%s: GET_CONNECTOR_STATUS failed (%d)\n",
                        __func__, ret);
                goto out_unlock;
        }
 
+       /* 5. Inferre any missing changes */
+       changed_flags = pre_ack_status.flags ^ post_ack_status.flags;
+       inferred_changes = 0;
+       if (UCSI_CONSTAT_PWR_OPMODE(changed_flags) != 0)
+               inferred_changes |= UCSI_CONSTAT_POWER_OPMODE_CHANGE;
+
+       if (changed_flags & UCSI_CONSTAT_CONNECTED)
+               inferred_changes |= UCSI_CONSTAT_CONNECT_CHANGE;
+
+       if (changed_flags & UCSI_CONSTAT_PWR_DIR)
+               inferred_changes |= UCSI_CONSTAT_POWER_DIR_CHANGE;
+
+       if (UCSI_CONSTAT_PARTNER_FLAGS(changed_flags) != 0)
+               inferred_changes |= UCSI_CONSTAT_PARTNER_CHANGE;
+
+       if (UCSI_CONSTAT_PARTNER_TYPE(changed_flags) != 0)
+               inferred_changes |= UCSI_CONSTAT_PARTNER_CHANGE;
+
+       /* Mask out anything that was correctly notified in the later call. */
+       inferred_changes &= ~post_ack_status.change;
+       if (inferred_changes)
+               dev_dbg(ucsi->dev, "%s: Inferred changes that would have been lost: 0x%04x\n",
+                       __func__, inferred_changes);
+
+       con->unprocessed_changes |= inferred_changes;
+
+       /* 6. If PPM reported a new change, then restart in order to ACK */
+       if (post_ack_status.change)
+               goto out_unlock;
+
+       /* 7. Continue as if nothing happened */
+       con->status = post_ack_status;
+       con->status.change = con->unprocessed_changes;
+       con->unprocessed_changes = 0;
+
        role = !!(con->status.flags & UCSI_CONSTAT_PWR_DIR);
 
        if (con->status.change & UCSI_CONSTAT_POWER_OPMODE_CHANGE ||
@@ -680,28 +772,19 @@ static void ucsi_handle_connector_change(struct work_struct *work)
                ucsi_port_psy_changed(con);
        }
 
-       if (con->status.change & UCSI_CONSTAT_CAM_CHANGE) {
-               /*
-                * We don't need to know the currently supported alt modes here.
-                * Running GET_CAM_SUPPORTED command just to make sure the PPM
-                * does not get stuck in case it assumes we do so.
-                */
-               command = UCSI_GET_CAM_SUPPORTED;
-               command |= UCSI_CONNECTOR_NUMBER(con->num);
-               ucsi_send_command(con->ucsi, command, NULL, 0);
-       }
-
        if (con->status.change & UCSI_CONSTAT_PARTNER_CHANGE)
                ucsi_partner_change(con);
 
-       ret = ucsi_acknowledge_connector_change(ucsi);
-       if (ret)
-               dev_err(ucsi->dev, "%s: ACK failed (%d)", __func__, ret);
-
        trace_ucsi_connector_change(con->num, &con->status);
 
 out_unlock:
-       clear_bit(EVENT_PENDING, &ucsi->flags);
+       if (test_and_clear_bit(EVENT_PENDING, &ucsi->flags)) {
+               schedule_work(&con->work);
+               mutex_unlock(&con->lock);
+               return;
+       }
+
+       clear_bit(EVENT_PROCESSING, &ucsi->flags);
        mutex_unlock(&con->lock);
 }
 
@@ -719,7 +802,9 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num)
                return;
        }
 
-       if (!test_and_set_bit(EVENT_PENDING, &ucsi->flags))
+       set_bit(EVENT_PENDING, &ucsi->flags);
+
+       if (!test_and_set_bit(EVENT_PROCESSING, &ucsi->flags))
                schedule_work(&con->work);
 }
 EXPORT_SYMBOL_GPL(ucsi_connector_change);
index b7a92f2..dd9ba60 100644 (file)
@@ -296,6 +296,7 @@ struct ucsi {
 #define EVENT_PENDING  0
 #define COMMAND_PENDING        1
 #define ACK_PENDING    2
+#define EVENT_PROCESSING       3
 };
 
 #define UCSI_MAX_SVID          5
@@ -322,6 +323,7 @@ struct ucsi_connector {
 
        struct typec_capability typec_cap;
 
+       u16 unprocessed_changes;
        struct ucsi_connector_status status;
        struct ucsi_connector_capability cap;
        struct power_supply *psy;
index fbfe8f5..0497643 100644 (file)
@@ -103,11 +103,12 @@ static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data)
        if (ret)
                return;
 
+       if (UCSI_CCI_CONNECTOR(cci))
+               ucsi_connector_change(ua->ucsi, UCSI_CCI_CONNECTOR(cci));
+
        if (test_bit(COMMAND_PENDING, &ua->flags) &&
            cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE))
                complete(&ua->complete);
-       else if (UCSI_CCI_CONNECTOR(cci))
-               ucsi_connector_change(ua->ucsi, UCSI_CCI_CONNECTOR(cci));
 }
 
 static int ucsi_acpi_probe(struct platform_device *pdev)
index 4ce6c6a..2ab9924 100644 (file)
@@ -324,11 +324,6 @@ int usbip_recv(struct socket *sock, void *buf, int size)
        } while (msg_data_left(&msg));
 
        if (usbip_dbg_flag_xmit) {
-               if (!in_interrupt())
-                       pr_debug("%-10s:", current->comm);
-               else
-                       pr_debug("interrupt  :");
-
                pr_debug("receiving....\n");
                usbip_dump_buffer(buf, size);
                pr_debug("received, osize %d ret %d size %zd total %d\n",
index 985f2bb..0352893 100644 (file)
         PDO_PPS_APDO_MIN_VOLT(min_mv) | PDO_PPS_APDO_MAX_VOLT(max_mv) |        \
         PDO_PPS_APDO_MAX_CURR(max_ma))
 
+ /*
+  * Based on "Table 6-14 Fixed Supply PDO - Sink" of "USB Power Delivery Specification Revision 3.0,
+  * Version 1.2"
+  * Initial current capability of the new source when vSafe5V is applied.
+  */
+#define FRS_DEFAULT_POWER      1
+#define FRS_5V_1P5A            2
+#define FRS_5V_3A              3
  #endif /* __DT_POWER_DELIVERY_H */
diff --git a/include/linux/platform_data/usb-ehci-mxc.h b/include/linux/platform_data/usb-ehci-mxc.h
deleted file mode 100644 (file)
index ad9794d..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __INCLUDE_ASM_ARCH_MXC_EHCI_H
-#define __INCLUDE_ASM_ARCH_MXC_EHCI_H
-
-struct mxc_usbh_platform_data {
-       int (*init)(struct platform_device *pdev);
-       int (*exit)(struct platform_device *pdev);
-
-       unsigned int             portsc;
-       struct usb_phy          *otg;
-};
-
-#endif /* __INCLUDE_ASM_ARCH_MXC_EHCI_H */
-
index 3dbb42c..96281cd 100644 (file)
@@ -734,10 +734,6 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
 
 /* random stuff */
 
-#define        RUN_CONTEXT (in_irq() ? "in_irq" \
-               : (in_interrupt() ? "in_interrupt" : "can sleep"))
-
-
 /* This rwsem is for use only by the hub driver and ehci-hcd.
  * Nobody else should touch it.
  */
index 3a805e2..63a66dd 100644 (file)
@@ -484,6 +484,7 @@ static inline unsigned int rdo_max_power(u32 rdo)
 
 #define PD_T_CC_DEBOUNCE       200     /* 100 - 200 ms */
 #define PD_T_PD_DEBOUNCE       20      /* 10 - 20 ms */
+#define PD_T_TRY_CC_DEBOUNCE   15      /* 10 - 20 ms */
 
 #define PD_N_CAPS_COUNT                (PD_T_NO_RESPONSE / PD_T_SEND_SOURCE_CAP)
 #define PD_N_HARD_RESET_COUNT  2
index 68bdc4e..8c08eeb 100644 (file)
  * --------------------
  * <31>     :: data capable as a USB host
  * <30>     :: data capable as a USB device
- * <29:27>  :: product type
+ * <29:27>  :: product type (UFP / Cable)
  * <26>     :: modal operation supported (1b == yes)
- * <25:16>  :: Reserved, Shall be set to zero
+ * <25:16>  :: product type (DFP)
  * <15:0>   :: USB-IF assigned VID for this cable vendor
  */
 #define IDH_PTYPE_UNDEF                0
 #define IDH_PTYPE_HUB          1
 #define IDH_PTYPE_PERIPH       2
+#define IDH_PTYPE_PSD          3
+#define IDH_PTYPE_AMA          5
+
 #define IDH_PTYPE_PCABLE       3
 #define IDH_PTYPE_ACABLE       4
-#define IDH_PTYPE_AMA          5
+
+#define IDH_PTYPE_DFP_UNDEF    0
+#define IDH_PTYPE_DFP_HUB      1
+#define IDH_PTYPE_DFP_HOST     2
+#define IDH_PTYPE_DFP_PB       3
+#define IDH_PTYPE_DFP_AMC      4
 
 #define VDO_IDH(usbh, usbd, ptype, is_modal, vid)              \
        ((usbh) << 31 | (usbd) << 30 | ((ptype) & 0x7) << 27    \
 #define PD_IDH_PTYPE(vdo)      (((vdo) >> 27) & 0x7)
 #define PD_IDH_VID(vdo)                ((vdo) & 0xffff)
 #define PD_IDH_MODAL_SUPP(vdo) ((vdo) & (1 << 26))
+#define PD_IDH_DFP_PTYPE(vdo)  (((vdo) >> 23) & 0x7)
 
 /*
  * Cert Stat VDO
  * <31:28> :: Cable HW version
  * <27:24> :: Cable FW version
  * <23:20> :: Reserved, Shall be set to zero
- * <19:18> :: type-C to Type-A/B/C (00b == A, 01 == B, 10 == C)
+ * <19:18> :: type-C to Type-A/B/C/Captive (00b == A, 01 == B, 10 == C, 11 == Captive)
  * <17>    :: Type-C to Plug/Receptacle (0b == plug, 1b == receptacle)
  * <16:13> :: cable latency (0001 == <10ns(~1m length))
  * <12:11> :: cable termination type (11b == both ends active VCONN req)
 #define CABLE_ATYPE            0
 #define CABLE_BTYPE            1
 #define CABLE_CTYPE            2
+#define CABLE_CAPTIVE          3
 #define CABLE_PLUG             0
 #define CABLE_RECEPTACLE       1
 #define CABLE_CURR_1A5         0
         | (tx1d) << 10 | (tx2d) << 9 | (rx1d) << 8 | (rx2d) << 7       \
         | ((cur) & 0x3) << 5 | (vps) << 4 | (sopp) << 3                \
         | ((usbss) & 0x7))
+#define VDO_TYPEC_CABLE_TYPE(vdo)      (((vdo) >> 18) & 0x3)
 
 /*
  * AMA VDO
index 09762d2..e68aaa1 100644 (file)
@@ -83,6 +83,21 @@ enum tcpm_transmit_type {
  *             Optional; Called to enable/disable PD 3.0 fast role swap.
  *             Enabling frs is accessory dependent as not all PD3.0
  *             accessories support fast role swap.
+ * @frs_sourcing_vbus:
+ *             Optional; Called to notify that vbus is now being sourced.
+ *             Low level drivers can perform chip specific operations, if any.
+ * @enable_auto_vbus_discharge:
+ *             Optional; TCPCI spec based TCPC implementations can optionally
+ *             support hardware to autonomously dischrge vbus upon disconnecting
+ *             as sink or source. TCPM signals TCPC to enable the mechanism upon
+ *             entering connected state and signals disabling upon disconnect.
+ * @set_auto_vbus_discharge_threshold:
+ *             Mandatory when enable_auto_vbus_discharge is implemented. TCPM
+ *             calls this function to allow lower levels drivers to program the
+ *             vbus threshold voltage below which the vbus discharge circuit
+ *             will be turned on. requested_vbus_voltage is set to 0 when vbus
+ *             is going to disappear knowingly i.e. during PR_SWAP and
+ *             HARD_RESET etc.
  */
 struct tcpc_dev {
        struct fwnode_handle *fwnode;
@@ -109,6 +124,10 @@ struct tcpc_dev {
                           const struct pd_message *msg);
        int (*set_bist_data)(struct tcpc_dev *dev, bool on);
        int (*enable_frs)(struct tcpc_dev *dev, bool enable);
+       void (*frs_sourcing_vbus)(struct tcpc_dev *dev);
+       int (*enable_auto_vbus_discharge)(struct tcpc_dev *dev, bool enable);
+       int (*set_auto_vbus_discharge_threshold)(struct tcpc_dev *dev, enum typec_pwr_opmode mode,
+                                                bool pps_active, u32 requested_vbus_voltage);
 };
 
 struct tcpm_port;
index 6be5580..5447532 100644 (file)
@@ -126,9 +126,11 @@ struct typec_altmode_desc {
        enum typec_port_data    roles;
 };
 
+int typec_partner_set_num_altmodes(struct typec_partner *partner, int num_altmodes);
 struct typec_altmode
 *typec_partner_register_altmode(struct typec_partner *partner,
                                const struct typec_altmode_desc *desc);
+int typec_plug_set_num_altmodes(struct typec_plug *plug, int num_altmodes);
 struct typec_altmode
 *typec_plug_register_altmode(struct typec_plug *plug,
                             const struct typec_altmode_desc *desc);
index 47c2d50..63dd44b 100644 (file)
@@ -39,12 +39,16 @@ struct typec_thunderbolt_data {
 #define   TBT_CABLE_USB3_GEN1          1
 #define   TBT_CABLE_USB3_PASSIVE       2
 #define   TBT_CABLE_10_AND_20GBPS      3
-#define TBT_CABLE_ROUNDED              BIT(19)
+#define TBT_CABLE_ROUNDED_SUPPORT(_vdo_) \
+                                       (((_vdo_) & GENMASK(20, 19)) >> 19)
+#define   TBT_GEN3_NON_ROUNDED                 0
+#define   TBT_GEN3_GEN4_ROUNDED_NON_ROUNDED    1
 #define TBT_CABLE_OPTICAL              BIT(21)
 #define TBT_CABLE_RETIMER              BIT(22)
 #define TBT_CABLE_LINK_TRAINING                BIT(23)
 
 #define TBT_SET_CABLE_SPEED(_s_)       (((_s_) & GENMASK(2, 0)) << 16)
+#define TBT_SET_CABLE_ROUNDED(_g_)     (((_g_) & GENMASK(1, 0)) << 19)
 
 /* TBT3 Device Enter Mode VDO bits */
 #define TBT_ENTER_MODE_CABLE_SPEED(s)  TBT_SET_CABLE_SPEED(s)