Merge tag 'usb-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 7 Oct 2022 23:48:26 +0000 (16:48 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 7 Oct 2022 23:48:26 +0000 (16:48 -0700)
Pull USB / Thunderbolt updates from Greg KH:
 "Here is the big set of USB and Thunderbolt driver changes for 6.1-rc1.

  Nothing major in here, lots of little things with new devices
  supported and updates for a few drivers. Highlights include:

   - thunderbolt/USB4 devices supported a bit better than before, and
     some new ids to enable new hardware devices

   - USB gadget uvc updates for newer video formats and better v4l
     integration (the v4l portions were acked by those maintainers)

   - typec updates for tiny issues and more typec drivers for new chips.

   - xhci tiny updates for minor issues

   - big usb-serial ftdi_sio driver update to handle new devices better

   - lots of tiny dwc3 fixes and updates for the IP block that is
     showing up everywhere these days

   - dts updates for new devices being supported

   - other tiny janitorial and cleanups fixes for lots of different USB
     drivers. Full details are in the shortlog.

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'usb-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (169 commits)
  usb: gadget: uvc: don't put item still in use
  usb: gadget: uvc: Fix argument to sizeof() in uvc_register_video()
  usb: host: ehci-exynos: switch to using gpiod API
  Revert "usb: dwc3: Don't switch OTG -> peripheral if extcon is present"
  Revert "USB: fixup for merge issue with "usb: dwc3: Don't switch OTG -> peripheral if extcon is present""
  dt-bindings: usb: Convert FOTG210 to dt schema
  usb: mtu3: fix failed runtime suspend in host only mode
  USB: omap_udc: Fix spelling mistake: "tranceiver_ctrl" -> "transceiver_ctrl"
  usb: typec: ucsi_ccg: Disable UCSI ALT support on Tegra
  usb: typec: Replace custom implementation of device_match_fwnode()
  usb: typec: ucsi: Don't warn on probe deferral
  usb: add quirks for Lenovo OneLink+ Dock
  MAINTAINERS: switch dwc3 to Thinh
  usb: idmouse: fix an uninit-value in idmouse_open
  USB: PHY: JZ4770: Switch to use dev_err_probe() helper
  usb: phy: generic: Switch to use dev_err_probe() helper
  usb: ulpi: use DEFINE_SHOW_ATTRIBUTE to simplify ulpi_regs
  usb: cdns3: remove dead code
  usb: cdc-wdm: Use skb_put_data() instead of skb_put/memcpy pair
  usb: musb: sunxi: Switch to use dev_err_probe() helper
  ...

191 files changed:
Documentation/ABI/testing/sysfs-bus-thunderbolt
Documentation/devicetree/bindings/phy/mxs-usb-phy.txt
Documentation/devicetree/bindings/usb/analogix,anx7411.yaml
Documentation/devicetree/bindings/usb/aspeed,usb-vhub.yaml
Documentation/devicetree/bindings/usb/dwc2.yaml
Documentation/devicetree/bindings/usb/faraday,fotg210.txt [deleted file]
Documentation/devicetree/bindings/usb/faraday,fotg210.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/usb/npcm7xx-usb.txt
Documentation/devicetree/bindings/usb/qcom,dwc3.yaml
Documentation/devicetree/bindings/usb/renesas,usb3-peri.yaml
Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/usb/snps,dwc3.yaml
Documentation/devicetree/bindings/usb/st,stusb160x.yaml
Documentation/devicetree/bindings/usb/willsemi,wusb3801.yaml
Documentation/usb/usbip_protocol.rst
MAINTAINERS
arch/arm/mach-s3c/mach-gta02.c
arch/arm/mach-s3c/mach-h1940.c
arch/arm/mach-s3c/mach-jive.c
arch/arm/mach-s3c/mach-mini2440.c
arch/arm/mach-s3c/mach-n30.c
arch/arm/mach-s3c/mach-rx1950.c
arch/arm/mach-s3c/mach-smdk2413.c
arch/arm64/boot/dts/freescale/imx8mp.dtsi
drivers/media/usb/b2c2/flexcop-usb.c
drivers/media/usb/uvc/uvc_ctrl.c
drivers/media/usb/uvc/uvc_driver.c
drivers/media/usb/uvc/uvc_v4l2.c
drivers/media/usb/uvc/uvcvideo.h
drivers/media/v4l2-core/v4l2-common.c
drivers/phy/tegra/xusb-tegra186.c
drivers/phy/tegra/xusb.c
drivers/phy/tegra/xusb.h
drivers/thunderbolt/Kconfig
drivers/thunderbolt/debugfs.c
drivers/thunderbolt/domain.c
drivers/thunderbolt/icm.c
drivers/thunderbolt/nhi.c
drivers/thunderbolt/nhi.h
drivers/thunderbolt/nvm.c
drivers/thunderbolt/retimer.c
drivers/thunderbolt/sb_regs.h
drivers/thunderbolt/switch.c
drivers/thunderbolt/tb.c
drivers/thunderbolt/tb.h
drivers/thunderbolt/tb_regs.h
drivers/thunderbolt/usb4.c
drivers/thunderbolt/xdomain.c
drivers/usb/atm/usbatm.c
drivers/usb/cdns3/cdns3-plat.c
drivers/usb/chipidea/Kconfig
drivers/usb/chipidea/ci_hdrc_usb2.c
drivers/usb/chipidea/host.c
drivers/usb/chipidea/otg_fsm.c
drivers/usb/class/cdc-wdm.c
drivers/usb/common/debug.c
drivers/usb/common/ulpi.c
drivers/usb/common/usb-conn-gpio.c
drivers/usb/core/devio.c
drivers/usb/core/hcd-pci.c
drivers/usb/core/hcd.c
drivers/usb/core/quirks.c
drivers/usb/dwc2/core.c
drivers/usb/dwc2/core.h
drivers/usb/dwc2/core_intr.c
drivers/usb/dwc2/hcd.c
drivers/usb/dwc2/hcd.h
drivers/usb/dwc2/hcd_ddma.c
drivers/usb/dwc2/hcd_intr.c
drivers/usb/dwc2/hcd_queue.c
drivers/usb/dwc2/hw.h
drivers/usb/dwc2/params.c
drivers/usb/dwc2/pci.c
drivers/usb/dwc2/platform.c
drivers/usb/dwc3/core.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/debug.h
drivers/usb/dwc3/drd.c
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/dwc3/dwc3-qcom.c
drivers/usb/dwc3/dwc3-xilinx.c
drivers/usb/dwc3/ep0.c
drivers/usb/dwc3/gadget.c
drivers/usb/dwc3/trace.h
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_mass_storage.c
drivers/usb/gadget/function/f_ncm.c
drivers/usb/gadget/function/f_printer.c
drivers/usb/gadget/function/f_tcm.c
drivers/usb/gadget/function/f_uvc.c
drivers/usb/gadget/function/rndis.c
drivers/usb/gadget/function/u_ether.c
drivers/usb/gadget/function/u_serial.c
drivers/usb/gadget/function/uvc.h
drivers/usb/gadget/function/uvc_v4l2.c
drivers/usb/gadget/function/uvc_video.c
drivers/usb/gadget/udc/at91_udc.c
drivers/usb/gadget/udc/net2272.c
drivers/usb/gadget/udc/omap_udc.c
drivers/usb/gadget/udc/renesas_usb3.c
drivers/usb/gadget/udc/s3c2410_udc.c
drivers/usb/gadget/udc/s3c2410_udc.h
drivers/usb/gadget/udc/tegra-xudc.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-atmel.c
drivers/usb/host/ehci-exynos.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-npcm7xx.c
drivers/usb/host/ehci-omap.c
drivers/usb/host/ehci-orion.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-platform.c
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-spear.c
drivers/usb/host/ehci-st.c
drivers/usb/host/fhci-hcd.c
drivers/usb/host/fhci-hub.c
drivers/usb/host/fhci.h
drivers/usb/host/fotg210-hcd.c
drivers/usb/host/ohci-at91.c
drivers/usb/host/ohci-da8xx.c
drivers/usb/host/ohci-exynos.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-nxp.c
drivers/usb/host/ohci-omap.c
drivers/usb/host/ohci-pci.c
drivers/usb/host/ohci-platform.c
drivers/usb/host/ohci-pxa27x.c
drivers/usb/host/ohci-s3c2410.c
drivers/usb/host/ohci-spear.c
drivers/usb/host/ohci-st.c
drivers/usb/host/u132-hcd.c
drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-pci.c
drivers/usb/host/xhci-dbgcap.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-plat.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/misc/idmouse.c
drivers/usb/misc/usb251xb.c
drivers/usb/misc/usb3503.c
drivers/usb/misc/uss720.c
drivers/usb/mon/mon_bin.c
drivers/usb/mtu3/mtu3_core.c
drivers/usb/mtu3/mtu3_plat.c
drivers/usb/musb/da8xx.c
drivers/usb/musb/jz4740.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_cppi41.c
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/sunxi.c
drivers/usb/phy/phy-generic.c
drivers/usb/phy/phy-jz4770.c
drivers/usb/phy/phy-mxs-usb.c
drivers/usb/phy/phy-tegra-usb.c
drivers/usb/serial/console.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio.h
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/qcserial.c
drivers/usb/storage/onetouch.c
drivers/usb/storage/unusual_devs.h
drivers/usb/typec/anx7411.c
drivers/usb/typec/mux.c
drivers/usb/typec/qcom-pmic-typec.c
drivers/usb/typec/retimer.c
drivers/usb/typec/stusb160x.c
drivers/usb/typec/tcpm/Kconfig
drivers/usb/typec/tcpm/Makefile
drivers/usb/typec/tcpm/fusb302.c
drivers/usb/typec/tcpm/tcpci.c
drivers/usb/typec/tcpm/tcpci_mt6370.c [new file with mode: 0644]
drivers/usb/typec/tcpm/tcpci_rt1711h.c
drivers/usb/typec/ucsi/ucsi.c
drivers/usb/typec/ucsi/ucsi_ccg.c
drivers/usb/typec/ucsi/ucsi_stm32g0.c
drivers/usb/usbip/stub_main.c
drivers/usb/usbip/stub_rx.c
drivers/usb/usbip/usbip_common.c
include/linux/phy/tegra/xusb.h
include/linux/platform_data/usb-s3c2410_udc.h
include/linux/usb/chipidea.h
include/linux/usb/hcd.h
include/linux/usb/tcpci.h
include/media/v4l2-common.h
include/media/v4l2-uvc.h [new file with mode: 0644]
include/uapi/linux/usbip.h

index f7570c2..76ab3e1 100644 (file)
@@ -153,7 +153,7 @@ Date:               Jan 2020
 KernelVersion: 5.5
 Contact:       Mika Westerberg <mika.westerberg@linux.intel.com>
 Description:   This attribute reports number of RX lanes the device is
-               using simultaneusly through its upstream port.
+               using simultaneously through its upstream port.
 
 What:          /sys/bus/thunderbolt/devices/.../tx_speed
 Date:          Jan 2020
@@ -167,7 +167,7 @@ Date:               Jan 2020
 KernelVersion: 5.5
 Contact:       Mika Westerberg <mika.westerberg@linux.intel.com>
 Description:   This attribute reports number of TX lanes the device is
-               using simultaneusly through its upstream port.
+               using simultaneously through its upstream port.
 
 What:          /sys/bus/thunderbolt/devices/.../vendor
 Date:          Sep 2017
index c9e392c..70c813b 100644 (file)
@@ -15,10 +15,10 @@ Required properties:
 - fsl,anatop: phandle for anatop register, it is only for imx6 SoC series
 
 Optional properties:
-- fsl,tx-cal-45-dn-ohms: Integer [30-55]. Resistance (in ohms) of switchable
+- fsl,tx-cal-45-dn-ohms: Integer [35-54]. Resistance (in ohms) of switchable
   high-speed trimming resistor connected in parallel with the 45 ohm resistor
   that terminates the DN output signal. Default: 45
-- fsl,tx-cal-45-dp-ohms: Integer [30-55]. Resistance (in ohms) of switchable
+- fsl,tx-cal-45-dp-ohms: Integer [35-54]. Resistance (in ohms) of switchable
   high-speed trimming resistor connected in parallel with the 45 ohm resistor
   that terminates the DP output signal. Default: 45
 - fsl,tx-d-cal: Integer [79-119]. Current trimming value (as a percentage) of
index ee43630..0e72c08 100644 (file)
@@ -23,6 +23,8 @@ properties:
   connector:
     type: object
     $ref: ../connector/usb-connector.yaml
+    unevaluatedProperties: false
+
     description:
       Properties for usb c connector.
 
index 8b019ac..a86bcd9 100644 (file)
@@ -67,6 +67,7 @@ properties:
 
   vhub-strings:
     type: object
+    additionalProperties: false
 
     properties:
       '#address-cells':
@@ -78,6 +79,7 @@ properties:
     patternProperties:
       '^string@[0-9a-f]+$':
         type: object
+        additionalProperties: false
         description: string descriptors of the specific language
 
         properties:
index 1bfbc6e..dc4988c 100644 (file)
@@ -32,6 +32,7 @@ properties:
           - enum:
               - rockchip,px30-usb
               - rockchip,rk3036-usb
+              - rockchip,rk3128-usb
               - rockchip,rk3188-usb
               - rockchip,rk3228-usb
               - rockchip,rk3288-usb
diff --git a/Documentation/devicetree/bindings/usb/faraday,fotg210.txt b/Documentation/devicetree/bindings/usb/faraday,fotg210.txt
deleted file mode 100644 (file)
index 06a2286..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-Faraday FOTG Host controller
-
-This OTG-capable USB host controller is found in Cortina Systems
-Gemini and other SoC products.
-
-Required properties:
-- compatible: should be one of:
-  "faraday,fotg210"
-  "cortina,gemini-usb", "faraday,fotg210"
-- reg: should contain one register range i.e. start and length
-- interrupts: description of the interrupt line
-
-Optional properties:
-- clocks: should contain the IP block clock
-- clock-names: should be "PCLK" for the IP block clock
-
-Required properties for "cortina,gemini-usb" compatible:
-- syscon: a phandle to the system controller to access PHY registers
-
-Optional properties for "cortina,gemini-usb" compatible:
-- cortina,gemini-mini-b: boolean property that indicates that a Mini-B
-  OTG connector is in use
-- wakeup-source: see power/wakeup-source.txt
-
-Example for Gemini:
-
-usb@68000000 {
-       compatible = "cortina,gemini-usb", "faraday,fotg210";
-       reg = <0x68000000 0x1000>;
-       interrupts = <10 IRQ_TYPE_LEVEL_HIGH>;
-       clocks = <&cc 12>;
-       clock-names = "PCLK";
-       syscon = <&syscon>;
-       wakeup-source;
-};
diff --git a/Documentation/devicetree/bindings/usb/faraday,fotg210.yaml b/Documentation/devicetree/bindings/usb/faraday,fotg210.yaml
new file mode 100644 (file)
index 0000000..c69bbfb
--- /dev/null
@@ -0,0 +1,77 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2022 Linaro Ltd.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/faraday,fotg210.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Faraday Technology FOTG210 HS OTG USB 2.0 controller Bindings
+
+maintainers:
+  - Linus Walleij <linus.walleij@linaro.org>
+
+allOf:
+  - $ref: usb-drd.yaml#
+  - $ref: usb-hcd.yaml#
+
+properties:
+  compatible:
+    oneOf:
+      - const: faraday,fotg210
+      - items:
+          - const: cortina,gemini-usb
+          - const: faraday,fotg210
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: PCLK
+
+  resets:
+    maxItems: 1
+
+  syscon:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: a phandle to the global Gemini system controller on
+      Gemini systems
+
+  dr_mode: true
+
+  phys:
+    maxItems: 1
+
+  phy-names:
+    const: usb2-phy
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/clock/cortina,gemini-clock.h>
+    #include <dt-bindings/reset/cortina,gemini-reset.h>
+    usb0: usb@68000000 {
+        compatible = "cortina,gemini-usb", "faraday,fotg210";
+        reg = <0x68000000 0x1000>;
+        interrupts = <10 IRQ_TYPE_LEVEL_HIGH>;
+        resets = <&syscon GEMINI_RESET_USB0>;
+        clocks = <&syscon GEMINI_CLK_GATE_USB0>;
+        clock-names = "PCLK";
+        syscon = <&syscon>;
+        dr_mode = "host";
+    };
diff --git a/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml
new file mode 100644 (file)
index 0000000..72f56cc
--- /dev/null
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/usb/mediatek,mt6370-tcpc.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: MediatTek MT6370 Type-C Port Switch and Power Delivery controller
+
+maintainers:
+  - ChiYuan Huang <cy_huang@richtek.com>
+
+description: |
+  MediaTek MT6370 is a multi-functional device.
+  It integrates charger, ADC, flash, RGB indicators,
+  regulators (DSV/VIBLDO), and TypeC Port Switch with Power Delivery controller.
+  This document only describes MT6370 Type-C Port Switch and
+  Power Delivery controller.
+
+properties:
+  compatible:
+    enum:
+      - mediatek,mt6370-tcpc
+
+  interrupts:
+    maxItems: 1
+
+  connector:
+    type: object
+    $ref: /schemas/connector/usb-connector.yaml#
+    unevaluatedProperties: false
+
+additionalProperties: false
+
+required:
+  - compatible
+  - interrupts
index 5a0f1f1..352a0a1 100644 (file)
@@ -5,7 +5,9 @@ EHCI:
 -----
 
 Required properties:
-- compatible: "nuvoton,npcm750-ehci"
+- compatible: should be one of
+    "nuvoton,npcm750-ehci"
+    "nuvoton,npcm845-ehci"
 - interrupts: Should contain the EHCI interrupt
 - reg:        Physical address and length of the register set for the device
 
index cd2f7cb..a6e6abb 100644 (file)
@@ -26,6 +26,7 @@ properties:
           - qcom,sc7280-dwc3
           - qcom,sc8280xp-dwc3
           - qcom,sdm660-dwc3
+          - qcom,sdm670-dwc3
           - qcom,sdm845-dwc3
           - qcom,sdx55-dwc3
           - qcom,sdx65-dwc3
@@ -175,6 +176,7 @@ allOf:
               - qcom,msm8998-dwc3
               - qcom,sc7180-dwc3
               - qcom,sc7280-dwc3
+              - qcom,sdm670-dwc3
               - qcom,sdm845-dwc3
               - qcom,sdx55-dwc3
               - qcom,sm6350-dwc3
@@ -294,6 +296,7 @@ allOf:
         compatible:
           contains:
             enum:
+              - qcom,sm6115-dwc3
               - qcom,sm6125-dwc3
               - qcom,sm8150-dwc3
               - qcom,sm8250-dwc3
@@ -344,11 +347,11 @@ allOf:
               - qcom,msm8994-dwc3
               - qcom,qcs404-dwc3
               - qcom,sc7180-dwc3
+              - qcom,sdm670-dwc3
               - qcom,sdm845-dwc3
               - qcom,sdx55-dwc3
               - qcom,sdx65-dwc3
               - qcom,sm4250-dwc3
-              - qcom,sm6115-dwc3
               - qcom,sm6125-dwc3
               - qcom,sm6350-dwc3
               - qcom,sm8150-dwc3
@@ -380,6 +383,7 @@ allOf:
               - qcom,msm8953-dwc3
               - qcom,msm8996-dwc3
               - qcom,msm8998-dwc3
+              - qcom,sm6115-dwc3
     then:
       properties:
         interrupts:
index 9fcf54b..55dfd12 100644 (file)
@@ -11,27 +11,55 @@ maintainers:
 
 properties:
   compatible:
-    items:
-      - enum:
-          - renesas,r8a774a1-usb3-peri # RZ/G2M
-          - renesas,r8a774b1-usb3-peri # RZ/G2N
-          - renesas,r8a774c0-usb3-peri # RZ/G2E
-          - renesas,r8a774e1-usb3-peri # RZ/G2H
-          - renesas,r8a7795-usb3-peri  # R-Car H3
-          - renesas,r8a7796-usb3-peri  # R-Car M3-W
-          - renesas,r8a77961-usb3-peri # R-Car M3-W+
-          - renesas,r8a77965-usb3-peri # R-Car M3-N
-          - renesas,r8a77990-usb3-peri # R-Car E3
-      - const: renesas,rcar-gen3-usb3-peri
+    oneOf:
+      - items:
+          - enum:
+              - renesas,r8a774a1-usb3-peri # RZ/G2M
+              - renesas,r8a774b1-usb3-peri # RZ/G2N
+              - renesas,r8a774c0-usb3-peri # RZ/G2E
+              - renesas,r8a774e1-usb3-peri # RZ/G2H
+              - renesas,r8a7795-usb3-peri  # R-Car H3
+              - renesas,r8a7796-usb3-peri  # R-Car M3-W
+              - renesas,r8a77961-usb3-peri # R-Car M3-W+
+              - renesas,r8a77965-usb3-peri # R-Car M3-N
+              - renesas,r8a77990-usb3-peri # R-Car E3
+          - const: renesas,rcar-gen3-usb3-peri
+
+      - items:
+          - enum:
+              - renesas,r9a09g011-usb3-peri # RZ/V2M
+          - const: renesas,rzv2m-usb3-peri
 
   reg:
     maxItems: 1
 
   interrupts:
-    maxItems: 1
+    minItems: 1
+    items:
+      - description: Combined interrupt for DMA, SYS and ERR
+      - description: Dual Role Device (DRD)
+      - description: Battery Charging
+      - description: Global Purpose Input
+
+  interrupt-names:
+    minItems: 1
+    items:
+      - const: all_p
+      - const: drd
+      - const: bc
+      - const: gpi
 
   clocks:
-    maxItems: 1
+    minItems: 1
+    items:
+      - description: Main clock
+      - description: Register access clock
+
+  clock-names:
+    minItems: 1
+    items:
+      - const: aclk
+      - const: reg
 
   phys:
     maxItems: 1
@@ -43,7 +71,15 @@ properties:
     maxItems: 1
 
   resets:
-    maxItems: 1
+    minItems: 1
+    items:
+      - description: Peripheral reset
+      - description: DRD reset
+
+  reset-names:
+    items:
+      - const: aresetn_p
+      - const: drd_reset
 
   usb-role-switch:
     $ref: /schemas/types.yaml#/definitions/flag
@@ -78,6 +114,39 @@ required:
   - interrupts
   - clocks
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - renesas,rzv2m-usb3-peri
+    then:
+      properties:
+        clocks:
+          minItems: 2
+        clock-names:
+          minItems: 2
+        interrupts:
+          minItems: 4
+        interrupt-names:
+          minItems: 4
+        resets:
+          minItems: 2
+      required:
+        - clock-names
+        - interrupt-names
+        - resets
+        - reset-names
+    else:
+      properties:
+        clocks:
+          maxItems: 1
+        interrupts:
+          maxItems: 1
+        resets:
+          maxItems: 1
+
 additionalProperties: false
 
 examples:
diff --git a/Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml b/Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml
new file mode 100644 (file)
index 0000000..1999f61
--- /dev/null
@@ -0,0 +1,100 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/usb/richtek,rt1711h.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Richtek RT1711H Type-C Port Switch and Power Delivery controller
+
+maintainers:
+  - Gene Chen <gene_chen@richtek.com>
+
+description: |
+  The RT1711H is a USB Type-C controller that complies with the latest
+  USB Type-C and PD standards. It does the USB Type-C detection including attach
+  and orientation. It integrates the physical layer of the USB BMC power
+  delivery protocol to allow up to 100W of power. The BMC PD block enables full
+  support for alternative interfaces of the Type-C specification.
+
+properties:
+  compatible:
+    enum:
+      - richtek,rt1711h
+      - richtek,rt1715
+    description:
+      RT1711H support PD20, RT1715 support PD30 except Fast Role Swap.
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  wakeup-source:
+    type: boolean
+
+  connector:
+    type: object
+    $ref: /schemas/connector/usb-connector.yaml#
+    description:
+      Properties for usb c connector.
+
+additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - connector
+  - interrupts
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/usb/pd.h>
+    i2c0 {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      rt1711h@4e {
+        compatible = "richtek,rt1711h";
+        reg = <0x4e>;
+        interrupts-extended = <&gpio26 3 IRQ_TYPE_LEVEL_LOW>;
+        wakeup-source;
+
+        connector {
+          compatible = "usb-c-connector";
+          label = "USB-C";
+          data-role = "dual";
+          power-role = "dual";
+          try-power-role = "sink";
+          source-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP)>;
+          sink-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP)>;
+          op-sink-microwatt = <10000000>;
+
+          ports {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            port@0 {
+              reg = <0>;
+              endpoint {
+                remote-endpoint = <&usb_hs>;
+              };
+            };
+            port@1 {
+              reg = <1>;
+              endpoint {
+                remote-endpoint = <&usb_ss>;
+              };
+            };
+            port@2 {
+              reg = <2>;
+              endpoint {
+                remote-endpoint = <&dp_aux>;
+              };
+            };
+          };
+        };
+      };
+    };
+...
index 1779d08..6d78048 100644 (file)
@@ -234,6 +234,18 @@ properties:
       avoid -EPROTO errors with usbhid on some devices (Hikey 970).
     type: boolean
 
+  snps,gfladj-refclk-lpm-sel-quirk:
+    description:
+      When set, run the SOF/ITP counter based on ref_clk.
+    type: boolean
+
+  snps,resume-hs-terminations:
+    description:
+      Fix the issue of HS terminations CRC error on resume by enabling this
+      quirk. When set, all the termsel, xcvrsel, opmode becomes 0 during end
+      of resume. This option is to support certain legacy ULPI PHYs.
+    type: boolean
+
   snps,is-utmi-l1-suspend:
     description:
       True when DWC3 asserts output signal utmi_l1_suspend_n, false when
index b5a8c98..b897480 100644 (file)
@@ -33,6 +33,7 @@ properties:
   connector:
     type: object
     $ref: /schemas/connector/usb-connector.yaml#
+    unevaluatedProperties: false
 
     properties:
       compatible:
@@ -74,9 +75,14 @@ examples:
                 data-role = "dual";
                 typec-power-opmode = "default";
 
-                port {
-                    typec_con_ep: endpoint {
-                        remote-endpoint = <&usbotg_hs_ep>;
+                ports {
+                    #address-cells = <1>;
+                    #size-cells = <0>;
+                    port@0 {
+                        reg = <0>;
+                        typec_con_ep: endpoint {
+                            remote-endpoint = <&usbotg_hs_ep>;
+                        };
                     };
                 };
             };
index c2b2243..5aa4ffd 100644 (file)
@@ -28,6 +28,7 @@ properties:
   connector:
     type: object
     $ref: ../connector/usb-connector.yaml#
+    unevaluatedProperties: false
     description:
       The managed USB Type-C connector. Since WUSB3801 does not support
       Power Delivery, the node should have the "pd-disable" property.
index 0b8541f..adc1589 100644 (file)
@@ -340,13 +340,12 @@ USBIP_CMD_SUBMIT:
 | 0         | 20     | usbip_header_basic, 'command' shall be 0x00000001 |
 +-----------+--------+---------------------------------------------------+
 | 0x14      | 4      | transfer_flags: possible values depend on the     |
-|           |        | URB transfer_flags (refer to URB doc in           |
-|           |        | Documentation/driver-api/usb/URB.rst)             |
-|           |        | but with URB_NO_TRANSFER_DMA_MAP masked. Refer to |
-|           |        | function usbip_pack_cmd_submit and function       |
-|           |        | tweak_transfer_flags in drivers/usb/usbip/        |
-|           |        | usbip_common.c. The following fields may also ref |
-|           |        | to function usbip_pack_cmd_submit and URB doc     |
+|           |        | USBIP_URB transfer_flags.                         |
+|           |        | Refer to include/uapi/linux/usbip.h and           |
+|           |        | Documentation/driver-api/usb/URB.rst.             |
+|           |        | Refer to usbip_pack_cmd_submit() and              |
+|           |        | tweak_transfer_flags() in drivers/usb/usbip/      |
+|           |        | usbip_common.c.                                   |
 +-----------+--------+---------------------------------------------------+
 | 0x18      | 4      | transfer_buffer_length:                           |
 |           |        | use URB transfer_buffer_length                    |
index 5beeea4..04b7e12 100644 (file)
@@ -5921,10 +5921,9 @@ T:       git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 F:     drivers/usb/dwc2/
 
 DESIGNWARE USB3 DRD IP DRIVER
-M:     Felipe Balbi <balbi@kernel.org>
+M:     Thinh Nguyen <Thinh.Nguyen@synopsys.com>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 F:     drivers/usb/dwc3/
 
 DEVANTECH SRF ULTRASONIC RANGER IIO DRIVER
index abfdce7..d50a81d 100644 (file)
@@ -421,7 +421,14 @@ static struct s3c2410_platform_nand __initdata gta02_nand_info = {
 /* Get PMU to set USB current limit accordingly. */
 static struct s3c2410_udc_mach_info gta02_udc_cfg __initdata = {
        .vbus_draw      = gta02_udc_vbus_draw,
-       .pullup_pin = GTA02_GPIO_USB_PULLUP,
+};
+
+static struct gpiod_lookup_table gta02_udc_gpio_table = {
+       .dev_id = "s3c2410-usbgadget",
+       .table = {
+               GPIO_LOOKUP("GPIOB", 9, "pullup", GPIO_ACTIVE_HIGH),
+               { },
+       },
 };
 
 /* USB */
@@ -555,6 +562,7 @@ static void __init gta02_machine_init(void)
        s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2),
                              S3C_GPIO_PULL_NONE);
 
+       gpiod_add_lookup_table(&gta02_udc_gpio_table);
        gpiod_add_lookup_table(&gta02_audio_gpio_table);
        gpiod_add_lookup_table(&gta02_mmc_gpio_table);
        platform_add_devices(gta02_devices, ARRAY_SIZE(gta02_devices));
index 032b188..83ac6cf 100644 (file)
@@ -167,9 +167,15 @@ static struct gpio_chip h1940_latch_gpiochip = {
 };
 
 static struct s3c2410_udc_mach_info h1940_udc_cfg __initdata = {
-       .vbus_pin               = S3C2410_GPG(5),
-       .vbus_pin_inverted      = 1,
-       .pullup_pin             = H1940_LATCH_USB_DP,
+};
+
+static struct gpiod_lookup_table h1940_udc_gpio_table = {
+       .dev_id = "s3c2410-usbgadget",
+       .table = {
+               GPIO_LOOKUP("GPIOG", 5, "vbus", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("H1940_LATCH", 7, "pullup", GPIO_ACTIVE_HIGH),
+               { },
+       },
 };
 
 static struct s3c2410_ts_mach_info h1940_ts_cfg __initdata = {
@@ -725,6 +731,7 @@ static void __init h1940_init(void)
        u32 tmp;
 
        s3c24xx_fb_set_platdata(&h1940_fb_info);
+       gpiod_add_lookup_table(&h1940_udc_gpio_table);
        gpiod_add_lookup_table(&h1940_mmc_gpio_table);
        gpiod_add_lookup_table(&h1940_audio_gpio_table);
        gpiod_add_lookup_table(&h1940_bat_gpio_table);
index e327731..16859bb 100644 (file)
@@ -493,7 +493,14 @@ static struct platform_device *jive_devices[] __initdata = {
 };
 
 static struct s3c2410_udc_mach_info jive_udc_cfg __initdata = {
-       .vbus_pin       = S3C2410_GPG(1),               /* detect is on GPG1 */
+};
+
+static struct gpiod_lookup_table jive_udc_gpio_table = {
+       .dev_id = "s3c2410-usbgadget",
+       .table = {
+               GPIO_LOOKUP("GPIOG", 1, "vbus", GPIO_ACTIVE_HIGH),
+               { },
+       },
 };
 
 /* Jive power management device */
@@ -669,6 +676,7 @@ static void __init jive_machine_init(void)
 
        pm_power_off = jive_power_off;
 
+       gpiod_add_lookup_table(&jive_udc_gpio_table);
        gpiod_add_lookup_table(&jive_lcdspi_gpiod_table);
        gpiod_add_lookup_table(&jive_wm8750_gpiod_table);
        platform_add_devices(jive_devices, ARRAY_SIZE(jive_devices));
index a6d17ff..283be70 100644 (file)
@@ -93,9 +93,15 @@ static struct s3c2410_uartcfg mini2440_uartcfgs[] __initdata = {
 /* USB device UDC support */
 
 static struct s3c2410_udc_mach_info mini2440_udc_cfg __initdata = {
-       .pullup_pin = S3C2410_GPC(5),
 };
 
+static struct gpiod_lookup_table mini2440_udc_gpio_table = {
+       .dev_id = "s3c2410-usbgadget",
+       .table = {
+               GPIO_LOOKUP("GPIOC", 5, "pullup", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
 
 /* LCD timing and setup */
 
@@ -755,6 +761,7 @@ static void __init mini2440_init(void)
                s3c24xx_fb_set_platdata(&mini2440_fb_info);
        }
 
+       gpiod_add_lookup_table(&mini2440_udc_gpio_table);
        s3c24xx_udc_set_platdata(&mini2440_udc_cfg);
        gpiod_add_lookup_table(&mini2440_mmc_gpio_table);
        s3c24xx_mci_set_platdata(&mini2440_mmc_cfg);
index 75f5dc6..90122fc 100644 (file)
@@ -84,9 +84,15 @@ static struct s3c2410_uartcfg n30_uartcfgs[] = {
 };
 
 static struct s3c2410_udc_mach_info n30_udc_cfg __initdata = {
-       .vbus_pin               = S3C2410_GPG(1),
-       .vbus_pin_inverted      = 0,
-       .pullup_pin             = S3C2410_GPB(3),
+};
+
+static struct gpiod_lookup_table n30_udc_gpio_table = {
+       .dev_id = "s3c2410-usbgadget",
+       .table = {
+               GPIO_LOOKUP("GPIOG", 1, "vbus", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("GPIOB", 3, "pullup", GPIO_ACTIVE_HIGH),
+               { },
+       },
 };
 
 static struct gpio_keys_button n30_buttons[] = {
@@ -595,6 +601,7 @@ static void __init n30_init(void)
        WARN_ON(gpio_request(S3C2410_GPG(4), "mmc power"));
 
        s3c24xx_fb_set_platdata(&n30_fb_info);
+       gpiod_add_lookup_table(&n30_udc_gpio_table);
        s3c24xx_udc_set_platdata(&n30_udc_cfg);
        gpiod_add_lookup_table(&n30_mci_gpio_table);
        s3c24xx_mci_set_platdata(&n30_mci_cfg);
index 7a3e7c0..d8c49e5 100644 (file)
@@ -643,9 +643,15 @@ static struct s3c2410_platform_nand rx1950_nand_info = {
 };
 
 static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = {
-       .vbus_pin = S3C2410_GPG(5),
-       .vbus_pin_inverted = 1,
-       .pullup_pin = S3C2410_GPJ(5),
+};
+
+static struct gpiod_lookup_table rx1950_udc_gpio_table = {
+       .dev_id = "s3c2410-usbgadget",
+       .table = {
+               GPIO_LOOKUP("GPIOG", 5, "vbus", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("GPIOJ", 5, "pullup", GPIO_ACTIVE_HIGH),
+               { },
+       },
 };
 
 static struct s3c2410_ts_mach_info rx1950_ts_cfg __initdata = {
@@ -847,6 +853,7 @@ static void __init rx1950_init_machine(void)
        gpio_direction_output(S3C2410_GPJ(6), 0);
 
        pwm_add_table(rx1950_pwm_lookup, ARRAY_SIZE(rx1950_pwm_lookup));
+       gpiod_add_lookup_table(&rx1950_udc_gpio_table);
        gpiod_add_lookup_table(&rx1950_audio_gpio_table);
        gpiod_add_lookup_table(&rx1950_bat_gpio_table);
        /* Configure the I2S pins (GPE0...GPE4) in correct mode */
index f1f0ec1..2b4e20a 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/serial_core.h>
 #include <linux/serial_s3c.h>
 #include <linux/platform_device.h>
@@ -74,9 +74,15 @@ static struct s3c2410_uartcfg smdk2413_uartcfgs[] __initdata = {
 
 
 static struct s3c2410_udc_mach_info smdk2413_udc_cfg __initdata = {
-       .pullup_pin = S3C2410_GPF(2),
 };
 
+static struct gpiod_lookup_table smdk2413_udc_gpio_table = {
+       .dev_id = "s3c2410-usbgadget",
+       .table = {
+               GPIO_LOOKUP("GPIOF", 2, "pullup", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
 
 static struct platform_device *smdk2413_devices[] __initdata = {
        &s3c_device_ohci,
@@ -115,7 +121,7 @@ static void __init smdk2413_machine_init(void)
                              S3C2410_MISCCR_USBSUSPND0 |
                              S3C2410_MISCCR_USBSUSPND1, 0x0);
 
-
+       gpiod_add_lookup_table(&smdk2413_udc_gpio_table);
        s3c24xx_udc_set_platdata(&smdk2413_udc_cfg);
        s3c_i2c0_set_platdata(NULL);
        /* Configure the I2S pins (GPE0...GPE4) in correct mode */
index 53493dc..bb916a0 100644 (file)
                                interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
                                phys = <&usb3_phy0>, <&usb3_phy0>;
                                phy-names = "usb2-phy", "usb3-phy";
-                               snps,dis-u2-freeclk-exists-quirk;
+                               snps,gfladj-refclk-lpm-sel-quirk;
                        };
 
                };
                                interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
                                phys = <&usb3_phy1>, <&usb3_phy1>;
                                phy-names = "usb2-phy", "usb3-phy";
-                               snps,dis-u2-freeclk-exists-quirk;
+                               snps,gfladj-refclk-lpm-sel-quirk;
                        };
                };
 
index e012b21..790787f 100644 (file)
@@ -425,12 +425,14 @@ static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb)
 
 static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
 {
-       u16 frame_size = le16_to_cpu(
-               fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize);
-       int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO *
-               frame_size, i, j, ret;
+       struct usb_host_interface *alt = fc_usb->uintf->cur_altsetting;
+       u16 frame_size;
+       int bufsize, i, j, ret;
        int buffer_offset = 0;
 
+       frame_size = usb_endpoint_maxp(&alt->endpoint[0].desc);
+       bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * frame_size;
+
        deb_ts("creating %d iso-urbs with %d frames each of %d bytes size = %d.\n",
               B2C2_USB_NUM_ISO_URB,
                        B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize);
@@ -501,17 +503,21 @@ urb_error:
 
 static int flexcop_usb_init(struct flexcop_usb *fc_usb)
 {
-       /* use the alternate setting with the larges buffer */
-       int ret = usb_set_interface(fc_usb->udev, 0, 1);
+       struct usb_host_interface *alt;
+       int ret;
 
+       /* use the alternate setting with the largest buffer */
+       ret = usb_set_interface(fc_usb->udev, 0, 1);
        if (ret) {
                err("set interface failed.");
                return ret;
        }
 
-       if (fc_usb->uintf->cur_altsetting->desc.bNumEndpoints < 1)
+       alt = fc_usb->uintf->cur_altsetting;
+
+       if (alt->desc.bNumEndpoints < 1)
                return -ENODEV;
-       if (!usb_endpoint_is_isoc_in(&fc_usb->uintf->cur_altsetting->endpoint[0].desc))
+       if (!usb_endpoint_is_isoc_in(&alt->endpoint[0].desc))
                return -ENODEV;
 
        switch (fc_usb->udev->speed) {
index 97f3120..c95a222 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/workqueue.h>
 #include <linux/atomic.h>
 #include <media/v4l2-ctrls.h>
+#include <media/v4l2-uvc.h>
 
 #include "uvcvideo.h"
 
index 744051b..215fb48 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-uvc.h>
 
 #include "uvcvideo.h"
 
@@ -35,198 +36,6 @@ unsigned int uvc_dbg_param;
 unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT;
 
 /* ------------------------------------------------------------------------
- * Video formats
- */
-
-static struct uvc_format_desc uvc_fmts[] = {
-       {
-               .name           = "YUV 4:2:2 (YUYV)",
-               .guid           = UVC_GUID_FORMAT_YUY2,
-               .fcc            = V4L2_PIX_FMT_YUYV,
-       },
-       {
-               .name           = "YUV 4:2:2 (YUYV)",
-               .guid           = UVC_GUID_FORMAT_YUY2_ISIGHT,
-               .fcc            = V4L2_PIX_FMT_YUYV,
-       },
-       {
-               .name           = "YUV 4:2:0 (NV12)",
-               .guid           = UVC_GUID_FORMAT_NV12,
-               .fcc            = V4L2_PIX_FMT_NV12,
-       },
-       {
-               .name           = "MJPEG",
-               .guid           = UVC_GUID_FORMAT_MJPEG,
-               .fcc            = V4L2_PIX_FMT_MJPEG,
-       },
-       {
-               .name           = "YVU 4:2:0 (YV12)",
-               .guid           = UVC_GUID_FORMAT_YV12,
-               .fcc            = V4L2_PIX_FMT_YVU420,
-       },
-       {
-               .name           = "YUV 4:2:0 (I420)",
-               .guid           = UVC_GUID_FORMAT_I420,
-               .fcc            = V4L2_PIX_FMT_YUV420,
-       },
-       {
-               .name           = "YUV 4:2:0 (M420)",
-               .guid           = UVC_GUID_FORMAT_M420,
-               .fcc            = V4L2_PIX_FMT_M420,
-       },
-       {
-               .name           = "YUV 4:2:2 (UYVY)",
-               .guid           = UVC_GUID_FORMAT_UYVY,
-               .fcc            = V4L2_PIX_FMT_UYVY,
-       },
-       {
-               .name           = "Greyscale 8-bit (Y800)",
-               .guid           = UVC_GUID_FORMAT_Y800,
-               .fcc            = V4L2_PIX_FMT_GREY,
-       },
-       {
-               .name           = "Greyscale 8-bit (Y8  )",
-               .guid           = UVC_GUID_FORMAT_Y8,
-               .fcc            = V4L2_PIX_FMT_GREY,
-       },
-       {
-               .name           = "Greyscale 8-bit (D3DFMT_L8)",
-               .guid           = UVC_GUID_FORMAT_D3DFMT_L8,
-               .fcc            = V4L2_PIX_FMT_GREY,
-       },
-       {
-               .name           = "IR 8-bit (L8_IR)",
-               .guid           = UVC_GUID_FORMAT_KSMEDIA_L8_IR,
-               .fcc            = V4L2_PIX_FMT_GREY,
-       },
-       {
-               .name           = "Greyscale 10-bit (Y10 )",
-               .guid           = UVC_GUID_FORMAT_Y10,
-               .fcc            = V4L2_PIX_FMT_Y10,
-       },
-       {
-               .name           = "Greyscale 12-bit (Y12 )",
-               .guid           = UVC_GUID_FORMAT_Y12,
-               .fcc            = V4L2_PIX_FMT_Y12,
-       },
-       {
-               .name           = "Greyscale 16-bit (Y16 )",
-               .guid           = UVC_GUID_FORMAT_Y16,
-               .fcc            = V4L2_PIX_FMT_Y16,
-       },
-       {
-               .name           = "BGGR Bayer (BY8 )",
-               .guid           = UVC_GUID_FORMAT_BY8,
-               .fcc            = V4L2_PIX_FMT_SBGGR8,
-       },
-       {
-               .name           = "BGGR Bayer (BA81)",
-               .guid           = UVC_GUID_FORMAT_BA81,
-               .fcc            = V4L2_PIX_FMT_SBGGR8,
-       },
-       {
-               .name           = "GBRG Bayer (GBRG)",
-               .guid           = UVC_GUID_FORMAT_GBRG,
-               .fcc            = V4L2_PIX_FMT_SGBRG8,
-       },
-       {
-               .name           = "GRBG Bayer (GRBG)",
-               .guid           = UVC_GUID_FORMAT_GRBG,
-               .fcc            = V4L2_PIX_FMT_SGRBG8,
-       },
-       {
-               .name           = "RGGB Bayer (RGGB)",
-               .guid           = UVC_GUID_FORMAT_RGGB,
-               .fcc            = V4L2_PIX_FMT_SRGGB8,
-       },
-       {
-               .name           = "RGB565",
-               .guid           = UVC_GUID_FORMAT_RGBP,
-               .fcc            = V4L2_PIX_FMT_RGB565,
-       },
-       {
-               .name           = "BGR 8:8:8 (BGR3)",
-               .guid           = UVC_GUID_FORMAT_BGR3,
-               .fcc            = V4L2_PIX_FMT_BGR24,
-       },
-       {
-               .name           = "H.264",
-               .guid           = UVC_GUID_FORMAT_H264,
-               .fcc            = V4L2_PIX_FMT_H264,
-       },
-       {
-               .name           = "H.265",
-               .guid           = UVC_GUID_FORMAT_H265,
-               .fcc            = V4L2_PIX_FMT_HEVC,
-       },
-       {
-               .name           = "Greyscale 8 L/R (Y8I)",
-               .guid           = UVC_GUID_FORMAT_Y8I,
-               .fcc            = V4L2_PIX_FMT_Y8I,
-       },
-       {
-               .name           = "Greyscale 12 L/R (Y12I)",
-               .guid           = UVC_GUID_FORMAT_Y12I,
-               .fcc            = V4L2_PIX_FMT_Y12I,
-       },
-       {
-               .name           = "Depth data 16-bit (Z16)",
-               .guid           = UVC_GUID_FORMAT_Z16,
-               .fcc            = V4L2_PIX_FMT_Z16,
-       },
-       {
-               .name           = "Bayer 10-bit (SRGGB10P)",
-               .guid           = UVC_GUID_FORMAT_RW10,
-               .fcc            = V4L2_PIX_FMT_SRGGB10P,
-       },
-       {
-               .name           = "Bayer 16-bit (SBGGR16)",
-               .guid           = UVC_GUID_FORMAT_BG16,
-               .fcc            = V4L2_PIX_FMT_SBGGR16,
-       },
-       {
-               .name           = "Bayer 16-bit (SGBRG16)",
-               .guid           = UVC_GUID_FORMAT_GB16,
-               .fcc            = V4L2_PIX_FMT_SGBRG16,
-       },
-       {
-               .name           = "Bayer 16-bit (SRGGB16)",
-               .guid           = UVC_GUID_FORMAT_RG16,
-               .fcc            = V4L2_PIX_FMT_SRGGB16,
-       },
-       {
-               .name           = "Bayer 16-bit (SGRBG16)",
-               .guid           = UVC_GUID_FORMAT_GR16,
-               .fcc            = V4L2_PIX_FMT_SGRBG16,
-       },
-       {
-               .name           = "Depth data 16-bit (Z16)",
-               .guid           = UVC_GUID_FORMAT_INVZ,
-               .fcc            = V4L2_PIX_FMT_Z16,
-       },
-       {
-               .name           = "Greyscale 10-bit (Y10 )",
-               .guid           = UVC_GUID_FORMAT_INVI,
-               .fcc            = V4L2_PIX_FMT_Y10,
-       },
-       {
-               .name           = "IR:Depth 26-bit (INZI)",
-               .guid           = UVC_GUID_FORMAT_INZI,
-               .fcc            = V4L2_PIX_FMT_INZI,
-       },
-       {
-               .name           = "4-bit Depth Confidence (Packed)",
-               .guid           = UVC_GUID_FORMAT_CNF4,
-               .fcc            = V4L2_PIX_FMT_CNF4,
-       },
-       {
-               .name           = "HEVC",
-               .guid           = UVC_GUID_FORMAT_HEVC,
-               .fcc            = V4L2_PIX_FMT_HEVC,
-       },
-};
-
-/* ------------------------------------------------------------------------
  * Utility functions
  */
 
@@ -245,19 +54,6 @@ struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
        return NULL;
 }
 
-static struct uvc_format_desc *uvc_format_by_guid(const u8 guid[16])
-{
-       unsigned int len = ARRAY_SIZE(uvc_fmts);
-       unsigned int i;
-
-       for (i = 0; i < len; ++i) {
-               if (memcmp(guid, uvc_fmts[i].guid, 16) == 0)
-                       return &uvc_fmts[i];
-       }
-
-       return NULL;
-}
-
 static enum v4l2_colorspace uvc_colorspace(const u8 primaries)
 {
        static const enum v4l2_colorspace colorprimaries[] = {
@@ -329,90 +125,6 @@ static enum v4l2_ycbcr_encoding uvc_ycbcr_enc(const u8 matrix_coefficients)
        return V4L2_YCBCR_ENC_DEFAULT;  /* Reserved */
 }
 
-/*
- * Simplify a fraction using a simple continued fraction decomposition. The
- * idea here is to convert fractions such as 333333/10000000 to 1/30 using
- * 32 bit arithmetic only. The algorithm is not perfect and relies upon two
- * arbitrary parameters to remove non-significative terms from the simple
- * continued fraction decomposition. Using 8 and 333 for n_terms and threshold
- * respectively seems to give nice results.
- */
-void uvc_simplify_fraction(u32 *numerator, u32 *denominator,
-               unsigned int n_terms, unsigned int threshold)
-{
-       u32 *an;
-       u32 x, y, r;
-       unsigned int i, n;
-
-       an = kmalloc_array(n_terms, sizeof(*an), GFP_KERNEL);
-       if (an == NULL)
-               return;
-
-       /*
-        * Convert the fraction to a simple continued fraction. See
-        * https://en.wikipedia.org/wiki/Continued_fraction
-        * Stop if the current term is bigger than or equal to the given
-        * threshold.
-        */
-       x = *numerator;
-       y = *denominator;
-
-       for (n = 0; n < n_terms && y != 0; ++n) {
-               an[n] = x / y;
-               if (an[n] >= threshold) {
-                       if (n < 2)
-                               n++;
-                       break;
-               }
-
-               r = x - an[n] * y;
-               x = y;
-               y = r;
-       }
-
-       /* Expand the simple continued fraction back to an integer fraction. */
-       x = 0;
-       y = 1;
-
-       for (i = n; i > 0; --i) {
-               r = y;
-               y = an[i-1] * y + x;
-               x = r;
-       }
-
-       *numerator = y;
-       *denominator = x;
-       kfree(an);
-}
-
-/*
- * Convert a fraction to a frame interval in 100ns multiples. The idea here is
- * to compute numerator / denominator * 10000000 using 32 bit fixed point
- * arithmetic only.
- */
-u32 uvc_fraction_to_interval(u32 numerator, u32 denominator)
-{
-       u32 multiplier;
-
-       /* Saturate the result if the operation would overflow. */
-       if (denominator == 0 ||
-           numerator/denominator >= ((u32)-1)/10000000)
-               return (u32)-1;
-
-       /*
-        * Divide both the denominator and the multiplier by two until
-        * numerator * multiplier doesn't overflow. If anyone knows a better
-        * algorithm please let me know.
-        */
-       multiplier = 10000000;
-       while (numerator > ((u32)-1)/multiplier) {
-               multiplier /= 2;
-               denominator /= 2;
-       }
-
-       return denominator ? numerator * multiplier / denominator : 0;
-}
-
 /* ------------------------------------------------------------------------
  * Terminal and unit management
  */
index 4cc3fa6..f4d4c33 100644 (file)
@@ -386,7 +386,7 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
        mutex_unlock(&stream->mutex);
 
        denominator = 10000000;
-       uvc_simplify_fraction(&numerator, &denominator, 8, 333);
+       v4l2_simplify_fraction(&numerator, &denominator, 8, 333);
 
        memset(parm, 0, sizeof(*parm));
        parm->type = stream->type;
@@ -427,7 +427,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
        else
                timeperframe = parm->parm.output.timeperframe;
 
-       interval = uvc_fraction_to_interval(timeperframe.numerator,
+       interval = v4l2_fraction_to_interval(timeperframe.numerator,
                timeperframe.denominator);
        uvc_dbg(stream->dev, FORMAT, "Setting frame interval to %u/%u (%u)\n",
                timeperframe.numerator, timeperframe.denominator, interval);
@@ -481,7 +481,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
        /* Return the actual frame period. */
        timeperframe.numerator = probe.dwFrameInterval;
        timeperframe.denominator = 10000000;
-       uvc_simplify_fraction(&timeperframe.numerator,
+       v4l2_simplify_fraction(&timeperframe.numerator,
                &timeperframe.denominator, 8, 333);
 
        if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
@@ -1275,7 +1275,7 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh,
                fival->discrete.numerator =
                        frame->dwFrameInterval[index];
                fival->discrete.denominator = 10000000;
-               uvc_simplify_fraction(&fival->discrete.numerator,
+               v4l2_simplify_fraction(&fival->discrete.numerator,
                        &fival->discrete.denominator, 8, 333);
        } else {
                fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
@@ -1285,11 +1285,11 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh,
                fival->stepwise.max.denominator = 10000000;
                fival->stepwise.step.numerator = frame->dwFrameInterval[2];
                fival->stepwise.step.denominator = 10000000;
-               uvc_simplify_fraction(&fival->stepwise.min.numerator,
+               v4l2_simplify_fraction(&fival->stepwise.min.numerator,
                        &fival->stepwise.min.denominator, 8, 333);
-               uvc_simplify_fraction(&fival->stepwise.max.numerator,
+               v4l2_simplify_fraction(&fival->stepwise.max.numerator,
                        &fival->stepwise.max.denominator, 8, 333);
-               uvc_simplify_fraction(&fival->stepwise.step.numerator,
+               v4l2_simplify_fraction(&fival->stepwise.step.numerator,
                        &fival->stepwise.step.denominator, 8, 333);
        }
 
index 24c911a..df93db2 100644 (file)
 #define UVC_EXT_GPIO_UNIT_ID           0x100
 
 /* ------------------------------------------------------------------------
- * GUIDs
- */
-#define UVC_GUID_UVC_CAMERA \
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
-#define UVC_GUID_UVC_OUTPUT \
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}
-#define UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT \
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
-#define UVC_GUID_UVC_PROCESSING \
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01}
-#define UVC_GUID_UVC_SELECTOR \
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}
-#define UVC_GUID_EXT_GPIO_CONTROLLER \
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03}
-
-#define UVC_GUID_FORMAT_MJPEG \
-       { 'M',  'J',  'P',  'G', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_YUY2 \
-       { 'Y',  'U',  'Y',  '2', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_YUY2_ISIGHT \
-       { 'Y',  'U',  'Y',  '2', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0x00, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_NV12 \
-       { 'N',  'V',  '1',  '2', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_YV12 \
-       { 'Y',  'V',  '1',  '2', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_I420 \
-       { 'I',  '4',  '2',  '0', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_UYVY \
-       { 'U',  'Y',  'V',  'Y', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y800 \
-       { 'Y',  '8',  '0',  '0', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y8 \
-       { 'Y',  '8',  ' ',  ' ', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y10 \
-       { 'Y',  '1',  '0',  ' ', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y12 \
-       { 'Y',  '1',  '2',  ' ', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y16 \
-       { 'Y',  '1',  '6',  ' ', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_BY8 \
-       { 'B',  'Y',  '8',  ' ', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_BA81 \
-       { 'B',  'A',  '8',  '1', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_GBRG \
-       { 'G',  'B',  'R',  'G', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_GRBG \
-       { 'G',  'R',  'B',  'G', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_RGGB \
-       { 'R',  'G',  'G',  'B', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_BG16 \
-       { 'B',  'G',  '1',  '6', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_GB16 \
-       { 'G',  'B',  '1',  '6', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_RG16 \
-       { 'R',  'G',  '1',  '6', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_GR16 \
-       { 'G',  'R',  '1',  '6', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_RGBP \
-       { 'R',  'G',  'B',  'P', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_BGR3 \
-       { 0x7d, 0xeb, 0x36, 0xe4, 0x4f, 0x52, 0xce, 0x11, \
-        0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}
-#define UVC_GUID_FORMAT_M420 \
-       { 'M',  '4',  '2',  '0', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-
-#define UVC_GUID_FORMAT_H264 \
-       { 'H',  '2',  '6',  '4', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_H265 \
-       { 'H',  '2',  '6',  '5', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y8I \
-       { 'Y',  '8',  'I',  ' ', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y12I \
-       { 'Y',  '1',  '2',  'I', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Z16 \
-       { 'Z',  '1',  '6',  ' ', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_RW10 \
-       { 'R',  'W',  '1',  '0', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_INVZ \
-       { 'I',  'N',  'V',  'Z', 0x90, 0x2d, 0x58, 0x4a, \
-        0x92, 0x0b, 0x77, 0x3f, 0x1f, 0x2c, 0x55, 0x6b}
-#define UVC_GUID_FORMAT_INZI \
-       { 'I',  'N',  'Z',  'I', 0x66, 0x1a, 0x42, 0xa2, \
-        0x90, 0x65, 0xd0, 0x18, 0x14, 0xa8, 0xef, 0x8a}
-#define UVC_GUID_FORMAT_INVI \
-       { 'I',  'N',  'V',  'I', 0xdb, 0x57, 0x49, 0x5e, \
-        0x8e, 0x3f, 0xf4, 0x79, 0x53, 0x2b, 0x94, 0x6f}
-#define UVC_GUID_FORMAT_CNF4 \
-       { 'C',  ' ',  ' ',  ' ', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-
-#define UVC_GUID_FORMAT_D3DFMT_L8 \
-       {0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_KSMEDIA_L8_IR \
-       {0x32, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-
-#define UVC_GUID_FORMAT_HEVC \
-       { 'H',  'E',  'V',  'C', 0x00, 0x00, 0x10, 0x00, \
-        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-
-
-/* ------------------------------------------------------------------------
  * Driver specific constants.
  */
 
@@ -283,12 +145,6 @@ struct uvc_control {
        struct uvc_fh *handle;  /* File handle that last changed the control. */
 };
 
-struct uvc_format_desc {
-       char *name;
-       u8 guid[16];
-       u32 fcc;
-};
-
 /*
  * The term 'entity' refers to both UVC units and UVC terminals.
  *
@@ -911,9 +767,6 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
                      struct uvc_xu_control_query *xqry);
 
 /* Utility functions */
-void uvc_simplify_fraction(u32 *numerator, u32 *denominator,
-                          unsigned int n_terms, unsigned int threshold);
-u32 uvc_fraction_to_interval(u32 numerator, u32 denominator);
 struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
                                            u8 epaddr);
 u16 uvc_endpoint_max_bpi(struct usb_device *dev, struct usb_host_endpoint *ep);
index e0fbe6b..40f56e0 100644 (file)
@@ -484,3 +484,89 @@ s64 v4l2_get_link_freq(struct v4l2_ctrl_handler *handler, unsigned int mul,
        return freq > 0 ? freq : -EINVAL;
 }
 EXPORT_SYMBOL_GPL(v4l2_get_link_freq);
+
+/*
+ * Simplify a fraction using a simple continued fraction decomposition. The
+ * idea here is to convert fractions such as 333333/10000000 to 1/30 using
+ * 32 bit arithmetic only. The algorithm is not perfect and relies upon two
+ * arbitrary parameters to remove non-significative terms from the simple
+ * continued fraction decomposition. Using 8 and 333 for n_terms and threshold
+ * respectively seems to give nice results.
+ */
+void v4l2_simplify_fraction(u32 *numerator, u32 *denominator,
+               unsigned int n_terms, unsigned int threshold)
+{
+       u32 *an;
+       u32 x, y, r;
+       unsigned int i, n;
+
+       an = kmalloc_array(n_terms, sizeof(*an), GFP_KERNEL);
+       if (an == NULL)
+               return;
+
+       /*
+        * Convert the fraction to a simple continued fraction. See
+        * https://en.wikipedia.org/wiki/Continued_fraction
+        * Stop if the current term is bigger than or equal to the given
+        * threshold.
+        */
+       x = *numerator;
+       y = *denominator;
+
+       for (n = 0; n < n_terms && y != 0; ++n) {
+               an[n] = x / y;
+               if (an[n] >= threshold) {
+                       if (n < 2)
+                               n++;
+                       break;
+               }
+
+               r = x - an[n] * y;
+               x = y;
+               y = r;
+       }
+
+       /* Expand the simple continued fraction back to an integer fraction. */
+       x = 0;
+       y = 1;
+
+       for (i = n; i > 0; --i) {
+               r = y;
+               y = an[i-1] * y + x;
+               x = r;
+       }
+
+       *numerator = y;
+       *denominator = x;
+       kfree(an);
+}
+EXPORT_SYMBOL_GPL(v4l2_simplify_fraction);
+
+/*
+ * Convert a fraction to a frame interval in 100ns multiples. The idea here is
+ * to compute numerator / denominator * 10000000 using 32 bit fixed point
+ * arithmetic only.
+ */
+u32 v4l2_fraction_to_interval(u32 numerator, u32 denominator)
+{
+       u32 multiplier;
+
+       /* Saturate the result if the operation would overflow. */
+       if (denominator == 0 ||
+           numerator/denominator >= ((u32)-1)/10000000)
+               return (u32)-1;
+
+       /*
+        * Divide both the denominator and the multiplier by two until
+        * numerator * multiplier doesn't overflow. If anyone knows a better
+        * algorithm please let me know.
+        */
+       multiplier = 10000000;
+       while (numerator > ((u32)-1)/multiplier) {
+               multiplier /= 2;
+               denominator /= 2;
+       }
+
+       return denominator ? numerator * multiplier / denominator : 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_fraction_to_interval);
index f1643fb..0996ede 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) 2016-2020, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2016-2022, NVIDIA CORPORATION.  All rights reserved.
  */
 
 #include <linux/delay.h>
@@ -638,7 +638,7 @@ static void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl)
        mutex_unlock(&padctl->lock);
 }
 
-static void tegra_phy_xusb_utmi_pad_power_on(struct phy *phy)
+static void tegra186_utmi_pad_power_on(struct phy *phy)
 {
        struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
        struct tegra_xusb_padctl *padctl = lane->pad->padctl;
@@ -656,6 +656,8 @@ static void tegra_phy_xusb_utmi_pad_power_on(struct phy *phy)
                return;
        }
 
+       dev_dbg(dev, "power on UTMI pad %u\n", index);
+
        tegra186_utmi_bias_pad_power_on(padctl);
 
        udelay(2);
@@ -669,7 +671,7 @@ static void tegra_phy_xusb_utmi_pad_power_on(struct phy *phy)
        padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
 }
 
-static void tegra_phy_xusb_utmi_pad_power_down(struct phy *phy)
+static void tegra186_utmi_pad_power_down(struct phy *phy)
 {
        struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
        struct tegra_xusb_padctl *padctl = lane->pad->padctl;
@@ -679,6 +681,8 @@ static void tegra_phy_xusb_utmi_pad_power_down(struct phy *phy)
        if (!phy)
                return;
 
+       dev_dbg(padctl->dev, "power down UTMI pad %u\n", index);
+
        value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
        value |= USB2_OTG_PD;
        padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
@@ -849,15 +853,14 @@ static int tegra186_utmi_phy_power_on(struct phy *phy)
        value |= RPD_CTRL(priv->calib.rpd_ctrl);
        padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
 
-       /* TODO: pad power saving */
-       tegra_phy_xusb_utmi_pad_power_on(phy);
+       tegra186_utmi_pad_power_on(phy);
+
        return 0;
 }
 
 static int tegra186_utmi_phy_power_off(struct phy *phy)
 {
-       /* TODO: pad power saving */
-       tegra_phy_xusb_utmi_pad_power_down(phy);
+       tegra186_utmi_pad_power_down(phy);
 
        return 0;
 }
@@ -1483,6 +1486,8 @@ static const struct tegra_xusb_padctl_ops tegra186_xusb_padctl_ops = {
        .suspend_noirq = tegra186_xusb_padctl_suspend_noirq,
        .resume_noirq = tegra186_xusb_padctl_resume_noirq,
        .vbus_override = tegra186_xusb_padctl_vbus_override,
+       .utmi_pad_power_on = tegra186_utmi_pad_power_on,
+       .utmi_pad_power_down = tegra186_utmi_pad_power_down,
 };
 
 #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC)
index 82fff4d..9509187 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2014-2020, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2014-2022, NVIDIA CORPORATION.  All rights reserved.
  */
 
 #include <linux/delay.h>
@@ -1459,6 +1459,26 @@ int tegra_phy_xusb_utmi_port_reset(struct phy *phy)
 }
 EXPORT_SYMBOL_GPL(tegra_phy_xusb_utmi_port_reset);
 
+void tegra_phy_xusb_utmi_pad_power_on(struct phy *phy)
+{
+       struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+       struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+
+       if (padctl->soc->ops->utmi_pad_power_on)
+               padctl->soc->ops->utmi_pad_power_on(phy);
+}
+EXPORT_SYMBOL_GPL(tegra_phy_xusb_utmi_pad_power_on);
+
+void tegra_phy_xusb_utmi_pad_power_down(struct phy *phy)
+{
+       struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+       struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+
+       if (padctl->soc->ops->utmi_pad_power_down)
+               padctl->soc->ops->utmi_pad_power_down(phy);
+}
+EXPORT_SYMBOL_GPL(tegra_phy_xusb_utmi_pad_power_down);
+
 int tegra_xusb_padctl_get_usb3_companion(struct tegra_xusb_padctl *padctl,
                                    unsigned int port)
 {
index 034f7a2..8cfbbdb 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2014-2020, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2014-2022, NVIDIA CORPORATION.  All rights reserved.
  * Copyright (c) 2015, Google Inc.
  */
 
@@ -412,6 +412,8 @@ struct tegra_xusb_padctl_ops {
                                    unsigned int index, bool enable);
        int (*vbus_override)(struct tegra_xusb_padctl *padctl, bool set);
        int (*utmi_port_reset)(struct phy *phy);
+       void (*utmi_pad_power_on)(struct phy *phy);
+       void (*utmi_pad_power_down)(struct phy *phy);
 };
 
 struct tegra_xusb_padctl_soc {
index f12d0a3..448fd2e 100644 (file)
@@ -27,6 +27,16 @@ config USB4_DEBUGFS_WRITE
          Only enable this if you know what you are doing! Never enable
          this for production systems or distro kernels.
 
+config USB4_DEBUGFS_MARGINING
+       bool "Expose receiver lane margining operations under USB4 ports (DANGEROUS)"
+       depends on DEBUG_FS
+       depends on USB4_DEBUGFS_WRITE
+       help
+         Enables hardware and software based receiver lane margining support
+         under each USB4 port. Used for electrical quality and robustness
+         validation during manufacturing. Should not be enabled by distro
+         kernels.
+
 config USB4_KUNIT_TEST
        bool "KUnit tests" if !KUNIT_ALL_TESTS
        depends on USB4 && KUNIT=y
index c850b0a..834bcad 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/uaccess.h>
 
 #include "tb.h"
+#include "sb_regs.h"
 
 #define PORT_CAP_PCIE_LEN      1
 #define PORT_CAP_POWER_LEN     2
@@ -187,6 +188,828 @@ static ssize_t switch_regs_write(struct file *file, const char __user *user_buf,
 #define DEBUGFS_MODE           0400
 #endif
 
+#if IS_ENABLED(CONFIG_USB4_DEBUGFS_MARGINING)
+/**
+ * struct tb_margining - Lane margining support
+ * @caps: Port lane margining capabilities
+ * @results: Last lane margining results
+ * @lanes: %0, %1 or %7 (all)
+ * @min_ber_level: Minimum supported BER level contour value
+ * @max_ber_level: Maximum supported BER level contour value
+ * @ber_level: Current BER level contour value
+ * @voltage_steps: Number of mandatory voltage steps
+ * @max_voltage_offset: Maximum mandatory voltage offset (in mV)
+ * @time_steps: Number of time margin steps
+ * @max_time_offset: Maximum time margin offset (in mUI)
+ * @software: %true if software margining is used instead of hardware
+ * @time: %true if time margining is used instead of voltage
+ * @right_high: %false if left/low margin test is performed, %true if
+ *             right/high
+ */
+struct tb_margining {
+       u32 caps[2];
+       u32 results[2];
+       unsigned int lanes;
+       unsigned int min_ber_level;
+       unsigned int max_ber_level;
+       unsigned int ber_level;
+       unsigned int voltage_steps;
+       unsigned int max_voltage_offset;
+       unsigned int time_steps;
+       unsigned int max_time_offset;
+       bool software;
+       bool time;
+       bool right_high;
+};
+
+static bool supports_software(const struct usb4_port *usb4)
+{
+       return usb4->margining->caps[0] & USB4_MARGIN_CAP_0_MODES_SW;
+}
+
+static bool supports_hardware(const struct usb4_port *usb4)
+{
+       return usb4->margining->caps[0] & USB4_MARGIN_CAP_0_MODES_HW;
+}
+
+static bool both_lanes(const struct usb4_port *usb4)
+{
+       return usb4->margining->caps[0] & USB4_MARGIN_CAP_0_2_LANES;
+}
+
+static unsigned int independent_voltage_margins(const struct usb4_port *usb4)
+{
+       return (usb4->margining->caps[0] & USB4_MARGIN_CAP_0_VOLTAGE_INDP_MASK) >>
+               USB4_MARGIN_CAP_0_VOLTAGE_INDP_SHIFT;
+}
+
+static bool supports_time(const struct usb4_port *usb4)
+{
+       return usb4->margining->caps[0] & USB4_MARGIN_CAP_0_TIME;
+}
+
+/* Only applicable if supports_time() returns true */
+static unsigned int independent_time_margins(const struct usb4_port *usb4)
+{
+       return (usb4->margining->caps[1] & USB4_MARGIN_CAP_1_TIME_INDP_MASK) >>
+               USB4_MARGIN_CAP_1_TIME_INDP_SHIFT;
+}
+
+static ssize_t
+margining_ber_level_write(struct file *file, const char __user *user_buf,
+                          size_t count, loff_t *ppos)
+{
+       struct seq_file *s = file->private_data;
+       struct tb_port *port = s->private;
+       struct usb4_port *usb4 = port->usb4;
+       struct tb *tb = port->sw->tb;
+       unsigned int val;
+       int ret = 0;
+       char *buf;
+
+       if (mutex_lock_interruptible(&tb->lock))
+               return -ERESTARTSYS;
+
+       if (usb4->margining->software) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       buf = validate_and_copy_from_user(user_buf, &count);
+       if (IS_ERR(buf)) {
+               ret = PTR_ERR(buf);
+               goto out_unlock;
+       }
+
+       buf[count - 1] = '\0';
+
+       ret = kstrtouint(buf, 10, &val);
+       if (ret)
+               goto out_free;
+
+       if (val < usb4->margining->min_ber_level ||
+           val > usb4->margining->max_ber_level) {
+               ret = -EINVAL;
+               goto out_free;
+       }
+
+       usb4->margining->ber_level = val;
+
+out_free:
+       free_page((unsigned long)buf);
+out_unlock:
+       mutex_unlock(&tb->lock);
+
+       return ret < 0 ? ret : count;
+}
+
+static void ber_level_show(struct seq_file *s, unsigned int val)
+{
+       if (val % 2)
+               seq_printf(s, "3 * 1e%d (%u)\n", -12 + (val + 1) / 2, val);
+       else
+               seq_printf(s, "1e%d (%u)\n", -12 + val / 2, val);
+}
+
+static int margining_ber_level_show(struct seq_file *s, void *not_used)
+{
+       struct tb_port *port = s->private;
+       struct usb4_port *usb4 = port->usb4;
+
+       if (usb4->margining->software)
+               return -EINVAL;
+       ber_level_show(s, usb4->margining->ber_level);
+       return 0;
+}
+DEBUGFS_ATTR_RW(margining_ber_level);
+
+static int margining_caps_show(struct seq_file *s, void *not_used)
+{
+       struct tb_port *port = s->private;
+       struct usb4_port *usb4 = port->usb4;
+       struct tb *tb = port->sw->tb;
+       u32 cap0, cap1;
+
+       if (mutex_lock_interruptible(&tb->lock))
+               return -ERESTARTSYS;
+
+       /* Dump the raw caps first */
+       cap0 = usb4->margining->caps[0];
+       seq_printf(s, "0x%08x\n", cap0);
+       cap1 = usb4->margining->caps[1];
+       seq_printf(s, "0x%08x\n", cap1);
+
+       seq_printf(s, "# software margining: %s\n",
+                  supports_software(usb4) ? "yes" : "no");
+       if (supports_hardware(usb4)) {
+               seq_puts(s, "# hardware margining: yes\n");
+               seq_puts(s, "# minimum BER level contour: ");
+               ber_level_show(s, usb4->margining->min_ber_level);
+               seq_puts(s, "# maximum BER level contour: ");
+               ber_level_show(s, usb4->margining->max_ber_level);
+       } else {
+               seq_puts(s, "# hardware margining: no\n");
+       }
+
+       seq_printf(s, "# both lanes simultaneously: %s\n",
+                 both_lanes(usb4) ? "yes" : "no");
+       seq_printf(s, "# voltage margin steps: %u\n",
+                  usb4->margining->voltage_steps);
+       seq_printf(s, "# maximum voltage offset: %u mV\n",
+                  usb4->margining->max_voltage_offset);
+
+       switch (independent_voltage_margins(usb4)) {
+       case USB4_MARGIN_CAP_0_VOLTAGE_MIN:
+               seq_puts(s, "# returns minimum between high and low voltage margins\n");
+               break;
+       case USB4_MARGIN_CAP_0_VOLTAGE_HL:
+               seq_puts(s, "# returns high or low voltage margin\n");
+               break;
+       case USB4_MARGIN_CAP_0_VOLTAGE_BOTH:
+               seq_puts(s, "# returns both high and low margins\n");
+               break;
+       }
+
+       if (supports_time(usb4)) {
+               seq_puts(s, "# time margining: yes\n");
+               seq_printf(s, "# time margining is destructive: %s\n",
+                          cap1 & USB4_MARGIN_CAP_1_TIME_DESTR ? "yes" : "no");
+
+               switch (independent_time_margins(usb4)) {
+               case USB4_MARGIN_CAP_1_TIME_MIN:
+                       seq_puts(s, "# returns minimum between left and right time margins\n");
+                       break;
+               case USB4_MARGIN_CAP_1_TIME_LR:
+                       seq_puts(s, "# returns left or right margin\n");
+                       break;
+               case USB4_MARGIN_CAP_1_TIME_BOTH:
+                       seq_puts(s, "# returns both left and right margins\n");
+                       break;
+               }
+
+               seq_printf(s, "# time margin steps: %u\n",
+                          usb4->margining->time_steps);
+               seq_printf(s, "# maximum time offset: %u mUI\n",
+                          usb4->margining->max_time_offset);
+       } else {
+               seq_puts(s, "# time margining: no\n");
+       }
+
+       mutex_unlock(&tb->lock);
+       return 0;
+}
+DEBUGFS_ATTR_RO(margining_caps);
+
+static ssize_t
+margining_lanes_write(struct file *file, const char __user *user_buf,
+                     size_t count, loff_t *ppos)
+{
+       struct seq_file *s = file->private_data;
+       struct tb_port *port = s->private;
+       struct usb4_port *usb4 = port->usb4;
+       struct tb *tb = port->sw->tb;
+       int ret = 0;
+       char *buf;
+
+       buf = validate_and_copy_from_user(user_buf, &count);
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
+
+       buf[count - 1] = '\0';
+
+       if (mutex_lock_interruptible(&tb->lock)) {
+               ret = -ERESTARTSYS;
+               goto out_free;
+       }
+
+       if (!strcmp(buf, "0")) {
+               usb4->margining->lanes = 0;
+       } else if (!strcmp(buf, "1")) {
+               usb4->margining->lanes = 1;
+       } else if (!strcmp(buf, "all")) {
+               /* Needs to be supported */
+               if (both_lanes(usb4))
+                       usb4->margining->lanes = 7;
+               else
+                       ret = -EINVAL;
+       } else {
+               ret = -EINVAL;
+       }
+
+       mutex_unlock(&tb->lock);
+
+out_free:
+       free_page((unsigned long)buf);
+       return ret < 0 ? ret : count;
+}
+
+static int margining_lanes_show(struct seq_file *s, void *not_used)
+{
+       struct tb_port *port = s->private;
+       struct usb4_port *usb4 = port->usb4;
+       struct tb *tb = port->sw->tb;
+       unsigned int lanes;
+
+       if (mutex_lock_interruptible(&tb->lock))
+               return -ERESTARTSYS;
+
+       lanes = usb4->margining->lanes;
+       if (both_lanes(usb4)) {
+               if (!lanes)
+                       seq_puts(s, "[0] 1 all\n");
+               else if (lanes == 1)
+                       seq_puts(s, "0 [1] all\n");
+               else
+                       seq_puts(s, "0 1 [all]\n");
+       } else {
+               if (!lanes)
+                       seq_puts(s, "[0] 1\n");
+               else
+                       seq_puts(s, "0 [1]\n");
+       }
+
+       mutex_unlock(&tb->lock);
+       return 0;
+}
+DEBUGFS_ATTR_RW(margining_lanes);
+
+static ssize_t margining_mode_write(struct file *file,
+                                  const char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct seq_file *s = file->private_data;
+       struct tb_port *port = s->private;
+       struct usb4_port *usb4 = port->usb4;
+       struct tb *tb = port->sw->tb;
+       int ret = 0;
+       char *buf;
+
+       buf = validate_and_copy_from_user(user_buf, &count);
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
+
+       buf[count - 1] = '\0';
+
+       if (mutex_lock_interruptible(&tb->lock)) {
+               ret = -ERESTARTSYS;
+               goto out_free;
+       }
+
+       if (!strcmp(buf, "software")) {
+               if (supports_software(usb4))
+                       usb4->margining->software = true;
+               else
+                       ret = -EINVAL;
+       } else if (!strcmp(buf, "hardware")) {
+               if (supports_hardware(usb4))
+                       usb4->margining->software = false;
+               else
+                       ret = -EINVAL;
+       } else {
+               ret = -EINVAL;
+       }
+
+       mutex_unlock(&tb->lock);
+
+out_free:
+       free_page((unsigned long)buf);
+       return ret ? ret : count;
+}
+
+static int margining_mode_show(struct seq_file *s, void *not_used)
+{
+       const struct tb_port *port = s->private;
+       const struct usb4_port *usb4 = port->usb4;
+       struct tb *tb = port->sw->tb;
+       const char *space = "";
+
+       if (mutex_lock_interruptible(&tb->lock))
+               return -ERESTARTSYS;
+
+       if (supports_software(usb4)) {
+               if (usb4->margining->software)
+                       seq_puts(s, "[software]");
+               else
+                       seq_puts(s, "software");
+               space = " ";
+       }
+       if (supports_hardware(usb4)) {
+               if (usb4->margining->software)
+                       seq_printf(s, "%shardware", space);
+               else
+                       seq_printf(s, "%s[hardware]", space);
+       }
+
+       mutex_unlock(&tb->lock);
+
+       seq_puts(s, "\n");
+       return 0;
+}
+DEBUGFS_ATTR_RW(margining_mode);
+
+static int margining_run_write(void *data, u64 val)
+{
+       struct tb_port *port = data;
+       struct usb4_port *usb4 = port->usb4;
+       struct tb_switch *sw = port->sw;
+       struct tb_margining *margining;
+       struct tb *tb = sw->tb;
+       int ret;
+
+       if (val != 1)
+               return -EINVAL;
+
+       pm_runtime_get_sync(&sw->dev);
+
+       if (mutex_lock_interruptible(&tb->lock)) {
+               ret = -ERESTARTSYS;
+               goto out_rpm_put;
+       }
+
+       /*
+        * CL states may interfere with lane margining so inform the user know
+        * and bail out.
+        */
+       if (tb_port_is_clx_enabled(port, TB_CL1 | TB_CL2)) {
+               tb_port_warn(port,
+                            "CL states are enabled, Disable them with clx=0 and re-connect\n");
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       margining = usb4->margining;
+
+       if (margining->software) {
+               tb_port_dbg(port, "running software %s lane margining for lanes %u\n",
+                           margining->time ? "time" : "voltage", margining->lanes);
+               ret = usb4_port_sw_margin(port, margining->lanes, margining->time,
+                                         margining->right_high,
+                                         USB4_MARGIN_SW_COUNTER_CLEAR);
+               if (ret)
+                       goto out_unlock;
+
+               ret = usb4_port_sw_margin_errors(port, &margining->results[0]);
+       } else {
+               tb_port_dbg(port, "running hardware %s lane margining for lanes %u\n",
+                           margining->time ? "time" : "voltage", margining->lanes);
+               /* Clear the results */
+               margining->results[0] = 0;
+               margining->results[1] = 0;
+               ret = usb4_port_hw_margin(port, margining->lanes,
+                                         margining->ber_level, margining->time,
+                                         margining->right_high, margining->results);
+       }
+
+out_unlock:
+       mutex_unlock(&tb->lock);
+out_rpm_put:
+       pm_runtime_mark_last_busy(&sw->dev);
+       pm_runtime_put_autosuspend(&sw->dev);
+
+       return ret;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(margining_run_fops, NULL, margining_run_write,
+                        "%llu\n");
+
+static ssize_t margining_results_write(struct file *file,
+                                      const char __user *user_buf,
+                                      size_t count, loff_t *ppos)
+{
+       struct seq_file *s = file->private_data;
+       struct tb_port *port = s->private;
+       struct usb4_port *usb4 = port->usb4;
+       struct tb *tb = port->sw->tb;
+
+       if (mutex_lock_interruptible(&tb->lock))
+               return -ERESTARTSYS;
+
+       /* Just clear the results */
+       usb4->margining->results[0] = 0;
+       usb4->margining->results[1] = 0;
+
+       mutex_unlock(&tb->lock);
+       return count;
+}
+
+static void voltage_margin_show(struct seq_file *s,
+                               const struct tb_margining *margining, u8 val)
+{
+       unsigned int tmp, voltage;
+
+       tmp = val & USB4_MARGIN_HW_RES_1_MARGIN_MASK;
+       voltage = tmp * margining->max_voltage_offset / margining->voltage_steps;
+       seq_printf(s, "%u mV (%u)", voltage, tmp);
+       if (val & USB4_MARGIN_HW_RES_1_EXCEEDS)
+               seq_puts(s, " exceeds maximum");
+       seq_puts(s, "\n");
+}
+
+static void time_margin_show(struct seq_file *s,
+                            const struct tb_margining *margining, u8 val)
+{
+       unsigned int tmp, interval;
+
+       tmp = val & USB4_MARGIN_HW_RES_1_MARGIN_MASK;
+       interval = tmp * margining->max_time_offset / margining->time_steps;
+       seq_printf(s, "%u mUI (%u)", interval, tmp);
+       if (val & USB4_MARGIN_HW_RES_1_EXCEEDS)
+               seq_puts(s, " exceeds maximum");
+       seq_puts(s, "\n");
+}
+
+static int margining_results_show(struct seq_file *s, void *not_used)
+{
+       struct tb_port *port = s->private;
+       struct usb4_port *usb4 = port->usb4;
+       struct tb_margining *margining;
+       struct tb *tb = port->sw->tb;
+
+       if (mutex_lock_interruptible(&tb->lock))
+               return -ERESTARTSYS;
+
+       margining = usb4->margining;
+       /* Dump the raw results first */
+       seq_printf(s, "0x%08x\n", margining->results[0]);
+       /* Only the hardware margining has two result dwords */
+       if (!margining->software) {
+               unsigned int val;
+
+               seq_printf(s, "0x%08x\n", margining->results[1]);
+
+               if (margining->time) {
+                       if (!margining->lanes || margining->lanes == 7) {
+                               val = margining->results[1];
+                               seq_puts(s, "# lane 0 right time margin: ");
+                               time_margin_show(s, margining, val);
+                               val = margining->results[1] >>
+                                       USB4_MARGIN_HW_RES_1_L0_LL_MARGIN_SHIFT;
+                               seq_puts(s, "# lane 0 left time margin: ");
+                               time_margin_show(s, margining, val);
+                       }
+                       if (margining->lanes == 1 || margining->lanes == 7) {
+                               val = margining->results[1] >>
+                                       USB4_MARGIN_HW_RES_1_L1_RH_MARGIN_SHIFT;
+                               seq_puts(s, "# lane 1 right time margin: ");
+                               time_margin_show(s, margining, val);
+                               val = margining->results[1] >>
+                                       USB4_MARGIN_HW_RES_1_L1_LL_MARGIN_SHIFT;
+                               seq_puts(s, "# lane 1 left time margin: ");
+                               time_margin_show(s, margining, val);
+                       }
+               } else {
+                       if (!margining->lanes || margining->lanes == 7) {
+                               val = margining->results[1];
+                               seq_puts(s, "# lane 0 high voltage margin: ");
+                               voltage_margin_show(s, margining, val);
+                               val = margining->results[1] >>
+                                       USB4_MARGIN_HW_RES_1_L0_LL_MARGIN_SHIFT;
+                               seq_puts(s, "# lane 0 low voltage margin: ");
+                               voltage_margin_show(s, margining, val);
+                       }
+                       if (margining->lanes == 1 || margining->lanes == 7) {
+                               val = margining->results[1] >>
+                                       USB4_MARGIN_HW_RES_1_L1_RH_MARGIN_SHIFT;
+                               seq_puts(s, "# lane 1 high voltage margin: ");
+                               voltage_margin_show(s, margining, val);
+                               val = margining->results[1] >>
+                                       USB4_MARGIN_HW_RES_1_L1_LL_MARGIN_SHIFT;
+                               seq_puts(s, "# lane 1 low voltage margin: ");
+                               voltage_margin_show(s, margining, val);
+                       }
+               }
+       }
+
+       mutex_unlock(&tb->lock);
+       return 0;
+}
+DEBUGFS_ATTR_RW(margining_results);
+
+static ssize_t margining_test_write(struct file *file,
+                                   const char __user *user_buf,
+                                   size_t count, loff_t *ppos)
+{
+       struct seq_file *s = file->private_data;
+       struct tb_port *port = s->private;
+       struct usb4_port *usb4 = port->usb4;
+       struct tb *tb = port->sw->tb;
+       int ret = 0;
+       char *buf;
+
+       buf = validate_and_copy_from_user(user_buf, &count);
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
+
+       buf[count - 1] = '\0';
+
+       if (mutex_lock_interruptible(&tb->lock)) {
+               ret = -ERESTARTSYS;
+               goto out_free;
+       }
+
+       if (!strcmp(buf, "time") && supports_time(usb4))
+               usb4->margining->time = true;
+       else if (!strcmp(buf, "voltage"))
+               usb4->margining->time = false;
+       else
+               ret = -EINVAL;
+
+       mutex_unlock(&tb->lock);
+
+out_free:
+       free_page((unsigned long)buf);
+       return ret ? ret : count;
+}
+
+static int margining_test_show(struct seq_file *s, void *not_used)
+{
+       struct tb_port *port = s->private;
+       struct usb4_port *usb4 = port->usb4;
+       struct tb *tb = port->sw->tb;
+
+       if (mutex_lock_interruptible(&tb->lock))
+               return -ERESTARTSYS;
+
+       if (supports_time(usb4)) {
+               if (usb4->margining->time)
+                       seq_puts(s, "voltage [time]\n");
+               else
+                       seq_puts(s, "[voltage] time\n");
+       } else {
+               seq_puts(s, "[voltage]\n");
+       }
+
+       mutex_unlock(&tb->lock);
+       return 0;
+}
+DEBUGFS_ATTR_RW(margining_test);
+
+static ssize_t margining_margin_write(struct file *file,
+                                   const char __user *user_buf,
+                                   size_t count, loff_t *ppos)
+{
+       struct seq_file *s = file->private_data;
+       struct tb_port *port = s->private;
+       struct usb4_port *usb4 = port->usb4;
+       struct tb *tb = port->sw->tb;
+       int ret = 0;
+       char *buf;
+
+       buf = validate_and_copy_from_user(user_buf, &count);
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
+
+       buf[count - 1] = '\0';
+
+       if (mutex_lock_interruptible(&tb->lock)) {
+               ret = -ERESTARTSYS;
+               goto out_free;
+       }
+
+       if (usb4->margining->time) {
+               if (!strcmp(buf, "left"))
+                       usb4->margining->right_high = false;
+               else if (!strcmp(buf, "right"))
+                       usb4->margining->right_high = true;
+               else
+                       ret = -EINVAL;
+       } else {
+               if (!strcmp(buf, "low"))
+                       usb4->margining->right_high = false;
+               else if (!strcmp(buf, "high"))
+                       usb4->margining->right_high = true;
+               else
+                       ret = -EINVAL;
+       }
+
+       mutex_unlock(&tb->lock);
+
+out_free:
+       free_page((unsigned long)buf);
+       return ret ? ret : count;
+}
+
+static int margining_margin_show(struct seq_file *s, void *not_used)
+{
+       struct tb_port *port = s->private;
+       struct usb4_port *usb4 = port->usb4;
+       struct tb *tb = port->sw->tb;
+
+       if (mutex_lock_interruptible(&tb->lock))
+               return -ERESTARTSYS;
+
+       if (usb4->margining->time) {
+               if (usb4->margining->right_high)
+                       seq_puts(s, "left [right]\n");
+               else
+                       seq_puts(s, "[left] right\n");
+       } else {
+               if (usb4->margining->right_high)
+                       seq_puts(s, "low [high]\n");
+               else
+                       seq_puts(s, "[low] high\n");
+       }
+
+       mutex_unlock(&tb->lock);
+       return 0;
+}
+DEBUGFS_ATTR_RW(margining_margin);
+
+static void margining_port_init(struct tb_port *port)
+{
+       struct tb_margining *margining;
+       struct dentry *dir, *parent;
+       struct usb4_port *usb4;
+       char dir_name[10];
+       unsigned int val;
+       int ret;
+
+       usb4 = port->usb4;
+       if (!usb4)
+               return;
+
+       snprintf(dir_name, sizeof(dir_name), "port%d", port->port);
+       parent = debugfs_lookup(dir_name, port->sw->debugfs_dir);
+
+       margining = kzalloc(sizeof(*margining), GFP_KERNEL);
+       if (!margining)
+               return;
+
+       ret = usb4_port_margining_caps(port, margining->caps);
+       if (ret) {
+               kfree(margining);
+               return;
+       }
+
+       usb4->margining = margining;
+
+       /* Set the initial mode */
+       if (supports_software(usb4))
+               margining->software = true;
+
+       val = (margining->caps[0] & USB4_MARGIN_CAP_0_VOLTAGE_STEPS_MASK) >>
+               USB4_MARGIN_CAP_0_VOLTAGE_STEPS_SHIFT;
+       margining->voltage_steps = val;
+       val = (margining->caps[0] & USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_MASK) >>
+               USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_SHIFT;
+       margining->max_voltage_offset = 74 + val * 2;
+
+       if (supports_time(usb4)) {
+               val = (margining->caps[1] & USB4_MARGIN_CAP_1_TIME_STEPS_MASK) >>
+                       USB4_MARGIN_CAP_1_TIME_STEPS_SHIFT;
+               margining->time_steps = val;
+               val = (margining->caps[1] & USB4_MARGIN_CAP_1_TIME_OFFSET_MASK) >>
+                       USB4_MARGIN_CAP_1_TIME_OFFSET_SHIFT;
+               /*
+                * Store it as mUI (milli Unit Interval) because we want
+                * to keep it as integer.
+                */
+               margining->max_time_offset = 200 + 10 * val;
+       }
+
+       dir = debugfs_create_dir("margining", parent);
+       if (supports_hardware(usb4)) {
+               val = (margining->caps[1] & USB4_MARGIN_CAP_1_MIN_BER_MASK) >>
+                       USB4_MARGIN_CAP_1_MIN_BER_SHIFT;
+               margining->min_ber_level = val;
+               val = (margining->caps[1] & USB4_MARGIN_CAP_1_MAX_BER_MASK) >>
+                       USB4_MARGIN_CAP_1_MAX_BER_SHIFT;
+               margining->max_ber_level = val;
+
+               /* Set the default to minimum */
+               margining->ber_level = margining->min_ber_level;
+
+               debugfs_create_file("ber_level_contour", 0400, dir, port,
+                                   &margining_ber_level_fops);
+       }
+       debugfs_create_file("caps", 0400, dir, port, &margining_caps_fops);
+       debugfs_create_file("lanes", 0600, dir, port, &margining_lanes_fops);
+       debugfs_create_file("mode", 0600, dir, port, &margining_mode_fops);
+       debugfs_create_file("run", 0600, dir, port, &margining_run_fops);
+       debugfs_create_file("results", 0600, dir, port, &margining_results_fops);
+       debugfs_create_file("test", 0600, dir, port, &margining_test_fops);
+       if (independent_voltage_margins(usb4) ||
+           (supports_time(usb4) && independent_time_margins(usb4)))
+               debugfs_create_file("margin", 0600, dir, port, &margining_margin_fops);
+}
+
+static void margining_port_remove(struct tb_port *port)
+{
+       struct dentry *parent;
+       char dir_name[10];
+
+       if (!port->usb4)
+               return;
+
+       snprintf(dir_name, sizeof(dir_name), "port%d", port->port);
+       parent = debugfs_lookup(dir_name, port->sw->debugfs_dir);
+       debugfs_remove_recursive(debugfs_lookup("margining", parent));
+
+       kfree(port->usb4->margining);
+       port->usb4->margining = NULL;
+}
+
+static void margining_switch_init(struct tb_switch *sw)
+{
+       struct tb_port *upstream, *downstream;
+       struct tb_switch *parent_sw;
+       u64 route = tb_route(sw);
+
+       if (!route)
+               return;
+
+       upstream = tb_upstream_port(sw);
+       parent_sw = tb_switch_parent(sw);
+       downstream = tb_port_at(route, parent_sw);
+
+       margining_port_init(downstream);
+       margining_port_init(upstream);
+}
+
+static void margining_switch_remove(struct tb_switch *sw)
+{
+       struct tb_switch *parent_sw;
+       struct tb_port *downstream;
+       u64 route = tb_route(sw);
+
+       if (!route)
+               return;
+
+       /*
+        * Upstream is removed with the router itself but we need to
+        * remove the downstream port margining directory.
+        */
+       parent_sw = tb_switch_parent(sw);
+       downstream = tb_port_at(route, parent_sw);
+       margining_port_remove(downstream);
+}
+
+static void margining_xdomain_init(struct tb_xdomain *xd)
+{
+       struct tb_switch *parent_sw;
+       struct tb_port *downstream;
+
+       parent_sw = tb_xdomain_parent(xd);
+       downstream = tb_port_at(xd->route, parent_sw);
+
+       margining_port_init(downstream);
+}
+
+static void margining_xdomain_remove(struct tb_xdomain *xd)
+{
+       struct tb_switch *parent_sw;
+       struct tb_port *downstream;
+
+       parent_sw = tb_xdomain_parent(xd);
+       downstream = tb_port_at(xd->route, parent_sw);
+       margining_port_remove(downstream);
+}
+#else
+static inline void margining_switch_init(struct tb_switch *sw) { }
+static inline void margining_switch_remove(struct tb_switch *sw) { }
+static inline void margining_xdomain_init(struct tb_xdomain *xd) { }
+static inline void margining_xdomain_remove(struct tb_xdomain *xd) { }
+#endif
+
 static int port_clear_all_counters(struct tb_port *port)
 {
        u32 *buf;
@@ -689,6 +1512,8 @@ void tb_switch_debugfs_init(struct tb_switch *sw)
                        debugfs_create_file("counters", 0600, debugfs_dir, port,
                                            &counters_fops);
        }
+
+       margining_switch_init(sw);
 }
 
 /**
@@ -699,9 +1524,20 @@ void tb_switch_debugfs_init(struct tb_switch *sw)
  */
 void tb_switch_debugfs_remove(struct tb_switch *sw)
 {
+       margining_switch_remove(sw);
        debugfs_remove_recursive(sw->debugfs_dir);
 }
 
+void tb_xdomain_debugfs_init(struct tb_xdomain *xd)
+{
+       margining_xdomain_init(xd);
+}
+
+void tb_xdomain_debugfs_remove(struct tb_xdomain *xd)
+{
+       margining_xdomain_remove(xd);
+}
+
 /**
  * tb_service_debugfs_init() - Add debugfs directory for service
  * @svc: Thunderbolt service pointer
index 99211f3..ec7b5f6 100644 (file)
@@ -144,11 +144,9 @@ static ssize_t boot_acl_show(struct device *dev, struct device_attribute *attr,
 
        for (ret = 0, i = 0; i < tb->nboot_acl; i++) {
                if (!uuid_is_null(&uuids[i]))
-                       ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%pUb",
-                                       &uuids[i]);
+                       ret += sysfs_emit_at(buf, ret, "%pUb", &uuids[i]);
 
-               ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s",
-                              i < tb->nboot_acl - 1 ? "," : "\n");
+               ret += sysfs_emit_at(buf, ret, "%s", i < tb->nboot_acl - 1 ? "," : "\n");
        }
 
 out:
@@ -247,7 +245,7 @@ static ssize_t deauthorization_show(struct device *dev,
            tb->security_level == TB_SECURITY_SECURE)
                deauthorization = !!tb->cm_ops->disapprove_switch;
 
-       return sprintf(buf, "%d\n", deauthorization);
+       return sysfs_emit(buf, "%d\n", deauthorization);
 }
 static DEVICE_ATTR_RO(deauthorization);
 
@@ -270,7 +268,7 @@ static ssize_t security_show(struct device *dev, struct device_attribute *attr,
        if (tb->security_level < ARRAY_SIZE(tb_security_names))
                name = tb_security_names[tb->security_level];
 
-       return sprintf(buf, "%s\n", name);
+       return sysfs_emit(buf, "%s\n", name);
 }
 static DEVICE_ATTR_RO(security);
 
index 572b589..86521eb 100644 (file)
@@ -2518,6 +2518,9 @@ struct tb *icm_probe(struct tb_nhi *nhi)
        case PCI_DEVICE_ID_INTEL_ADL_NHI1:
        case PCI_DEVICE_ID_INTEL_RPL_NHI0:
        case PCI_DEVICE_ID_INTEL_RPL_NHI1:
+       case PCI_DEVICE_ID_INTEL_MTL_M_NHI0:
+       case PCI_DEVICE_ID_INTEL_MTL_P_NHI0:
+       case PCI_DEVICE_ID_INTEL_MTL_P_NHI1:
                icm->is_supported = icm_tgl_is_supported;
                icm->driver_ready = icm_icl_driver_ready;
                icm->set_uuid = icm_icl_set_uuid;
index b5cd967..4dce2ed 100644 (file)
@@ -1184,6 +1184,7 @@ static void nhi_check_iommu(struct tb_nhi *nhi)
 static int nhi_init_msi(struct tb_nhi *nhi)
 {
        struct pci_dev *pdev = nhi->pdev;
+       struct device *dev = &pdev->dev;
        int res, irq, nvec;
 
        /* In case someone left them on. */
@@ -1214,10 +1215,8 @@ static int nhi_init_msi(struct tb_nhi *nhi)
 
                res = devm_request_irq(&pdev->dev, irq, nhi_msi,
                                       IRQF_NO_SUSPEND, "thunderbolt", nhi);
-               if (res) {
-                       dev_err(&pdev->dev, "request_irq failed, aborting\n");
-                       return res;
-               }
+               if (res)
+                       return dev_err_probe(dev, res, "request_irq failed, aborting\n");
        }
 
        return 0;
@@ -1258,26 +1257,21 @@ static struct tb *nhi_select_cm(struct tb_nhi *nhi)
 
 static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
+       struct device *dev = &pdev->dev;
        struct tb_nhi *nhi;
        struct tb *tb;
        int res;
 
-       if (!nhi_imr_valid(pdev)) {
-               dev_warn(&pdev->dev, "firmware image not valid, aborting\n");
-               return -ENODEV;
-       }
+       if (!nhi_imr_valid(pdev))
+               return dev_err_probe(dev, -ENODEV, "firmware image not valid, aborting\n");
 
        res = pcim_enable_device(pdev);
-       if (res) {
-               dev_err(&pdev->dev, "cannot enable PCI device, aborting\n");
-               return res;
-       }
+       if (res)
+               return dev_err_probe(dev, res, "cannot enable PCI device, aborting\n");
 
        res = pcim_iomap_regions(pdev, 1 << 0, "thunderbolt");
-       if (res) {
-               dev_err(&pdev->dev, "cannot obtain PCI resources, aborting\n");
-               return res;
-       }
+       if (res)
+               return dev_err_probe(dev, res, "cannot obtain PCI resources, aborting\n");
 
        nhi = devm_kzalloc(&pdev->dev, sizeof(*nhi), GFP_KERNEL);
        if (!nhi)
@@ -1288,7 +1282,7 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        /* cannot fail - table is allocated in pcim_iomap_regions */
        nhi->iobase = pcim_iomap_table(pdev)[0];
        nhi->hop_count = ioread32(nhi->iobase + REG_HOP_COUNT) & 0x3ff;
-       dev_dbg(&pdev->dev, "total paths: %d\n", nhi->hop_count);
+       dev_dbg(dev, "total paths: %d\n", nhi->hop_count);
 
        nhi->tx_rings = devm_kcalloc(&pdev->dev, nhi->hop_count,
                                     sizeof(*nhi->tx_rings), GFP_KERNEL);
@@ -1301,18 +1295,14 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        nhi_check_iommu(nhi);
 
        res = nhi_init_msi(nhi);
-       if (res) {
-               dev_err(&pdev->dev, "cannot enable MSI, aborting\n");
-               return res;
-       }
+       if (res)
+               return dev_err_probe(dev, res, "cannot enable MSI, aborting\n");
 
        spin_lock_init(&nhi->lock);
 
        res = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
-       if (res) {
-               dev_err(&pdev->dev, "failed to set DMA mask\n");
-               return res;
-       }
+       if (res)
+               return dev_err_probe(dev, res, "failed to set DMA mask\n");
 
        pci_set_master(pdev);
 
@@ -1323,13 +1313,11 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        }
 
        tb = nhi_select_cm(nhi);
-       if (!tb) {
-               dev_err(&nhi->pdev->dev,
+       if (!tb)
+               return dev_err_probe(dev, -ENODEV,
                        "failed to determine connection manager, aborting\n");
-               return -ENODEV;
-       }
 
-       dev_dbg(&nhi->pdev->dev, "NHI initialized, starting thunderbolt\n");
+       dev_dbg(dev, "NHI initialized, starting thunderbolt\n");
 
        res = tb_domain_add(tb);
        if (res) {
@@ -1433,6 +1421,7 @@ static struct pci_device_id nhi_ids[] = {
          .driver_data = (kernel_ulong_t)&icl_nhi_ops },
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICL_NHI1),
          .driver_data = (kernel_ulong_t)&icl_nhi_ops },
+       /* Thunderbolt 4 */
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGL_NHI0),
          .driver_data = (kernel_ulong_t)&icl_nhi_ops },
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGL_NHI1),
@@ -1449,6 +1438,12 @@ static struct pci_device_id nhi_ids[] = {
          .driver_data = (kernel_ulong_t)&icl_nhi_ops },
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPL_NHI1),
          .driver_data = (kernel_ulong_t)&icl_nhi_ops },
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL_M_NHI0),
+         .driver_data = (kernel_ulong_t)&icl_nhi_ops },
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL_P_NHI0),
+         .driver_data = (kernel_ulong_t)&icl_nhi_ops },
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL_P_NHI1),
+         .driver_data = (kernel_ulong_t)&icl_nhi_ops },
 
        /* Any USB4 compliant host */
        { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_USB4, ~0) },
index 01190d9..b071802 100644 (file)
@@ -75,6 +75,9 @@ extern const struct tb_nhi_ops icl_nhi_ops;
 #define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_BRIDGE      0x15ef
 #define PCI_DEVICE_ID_INTEL_ADL_NHI0                   0x463e
 #define PCI_DEVICE_ID_INTEL_ADL_NHI1                   0x466d
+#define PCI_DEVICE_ID_INTEL_MTL_M_NHI0                 0x7eb2
+#define PCI_DEVICE_ID_INTEL_MTL_P_NHI0                 0x7ec2
+#define PCI_DEVICE_ID_INTEL_MTL_P_NHI1                 0x7ec3
 #define PCI_DEVICE_ID_INTEL_ICL_NHI1                   0x8a0d
 #define PCI_DEVICE_ID_INTEL_ICL_NHI0                   0x8a17
 #define PCI_DEVICE_ID_INTEL_TGL_NHI0                   0x9a1b
index b3f3103..3dd5f81 100644 (file)
 
 #include "tb.h"
 
+/* Intel specific NVM offsets */
+#define INTEL_NVM_DEVID                        0x05
+#define INTEL_NVM_VERSION              0x08
+#define INTEL_NVM_CSS                  0x10
+#define INTEL_NVM_FLASH_SIZE           0x45
+
+/* ASMedia specific NVM offsets */
+#define ASMEDIA_NVM_DATE               0x1c
+#define ASMEDIA_NVM_VERSION            0x28
+
 static DEFINE_IDA(nvm_ida);
 
 /**
+ * struct tb_nvm_vendor_ops - Vendor specific NVM operations
+ * @read_version: Reads out NVM version from the flash
+ * @validate: Validates the NVM image before update (optional)
+ * @write_headers: Writes headers before the rest of the image (optional)
+ */
+struct tb_nvm_vendor_ops {
+       int (*read_version)(struct tb_nvm *nvm);
+       int (*validate)(struct tb_nvm *nvm);
+       int (*write_headers)(struct tb_nvm *nvm);
+};
+
+/**
+ * struct tb_nvm_vendor - Vendor to &struct tb_nvm_vendor_ops mapping
+ * @vendor: Vendor ID
+ * @vops: Vendor specific NVM operations
+ *
+ * Maps vendor ID to NVM vendor operations. If there is no mapping then
+ * NVM firmware upgrade is disabled for the device.
+ */
+struct tb_nvm_vendor {
+       u16 vendor;
+       const struct tb_nvm_vendor_ops *vops;
+};
+
+static int intel_switch_nvm_version(struct tb_nvm *nvm)
+{
+       struct tb_switch *sw = tb_to_switch(nvm->dev);
+       u32 val, nvm_size, hdr_size;
+       int ret;
+
+       /*
+        * If the switch is in safe-mode the only accessible portion of
+        * the NVM is the non-active one where userspace is expected to
+        * write new functional NVM.
+        */
+       if (sw->safe_mode)
+               return 0;
+
+       ret = tb_switch_nvm_read(sw, INTEL_NVM_FLASH_SIZE, &val, sizeof(val));
+       if (ret)
+               return ret;
+
+       hdr_size = sw->generation < 3 ? SZ_8K : SZ_16K;
+       nvm_size = (SZ_1M << (val & 7)) / 8;
+       nvm_size = (nvm_size - hdr_size) / 2;
+
+       ret = tb_switch_nvm_read(sw, INTEL_NVM_VERSION, &val, sizeof(val));
+       if (ret)
+               return ret;
+
+       nvm->major = (val >> 16) & 0xff;
+       nvm->minor = (val >> 8) & 0xff;
+       nvm->active_size = nvm_size;
+
+       return 0;
+}
+
+static int intel_switch_nvm_validate(struct tb_nvm *nvm)
+{
+       struct tb_switch *sw = tb_to_switch(nvm->dev);
+       unsigned int image_size, hdr_size;
+       u16 ds_size, device_id;
+       u8 *buf = nvm->buf;
+
+       image_size = nvm->buf_data_size;
+
+       /*
+        * FARB pointer must point inside the image and must at least
+        * contain parts of the digital section we will be reading here.
+        */
+       hdr_size = (*(u32 *)buf) & 0xffffff;
+       if (hdr_size + INTEL_NVM_DEVID + 2 >= image_size)
+               return -EINVAL;
+
+       /* Digital section start should be aligned to 4k page */
+       if (!IS_ALIGNED(hdr_size, SZ_4K))
+               return -EINVAL;
+
+       /*
+        * Read digital section size and check that it also fits inside
+        * the image.
+        */
+       ds_size = *(u16 *)(buf + hdr_size);
+       if (ds_size >= image_size)
+               return -EINVAL;
+
+       if (sw->safe_mode)
+               return 0;
+
+       /*
+        * Make sure the device ID in the image matches the one
+        * we read from the switch config space.
+        */
+       device_id = *(u16 *)(buf + hdr_size + INTEL_NVM_DEVID);
+       if (device_id != sw->config.device_id)
+               return -EINVAL;
+
+       /* Skip headers in the image */
+       nvm->buf_data_start = buf + hdr_size;
+       nvm->buf_data_size = image_size - hdr_size;
+
+       return 0;
+}
+
+static int intel_switch_nvm_write_headers(struct tb_nvm *nvm)
+{
+       struct tb_switch *sw = tb_to_switch(nvm->dev);
+
+       if (sw->generation < 3) {
+               int ret;
+
+               /* Write CSS headers first */
+               ret = dma_port_flash_write(sw->dma_port,
+                       DMA_PORT_CSS_ADDRESS, nvm->buf + INTEL_NVM_CSS,
+                       DMA_PORT_CSS_MAX_SIZE);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static const struct tb_nvm_vendor_ops intel_switch_nvm_ops = {
+       .read_version = intel_switch_nvm_version,
+       .validate = intel_switch_nvm_validate,
+       .write_headers = intel_switch_nvm_write_headers,
+};
+
+static int asmedia_switch_nvm_version(struct tb_nvm *nvm)
+{
+       struct tb_switch *sw = tb_to_switch(nvm->dev);
+       u32 val;
+       int ret;
+
+       ret = tb_switch_nvm_read(sw, ASMEDIA_NVM_VERSION, &val, sizeof(val));
+       if (ret)
+               return ret;
+
+       nvm->major = (val << 16) & 0xff0000;
+       nvm->major |= val & 0x00ff00;
+       nvm->major |= (val >> 16) & 0x0000ff;
+
+       ret = tb_switch_nvm_read(sw, ASMEDIA_NVM_DATE, &val, sizeof(val));
+       if (ret)
+               return ret;
+
+       nvm->minor = (val << 16) & 0xff0000;
+       nvm->minor |= val & 0x00ff00;
+       nvm->minor |= (val >> 16) & 0x0000ff;
+
+       /* ASMedia NVM size is fixed to 512k */
+       nvm->active_size = SZ_512K;
+
+       return 0;
+}
+
+static const struct tb_nvm_vendor_ops asmedia_switch_nvm_ops = {
+       .read_version = asmedia_switch_nvm_version,
+};
+
+/* Router vendor NVM support table */
+static const struct tb_nvm_vendor switch_nvm_vendors[] = {
+       { 0x174c, &asmedia_switch_nvm_ops },
+       { PCI_VENDOR_ID_INTEL, &intel_switch_nvm_ops },
+       { 0x8087, &intel_switch_nvm_ops },
+};
+
+static int intel_retimer_nvm_version(struct tb_nvm *nvm)
+{
+       struct tb_retimer *rt = tb_to_retimer(nvm->dev);
+       u32 val, nvm_size;
+       int ret;
+
+       ret = tb_retimer_nvm_read(rt, INTEL_NVM_VERSION, &val, sizeof(val));
+       if (ret)
+               return ret;
+
+       nvm->major = (val >> 16) & 0xff;
+       nvm->minor = (val >> 8) & 0xff;
+
+       ret = tb_retimer_nvm_read(rt, INTEL_NVM_FLASH_SIZE, &val, sizeof(val));
+       if (ret)
+               return ret;
+
+       nvm_size = (SZ_1M << (val & 7)) / 8;
+       nvm_size = (nvm_size - SZ_16K) / 2;
+       nvm->active_size = nvm_size;
+
+       return 0;
+}
+
+static int intel_retimer_nvm_validate(struct tb_nvm *nvm)
+{
+       struct tb_retimer *rt = tb_to_retimer(nvm->dev);
+       unsigned int image_size, hdr_size;
+       u8 *buf = nvm->buf;
+       u16 ds_size, device;
+
+       image_size = nvm->buf_data_size;
+
+       /*
+        * FARB pointer must point inside the image and must at least
+        * contain parts of the digital section we will be reading here.
+        */
+       hdr_size = (*(u32 *)buf) & 0xffffff;
+       if (hdr_size + INTEL_NVM_DEVID + 2 >= image_size)
+               return -EINVAL;
+
+       /* Digital section start should be aligned to 4k page */
+       if (!IS_ALIGNED(hdr_size, SZ_4K))
+               return -EINVAL;
+
+       /*
+        * Read digital section size and check that it also fits inside
+        * the image.
+        */
+       ds_size = *(u16 *)(buf + hdr_size);
+       if (ds_size >= image_size)
+               return -EINVAL;
+
+       /*
+        * Make sure the device ID in the image matches the retimer
+        * hardware.
+        */
+       device = *(u16 *)(buf + hdr_size + INTEL_NVM_DEVID);
+       if (device != rt->device)
+               return -EINVAL;
+
+       /* Skip headers in the image */
+       nvm->buf_data_start = buf + hdr_size;
+       nvm->buf_data_size = image_size - hdr_size;
+
+       return 0;
+}
+
+static const struct tb_nvm_vendor_ops intel_retimer_nvm_ops = {
+       .read_version = intel_retimer_nvm_version,
+       .validate = intel_retimer_nvm_validate,
+};
+
+/* Retimer vendor NVM support table */
+static const struct tb_nvm_vendor retimer_nvm_vendors[] = {
+       { 0x8087, &intel_retimer_nvm_ops },
+};
+
+/**
  * tb_nvm_alloc() - Allocate new NVM structure
  * @dev: Device owning the NVM
  *
  * Allocates new NVM structure with unique @id and returns it. In case
- * of error returns ERR_PTR().
+ * of error returns ERR_PTR(). Specifically returns %-EOPNOTSUPP if the
+ * NVM format of the @dev is not known by the kernel.
  */
 struct tb_nvm *tb_nvm_alloc(struct device *dev)
 {
+       const struct tb_nvm_vendor_ops *vops = NULL;
        struct tb_nvm *nvm;
-       int ret;
+       int ret, i;
+
+       if (tb_is_switch(dev)) {
+               const struct tb_switch *sw = tb_to_switch(dev);
+
+               for (i = 0; i < ARRAY_SIZE(switch_nvm_vendors); i++) {
+                       const struct tb_nvm_vendor *v = &switch_nvm_vendors[i];
+
+                       if (v->vendor == sw->config.vendor_id) {
+                               vops = v->vops;
+                               break;
+                       }
+               }
+
+               if (!vops) {
+                       tb_sw_dbg(sw, "router NVM format of vendor %#x unknown\n",
+                                 sw->config.vendor_id);
+                       return ERR_PTR(-EOPNOTSUPP);
+               }
+       } else if (tb_is_retimer(dev)) {
+               const struct tb_retimer *rt = tb_to_retimer(dev);
+
+               for (i = 0; i < ARRAY_SIZE(retimer_nvm_vendors); i++) {
+                       const struct tb_nvm_vendor *v = &retimer_nvm_vendors[i];
+
+                       if (v->vendor == rt->vendor) {
+                               vops = v->vops;
+                               break;
+                       }
+               }
+
+               if (!vops) {
+                       dev_dbg(dev, "retimer NVM format of vendor %#x unknown\n",
+                               rt->vendor);
+                       return ERR_PTR(-EOPNOTSUPP);
+               }
+       } else {
+               return ERR_PTR(-EOPNOTSUPP);
+       }
 
        nvm = kzalloc(sizeof(*nvm), GFP_KERNEL);
        if (!nvm)
@@ -38,14 +334,85 @@ struct tb_nvm *tb_nvm_alloc(struct device *dev)
 
        nvm->id = ret;
        nvm->dev = dev;
+       nvm->vops = vops;
 
        return nvm;
 }
 
 /**
+ * tb_nvm_read_version() - Read and populate NVM version
+ * @nvm: NVM structure
+ *
+ * Uses vendor specific means to read out and fill in the existing
+ * active NVM version. Returns %0 in case of success and negative errno
+ * otherwise.
+ */
+int tb_nvm_read_version(struct tb_nvm *nvm)
+{
+       const struct tb_nvm_vendor_ops *vops = nvm->vops;
+
+       if (vops && vops->read_version)
+               return vops->read_version(nvm);
+
+       return -EOPNOTSUPP;
+}
+
+/**
+ * tb_nvm_validate() - Validate new NVM image
+ * @nvm: NVM structure
+ *
+ * Runs vendor specific validation over the new NVM image and if all
+ * checks pass returns %0. As side effect updates @nvm->buf_data_start
+ * and @nvm->buf_data_size fields to match the actual data to be written
+ * to the NVM.
+ *
+ * If the validation does not pass then returns negative errno.
+ */
+int tb_nvm_validate(struct tb_nvm *nvm)
+{
+       const struct tb_nvm_vendor_ops *vops = nvm->vops;
+       unsigned int image_size;
+       u8 *buf = nvm->buf;
+
+       if (!buf)
+               return -EINVAL;
+       if (!vops)
+               return -EOPNOTSUPP;
+
+       /* Just do basic image size checks */
+       image_size = nvm->buf_data_size;
+       if (image_size < NVM_MIN_SIZE || image_size > NVM_MAX_SIZE)
+               return -EINVAL;
+
+       /*
+        * Set the default data start in the buffer. The validate method
+        * below can change this if needed.
+        */
+       nvm->buf_data_start = buf;
+
+       return vops->validate ? vops->validate(nvm) : 0;
+}
+
+/**
+ * tb_nvm_write_headers() - Write headers before the rest of the image
+ * @nvm: NVM structure
+ *
+ * If the vendor NVM format requires writing headers before the rest of
+ * the image, this function does that. Can be called even if the device
+ * does not need this.
+ *
+ * Returns %0 in case of success and negative errno otherwise.
+ */
+int tb_nvm_write_headers(struct tb_nvm *nvm)
+{
+       const struct tb_nvm_vendor_ops *vops = nvm->vops;
+
+       return vops->write_headers ? vops->write_headers(nvm) : 0;
+}
+
+/**
  * tb_nvm_add_active() - Adds active NVMem device to NVM
  * @nvm: NVM structure
- * @size: Size of the active NVM in bytes
  * @reg_read: Pointer to the function to read the NVM (passed directly to the
  *           NVMem device)
  *
@@ -54,7 +421,7 @@ struct tb_nvm *tb_nvm_alloc(struct device *dev)
  * needed. The first parameter passed to @reg_read is @nvm structure.
  * Returns %0 in success and negative errno otherwise.
  */
-int tb_nvm_add_active(struct tb_nvm *nvm, size_t size, nvmem_reg_read_t reg_read)
+int tb_nvm_add_active(struct tb_nvm *nvm, nvmem_reg_read_t reg_read)
 {
        struct nvmem_config config;
        struct nvmem_device *nvmem;
@@ -67,7 +434,7 @@ int tb_nvm_add_active(struct tb_nvm *nvm, size_t size, nvmem_reg_read_t reg_read
        config.id = nvm->id;
        config.stride = 4;
        config.word_size = 4;
-       config.size = size;
+       config.size = nvm->active_size;
        config.dev = nvm->dev;
        config.owner = THIS_MODULE;
        config.priv = nvm;
@@ -109,17 +476,17 @@ int tb_nvm_write_buf(struct tb_nvm *nvm, unsigned int offset, void *val,
 /**
  * tb_nvm_add_non_active() - Adds non-active NVMem device to NVM
  * @nvm: NVM structure
- * @size: Size of the non-active NVM in bytes
  * @reg_write: Pointer to the function to write the NVM (passed directly
  *            to the NVMem device)
  *
  * Registers new non-active NVmem device for @nvm. The @reg_write is called
  * directly from NVMem so it must handle possible concurrent access if
  * needed. The first parameter passed to @reg_write is @nvm structure.
+ * The size of the NVMem device is set to %NVM_MAX_SIZE.
+ *
  * Returns %0 in success and negative errno otherwise.
  */
-int tb_nvm_add_non_active(struct tb_nvm *nvm, size_t size,
-                         nvmem_reg_write_t reg_write)
+int tb_nvm_add_non_active(struct tb_nvm *nvm, nvmem_reg_write_t reg_write)
 {
        struct nvmem_config config;
        struct nvmem_device *nvmem;
@@ -132,7 +499,7 @@ int tb_nvm_add_non_active(struct tb_nvm *nvm, size_t size,
        config.id = nvm->id;
        config.stride = 4;
        config.word_size = 4;
-       config.size = size;
+       config.size = NVM_MAX_SIZE;
        config.dev = nvm->dev;
        config.owner = THIS_MODULE;
        config.priv = nvm;
index 8c29bd5..81252e3 100644 (file)
 
 #define TB_MAX_RETIMER_INDEX   6
 
-static int tb_retimer_nvm_read(void *priv, unsigned int offset, void *val,
-                              size_t bytes)
+/**
+ * tb_retimer_nvm_read() - Read contents of retimer NVM
+ * @rt: Retimer device
+ * @address: NVM address (in bytes) to start reading
+ * @buf: Data read from NVM is stored here
+ * @size: Number of bytes to read
+ *
+ * Reads retimer NVM and copies the contents to @buf. Returns %0 if the
+ * read was successful and negative errno in case of failure.
+ */
+int tb_retimer_nvm_read(struct tb_retimer *rt, unsigned int address, void *buf,
+                       size_t size)
+{
+       return usb4_port_retimer_nvm_read(rt->port, rt->index, address, buf, size);
+}
+
+static int nvm_read(void *priv, unsigned int offset, void *val, size_t bytes)
 {
        struct tb_nvm *nvm = priv;
        struct tb_retimer *rt = tb_to_retimer(nvm->dev);
@@ -30,7 +45,7 @@ static int tb_retimer_nvm_read(void *priv, unsigned int offset, void *val,
                goto out;
        }
 
-       ret = usb4_port_retimer_nvm_read(rt->port, rt->index, offset, val, bytes);
+       ret = tb_retimer_nvm_read(rt, offset, val, bytes);
        mutex_unlock(&rt->tb->lock);
 
 out:
@@ -40,8 +55,7 @@ out:
        return ret;
 }
 
-static int tb_retimer_nvm_write(void *priv, unsigned int offset, void *val,
-                               size_t bytes)
+static int nvm_write(void *priv, unsigned int offset, void *val, size_t bytes)
 {
        struct tb_nvm *nvm = priv;
        struct tb_retimer *rt = tb_to_retimer(nvm->dev);
@@ -59,34 +73,23 @@ static int tb_retimer_nvm_write(void *priv, unsigned int offset, void *val,
 static int tb_retimer_nvm_add(struct tb_retimer *rt)
 {
        struct tb_nvm *nvm;
-       u32 val, nvm_size;
        int ret;
 
        nvm = tb_nvm_alloc(&rt->dev);
-       if (IS_ERR(nvm))
-               return PTR_ERR(nvm);
-
-       ret = usb4_port_retimer_nvm_read(rt->port, rt->index, NVM_VERSION, &val,
-                                        sizeof(val));
-       if (ret)
+       if (IS_ERR(nvm)) {
+               ret = PTR_ERR(nvm) == -EOPNOTSUPP ? 0 : PTR_ERR(nvm);
                goto err_nvm;
+       }
 
-       nvm->major = val >> 16;
-       nvm->minor = val >> 8;
-
-       ret = usb4_port_retimer_nvm_read(rt->port, rt->index, NVM_FLASH_SIZE,
-                                        &val, sizeof(val));
+       ret = tb_nvm_read_version(nvm);
        if (ret)
                goto err_nvm;
 
-       nvm_size = (SZ_1M << (val & 7)) / 8;
-       nvm_size = (nvm_size - SZ_16K) / 2;
-
-       ret = tb_nvm_add_active(nvm, nvm_size, tb_retimer_nvm_read);
+       ret = tb_nvm_add_active(nvm, nvm_read);
        if (ret)
                goto err_nvm;
 
-       ret = tb_nvm_add_non_active(nvm, NVM_MAX_SIZE, tb_retimer_nvm_write);
+       ret = tb_nvm_add_non_active(nvm, nvm_write);
        if (ret)
                goto err_nvm;
 
@@ -94,59 +97,33 @@ static int tb_retimer_nvm_add(struct tb_retimer *rt)
        return 0;
 
 err_nvm:
-       tb_nvm_free(nvm);
+       dev_dbg(&rt->dev, "NVM upgrade disabled\n");
+       if (!IS_ERR(nvm))
+               tb_nvm_free(nvm);
+
        return ret;
 }
 
 static int tb_retimer_nvm_validate_and_write(struct tb_retimer *rt)
 {
-       unsigned int image_size, hdr_size;
-       const u8 *buf = rt->nvm->buf;
-       u16 ds_size, device;
+       unsigned int image_size;
+       const u8 *buf;
        int ret;
 
-       image_size = rt->nvm->buf_data_size;
-       if (image_size < NVM_MIN_SIZE || image_size > NVM_MAX_SIZE)
-               return -EINVAL;
-
-       /*
-        * FARB pointer must point inside the image and must at least
-        * contain parts of the digital section we will be reading here.
-        */
-       hdr_size = (*(u32 *)buf) & 0xffffff;
-       if (hdr_size + NVM_DEVID + 2 >= image_size)
-               return -EINVAL;
-
-       /* Digital section start should be aligned to 4k page */
-       if (!IS_ALIGNED(hdr_size, SZ_4K))
-               return -EINVAL;
-
-       /*
-        * Read digital section size and check that it also fits inside
-        * the image.
-        */
-       ds_size = *(u16 *)(buf + hdr_size);
-       if (ds_size >= image_size)
-               return -EINVAL;
-
-       /*
-        * Make sure the device ID in the image matches the retimer
-        * hardware.
-        */
-       device = *(u16 *)(buf + hdr_size + NVM_DEVID);
-       if (device != rt->device)
-               return -EINVAL;
+       ret = tb_nvm_validate(rt->nvm);
+       if (ret)
+               return ret;
 
-       /* Skip headers in the image */
-       buf += hdr_size;
-       image_size -= hdr_size;
+       buf = rt->nvm->buf_data_start;
+       image_size = rt->nvm->buf_data_size;
 
        ret = usb4_port_retimer_nvm_write(rt->port, rt->index, 0, buf,
                                         image_size);
-       if (!ret)
-               rt->nvm->flushed = true;
+       if (ret)
+               return ret;
 
-       return ret;
+       rt->nvm->flushed = true;
+       return 0;
 }
 
 static int tb_retimer_nvm_authenticate(struct tb_retimer *rt, bool auth_only)
@@ -185,7 +162,7 @@ static ssize_t device_show(struct device *dev, struct device_attribute *attr,
 {
        struct tb_retimer *rt = tb_to_retimer(dev);
 
-       return sprintf(buf, "%#x\n", rt->device);
+       return sysfs_emit(buf, "%#x\n", rt->device);
 }
 static DEVICE_ATTR_RO(device);
 
@@ -200,8 +177,10 @@ static ssize_t nvm_authenticate_show(struct device *dev,
 
        if (!rt->nvm)
                ret = -EAGAIN;
+       else if (rt->no_nvm_upgrade)
+               ret = -EOPNOTSUPP;
        else
-               ret = sprintf(buf, "%#x\n", rt->auth_status);
+               ret = sysfs_emit(buf, "%#x\n", rt->auth_status);
 
        mutex_unlock(&rt->tb->lock);
 
@@ -276,7 +255,7 @@ static ssize_t nvm_version_show(struct device *dev,
        if (!rt->nvm)
                ret = -EAGAIN;
        else
-               ret = sprintf(buf, "%x.%x\n", rt->nvm->major, rt->nvm->minor);
+               ret = sysfs_emit(buf, "%x.%x\n", rt->nvm->major, rt->nvm->minor);
 
        mutex_unlock(&rt->tb->lock);
        return ret;
@@ -288,7 +267,7 @@ static ssize_t vendor_show(struct device *dev, struct device_attribute *attr,
 {
        struct tb_retimer *rt = tb_to_retimer(dev);
 
-       return sprintf(buf, "%#x\n", rt->vendor);
+       return sysfs_emit(buf, "%#x\n", rt->vendor);
 }
 static DEVICE_ATTR_RO(vendor);
 
index bda889f..5185cf3 100644 (file)
@@ -26,10 +26,68 @@ enum usb4_sb_opcode {
        USB4_SB_OPCODE_NVM_BLOCK_WRITE = 0x574b4c42,            /* "BLKW" */
        USB4_SB_OPCODE_NVM_AUTH_WRITE = 0x48545541,             /* "AUTH" */
        USB4_SB_OPCODE_NVM_READ = 0x52524641,                   /* "AFRR" */
+       USB4_SB_OPCODE_READ_LANE_MARGINING_CAP = 0x50434452,    /* "RDCP" */
+       USB4_SB_OPCODE_RUN_HW_LANE_MARGINING = 0x474d4852,      /* "RHMG" */
+       USB4_SB_OPCODE_RUN_SW_LANE_MARGINING = 0x474d5352,      /* "RSMG" */
+       USB4_SB_OPCODE_READ_SW_MARGIN_ERR = 0x57534452,         /* "RDSW" */
 };
 
 #define USB4_SB_METADATA                       0x09
 #define USB4_SB_METADATA_NVM_AUTH_WRITE_MASK   GENMASK(5, 0)
 #define USB4_SB_DATA                           0x12
 
+/* USB4_SB_OPCODE_READ_LANE_MARGINING_CAP */
+#define USB4_MARGIN_CAP_0_MODES_HW             BIT(0)
+#define USB4_MARGIN_CAP_0_MODES_SW             BIT(1)
+#define USB4_MARGIN_CAP_0_2_LANES              BIT(2)
+#define USB4_MARGIN_CAP_0_VOLTAGE_INDP_MASK    GENMASK(4, 3)
+#define USB4_MARGIN_CAP_0_VOLTAGE_INDP_SHIFT   3
+#define USB4_MARGIN_CAP_0_VOLTAGE_MIN          0x0
+#define USB4_MARGIN_CAP_0_VOLTAGE_HL           0x1
+#define USB4_MARGIN_CAP_0_VOLTAGE_BOTH         0x2
+#define USB4_MARGIN_CAP_0_TIME                 BIT(5)
+#define USB4_MARGIN_CAP_0_VOLTAGE_STEPS_MASK   GENMASK(12, 6)
+#define USB4_MARGIN_CAP_0_VOLTAGE_STEPS_SHIFT  6
+#define USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_MASK GENMASK(18, 13)
+#define USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_SHIFT 13
+#define USB4_MARGIN_CAP_1_TIME_DESTR           BIT(8)
+#define USB4_MARGIN_CAP_1_TIME_INDP_MASK       GENMASK(10, 9)
+#define USB4_MARGIN_CAP_1_TIME_INDP_SHIFT      9
+#define USB4_MARGIN_CAP_1_TIME_MIN             0x0
+#define USB4_MARGIN_CAP_1_TIME_LR              0x1
+#define USB4_MARGIN_CAP_1_TIME_BOTH            0x2
+#define USB4_MARGIN_CAP_1_TIME_STEPS_MASK      GENMASK(15, 11)
+#define USB4_MARGIN_CAP_1_TIME_STEPS_SHIFT     11
+#define USB4_MARGIN_CAP_1_TIME_OFFSET_MASK     GENMASK(20, 16)
+#define USB4_MARGIN_CAP_1_TIME_OFFSET_SHIFT    16
+#define USB4_MARGIN_CAP_1_MIN_BER_MASK         GENMASK(25, 21)
+#define USB4_MARGIN_CAP_1_MIN_BER_SHIFT                21
+#define USB4_MARGIN_CAP_1_MAX_BER_MASK         GENMASK(30, 26)
+#define USB4_MARGIN_CAP_1_MAX_BER_SHIFT                26
+#define USB4_MARGIN_CAP_1_MAX_BER_SHIFT                26
+
+/* USB4_SB_OPCODE_RUN_HW_LANE_MARGINING */
+#define USB4_MARGIN_HW_TIME                    BIT(3)
+#define USB4_MARGIN_HW_RH                      BIT(4)
+#define USB4_MARGIN_HW_BER_MASK                        GENMASK(9, 5)
+#define USB4_MARGIN_HW_BER_SHIFT               5
+
+/* Applicable to all margin values */
+#define USB4_MARGIN_HW_RES_1_MARGIN_MASK       GENMASK(6, 0)
+#define USB4_MARGIN_HW_RES_1_EXCEEDS           BIT(7)
+/* Different lane margin shifts */
+#define USB4_MARGIN_HW_RES_1_L0_LL_MARGIN_SHIFT        8
+#define USB4_MARGIN_HW_RES_1_L1_RH_MARGIN_SHIFT        16
+#define USB4_MARGIN_HW_RES_1_L1_LL_MARGIN_SHIFT        24
+
+/* USB4_SB_OPCODE_RUN_SW_LANE_MARGINING */
+#define USB4_MARGIN_SW_TIME                    BIT(3)
+#define USB4_MARGIN_SW_RH                      BIT(4)
+#define USB4_MARGIN_SW_COUNTER_MASK            GENMASK(14, 13)
+#define USB4_MARGIN_SW_COUNTER_SHIFT           13
+#define USB4_MARGIN_SW_COUNTER_NOP             0x0
+#define USB4_MARGIN_SW_COUNTER_CLEAR           0x1
+#define USB4_MARGIN_SW_COUNTER_START           0x2
+#define USB4_MARGIN_SW_COUNTER_STOP            0x3
+
 #endif
index 77d7f07..60da5c2 100644 (file)
@@ -19,8 +19,6 @@
 
 /* Switch NVM support */
 
-#define NVM_CSS                        0x10
-
 struct nvm_auth_status {
        struct list_head list;
        uuid_t uuid;
@@ -102,70 +100,30 @@ static void nvm_clear_auth_status(const struct tb_switch *sw)
 
 static int nvm_validate_and_write(struct tb_switch *sw)
 {
-       unsigned int image_size, hdr_size;
-       const u8 *buf = sw->nvm->buf;
-       u16 ds_size;
+       unsigned int image_size;
+       const u8 *buf;
        int ret;
 
-       if (!buf)
-               return -EINVAL;
-
-       image_size = sw->nvm->buf_data_size;
-       if (image_size < NVM_MIN_SIZE || image_size > NVM_MAX_SIZE)
-               return -EINVAL;
-
-       /*
-        * FARB pointer must point inside the image and must at least
-        * contain parts of the digital section we will be reading here.
-        */
-       hdr_size = (*(u32 *)buf) & 0xffffff;
-       if (hdr_size + NVM_DEVID + 2 >= image_size)
-               return -EINVAL;
-
-       /* Digital section start should be aligned to 4k page */
-       if (!IS_ALIGNED(hdr_size, SZ_4K))
-               return -EINVAL;
-
-       /*
-        * Read digital section size and check that it also fits inside
-        * the image.
-        */
-       ds_size = *(u16 *)(buf + hdr_size);
-       if (ds_size >= image_size)
-               return -EINVAL;
-
-       if (!sw->safe_mode) {
-               u16 device_id;
+       ret = tb_nvm_validate(sw->nvm);
+       if (ret)
+               return ret;
 
-               /*
-                * Make sure the device ID in the image matches the one
-                * we read from the switch config space.
-                */
-               device_id = *(u16 *)(buf + hdr_size + NVM_DEVID);
-               if (device_id != sw->config.device_id)
-                       return -EINVAL;
-
-               if (sw->generation < 3) {
-                       /* Write CSS headers first */
-                       ret = dma_port_flash_write(sw->dma_port,
-                               DMA_PORT_CSS_ADDRESS, buf + NVM_CSS,
-                               DMA_PORT_CSS_MAX_SIZE);
-                       if (ret)
-                               return ret;
-               }
+       ret = tb_nvm_write_headers(sw->nvm);
+       if (ret)
+               return ret;
 
-               /* Skip headers in the image */
-               buf += hdr_size;
-               image_size -= hdr_size;
-       }
+       buf = sw->nvm->buf_data_start;
+       image_size = sw->nvm->buf_data_size;
 
        if (tb_switch_is_usb4(sw))
                ret = usb4_switch_nvm_write(sw, 0, buf, image_size);
        else
                ret = dma_port_flash_write(sw->dma_port, 0, buf, image_size);
-       if (!ret)
-               sw->nvm->flushed = true;
-       return ret;
+       if (ret)
+               return ret;
+
+       sw->nvm->flushed = true;
+       return 0;
 }
 
 static int nvm_authenticate_host_dma_port(struct tb_switch *sw)
@@ -300,14 +258,6 @@ static inline bool nvm_upgradeable(struct tb_switch *sw)
        return nvm_readable(sw);
 }
 
-static inline int nvm_read(struct tb_switch *sw, unsigned int address,
-                          void *buf, size_t size)
-{
-       if (tb_switch_is_usb4(sw))
-               return usb4_switch_nvm_read(sw, address, buf, size);
-       return dma_port_flash_read(sw->dma_port, address, buf, size);
-}
-
 static int nvm_authenticate(struct tb_switch *sw, bool auth_only)
 {
        int ret;
@@ -335,8 +285,26 @@ static int nvm_authenticate(struct tb_switch *sw, bool auth_only)
        return ret;
 }
 
-static int tb_switch_nvm_read(void *priv, unsigned int offset, void *val,
-                             size_t bytes)
+/**
+ * tb_switch_nvm_read() - Read router NVM
+ * @sw: Router whose NVM to read
+ * @address: Start address on the NVM
+ * @buf: Buffer where the read data is copied
+ * @size: Size of the buffer in bytes
+ *
+ * Reads from router NVM and returns the requested data in @buf. Locking
+ * is up to the caller. Returns %0 in success and negative errno in case
+ * of failure.
+ */
+int tb_switch_nvm_read(struct tb_switch *sw, unsigned int address, void *buf,
+                      size_t size)
+{
+       if (tb_switch_is_usb4(sw))
+               return usb4_switch_nvm_read(sw, address, buf, size);
+       return dma_port_flash_read(sw->dma_port, address, buf, size);
+}
+
+static int nvm_read(void *priv, unsigned int offset, void *val, size_t bytes)
 {
        struct tb_nvm *nvm = priv;
        struct tb_switch *sw = tb_to_switch(nvm->dev);
@@ -349,7 +317,7 @@ static int tb_switch_nvm_read(void *priv, unsigned int offset, void *val,
                goto out;
        }
 
-       ret = nvm_read(sw, offset, val, bytes);
+       ret = tb_switch_nvm_read(sw, offset, val, bytes);
        mutex_unlock(&sw->tb->lock);
 
 out:
@@ -359,8 +327,7 @@ out:
        return ret;
 }
 
-static int tb_switch_nvm_write(void *priv, unsigned int offset, void *val,
-                              size_t bytes)
+static int nvm_write(void *priv, unsigned int offset, void *val, size_t bytes)
 {
        struct tb_nvm *nvm = priv;
        struct tb_switch *sw = tb_to_switch(nvm->dev);
@@ -384,28 +351,20 @@ static int tb_switch_nvm_write(void *priv, unsigned int offset, void *val,
 static int tb_switch_nvm_add(struct tb_switch *sw)
 {
        struct tb_nvm *nvm;
-       u32 val;
        int ret;
 
        if (!nvm_readable(sw))
                return 0;
 
-       /*
-        * The NVM format of non-Intel hardware is not known so
-        * currently restrict NVM upgrade for Intel hardware. We may
-        * relax this in the future when we learn other NVM formats.
-        */
-       if (sw->config.vendor_id != PCI_VENDOR_ID_INTEL &&
-           sw->config.vendor_id != 0x8087) {
-               dev_info(&sw->dev,
-                        "NVM format of vendor %#x is not known, disabling NVM upgrade\n",
-                        sw->config.vendor_id);
-               return 0;
+       nvm = tb_nvm_alloc(&sw->dev);
+       if (IS_ERR(nvm)) {
+               ret = PTR_ERR(nvm) == -EOPNOTSUPP ? 0 : PTR_ERR(nvm);
+               goto err_nvm;
        }
 
-       nvm = tb_nvm_alloc(&sw->dev);
-       if (IS_ERR(nvm))
-               return PTR_ERR(nvm);
+       ret = tb_nvm_read_version(nvm);
+       if (ret)
+               goto err_nvm;
 
        /*
         * If the switch is in safe-mode the only accessible portion of
@@ -413,31 +372,13 @@ static int tb_switch_nvm_add(struct tb_switch *sw)
         * write new functional NVM.
         */
        if (!sw->safe_mode) {
-               u32 nvm_size, hdr_size;
-
-               ret = nvm_read(sw, NVM_FLASH_SIZE, &val, sizeof(val));
-               if (ret)
-                       goto err_nvm;
-
-               hdr_size = sw->generation < 3 ? SZ_8K : SZ_16K;
-               nvm_size = (SZ_1M << (val & 7)) / 8;
-               nvm_size = (nvm_size - hdr_size) / 2;
-
-               ret = nvm_read(sw, NVM_VERSION, &val, sizeof(val));
-               if (ret)
-                       goto err_nvm;
-
-               nvm->major = val >> 16;
-               nvm->minor = val >> 8;
-
-               ret = tb_nvm_add_active(nvm, nvm_size, tb_switch_nvm_read);
+               ret = tb_nvm_add_active(nvm, nvm_read);
                if (ret)
                        goto err_nvm;
        }
 
        if (!sw->no_nvm_upgrade) {
-               ret = tb_nvm_add_non_active(nvm, NVM_MAX_SIZE,
-                                           tb_switch_nvm_write);
+               ret = tb_nvm_add_non_active(nvm, nvm_write);
                if (ret)
                        goto err_nvm;
        }
@@ -446,7 +387,11 @@ static int tb_switch_nvm_add(struct tb_switch *sw)
        return 0;
 
 err_nvm:
-       tb_nvm_free(nvm);
+       tb_sw_dbg(sw, "NVM upgrade disabled\n");
+       sw->no_nvm_upgrade = true;
+       if (!IS_ERR(nvm))
+               tb_nvm_free(nvm);
+
        return ret;
 }
 
@@ -1229,6 +1174,135 @@ int tb_port_update_credits(struct tb_port *port)
        return tb_port_do_update_credits(port->dual_link_port);
 }
 
+static int __tb_port_pm_secondary_set(struct tb_port *port, bool secondary)
+{
+       u32 phy;
+       int ret;
+
+       ret = tb_port_read(port, &phy, TB_CFG_PORT,
+                          port->cap_phy + LANE_ADP_CS_1, 1);
+       if (ret)
+               return ret;
+
+       if (secondary)
+               phy |= LANE_ADP_CS_1_PMS;
+       else
+               phy &= ~LANE_ADP_CS_1_PMS;
+
+       return tb_port_write(port, &phy, TB_CFG_PORT,
+                            port->cap_phy + LANE_ADP_CS_1, 1);
+}
+
+static int tb_port_pm_secondary_enable(struct tb_port *port)
+{
+       return __tb_port_pm_secondary_set(port, true);
+}
+
+static int tb_port_pm_secondary_disable(struct tb_port *port)
+{
+       return __tb_port_pm_secondary_set(port, false);
+}
+
+/* Called for USB4 or Titan Ridge routers only */
+static bool tb_port_clx_supported(struct tb_port *port, unsigned int clx_mask)
+{
+       u32 val, mask = 0;
+       bool ret;
+
+       /* Don't enable CLx in case of two single-lane links */
+       if (!port->bonded && port->dual_link_port)
+               return false;
+
+       /* Don't enable CLx in case of inter-domain link */
+       if (port->xdomain)
+               return false;
+
+       if (tb_switch_is_usb4(port->sw)) {
+               if (!usb4_port_clx_supported(port))
+                       return false;
+       } else if (!tb_lc_is_clx_supported(port)) {
+               return false;
+       }
+
+       if (clx_mask & TB_CL1) {
+               /* CL0s and CL1 are enabled and supported together */
+               mask |= LANE_ADP_CS_0_CL0S_SUPPORT | LANE_ADP_CS_0_CL1_SUPPORT;
+       }
+       if (clx_mask & TB_CL2)
+               mask |= LANE_ADP_CS_0_CL2_SUPPORT;
+
+       ret = tb_port_read(port, &val, TB_CFG_PORT,
+                          port->cap_phy + LANE_ADP_CS_0, 1);
+       if (ret)
+               return false;
+
+       return !!(val & mask);
+}
+
+static int __tb_port_clx_set(struct tb_port *port, enum tb_clx clx, bool enable)
+{
+       u32 phy, mask;
+       int ret;
+
+       /* CL0s and CL1 are enabled and supported together */
+       if (clx == TB_CL1)
+               mask = LANE_ADP_CS_1_CL0S_ENABLE | LANE_ADP_CS_1_CL1_ENABLE;
+       else
+               /* For now we support only CL0s and CL1. Not CL2 */
+               return -EOPNOTSUPP;
+
+       ret = tb_port_read(port, &phy, TB_CFG_PORT,
+                          port->cap_phy + LANE_ADP_CS_1, 1);
+       if (ret)
+               return ret;
+
+       if (enable)
+               phy |= mask;
+       else
+               phy &= ~mask;
+
+       return tb_port_write(port, &phy, TB_CFG_PORT,
+                            port->cap_phy + LANE_ADP_CS_1, 1);
+}
+
+static int tb_port_clx_disable(struct tb_port *port, enum tb_clx clx)
+{
+       return __tb_port_clx_set(port, clx, false);
+}
+
+static int tb_port_clx_enable(struct tb_port *port, enum tb_clx clx)
+{
+       return __tb_port_clx_set(port, clx, true);
+}
+
+/**
+ * tb_port_is_clx_enabled() - Is given CL state enabled
+ * @port: USB4 port to check
+ * @clx_mask: Mask of CL states to check
+ *
+ * Returns true if any of the given CL states is enabled for @port.
+ */
+bool tb_port_is_clx_enabled(struct tb_port *port, unsigned int clx_mask)
+{
+       u32 val, mask = 0;
+       int ret;
+
+       if (!tb_port_clx_supported(port, clx_mask))
+               return false;
+
+       if (clx_mask & TB_CL1)
+               mask |= LANE_ADP_CS_1_CL0S_ENABLE | LANE_ADP_CS_1_CL1_ENABLE;
+       if (clx_mask & TB_CL2)
+               mask |= LANE_ADP_CS_1_CL2_ENABLE;
+
+       ret = tb_port_read(port, &val, TB_CFG_PORT,
+                          port->cap_phy + LANE_ADP_CS_1, 1);
+       if (ret)
+               return false;
+
+       return !!(val & mask);
+}
+
 static int tb_port_start_lane_initialization(struct tb_port *port)
 {
        int ret;
@@ -1620,7 +1694,7 @@ static ssize_t authorized_show(struct device *dev,
 {
        struct tb_switch *sw = tb_to_switch(dev);
 
-       return sprintf(buf, "%u\n", sw->authorized);
+       return sysfs_emit(buf, "%u\n", sw->authorized);
 }
 
 static int disapprove_switch(struct device *dev, void *not_used)
@@ -1730,7 +1804,7 @@ static ssize_t boot_show(struct device *dev, struct device_attribute *attr,
 {
        struct tb_switch *sw = tb_to_switch(dev);
 
-       return sprintf(buf, "%u\n", sw->boot);
+       return sysfs_emit(buf, "%u\n", sw->boot);
 }
 static DEVICE_ATTR_RO(boot);
 
@@ -1739,7 +1813,7 @@ static ssize_t device_show(struct device *dev, struct device_attribute *attr,
 {
        struct tb_switch *sw = tb_to_switch(dev);
 
-       return sprintf(buf, "%#x\n", sw->device);
+       return sysfs_emit(buf, "%#x\n", sw->device);
 }
 static DEVICE_ATTR_RO(device);
 
@@ -1748,7 +1822,7 @@ device_name_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct tb_switch *sw = tb_to_switch(dev);
 
-       return sprintf(buf, "%s\n", sw->device_name ? sw->device_name : "");
+       return sysfs_emit(buf, "%s\n", sw->device_name ?: "");
 }
 static DEVICE_ATTR_RO(device_name);
 
@@ -1757,7 +1831,7 @@ generation_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct tb_switch *sw = tb_to_switch(dev);
 
-       return sprintf(buf, "%u\n", sw->generation);
+       return sysfs_emit(buf, "%u\n", sw->generation);
 }
 static DEVICE_ATTR_RO(generation);
 
@@ -1771,9 +1845,9 @@ static ssize_t key_show(struct device *dev, struct device_attribute *attr,
                return restart_syscall();
 
        if (sw->key)
-               ret = sprintf(buf, "%*phN\n", TB_SWITCH_KEY_SIZE, sw->key);
+               ret = sysfs_emit(buf, "%*phN\n", TB_SWITCH_KEY_SIZE, sw->key);
        else
-               ret = sprintf(buf, "\n");
+               ret = sysfs_emit(buf, "\n");
 
        mutex_unlock(&sw->tb->lock);
        return ret;
@@ -1818,7 +1892,7 @@ static ssize_t speed_show(struct device *dev, struct device_attribute *attr,
 {
        struct tb_switch *sw = tb_to_switch(dev);
 
-       return sprintf(buf, "%u.0 Gb/s\n", sw->link_speed);
+       return sysfs_emit(buf, "%u.0 Gb/s\n", sw->link_speed);
 }
 
 /*
@@ -1833,7 +1907,7 @@ static ssize_t lanes_show(struct device *dev, struct device_attribute *attr,
 {
        struct tb_switch *sw = tb_to_switch(dev);
 
-       return sprintf(buf, "%u\n", sw->link_width);
+       return sysfs_emit(buf, "%u\n", sw->link_width);
 }
 
 /*
@@ -1850,7 +1924,7 @@ static ssize_t nvm_authenticate_show(struct device *dev,
        u32 status;
 
        nvm_get_auth_status(sw, &status);
-       return sprintf(buf, "%#x\n", status);
+       return sysfs_emit(buf, "%#x\n", status);
 }
 
 static ssize_t nvm_authenticate_sysfs(struct device *dev, const char *buf,
@@ -1866,6 +1940,11 @@ static ssize_t nvm_authenticate_sysfs(struct device *dev, const char *buf,
                goto exit_rpm;
        }
 
+       if (sw->no_nvm_upgrade) {
+               ret = -EOPNOTSUPP;
+               goto exit_unlock;
+       }
+
        /* If NVMem devices are not yet added */
        if (!sw->nvm) {
                ret = -EAGAIN;
@@ -1954,7 +2033,7 @@ static ssize_t nvm_version_show(struct device *dev,
        else if (!sw->nvm)
                ret = -EAGAIN;
        else
-               ret = sprintf(buf, "%x.%x\n", sw->nvm->major, sw->nvm->minor);
+               ret = sysfs_emit(buf, "%x.%x\n", sw->nvm->major, sw->nvm->minor);
 
        mutex_unlock(&sw->tb->lock);
 
@@ -1967,7 +2046,7 @@ static ssize_t vendor_show(struct device *dev, struct device_attribute *attr,
 {
        struct tb_switch *sw = tb_to_switch(dev);
 
-       return sprintf(buf, "%#x\n", sw->vendor);
+       return sysfs_emit(buf, "%#x\n", sw->vendor);
 }
 static DEVICE_ATTR_RO(vendor);
 
@@ -1976,7 +2055,7 @@ vendor_name_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct tb_switch *sw = tb_to_switch(dev);
 
-       return sprintf(buf, "%s\n", sw->vendor_name ? sw->vendor_name : "");
+       return sysfs_emit(buf, "%s\n", sw->vendor_name ?: "");
 }
 static DEVICE_ATTR_RO(vendor_name);
 
@@ -1985,7 +2064,7 @@ static ssize_t unique_id_show(struct device *dev, struct device_attribute *attr,
 {
        struct tb_switch *sw = tb_to_switch(dev);
 
-       return sprintf(buf, "%pUb\n", sw->uuid);
+       return sysfs_emit(buf, "%pUb\n", sw->uuid);
 }
 static DEVICE_ATTR_RO(unique_id);
 
@@ -2822,6 +2901,26 @@ static void tb_switch_credits_init(struct tb_switch *sw)
                tb_sw_info(sw, "failed to determine preferred buffer allocation, using defaults\n");
 }
 
+static int tb_switch_port_hotplug_enable(struct tb_switch *sw)
+{
+       struct tb_port *port;
+
+       if (tb_switch_is_icm(sw))
+               return 0;
+
+       tb_switch_for_each_port(sw, port) {
+               int res;
+
+               if (!port->cap_usb4)
+                       continue;
+
+               res = usb4_port_hotplug_enable(port);
+               if (res)
+                       return res;
+       }
+       return 0;
+}
+
 /**
  * tb_switch_add() - Add a switch to the domain
  * @sw: Switch to add
@@ -2891,6 +2990,10 @@ int tb_switch_add(struct tb_switch *sw)
                        return ret;
        }
 
+       ret = tb_switch_port_hotplug_enable(sw);
+       if (ret)
+               return ret;
+
        ret = device_add(&sw->dev);
        if (ret) {
                dev_err(&sw->dev, "failed to add device: %d\n", ret);
@@ -3362,35 +3465,6 @@ struct tb_port *tb_switch_find_port(struct tb_switch *sw,
        return NULL;
 }
 
-static int __tb_port_pm_secondary_set(struct tb_port *port, bool secondary)
-{
-       u32 phy;
-       int ret;
-
-       ret = tb_port_read(port, &phy, TB_CFG_PORT,
-                          port->cap_phy + LANE_ADP_CS_1, 1);
-       if (ret)
-               return ret;
-
-       if (secondary)
-               phy |= LANE_ADP_CS_1_PMS;
-       else
-               phy &= ~LANE_ADP_CS_1_PMS;
-
-       return tb_port_write(port, &phy, TB_CFG_PORT,
-                            port->cap_phy + LANE_ADP_CS_1, 1);
-}
-
-static int tb_port_pm_secondary_enable(struct tb_port *port)
-{
-       return __tb_port_pm_secondary_set(port, true);
-}
-
-static int tb_port_pm_secondary_disable(struct tb_port *port)
-{
-       return __tb_port_pm_secondary_set(port, false);
-}
-
 static int tb_switch_pm_secondary_resolve(struct tb_switch *sw)
 {
        struct tb_switch *parent = tb_switch_parent(sw);
@@ -3409,83 +3483,6 @@ static int tb_switch_pm_secondary_resolve(struct tb_switch *sw)
        return tb_port_pm_secondary_disable(down);
 }
 
-/* Called for USB4 or Titan Ridge routers only */
-static bool tb_port_clx_supported(struct tb_port *port, enum tb_clx clx)
-{
-       u32 mask, val;
-       bool ret;
-
-       /* Don't enable CLx in case of two single-lane links */
-       if (!port->bonded && port->dual_link_port)
-               return false;
-
-       /* Don't enable CLx in case of inter-domain link */
-       if (port->xdomain)
-               return false;
-
-       if (tb_switch_is_usb4(port->sw)) {
-               if (!usb4_port_clx_supported(port))
-                       return false;
-       } else if (!tb_lc_is_clx_supported(port)) {
-               return false;
-       }
-
-       switch (clx) {
-       case TB_CL1:
-               /* CL0s and CL1 are enabled and supported together */
-               mask = LANE_ADP_CS_0_CL0S_SUPPORT | LANE_ADP_CS_0_CL1_SUPPORT;
-               break;
-
-       /* For now we support only CL0s and CL1. Not CL2 */
-       case TB_CL2:
-       default:
-               return false;
-       }
-
-       ret = tb_port_read(port, &val, TB_CFG_PORT,
-                          port->cap_phy + LANE_ADP_CS_0, 1);
-       if (ret)
-               return false;
-
-       return !!(val & mask);
-}
-
-static int __tb_port_clx_set(struct tb_port *port, enum tb_clx clx, bool enable)
-{
-       u32 phy, mask;
-       int ret;
-
-       /* CL0s and CL1 are enabled and supported together */
-       if (clx == TB_CL1)
-               mask = LANE_ADP_CS_1_CL0S_ENABLE | LANE_ADP_CS_1_CL1_ENABLE;
-       else
-               /* For now we support only CL0s and CL1. Not CL2 */
-               return -EOPNOTSUPP;
-
-       ret = tb_port_read(port, &phy, TB_CFG_PORT,
-                          port->cap_phy + LANE_ADP_CS_1, 1);
-       if (ret)
-               return ret;
-
-       if (enable)
-               phy |= mask;
-       else
-               phy &= ~mask;
-
-       return tb_port_write(port, &phy, TB_CFG_PORT,
-                            port->cap_phy + LANE_ADP_CS_1, 1);
-}
-
-static int tb_port_clx_disable(struct tb_port *port, enum tb_clx clx)
-{
-       return __tb_port_clx_set(port, clx, false);
-}
-
-static int tb_port_clx_enable(struct tb_port *port, enum tb_clx clx)
-{
-       return __tb_port_clx_set(port, clx, true);
-}
-
 static int __tb_switch_enable_clx(struct tb_switch *sw, enum tb_clx clx)
 {
        struct tb_switch *parent = tb_switch_parent(sw);
index 9a27707..4628458 100644 (file)
@@ -105,6 +105,32 @@ static void tb_remove_dp_resources(struct tb_switch *sw)
        }
 }
 
+static void tb_discover_dp_resource(struct tb *tb, struct tb_port *port)
+{
+       struct tb_cm *tcm = tb_priv(tb);
+       struct tb_port *p;
+
+       list_for_each_entry(p, &tcm->dp_resources, list) {
+               if (p == port)
+                       return;
+       }
+
+       tb_port_dbg(port, "DP %s resource available discovered\n",
+                   tb_port_is_dpin(port) ? "IN" : "OUT");
+       list_add_tail(&port->list, &tcm->dp_resources);
+}
+
+static void tb_discover_dp_resources(struct tb *tb)
+{
+       struct tb_cm *tcm = tb_priv(tb);
+       struct tb_tunnel *tunnel;
+
+       list_for_each_entry(tunnel, &tcm->tunnel_list, list) {
+               if (tb_tunnel_is_dp(tunnel))
+                       tb_discover_dp_resource(tb, tunnel->dst_port);
+       }
+}
+
 static void tb_switch_discover_tunnels(struct tb_switch *sw,
                                       struct list_head *list,
                                       bool alloc_hopids)
@@ -1416,8 +1442,11 @@ static int tb_start(struct tb *tb)
         * ICM firmware upgrade needs running firmware and in native
         * mode that is not available so disable firmware upgrade of the
         * root switch.
+        *
+        * However, USB4 routers support NVM firmware upgrade if they
+        * implement the necessary router operations.
         */
-       tb->root_switch->no_nvm_upgrade = true;
+       tb->root_switch->no_nvm_upgrade = !tb_switch_is_usb4(tb->root_switch);
        /* All USB4 routers support runtime PM */
        tb->root_switch->rpm = tb_switch_is_usb4(tb->root_switch);
 
@@ -1446,6 +1475,8 @@ static int tb_start(struct tb *tb)
        tb_scan_switch(tb->root_switch);
        /* Find out tunnels created by the boot firmware */
        tb_discover_tunnels(tb);
+       /* Add DP resources from the DP tunnels created by the boot firmware */
+       tb_discover_dp_resources(tb);
        /*
         * If the boot firmware did not create USB 3.x tunnels create them
         * now for the whole topology.
index 0f067c0..f978697 100644 (file)
 #define NVM_MAX_SIZE           SZ_512K
 #define NVM_DATA_DWORDS                16
 
-/* Intel specific NVM offsets */
-#define NVM_DEVID              0x05
-#define NVM_VERSION            0x08
-#define NVM_FLASH_SIZE         0x45
-
 /**
  * struct tb_nvm - Structure holding NVM information
  * @dev: Owner of the NVM
  * @minor: Minor version number of the active NVM portion
  * @id: Identifier used with both NVM portions
  * @active: Active portion NVMem device
+ * @active_size: Size in bytes of the active NVM
  * @non_active: Non-active portion NVMem device
  * @buf: Buffer where the NVM image is stored before it is written to
  *      the actual NVM flash device
+ * @buf_data_start: Where the actual image starts after skipping
+ *                 possible headers
  * @buf_data_size: Number of bytes actually consumed by the new NVM
  *                image
  * @authenticating: The device is authenticating the new NVM
  * @flushed: The image has been flushed to the storage area
+ * @vops: Router vendor specific NVM operations (optional)
  *
  * The user of this structure needs to handle serialization of possible
  * concurrent access.
  */
 struct tb_nvm {
        struct device *dev;
-       u8 major;
-       u8 minor;
+       u32 major;
+       u32 minor;
        int id;
        struct nvmem_device *active;
+       size_t active_size;
        struct nvmem_device *non_active;
        void *buf;
+       void *buf_data_start;
        size_t buf_data_size;
        bool authenticating;
        bool flushed;
+       const struct tb_nvm_vendor_ops *vops;
 };
 
 enum tb_nvm_write_ops {
@@ -113,8 +115,8 @@ struct tb_switch_tmu {
 enum tb_clx {
        TB_CLX_DISABLE,
        /* CL0s and CL1 are enabled and supported together */
-       TB_CL1,
-       TB_CL2,
+       TB_CL1 = BIT(0),
+       TB_CL2 = BIT(1),
 };
 
 /**
@@ -279,12 +281,16 @@ struct tb_port {
  * @can_offline: Does the port have necessary platform support to moved
  *              it into offline mode and back
  * @offline: The port is currently in offline mode
+ * @margining: Pointer to margining structure if enabled
  */
 struct usb4_port {
        struct device dev;
        struct tb_port *port;
        bool can_offline;
        bool offline;
+#ifdef CONFIG_USB4_DEBUGFS_MARGINING
+       struct tb_margining *margining;
+#endif
 };
 
 /**
@@ -296,6 +302,7 @@ struct usb4_port {
  * @device: Device ID of the retimer
  * @port: Pointer to the lane 0 adapter
  * @nvm: Pointer to the NVM if the retimer has one (%NULL otherwise)
+ * @no_nvm_upgrade: Prevent NVM upgrade of this retimer
  * @auth_status: Status of last NVM authentication
  */
 struct tb_retimer {
@@ -306,6 +313,7 @@ struct tb_retimer {
        u32 device;
        struct tb_port *port;
        struct tb_nvm *nvm;
+       bool no_nvm_upgrade;
        u32 auth_status;
 };
 
@@ -737,11 +745,13 @@ static inline void tb_domain_put(struct tb *tb)
 }
 
 struct tb_nvm *tb_nvm_alloc(struct device *dev);
-int tb_nvm_add_active(struct tb_nvm *nvm, size_t size, nvmem_reg_read_t reg_read);
+int tb_nvm_read_version(struct tb_nvm *nvm);
+int tb_nvm_validate(struct tb_nvm *nvm);
+int tb_nvm_write_headers(struct tb_nvm *nvm);
+int tb_nvm_add_active(struct tb_nvm *nvm, nvmem_reg_read_t reg_read);
 int tb_nvm_write_buf(struct tb_nvm *nvm, unsigned int offset, void *val,
                     size_t bytes);
-int tb_nvm_add_non_active(struct tb_nvm *nvm, size_t size,
-                         nvmem_reg_write_t reg_write);
+int tb_nvm_add_non_active(struct tb_nvm *nvm, nvmem_reg_write_t reg_write);
 void tb_nvm_free(struct tb_nvm *nvm);
 void tb_nvm_exit(void);
 
@@ -755,6 +765,8 @@ int tb_nvm_write_data(unsigned int address, const void *buf, size_t size,
                      unsigned int retries, write_block_fn write_next_block,
                      void *write_block_data);
 
+int tb_switch_nvm_read(struct tb_switch *sw, unsigned int address, void *buf,
+                      size_t size);
 struct tb_switch *tb_switch_alloc(struct tb *tb, struct device *parent,
                                  u64 route);
 struct tb_switch *tb_switch_alloc_safe_mode(struct tb *tb,
@@ -1035,6 +1047,7 @@ void tb_port_lane_bonding_disable(struct tb_port *port);
 int tb_port_wait_for_link_width(struct tb_port *port, int width,
                                int timeout_msec);
 int tb_port_update_credits(struct tb_port *port);
+bool tb_port_is_clx_enabled(struct tb_port *port, enum tb_clx clx);
 
 int tb_switch_find_vse_cap(struct tb_switch *sw, enum tb_switch_vse_cap vsec);
 int tb_switch_find_cap(struct tb_switch *sw, enum tb_switch_cap cap);
@@ -1132,6 +1145,13 @@ void tb_xdomain_remove(struct tb_xdomain *xd);
 struct tb_xdomain *tb_xdomain_find_by_link_depth(struct tb *tb, u8 link,
                                                 u8 depth);
 
+static inline struct tb_switch *tb_xdomain_parent(struct tb_xdomain *xd)
+{
+       return tb_to_switch(xd->dev.parent);
+}
+
+int tb_retimer_nvm_read(struct tb_retimer *rt, unsigned int address, void *buf,
+                       size_t size);
 int tb_retimer_scan(struct tb_port *port, bool add);
 void tb_retimer_remove_all(struct tb_port *port);
 
@@ -1174,6 +1194,7 @@ int usb4_switch_add_ports(struct tb_switch *sw);
 void usb4_switch_remove_ports(struct tb_switch *sw);
 
 int usb4_port_unlock(struct tb_port *port);
+int usb4_port_hotplug_enable(struct tb_port *port);
 int usb4_port_configure(struct tb_port *port);
 void usb4_port_unconfigure(struct tb_port *port);
 int usb4_port_configure_xdomain(struct tb_port *port, struct tb_xdomain *xd);
@@ -1182,6 +1203,13 @@ int usb4_port_router_offline(struct tb_port *port);
 int usb4_port_router_online(struct tb_port *port);
 int usb4_port_enumerate_retimers(struct tb_port *port);
 bool usb4_port_clx_supported(struct tb_port *port);
+int usb4_port_margining_caps(struct tb_port *port, u32 *caps);
+int usb4_port_hw_margin(struct tb_port *port, unsigned int lanes,
+                       unsigned int ber_level, bool timing, bool right_high,
+                       u32 *results);
+int usb4_port_sw_margin(struct tb_port *port, unsigned int lanes, bool timing,
+                       bool right_high, u32 counter);
+int usb4_port_sw_margin_errors(struct tb_port *port, u32 *errors);
 
 int usb4_port_retimer_set_inbound_sbtx(struct tb_port *port, u8 index);
 int usb4_port_retimer_read(struct tb_port *port, u8 index, u8 reg, void *buf,
@@ -1264,6 +1292,8 @@ void tb_debugfs_init(void);
 void tb_debugfs_exit(void);
 void tb_switch_debugfs_init(struct tb_switch *sw);
 void tb_switch_debugfs_remove(struct tb_switch *sw);
+void tb_xdomain_debugfs_init(struct tb_xdomain *xd);
+void tb_xdomain_debugfs_remove(struct tb_xdomain *xd);
 void tb_service_debugfs_init(struct tb_service *svc);
 void tb_service_debugfs_remove(struct tb_service *svc);
 #else
@@ -1271,6 +1301,8 @@ static inline void tb_debugfs_init(void) { }
 static inline void tb_debugfs_exit(void) { }
 static inline void tb_switch_debugfs_init(struct tb_switch *sw) { }
 static inline void tb_switch_debugfs_remove(struct tb_switch *sw) { }
+static inline void tb_xdomain_debugfs_init(struct tb_xdomain *xd) { }
+static inline void tb_xdomain_debugfs_remove(struct tb_xdomain *xd) { }
 static inline void tb_service_debugfs_init(struct tb_service *svc) { }
 static inline void tb_service_debugfs_remove(struct tb_service *svc) { }
 #endif
index 1660541..86319dc 100644 (file)
@@ -308,6 +308,7 @@ struct tb_regs_port_header {
 #define ADP_CS_5                               0x05
 #define ADP_CS_5_LCA_MASK                      GENMASK(28, 22)
 #define ADP_CS_5_LCA_SHIFT                     22
+#define ADP_CS_5_DHP                           BIT(31)
 
 /* TMU adapter registers */
 #define TMU_ADP_CS_3                           0x03
@@ -324,6 +325,7 @@ struct tb_regs_port_header {
 #define LANE_ADP_CS_0_SUPPORTED_WIDTH_DUAL     0x2
 #define LANE_ADP_CS_0_CL0S_SUPPORT             BIT(26)
 #define LANE_ADP_CS_0_CL1_SUPPORT              BIT(27)
+#define LANE_ADP_CS_0_CL2_SUPPORT              BIT(28)
 #define LANE_ADP_CS_1                          0x01
 #define LANE_ADP_CS_1_TARGET_SPEED_MASK                GENMASK(3, 0)
 #define LANE_ADP_CS_1_TARGET_SPEED_GEN3                0xc
@@ -333,6 +335,7 @@ struct tb_regs_port_header {
 #define LANE_ADP_CS_1_TARGET_WIDTH_DUAL                0x3
 #define LANE_ADP_CS_1_CL0S_ENABLE              BIT(10)
 #define LANE_ADP_CS_1_CL1_ENABLE               BIT(11)
+#define LANE_ADP_CS_1_CL2_ENABLE               BIT(12)
 #define LANE_ADP_CS_1_LD                       BIT(14)
 #define LANE_ADP_CS_1_LB                       BIT(15)
 #define LANE_ADP_CS_1_CURRENT_SPEED_MASK       GENMASK(19, 16)
index a386228..f986854 100644 (file)
@@ -1046,6 +1046,26 @@ int usb4_port_unlock(struct tb_port *port)
        return tb_port_write(port, &val, TB_CFG_PORT, ADP_CS_4, 1);
 }
 
+/**
+ * usb4_port_hotplug_enable() - Enables hotplug for a port
+ * @port: USB4 port to operate on
+ *
+ * Enables hot plug events on a given port. This is only intended
+ * to be used on lane, DP-IN, and DP-OUT adapters.
+ */
+int usb4_port_hotplug_enable(struct tb_port *port)
+{
+       int ret;
+       u32 val;
+
+       ret = tb_port_read(port, &val, TB_CFG_PORT, ADP_CS_5, 1);
+       if (ret)
+               return ret;
+
+       val &= ~ADP_CS_5_DHP;
+       return tb_port_write(port, &val, TB_CFG_PORT, ADP_CS_5, 1);
+}
+
 static int usb4_port_set_configured(struct tb_port *port, bool configured)
 {
        int ret;
@@ -1386,6 +1406,126 @@ bool usb4_port_clx_supported(struct tb_port *port)
        return !!(val & PORT_CS_18_CPS);
 }
 
+/**
+ * usb4_port_margining_caps() - Read USB4 port marginig capabilities
+ * @port: USB4 port
+ * @caps: Array with at least two elements to hold the results
+ *
+ * Reads the USB4 port lane margining capabilities into @caps.
+ */
+int usb4_port_margining_caps(struct tb_port *port, u32 *caps)
+{
+       int ret;
+
+       ret = usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0,
+                             USB4_SB_OPCODE_READ_LANE_MARGINING_CAP, 500);
+       if (ret)
+               return ret;
+
+       return usb4_port_sb_read(port, USB4_SB_TARGET_ROUTER, 0,
+                                USB4_SB_DATA, caps, sizeof(*caps) * 2);
+}
+
+/**
+ * usb4_port_hw_margin() - Run hardware lane margining on port
+ * @port: USB4 port
+ * @lanes: Which lanes to run (must match the port capabilities). Can be
+ *        %0, %1 or %7.
+ * @ber_level: BER level contour value
+ * @timing: Perform timing margining instead of voltage
+ * @right_high: Use Right/high margin instead of left/low
+ * @results: Array with at least two elements to hold the results
+ *
+ * Runs hardware lane margining on USB4 port and returns the result in
+ * @results.
+ */
+int usb4_port_hw_margin(struct tb_port *port, unsigned int lanes,
+                       unsigned int ber_level, bool timing, bool right_high,
+                       u32 *results)
+{
+       u32 val;
+       int ret;
+
+       val = lanes;
+       if (timing)
+               val |= USB4_MARGIN_HW_TIME;
+       if (right_high)
+               val |= USB4_MARGIN_HW_RH;
+       if (ber_level)
+               val |= (ber_level << USB4_MARGIN_HW_BER_SHIFT) &
+                       USB4_MARGIN_HW_BER_MASK;
+
+       ret = usb4_port_sb_write(port, USB4_SB_TARGET_ROUTER, 0,
+                                USB4_SB_METADATA, &val, sizeof(val));
+       if (ret)
+               return ret;
+
+       ret = usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0,
+                             USB4_SB_OPCODE_RUN_HW_LANE_MARGINING, 2500);
+       if (ret)
+               return ret;
+
+       return usb4_port_sb_read(port, USB4_SB_TARGET_ROUTER, 0,
+                                USB4_SB_DATA, results, sizeof(*results) * 2);
+}
+
+/**
+ * usb4_port_sw_margin() - Run software lane margining on port
+ * @port: USB4 port
+ * @lanes: Which lanes to run (must match the port capabilities). Can be
+ *        %0, %1 or %7.
+ * @timing: Perform timing margining instead of voltage
+ * @right_high: Use Right/high margin instead of left/low
+ * @counter: What to do with the error counter
+ *
+ * Runs software lane margining on USB4 port. Read back the error
+ * counters by calling usb4_port_sw_margin_errors(). Returns %0 in
+ * success and negative errno otherwise.
+ */
+int usb4_port_sw_margin(struct tb_port *port, unsigned int lanes, bool timing,
+                       bool right_high, u32 counter)
+{
+       u32 val;
+       int ret;
+
+       val = lanes;
+       if (timing)
+               val |= USB4_MARGIN_SW_TIME;
+       if (right_high)
+               val |= USB4_MARGIN_SW_RH;
+       val |= (counter << USB4_MARGIN_SW_COUNTER_SHIFT) &
+               USB4_MARGIN_SW_COUNTER_MASK;
+
+       ret = usb4_port_sb_write(port, USB4_SB_TARGET_ROUTER, 0,
+                                USB4_SB_METADATA, &val, sizeof(val));
+       if (ret)
+               return ret;
+
+       return usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0,
+                              USB4_SB_OPCODE_RUN_SW_LANE_MARGINING, 2500);
+}
+
+/**
+ * usb4_port_sw_margin_errors() - Read the software margining error counters
+ * @port: USB4 port
+ * @errors: Error metadata is copied here.
+ *
+ * This reads back the software margining error counters from the port.
+ * Returns %0 in success and negative errno otherwise.
+ */
+int usb4_port_sw_margin_errors(struct tb_port *port, u32 *errors)
+{
+       int ret;
+
+       ret = usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0,
+                             USB4_SB_OPCODE_READ_SW_MARGIN_ERR, 150);
+       if (ret)
+               return ret;
+
+       return usb4_port_sb_read(port, USB4_SB_TARGET_ROUTER, 0,
+                                USB4_SB_METADATA, errors, sizeof(*errors));
+}
+
 static inline int usb4_port_retimer_op(struct tb_port *port, u8 index,
                                       enum usb4_sb_opcode opcode,
                                       int timeout_msec)
index c31c0d9..bbb248a 100644 (file)
@@ -877,7 +877,7 @@ static ssize_t key_show(struct device *dev, struct device_attribute *attr,
         * It should be null terminated but anything else is pretty much
         * allowed.
         */
-       return sprintf(buf, "%*pE\n", (int)strlen(svc->key), svc->key);
+       return sysfs_emit(buf, "%*pE\n", (int)strlen(svc->key), svc->key);
 }
 static DEVICE_ATTR_RO(key);
 
@@ -903,7 +903,7 @@ static ssize_t prtcid_show(struct device *dev, struct device_attribute *attr,
 {
        struct tb_service *svc = container_of(dev, struct tb_service, dev);
 
-       return sprintf(buf, "%u\n", svc->prtcid);
+       return sysfs_emit(buf, "%u\n", svc->prtcid);
 }
 static DEVICE_ATTR_RO(prtcid);
 
@@ -912,7 +912,7 @@ static ssize_t prtcvers_show(struct device *dev, struct device_attribute *attr,
 {
        struct tb_service *svc = container_of(dev, struct tb_service, dev);
 
-       return sprintf(buf, "%u\n", svc->prtcvers);
+       return sysfs_emit(buf, "%u\n", svc->prtcvers);
 }
 static DEVICE_ATTR_RO(prtcvers);
 
@@ -921,7 +921,7 @@ static ssize_t prtcrevs_show(struct device *dev, struct device_attribute *attr,
 {
        struct tb_service *svc = container_of(dev, struct tb_service, dev);
 
-       return sprintf(buf, "%u\n", svc->prtcrevs);
+       return sysfs_emit(buf, "%u\n", svc->prtcrevs);
 }
 static DEVICE_ATTR_RO(prtcrevs);
 
@@ -930,7 +930,7 @@ static ssize_t prtcstns_show(struct device *dev, struct device_attribute *attr,
 {
        struct tb_service *svc = container_of(dev, struct tb_service, dev);
 
-       return sprintf(buf, "0x%08x\n", svc->prtcstns);
+       return sysfs_emit(buf, "0x%08x\n", svc->prtcstns);
 }
 static DEVICE_ATTR_RO(prtcstns);
 
@@ -1131,11 +1131,6 @@ static int populate_properties(struct tb_xdomain *xd,
        return 0;
 }
 
-static inline struct tb_switch *tb_xdomain_parent(struct tb_xdomain *xd)
-{
-       return tb_to_switch(xd->dev.parent);
-}
-
 static int tb_xdomain_update_link_attributes(struct tb_xdomain *xd)
 {
        bool change = false;
@@ -1440,6 +1435,8 @@ static int tb_xdomain_get_properties(struct tb_xdomain *xd)
                if (xd->vendor_name && xd->device_name)
                        dev_info(&xd->dev, "%s %s\n", xd->vendor_name,
                                 xd->device_name);
+
+               tb_xdomain_debugfs_init(xd);
        } else {
                kobject_uevent(&xd->dev.kobj, KOBJ_CHANGE);
        }
@@ -1664,7 +1661,7 @@ static ssize_t device_show(struct device *dev, struct device_attribute *attr,
 {
        struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev);
 
-       return sprintf(buf, "%#x\n", xd->device);
+       return sysfs_emit(buf, "%#x\n", xd->device);
 }
 static DEVICE_ATTR_RO(device);
 
@@ -1676,7 +1673,7 @@ device_name_show(struct device *dev, struct device_attribute *attr, char *buf)
 
        if (mutex_lock_interruptible(&xd->lock))
                return -ERESTARTSYS;
-       ret = sprintf(buf, "%s\n", xd->device_name ? xd->device_name : "");
+       ret = sysfs_emit(buf, "%s\n", xd->device_name ?: "");
        mutex_unlock(&xd->lock);
 
        return ret;
@@ -1688,7 +1685,7 @@ static ssize_t maxhopid_show(struct device *dev, struct device_attribute *attr,
 {
        struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev);
 
-       return sprintf(buf, "%d\n", xd->remote_max_hopid);
+       return sysfs_emit(buf, "%d\n", xd->remote_max_hopid);
 }
 static DEVICE_ATTR_RO(maxhopid);
 
@@ -1697,7 +1694,7 @@ static ssize_t vendor_show(struct device *dev, struct device_attribute *attr,
 {
        struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev);
 
-       return sprintf(buf, "%#x\n", xd->vendor);
+       return sysfs_emit(buf, "%#x\n", xd->vendor);
 }
 static DEVICE_ATTR_RO(vendor);
 
@@ -1709,7 +1706,7 @@ vendor_name_show(struct device *dev, struct device_attribute *attr, char *buf)
 
        if (mutex_lock_interruptible(&xd->lock))
                return -ERESTARTSYS;
-       ret = sprintf(buf, "%s\n", xd->vendor_name ? xd->vendor_name : "");
+       ret = sysfs_emit(buf, "%s\n", xd->vendor_name ?: "");
        mutex_unlock(&xd->lock);
 
        return ret;
@@ -1721,7 +1718,7 @@ static ssize_t unique_id_show(struct device *dev, struct device_attribute *attr,
 {
        struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev);
 
-       return sprintf(buf, "%pUb\n", xd->remote_uuid);
+       return sysfs_emit(buf, "%pUb\n", xd->remote_uuid);
 }
 static DEVICE_ATTR_RO(unique_id);
 
@@ -1730,7 +1727,7 @@ static ssize_t speed_show(struct device *dev, struct device_attribute *attr,
 {
        struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev);
 
-       return sprintf(buf, "%u.0 Gb/s\n", xd->link_speed);
+       return sysfs_emit(buf, "%u.0 Gb/s\n", xd->link_speed);
 }
 
 static DEVICE_ATTR(rx_speed, 0444, speed_show, NULL);
@@ -1741,7 +1738,7 @@ static ssize_t lanes_show(struct device *dev, struct device_attribute *attr,
 {
        struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev);
 
-       return sprintf(buf, "%u\n", xd->link_width);
+       return sysfs_emit(buf, "%u\n", xd->link_width);
 }
 
 static DEVICE_ATTR(rx_lanes, 0444, lanes_show, NULL);
@@ -1940,6 +1937,8 @@ static int unregister_service(struct device *dev, void *data)
  */
 void tb_xdomain_remove(struct tb_xdomain *xd)
 {
+       tb_xdomain_debugfs_remove(xd);
+
        stop_handshake(xd);
 
        device_for_each_child_reverse(&xd->dev, xd, unregister_service);
index 3622171..1cdb875 100644 (file)
@@ -1026,7 +1026,7 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
        /* public fields */
 
        instance->driver = driver;
-       strlcpy(instance->driver_name, driver->driver_name,
+       strscpy(instance->driver_name, driver->driver_name,
                sizeof(instance->driver_name));
 
        instance->usb_dev = usb_dev;
index dc068e9..2bc5d09 100644 (file)
@@ -110,8 +110,6 @@ static int cdns3_plat_probe(struct platform_device *pdev)
        cdns->wakeup_irq = platform_get_irq_byname_optional(pdev, "wakeup");
        if (cdns->wakeup_irq == -EPROBE_DEFER)
                return cdns->wakeup_irq;
-       else if (cdns->wakeup_irq == 0)
-               return -EINVAL;
 
        if (cdns->wakeup_irq < 0) {
                dev_dbg(dev, "couldn't get wakeup irq\n");
index 661818e..c815824 100644 (file)
@@ -34,26 +34,26 @@ config USB_CHIPIDEA_HOST
          ChipIdea driver.
 
 config USB_CHIPIDEA_PCI
-       tristate "Enable PCI glue driver" if EMBEDDED
+       tristate "Enable PCI glue driver" if EXPERT
        depends on USB_PCI
        depends on NOP_USB_XCEIV
        default USB_CHIPIDEA
 
 config USB_CHIPIDEA_MSM
-       tristate "Enable MSM hsusb glue driver" if EMBEDDED
+       tristate "Enable MSM hsusb glue driver" if EXPERT
        default USB_CHIPIDEA
 
 config USB_CHIPIDEA_IMX
-       tristate "Enable i.MX USB glue driver" if EMBEDDED
+       tristate "Enable i.MX USB glue driver" if EXPERT
        depends on OF
        default USB_CHIPIDEA
 
 config USB_CHIPIDEA_GENERIC
-       tristate "Enable generic USB2 glue driver" if EMBEDDED
+       tristate "Enable generic USB2 glue driver" if EXPERT
        default USB_CHIPIDEA
 
 config USB_CHIPIDEA_TEGRA
-       tristate "Enable Tegra USB glue driver" if EMBEDDED
+       tristate "Enable Tegra USB glue driver" if EXPERT
        depends on OF
        default USB_CHIPIDEA
 
index 89e1d82..dc86b12 100644 (file)
@@ -30,6 +30,7 @@ static const struct ci_hdrc_platform_data ci_default_pdata = {
 
 static const struct ci_hdrc_platform_data ci_zynq_pdata = {
        .capoffset      = DEF_CAPOFFSET,
+       .flags          = CI_HDRC_PHY_VBUS_CONTROL,
 };
 
 static const struct ci_hdrc_platform_data ci_zevio_pdata = {
index bdc3885..bc3634a 100644 (file)
@@ -63,6 +63,13 @@ static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
                priv->enabled = enable;
        }
 
+       if (ci->platdata->flags & CI_HDRC_PHY_VBUS_CONTROL) {
+               if (enable)
+                       usb_phy_vbus_on(ci->usb_phy);
+               else
+                       usb_phy_vbus_off(ci->usb_phy);
+       }
+
        if (enable && (ci->platdata->phy_mode == USBPHY_INTERFACE_MODE_HSIC)) {
                /*
                 * Marvell 28nm HSIC PHY requires forcing the port to HS mode.
index 61b157b..ada78da 100644 (file)
@@ -471,6 +471,10 @@ static void ci_otg_drv_vbus(struct otg_fsm *fsm, int on)
                                return;
                        }
                }
+
+               if (ci->platdata->flags & CI_HDRC_PHY_VBUS_CONTROL)
+                       usb_phy_vbus_on(ci->usb_phy);
+
                /* Disable data pulse irq */
                hw_write_otgsc(ci, OTGSC_DPIE, 0);
 
@@ -480,6 +484,9 @@ static void ci_otg_drv_vbus(struct otg_fsm *fsm, int on)
                if (ci->platdata->reg_vbus)
                        regulator_disable(ci->platdata->reg_vbus);
 
+               if (ci->platdata->flags & CI_HDRC_PHY_VBUS_CONTROL)
+                       usb_phy_vbus_off(ci->usb_phy);
+
                fsm->a_bus_drop = 1;
                fsm->a_bus_req = 0;
        }
index eebe782..1f0951b 100644 (file)
@@ -958,7 +958,7 @@ static void wdm_wwan_rx(struct wdm_device *desc, int length)
        if (!skb)
                return;
 
-       memcpy(skb_put(skb, length), desc->inbuf, length);
+       skb_put_data(skb, desc->inbuf, length);
        wwan_port_rx(port, skb);
 
        /* inbuf has been copied, it is safe to check for outstanding data */
index 075f6b1..f204cec 100644 (file)
@@ -208,30 +208,28 @@ static void usb_decode_set_isoch_delay(__u8 wValue, char *str, size_t size)
        snprintf(str, size, "Set Isochronous Delay(Delay = %d ns)", wValue);
 }
 
-/**
- * usb_decode_ctrl - Returns human readable representation of control request.
- * @str: buffer to return a human-readable representation of control request.
- *       This buffer should have about 200 bytes.
- * @size: size of str buffer.
- * @bRequestType: matches the USB bmRequestType field
- * @bRequest: matches the USB bRequest field
- * @wValue: matches the USB wValue field (CPU byte order)
- * @wIndex: matches the USB wIndex field (CPU byte order)
- * @wLength: matches the USB wLength field (CPU byte order)
- *
- * Function returns decoded, formatted and human-readable description of
- * control request packet.
- *
- * The usage scenario for this is for tracepoints, so function as a return
- * use the same value as in parameters. This approach allows to use this
- * function in TP_printk
- *
- * Important: wValue, wIndex, wLength parameters before invoking this function
- * should be processed by le16_to_cpu macro.
- */
-const char *usb_decode_ctrl(char *str, size_t size, __u8 bRequestType,
-                           __u8 bRequest, __u16 wValue, __u16 wIndex,
-                           __u16 wLength)
+static void usb_decode_ctrl_generic(char *str, size_t size, __u8 bRequestType,
+                                   __u8 bRequest, __u16 wValue, __u16 wIndex,
+                                   __u16 wLength)
+{
+       u8 recip = bRequestType & USB_RECIP_MASK;
+       u8 type = bRequestType & USB_TYPE_MASK;
+
+       snprintf(str, size,
+                "Type=%s Recipient=%s Dir=%s bRequest=%u wValue=%u wIndex=%u wLength=%u",
+                (type == USB_TYPE_STANDARD)    ? "Standard" :
+                (type == USB_TYPE_VENDOR)      ? "Vendor" :
+                (type == USB_TYPE_CLASS)       ? "Class" : "Unknown",
+                (recip == USB_RECIP_DEVICE)    ? "Device" :
+                (recip == USB_RECIP_INTERFACE) ? "Interface" :
+                (recip == USB_RECIP_ENDPOINT)  ? "Endpoint" : "Unknown",
+                (bRequestType & USB_DIR_IN)    ? "IN" : "OUT",
+                bRequest, wValue, wIndex, wLength);
+}
+
+static void usb_decode_ctrl_standard(char *str, size_t size, __u8 bRequestType,
+                                    __u8 bRequest, __u16 wValue, __u16 wIndex,
+                                    __u16 wLength)
 {
        switch (bRequest) {
        case USB_REQ_GET_STATUS:
@@ -272,14 +270,48 @@ const char *usb_decode_ctrl(char *str, size_t size, __u8 bRequestType,
                usb_decode_set_isoch_delay(wValue, str, size);
                break;
        default:
-               snprintf(str, size, "%02x %02x %02x %02x %02x %02x %02x %02x",
-                        bRequestType, bRequest,
-                        (u8)(cpu_to_le16(wValue) & 0xff),
-                        (u8)(cpu_to_le16(wValue) >> 8),
-                        (u8)(cpu_to_le16(wIndex) & 0xff),
-                        (u8)(cpu_to_le16(wIndex) >> 8),
-                        (u8)(cpu_to_le16(wLength) & 0xff),
-                        (u8)(cpu_to_le16(wLength) >> 8));
+               usb_decode_ctrl_generic(str, size, bRequestType, bRequest,
+                                       wValue, wIndex, wLength);
+               break;
+       }
+}
+
+/**
+ * usb_decode_ctrl - Returns human readable representation of control request.
+ * @str: buffer to return a human-readable representation of control request.
+ *       This buffer should have about 200 bytes.
+ * @size: size of str buffer.
+ * @bRequestType: matches the USB bmRequestType field
+ * @bRequest: matches the USB bRequest field
+ * @wValue: matches the USB wValue field (CPU byte order)
+ * @wIndex: matches the USB wIndex field (CPU byte order)
+ * @wLength: matches the USB wLength field (CPU byte order)
+ *
+ * Function returns decoded, formatted and human-readable description of
+ * control request packet.
+ *
+ * The usage scenario for this is for tracepoints, so function as a return
+ * use the same value as in parameters. This approach allows to use this
+ * function in TP_printk
+ *
+ * Important: wValue, wIndex, wLength parameters before invoking this function
+ * should be processed by le16_to_cpu macro.
+ */
+const char *usb_decode_ctrl(char *str, size_t size, __u8 bRequestType,
+                           __u8 bRequest, __u16 wValue, __u16 wIndex,
+                           __u16 wLength)
+{
+       switch (bRequestType & USB_TYPE_MASK) {
+       case USB_TYPE_STANDARD:
+               usb_decode_ctrl_standard(str, size, bRequestType, bRequest,
+                                        wValue, wIndex, wLength);
+               break;
+       case USB_TYPE_VENDOR:
+       case USB_TYPE_CLASS:
+       default:
+               usb_decode_ctrl_generic(str, size, bRequestType, bRequest,
+                                       wValue, wIndex, wLength);
+               break;
        }
 
        return str;
index 0a4f441..d7c8461 100644 (file)
@@ -233,7 +233,7 @@ err:
        return 0;
 }
 
-static int ulpi_regs_read(struct seq_file *seq, void *data)
+static int ulpi_regs_show(struct seq_file *seq, void *data)
 {
        struct ulpi *ulpi = seq->private;
 
@@ -269,21 +269,7 @@ static int ulpi_regs_read(struct seq_file *seq, void *data)
 
        return 0;
 }
-
-static int ulpi_regs_open(struct inode *inode, struct file *f)
-{
-       struct ulpi *ulpi = inode->i_private;
-
-       return single_open(f, ulpi_regs_read, ulpi);
-}
-
-static const struct file_operations ulpi_regs_ops = {
-       .owner = THIS_MODULE,
-       .open = ulpi_regs_open,
-       .release = single_release,
-       .read = seq_read,
-       .llseek = seq_lseek
-};
+DEFINE_SHOW_ATTRIBUTE(ulpi_regs);
 
 #define ULPI_ROOT debugfs_lookup(KBUILD_MODNAME, NULL)
 
@@ -316,7 +302,7 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi)
        }
 
        root = debugfs_create_dir(dev_name(dev), ULPI_ROOT);
-       debugfs_create_file("regs", 0444, root, ulpi, &ulpi_regs_ops);
+       debugfs_create_file("regs", 0444, root, ulpi, &ulpi_regs_fops);
 
        dev_dbg(&ulpi->dev, "registered ULPI PHY: vendor %04x, product %04x\n",
                ulpi->id.vendor, ulpi->id.product);
index b39c9f1..e20874c 100644 (file)
@@ -208,10 +208,8 @@ static int usb_conn_probe(struct platform_device *pdev)
        if (PTR_ERR(info->vbus) == -ENODEV)
                info->vbus = NULL;
 
-       if (IS_ERR(info->vbus)) {
-               ret = PTR_ERR(info->vbus);
-               return dev_err_probe(dev, ret, "failed to get vbus :%d\n", ret);
-       }
+       if (IS_ERR(info->vbus))
+               return dev_err_probe(dev, PTR_ERR(info->vbus), "failed to get vbus\n");
 
        info->role_sw = usb_role_switch_get(dev);
        if (IS_ERR(info->role_sw))
index b5b85bf..837f3e5 100644 (file)
@@ -1434,7 +1434,7 @@ static int proc_getdriver(struct usb_dev_state *ps, void __user *arg)
        if (!intf || !intf->dev.driver)
                ret = -ENODATA;
        else {
-               strlcpy(gd.driver, intf->dev.driver->name,
+               strscpy(gd.driver, intf->dev.driver->name,
                                sizeof(gd.driver));
                ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0);
        }
index 482dae7..9b77f49 100644 (file)
@@ -157,7 +157,6 @@ static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd,
 /**
  * usb_hcd_pci_probe - initialize PCI-based HCDs
  * @dev: USB Host Controller being probed
- * @id: pci hotplug id connecting controller to HCD framework
  * @driver: USB HC driver handle
  *
  * Context: task context, might sleep
@@ -170,8 +169,7 @@ static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd,
  *
  * Return: 0 if successful.
  */
-int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id,
-                     const struct hc_driver *driver)
+int usb_hcd_pci_probe(struct pci_dev *dev, const struct hc_driver *driver)
 {
        struct usb_hcd          *hcd;
        int                     retval;
@@ -180,9 +178,6 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id,
        if (usb_disabled())
                return -ENODEV;
 
-       if (!id)
-               return -EINVAL;
-
        if (!driver)
                return -EINVAL;
 
index 94b305b..faeaace 100644 (file)
@@ -1474,7 +1474,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
                                                urb->sg,
                                                urb->num_sgs,
                                                dir);
-                               if (n <= 0)
+                               if (!n)
                                        ret = -EAGAIN;
                                else
                                        urb->transfer_flags |= URB_DMA_MAP_SG;
@@ -2158,21 +2158,14 @@ static struct urb *request_single_step_set_feature_urb(
 {
        struct urb *urb;
        struct usb_hcd *hcd = bus_to_hcd(udev->bus);
-       struct usb_host_endpoint *ep;
 
        urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!urb)
                return NULL;
 
        urb->pipe = usb_rcvctrlpipe(udev, 0);
-       ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out)
-                               [usb_pipeendpoint(urb->pipe)];
-       if (!ep) {
-               usb_free_urb(urb);
-               return NULL;
-       }
 
-       urb->ep = ep;
+       urb->ep = &udev->ep0;
        urb->dev = udev;
        urb->setup_packet = (void *)dr;
        urb->transfer_buffer = buf;
index f99a65a..0722d21 100644 (file)
@@ -388,6 +388,15 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* Kingston DataTraveler 3.0 */
        { USB_DEVICE(0x0951, 0x1666), .driver_info = USB_QUIRK_NO_LPM },
 
+       /* NVIDIA Jetson devices in Force Recovery mode */
+       { USB_DEVICE(0x0955, 0x7018), .driver_info = USB_QUIRK_RESET_RESUME },
+       { USB_DEVICE(0x0955, 0x7019), .driver_info = USB_QUIRK_RESET_RESUME },
+       { USB_DEVICE(0x0955, 0x7418), .driver_info = USB_QUIRK_RESET_RESUME },
+       { USB_DEVICE(0x0955, 0x7721), .driver_info = USB_QUIRK_RESET_RESUME },
+       { USB_DEVICE(0x0955, 0x7c18), .driver_info = USB_QUIRK_RESET_RESUME },
+       { USB_DEVICE(0x0955, 0x7e19), .driver_info = USB_QUIRK_RESET_RESUME },
+       { USB_DEVICE(0x0955, 0x7f21), .driver_info = USB_QUIRK_RESET_RESUME },
+
        /* X-Rite/Gretag-Macbeth Eye-One Pro display colorimeter */
        { USB_DEVICE(0x0971, 0x2000), .driver_info = USB_QUIRK_NO_SET_INTF },
 
@@ -437,6 +446,10 @@ static const struct usb_device_id usb_quirk_list[] = {
        { USB_DEVICE(0x1532, 0x0116), .driver_info =
                        USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
 
+       /* Lenovo ThinkPad OneLink+ Dock twin hub controllers (VIA Labs VL812) */
+       { USB_DEVICE(0x17ef, 0x1018), .driver_info = USB_QUIRK_RESET_RESUME },
+       { USB_DEVICE(0x17ef, 0x1019), .driver_info = USB_QUIRK_RESET_RESUME },
+
        /* Lenovo USB-C to Ethernet Adapter RTL8153-04 */
        { USB_DEVICE(0x17ef, 0x720c), .driver_info = USB_QUIRK_NO_LPM },
 
index dc4fc72..5635e4d 100644 (file)
@@ -3,36 +3,6 @@
  * core.c - DesignWare HS OTG Controller common routines
  *
  * Copyright (C) 2004-2013 Synopsys, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 /*
index 0683852..40cf288 100644 (file)
@@ -3,36 +3,6 @@
  * core.h - DesignWare HS OTG Controller common declarations
  *
  * Copyright (C) 2004-2013 Synopsys, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef __DWC2_CORE_H__
index a5c52b2..158ede7 100644 (file)
@@ -3,36 +3,6 @@
  * core_intr.c - DesignWare HS OTG Controller common interrupt handling
  *
  * Copyright (C) 2004-2013 Synopsys, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 /*
index aaf7b9f..657f1f6 100644 (file)
@@ -3,36 +3,6 @@
  * hcd.c - DesignWare HS OTG Controller host-mode routines
  *
  * Copyright (C) 2004-2013 Synopsys, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 /*
index ea02ee6..b7254d9 100644 (file)
@@ -3,37 +3,8 @@
  * hcd.h - DesignWare HS OTG Controller host-mode declarations
  *
  * Copyright (C) 2004-2013 Synopsys, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+
 #ifndef __DWC2_HCD_H__
 #define __DWC2_HCD_H__
 
index a858b5f..6b4d825 100644 (file)
@@ -3,36 +3,6 @@
  * hcd_ddma.c - DesignWare HS OTG Controller descriptor DMA routines
  *
  * Copyright (C) 2004-2013 Synopsys, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 /*
index d5f4ec1..c9740ca 100644 (file)
@@ -3,36 +3,6 @@
  * hcd_intr.c - DesignWare HS OTG Controller host-mode interrupt handling
  *
  * Copyright (C) 2004-2013 Synopsys, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 /*
index 24beff6..0a11455 100644 (file)
@@ -3,36 +3,6 @@
  * hcd_queue.c - DesignWare HS OTG Controller host queuing routines
  *
  * Copyright (C) 2004-2013 Synopsys, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 /*
index 6b16fbf..13abdd5 100644 (file)
@@ -3,36 +3,6 @@
  * hw.h - DesignWare HS OTG Controller hardware definitions
  *
  * Copyright 2004-2013 Synopsys, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef __DWC2_HW_H__
index fdb8a42..8eab5f3 100644 (file)
@@ -1,36 +1,6 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
 /*
  * Copyright (C) 2004-2016 Synopsys, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include <linux/kernel.h>
index a93559b..b7306ed 100644 (file)
@@ -3,36 +3,6 @@
  * pci.c - DesignWare HS OTG Controller PCI driver
  *
  * Copyright (C) 2004-2013 Synopsys, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 /*
index fd0ccf6..ec4ace0 100644 (file)
@@ -3,36 +3,6 @@
  * platform.c - DesignWare HS OTG Controller platform driver
  *
  * Copyright (C) Matthijs Kooijman <matthijs@stdin.nl>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include <linux/kernel.h>
index d0237b3..ea51624 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/of.h>
-#include <linux/of_graph.h>
 #include <linux/acpi.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/reset.h>
@@ -86,7 +85,7 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
                 * mode. If the controller supports DRD but the dr_mode is not
                 * specified or set to OTG, then set the mode to peripheral.
                 */
-               if (mode == USB_DR_MODE_OTG && !dwc->edev &&
+               if (mode == USB_DR_MODE_OTG &&
                    (!IS_ENABLED(CONFIG_USB_ROLE_SWITCH) ||
                     !device_property_read_bool(dwc->dev, "usb-role-switch")) &&
                    !DWC3_VER_IS_PRIOR(DWC3, 330A))
@@ -408,6 +407,10 @@ static void dwc3_ref_clk_period(struct dwc3 *dwc)
        reg |= FIELD_PREP(DWC3_GFLADJ_REFCLK_FLADJ_MASK, fladj)
            |  FIELD_PREP(DWC3_GFLADJ_240MHZDECR, decr >> 1)
            |  FIELD_PREP(DWC3_GFLADJ_240MHZDECR_PLS1, decr & 1);
+
+       if (dwc->gfladj_refclk_lpm_sel)
+               reg |=  DWC3_GFLADJ_REFCLK_LPM_SEL;
+
        dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
 }
 
@@ -789,7 +792,7 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
        else
                reg |= DWC3_GUSB2PHYCFG_ENBLSLPM;
 
-       if (dwc->dis_u2_freeclk_exists_quirk)
+       if (dwc->dis_u2_freeclk_exists_quirk || dwc->gfladj_refclk_lpm_sel)
                reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
 
        dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
@@ -1180,6 +1183,21 @@ static int dwc3_core_init(struct dwc3 *dwc)
                dwc3_writel(dwc->regs, DWC3_GUCTL2, reg);
        }
 
+       /*
+        * When configured in HOST mode, after issuing U3/L2 exit controller
+        * fails to send proper CRC checksum in CRC5 feild. Because of this
+        * behaviour Transaction Error is generated, resulting in reset and
+        * re-enumeration of usb device attached. All the termsel, xcvrsel,
+        * opmode becomes 0 during end of resume. Enabling bit 10 of GUCTL1
+        * will correct this problem. This option is to support certain
+        * legacy ULPI PHYs.
+        */
+       if (dwc->resume_hs_terminations) {
+               reg = dwc3_readl(dwc->regs, DWC3_GUCTL1);
+               reg |= DWC3_GUCTL1_RESUME_OPMODE_HS_HOST;
+               dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
+       }
+
        if (!DWC3_VER_IS_PRIOR(DWC3, 250A)) {
                reg = dwc3_readl(dwc->regs, DWC3_GUCTL1);
 
@@ -1523,8 +1541,12 @@ static void dwc3_get_properties(struct dwc3 *dwc)
                                "snps,dis-del-phy-power-chg-quirk");
        dwc->dis_tx_ipgap_linecheck_quirk = device_property_read_bool(dev,
                                "snps,dis-tx-ipgap-linecheck-quirk");
+       dwc->resume_hs_terminations = device_property_read_bool(dev,
+                               "snps,resume-hs-terminations");
        dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev,
                                "snps,parkmode-disable-ss-quirk");
+       dwc->gfladj_refclk_lpm_sel = device_property_read_bool(dev,
+                               "snps,gfladj-refclk-lpm-sel-quirk");
 
        dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
                                "snps,tx_de_emphasis_quirk");
@@ -1668,46 +1690,6 @@ static void dwc3_check_params(struct dwc3 *dwc)
        }
 }
 
-static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
-{
-       struct device *dev = dwc->dev;
-       struct device_node *np_phy;
-       struct extcon_dev *edev = NULL;
-       const char *name;
-
-       if (device_property_read_bool(dev, "extcon"))
-               return extcon_get_edev_by_phandle(dev, 0);
-
-       /*
-        * Device tree platforms should get extcon via phandle.
-        * On ACPI platforms, we get the name from a device property.
-        * This device property is for kernel internal use only and
-        * is expected to be set by the glue code.
-        */
-       if (device_property_read_string(dev, "linux,extcon-name", &name) == 0)
-               return extcon_get_extcon_dev(name);
-
-       /*
-        * Try to get an extcon device from the USB PHY controller's "port"
-        * node. Check if it has the "port" node first, to avoid printing the
-        * error message from underlying code, as it's a valid case: extcon
-        * device (and "port" node) may be missing in case of "usb-role-switch"
-        * or OTG mode.
-        */
-       np_phy = of_parse_phandle(dev->of_node, "phys", 0);
-       if (of_graph_is_present(np_phy)) {
-               struct device_node *np_conn;
-
-               np_conn = of_graph_get_remote_node(np_phy, -1, -1);
-               if (np_conn)
-                       edev = extcon_find_edev_by_node(np_conn);
-               of_node_put(np_conn);
-       }
-       of_node_put(np_phy);
-
-       return edev;
-}
-
 static int dwc3_probe(struct platform_device *pdev)
 {
        struct device           *dev = &pdev->dev;
@@ -1753,8 +1735,10 @@ static int dwc3_probe(struct platform_device *pdev)
        dwc3_get_properties(dwc);
 
        dwc->reset = devm_reset_control_array_get_optional_shared(dev);
-       if (IS_ERR(dwc->reset))
-               return PTR_ERR(dwc->reset);
+       if (IS_ERR(dwc->reset)) {
+               ret = PTR_ERR(dwc->reset);
+               goto put_usb_psy;
+       }
 
        if (dev->of_node) {
                /*
@@ -1764,45 +1748,57 @@ static int dwc3_probe(struct platform_device *pdev)
                 * check for them to retain backwards compatibility.
                 */
                dwc->bus_clk = devm_clk_get_optional(dev, "bus_early");
-               if (IS_ERR(dwc->bus_clk))
-                       return dev_err_probe(dev, PTR_ERR(dwc->bus_clk),
-                                            "could not get bus clock\n");
+               if (IS_ERR(dwc->bus_clk)) {
+                       ret = dev_err_probe(dev, PTR_ERR(dwc->bus_clk),
+                                           "could not get bus clock\n");
+                       goto put_usb_psy;
+               }
 
                if (dwc->bus_clk == NULL) {
                        dwc->bus_clk = devm_clk_get_optional(dev, "bus_clk");
-                       if (IS_ERR(dwc->bus_clk))
-                               return dev_err_probe(dev, PTR_ERR(dwc->bus_clk),
-                                                    "could not get bus clock\n");
+                       if (IS_ERR(dwc->bus_clk)) {
+                               ret = dev_err_probe(dev, PTR_ERR(dwc->bus_clk),
+                                                   "could not get bus clock\n");
+                               goto put_usb_psy;
+                       }
                }
 
                dwc->ref_clk = devm_clk_get_optional(dev, "ref");
-               if (IS_ERR(dwc->ref_clk))
-                       return dev_err_probe(dev, PTR_ERR(dwc->ref_clk),
-                                            "could not get ref clock\n");
+               if (IS_ERR(dwc->ref_clk)) {
+                       ret = dev_err_probe(dev, PTR_ERR(dwc->ref_clk),
+                                           "could not get ref clock\n");
+                       goto put_usb_psy;
+               }
 
                if (dwc->ref_clk == NULL) {
                        dwc->ref_clk = devm_clk_get_optional(dev, "ref_clk");
-                       if (IS_ERR(dwc->ref_clk))
-                               return dev_err_probe(dev, PTR_ERR(dwc->ref_clk),
-                                                    "could not get ref clock\n");
+                       if (IS_ERR(dwc->ref_clk)) {
+                               ret = dev_err_probe(dev, PTR_ERR(dwc->ref_clk),
+                                                   "could not get ref clock\n");
+                               goto put_usb_psy;
+                       }
                }
 
                dwc->susp_clk = devm_clk_get_optional(dev, "suspend");
-               if (IS_ERR(dwc->susp_clk))
-                       return dev_err_probe(dev, PTR_ERR(dwc->susp_clk),
-                                            "could not get suspend clock\n");
+               if (IS_ERR(dwc->susp_clk)) {
+                       ret = dev_err_probe(dev, PTR_ERR(dwc->susp_clk),
+                                           "could not get suspend clock\n");
+                       goto put_usb_psy;
+               }
 
                if (dwc->susp_clk == NULL) {
                        dwc->susp_clk = devm_clk_get_optional(dev, "suspend_clk");
-                       if (IS_ERR(dwc->susp_clk))
-                               return dev_err_probe(dev, PTR_ERR(dwc->susp_clk),
-                                                    "could not get suspend clock\n");
+                       if (IS_ERR(dwc->susp_clk)) {
+                               ret = dev_err_probe(dev, PTR_ERR(dwc->susp_clk),
+                                                   "could not get suspend clock\n");
+                               goto put_usb_psy;
+                       }
                }
        }
 
        ret = reset_control_deassert(dwc->reset);
        if (ret)
-               return ret;
+               goto put_usb_psy;
 
        ret = dwc3_clk_enable(dwc);
        if (ret)
@@ -1844,13 +1840,6 @@ static int dwc3_probe(struct platform_device *pdev)
                goto err2;
        }
 
-       dwc->edev = dwc3_get_extcon(dwc);
-       if (IS_ERR(dwc->edev)) {
-               ret = PTR_ERR(dwc->edev);
-               dev_err_probe(dwc->dev, ret, "failed to get extcon\n");
-               goto err3;
-       }
-
        ret = dwc3_get_dr_mode(dwc);
        if (ret)
                goto err3;
@@ -1909,7 +1898,7 @@ disable_clks:
        dwc3_clk_disable(dwc);
 assert_reset:
        reset_control_assert(dwc->reset);
-
+put_usb_psy:
        if (dwc->usb_psy)
                power_supply_put(dwc->usb_psy);
 
@@ -1977,9 +1966,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
        case DWC3_GCTL_PRTCAP_DEVICE:
                if (pm_runtime_suspended(dwc->dev))
                        break;
-               spin_lock_irqsave(&dwc->lock, flags);
                dwc3_gadget_suspend(dwc);
-               spin_unlock_irqrestore(&dwc->lock, flags);
                synchronize_irq(dwc->irq_gadget);
                dwc3_core_exit(dwc);
                break;
@@ -2040,9 +2027,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
                        return ret;
 
                dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
-               spin_lock_irqsave(&dwc->lock, flags);
                dwc3_gadget_resume(dwc);
-               spin_unlock_irqrestore(&dwc->lock, flags);
                break;
        case DWC3_GCTL_PRTCAP_HOST:
                if (!PMSG_IS_AUTO(msg) && !device_may_wakeup(dwc->dev)) {
index 4fe4287..8f9959b 100644 (file)
 #define DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK        BIT(26)
 #define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW          BIT(24)
 #define DWC3_GUCTL1_PARKMODE_DISABLE_SS                BIT(17)
+#define DWC3_GUCTL1_RESUME_OPMODE_HS_HOST      BIT(10)
 
 /* Global Status Register */
 #define DWC3_GSTS_OTG_IP       BIT(10)
 #define DWC3_GFLADJ_30MHZ_SDBND_SEL            BIT(7)
 #define DWC3_GFLADJ_30MHZ_MASK                 0x3f
 #define DWC3_GFLADJ_REFCLK_FLADJ_MASK          GENMASK(21, 8)
+#define DWC3_GFLADJ_REFCLK_LPM_SEL             BIT(23)
 #define DWC3_GFLADJ_240MHZDECR                 GENMASK(30, 24)
 #define DWC3_GFLADJ_240MHZDECR_PLS1            BIT(31)
 
@@ -1096,6 +1098,8 @@ struct dwc3_scratchpad_array {
  *                     change quirk.
  * @dis_tx_ipgap_linecheck_quirk: set if we disable u2mac linestate
  *                     check during HS transmit.
+ * @resume-hs-terminations: Set if we enable quirk for fixing improper crc
+ *                     generation after resume from suspend.
  * @parkmode_disable_ss_quirk: set if we need to disable all SuperSpeed
  *                     instances in park mode.
  * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
@@ -1311,7 +1315,9 @@ struct dwc3 {
        unsigned                dis_u2_freeclk_exists_quirk:1;
        unsigned                dis_del_phy_power_chg_quirk:1;
        unsigned                dis_tx_ipgap_linecheck_quirk:1;
+       unsigned                resume_hs_terminations:1;
        unsigned                parkmode_disable_ss_quirk:1;
+       unsigned                gfladj_refclk_lpm_sel:1;
 
        unsigned                tx_de_emphasis_quirk:1;
        unsigned                tx_de_emphasis:2;
@@ -1560,6 +1566,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd,
 int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned int cmd,
                u32 param);
 void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc);
+void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep, int status);
 #else
 static inline int dwc3_gadget_init(struct dwc3 *dwc)
 { return 0; }
index d223c54..48b44b8 100644 (file)
@@ -278,7 +278,7 @@ static inline const char *dwc3_ep_event_string(char *str, size_t size,
                break;
        case DWC3_DEPEVT_XFERINPROGRESS:
                scnprintf(str + len, size - len,
-                               "Transfer In Progress [%d] (%c%c%c)",
+                               "Transfer In Progress [%08x] (%c%c%c)",
                                event->parameters,
                                status & DEPEVT_STATUS_SHORT ? 'S' : 's',
                                status & DEPEVT_STATUS_IOC ? 'I' : 'i',
@@ -286,7 +286,7 @@ static inline const char *dwc3_ep_event_string(char *str, size_t size,
                break;
        case DWC3_DEPEVT_XFERNOTREADY:
                len += scnprintf(str + len, size - len,
-                               "Transfer Not Ready [%d]%s",
+                               "Transfer Not Ready [%08x]%s",
                                event->parameters,
                                status & DEPEVT_STATUS_TRANSFER_ACTIVE ?
                                " (Active)" : " (Not Active)");
index 039bf24..8cad9e7 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/extcon.h>
+#include <linux/of_graph.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
@@ -438,6 +439,51 @@ static int dwc3_drd_notifier(struct notifier_block *nb,
        return NOTIFY_DONE;
 }
 
+static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
+{
+       struct device *dev = dwc->dev;
+       struct device_node *np_phy;
+       struct extcon_dev *edev = NULL;
+       const char *name;
+
+       if (device_property_read_bool(dev, "extcon"))
+               return extcon_get_edev_by_phandle(dev, 0);
+
+       /*
+        * Device tree platforms should get extcon via phandle.
+        * On ACPI platforms, we get the name from a device property.
+        * This device property is for kernel internal use only and
+        * is expected to be set by the glue code.
+        */
+       if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) {
+               edev = extcon_get_extcon_dev(name);
+               if (!edev)
+                       return ERR_PTR(-EPROBE_DEFER);
+
+               return edev;
+       }
+
+       /*
+        * Try to get an extcon device from the USB PHY controller's "port"
+        * node. Check if it has the "port" node first, to avoid printing the
+        * error message from underlying code, as it's a valid case: extcon
+        * device (and "port" node) may be missing in case of "usb-role-switch"
+        * or OTG mode.
+        */
+       np_phy = of_parse_phandle(dev->of_node, "phys", 0);
+       if (of_graph_is_present(np_phy)) {
+               struct device_node *np_conn;
+
+               np_conn = of_graph_get_remote_node(np_phy, -1, -1);
+               if (np_conn)
+                       edev = extcon_find_edev_by_node(np_conn);
+               of_node_put(np_conn);
+       }
+       of_node_put(np_phy);
+
+       return edev;
+}
+
 #if IS_ENABLED(CONFIG_USB_ROLE_SWITCH)
 #define ROLE_SWITCH 1
 static int dwc3_usb_role_switch_set(struct usb_role_switch *sw,
@@ -542,6 +588,10 @@ int dwc3_drd_init(struct dwc3 *dwc)
            device_property_read_bool(dwc->dev, "usb-role-switch"))
                return dwc3_setup_role_switch(dwc);
 
+       dwc->edev = dwc3_get_extcon(dwc);
+       if (IS_ERR(dwc->edev))
+               return PTR_ERR(dwc->edev);
+
        if (dwc->edev) {
                dwc->edev_nb.notifier_call = dwc3_drd_notifier;
                ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
index 4ee4ca0..fb14511 100644 (file)
 #define PCI_DEVICE_ID_INTEL_TGPLP              0xa0ee
 #define PCI_DEVICE_ID_INTEL_TGPH               0x43ee
 #define PCI_DEVICE_ID_INTEL_JSP                        0x4dee
-#define PCI_DEVICE_ID_INTEL_ADL                        0x465e
-#define PCI_DEVICE_ID_INTEL_ADLP               0x51ee
-#define PCI_DEVICE_ID_INTEL_ADLM               0x54ee
+#define PCI_DEVICE_ID_INTEL_ADL                        0x460e
+#define PCI_DEVICE_ID_INTEL_ADL_PCH            0x51ee
+#define PCI_DEVICE_ID_INTEL_ADLN               0x465e
+#define PCI_DEVICE_ID_INTEL_ADLN_PCH           0x54ee
 #define PCI_DEVICE_ID_INTEL_ADLS               0x7ae1
 #define PCI_DEVICE_ID_INTEL_RPL                        0x460e
 #define PCI_DEVICE_ID_INTEL_RPLS               0x7a61
@@ -448,10 +449,13 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL),
          (kernel_ulong_t) &dwc3_pci_intel_swnode, },
 
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLP),
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL_PCH),
          (kernel_ulong_t) &dwc3_pci_intel_swnode, },
 
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLM),
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLN),
+         (kernel_ulong_t) &dwc3_pci_intel_swnode, },
+
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLN_PCH),
          (kernel_ulong_t) &dwc3_pci_intel_swnode, },
 
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLS),
index d3f3937..7c40f3f 100644 (file)
@@ -243,6 +243,7 @@ static int dwc3_qcom_interconnect_disable(struct dwc3_qcom *qcom)
  */
 static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
 {
+       enum usb_device_speed max_speed;
        struct device *dev = qcom->dev;
        int ret;
 
@@ -252,7 +253,7 @@ static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
        qcom->icc_path_ddr = of_icc_get(dev, "usb-ddr");
        if (IS_ERR(qcom->icc_path_ddr)) {
                dev_err(dev, "failed to get usb-ddr path: %ld\n",
-                       PTR_ERR(qcom->icc_path_ddr));
+                               PTR_ERR(qcom->icc_path_ddr));
                return PTR_ERR(qcom->icc_path_ddr);
        }
 
@@ -263,21 +264,20 @@ static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
                return PTR_ERR(qcom->icc_path_apps);
        }
 
-       if (usb_get_maximum_speed(&qcom->dwc3->dev) >= USB_SPEED_SUPER ||
-                       usb_get_maximum_speed(&qcom->dwc3->dev) == USB_SPEED_UNKNOWN)
+       max_speed = usb_get_maximum_speed(&qcom->dwc3->dev);
+       if (max_speed >= USB_SPEED_SUPER || max_speed == USB_SPEED_UNKNOWN) {
                ret = icc_set_bw(qcom->icc_path_ddr,
-                       USB_MEMORY_AVG_SS_BW, USB_MEMORY_PEAK_SS_BW);
-       else
+                               USB_MEMORY_AVG_SS_BW, USB_MEMORY_PEAK_SS_BW);
+       } else {
                ret = icc_set_bw(qcom->icc_path_ddr,
-                       USB_MEMORY_AVG_HS_BW, USB_MEMORY_PEAK_HS_BW);
-
+                               USB_MEMORY_AVG_HS_BW, USB_MEMORY_PEAK_HS_BW);
+       }
        if (ret) {
                dev_err(dev, "failed to set bandwidth for usb-ddr path: %d\n", ret);
                return ret;
        }
 
-       ret = icc_set_bw(qcom->icc_path_apps,
-               APPS_USB_AVG_BW, APPS_USB_PEAK_BW);
+       ret = icc_set_bw(qcom->icc_path_apps, APPS_USB_AVG_BW, APPS_USB_PEAK_BW);
        if (ret) {
                dev_err(dev, "failed to set bandwidth for apps-usb path: %d\n", ret);
                return ret;
@@ -1007,10 +1007,6 @@ static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = {
 
 static const struct of_device_id dwc3_qcom_of_match[] = {
        { .compatible = "qcom,dwc3" },
-       { .compatible = "qcom,msm8996-dwc3" },
-       { .compatible = "qcom,msm8998-dwc3" },
-       { .compatible = "qcom,sdm660-dwc3" },
-       { .compatible = "qcom,sdm845-dwc3" },
        { }
 };
 MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match);
index 67b237c..8607d4c 100644 (file)
@@ -47,6 +47,7 @@ struct dwc3_xlnx {
        struct device                   *dev;
        void __iomem                    *regs;
        int                             (*pltfm_init)(struct dwc3_xlnx *data);
+       struct phy                      *usb3_phy;
 };
 
 static void dwc3_xlnx_mask_phy_rst(struct dwc3_xlnx *priv_data, bool mask)
@@ -100,13 +101,12 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
        struct device           *dev = priv_data->dev;
        struct reset_control    *crst, *hibrst, *apbrst;
        struct gpio_desc        *reset_gpio;
-       struct phy              *usb3_phy;
        int                     ret = 0;
        u32                     reg;
 
-       usb3_phy = devm_phy_optional_get(dev, "usb3-phy");
-       if (IS_ERR(usb3_phy)) {
-               ret = PTR_ERR(usb3_phy);
+       priv_data->usb3_phy = devm_phy_optional_get(dev, "usb3-phy");
+       if (IS_ERR(priv_data->usb3_phy)) {
+               ret = PTR_ERR(priv_data->usb3_phy);
                dev_err_probe(dev, ret,
                              "failed to get USB3 PHY\n");
                goto err;
@@ -121,7 +121,7 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
         * in use but the usb3-phy entry is missing from the device tree.
         * Therefore, skip these operations in this case.
         */
-       if (!usb3_phy)
+       if (!priv_data->usb3_phy)
                goto skip_usb3_phy;
 
        crst = devm_reset_control_get_exclusive(dev, "usb_crst");
@@ -166,9 +166,9 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
                goto err;
        }
 
-       ret = phy_init(usb3_phy);
+       ret = phy_init(priv_data->usb3_phy);
        if (ret < 0) {
-               phy_exit(usb3_phy);
+               phy_exit(priv_data->usb3_phy);
                goto err;
        }
 
@@ -196,9 +196,9 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
                goto err;
        }
 
-       ret = phy_power_on(usb3_phy);
+       ret = phy_power_on(priv_data->usb3_phy);
        if (ret < 0) {
-               phy_exit(usb3_phy);
+               phy_exit(priv_data->usb3_phy);
                goto err;
        }
 
@@ -322,7 +322,7 @@ static int dwc3_xlnx_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int __maybe_unused dwc3_xlnx_suspend_common(struct device *dev)
+static int __maybe_unused dwc3_xlnx_runtime_suspend(struct device *dev)
 {
        struct dwc3_xlnx *priv_data = dev_get_drvdata(dev);
 
@@ -331,7 +331,7 @@ static int __maybe_unused dwc3_xlnx_suspend_common(struct device *dev)
        return 0;
 }
 
-static int __maybe_unused dwc3_xlnx_resume_common(struct device *dev)
+static int __maybe_unused dwc3_xlnx_runtime_resume(struct device *dev)
 {
        struct dwc3_xlnx *priv_data = dev_get_drvdata(dev);
 
@@ -346,8 +346,45 @@ static int __maybe_unused dwc3_xlnx_runtime_idle(struct device *dev)
        return 0;
 }
 
-static UNIVERSAL_DEV_PM_OPS(dwc3_xlnx_dev_pm_ops, dwc3_xlnx_suspend_common,
-                           dwc3_xlnx_resume_common, dwc3_xlnx_runtime_idle);
+static int __maybe_unused dwc3_xlnx_suspend(struct device *dev)
+{
+       struct dwc3_xlnx *priv_data = dev_get_drvdata(dev);
+
+       phy_exit(priv_data->usb3_phy);
+
+       /* Disable the clocks */
+       clk_bulk_disable(priv_data->num_clocks, priv_data->clks);
+
+       return 0;
+}
+
+static int __maybe_unused dwc3_xlnx_resume(struct device *dev)
+{
+       struct dwc3_xlnx *priv_data = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_bulk_enable(priv_data->num_clocks, priv_data->clks);
+       if (ret)
+               return ret;
+
+       ret = phy_init(priv_data->usb3_phy);
+       if (ret < 0)
+               return ret;
+
+       ret = phy_power_on(priv_data->usb3_phy);
+       if (ret < 0) {
+               phy_exit(priv_data->usb3_phy);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct dev_pm_ops dwc3_xlnx_dev_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(dwc3_xlnx_suspend, dwc3_xlnx_resume)
+       SET_RUNTIME_PM_OPS(dwc3_xlnx_runtime_suspend,
+                          dwc3_xlnx_runtime_resume, dwc3_xlnx_runtime_idle)
+};
 
 static struct platform_driver dwc3_xlnx_driver = {
        .probe          = dwc3_xlnx_probe,
index 197af63..61de693 100644 (file)
@@ -197,7 +197,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
        int                             ret;
 
        spin_lock_irqsave(&dwc->lock, flags);
-       if (!dep->endpoint.desc || !dwc->pullups_connected) {
+       if (!dep->endpoint.desc || !dwc->pullups_connected || !dwc->connected) {
                dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n",
                                dep->name);
                ret = -ESHUTDOWN;
@@ -293,7 +293,10 @@ void dwc3_ep0_out_start(struct dwc3 *dwc)
                        continue;
 
                dwc3_ep->flags &= ~DWC3_EP_DELAY_STOP;
-               dwc3_stop_active_transfer(dwc3_ep, true, true);
+               if (dwc->connected)
+                       dwc3_stop_active_transfer(dwc3_ep, true, true);
+               else
+                       dwc3_remove_requests(dwc, dwc3_ep, -ESHUTDOWN);
        }
 }
 
@@ -815,7 +818,7 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
        int ret = -EINVAL;
        u32 len;
 
-       if (!dwc->gadget_driver || !dwc->connected)
+       if (!dwc->gadget_driver || !dwc->softconnect || !dwc->connected)
                goto out;
 
        trace_dwc3_ctrl_req(ctrl);
@@ -1118,6 +1121,8 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
 {
        switch (event->status) {
        case DEPEVT_STATUS_CONTROL_DATA:
+               if (!dwc->softconnect || !dwc->connected)
+                       return;
                /*
                 * We already have a DATA transfer in the controller's cache,
                 * if we receive a XferNotReady(DATA) we will ignore it, unless
index eca945f..079cd33 100644 (file)
@@ -366,7 +366,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd,
 
        dwc3_writel(dep->regs, DWC3_DEPCMD, cmd);
 
-       if (!(cmd & DWC3_DEPCMD_CMDACT)) {
+       if (!(cmd & DWC3_DEPCMD_CMDACT) ||
+               (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_ENDTRANSFER &&
+               !(cmd & DWC3_DEPCMD_CMDIOC))) {
                ret = 0;
                goto skip_status;
        }
@@ -965,29 +967,33 @@ out:
        return 0;
 }
 
-static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
+void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep, int status)
 {
        struct dwc3_request             *req;
 
        dwc3_stop_active_transfer(dep, true, false);
 
+       /* If endxfer is delayed, avoid unmapping requests */
+       if (dep->flags & DWC3_EP_DELAY_STOP)
+               return;
+
        /* - giveback all requests to gadget driver */
        while (!list_empty(&dep->started_list)) {
                req = next_request(&dep->started_list);
 
-               dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
+               dwc3_gadget_giveback(dep, req, status);
        }
 
        while (!list_empty(&dep->pending_list)) {
                req = next_request(&dep->pending_list);
 
-               dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
+               dwc3_gadget_giveback(dep, req, status);
        }
 
        while (!list_empty(&dep->cancelled_list)) {
                req = next_request(&dep->cancelled_list);
 
-               dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
+               dwc3_gadget_giveback(dep, req, status);
        }
 }
 
@@ -1005,6 +1011,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
 {
        struct dwc3             *dwc = dep->dwc;
        u32                     reg;
+       u32                     mask;
 
        trace_dwc3_gadget_ep_disable(dep);
 
@@ -1022,11 +1029,19 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
                dep->endpoint.desc = NULL;
        }
 
-       dwc3_remove_requests(dwc, dep);
+       dwc3_remove_requests(dwc, dep, -ECONNRESET);
 
        dep->stream_capable = false;
        dep->type = 0;
-       dep->flags &= DWC3_EP_TXFIFO_RESIZED;
+       mask = DWC3_EP_TXFIFO_RESIZED;
+       /*
+        * dwc3_remove_requests() can exit early if DWC3 EP delayed stop is
+        * set.  Do not clear DEP flags, so that the end transfer command will
+        * be reattempted during the next SETUP stage.
+        */
+       if (dep->flags & DWC3_EP_DELAY_STOP)
+               mask |= (DWC3_EP_DELAY_STOP | DWC3_EP_TRANSFER_STARTED);
+       dep->flags &= mask;
 
        return 0;
 }
@@ -2340,7 +2355,7 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc)
                if (!dep)
                        continue;
 
-               dwc3_remove_requests(dwc, dep);
+               dwc3_remove_requests(dwc, dep, -ESHUTDOWN);
        }
 }
 
@@ -2440,7 +2455,7 @@ static void __dwc3_gadget_set_speed(struct dwc3 *dwc)
 static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
 {
        u32                     reg;
-       u32                     timeout = 500;
+       u32                     timeout = 2000;
 
        if (pm_runtime_suspended(dwc->dev))
                return 0;
@@ -2473,6 +2488,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
        dwc3_gadget_dctl_write_safe(dwc, reg);
 
        do {
+               usleep_range(1000, 2000);
                reg = dwc3_readl(dwc->regs, DWC3_DSTS);
                reg &= DWC3_DSTS_DEVCTRLHLT;
        } while (--timeout && !(!is_on ^ !reg));
@@ -2501,6 +2517,9 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc)
        if (dwc->ep0state != EP0_SETUP_PHASE) {
                int ret;
 
+               if (dwc->delayed_status)
+                       dwc3_ep0_send_delayed_status(dwc);
+
                reinit_completion(&dwc->ep0_in_setup);
 
                spin_unlock_irqrestore(&dwc->lock, flags);
@@ -2568,6 +2587,8 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
                return 0;
        }
 
+       synchronize_irq(dwc->irq_gadget);
+
        if (!is_on) {
                ret = dwc3_gadget_soft_disconnect(dwc);
        } else {
@@ -2718,6 +2739,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
        dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
 
        dep = dwc->eps[0];
+       dep->flags = 0;
        ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT);
        if (ret) {
                dev_err(dwc->dev, "failed to enable %s\n", dep->name);
@@ -2725,6 +2747,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
        }
 
        dep = dwc->eps[1];
+       dep->flags = 0;
        ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT);
        if (ret) {
                dev_err(dwc->dev, "failed to enable %s\n", dep->name);
@@ -3568,7 +3591,7 @@ static void dwc3_gadget_endpoint_stream_event(struct dwc3_ep *dep,
                 * streams are updated, and the device controller will not be
                 * triggered to generate ERDY to move the next stream data. To
                 * workaround this and maintain compatibility with various
-                * hosts, force to reinitate the stream until the host is ready
+                * hosts, force to reinitiate the stream until the host is ready
                 * instead of waiting for the host to prime the endpoint.
                 */
                if (DWC3_VER_IS_WITHIN(DWC32, 100A, ANY)) {
@@ -3596,11 +3619,12 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
        dep = dwc->eps[epnum];
 
        if (!(dep->flags & DWC3_EP_ENABLED)) {
-               if (!(dep->flags & DWC3_EP_TRANSFER_STARTED))
+               if ((epnum > 1) && !(dep->flags & DWC3_EP_TRANSFER_STARTED))
                        return;
 
                /* Handle only EPCMDCMPLT when EP disabled */
-               if (event->endpoint_event != DWC3_DEPEVT_EPCMDCMPLT)
+               if ((event->endpoint_event != DWC3_DEPEVT_EPCMDCMPLT) &&
+                       !(epnum <= 1 && event->endpoint_event == DWC3_DEPEVT_XFERCOMPLETE))
                        return;
        }
 
@@ -3695,7 +3719,7 @@ void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force,
         * timeout. Delay issuing the End Transfer command until the Setup TRB is
         * prepared.
         */
-       if (dwc->ep0state != EP0_SETUP_PHASE && !dwc->delayed_status) {
+       if (dwc->ep0state != EP0_SETUP_PHASE) {
                dep->flags |= DWC3_EP_DELAY_STOP;
                return;
        }
@@ -3763,13 +3787,24 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
        reg &= ~DWC3_DCTL_INITU2ENA;
        dwc3_gadget_dctl_write_safe(dwc, reg);
 
+       dwc->connected = false;
+
        dwc3_disconnect_gadget(dwc);
 
        dwc->gadget->speed = USB_SPEED_UNKNOWN;
        dwc->setup_packet_pending = false;
        usb_gadget_set_state(dwc->gadget, USB_STATE_NOTATTACHED);
 
-       dwc->connected = false;
+       if (dwc->ep0state != EP0_SETUP_PHASE) {
+               unsigned int    dir;
+
+               dir = !!dwc->ep0_expect_in;
+               if (dwc->ep0state == EP0_DATA_PHASE)
+                       dwc3_ep0_end_control_data(dwc, dwc->eps[dir]);
+               else
+                       dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]);
+               dwc3_ep0_stall_and_restart(dwc);
+       }
 }
 
 static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
@@ -3867,6 +3902,9 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
        u8                      lanes = 1;
        u8                      speed;
 
+       if (!dwc->softconnect)
+               return;
+
        reg = dwc3_readl(dwc->regs, DWC3_DSTS);
        speed = reg & DWC3_DSTS_CONNECTSPD;
        dwc->speed = speed;
@@ -4129,7 +4167,7 @@ static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc,
        unsigned int is_ss = evtinfo & BIT(4);
 
        /*
-        * WORKAROUND: DWC3 revison 2.20a with hibernation support
+        * WORKAROUND: DWC3 revision 2.20a with hibernation support
         * have a known issue which can cause USB CV TD.9.23 to fail
         * randomly.
         *
@@ -4507,12 +4545,17 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
 
 int dwc3_gadget_suspend(struct dwc3 *dwc)
 {
+       unsigned long flags;
+
        if (!dwc->gadget_driver)
                return 0;
 
        dwc3_gadget_run_stop(dwc, false, false);
+
+       spin_lock_irqsave(&dwc->lock, flags);
        dwc3_disconnect_gadget(dwc);
        __dwc3_gadget_stop(dwc);
+       spin_unlock_irqrestore(&dwc->lock, flags);
 
        return 0;
 }
index cb998ba..1975aec 100644 (file)
@@ -241,7 +241,7 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
                __entry->enqueue = dep->trb_enqueue;
                __entry->dequeue = dep->trb_dequeue;
        ),
-       TP_printk("%s: trb %p (E%d:D%d) buf %08x%08x size %s%d ctrl %08x (%c%c%c%c:%c%c:%s)",
+       TP_printk("%s: trb %p (E%d:D%d) buf %08x%08x size %s%d ctrl %08x sofn %08x (%c%c%c%c:%c%c:%s)",
                __get_str(name), __entry->trb, __entry->enqueue,
                __entry->dequeue, __entry->bph, __entry->bpl,
                ({char *s;
@@ -267,6 +267,7 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
                        s = "";
                } s; }),
                DWC3_TRB_SIZE_LENGTH(__entry->size), __entry->ctrl,
+               DWC3_TRB_CTRL_GET_SID_SOFN(__entry->ctrl),
                __entry->ctrl & DWC3_TRB_CTRL_HWO ? 'H' : 'h',
                __entry->ctrl & DWC3_TRB_CTRL_LST ? 'L' : 'l',
                __entry->ctrl & DWC3_TRB_CTRL_CHN ? 'C' : 'c',
index e0fa4b1..73dc10a 100644 (file)
@@ -2645,10 +2645,10 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
                unsigned i = 0;
                vla_group(d);
                vla_item(d, struct usb_gadget_strings *, stringtabs,
-                       lang_count + 1);
+                       size_add(lang_count, 1));
                vla_item(d, struct usb_gadget_strings, stringtab, lang_count);
                vla_item(d, struct usb_string, strings,
-                       lang_count*(needed_count+1));
+                       size_mul(lang_count, (needed_count + 1)));
 
                char *vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL);
 
@@ -3700,7 +3700,7 @@ int ffs_name_dev(struct ffs_dev *dev, const char *name)
 
        existing = _ffs_do_find_dev(name);
        if (!existing)
-               strlcpy(dev->name, name, ARRAY_SIZE(dev->name));
+               strscpy(dev->name, name, ARRAY_SIZE(dev->name));
        else if (existing != dev)
                ret = -EBUSY;
 
index 925e99f..3abf7f5 100644 (file)
@@ -2662,11 +2662,16 @@ static ssize_t forced_eject_store(struct device *dev,
 }
 
 static DEVICE_ATTR_RW(nofua);
-/* mode wil be set in fsg_lun_attr_is_visible() */
-static DEVICE_ATTR(ro, 0, ro_show, ro_store);
-static DEVICE_ATTR(file, 0, file_show, file_store);
 static DEVICE_ATTR_WO(forced_eject);
 
+/*
+ * Mode of the ro and file attribute files will be overridden in
+ * fsg_lun_dev_is_visible() depending on if this is a cdrom, or if it is a
+ * removable device.
+ */
+static DEVICE_ATTR_RW(ro);
+static DEVICE_ATTR_RW(file);
+
 /****************************** FSG COMMON ******************************/
 
 static void fsg_lun_release(struct device *dev)
index dc8f078..c36bcfa 100644 (file)
@@ -450,39 +450,35 @@ struct ndp_parser_opts {
        unsigned        next_ndp_index;
 };
 
-#define INIT_NDP16_OPTS {                                      \
-               .nth_sign = USB_CDC_NCM_NTH16_SIGN,             \
-               .ndp_sign = USB_CDC_NCM_NDP16_NOCRC_SIGN,       \
-               .nth_size = sizeof(struct usb_cdc_ncm_nth16),   \
-               .ndp_size = sizeof(struct usb_cdc_ncm_ndp16),   \
-               .dpe_size = sizeof(struct usb_cdc_ncm_dpe16),   \
-               .ndplen_align = 4,                              \
-               .dgram_item_len = 1,                            \
-               .block_length = 1,                              \
-               .ndp_index = 1,                                 \
-               .reserved1 = 0,                                 \
-               .reserved2 = 0,                                 \
-               .next_ndp_index = 1,                            \
-       }
-
-
-#define INIT_NDP32_OPTS {                                      \
-               .nth_sign = USB_CDC_NCM_NTH32_SIGN,             \
-               .ndp_sign = USB_CDC_NCM_NDP32_NOCRC_SIGN,       \
-               .nth_size = sizeof(struct usb_cdc_ncm_nth32),   \
-               .ndp_size = sizeof(struct usb_cdc_ncm_ndp32),   \
-               .dpe_size = sizeof(struct usb_cdc_ncm_dpe32),   \
-               .ndplen_align = 8,                              \
-               .dgram_item_len = 2,                            \
-               .block_length = 2,                              \
-               .ndp_index = 2,                                 \
-               .reserved1 = 1,                                 \
-               .reserved2 = 2,                                 \
-               .next_ndp_index = 2,                            \
-       }
+static const struct ndp_parser_opts ndp16_opts = {
+       .nth_sign = USB_CDC_NCM_NTH16_SIGN,
+       .ndp_sign = USB_CDC_NCM_NDP16_NOCRC_SIGN,
+       .nth_size = sizeof(struct usb_cdc_ncm_nth16),
+       .ndp_size = sizeof(struct usb_cdc_ncm_ndp16),
+       .dpe_size = sizeof(struct usb_cdc_ncm_dpe16),
+       .ndplen_align = 4,
+       .dgram_item_len = 1,
+       .block_length = 1,
+       .ndp_index = 1,
+       .reserved1 = 0,
+       .reserved2 = 0,
+       .next_ndp_index = 1,
+};
 
-static const struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS;
-static const struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS;
+static const struct ndp_parser_opts ndp32_opts = {
+       .nth_sign = USB_CDC_NCM_NTH32_SIGN,
+       .ndp_sign = USB_CDC_NCM_NDP32_NOCRC_SIGN,
+       .nth_size = sizeof(struct usb_cdc_ncm_nth32),
+       .ndp_size = sizeof(struct usb_cdc_ncm_ndp32),
+       .dpe_size = sizeof(struct usb_cdc_ncm_dpe32),
+       .ndplen_align = 8,
+       .dgram_item_len = 2,
+       .block_length = 2,
+       .ndp_index = 2,
+       .reserved1 = 1,
+       .reserved2 = 2,
+       .next_ndp_index = 2,
+};
 
 static inline void put_ncm(__le16 **p, unsigned size, unsigned val)
 {
index abec5c5..a881c69 100644 (file)
@@ -89,7 +89,7 @@ struct printer_dev {
        u8                      printer_cdev_open;
        wait_queue_head_t       wait;
        unsigned                q_len;
-       char                    *pnp_string;    /* We don't own memory! */
+       char                    **pnp_string;   /* We don't own memory! */
        struct usb_function     function;
 };
 
@@ -1000,16 +1000,16 @@ static int printer_func_setup(struct usb_function *f,
                        if ((wIndex>>8) != dev->interface)
                                break;
 
-                       if (!dev->pnp_string) {
+                       if (!*dev->pnp_string) {
                                value = 0;
                                break;
                        }
-                       value = strlen(dev->pnp_string);
+                       value = strlen(*dev->pnp_string);
                        buf[0] = (value >> 8) & 0xFF;
                        buf[1] = value & 0xFF;
-                       memcpy(buf + 2, dev->pnp_string, value);
+                       memcpy(buf + 2, *dev->pnp_string, value);
                        DBG(dev, "1284 PNP String: %x %s\n", value,
-                           dev->pnp_string);
+                           *dev->pnp_string);
                        break;
 
                case GET_PORT_STATUS: /* Get Port Status */
@@ -1475,7 +1475,7 @@ static struct usb_function *gprinter_alloc(struct usb_function_instance *fi)
        kref_init(&dev->kref);
        ++opts->refcnt;
        dev->minor = opts->minor;
-       dev->pnp_string = opts->pnp_string;
+       dev->pnp_string = &opts->pnp_string;
        dev->q_len = opts->q_len;
        mutex_unlock(&opts->lock);
 
index 8e17ac8..658e2e2 100644 (file)
@@ -2306,7 +2306,7 @@ static struct usb_function *tcm_alloc(struct usb_function_instance *fi)
 
 DECLARE_USB_FUNCTION(tcm, tcm_alloc_inst, tcm_alloc);
 
-static int tcm_init(void)
+static int __init tcm_init(void)
 {
        int ret;
 
@@ -2322,7 +2322,7 @@ static int tcm_init(void)
 }
 module_init(tcm_init);
 
-static void tcm_exit(void)
+static void __exit tcm_exit(void)
 {
        target_unregister_template(&usbg_ops);
        usb_function_unregister(&tcmusb_func);
index 71669e0..6e196e0 100644 (file)
@@ -421,7 +421,7 @@ uvc_register_video(struct uvc_device *uvc)
        int ret;
 
        /* TODO reference counting. */
-       memset(&uvc->vdev, 0, sizeof(uvc->video));
+       memset(&uvc->vdev, 0, sizeof(uvc->vdev));
        uvc->vdev.v4l2_dev = &uvc->v4l2_dev;
        uvc->vdev.v4l2_dev->dev = &cdev->gadget->dev;
        uvc->vdev.fops = &uvc_v4l2_fops;
@@ -430,7 +430,7 @@ uvc_register_video(struct uvc_device *uvc)
        uvc->vdev.vfl_dir = VFL_DIR_TX;
        uvc->vdev.lock = &uvc->video.mutex;
        uvc->vdev.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
-       strlcpy(uvc->vdev.name, cdev->gadget->name, sizeof(uvc->vdev.name));
+       strscpy(uvc->vdev.name, cdev->gadget->name, sizeof(uvc->vdev.name));
 
        video_set_drvdata(&uvc->vdev, uvc);
 
@@ -888,6 +888,7 @@ static void uvc_free(struct usb_function *f)
        struct uvc_device *uvc = to_uvc(f);
        struct f_uvc_opts *opts = container_of(f->fi, struct f_uvc_opts,
                                               func_inst);
+       config_item_put(&uvc->header->item);
        --opts->refcnt;
        kfree(uvc);
 }
@@ -897,10 +898,14 @@ static void uvc_function_unbind(struct usb_configuration *c,
 {
        struct usb_composite_dev *cdev = c->cdev;
        struct uvc_device *uvc = to_uvc(f);
+       struct uvc_video *video = &uvc->video;
        long wait_ret = 1;
 
        uvcg_info(f, "%s()\n", __func__);
 
+       if (video->async_wq)
+               destroy_workqueue(video->async_wq);
+
        /*
         * If we know we're connected via v4l2, then there should be a cleanup
         * of the device from userspace either via UVC_EVENT_DISCONNECT or
@@ -941,6 +946,7 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
        struct uvc_device *uvc;
        struct f_uvc_opts *opts;
        struct uvc_descriptor_header **strm_cls;
+       struct config_item *streaming, *header, *h;
 
        uvc = kzalloc(sizeof(*uvc), GFP_KERNEL);
        if (uvc == NULL)
@@ -973,6 +979,28 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
        uvc->desc.fs_streaming = opts->fs_streaming;
        uvc->desc.hs_streaming = opts->hs_streaming;
        uvc->desc.ss_streaming = opts->ss_streaming;
+
+       streaming = config_group_find_item(&opts->func_inst.group, "streaming");
+       if (!streaming)
+               goto err_config;
+
+       header = config_group_find_item(to_config_group(streaming), "header");
+       config_item_put(streaming);
+       if (!header)
+               goto err_config;
+
+       h = config_group_find_item(to_config_group(header), "h");
+       config_item_put(header);
+       if (!h)
+               goto err_config;
+
+       uvc->header = to_uvcg_streaming_header(h);
+       if (!uvc->header->linked) {
+               mutex_unlock(&opts->lock);
+               kfree(uvc);
+               return ERR_PTR(-EBUSY);
+       }
+
        ++opts->refcnt;
        mutex_unlock(&opts->lock);
 
@@ -988,6 +1016,11 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
        uvc->func.bind_deactivated = true;
 
        return &uvc->func;
+
+err_config:
+       mutex_unlock(&opts->lock);
+       kfree(uvc);
+       return ERR_PTR(-ENOENT);
 }
 
 DECLARE_USB_FUNCTION_INIT(uvc, uvc_alloc_inst, uvc_alloc);
index 713efd9..29bf866 100644 (file)
@@ -869,7 +869,7 @@ EXPORT_SYMBOL_GPL(rndis_msg_parser);
 
 static inline int rndis_get_nr(void)
 {
-       return ida_simple_get(&rndis_ida, 0, 0, GFP_KERNEL);
+       return ida_simple_get(&rndis_ida, 0, 1000, GFP_KERNEL);
 }
 
 static inline void rndis_put_nr(int nr)
@@ -1105,7 +1105,7 @@ static int rndis_proc_show(struct seq_file *m, void *v)
                         "used      : %s\n"
                         "state     : %s\n"
                         "medium    : 0x%08X\n"
-                        "speed     : %d\n"
+                        "speed     : %u\n"
                         "cable     : %s\n"
                         "vendor ID : 0x%08X\n"
                         "vendor    : %s\n",
index 7887def..e060228 100644 (file)
@@ -144,10 +144,10 @@ static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
 {
        struct eth_dev *dev = netdev_priv(net);
 
-       strlcpy(p->driver, "g_ether", sizeof(p->driver));
-       strlcpy(p->version, UETH__VERSION, sizeof(p->version));
-       strlcpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version));
-       strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info));
+       strscpy(p->driver, "g_ether", sizeof(p->driver));
+       strscpy(p->version, UETH__VERSION, sizeof(p->version));
+       strscpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version));
+       strscpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info));
 }
 
 /* REVISIT can also support:
index 6f68cbe..7538279 100644 (file)
@@ -1443,7 +1443,7 @@ void gserial_resume(struct gserial *gser)
 }
 EXPORT_SYMBOL_GPL(gserial_resume);
 
-static int userial_init(void)
+static int __init userial_init(void)
 {
        struct tty_driver *driver;
        unsigned                        i;
@@ -1496,7 +1496,7 @@ fail:
 }
 module_init(userial_init);
 
-static void userial_cleanup(void)
+static void __exit userial_cleanup(void)
 {
        tty_unregister_driver(gs_tty_driver);
        tty_driver_kref_put(gs_tty_driver);
index 58e383a..40226b1 100644 (file)
@@ -88,6 +88,7 @@ struct uvc_video {
        struct usb_ep *ep;
 
        struct work_struct pump;
+       struct workqueue_struct *async_wq;
 
        /* Frame parameters */
        u8 bpp;
@@ -133,6 +134,8 @@ struct uvc_device {
        bool func_connected;
        wait_queue_head_t func_connected_queue;
 
+       struct uvcg_streaming_header *header;
+
        /* Descriptors */
        struct {
                const struct uvc_descriptor_header * const *fs_control;
index fd8f73b..c4ed48d 100644 (file)
 #include <media/v4l2-dev.h>
 #include <media/v4l2-event.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-uvc.h>
 
 #include "f_uvc.h"
 #include "uvc.h"
 #include "uvc_queue.h"
 #include "uvc_video.h"
 #include "uvc_v4l2.h"
+#include "uvc_configfs.h"
+
+static struct uvc_format_desc *to_uvc_format(struct uvcg_format *uformat)
+{
+       char guid[16] = UVC_GUID_FORMAT_MJPEG;
+       struct uvc_format_desc *format;
+       struct uvcg_uncompressed *unc;
+
+       if (uformat->type == UVCG_UNCOMPRESSED) {
+               unc = to_uvcg_uncompressed(&uformat->group.cg_item);
+               if (!unc)
+                       return ERR_PTR(-EINVAL);
+
+               memcpy(guid, unc->desc.guidFormat, sizeof(guid));
+       }
+
+       format = uvc_format_by_guid(guid);
+       if (!format)
+               return ERR_PTR(-EINVAL);
+
+       return format;
+}
+
+static int uvc_v4l2_get_bytesperline(struct uvcg_format *uformat,
+                             struct uvcg_frame *uframe)
+{
+       struct uvcg_uncompressed *u;
+
+       if (uformat->type == UVCG_UNCOMPRESSED) {
+               u = to_uvcg_uncompressed(&uformat->group.cg_item);
+               if (!u)
+                       return 0;
+
+               return u->desc.bBitsPerPixel * uframe->frame.w_width / 8;
+       }
+
+       return 0;
+}
+
+static int uvc_get_frame_size(struct uvcg_format *uformat,
+                      struct uvcg_frame *uframe)
+{
+       unsigned int bpl = uvc_v4l2_get_bytesperline(uformat, uframe);
+
+       return bpl ? bpl * uframe->frame.w_height :
+               uframe->frame.dw_max_video_frame_buffer_size;
+}
+
+static struct uvcg_format *find_format_by_index(struct uvc_device *uvc, int index)
+{
+       struct uvcg_format_ptr *format;
+       struct uvcg_format *uformat = NULL;
+       int i = 1;
+
+       list_for_each_entry(format, &uvc->header->formats, entry) {
+               if (index == i) {
+                       uformat = format->fmt;
+                       break;
+               }
+               i++;
+       }
+
+       return uformat;
+}
+
+static struct uvcg_frame *find_frame_by_index(struct uvc_device *uvc,
+                                      struct uvcg_format *uformat,
+                                      int index)
+{
+       struct uvcg_format_ptr *format;
+       struct uvcg_frame_ptr *frame;
+       struct uvcg_frame *uframe = NULL;
+
+       list_for_each_entry(format, &uvc->header->formats, entry) {
+               if (format->fmt->type != uformat->type)
+                       continue;
+               list_for_each_entry(frame, &format->fmt->frames, entry) {
+                       if (index == frame->frm->frame.b_frame_index) {
+                               uframe = frame->frm;
+                               break;
+                       }
+               }
+       }
+
+       return uframe;
+}
+
+static struct uvcg_format *find_format_by_pix(struct uvc_device *uvc,
+                                             u32 pixelformat)
+{
+       struct uvcg_format_ptr *format;
+       struct uvcg_format *uformat = NULL;
+
+       list_for_each_entry(format, &uvc->header->formats, entry) {
+               struct uvc_format_desc *fmtdesc = to_uvc_format(format->fmt);
+
+               if (fmtdesc->fcc == pixelformat) {
+                       uformat = format->fmt;
+                       break;
+               }
+       }
+
+       return uformat;
+}
+
+static struct uvcg_frame *find_closest_frame_by_size(struct uvc_device *uvc,
+                                          struct uvcg_format *uformat,
+                                          u16 rw, u16 rh)
+{
+       struct uvc_video *video = &uvc->video;
+       struct uvcg_format_ptr *format;
+       struct uvcg_frame_ptr *frame;
+       struct uvcg_frame *uframe = NULL;
+       unsigned int d, maxd;
+
+       /* Find the closest image size. The distance between image sizes is
+        * the size in pixels of the non-overlapping regions between the
+        * requested size and the frame-specified size.
+        */
+       maxd = (unsigned int)-1;
+
+       list_for_each_entry(format, &uvc->header->formats, entry) {
+               if (format->fmt->type != uformat->type)
+                       continue;
+
+               list_for_each_entry(frame, &format->fmt->frames, entry) {
+                       u16 w, h;
+
+                       w = frame->frm->frame.w_width;
+                       h = frame->frm->frame.w_height;
+
+                       d = min(w, rw) * min(h, rh);
+                       d = w*h + rw*rh - 2*d;
+                       if (d < maxd) {
+                               maxd = d;
+                               uframe = frame->frm;
+                       }
+
+                       if (maxd == 0)
+                               break;
+               }
+       }
+
+       if (!uframe)
+               uvcg_dbg(&video->uvc->func, "Unsupported size %ux%u\n", rw, rh);
+
+       return uframe;
+}
 
 /* --------------------------------------------------------------------------
  * Requests handling
@@ -67,9 +216,9 @@ uvc_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
        struct uvc_device *uvc = video_get_drvdata(vdev);
        struct usb_composite_dev *cdev = uvc->func.config->cdev;
 
-       strlcpy(cap->driver, "g_uvc", sizeof(cap->driver));
-       strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card));
-       strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev),
+       strscpy(cap->driver, "g_uvc", sizeof(cap->driver));
+       strscpy(cap->card, cdev->gadget->name, sizeof(cap->card));
+       strscpy(cap->bus_info, dev_name(&cdev->gadget->dev),
                sizeof(cap->bus_info));
        return 0;
 }
@@ -135,6 +284,139 @@ uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt)
 }
 
 static int
+uvc_v4l2_try_format(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct uvc_device *uvc = video_get_drvdata(vdev);
+       struct uvc_video *video = &uvc->video;
+       struct uvcg_format *uformat;
+       struct uvcg_frame *uframe;
+       u8 *fcc;
+
+       if (fmt->type != video->queue.queue.type)
+               return -EINVAL;
+
+       fcc = (u8 *)&fmt->fmt.pix.pixelformat;
+       uvcg_dbg(&uvc->func, "Trying format 0x%08x (%c%c%c%c): %ux%u\n",
+               fmt->fmt.pix.pixelformat,
+               fcc[0], fcc[1], fcc[2], fcc[3],
+               fmt->fmt.pix.width, fmt->fmt.pix.height);
+
+       uformat = find_format_by_pix(uvc, fmt->fmt.pix.pixelformat);
+       if (!uformat)
+               return -EINVAL;
+
+       uframe = find_closest_frame_by_size(uvc, uformat,
+                               fmt->fmt.pix.width, fmt->fmt.pix.height);
+       if (!uframe)
+               return -EINVAL;
+
+       fmt->fmt.pix.width = uframe->frame.w_width;
+       fmt->fmt.pix.height = uframe->frame.w_height;
+       fmt->fmt.pix.field = V4L2_FIELD_NONE;
+       fmt->fmt.pix.bytesperline = uvc_v4l2_get_bytesperline(uformat, uframe);
+       fmt->fmt.pix.sizeimage = uvc_get_frame_size(uformat, uframe);
+       fmt->fmt.pix.pixelformat = to_uvc_format(uformat)->fcc;
+       fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+       fmt->fmt.pix.priv = 0;
+
+       return 0;
+}
+
+static int
+uvc_v4l2_enum_frameintervals(struct file *file, void *fh,
+               struct v4l2_frmivalenum *fival)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct uvc_device *uvc = video_get_drvdata(vdev);
+       struct uvcg_format *uformat = NULL;
+       struct uvcg_frame *uframe = NULL;
+       struct uvcg_frame_ptr *frame;
+
+       uformat = find_format_by_pix(uvc, fival->pixel_format);
+       if (!uformat)
+               return -EINVAL;
+
+       list_for_each_entry(frame, &uformat->frames, entry) {
+               if (frame->frm->frame.w_width == fival->width &&
+                   frame->frm->frame.w_height == fival->height) {
+                       uframe = frame->frm;
+                       break;
+               }
+       }
+       if (!uframe)
+               return -EINVAL;
+
+       if (fival->index >= uframe->frame.b_frame_interval_type)
+               return -EINVAL;
+
+       fival->discrete.numerator =
+               uframe->dw_frame_interval[fival->index];
+
+       /* TODO: handle V4L2_FRMIVAL_TYPE_STEPWISE */
+       fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+       fival->discrete.denominator = 10000000;
+       v4l2_simplify_fraction(&fival->discrete.numerator,
+               &fival->discrete.denominator, 8, 333);
+
+       return 0;
+}
+
+static int
+uvc_v4l2_enum_framesizes(struct file *file, void *fh,
+               struct v4l2_frmsizeenum *fsize)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct uvc_device *uvc = video_get_drvdata(vdev);
+       struct uvcg_format *uformat = NULL;
+       struct uvcg_frame *uframe = NULL;
+
+       uformat = find_format_by_pix(uvc, fsize->pixel_format);
+       if (!uformat)
+               return -EINVAL;
+
+       if (fsize->index >= uformat->num_frames)
+               return -EINVAL;
+
+       uframe = find_frame_by_index(uvc, uformat, fsize->index + 1);
+       if (!uframe)
+               return -EINVAL;
+
+       fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+       fsize->discrete.width = uframe->frame.w_width;
+       fsize->discrete.height = uframe->frame.w_height;
+
+       return 0;
+}
+
+static int
+uvc_v4l2_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct uvc_device *uvc = video_get_drvdata(vdev);
+       struct uvc_format_desc *fmtdesc;
+       struct uvcg_format *uformat;
+
+       if (f->index >= uvc->header->num_fmt)
+               return -EINVAL;
+
+       uformat = find_format_by_index(uvc, f->index + 1);
+       if (!uformat)
+               return -EINVAL;
+
+       if (uformat->type != UVCG_UNCOMPRESSED)
+               f->flags |= V4L2_FMT_FLAG_COMPRESSED;
+
+       fmtdesc = to_uvc_format(uformat);
+       f->pixelformat = fmtdesc->fcc;
+
+       strscpy(f->description, fmtdesc->name, sizeof(f->description));
+       f->description[strlen(fmtdesc->name) - 1] = 0;
+
+       return 0;
+}
+
+static int
 uvc_v4l2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *b)
 {
        struct video_device *vdev = video_devdata(file);
@@ -170,7 +452,7 @@ uvc_v4l2_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
                return ret;
 
        if (uvc->state == UVC_STATE_STREAMING)
-               schedule_work(&video->pump);
+               queue_work(video->async_wq, &video->pump);
 
        return ret;
 }
@@ -298,8 +580,12 @@ uvc_v4l2_ioctl_default(struct file *file, void *fh, bool valid_prio,
 
 const struct v4l2_ioctl_ops uvc_v4l2_ioctl_ops = {
        .vidioc_querycap = uvc_v4l2_querycap,
+       .vidioc_try_fmt_vid_out = uvc_v4l2_try_format,
        .vidioc_g_fmt_vid_out = uvc_v4l2_get_format,
        .vidioc_s_fmt_vid_out = uvc_v4l2_set_format,
+       .vidioc_enum_frameintervals = uvc_v4l2_enum_frameintervals,
+       .vidioc_enum_framesizes = uvc_v4l2_enum_framesizes,
+       .vidioc_enum_fmt_vid_out = uvc_v4l2_enum_format,
        .vidioc_reqbufs = uvc_v4l2_reqbufs,
        .vidioc_querybuf = uvc_v4l2_querybuf,
        .vidioc_qbuf = uvc_v4l2_qbuf,
index c00ce0e..bb037fc 100644 (file)
@@ -277,7 +277,7 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
        spin_unlock_irqrestore(&video->req_lock, flags);
 
        if (uvc->state == UVC_STATE_STREAMING)
-               schedule_work(&video->pump);
+               queue_work(video->async_wq, &video->pump);
 }
 
 static int
@@ -485,7 +485,7 @@ int uvcg_video_enable(struct uvc_video *video, int enable)
 
        video->req_int_count = 0;
 
-       schedule_work(&video->pump);
+       queue_work(video->async_wq, &video->pump);
 
        return ret;
 }
@@ -499,6 +499,11 @@ int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc)
        spin_lock_init(&video->req_lock);
        INIT_WORK(&video->pump, uvcg_video_pump);
 
+       /* Allocate a work queue for asynchronous video pump handler. */
+       video->async_wq = alloc_workqueue("uvcgadget", WQ_UNBOUND | WQ_HIGHPRI, 0);
+       if (!video->async_wq)
+               return -EINVAL;
+
        video->uvc = uvc;
        video->fcc = V4L2_PIX_FMT_YUYV;
        video->bpp = 16;
index 7289872..a9a7b3f 100644 (file)
@@ -994,7 +994,7 @@ static const struct usb_gadget_ops at91_udc_ops = {
        .udc_stop               = at91_stop,
 
        /*
-        * VBUS-powered devices may also also want to support bigger
+        * VBUS-powered devices may also want to support bigger
         * power budgets after an appropriate SET_CONFIGURATION.
         */
        /* .vbus_power          = at91_vbus_power, */
@@ -1779,12 +1779,14 @@ static void at91udc_of_init(struct at91_udc *udc, struct device_node *np)
        if (of_property_read_u32(np, "atmel,vbus-polled", &val) == 0)
                board->vbus_polled = 1;
 
-       board->vbus_pin = gpiod_get_from_of_node(np, "atmel,vbus-gpio", 0,
-                                                GPIOD_IN, "udc_vbus");
+       board->vbus_pin = fwnode_gpiod_get_index(of_fwnode_handle(np),
+                                                "atmel,vbus", 0, GPIOD_IN,
+                                                "udc_vbus");
        if (IS_ERR(board->vbus_pin))
                board->vbus_pin = NULL;
 
-       board->pullup_pin = gpiod_get_from_of_node(np, "atmel,pullup-gpio", 0,
+       board->pullup_pin = fwnode_gpiod_get_index(of_fwnode_handle(np),
+                                                  "atmel,pullup", 0,
                                                   GPIOD_ASIS, "udc_pullup");
        if (IS_ERR(board->pullup_pin))
                board->pullup_pin = NULL;
index c97cd4b..84605a4 100644 (file)
@@ -91,7 +91,7 @@ module_param(dma_mode, ushort, 0644);
  *      mode 2 == ep-a 1k, ep-b 1k, ep-c 512db
  *      mode 3 == ep-a 1k, ep-b disabled, ep-c 512db
  */
-static ushort fifo_mode = 0;
+static ushort fifo_mode;
 module_param(fifo_mode, ushort, 0644);
 
 /*
@@ -100,7 +100,7 @@ module_param(fifo_mode, ushort, 0644);
  * USB suspend requests will be ignored.  This is acceptable for
  * self-powered devices.  For bus powered devices set this to 1.
  */
-static ushort enable_suspend = 0;
+static ushort enable_suspend;
 module_param(enable_suspend, ushort, 0644);
 
 static void assert_out_naking(struct net2272_ep *ep, const char *where)
index 61cabb9..bea346e 100644 (file)
@@ -2234,7 +2234,7 @@ static int proc_otg_show(struct seq_file *s)
        char            *ctrl_name = "(UNKNOWN)";
 
        tmp = omap_readl(OTG_REV);
-       ctrl_name = "tranceiver_ctrl";
+       ctrl_name = "transceiver_ctrl";
        trans = omap_readw(USB_TRANSCEIVER_CTRL);
        seq_printf(s, "\nOTG rev %d.%d, %s %05x\n",
                tmp >> 4, tmp & 0xf, ctrl_name, trans);
@@ -2558,7 +2558,7 @@ omap_ep_setup(char *name, u8 addr, u8 type,
 
        /* set up driver data structures */
        BUG_ON(strlen(name) >= sizeof ep->name);
-       strlcpy(ep->name, name, sizeof ep->name);
+       strscpy(ep->name, name, sizeof(ep->name));
        INIT_LIST_HEAD(&ep->queue);
        INIT_LIST_HEAD(&ep->iso);
        ep->bEndpointAddress = addr;
index 648be3f..615ba0a 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/reset.h>
 #include <linux/sizes.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #define USB3_USB20_CON         0x204
 #define USB3_USB30_CON         0x208
 #define USB3_USB_STA           0x210
-#define USB3_DRD_CON           0x218
+#define USB3_DRD_CON(p)                ((p)->is_rzv2m ? 0x400 : 0x218)
 #define USB3_USB_INT_STA_1     0x220
 #define USB3_USB_INT_STA_2     0x224
 #define USB3_USB_INT_ENA_1     0x228
 #define USB3_USB_INT_ENA_2     0x22c
 #define USB3_STUP_DAT_0                0x230
 #define USB3_STUP_DAT_1                0x234
-#define USB3_USB_OTG_STA       0x268
-#define USB3_USB_OTG_INT_STA   0x26c
-#define USB3_USB_OTG_INT_ENA   0x270
+#define USB3_USB_OTG_STA(p)    ((p)->is_rzv2m ? 0x410 : 0x268)
+#define USB3_USB_OTG_INT_STA(p)        ((p)->is_rzv2m ? 0x414 : 0x26c)
+#define USB3_USB_OTG_INT_ENA(p)        ((p)->is_rzv2m ? 0x418 : 0x270)
 #define USB3_P0_MOD            0x280
 #define USB3_P0_CON            0x288
 #define USB3_P0_STA            0x28c
 #define USB_STA_VBUS_STA       BIT(0)
 
 /* DRD_CON */
+#define DRD_CON_PERI_RST       BIT(31)         /* rzv2m only */
+#define DRD_CON_HOST_RST       BIT(30)         /* rzv2m only */
 #define DRD_CON_PERI_CON       BIT(24)
 #define DRD_CON_VBOUT          BIT(0)
 
 #define USB_INT_2_PIPE(n)      BIT(n)
 
 /* USB_OTG_STA, USB_OTG_INT_STA and USB_OTG_INT_ENA */
-#define USB_OTG_IDMON          BIT(4)
+#define USB_OTG_IDMON(p)       ((p)->is_rzv2m ? BIT(0) : BIT(4))
 
 /* P0_MOD */
 #define P0_MOD_DIR             BIT(6)
 #define USB3_EP0_SS_MAX_PACKET_SIZE    512
 #define USB3_EP0_HSFS_MAX_PACKET_SIZE  64
 #define USB3_EP0_BUF_SIZE              8
-#define USB3_MAX_NUM_PIPES             6       /* This includes PIPE 0 */
+#define USB3_MAX_NUM_PIPES(p)          ((p)->is_rzv2m ? 16 : 6)        /* This includes PIPE 0 */
 #define USB3_WAIT_US                   3
 #define USB3_DMA_NUM_SETTING_AREA      4
 /*
@@ -326,10 +329,13 @@ struct renesas_usb3_priv {
        int num_ramif;
        int ramsize_per_pipe;           /* unit = bytes */
        bool workaround_for_vbus;       /* if true, don't check vbus signal */
+       bool is_rzv2m;                  /* if true, RZ/V2M SoC */
 };
 
 struct renesas_usb3 {
        void __iomem *reg;
+       struct reset_control *drd_rstc;
+       struct reset_control *usbp_rstc;
 
        struct usb_gadget gadget;
        struct usb_gadget_driver *driver;
@@ -363,6 +369,7 @@ struct renesas_usb3 {
        bool forced_b_device;
        bool start_to_connect;
        bool role_sw_by_connector;
+       bool is_rzv2m;
 };
 
 #define gadget_to_renesas_usb3(_gadget)        \
@@ -467,7 +474,7 @@ static void usb3_disable_pipe_irq(struct renesas_usb3 *usb3, int num)
 
 static bool usb3_is_host(struct renesas_usb3 *usb3)
 {
-       return !(usb3_read(usb3, USB3_DRD_CON) & DRD_CON_PERI_CON);
+       return !(usb3_read(usb3, USB3_DRD_CON(usb3)) & DRD_CON_PERI_CON);
 }
 
 static void usb3_init_axi_bridge(struct renesas_usb3 *usb3)
@@ -674,10 +681,20 @@ static void renesas_usb3_role_work(struct work_struct *work)
 
 static void usb3_set_mode(struct renesas_usb3 *usb3, bool host)
 {
+       if (usb3->is_rzv2m) {
+               if (host) {
+                       usb3_set_bit(usb3, DRD_CON_PERI_RST, USB3_DRD_CON(usb3));
+                       usb3_clear_bit(usb3, DRD_CON_HOST_RST, USB3_DRD_CON(usb3));
+               } else {
+                       usb3_set_bit(usb3, DRD_CON_HOST_RST, USB3_DRD_CON(usb3));
+                       usb3_clear_bit(usb3, DRD_CON_PERI_RST, USB3_DRD_CON(usb3));
+               }
+       }
+
        if (host)
-               usb3_clear_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
+               usb3_clear_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON(usb3));
        else
-               usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
+               usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON(usb3));
 }
 
 static void usb3_set_mode_by_role_sw(struct renesas_usb3 *usb3, bool host)
@@ -693,9 +710,9 @@ static void usb3_set_mode_by_role_sw(struct renesas_usb3 *usb3, bool host)
 static void usb3_vbus_out(struct renesas_usb3 *usb3, bool enable)
 {
        if (enable)
-               usb3_set_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON);
+               usb3_set_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON(usb3));
        else
-               usb3_clear_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON);
+               usb3_clear_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON(usb3));
 }
 
 static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
@@ -716,7 +733,7 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
 
 static bool usb3_is_a_device(struct renesas_usb3 *usb3)
 {
-       return !(usb3_read(usb3, USB3_USB_OTG_STA) & USB_OTG_IDMON);
+       return !(usb3_read(usb3, USB3_USB_OTG_STA(usb3)) & USB_OTG_IDMON(usb3));
 }
 
 static void usb3_check_id(struct renesas_usb3 *usb3)
@@ -739,8 +756,8 @@ static void renesas_usb3_init_controller(struct renesas_usb3 *usb3)
        usb3_set_bit(usb3, USB_COM_CON_PN_WDATAIF_NL |
                     USB_COM_CON_PN_RDATAIF_NL | USB_COM_CON_PN_LSTTR_PP,
                     USB3_USB_COM_CON);
-       usb3_write(usb3, USB_OTG_IDMON, USB3_USB_OTG_INT_STA);
-       usb3_write(usb3, USB_OTG_IDMON, USB3_USB_OTG_INT_ENA);
+       usb3_write(usb3, USB_OTG_IDMON(usb3), USB3_USB_OTG_INT_STA(usb3));
+       usb3_write(usb3, USB_OTG_IDMON(usb3), USB3_USB_OTG_INT_ENA(usb3));
 
        usb3_check_id(usb3);
        usb3_check_vbus(usb3);
@@ -750,7 +767,7 @@ static void renesas_usb3_stop_controller(struct renesas_usb3 *usb3)
 {
        usb3_disconnect(usb3);
        usb3_write(usb3, 0, USB3_P0_INT_ENA);
-       usb3_write(usb3, 0, USB3_USB_OTG_INT_ENA);
+       usb3_write(usb3, 0, USB3_USB_OTG_INT_ENA(usb3));
        usb3_write(usb3, 0, USB3_USB_INT_ENA_1);
        usb3_write(usb3, 0, USB3_USB_INT_ENA_2);
        usb3_write(usb3, 0, USB3_AXI_INT_ENA);
@@ -2005,9 +2022,15 @@ static void usb3_irq_idmon_change(struct renesas_usb3 *usb3)
        usb3_check_id(usb3);
 }
 
-static void usb3_irq_otg_int(struct renesas_usb3 *usb3, u32 otg_int_sta)
+static void usb3_irq_otg_int(struct renesas_usb3 *usb3)
 {
-       if (otg_int_sta & USB_OTG_IDMON)
+       u32 otg_int_sta = usb3_read(usb3, USB3_USB_OTG_INT_STA(usb3));
+
+       otg_int_sta &= usb3_read(usb3, USB3_USB_OTG_INT_ENA(usb3));
+       if (otg_int_sta)
+               usb3_write(usb3, otg_int_sta, USB3_USB_OTG_INT_STA(usb3));
+
+       if (otg_int_sta & USB_OTG_IDMON(usb3))
                usb3_irq_idmon_change(usb3);
 }
 
@@ -2015,7 +2038,6 @@ static void usb3_irq_epc(struct renesas_usb3 *usb3)
 {
        u32 int_sta_1 = usb3_read(usb3, USB3_USB_INT_STA_1);
        u32 int_sta_2 = usb3_read(usb3, USB3_USB_INT_STA_2);
-       u32 otg_int_sta = usb3_read(usb3, USB3_USB_OTG_INT_STA);
 
        int_sta_1 &= usb3_read(usb3, USB3_USB_INT_ENA_1);
        if (int_sta_1) {
@@ -2027,11 +2049,8 @@ static void usb3_irq_epc(struct renesas_usb3 *usb3)
        if (int_sta_2)
                usb3_irq_epc_int_2(usb3, int_sta_2);
 
-       otg_int_sta &= usb3_read(usb3, USB3_USB_OTG_INT_ENA);
-       if (otg_int_sta) {
-               usb3_write(usb3, otg_int_sta, USB3_USB_OTG_INT_STA);
-               usb3_irq_otg_int(usb3, otg_int_sta);
-       }
+       if (!usb3->is_rzv2m)
+               usb3_irq_otg_int(usb3);
 }
 
 static void usb3_irq_dma_int(struct renesas_usb3 *usb3, u32 dma_sta)
@@ -2085,6 +2104,15 @@ static irqreturn_t renesas_usb3_irq(int irq, void *_usb3)
        return ret;
 }
 
+static irqreturn_t renesas_usb3_otg_irq(int irq, void *_usb3)
+{
+       struct renesas_usb3 *usb3 = _usb3;
+
+       usb3_irq_otg_int(usb3);
+
+       return IRQ_HANDLED;
+}
+
 static void usb3_write_pn_mod(struct renesas_usb3_ep *usb3_ep,
                              const struct usb_endpoint_descriptor *desc)
 {
@@ -2571,6 +2599,8 @@ static int renesas_usb3_remove(struct platform_device *pdev)
        usb_role_switch_unregister(usb3->role_sw);
 
        usb_del_gadget_udc(&usb3->gadget);
+       reset_control_assert(usb3->usbp_rstc);
+       reset_control_assert(usb3->drd_rstc);
        renesas_usb3_dma_free_prd(usb3, &pdev->dev);
 
        __renesas_usb3_ep_free_request(usb3->ep0_req);
@@ -2589,8 +2619,8 @@ static int renesas_usb3_init_ep(struct renesas_usb3 *usb3, struct device *dev,
        usb3->num_usb3_eps = priv->ramsize_per_ramif * priv->num_ramif * 2 /
                             priv->ramsize_per_pipe + 1;
 
-       if (usb3->num_usb3_eps > USB3_MAX_NUM_PIPES)
-               usb3->num_usb3_eps = USB3_MAX_NUM_PIPES;
+       if (usb3->num_usb3_eps > USB3_MAX_NUM_PIPES(usb3))
+               usb3->num_usb3_eps = USB3_MAX_NUM_PIPES(usb3);
 
        usb3->usb3_ep = devm_kcalloc(dev,
                                     usb3->num_usb3_eps, sizeof(*usb3_ep),
@@ -2707,6 +2737,13 @@ static const struct renesas_usb3_priv renesas_usb3_priv_r8a77990 = {
        .workaround_for_vbus = true,
 };
 
+static const struct renesas_usb3_priv renesas_usb3_priv_rzv2m = {
+       .ramsize_per_ramif = SZ_16K,
+       .num_ramif = 1,
+       .ramsize_per_pipe = SZ_4K,
+       .is_rzv2m = true,
+};
+
 static const struct of_device_id usb3_of_match[] = {
        {
                .compatible = "renesas,r8a774c0-usb3-peri",
@@ -2718,6 +2755,9 @@ static const struct of_device_id usb3_of_match[] = {
                .compatible = "renesas,r8a77990-usb3-peri",
                .data = &renesas_usb3_priv_r8a77990,
        }, {
+               .compatible = "renesas,rzv2m-usb3-peri",
+               .data = &renesas_usb3_priv_rzv2m,
+       }, {
                .compatible = "renesas,rcar-gen3-usb3-peri",
                .data = &renesas_usb3_priv_gen3,
        },
@@ -2748,7 +2788,7 @@ static struct usb_role_switch_desc renesas_usb3_role_switch_desc = {
 static int renesas_usb3_probe(struct platform_device *pdev)
 {
        struct renesas_usb3 *usb3;
-       int irq, ret;
+       int irq, drd_irq, ret;
        const struct renesas_usb3_priv *priv;
        const struct soc_device_attribute *attr;
 
@@ -2762,10 +2802,18 @@ static int renesas_usb3_probe(struct platform_device *pdev)
        if (irq < 0)
                return irq;
 
+       if (priv->is_rzv2m) {
+               drd_irq = platform_get_irq_byname(pdev, "drd");
+               if (drd_irq < 0)
+                       return drd_irq;
+       }
+
        usb3 = devm_kzalloc(&pdev->dev, sizeof(*usb3), GFP_KERNEL);
        if (!usb3)
                return -ENOMEM;
 
+       usb3->is_rzv2m = priv->is_rzv2m;
+
        usb3->reg = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(usb3->reg))
                return PTR_ERR(usb3->reg);
@@ -2787,6 +2835,14 @@ static int renesas_usb3_probe(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
+       if (usb3->is_rzv2m) {
+               ret = devm_request_irq(&pdev->dev, drd_irq,
+                                      renesas_usb3_otg_irq, 0,
+                                      dev_name(&pdev->dev), usb3);
+               if (ret < 0)
+                       return ret;
+       }
+
        INIT_WORK(&usb3->extcon_work, renesas_usb3_extcon_work);
        usb3->extcon = devm_extcon_dev_allocate(&pdev->dev, renesas_usb3_cable);
        if (IS_ERR(usb3->extcon))
@@ -2817,10 +2873,27 @@ static int renesas_usb3_probe(struct platform_device *pdev)
                goto err_add_udc;
        }
 
+       usb3->drd_rstc = devm_reset_control_get_optional_shared(&pdev->dev,
+                                                               "drd_reset");
+       if (IS_ERR(usb3->drd_rstc)) {
+               ret = PTR_ERR(usb3->drd_rstc);
+               goto err_add_udc;
+       }
+
+       usb3->usbp_rstc = devm_reset_control_get_optional_shared(&pdev->dev,
+                                                                "aresetn_p");
+       if (IS_ERR(usb3->usbp_rstc)) {
+               ret = PTR_ERR(usb3->usbp_rstc);
+               goto err_add_udc;
+       }
+
+       reset_control_deassert(usb3->drd_rstc);
+       reset_control_deassert(usb3->usbp_rstc);
+
        pm_runtime_enable(&pdev->dev);
        ret = usb_add_gadget_udc(&pdev->dev, &usb3->gadget);
        if (ret < 0)
-               goto err_add_udc;
+               goto err_reset;
 
        ret = device_create_file(&pdev->dev, &dev_attr_role);
        if (ret < 0)
@@ -2858,6 +2931,10 @@ static int renesas_usb3_probe(struct platform_device *pdev)
 err_dev_create:
        usb_del_gadget_udc(&usb3->gadget);
 
+err_reset:
+       reset_control_assert(usb3->usbp_rstc);
+       reset_control_assert(usb3->drd_rstc);
+
 err_add_udc:
        renesas_usb3_dma_free_prd(usb3, &pdev->dev);
 
index c6625ae..8c57b19 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/prefetch.h>
 #include <linux/io.h>
 
@@ -1419,8 +1419,7 @@ static int s3c2410_udc_set_pullup(struct s3c2410_udc *udc, int is_on)
 {
        dprintk(DEBUG_NORMAL, "%s()\n", __func__);
 
-       if (udc_info && (udc_info->udc_command ||
-               gpio_is_valid(udc_info->pullup_pin))) {
+       if (udc_info && (udc_info->udc_command || udc->pullup_gpiod)) {
 
                if (is_on)
                        s3c2410_udc_enable(udc);
@@ -1467,9 +1466,7 @@ static irqreturn_t s3c2410_udc_vbus_irq(int irq, void *_dev)
 
        dprintk(DEBUG_NORMAL, "%s()\n", __func__);
 
-       value = gpio_get_value(udc_info->vbus_pin) ? 1 : 0;
-       if (udc_info->vbus_pin_inverted)
-               value = !value;
+       value = gpiod_get_value(dev->vbus_gpiod);
 
        if (value != dev->vbus)
                s3c2410_udc_vbus_session(&dev->gadget, value);
@@ -1504,14 +1501,15 @@ static const struct usb_gadget_ops s3c2410_ops = {
        .udc_stop               = s3c2410_udc_stop,
 };
 
-static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd)
+static void s3c2410_udc_command(struct s3c2410_udc *udc,
+                               enum s3c2410_udc_cmd_e cmd)
 {
        if (!udc_info)
                return;
 
        if (udc_info->udc_command) {
                udc_info->udc_command(cmd);
-       } else if (gpio_is_valid(udc_info->pullup_pin)) {
+       } else if (udc->pullup_gpiod) {
                int value;
 
                switch (cmd) {
@@ -1524,9 +1522,8 @@ static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd)
                default:
                        return;
                }
-               value ^= udc_info->pullup_pin_inverted;
 
-               gpio_set_value(udc_info->pullup_pin, value);
+               gpiod_set_value(udc->pullup_gpiod, value);
        }
 }
 
@@ -1551,7 +1548,7 @@ static void s3c2410_udc_disable(struct s3c2410_udc *dev)
        udc_write(0x1F, S3C2410_UDC_EP_INT_REG);
 
        /* Good bye, cruel world */
-       s3c2410_udc_command(S3C2410_UDC_P_DISABLE);
+       s3c2410_udc_command(dev, S3C2410_UDC_P_DISABLE);
 
        /* Set speed to unknown */
        dev->gadget.speed = USB_SPEED_UNKNOWN;
@@ -1613,7 +1610,7 @@ static void s3c2410_udc_enable(struct s3c2410_udc *dev)
        udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_EN_REG);
 
        /* time to say "hello, world" */
-       s3c2410_udc_command(S3C2410_UDC_P_ENABLE);
+       s3c2410_udc_command(dev, S3C2410_UDC_P_ENABLE);
 }
 
 static int s3c2410_udc_start(struct usb_gadget *g,
@@ -1802,14 +1799,15 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
 
        dev_dbg(dev, "got irq %i\n", irq_usbd);
 
-       if (udc_info && udc_info->vbus_pin > 0) {
-               retval = gpio_request(udc_info->vbus_pin, "udc vbus");
-               if (retval < 0) {
-                       dev_err(dev, "cannot claim vbus pin\n");
-                       goto err_int;
-               }
+       udc->vbus_gpiod = gpiod_get_optional(dev, "vbus", GPIOD_IN);
+       if (IS_ERR(udc->vbus_gpiod)) {
+               retval = PTR_ERR(udc->vbus_gpiod);
+               goto err_int;
+       }
+       if (udc->vbus_gpiod) {
+               gpiod_set_consumer_name(udc->vbus_gpiod, "udc vbus");
 
-               irq = gpio_to_irq(udc_info->vbus_pin);
+               irq = gpiod_to_irq(udc->vbus_gpiod);
                if (irq < 0) {
                        dev_err(dev, "no irq for gpio vbus pin\n");
                        retval = irq;
@@ -1833,16 +1831,12 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
                udc->vbus = 1;
        }
 
-       if (udc_info && !udc_info->udc_command &&
-               gpio_is_valid(udc_info->pullup_pin)) {
-
-               retval = gpio_request_one(udc_info->pullup_pin,
-                               udc_info->vbus_pin_inverted ?
-                               GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
-                               "udc pullup");
-               if (retval)
-                       goto err_vbus_irq;
+       udc->pullup_gpiod = gpiod_get_optional(dev, "pullup", GPIOD_OUT_LOW);
+       if (IS_ERR(udc->pullup_gpiod)) {
+               retval = PTR_ERR(udc->pullup_gpiod);
+               goto err_vbus_irq;
        }
+       gpiod_set_consumer_name(udc->pullup_gpiod, "udc pullup");
 
        retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
        if (retval)
@@ -1856,15 +1850,10 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
        return 0;
 
 err_add_udc:
-       if (udc_info && !udc_info->udc_command &&
-                       gpio_is_valid(udc_info->pullup_pin))
-               gpio_free(udc_info->pullup_pin);
 err_vbus_irq:
-       if (udc_info && udc_info->vbus_pin > 0)
-               free_irq(gpio_to_irq(udc_info->vbus_pin), udc);
+       if (udc->vbus_gpiod)
+               free_irq(gpiod_to_irq(udc->vbus_gpiod), udc);
 err_gpio_claim:
-       if (udc_info && udc_info->vbus_pin > 0)
-               gpio_free(udc_info->vbus_pin);
 err_int:
        free_irq(irq_usbd, udc);
 err_udc_clk:
@@ -1885,7 +1874,6 @@ err_usb_bus_clk:
 static int s3c2410_udc_remove(struct platform_device *pdev)
 {
        struct s3c2410_udc *udc = platform_get_drvdata(pdev);
-       unsigned int irq;
 
        dev_dbg(&pdev->dev, "%s()\n", __func__);
 
@@ -1895,14 +1883,8 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
        usb_del_gadget_udc(&udc->gadget);
        debugfs_remove(debugfs_lookup("registers", s3c2410_udc_debugfs_root));
 
-       if (udc_info && !udc_info->udc_command &&
-               gpio_is_valid(udc_info->pullup_pin))
-               gpio_free(udc_info->pullup_pin);
-
-       if (udc_info && udc_info->vbus_pin > 0) {
-               irq = gpio_to_irq(udc_info->vbus_pin);
-               free_irq(irq, udc);
-       }
+       if (udc->vbus_gpiod)
+               free_irq(gpiod_to_irq(udc->vbus_gpiod), udc);
 
        free_irq(irq_usbd, udc);
 
@@ -1926,14 +1908,18 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
 static int
 s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message)
 {
-       s3c2410_udc_command(S3C2410_UDC_P_DISABLE);
+       struct s3c2410_udc *udc = platform_get_drvdata(pdev);
+
+       s3c2410_udc_command(udc, S3C2410_UDC_P_DISABLE);
 
        return 0;
 }
 
 static int s3c2410_udc_resume(struct platform_device *pdev)
 {
-       s3c2410_udc_command(S3C2410_UDC_P_ENABLE);
+       struct s3c2410_udc *udc = platform_get_drvdata(pdev);
+
+       s3c2410_udc_command(udc, S3C2410_UDC_P_ENABLE);
 
        return 0;
 }
index 135a5bf..cdbf202 100644 (file)
@@ -83,6 +83,9 @@ struct s3c2410_udc {
        u32                             port_status;
        int                             ep0state;
 
+       struct gpio_desc                *vbus_gpiod;
+       struct gpio_desc                *pullup_gpiod;
+
        unsigned                        got_irq : 1;
 
        unsigned                        req_std : 1;
index 3c37eff..76919d7 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * NVIDIA Tegra XUSB device mode controller
  *
- * Copyright (c) 2013-2019, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2013-2022, NVIDIA CORPORATION.  All rights reserved.
  * Copyright (c) 2015, Google Inc.
  */
 
@@ -702,6 +702,8 @@ static void tegra_xudc_device_mode_on(struct tegra_xudc *xudc)
 
        pm_runtime_get_sync(xudc->dev);
 
+       tegra_phy_xusb_utmi_pad_power_on(xudc->curr_utmi_phy);
+
        err = phy_power_on(xudc->curr_utmi_phy);
        if (err < 0)
                dev_err(xudc->dev, "UTMI power on failed: %d\n", err);
@@ -756,6 +758,8 @@ static void tegra_xudc_device_mode_off(struct tegra_xudc *xudc)
        /* Make sure interrupt handler has completed before powergating. */
        synchronize_irq(xudc->irq);
 
+       tegra_phy_xusb_utmi_pad_power_down(xudc->curr_utmi_phy);
+
        err = phy_power_off(xudc->curr_utmi_phy);
        if (err < 0)
                dev_err(xudc->dev, "UTMI PHY power off failed: %d\n", err);
index fd9264c..247568b 100644 (file)
@@ -205,12 +205,12 @@ config USB_EHCI_FSL
          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
-       default y if (USB_EHCI_HCD && ARCH_NPCM7XX)
+       tristate "Support for Nuvoton NPCM on-chip EHCI USB controller"
+       depends on (USB_EHCI_HCD && ARCH_NPCM) || COMPILE_TEST
+       default y if (USB_EHCI_HCD && ARCH_NPCM)
        help
          Enables support for the on-chip EHCI controller on
-         Nuvoton NPCM7XX chips.
+         Nuvoton NPCM chips.
 
 config USB_EHCI_HCD_OMAP
        tristate "EHCI support for OMAP3 and later chips"
index 05d41fd..8b775e7 100644 (file)
@@ -25,8 +25,6 @@
 
 #define DRIVER_DESC "EHCI Atmel driver"
 
-static const char hcd_name[] = "ehci-atmel";
-
 #define EHCI_INSNREG(index)                    ((index) * 4 + 0x90)
 #define EHCI_INSNREG08_HSIC_EN                 BIT(2)
 
@@ -239,7 +237,6 @@ static int __init ehci_atmel_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
        ehci_init_driver(&ehci_atmel_hc_driver, &ehci_atmel_drv_overrides);
        return platform_driver_register(&ehci_atmel_driver);
 }
index 1a9b757..a333231 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
 #include <linux/usb.h>
@@ -32,7 +32,6 @@
        (EHCI_INSNREG00_ENA_INCR16 | EHCI_INSNREG00_ENA_INCR8 | \
         EHCI_INSNREG00_ENA_INCR4 | EHCI_INSNREG00_ENA_INCRX_ALIGN)
 
-static const char hcd_name[] = "ehci-exynos";
 static struct hc_driver __read_mostly exynos_ehci_hc_driver;
 
 #define PHY_NUMBER 3
@@ -132,20 +131,13 @@ static void exynos_ehci_phy_disable(struct device *dev)
 
 static void exynos_setup_vbus_gpio(struct device *dev)
 {
+       struct gpio_desc *gpio;
        int err;
-       int gpio;
 
-       if (!dev->of_node)
-               return;
-
-       gpio = of_get_named_gpio(dev->of_node, "samsung,vbus-gpio", 0);
-       if (!gpio_is_valid(gpio))
-               return;
-
-       err = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_HIGH,
-                                   "ehci_vbus_gpio");
+       gpio = devm_gpiod_get_optional(dev, "samsung,vbus", GPIOD_OUT_HIGH);
+       err = PTR_ERR_OR_ZERO(gpio);
        if (err)
-               dev_err(dev, "can't request ehci vbus gpio %d", gpio);
+               dev_err(dev, "can't request ehci vbus gpio: %d\n", err);
 }
 
 static int exynos_ehci_probe(struct platform_device *pdev)
@@ -347,7 +339,6 @@ static int __init ehci_exynos_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
        ehci_init_driver(&exynos_ehci_hc_driver, &exynos_overrides);
        return platform_driver_register(&exynos_ehci_driver);
 }
index 896c0d1..9cea785 100644 (file)
@@ -722,8 +722,6 @@ static int __init ehci_fsl_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info(DRV_NAME ": " DRIVER_DESC "\n");
-
        ehci_init_driver(&fsl_ehci_hc_driver, &ehci_fsl_overrides);
 
        fsl_ehci_hc_driver.product_desc =
index 684164f..a1930db 100644 (file)
@@ -1351,7 +1351,6 @@ static int __init ehci_hcd_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       printk(KERN_INFO "%s: " DRIVER_DESC "\n", hcd_name);
        set_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
        if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) ||
                        test_bit(USB_OHCI_LOADED, &usb_hcds_loaded))
index 6b5a7a8..63af1a8 100644 (file)
 
 #include "ehci.h"
 
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-
 #define DRIVER_DESC "EHCI npcm7xx driver"
 
-static const char hcd_name[] = "npcm7xx-ehci";
-
-#define  USB2PHYCTL_OFFSET 0x144
-
-#define  IPSRST2_OFFSET 0x24
-#define  IPSRST3_OFFSET 0x34
-
-
 static struct hc_driver __read_mostly ehci_npcm7xx_hc_driver;
 
 static int __maybe_unused ehci_npcm7xx_drv_suspend(struct device *dev)
@@ -60,52 +49,12 @@ static int npcm7xx_ehci_hcd_drv_probe(struct platform_device *pdev)
 {
        struct usb_hcd *hcd;
        struct resource *res;
-       struct regmap *gcr_regmap;
-       struct regmap *rst_regmap;
        const struct hc_driver *driver = &ehci_npcm7xx_hc_driver;
        int irq;
        int retval;
 
        dev_dbg(&pdev->dev,     "initializing npcm7xx ehci USB Controller\n");
 
-       gcr_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr");
-       if (IS_ERR(gcr_regmap)) {
-               dev_err(&pdev->dev, "%s: failed to find nuvoton,npcm750-gcr\n",
-                       __func__);
-               return PTR_ERR(gcr_regmap);
-       }
-
-       rst_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-rst");
-       if (IS_ERR(rst_regmap)) {
-               dev_err(&pdev->dev, "%s: failed to find nuvoton,npcm750-rst\n",
-                       __func__);
-               return PTR_ERR(rst_regmap);
-       }
-
-       /********* phy init  ******/
-       // reset usb host
-       regmap_update_bits(rst_regmap, IPSRST2_OFFSET,
-                       (0x1 << 26), (0x1 << 26));
-       regmap_update_bits(rst_regmap, IPSRST3_OFFSET,
-                       (0x1 << 25), (0x1 << 25));
-       regmap_update_bits(gcr_regmap, USB2PHYCTL_OFFSET,
-                       (0x1 << 28), 0);
-
-       udelay(1);
-
-       // enable phy
-       regmap_update_bits(rst_regmap, IPSRST3_OFFSET,
-                       (0x1 << 25), 0);
-
-       udelay(50); // enable phy
-
-       regmap_update_bits(gcr_regmap, USB2PHYCTL_OFFSET,
-                       (0x1 << 28), (0x1 << 28));
-
-       // enable host
-       regmap_update_bits(rst_regmap, IPSRST2_OFFSET,
-                       (0x1 << 26), 0);
-
        if (usb_disabled())
                return -ENODEV;
 
@@ -191,8 +140,6 @@ static int __init ehci_npcm7xx_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-
        ehci_init_driver(&ehci_npcm7xx_hc_driver, NULL);
        return platform_driver_register(&npcm7xx_ehci_hcd_driver);
 }
index 8c45bc1..7dd9847 100644 (file)
@@ -284,8 +284,6 @@ static int __init ehci_omap_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-
        ehci_init_driver(&ehci_omap_hc_driver, &ehci_omap_overrides);
        return platform_driver_register(&ehci_hcd_omap_driver);
 }
index 3626758..a3454a3 100644 (file)
@@ -65,8 +65,6 @@ struct orion_ehci_hcd {
        struct phy *phy;
 };
 
-static const char hcd_name[] = "ehci-orion";
-
 static struct hc_driver __read_mostly ehci_orion_hc_driver;
 
 /*
@@ -361,8 +359,6 @@ static int __init ehci_orion_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-
        ehci_init_driver(&ehci_orion_hc_driver, &orion_overrides);
        return platform_driver_register(&ehci_orion_driver);
 }
index 9937c5a..17f8b6e 100644 (file)
@@ -382,7 +382,7 @@ static int ehci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        if (is_bypassed_id(pdev))
                return -ENODEV;
-       return usb_hcd_pci_probe(pdev, id, &ehci_pci_hc_driver);
+       return usb_hcd_pci_probe(pdev, &ehci_pci_hc_driver);
 }
 
 static void ehci_pci_remove(struct pci_dev *pdev)
@@ -423,8 +423,6 @@ static int __init ehci_pci_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-
        ehci_init_driver(&ehci_pci_hc_driver, &pci_overrides);
 
        /* Entries for the PCI suspend/resume callbacks are special */
index 6924f03..fe497c8 100644 (file)
@@ -53,8 +53,6 @@ struct ehci_platform_priv {
        struct delayed_work poll_work;
 };
 
-static const char hcd_name[] = "ehci-platform";
-
 static int ehci_platform_reset(struct usb_hcd *hcd)
 {
        struct platform_device *pdev = to_platform_device(hcd->self.controller);
@@ -529,8 +527,6 @@ static int __init ehci_platform_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-
        ehci_init_driver(&ehci_platform_hc_driver, &platform_overrides);
        return platform_driver_register(&ehci_platform_driver);
 }
index 807e649..666f5c4 100644 (file)
@@ -645,7 +645,7 @@ qh_urb_transaction (
                token |= (1 /* "in" */ << 8);
        /* else it's already initted to "out" pid (0 << 8) */
 
-       maxpacket = usb_maxpacket(urb->dev, urb->pipe);
+       maxpacket = usb_endpoint_maxp(&urb->ep->desc);
 
        /*
         * buffer gets wrapped in one or more qtds;
@@ -1218,7 +1218,7 @@ static int ehci_submit_single_step_set_feature(
 
        token |= (1 /* "in" */ << 8);  /*This is IN stage*/
 
-       maxpacket = usb_maxpacket(urb->dev, urb->pipe);
+       maxpacket = usb_endpoint_maxp(&urb->ep->desc);
 
        qtd_fill(ehci, qtd, buf, len, token, maxpacket);
 
index 3694e45..c4ddd10 100644 (file)
@@ -24,8 +24,6 @@
 
 #define DRIVER_DESC "EHCI SPEAr driver"
 
-static const char hcd_name[] = "SPEAr-ehci";
-
 struct spear_ehci {
        struct clk *clk;
 };
@@ -167,8 +165,6 @@ static int __init ehci_spear_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-
        ehci_init_driver(&ehci_spear_hc_driver, &spear_overrides);
        return platform_driver_register(&spear_ehci_hcd_driver);
 }
index f74433a..f731dc9 100644 (file)
@@ -42,8 +42,6 @@ struct st_ehci_platform_priv {
 #define hcd_to_ehci_priv(h) \
        ((struct st_ehci_platform_priv *)hcd_to_ehci(h)->priv)
 
-static const char hcd_name[] = "ehci-st";
-
 #define EHCI_CAPS_SIZE 0x10
 #define AHB2STBUS_INSREG01 (EHCI_CAPS_SIZE + 0x84)
 
@@ -346,8 +344,6 @@ static int __init ehci_platform_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-
        ehci_init_driver(&ehci_platform_hc_driver, &platform_overrides);
        return platform_driver_register(&ehci_platform_driver);
 }
index 2ba09c3..95a4446 100644 (file)
@@ -25,8 +25,8 @@
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
-#include <linux/of_gpio.h>
 #include <linux/slab.h>
+#include <linux/gpio/consumer.h>
 #include <soc/fsl/qe/qe.h>
 #include <asm/fsl_gtm.h>
 #include "fhci.h"
@@ -150,15 +150,15 @@ int fhci_ioports_check_bus_state(struct fhci_hcd *fhci)
        u8 bits = 0;
 
        /* check USBOE,if transmitting,exit */
-       if (!gpio_get_value(fhci->gpios[GPIO_USBOE]))
+       if (!gpiod_get_value(fhci->gpiods[GPIO_USBOE]))
                return -1;
 
        /* check USBRP */
-       if (gpio_get_value(fhci->gpios[GPIO_USBRP]))
+       if (gpiod_get_value(fhci->gpiods[GPIO_USBRP]))
                bits |= 0x2;
 
        /* check USBRN */
-       if (gpio_get_value(fhci->gpios[GPIO_USBRN]))
+       if (gpiod_get_value(fhci->gpiods[GPIO_USBRN]))
                bits |= 0x1;
 
        return bits;
@@ -630,40 +630,23 @@ static int of_fhci_probe(struct platform_device *ofdev)
 
        /* GPIOs and pins */
        for (i = 0; i < NUM_GPIOS; i++) {
-               int gpio;
-               enum of_gpio_flags flags;
-
-               gpio = of_get_gpio_flags(node, i, &flags);
-               fhci->gpios[i] = gpio;
-               fhci->alow_gpios[i] = flags & OF_GPIO_ACTIVE_LOW;
-
-               if (!gpio_is_valid(gpio)) {
-                       if (i < GPIO_SPEED) {
-                               dev_err(dev, "incorrect GPIO%d: %d\n",
-                                       i, gpio);
-                               goto err_gpios;
-                       } else {
-                               dev_info(dev, "assuming board doesn't have "
-                                       "%s gpio\n", i == GPIO_SPEED ?
-                                       "speed" : "power");
-                               continue;
-                       }
-               }
+               if (i < GPIO_SPEED)
+                       fhci->gpiods[i] = devm_gpiod_get_index(dev,
+                                       NULL, i, GPIOD_IN);
+
+               else
+                       fhci->gpiods[i] = devm_gpiod_get_index_optional(dev,
+                                       NULL, i, GPIOD_OUT_LOW);
 
-               ret = gpio_request(gpio, dev_name(dev));
-               if (ret) {
-                       dev_err(dev, "failed to request gpio %d", i);
+               if (IS_ERR(fhci->gpiods[i])) {
+                       dev_err(dev, "incorrect GPIO%d: %ld\n",
+                               i, PTR_ERR(fhci->gpiods[i]));
                        goto err_gpios;
                }
-
-               if (i >= GPIO_SPEED) {
-                       ret = gpio_direction_output(gpio, 0);
-                       if (ret) {
-                               dev_err(dev, "failed to set gpio %d as "
-                                       "an output\n", i);
-                               i++;
-                               goto err_gpios;
-                       }
+               if (!fhci->gpiods[i]) {
+                       dev_info(dev, "assuming board doesn't have "
+                                "%s gpio\n", i == GPIO_SPEED ?
+                                "speed" : "power");
                }
        }
 
@@ -766,10 +749,6 @@ err_pins:
        while (--j >= 0)
                qe_pin_free(fhci->pins[j]);
 err_gpios:
-       while (--i >= 0) {
-               if (gpio_is_valid(fhci->gpios[i]))
-                       gpio_free(fhci->gpios[i]);
-       }
        cpm_muram_free(pram_addr);
 err_pram:
        iounmap(hcd->regs);
@@ -782,18 +761,12 @@ static int fhci_remove(struct device *dev)
 {
        struct usb_hcd *hcd = dev_get_drvdata(dev);
        struct fhci_hcd *fhci = hcd_to_fhci(hcd);
-       int i;
        int j;
 
        usb_remove_hcd(hcd);
        free_irq(fhci->timer->irq, hcd);
        gtm_put_timer16(fhci->timer);
        cpm_muram_free(cpm_muram_offset(fhci->pram));
-       for (i = 0; i < NUM_GPIOS; i++) {
-               if (!gpio_is_valid(fhci->gpios[i]))
-                       continue;
-               gpio_free(fhci->gpios[i]);
-       }
        for (j = 0; j < NUM_PINS; j++)
                qe_pin_free(fhci->pins[j]);
        fhci_dfs_destroy(fhci);
index c359dcd..5f48660 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/io.h>
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <soc/fsl/qe/qe.h>
 #include "fhci.h"
 
@@ -38,13 +38,12 @@ static u8 root_hub_des[] = {
 
 static void fhci_gpio_set_value(struct fhci_hcd *fhci, int gpio_nr, bool on)
 {
-       int gpio = fhci->gpios[gpio_nr];
-       bool alow = fhci->alow_gpios[gpio_nr];
+       struct gpio_desc *gpiod = fhci->gpiods[gpio_nr];
 
-       if (!gpio_is_valid(gpio))
+       if (!gpiod)
                return;
 
-       gpio_set_value(gpio, on ^ alow);
+       gpiod_set_value(gpiod, on);
        mdelay(5);
 }
 
@@ -129,9 +128,9 @@ void fhci_io_port_generate_reset(struct fhci_hcd *fhci)
 {
        fhci_dbg(fhci, "-> %s\n", __func__);
 
-       gpio_direction_output(fhci->gpios[GPIO_USBOE], 0);
-       gpio_direction_output(fhci->gpios[GPIO_USBTP], 0);
-       gpio_direction_output(fhci->gpios[GPIO_USBTN], 0);
+       gpiod_direction_output(fhci->gpiods[GPIO_USBOE], 0);
+       gpiod_direction_output(fhci->gpiods[GPIO_USBTP], 0);
+       gpiod_direction_output(fhci->gpiods[GPIO_USBTN], 0);
 
        mdelay(5);
 
index 81fbc01..1f57b09 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/io.h>
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
+#include <linux/gpio/consumer.h>
 #include <soc/fsl/qe/qe.h>
 #include <soc/fsl/qe/immap_qe.h>
 
@@ -242,8 +243,7 @@ struct fhci_hcd {
        enum qe_clock fullspeed_clk;
        enum qe_clock lowspeed_clk;
        struct qe_pin *pins[NUM_PINS];
-       int gpios[NUM_GPIOS];
-       bool alow_gpios[NUM_GPIOS];
+       struct gpio_desc *gpiods[NUM_GPIOS];
 
        struct qe_usb_ctlr __iomem *regs; /* I/O memory used to communicate */
        struct fhci_pram __iomem *pram; /* Parameter RAM */
index f8c111e..3d1dbcf 100644 (file)
@@ -5692,7 +5692,6 @@ static int __init fotg210_hcd_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
        set_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
        if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) ||
                        test_bit(USB_OHCI_LOADED, &usb_hcds_loaded))
index 9832646..533537e 100644 (file)
@@ -62,8 +62,6 @@ struct ohci_at91_priv {
 
 #define DRIVER_DESC "OHCI Atmel driver"
 
-static const char hcd_name[] = "ohci-atmel";
-
 static struct hc_driver __read_mostly ohci_at91_hc_driver;
 
 static const struct ohci_driver_overrides ohci_at91_drv_overrides __initconst = {
@@ -699,7 +697,6 @@ static int __init ohci_at91_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
        ohci_init_driver(&ohci_at91_hc_driver, &ohci_at91_drv_overrides);
 
        /*
index 1371b0c..d4818e8 100644 (file)
@@ -551,7 +551,6 @@ static int __init ohci_da8xx_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", DRV_NAME);
        ohci_init_driver(&ohci_da8xx_hc_driver, &da8xx_overrides);
 
        /*
index 5f5e8a6..8d7977f 100644 (file)
@@ -21,7 +21,6 @@
 
 #define DRIVER_DESC "OHCI Exynos driver"
 
-static const char hcd_name[] = "ohci-exynos";
 static struct hc_driver __read_mostly exynos_ohci_hc_driver;
 
 #define to_exynos_ohci(hcd) (struct exynos_ohci_hcd *)(hcd_to_ohci(hcd)->priv)
@@ -310,7 +309,6 @@ static int __init ohci_exynos_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
        ohci_init_driver(&exynos_ohci_hc_driver, &exynos_overrides);
        return platform_driver_register(&exynos_ohci_driver);
 }
index c4c821c..0457dd9 100644 (file)
@@ -1276,7 +1276,6 @@ static int __init ohci_hcd_mod_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       printk(KERN_INFO "%s: " DRIVER_DESC "\n", hcd_name);
        pr_debug ("%s: block sizes: ed %zd td %zd\n", hcd_name,
                sizeof (struct ed), sizeof (struct td));
        set_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
index 106a6bc..5b32e68 100644 (file)
@@ -275,8 +275,6 @@ static int __init ohci_nxp_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-
        ohci_init_driver(&ohci_nxp_hc_driver, NULL);
        return platform_driver_register(&ohci_hcd_nxp_driver);
 }
index f5bc9c8..cb29701 100644 (file)
@@ -423,8 +423,6 @@ static int __init ohci_omap_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-
        ohci_init_driver(&ohci_omap_hc_driver, &omap_overrides);
        return platform_driver_register(&ohci_hcd_omap_driver);
 }
index 41efe92..d7b4f40 100644 (file)
@@ -282,7 +282,7 @@ MODULE_DEVICE_TABLE (pci, pci_ids);
 
 static int ohci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
-       return usb_hcd_pci_probe(dev, id, &ohci_pci_hc_driver);
+       return usb_hcd_pci_probe(dev, &ohci_pci_hc_driver);
 }
 
 /* pci driver glue; this is a "new style" PCI driver module */
@@ -306,8 +306,6 @@ static int __init ohci_pci_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-
        ohci_init_driver(&ohci_pci_hc_driver, &pci_overrides);
 
 #ifdef CONFIG_PM
index 0adae62..a843050 100644 (file)
@@ -41,8 +41,6 @@ struct ohci_platform_priv {
        struct reset_control *resets;
 };
 
-static const char hcd_name[] = "ohci-platform";
-
 static int ohci_platform_power_on(struct platform_device *dev)
 {
        struct usb_hcd *hcd = platform_get_drvdata(dev);
@@ -289,7 +287,7 @@ static int ohci_platform_suspend(struct device *dev)
        return ret;
 }
 
-static int ohci_platform_resume(struct device *dev)
+static int ohci_platform_resume_common(struct device *dev, bool hibernated)
 {
        struct usb_hcd *hcd = dev_get_drvdata(dev);
        struct usb_ohci_pdata *pdata = dev_get_platdata(dev);
@@ -301,7 +299,7 @@ static int ohci_platform_resume(struct device *dev)
                        return err;
        }
 
-       ohci_resume(hcd, false);
+       ohci_resume(hcd, hibernated);
 
        pm_runtime_disable(dev);
        pm_runtime_set_active(dev);
@@ -309,6 +307,16 @@ static int ohci_platform_resume(struct device *dev)
 
        return 0;
 }
+
+static int ohci_platform_resume(struct device *dev)
+{
+       return ohci_platform_resume_common(dev, false);
+}
+
+static int ohci_platform_restore(struct device *dev)
+{
+       return ohci_platform_resume_common(dev, true);
+}
 #endif /* CONFIG_PM_SLEEP */
 
 static const struct of_device_id ohci_platform_ids[] = {
@@ -325,8 +333,16 @@ static const struct platform_device_id ohci_platform_table[] = {
 };
 MODULE_DEVICE_TABLE(platform, ohci_platform_table);
 
-static SIMPLE_DEV_PM_OPS(ohci_platform_pm_ops, ohci_platform_suspend,
-       ohci_platform_resume);
+#ifdef CONFIG_PM_SLEEP
+static const struct dev_pm_ops ohci_platform_pm_ops = {
+       .suspend = ohci_platform_suspend,
+       .resume = ohci_platform_resume,
+       .freeze = ohci_platform_suspend,
+       .thaw = ohci_platform_resume,
+       .poweroff = ohci_platform_suspend,
+       .restore = ohci_platform_restore,
+};
+#endif
 
 static struct platform_driver ohci_platform_driver = {
        .id_table       = ohci_platform_table,
@@ -335,7 +351,9 @@ static struct platform_driver ohci_platform_driver = {
        .shutdown       = usb_hcd_platform_shutdown,
        .driver         = {
                .name   = "ohci-platform",
+#ifdef CONFIG_PM_SLEEP
                .pm     = &ohci_platform_pm_ops,
+#endif
                .of_match_table = ohci_platform_ids,
                .probe_type = PROBE_PREFER_ASYNCHRONOUS,
        }
@@ -346,8 +364,6 @@ static int __init ohci_platform_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-
        ohci_init_driver(&ohci_platform_hc_driver, &platform_overrides);
        return platform_driver_register(&ohci_platform_driver);
 }
index ab4f610..a1dad87 100644 (file)
 
 #define PXA_UHC_MAX_PORTNUM    3
 
-static const char hcd_name[] = "ohci-pxa27x";
-
 static struct hc_driver __read_mostly ohci_pxa27x_hc_driver;
 
 struct pxa27x_ohci {
@@ -608,8 +606,6 @@ static int __init ohci_pxa27x_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-
        ohci_init_driver(&ohci_pxa27x_hc_driver, &pxa27x_overrides);
        ohci_pxa27x_hc_driver.hub_control = pxa27x_ohci_hub_control;
 
index 12264c0..85a0a9a 100644 (file)
@@ -39,8 +39,6 @@
 
 #define DRIVER_DESC "OHCI S3C2410 driver"
 
-static const char hcd_name[] = "ohci-s3c2410";
-
 static struct clk *clk;
 static struct clk *usb_clk;
 
@@ -474,7 +472,6 @@ static int __init ohci_s3c2410_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
        ohci_init_driver(&ohci_s3c2410_hc_driver, NULL);
 
        /*
index 9b81f42..196951a 100644 (file)
@@ -23,7 +23,6 @@
 
 #define DRIVER_DESC "OHCI SPEAr driver"
 
-static const char hcd_name[] = "SPEAr-ohci";
 struct spear_ohci {
        struct clk *clk;
 };
@@ -179,8 +178,6 @@ static int __init ohci_spear_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-
        ohci_init_driver(&ohci_spear_hc_driver, &spear_overrides);
        return platform_driver_register(&spear_ohci_hcd_driver);
 }
index ac796cc..82eef3c 100644 (file)
@@ -40,8 +40,6 @@ struct st_ohci_platform_priv {
 #define hcd_to_ohci_priv(h) \
        ((struct st_ohci_platform_priv *)hcd_to_ohci(h)->priv)
 
-static const char hcd_name[] = "ohci-st";
-
 static int st_ohci_platform_power_on(struct platform_device *dev)
 {
        struct usb_hcd *hcd = platform_get_drvdata(dev);
@@ -324,8 +322,6 @@ static int __init ohci_platform_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-
        ohci_init_driver(&ohci_platform_hc_driver, &platform_overrides);
        return platform_driver_register(&ohci_platform_driver);
 }
index d879d6a..95240c9 100644 (file)
@@ -3190,7 +3190,6 @@ static int __init u132_hcd_init(void)
        u132_exiting = 0;
        if (usb_disabled())
                return -ENODEV;
-       printk(KERN_INFO "driver %s\n", hcd_name);
        workqueue = create_singlethread_workqueue("u132");
        if (!workqueue)
                return -ENOMEM;
index d90b869..c22b51a 100644 (file)
@@ -867,8 +867,6 @@ static int __init uhci_hcd_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       printk(KERN_INFO "uhci_hcd: " DRIVER_DESC "%s\n",
-                       ignore_oc ? ", overcurrent ignored" : "");
        set_bit(USB_UHCI_LOADED, &usb_hcds_loaded);
 
 #ifdef CONFIG_DYNAMIC_DEBUG
index 9b88745..3592f75 100644 (file)
@@ -294,7 +294,7 @@ MODULE_DEVICE_TABLE(pci, uhci_pci_ids);
 
 static int uhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
-       return usb_hcd_pci_probe(dev, id, &uhci_driver);
+       return usb_hcd_pci_probe(dev, &uhci_driver);
 }
 
 static struct pci_driver uhci_pci_driver = {
index e61155f..f1367b5 100644 (file)
@@ -988,7 +988,7 @@ xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver *
        dbc->driver = driver;
 
        if (readl(&dbc->regs->control) & DBC_CTRL_DBC_ENABLE)
-               return NULL;
+               goto err;
 
        INIT_DELAYED_WORK(&dbc->event_work, xhci_dbc_handle_events);
        spin_lock_init(&dbc->lock);
index 8c19e15..9e56aa2 100644 (file)
@@ -641,7 +641,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
                        num_stream_ctxs, &stream_info->ctx_array_dma,
                        mem_flags);
        if (!stream_info->stream_ctx_array)
-               goto cleanup_ctx;
+               goto cleanup_ring_array;
        memset(stream_info->stream_ctx_array, 0,
                        sizeof(struct xhci_stream_ctx)*num_stream_ctxs);
 
@@ -702,6 +702,11 @@ cleanup_rings:
        }
        xhci_free_command(xhci, stream_info->free_streams_command);
 cleanup_ctx:
+       xhci_free_stream_ctx(xhci,
+               stream_info->num_stream_ctxs,
+               stream_info->stream_ctx_array,
+               stream_info->ctx_array_dma);
+cleanup_ring_array:
        kfree(stream_info->stream_rings);
 cleanup_info:
        kfree(stream_info);
index dce6c0e..40228a3 100644 (file)
@@ -431,7 +431,7 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
         * to say USB 2.0, but I'm not sure what the implications would be in
         * the other parts of the HCD code.
         */
-       retval = usb_hcd_pci_probe(dev, id, &xhci_pci_hc_driver);
+       retval = usb_hcd_pci_probe(dev, &xhci_pci_hc_driver);
 
        if (retval)
                goto put_runtime_pm;
index a8641b6..5fb55bf 100644 (file)
@@ -123,7 +123,7 @@ static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = {
 };
 
 static const struct xhci_plat_priv xhci_plat_brcm = {
-       .quirks = XHCI_RESET_ON_RESUME,
+       .quirks = XHCI_RESET_ON_RESUME | XHCI_SUSPEND_RESUME_CLKS,
 };
 
 static const struct of_device_id usb_xhci_of_match[] = {
@@ -437,7 +437,16 @@ static int __maybe_unused xhci_plat_suspend(struct device *dev)
         * xhci_suspend() needs `do_wakeup` to know whether host is allowed
         * to do wakeup during suspend.
         */
-       return xhci_suspend(xhci, device_may_wakeup(dev));
+       ret = xhci_suspend(xhci, device_may_wakeup(dev));
+       if (ret)
+               return ret;
+
+       if (!device_may_wakeup(dev) && (xhci->quirks & XHCI_SUSPEND_RESUME_CLKS)) {
+               clk_disable_unprepare(xhci->clk);
+               clk_disable_unprepare(xhci->reg_clk);
+       }
+
+       return 0;
 }
 
 static int __maybe_unused xhci_plat_resume(struct device *dev)
@@ -446,6 +455,11 @@ static int __maybe_unused xhci_plat_resume(struct device *dev)
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
        int ret;
 
+       if (!device_may_wakeup(dev) && (xhci->quirks & XHCI_SUSPEND_RESUME_CLKS)) {
+               clk_prepare_enable(xhci->clk);
+               clk_prepare_enable(xhci->reg_clk);
+       }
+
        ret = xhci_priv_resume_quirk(hcd);
        if (ret)
                return ret;
index 3864928..5176765 100644 (file)
@@ -1183,7 +1183,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
        /* re-initialize the HC on Restore Error, or Host Controller Error */
        if (temp & (STS_SRE | STS_HCE)) {
                reinit_xhc = true;
-               xhci_warn(xhci, "xHC error in resume, USBSTS 0x%x, Reinit\n", temp);
+               if (!xhci->broken_suspend)
+                       xhci_warn(xhci, "xHC error in resume, USBSTS 0x%x, Reinit\n", temp);
        }
 
        if (reinit_xhc) {
@@ -1482,7 +1483,7 @@ EXPORT_SYMBOL_GPL(xhci_get_endpoint_index);
 /* The reverse operation to xhci_get_endpoint_index. Calculate the USB endpoint
  * address from the XHCI endpoint index.
  */
-unsigned int xhci_get_endpoint_address(unsigned int ep_index)
+static unsigned int xhci_get_endpoint_address(unsigned int ep_index)
 {
        unsigned int number = DIV_ROUND_UP(ep_index, 2);
        unsigned int direction = ep_index % 2 ? USB_DIR_OUT : USB_DIR_IN;
@@ -4095,7 +4096,8 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
        slot_id = command->slot_id;
 
        if (!slot_id || command->status != COMP_SUCCESS) {
-               xhci_err(xhci, "Error while assigning device slot ID\n");
+               xhci_err(xhci, "Error while assigning device slot ID: %s\n",
+                        xhci_trb_comp_code_string(command->status));
                xhci_err(xhci, "Max number of devices this xHCI host supports is %u.\n",
                                HCS_MAX_SLOTS(
                                        readl(&xhci->cap_regs->hcs_params1)));
index 7caa0db..c0964fe 100644 (file)
@@ -1807,8 +1807,6 @@ struct xhci_hcd {
        struct xhci_erst        erst;
        /* Scratchpad */
        struct xhci_scratchpad  *scratchpad;
-       /* Store LPM test failed devices' information */
-       struct list_head        lpm_failed_devs;
 
        /* slot enabling and address device helpers */
        /* these are not thread safe so use mutex */
@@ -1827,7 +1825,6 @@ struct xhci_hcd {
        /* Host controller watchdog timer structures */
        unsigned int            xhc_state;
        unsigned long           run_graceperiod;
-       u32                     command;
        struct s3_save          s3;
 /* Host controller is dying - not responding to commands. "I'm not dead yet!"
  *
@@ -1899,6 +1896,7 @@ struct xhci_hcd {
 #define XHCI_NO_SOFT_RETRY     BIT_ULL(40)
 #define XHCI_BROKEN_D3COLD     BIT_ULL(41)
 #define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(42)
+#define XHCI_SUSPEND_RESUME_CLKS       BIT_ULL(43)
 
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;
@@ -2041,7 +2039,6 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
 void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,
                struct usb_device *udev);
 unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc);
-unsigned int xhci_get_endpoint_address(unsigned int ep_index);
 unsigned int xhci_last_valid_endpoint(u32 added_ctxs);
 void xhci_endpoint_zero(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_host_endpoint *ep);
 void xhci_update_tt_active_eps(struct xhci_hcd *xhci,
index e9437a1..ea39243 100644 (file)
@@ -177,10 +177,6 @@ static int idmouse_create_image(struct usb_idmouse *dev)
                bytes_read += bulk_read;
        }
 
-       /* reset the device */
-reset:
-       ftip_command(dev, FTIP_RELEASE, 0, 0);
-
        /* check for valid image */
        /* right border should be black (0x00) */
        for (bytes_read = sizeof(HEADER)-1 + WIDTH-1; bytes_read < IMGSIZE; bytes_read += WIDTH)
@@ -192,6 +188,10 @@ reset:
                if (dev->bulk_in_buffer[bytes_read] != 0xFF)
                        return -EAGAIN;
 
+       /* reset the device */
+reset:
+       ftip_command(dev, FTIP_RELEASE, 0, 0);
+
        /* should be IMGSIZE == 65040 */
        dev_dbg(&dev->interface->dev, "read %d bytes fingerprint data\n",
                bytes_read);
index 04c4e3f..54337d7 100644 (file)
@@ -400,7 +400,7 @@ static int usb251xb_get_ofdata(struct usb251xb *hub,
 {
        struct device *dev = hub->dev;
        struct device_node *np = dev->of_node;
-       int len, err;
+       int len;
        u32 property_u32 = 0;
        const char *cproperty_char;
        char str[USB251XB_STRING_BUFSIZE / 2];
@@ -416,13 +416,9 @@ static int usb251xb_get_ofdata(struct usb251xb *hub,
                hub->skip_config = 0;
 
        hub->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
-       if (PTR_ERR(hub->gpio_reset) == -EPROBE_DEFER) {
-               return -EPROBE_DEFER;
-       } else if (IS_ERR(hub->gpio_reset)) {
-               err = PTR_ERR(hub->gpio_reset);
-               dev_err(dev, "unable to request GPIO reset pin (%d)\n", err);
-               return err;
-       }
+       if (IS_ERR(hub->gpio_reset))
+               return dev_err_probe(dev, PTR_ERR(hub->gpio_reset),
+                                    "unable to request GPIO reset pin\n");
 
        if (of_property_read_u16_array(np, "vendor-id", &hub->vendor_id, 1))
                hub->vendor_id = USB251XB_DEF_VENDOR_ID;
@@ -547,7 +543,7 @@ static int usb251xb_get_ofdata(struct usb251xb *hub,
                hub->boost_up = USB251XB_DEF_BOOST_UP;
 
        cproperty_char = of_get_property(np, "manufacturer", NULL);
-       strlcpy(str, cproperty_char ? : USB251XB_DEF_MANUFACTURER_STRING,
+       strscpy(str, cproperty_char ? : USB251XB_DEF_MANUFACTURER_STRING,
                sizeof(str));
        hub->manufacturer_len = strlen(str) & 0xFF;
        memset(hub->manufacturer, 0, USB251XB_STRING_BUFSIZE);
@@ -557,7 +553,7 @@ static int usb251xb_get_ofdata(struct usb251xb *hub,
                              USB251XB_STRING_BUFSIZE);
 
        cproperty_char = of_get_property(np, "product", NULL);
-       strlcpy(str, cproperty_char ? : data->product_str, sizeof(str));
+       strscpy(str, cproperty_char ? : data->product_str, sizeof(str));
        hub->product_len = strlen(str) & 0xFF;
        memset(hub->product, 0, USB251XB_STRING_BUFSIZE);
        len = min_t(size_t, USB251XB_STRING_BUFSIZE / 2, strlen(str));
@@ -566,7 +562,7 @@ static int usb251xb_get_ofdata(struct usb251xb *hub,
                              USB251XB_STRING_BUFSIZE);
 
        cproperty_char = of_get_property(np, "serial", NULL);
-       strlcpy(str, cproperty_char ? : USB251XB_DEF_SERIAL_STRING,
+       strscpy(str, cproperty_char ? : USB251XB_DEF_SERIAL_STRING,
                sizeof(str));
        hub->serial_len = strlen(str) & 0xFF;
        memset(hub->serial, 0, USB251XB_STRING_BUFSIZE);
index 3c9fa66..c70ca47 100644 (file)
@@ -160,6 +160,7 @@ static int usb3503_probe(struct usb3503 *hub)
        struct usb3503_platform_data *pdata = dev_get_platdata(dev);
        struct device_node *np = dev->of_node;
        int err;
+       bool is_clk_enabled = false;
        u32 mode = USB3503_MODE_HUB;
        const u32 *property;
        enum gpiod_flags flags;
@@ -217,6 +218,7 @@ static int usb3503_probe(struct usb3503 *hub)
                        return err;
                }
 
+               is_clk_enabled = true;
                property = of_get_property(np, "disabled-ports", &len);
                if (property && (len / sizeof(u32)) > 0) {
                        int i;
@@ -236,20 +238,26 @@ static int usb3503_probe(struct usb3503 *hub)
        else
                flags = GPIOD_OUT_HIGH;
        hub->intn = devm_gpiod_get_optional(dev, "intn", flags);
-       if (IS_ERR(hub->intn))
-               return PTR_ERR(hub->intn);
+       if (IS_ERR(hub->intn)) {
+               err = PTR_ERR(hub->intn);
+               goto err_clk;
+       }
        if (hub->intn)
                gpiod_set_consumer_name(hub->intn, "usb3503 intn");
 
        hub->connect = devm_gpiod_get_optional(dev, "connect", GPIOD_OUT_LOW);
-       if (IS_ERR(hub->connect))
-               return PTR_ERR(hub->connect);
+       if (IS_ERR(hub->connect)) {
+               err = PTR_ERR(hub->connect);
+               goto err_clk;
+       }
        if (hub->connect)
                gpiod_set_consumer_name(hub->connect, "usb3503 connect");
 
        hub->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
-       if (IS_ERR(hub->reset))
-               return PTR_ERR(hub->reset);
+       if (IS_ERR(hub->reset)) {
+               err = PTR_ERR(hub->reset);
+               goto err_clk;
+       }
        if (hub->reset) {
                /* Datasheet defines a hardware reset to be at least 100us */
                usleep_range(100, 10000);
@@ -265,6 +273,11 @@ static int usb3503_probe(struct usb3503 *hub)
                        (hub->mode == USB3503_MODE_HUB) ? "hub" : "standby");
 
        return 0;
+
+err_clk:
+       if (is_clk_enabled)
+               clk_disable_unprepare(hub->clk);
+       return err;
 }
 
 static int usb3503_i2c_probe(struct i2c_client *i2c,
index 0be8efc..b00d92d 100644 (file)
@@ -502,7 +502,7 @@ static size_t parport_uss720_epp_write_data(struct parport *pp, const void *buf,
 #else
        struct parport_uss720_private *priv = pp->private_data;
        struct usb_device *usbdev = priv->usbdev;
-       int rlen;
+       int rlen = 0;
        int i;
 
        if (!usbdev)
@@ -563,7 +563,7 @@ static size_t parport_uss720_ecp_write_data(struct parport *pp, const void *buff
 {
        struct parport_uss720_private *priv = pp->private_data;
        struct usb_device *usbdev = priv->usbdev;
-       int rlen;
+       int rlen = 0;
        int i;
 
        if (!usbdev)
@@ -581,7 +581,7 @@ static size_t parport_uss720_ecp_read_data(struct parport *pp, void *buffer, siz
 {
        struct parport_uss720_private *priv = pp->private_data;
        struct usb_device *usbdev = priv->usbdev;
-       int rlen;
+       int rlen = 0;
        int i;
 
        if (!usbdev)
@@ -614,7 +614,7 @@ static size_t parport_uss720_write_compat(struct parport *pp, const void *buffer
 {
        struct parport_uss720_private *priv = pp->private_data;
        struct usb_device *usbdev = priv->usbdev;
-       int rlen;
+       int rlen = 0;
        int i;
 
        if (!usbdev)
index f48a23a..094e812 100644 (file)
@@ -1268,6 +1268,11 @@ static int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
 {
        /* don't do anything here: "fault" will set up page table entries */
        vma->vm_ops = &mon_bin_vm_ops;
+
+       if (vma->vm_flags & VM_WRITE)
+               return -EPERM;
+
+       vma->vm_flags &= ~VM_MAYWRITE;
        vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
        vma->vm_private_data = filp->private_data;
        mon_bin_vma_open(vma);
index 0ca173a..a3a6282 100644 (file)
@@ -978,8 +978,6 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
                goto irq_err;
        }
 
-       device_init_wakeup(dev, true);
-
        /* power down device IP for power saving by default */
        mtu3_stop(mtu);
 
index 4cb6534..d78ae52 100644 (file)
@@ -356,6 +356,8 @@ static int mtu3_probe(struct platform_device *pdev)
        pm_runtime_enable(dev);
        pm_runtime_get_sync(dev);
 
+       device_init_wakeup(dev, true);
+
        ret = ssusb_rscs_init(ssusb);
        if (ret)
                goto comm_init_err;
index fd4ae2d..a4e55b0 100644 (file)
@@ -523,11 +523,9 @@ static int da8xx_probe(struct platform_device *pdev)
        }
 
        glue->phy = devm_phy_get(&pdev->dev, "usb-phy");
-       if (IS_ERR(glue->phy)) {
-               if (PTR_ERR(glue->phy) != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "failed to get phy\n");
-               return PTR_ERR(glue->phy);
-       }
+       if (IS_ERR(glue->phy))
+               return dev_err_probe(&pdev->dev, PTR_ERR(glue->phy),
+                                    "failed to get phy\n");
 
        glue->dev                       = &pdev->dev;
        glue->clk                       = clk;
index 417c30b..d1e4e0d 100644 (file)
@@ -105,7 +105,6 @@ static int jz4740_musb_init(struct musb *musb)
                .driver_data = glue,
                .fwnode = dev_fwnode(dev),
        };
-       int err;
 
        glue->musb = musb;
 
@@ -113,12 +112,9 @@ static int jz4740_musb_init(struct musb *musb)
                musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0);
        else
                musb->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
-       if (IS_ERR(musb->xceiv)) {
-               err = PTR_ERR(musb->xceiv);
-               if (err != -EPROBE_DEFER)
-                       dev_err(dev, "No transceiver configured: %d\n", err);
-               return err;
-       }
+       if (IS_ERR(musb->xceiv))
+               return dev_err_probe(dev, PTR_ERR(musb->xceiv),
+                                    "No transceiver configured\n");
 
        glue->role_sw = usb_role_switch_register(dev, &role_sw_desc);
        if (IS_ERR(glue->role_sw)) {
index bbbcfd4..03027c6 100644 (file)
@@ -2595,9 +2595,7 @@ fail2:
        musb_platform_exit(musb);
 
 fail1:
-       if (status != -EPROBE_DEFER)
-               dev_err(musb->controller,
-                       "%s failed with status %d\n", __func__, status);
+       dev_err_probe(musb->controller, status, "%s failed\n", __func__);
 
        musb_free(musb);
 
index c963cb8..9589243 100644 (file)
@@ -718,10 +718,8 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)
 
                dc = dma_request_chan(dev->parent, str);
                if (IS_ERR(dc)) {
-                       ret = PTR_ERR(dc);
-                       if (ret != -EPROBE_DEFER)
-                               dev_err(dev, "Failed to request %s: %d.\n",
-                                       str, ret);
+                       ret = dev_err_probe(dev, PTR_ERR(dc),
+                                           "Failed to request %s.\n", str);
                        goto err;
                }
 
index daada4b..6704a62 100644 (file)
@@ -760,6 +760,9 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                        musb_writew(epio, MUSB_RXCSR, csr);
 
 buffer_aint_mapped:
+                       fifo_count = min_t(unsigned int,
+                                       request->length - request->actual,
+                                       (unsigned int)fifo_count);
                        musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *)
                                        (request->buf + request->actual));
                        request->actual += fifo_count;
index 961c858..7f9a999 100644 (file)
@@ -743,31 +743,20 @@ static int sunxi_musb_probe(struct platform_device *pdev)
 
        if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) {
                glue->rst = devm_reset_control_get(&pdev->dev, NULL);
-               if (IS_ERR(glue->rst)) {
-                       if (PTR_ERR(glue->rst) == -EPROBE_DEFER)
-                               return -EPROBE_DEFER;
-                       dev_err(&pdev->dev, "Error getting reset %ld\n",
-                               PTR_ERR(glue->rst));
-                       return PTR_ERR(glue->rst);
-               }
+               if (IS_ERR(glue->rst))
+                       return dev_err_probe(&pdev->dev, PTR_ERR(glue->rst),
+                                            "Error getting reset\n");
        }
 
        glue->extcon = extcon_get_edev_by_phandle(&pdev->dev, 0);
-       if (IS_ERR(glue->extcon)) {
-               if (PTR_ERR(glue->extcon) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-               dev_err(&pdev->dev, "Invalid or missing extcon\n");
-               return PTR_ERR(glue->extcon);
-       }
+       if (IS_ERR(glue->extcon))
+               return dev_err_probe(&pdev->dev, PTR_ERR(glue->extcon),
+                                    "Invalid or missing extcon\n");
 
        glue->phy = devm_phy_get(&pdev->dev, "usb");
-       if (IS_ERR(glue->phy)) {
-               if (PTR_ERR(glue->phy) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-               dev_err(&pdev->dev, "Error getting phy %ld\n",
-                       PTR_ERR(glue->phy));
-               return PTR_ERR(glue->phy);
-       }
+       if (IS_ERR(glue->phy))
+               return dev_err_probe(&pdev->dev, PTR_ERR(glue->phy),
+                                    "Error getting phy\n");
 
        glue->usb_phy = usb_phy_generic_register();
        if (IS_ERR(glue->usb_phy)) {
index 34b9f81..3dc5c04 100644 (file)
@@ -230,12 +230,9 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop)
                err = PTR_ERR_OR_ZERO(nop->gpiod_vbus);
        }
 
-       if (err == -EPROBE_DEFER)
-               return -EPROBE_DEFER;
-       if (err) {
-               dev_err(dev, "Error requesting RESET or VBUS GPIO\n");
-               return err;
-       }
+       if (err)
+               return dev_err_probe(dev, err,
+                                    "Error requesting RESET or VBUS GPIO\n");
        if (nop->gpiod_reset)
                gpiod_direction_output(nop->gpiod_reset, 1);
 
index 4025da2..f16adca 100644 (file)
@@ -321,27 +321,18 @@ static int jz4770_phy_probe(struct platform_device *pdev)
        }
 
        priv->clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(priv->clk)) {
-               err = PTR_ERR(priv->clk);
-               if (err != -EPROBE_DEFER)
-                       dev_err(dev, "Failed to get clock\n");
-               return err;
-       }
+       if (IS_ERR(priv->clk))
+               return dev_err_probe(dev, PTR_ERR(priv->clk),
+                                    "Failed to get clock\n");
 
        priv->vcc_supply = devm_regulator_get(dev, "vcc");
-       if (IS_ERR(priv->vcc_supply)) {
-               err = PTR_ERR(priv->vcc_supply);
-               if (err != -EPROBE_DEFER)
-                       dev_err(dev, "Failed to get regulator\n");
-               return err;
-       }
+       if (IS_ERR(priv->vcc_supply))
+               return dev_err_probe(dev, PTR_ERR(priv->vcc_supply),
+                                    "Failed to get regulator\n");
 
        err = usb_add_phy(&priv->phy, USB_PHY_TYPE_USB2);
-       if (err) {
-               if (err != -EPROBE_DEFER)
-                       dev_err(dev, "Unable to register PHY\n");
-               return err;
-       }
+       if (err)
+               return dev_err_probe(dev, err, "Unable to register PHY\n");
 
        return devm_add_action_or_reset(dev, ingenic_usb_phy_remove, &priv->phy);
 }
index 8a262c5..d2836ef 100644 (file)
 #define MXS_PHY_NEED_IP_FIX                    BIT(3)
 
 /* Minimum and maximum values for device tree entries */
-#define MXS_PHY_TX_CAL45_MIN                   30
-#define MXS_PHY_TX_CAL45_MAX                   55
+#define MXS_PHY_TX_CAL45_MIN                   35
+#define MXS_PHY_TX_CAL45_MAX                   54
 #define MXS_PHY_TX_D_CAL_MIN                   79
 #define MXS_PHY_TX_D_CAL_MAX                   119
 
index 68cd4b6..f024010 100644 (file)
@@ -1440,16 +1440,22 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
                        return err;
                }
 
-               gpiod = devm_gpiod_get_from_of_node(&pdev->dev, np,
-                                                   "nvidia,phy-reset-gpio",
-                                                   0, GPIOD_OUT_HIGH,
-                                                   "ulpi_phy_reset_b");
+               gpiod = devm_gpiod_get(&pdev->dev, "nvidia,phy-reset",
+                                      GPIOD_OUT_HIGH);
                err = PTR_ERR_OR_ZERO(gpiod);
                if (err) {
                        dev_err(&pdev->dev,
                                "Request failed for reset GPIO: %d\n", err);
                        return err;
                }
+
+               err = gpiod_set_consumer_name(gpiod, "ulpi_phy_reset_b");
+               if (err) {
+                       dev_err(&pdev->dev,
+                               "Failed to set up reset GPIO name: %d\n", err);
+                       return err;
+               }
+
                tegra_phy->reset_gpio = gpiod;
 
                phy = devm_otg_ulpi_create(&pdev->dev,
index b97aa40..da19a5f 100644 (file)
@@ -189,8 +189,8 @@ static int usb_console_setup(struct console *co, char *options)
        info->port = NULL;
        usb_autopm_put_interface(serial->interface);
  error_get_interface:
-       usb_serial_put(serial);
        mutex_unlock(&serial->disc_mutex);
+       usb_serial_put(serial);
        return retval;
 }
 
index 0a1da57..05e28a5 100644 (file)
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr, Johan Hovold <jhovold@gmail.com>"
 #define DRIVER_DESC "USB FTDI Serial Converters Driver"
 
+enum ftdi_chip_type {
+       SIO,
+       FT232A,
+       FT232B,
+       FT2232C,
+       FT232R,
+       FT232H,
+       FT2232H,
+       FT4232H,
+       FT4232HA,
+       FT232HP,
+       FT233HP,
+       FT2232HP,
+       FT2233HP,
+       FT4232HP,
+       FT4233HP,
+       FTX,
+};
 
 struct ftdi_private {
        enum ftdi_chip_type chip_type;
-                               /* type of device, either SIO or FT8U232AM */
        int baud_base;          /* baud base clock for divisor setting */
        int custom_divisor;     /* custom_divisor kludge, this is for
                                   baud_base (different from what goes to the
@@ -62,8 +79,7 @@ struct ftdi_private {
        unsigned long last_dtr_rts;     /* saved modem control outputs */
        char prev_status;        /* Used for TIOCMIWAIT */
        char transmit_empty;    /* If transmitter is empty or not */
-       u16 interface;          /* FT2232C, FT2232H or FT4232H port interface
-                                  (0 for FT232/245) */
+       u16 channel;            /* channel index, or 0 for legacy types */
 
        speed_t force_baud;     /* if non-zero, force the baud rate to
                                   this value */
@@ -84,8 +100,7 @@ struct ftdi_private {
 #endif
 };
 
-/* struct ftdi_sio_quirk is used by devices requiring special attention. */
-struct ftdi_sio_quirk {
+struct ftdi_quirk {
        int (*probe)(struct usb_serial *);
        /* Special settings for probed ports. */
        void (*port_probe)(struct ftdi_private *);
@@ -98,27 +113,27 @@ static int   ftdi_8u2232c_probe(struct usb_serial *serial);
 static void  ftdi_USB_UIRT_setup(struct ftdi_private *priv);
 static void  ftdi_HE_TIRA1_setup(struct ftdi_private *priv);
 
-static const struct ftdi_sio_quirk ftdi_jtag_quirk = {
+static const struct ftdi_quirk ftdi_jtag_quirk = {
        .probe  = ftdi_jtag_probe,
 };
 
-static const struct ftdi_sio_quirk ftdi_NDI_device_quirk = {
+static const struct ftdi_quirk ftdi_NDI_device_quirk = {
        .probe  = ftdi_NDI_device_setup,
 };
 
-static const struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = {
+static const struct ftdi_quirk ftdi_USB_UIRT_quirk = {
        .port_probe = ftdi_USB_UIRT_setup,
 };
 
-static const struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
+static const struct ftdi_quirk ftdi_HE_TIRA1_quirk = {
        .port_probe = ftdi_HE_TIRA1_setup,
 };
 
-static const struct ftdi_sio_quirk ftdi_stmclite_quirk = {
+static const struct ftdi_quirk ftdi_stmclite_quirk = {
        .probe  = ftdi_stmclite_probe,
 };
 
-static const struct ftdi_sio_quirk ftdi_8u2232c_quirk = {
+static const struct ftdi_quirk ftdi_8u2232c_quirk = {
        .probe  = ftdi_8u2232c_probe,
 };
 
@@ -180,6 +195,13 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_232H_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_FTX_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_FT2233HP_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_FT4233HP_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_FT2232HP_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_FT4232HP_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_FT233HP_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_FT232HP_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_FT4232HA_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) },
@@ -1061,15 +1083,22 @@ static const struct usb_device_id id_table_combined[] = {
 MODULE_DEVICE_TABLE(usb, id_table_combined);
 
 static const char *ftdi_chip_name[] = {
-       [SIO] = "SIO",  /* the serial part of FT8U100AX */
-       [FT8U232AM] = "FT8U232AM",
-       [FT232BM] = "FT232BM",
-       [FT2232C] = "FT2232C",
-       [FT232RL] = "FT232RL",
-       [FT2232H] = "FT2232H",
-       [FT4232H] = "FT4232H",
-       [FT232H]  = "FT232H",
-       [FTX]     = "FT-X"
+       [SIO]           = "SIO",        /* the serial part of FT8U100AX */
+       [FT232A]        = "FT232A",
+       [FT232B]        = "FT232B",
+       [FT2232C]       = "FT2232C/D",
+       [FT232R]        = "FT232R",
+       [FT232H]        = "FT232H",
+       [FT2232H]       = "FT2232H",
+       [FT4232H]       = "FT4232H",
+       [FT4232HA]      = "FT4232HA",
+       [FT232HP]       = "FT232HP",
+       [FT233HP]       = "FT233HP",
+       [FT2232HP]      = "FT2232HP",
+       [FT2233HP]      = "FT2233HP",
+       [FT4232HP]      = "FT4232HP",
+       [FT4233HP]      = "FT4233HP",
+       [FTX]           = "FT-X",
 };
 
 
@@ -1078,75 +1107,12 @@ static const char *ftdi_chip_name[] = {
 #define FTDI_STATUS_B1_MASK    (FTDI_RS_BI)
 /* End TIOCMIWAIT */
 
-/* function prototypes for a FTDI serial converter */
-static int  ftdi_sio_probe(struct usb_serial *serial,
-                                       const struct usb_device_id *id);
-static int  ftdi_sio_port_probe(struct usb_serial_port *port);
-static void ftdi_sio_port_remove(struct usb_serial_port *port);
-static int  ftdi_open(struct tty_struct *tty, struct usb_serial_port *port);
-static void ftdi_dtr_rts(struct usb_serial_port *port, int on);
-static void ftdi_process_read_urb(struct urb *urb);
-static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
-                                               void *dest, size_t size);
 static void ftdi_set_termios(struct tty_struct *tty,
                             struct usb_serial_port *port,
                             const struct ktermios *old_termios);
-static int  ftdi_tiocmget(struct tty_struct *tty);
-static int  ftdi_tiocmset(struct tty_struct *tty,
-                       unsigned int set, unsigned int clear);
-static int  ftdi_ioctl(struct tty_struct *tty,
-                       unsigned int cmd, unsigned long arg);
-static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss);
-static int set_serial_info(struct tty_struct *tty,
-                               struct serial_struct *ss);
-static void ftdi_break_ctl(struct tty_struct *tty, int break_state);
-static bool ftdi_tx_empty(struct usb_serial_port *port);
 static int ftdi_get_modem_status(struct usb_serial_port *port,
                                                unsigned char status[2]);
 
-static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base);
-static unsigned short int ftdi_232am_baud_to_divisor(int baud);
-static u32 ftdi_232bm_baud_base_to_divisor(int baud, int base);
-static u32 ftdi_232bm_baud_to_divisor(int baud);
-static u32 ftdi_2232h_baud_base_to_divisor(int baud, int base);
-static u32 ftdi_2232h_baud_to_divisor(int baud);
-
-static struct usb_serial_driver ftdi_sio_device = {
-       .driver = {
-               .owner =        THIS_MODULE,
-               .name =         "ftdi_sio",
-       },
-       .description =          "FTDI USB Serial Device",
-       .id_table =             id_table_combined,
-       .num_ports =            1,
-       .bulk_in_size =         512,
-       .bulk_out_size =        256,
-       .probe =                ftdi_sio_probe,
-       .port_probe =           ftdi_sio_port_probe,
-       .port_remove =          ftdi_sio_port_remove,
-       .open =                 ftdi_open,
-       .dtr_rts =              ftdi_dtr_rts,
-       .throttle =             usb_serial_generic_throttle,
-       .unthrottle =           usb_serial_generic_unthrottle,
-       .process_read_urb =     ftdi_process_read_urb,
-       .prepare_write_buffer = ftdi_prepare_write_buffer,
-       .tiocmget =             ftdi_tiocmget,
-       .tiocmset =             ftdi_tiocmset,
-       .tiocmiwait =           usb_serial_generic_tiocmiwait,
-       .get_icount =           usb_serial_generic_get_icount,
-       .ioctl =                ftdi_ioctl,
-       .get_serial =           get_serial_info,
-       .set_serial =           set_serial_info,
-       .set_termios =          ftdi_set_termios,
-       .break_ctl =            ftdi_break_ctl,
-       .tx_empty =             ftdi_tx_empty,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-       &ftdi_sio_device, NULL
-};
-
-
 #define WDR_TIMEOUT 5000 /* default urb timeout */
 #define WDR_SHORT_TIMEOUT 1000 /* shorter urb timeout */
 
@@ -1262,7 +1228,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set,
                               usb_sndctrlpipe(port->serial->dev, 0),
                               FTDI_SIO_SET_MODEM_CTRL_REQUEST,
                               FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-                              value, priv->interface,
+                              value, priv->channel,
                               NULL, 0, WDR_TIMEOUT);
        if (rv < 0) {
                dev_dbg(dev, "%s Error from MODEM_CTRL urb: DTR %s, RTS %s\n",
@@ -1308,7 +1274,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty,
        if (!baud)
                baud = 9600;
        switch (priv->chip_type) {
-       case SIO: /* SIO chip */
+       case SIO:
                switch (baud) {
                case 300: div_value = ftdi_sio_b300; break;
                case 600: div_value = ftdi_sio_b600; break;
@@ -1320,8 +1286,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty,
                case 38400: div_value = ftdi_sio_b38400; break;
                case 57600: div_value = ftdi_sio_b57600;  break;
                case 115200: div_value = ftdi_sio_b115200; break;
-               } /* baud */
-               if (div_value == 0) {
+               default:
                        dev_dbg(dev, "%s - Baudrate (%d) requested is not supported\n",
                                __func__,  baud);
                        div_value = ftdi_sio_b9600;
@@ -1329,7 +1294,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty,
                        div_okay = 0;
                }
                break;
-       case FT8U232AM: /* 8U232AM chip */
+       case FT232A:
                if (baud <= 3000000) {
                        div_value = ftdi_232am_baud_to_divisor(baud);
                } else {
@@ -1339,10 +1304,10 @@ static u32 get_ftdi_divisor(struct tty_struct *tty,
                        div_okay = 0;
                }
                break;
-       case FT232BM: /* FT232BM chip */
-       case FT2232C: /* FT2232C chip */
-       case FT232RL: /* FT232RL chip */
-       case FTX:     /* FT-X series */
+       case FT232B:
+       case FT2232C:
+       case FT232R:
+       case FTX:
                if (baud <= 3000000) {
                        u16 product_id = le16_to_cpu(
                                port->serial->dev->descriptor.idProduct);
@@ -1362,9 +1327,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty,
                        baud = 9600;
                }
                break;
-       case FT2232H: /* FT2232H chip */
-       case FT4232H: /* FT4232H chip */
-       case FT232H:  /* FT232H chip */
+       default:
                if ((baud <= 12000000) && (baud >= 1200)) {
                        div_value = ftdi_2232h_baud_to_divisor(baud);
                } else if (baud < 1200) {
@@ -1376,7 +1339,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty,
                        baud = 9600;
                }
                break;
-       } /* priv->chip_type */
+       }
 
        if (div_okay) {
                dev_dbg(dev, "%s - Baud rate set to %d (divisor 0x%lX) on chip %s\n",
@@ -1399,13 +1362,8 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port)
        index_value = get_ftdi_divisor(tty, port);
        value = (u16)index_value;
        index = (u16)(index_value >> 16);
-       if (priv->chip_type == FT2232C || priv->chip_type == FT2232H ||
-                       priv->chip_type == FT4232H || priv->chip_type == FT232H ||
-                       priv->chip_type == FTX) {
-               /* Probably the BM type needs the MSB of the encoded fractional
-                * divider also moved like for the chips above. Any infos? */
-               index = (u16)((index << 8) | priv->interface);
-       }
+       if (priv->channel)
+               index = (u16)((index << 8) | priv->channel);
 
        rv = usb_control_msg(port->serial->dev,
                            usb_sndctrlpipe(port->serial->dev, 0),
@@ -1423,7 +1381,7 @@ static int write_latency_timer(struct usb_serial_port *port)
        int rv;
        int l = priv->latency;
 
-       if (priv->chip_type == SIO || priv->chip_type == FT8U232AM)
+       if (priv->chip_type == SIO || priv->chip_type == FT232A)
                return -EINVAL;
 
        if (priv->flags & ASYNC_LOW_LATENCY)
@@ -1435,7 +1393,7 @@ static int write_latency_timer(struct usb_serial_port *port)
                             usb_sndctrlpipe(udev, 0),
                             FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
                             FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
-                            l, priv->interface,
+                            l, priv->channel,
                             NULL, 0, WDR_TIMEOUT);
        if (rv < 0)
                dev_err(&port->dev, "Unable to write latency timer: %i\n", rv);
@@ -1451,7 +1409,7 @@ static int _read_latency_timer(struct usb_serial_port *port)
 
        rv = usb_control_msg_recv(udev, 0, FTDI_SIO_GET_LATENCY_TIMER_REQUEST,
                                  FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, 0,
-                                 priv->interface, &buf, 1, WDR_TIMEOUT,
+                                 priv->channel, &buf, 1, WDR_TIMEOUT,
                                  GFP_KERNEL);
        if (rv == 0)
                rv = buf;
@@ -1464,7 +1422,7 @@ static int read_latency_timer(struct usb_serial_port *port)
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        int rv;
 
-       if (priv->chip_type == SIO || priv->chip_type == FT8U232AM)
+       if (priv->chip_type == SIO || priv->chip_type == FT232A)
                return -EINVAL;
 
        rv = _read_latency_timer(port);
@@ -1539,90 +1497,97 @@ static int get_lsr_info(struct usb_serial_port *port,
        return 0;
 }
 
-
-/* Determine type of FTDI chip based on USB config and descriptor. */
-static void ftdi_determine_type(struct usb_serial_port *port)
+static int ftdi_determine_type(struct usb_serial_port *port)
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        struct usb_serial *serial = port->serial;
        struct usb_device *udev = serial->dev;
-       unsigned version;
-       unsigned interfaces;
-
-       /* Assume it is not the original SIO device for now. */
-       priv->baud_base = 48000000 / 2;
+       unsigned int version, ifnum;
 
        version = le16_to_cpu(udev->descriptor.bcdDevice);
-       interfaces = udev->actconfig->desc.bNumInterfaces;
-       dev_dbg(&port->dev, "%s: bcdDevice = 0x%x, bNumInterfaces = %u\n", __func__,
-               version, interfaces);
-       if (interfaces > 1) {
-               struct usb_interface *intf = serial->interface;
-               int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
-
-               /* Multiple interfaces.*/
-               if (version == 0x0800) {
-                       priv->chip_type = FT4232H;
-                       /* Hi-speed - baud clock runs at 120MHz */
-                       priv->baud_base = 120000000 / 2;
-               } else if (version == 0x0700) {
-                       priv->chip_type = FT2232H;
-                       /* Hi-speed - baud clock runs at 120MHz */
-                       priv->baud_base = 120000000 / 2;
-               } else
-                       priv->chip_type = FT2232C;
-
-               /* Determine interface code. */
-               if (ifnum == 0)
-                       priv->interface = INTERFACE_A;
-               else if (ifnum == 1)
-                       priv->interface = INTERFACE_B;
-               else if (ifnum == 2)
-                       priv->interface = INTERFACE_C;
-               else if (ifnum == 3)
-                       priv->interface = INTERFACE_D;
-
-               /* BM-type devices have a bug where bcdDevice gets set
-                * to 0x200 when iSerialNumber is 0.  */
-               if (version < 0x500) {
-                       dev_dbg(&port->dev,
-                               "%s: something fishy - bcdDevice too low for multi-interface device\n",
-                               __func__);
-               }
-       } else if (version < 0x200) {
-               /* Old device.  Assume it's the original SIO. */
-               priv->chip_type = SIO;
-               priv->baud_base = 12000000 / 16;
-       } else if (version < 0x400) {
-               /* Assume it's an FT8U232AM (or FT8U245AM) */
-               priv->chip_type = FT8U232AM;
+       ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
+
+       /* Assume Hi-Speed type */
+       priv->baud_base = 120000000 / 2;
+       priv->channel = CHANNEL_A + ifnum;
+
+       switch (version) {
+       case 0x200:
+               priv->chip_type = FT232A;
+               priv->baud_base = 48000000 / 2;
+               priv->channel = 0;
                /*
-                * It might be a BM type because of the iSerialNumber bug.
-                * If iSerialNumber==0 and the latency timer is readable,
-                * assume it is BM type.
+                * FT232B devices have a bug where bcdDevice gets set to 0x200
+                * when iSerialNumber is 0. Assume it is an FT232B in case the
+                * latency timer is readable.
                 */
                if (udev->descriptor.iSerialNumber == 0 &&
                                _read_latency_timer(port) >= 0) {
-                       dev_dbg(&port->dev,
-                               "%s: has latency timer so not an AM type\n",
-                               __func__);
-                       priv->chip_type = FT232BM;
+                       priv->chip_type = FT232B;
                }
-       } else if (version < 0x600) {
-               /* Assume it's an FT232BM (or FT245BM) */
-               priv->chip_type = FT232BM;
-       } else if (version < 0x900) {
-               /* Assume it's an FT232RL */
-               priv->chip_type = FT232RL;
-       } else if (version < 0x1000) {
-               /* Assume it's an FT232H */
+               break;
+       case 0x400:
+               priv->chip_type = FT232B;
+               priv->baud_base = 48000000 / 2;
+               priv->channel = 0;
+               break;
+       case 0x500:
+               priv->chip_type = FT2232C;
+               priv->baud_base = 48000000 / 2;
+               break;
+       case 0x600:
+               priv->chip_type = FT232R;
+               priv->baud_base = 48000000 / 2;
+               priv->channel = 0;
+               break;
+       case 0x700:
+               priv->chip_type = FT2232H;
+               break;
+       case 0x800:
+               priv->chip_type = FT4232H;
+               break;
+       case 0x900:
                priv->chip_type = FT232H;
-       } else {
-               /* Assume it's an FT-X series device */
+               break;
+       case 0x1000:
                priv->chip_type = FTX;
+               priv->baud_base = 48000000 / 2;
+               break;
+       case 0x2800:
+               priv->chip_type = FT2233HP;
+               break;
+       case 0x2900:
+               priv->chip_type = FT4233HP;
+               break;
+       case 0x3000:
+               priv->chip_type = FT2232HP;
+               break;
+       case 0x3100:
+               priv->chip_type = FT4232HP;
+               break;
+       case 0x3200:
+               priv->chip_type = FT233HP;
+               break;
+       case 0x3300:
+               priv->chip_type = FT232HP;
+               break;
+       case 0x3600:
+               priv->chip_type = FT4232HA;
+               break;
+       default:
+               if (version < 0x200) {
+                       priv->chip_type = SIO;
+                       priv->baud_base = 12000000 / 16;
+                       priv->channel = 0;
+               } else {
+                       dev_err(&port->dev, "unknown device type: 0x%02x\n", version);
+                       return -ENODEV;
+               }
        }
 
        dev_info(&udev->dev, "Detected %s\n", ftdi_chip_name[priv->chip_type]);
+
+       return 0;
 }
 
 
@@ -1721,7 +1686,7 @@ static ssize_t event_char_store(struct device *dev,
                             usb_sndctrlpipe(udev, 0),
                             FTDI_SIO_SET_EVENT_CHAR_REQUEST,
                             FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE,
-                            v, priv->interface,
+                            v, priv->channel,
                             NULL, 0, WDR_TIMEOUT);
        if (rv < 0) {
                dev_dbg(&port->dev, "Unable to write event character: %i\n", rv);
@@ -1732,51 +1697,42 @@ static ssize_t event_char_store(struct device *dev,
 }
 static DEVICE_ATTR_WO(event_char);
 
-static int create_sysfs_attrs(struct usb_serial_port *port)
-{
-       struct ftdi_private *priv = usb_get_serial_port_data(port);
-       int retval = 0;
-
-       /* XXX I've no idea if the original SIO supports the event_char
-        * sysfs parameter, so I'm playing it safe.  */
-       if (priv->chip_type != SIO) {
-               dev_dbg(&port->dev, "sysfs attributes for %s\n", ftdi_chip_name[priv->chip_type]);
-               retval = device_create_file(&port->dev, &dev_attr_event_char);
-               if ((!retval) &&
-                   (priv->chip_type == FT232BM ||
-                    priv->chip_type == FT2232C ||
-                    priv->chip_type == FT232RL ||
-                    priv->chip_type == FT2232H ||
-                    priv->chip_type == FT4232H ||
-                    priv->chip_type == FT232H ||
-                    priv->chip_type == FTX)) {
-                       retval = device_create_file(&port->dev,
-                                                   &dev_attr_latency_timer);
-               }
-       }
-       return retval;
-}
+static struct attribute *ftdi_attrs[] = {
+       &dev_attr_event_char.attr,
+       &dev_attr_latency_timer.attr,
+       NULL
+};
 
-static void remove_sysfs_attrs(struct usb_serial_port *port)
+static umode_t ftdi_is_visible(struct kobject *kobj, struct attribute *attr, int idx)
 {
+       struct device *dev = kobj_to_dev(kobj);
+       struct usb_serial_port *port = to_usb_serial_port(dev);
        struct ftdi_private *priv = usb_get_serial_port_data(port);
+       enum ftdi_chip_type type = priv->chip_type;
 
-       /* XXX see create_sysfs_attrs */
-       if (priv->chip_type != SIO) {
-               device_remove_file(&port->dev, &dev_attr_event_char);
-               if (priv->chip_type == FT232BM ||
-                   priv->chip_type == FT2232C ||
-                   priv->chip_type == FT232RL ||
-                   priv->chip_type == FT2232H ||
-                   priv->chip_type == FT4232H ||
-                   priv->chip_type == FT232H ||
-                   priv->chip_type == FTX) {
-                       device_remove_file(&port->dev, &dev_attr_latency_timer);
-               }
+       if (attr == &dev_attr_event_char.attr) {
+               if (type == SIO)
+                       return 0;
+       }
+
+       if (attr == &dev_attr_latency_timer.attr) {
+               if (type == SIO || type == FT232A)
+                       return 0;
        }
 
+       return attr->mode;
 }
 
+static const struct attribute_group ftdi_group = {
+       .attrs          = ftdi_attrs,
+       .is_visible     = ftdi_is_visible,
+};
+
+static const struct attribute_group *ftdi_groups[] = {
+       &ftdi_group,
+       NULL
+};
+
 #ifdef CONFIG_GPIOLIB
 
 static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode)
@@ -1795,7 +1751,7 @@ static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode)
                                 usb_sndctrlpipe(serial->dev, 0),
                                 FTDI_SIO_SET_BITMODE_REQUEST,
                                 FTDI_SIO_SET_BITMODE_REQUEST_TYPE, val,
-                                priv->interface, NULL, 0, WDR_TIMEOUT);
+                                priv->channel, NULL, 0, WDR_TIMEOUT);
        if (result < 0) {
                dev_err(&serial->interface->dev,
                        "bitmode request failed for value 0x%04x: %d\n",
@@ -1859,7 +1815,7 @@ static int ftdi_read_cbus_pins(struct usb_serial_port *port)
        result = usb_control_msg_recv(serial->dev, 0,
                                      FTDI_SIO_READ_PINS_REQUEST,
                                      FTDI_SIO_READ_PINS_REQUEST_TYPE, 0,
-                                     priv->interface, &buf, 1, WDR_TIMEOUT,
+                                     priv->channel, &buf, 1, WDR_TIMEOUT,
                                      GFP_KERNEL);
        if (result == 0)
                result = buf;
@@ -2144,7 +2100,7 @@ static int ftdi_gpio_init(struct usb_serial_port *port)
        case FT232H:
                result = ftdi_gpio_init_ft232h(port);
                break;
-       case FT232RL:
+       case FT232R:
                result = ftdi_gpio_init_ft232r(port);
                break;
        case FTX:
@@ -2214,12 +2170,9 @@ static void ftdi_gpio_remove(struct usb_serial_port *port) { }
  * ***************************************************************************
  */
 
-/* Probe function to check for special devices */
-static int ftdi_sio_probe(struct usb_serial *serial,
-                                       const struct usb_device_id *id)
+static int ftdi_probe(struct usb_serial *serial, const struct usb_device_id *id)
 {
-       const struct ftdi_sio_quirk *quirk =
-                               (struct ftdi_sio_quirk *)id->driver_info;
+       const struct ftdi_quirk *quirk = (struct ftdi_quirk *)id->driver_info;
 
        if (quirk && quirk->probe) {
                int ret = quirk->probe(serial);
@@ -2232,10 +2185,10 @@ static int ftdi_sio_probe(struct usb_serial *serial,
        return 0;
 }
 
-static int ftdi_sio_port_probe(struct usb_serial_port *port)
+static int ftdi_port_probe(struct usb_serial_port *port)
 {
+       const struct ftdi_quirk *quirk = usb_get_serial_data(port->serial);
        struct ftdi_private *priv;
-       const struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial);
        int result;
 
        priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
@@ -2249,12 +2202,14 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
 
        usb_set_serial_port_data(port, priv);
 
-       ftdi_determine_type(port);
+       result = ftdi_determine_type(port);
+       if (result)
+               goto err_free;
+
        ftdi_set_max_packet_size(port);
        if (read_latency_timer(port) < 0)
                priv->latency = 16;
        write_latency_timer(port);
-       create_sysfs_attrs(port);
 
        result = ftdi_gpio_init(port);
        if (result < 0) {
@@ -2264,6 +2219,11 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
        }
 
        return 0;
+
+err_free:
+       kfree(priv);
+
+       return result;
 }
 
 /* Setup for the USB-UIRT device, which requires hardwired
@@ -2374,14 +2334,12 @@ static int ftdi_stmclite_probe(struct usb_serial *serial)
        return 0;
 }
 
-static void ftdi_sio_port_remove(struct usb_serial_port *port)
+static void ftdi_port_remove(struct usb_serial_port *port)
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
 
        ftdi_gpio_remove(port);
 
-       remove_sysfs_attrs(port);
-
        kfree(priv);
 }
 
@@ -2395,7 +2353,7 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
        usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                        FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
                        FTDI_SIO_RESET_SIO,
-                       priv->interface, NULL, 0, WDR_TIMEOUT);
+                       priv->channel, NULL, 0, WDR_TIMEOUT);
 
        /* Termios defaults are set by usb_serial_init. We don't change
           port->tty->termios - this would lose speed settings, etc.
@@ -2418,7 +2376,7 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
                            usb_sndctrlpipe(port->serial->dev, 0),
                            FTDI_SIO_SET_FLOW_CTRL_REQUEST,
                            FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-                           0, priv->interface, NULL, 0,
+                           0, priv->channel, NULL, 0,
                            WDR_TIMEOUT) < 0) {
                        dev_err(&port->dev, "error from flowcontrol urb\n");
                }
@@ -2611,7 +2569,7 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
                        usb_sndctrlpipe(port->serial->dev, 0),
                        FTDI_SIO_SET_DATA_REQUEST,
                        FTDI_SIO_SET_DATA_REQUEST_TYPE,
-                       value , priv->interface,
+                       value, priv->channel,
                        NULL, 0, WDR_TIMEOUT) < 0) {
                dev_err(&port->dev, "%s FAILED to enable/disable break state (state was %d)\n",
                        __func__, break_state);
@@ -2748,7 +2706,7 @@ no_skip:
        if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                            FTDI_SIO_SET_DATA_REQUEST,
                            FTDI_SIO_SET_DATA_REQUEST_TYPE,
-                           value , priv->interface,
+                           value, priv->channel,
                            NULL, 0, WDR_SHORT_TIMEOUT) < 0) {
                dev_err(ddev, "%s FAILED to set databits/stopbits/parity\n",
                        __func__);
@@ -2761,7 +2719,7 @@ no_data_parity_stop_changes:
                if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST,
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-                                   0, priv->interface,
+                                   0, priv->channel,
                                    NULL, 0, WDR_TIMEOUT) < 0) {
                        dev_err(ddev, "%s error from disable flowcontrol urb\n",
                                __func__);
@@ -2795,7 +2753,7 @@ no_c_cflag_changes:
                index = FTDI_SIO_DISABLE_FLOW_CTRL;
        }
 
-       index |= priv->interface;
+       index |= priv->channel;
 
        ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                        FTDI_SIO_SET_FLOW_CTRL_REQUEST,
@@ -2823,33 +2781,19 @@ static int ftdi_get_modem_status(struct usb_serial_port *port,
        if (!buf)
                return -ENOMEM;
        /*
-        * The 8U232AM returns a two byte value (the SIO a 1 byte value) in
-        * the same format as the data returned from the in point.
+        * The device returns a two byte value (the SIO a 1 byte value) in the
+        * same format as the data returned from the IN endpoint.
         */
-       switch (priv->chip_type) {
-       case SIO:
+       if (priv->chip_type == SIO)
                len = 1;
-               break;
-       case FT8U232AM:
-       case FT232BM:
-       case FT2232C:
-       case FT232RL:
-       case FT2232H:
-       case FT4232H:
-       case FT232H:
-       case FTX:
+       else
                len = 2;
-               break;
-       default:
-               ret = -EFAULT;
-               goto out;
-       }
 
        ret = usb_control_msg(port->serial->dev,
                        usb_rcvctrlpipe(port->serial->dev, 0),
                        FTDI_SIO_GET_MODEM_STATUS_REQUEST,
                        FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
-                       0, priv->interface,
+                       0, priv->channel,
                        buf, len, WDR_TIMEOUT);
 
        /* NOTE: We allow short responses and handle that below. */
@@ -2919,6 +2863,41 @@ static int ftdi_ioctl(struct tty_struct *tty,
        return -ENOIOCTLCMD;
 }
 
+static struct usb_serial_driver ftdi_device = {
+       .driver = {
+               .owner =        THIS_MODULE,
+               .name =         "ftdi_sio",
+               .dev_groups =   ftdi_groups,
+       },
+       .description =          "FTDI USB Serial Device",
+       .id_table =             id_table_combined,
+       .num_ports =            1,
+       .bulk_in_size =         512,
+       .bulk_out_size =        256,
+       .probe =                ftdi_probe,
+       .port_probe =           ftdi_port_probe,
+       .port_remove =          ftdi_port_remove,
+       .open =                 ftdi_open,
+       .dtr_rts =              ftdi_dtr_rts,
+       .throttle =             usb_serial_generic_throttle,
+       .unthrottle =           usb_serial_generic_unthrottle,
+       .process_read_urb =     ftdi_process_read_urb,
+       .prepare_write_buffer = ftdi_prepare_write_buffer,
+       .tiocmget =             ftdi_tiocmget,
+       .tiocmset =             ftdi_tiocmset,
+       .tiocmiwait =           usb_serial_generic_tiocmiwait,
+       .get_icount =           usb_serial_generic_get_icount,
+       .ioctl =                ftdi_ioctl,
+       .get_serial =           get_serial_info,
+       .set_serial =           set_serial_info,
+       .set_termios =          ftdi_set_termios,
+       .break_ctl =            ftdi_break_ctl,
+       .tx_empty =             ftdi_tx_empty,
+};
+
+static struct usb_serial_driver * const serial_drivers[] = {
+       &ftdi_device, NULL
+};
 module_usb_serial_driver(serial_drivers, id_table_combined);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
index be1641e..55ea612 100644 (file)
 #define FTDI_SIO_READ_PINS             0x0c /* Read immediate value of pins */
 #define FTDI_SIO_READ_EEPROM           0x90 /* Read EEPROM */
 
-/* Interface indices for FT2232, FT2232H and FT4232H devices */
-#define INTERFACE_A            1
-#define INTERFACE_B            2
-#define INTERFACE_C            3
-#define INTERFACE_D            4
+/* Channel indices for FT2232, FT2232H and FT4232H devices */
+#define CHANNEL_A              1
+#define CHANNEL_B              2
+#define CHANNEL_C              3
+#define CHANNEL_D              4
 
 
 /*
  * not supported by the FT8U232AM).
  */
 
-enum ftdi_chip_type {
-       SIO = 1,
-       FT8U232AM = 2,
-       FT232BM = 3,
-       FT2232C = 4,
-       FT232RL = 5,
-       FT2232H = 6,
-       FT4232H = 7,
-       FT232H  = 8,
-       FTX     = 9,
-};
-
 enum ftdi_sio_baudrate {
        ftdi_sio_b300 = 0,
        ftdi_sio_b600 = 1,
index 31c8cca..e209944 100644 (file)
 #define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */
 #define FTDI_232H_PID  0x6014 /* Single channel hi-speed device */
 #define FTDI_FTX_PID   0x6015 /* FT-X series (FT201X, FT230X, FT231X, etc) */
+#define FTDI_FT2233HP_PID      0x6040 /* Dual channel hi-speed device with PD */
+#define FTDI_FT4233HP_PID      0x6041 /* Quad channel hi-speed device with PD */
+#define FTDI_FT2232HP_PID      0x6042 /* Dual channel hi-speed device with PD */
+#define FTDI_FT4232HP_PID      0x6043 /* Quad channel hi-speed device with PD */
+#define FTDI_FT233HP_PID       0x6044 /* Dual channel hi-speed device with PD */
+#define FTDI_FT232HP_PID       0x6045 /* Dual channel hi-speed device with PD */
+#define FTDI_FT4232HA_PID      0x6048 /* Quad channel automotive grade hi-speed device */
 #define FTDI_SIO_PID   0x8372  /* Product Id SIO application of 8U100AX */
 #define FTDI_232RL_PID  0xFBFA  /* Product ID for FT232RL */
 
index 586ef55..b1e844b 100644 (file)
@@ -177,6 +177,7 @@ static const struct usb_device_id id_table[] = {
        {DEVICE_SWI(0x413c, 0x81b3)},   /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */
        {DEVICE_SWI(0x413c, 0x81b5)},   /* Dell Wireless 5811e QDL */
        {DEVICE_SWI(0x413c, 0x81b6)},   /* Dell Wireless 5811e QDL */
+       {DEVICE_SWI(0x413c, 0x81c2)},   /* Dell Wireless 5811e */
        {DEVICE_SWI(0x413c, 0x81cb)},   /* Dell Wireless 5816e QDL */
        {DEVICE_SWI(0x413c, 0x81cc)},   /* Dell Wireless 5816e */
        {DEVICE_SWI(0x413c, 0x81cf)},   /* Dell Wireless 5819 */
index 1db2eef..01f3c27 100644 (file)
@@ -201,7 +201,7 @@ static int onetouch_connect_input(struct us_data *ss)
        onetouch->dev = input_dev;
 
        if (udev->manufacturer)
-               strlcpy(onetouch->name, udev->manufacturer,
+               strscpy(onetouch->name, udev->manufacturer,
                        sizeof(onetouch->name));
        if (udev->product) {
                if (udev->manufacturer)
index 4993227..20dcbcc 100644 (file)
@@ -1275,12 +1275,6 @@ UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999,
                USB_SC_RBC, USB_PR_BULK, NULL,
                0 ),
 
-UNUSUAL_DEV(0x090c, 0x1000, 0x1100, 0x1100,
-               "Samsung",
-               "Flash Drive FIT",
-               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
-               US_FL_MAX_SECTORS_64),
-
 /* aeb */
 UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff,
                "Feiya",
index e205f40..b8f3b75 100644 (file)
@@ -1105,7 +1105,7 @@ static int anx7411_typec_switch_probe(struct anx7411_data *ctx,
        int ret;
        struct device_node *node;
 
-       node = of_find_node_by_name(dev->of_node, "orientation_switch");
+       node = of_get_child_by_name(dev->of_node, "orientation_switch");
        if (!node)
                return 0;
 
@@ -1115,7 +1115,7 @@ static int anx7411_typec_switch_probe(struct anx7411_data *ctx,
                return ret;
        }
 
-       node = of_find_node_by_name(dev->of_node, "mode_switch");
+       node = of_get_child_by_name(dev->of_node, "mode_switch");
        if (!node) {
                dev_err(dev, "no typec mux exist");
                ret = -ENODEV;
index 4643307..941735c 100644 (file)
@@ -29,7 +29,7 @@ static int switch_fwnode_match(struct device *dev, const void *fwnode)
        if (!is_typec_switch_dev(dev))
                return 0;
 
-       return dev_fwnode(dev) == fwnode;
+       return device_match_fwnode(dev, fwnode);
 }
 
 static void *typec_switch_match(struct fwnode_handle *fwnode, const char *id,
@@ -259,7 +259,7 @@ static int mux_fwnode_match(struct device *dev, const void *fwnode)
        if (!is_typec_mux_dev(dev))
                return 0;
 
-       return dev_fwnode(dev) == fwnode;
+       return device_match_fwnode(dev, fwnode);
 }
 
 static void *typec_mux_match(struct fwnode_handle *fwnode, const char *id,
index a0454a8..432ea62 100644 (file)
@@ -195,9 +195,8 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev)
 
        qcom_usb->role_sw = fwnode_usb_role_switch_get(dev_fwnode(qcom_usb->dev));
        if (IS_ERR(qcom_usb->role_sw)) {
-               if (PTR_ERR(qcom_usb->role_sw) != -EPROBE_DEFER)
-                       dev_err(dev, "failed to get role switch\n");
-               ret = PTR_ERR(qcom_usb->role_sw);
+               ret = dev_err_probe(dev, PTR_ERR(qcom_usb->role_sw),
+                                   "failed to get role switch\n");
                goto err_typec_port;
        }
 
index 2003731..ee94dbb 100644 (file)
@@ -31,7 +31,7 @@ static bool dev_name_ends_with(struct device *dev, const char *suffix)
 
 static int retimer_fwnode_match(struct device *dev, const void *fwnode)
 {
-       return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-retimer");
+       return device_match_fwnode(dev, fwnode) && dev_name_ends_with(dev, "-retimer");
 }
 
 static void *typec_retimer_match(struct fwnode_handle *fwnode, const char *id, void *data)
index 8638f1d..494b371 100644 (file)
@@ -750,11 +750,8 @@ static int stusb160x_probe(struct i2c_client *client)
        if (client->irq) {
                chip->role_sw = fwnode_usb_role_switch_get(fwnode);
                if (IS_ERR(chip->role_sw)) {
-                       ret = PTR_ERR(chip->role_sw);
-                       if (ret != -EPROBE_DEFER)
-                               dev_err(chip->dev,
-                                       "Failed to get usb role switch: %d\n",
-                                       ret);
+                       ret = dev_err_probe(chip->dev, PTR_ERR(chip->role_sw),
+                                           "Failed to get usb role switch\n");
                        goto port_unregister;
                }
 
index 073fd2e..e6b88ca 100644 (file)
@@ -35,6 +35,17 @@ config TYPEC_MT6360
          USB Type-C. It works with Type-C Port Controller Manager
          to provide USB PD and USB Type-C functionalities.
 
+config TYPEC_TCPCI_MT6370
+       tristate "MediaTek MT6370 Type-C driver"
+       depends on MFD_MT6370
+       help
+         MediaTek MT6370 is a multi-functional IC that includes
+         USB Type-C. It works with Type-C Port Controller Manager
+         to provide USB PD and USB Type-C functionalities.
+
+         This driver can also be built as a module. The module
+         will be called "tcpci_mt6370".
+
 config TYPEC_TCPCI_MAXIM
        tristate "Maxim TCPCI based Type-C chip driver"
        help
index 7d499f3..906d9dc 100644 (file)
@@ -6,4 +6,5 @@ typec_wcove-y                           := wcove.o
 obj-$(CONFIG_TYPEC_TCPCI)              += tcpci.o
 obj-$(CONFIG_TYPEC_RT1711H)            += tcpci_rt1711h.o
 obj-$(CONFIG_TYPEC_MT6360)             += tcpci_mt6360.o
+obj-$(CONFIG_TYPEC_TCPCI_MT6370)       += tcpci_mt6370.o
 obj-$(CONFIG_TYPEC_TCPCI_MAXIM)                += tcpci_maxim.o
index 5e9348f..721b2a5 100644 (file)
@@ -151,7 +151,7 @@ static void _fusb302_log(struct fusb302_chip *chip, const char *fmt,
 
        if (fusb302_log_full(chip)) {
                chip->logbuffer_head = max(chip->logbuffer_head - 1, 0);
-               strlcpy(tmpbuffer, "overflow", sizeof(tmpbuffer));
+               strscpy(tmpbuffer, "overflow", sizeof(tmpbuffer));
        }
 
        if (chip->logbuffer_head < 0 ||
@@ -1743,9 +1743,8 @@ static int fusb302_probe(struct i2c_client *client,
        chip->tcpm_port = tcpm_register_port(&client->dev, &chip->tcpc_dev);
        if (IS_ERR(chip->tcpm_port)) {
                fwnode_handle_put(chip->tcpc_dev.fwnode);
-               ret = PTR_ERR(chip->tcpm_port);
-               if (ret != -EPROBE_DEFER)
-                       dev_err(dev, "cannot register tcpm port, ret=%d", ret);
+               ret = dev_err_probe(dev, PTR_ERR(chip->tcpm_port),
+                                   "cannot register tcpm port\n");
                goto destroy_workqueue;
        }
 
index f00810d..b2bfceb 100644 (file)
 #define        VPPS_VALID_MIN_MV                       100
 #define        VSINKDISCONNECT_PD_MIN_PERCENT          90
 
-#define tcpc_presenting_rd(reg, cc) \
-       (!(TCPC_ROLE_CTRL_DRP & (reg)) && \
-        (((reg) & (TCPC_ROLE_CTRL_## cc ##_MASK << TCPC_ROLE_CTRL_## cc ##_SHIFT)) == \
-         (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_## cc ##_SHIFT)))
-
 struct tcpci {
        struct device *dev;
 
@@ -218,23 +213,6 @@ static int tcpci_start_toggling(struct tcpc_dev *tcpc,
                            TCPC_CMD_LOOK4CONNECTION);
 }
 
-static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink)
-{
-       switch (cc) {
-       case 0x1:
-               return sink ? TYPEC_CC_RP_DEF : TYPEC_CC_RA;
-       case 0x2:
-               return sink ? TYPEC_CC_RP_1_5 : TYPEC_CC_RD;
-       case 0x3:
-               if (sink)
-                       return TYPEC_CC_RP_3_0;
-               fallthrough;
-       case 0x0:
-       default:
-               return TYPEC_CC_OPEN;
-       }
-}
-
 static int tcpci_get_cc(struct tcpc_dev *tcpc,
                        enum typec_cc_status *cc1, enum typec_cc_status *cc2)
 {
diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c b/drivers/usb/typec/tcpm/tcpci_mt6370.c
new file mode 100644 (file)
index 0000000..c5bb201
--- /dev/null
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiYuan Huang <cy_huang@richtek.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeup.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/usb/tcpci.h>
+#include <linux/usb/tcpm.h>
+
+#define MT6370_REG_SYSCTRL8    0x9B
+
+#define MT6370_AUTOIDLE_MASK   BIT(3)
+
+#define MT6370_VENDOR_ID       0x29CF
+#define MT6370_TCPC_DID_A      0x2170
+
+struct mt6370_priv {
+       struct device *dev;
+       struct regulator *vbus;
+       struct tcpci *tcpci;
+       struct tcpci_data tcpci_data;
+};
+
+static const struct reg_sequence mt6370_reg_init[] = {
+       REG_SEQ(0xA0, 0x1, 1000),
+       REG_SEQ(0x81, 0x38, 0),
+       REG_SEQ(0x82, 0x82, 0),
+       REG_SEQ(0xBA, 0xFC, 0),
+       REG_SEQ(0xBB, 0x50, 0),
+       REG_SEQ(0x9E, 0x8F, 0),
+       REG_SEQ(0xA1, 0x5, 0),
+       REG_SEQ(0xA2, 0x4, 0),
+       REG_SEQ(0xA3, 0x4A, 0),
+       REG_SEQ(0xA4, 0x01, 0),
+       REG_SEQ(0x95, 0x01, 0),
+       REG_SEQ(0x80, 0x71, 0),
+       REG_SEQ(0x9B, 0x3A, 1000),
+};
+
+static int mt6370_tcpc_init(struct tcpci *tcpci, struct tcpci_data *data)
+{
+       u16 did;
+       int ret;
+
+       ret = regmap_register_patch(data->regmap, mt6370_reg_init,
+                                   ARRAY_SIZE(mt6370_reg_init));
+       if (ret)
+               return ret;
+
+       ret = regmap_raw_read(data->regmap, TCPC_BCD_DEV, &did, sizeof(u16));
+       if (ret)
+               return ret;
+
+       if (did == MT6370_TCPC_DID_A)
+               return regmap_write(data->regmap, TCPC_FAULT_CTRL, 0x80);
+
+       return 0;
+}
+
+static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct tcpci_data *data,
+                                bool enable)
+{
+       return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8,
+                                 MT6370_AUTOIDLE_MASK,
+                                 enable ? 0 : MT6370_AUTOIDLE_MASK);
+}
+
+static int mt6370_tcpc_set_vbus(struct tcpci *tcpci, struct tcpci_data *data,
+                               bool source, bool sink)
+{
+       struct mt6370_priv *priv = container_of(data, struct mt6370_priv,
+                                               tcpci_data);
+       int ret;
+
+       ret = regulator_is_enabled(priv->vbus);
+       if (ret < 0)
+               return ret;
+
+       if (ret && !source)
+               return regulator_disable(priv->vbus);
+
+       if (!ret && source)
+               return regulator_enable(priv->vbus);
+
+       return 0;
+}
+
+static irqreturn_t mt6370_irq_handler(int irq, void *dev_id)
+{
+       struct mt6370_priv *priv = dev_id;
+
+       return tcpci_irq(priv->tcpci);
+}
+
+static int mt6370_check_vendor_info(struct mt6370_priv *priv)
+{
+       struct regmap *regmap = priv->tcpci_data.regmap;
+       u16 vid;
+       int ret;
+
+       ret = regmap_raw_read(regmap, TCPC_VENDOR_ID, &vid, sizeof(u16));
+       if (ret)
+               return ret;
+
+       if (vid != MT6370_VENDOR_ID)
+               return dev_err_probe(priv->dev, -ENODEV,
+                                    "Vendor ID not correct 0x%02x\n", vid);
+
+       return 0;
+}
+
+static void mt6370_unregister_tcpci_port(void *tcpci)
+{
+       tcpci_unregister_port(tcpci);
+}
+
+static int mt6370_tcpc_probe(struct platform_device *pdev)
+{
+       struct mt6370_priv *priv;
+       struct device *dev = &pdev->dev;
+       int irq, ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->dev = dev;
+
+       priv->tcpci_data.regmap = dev_get_regmap(dev->parent, NULL);
+       if (!priv->tcpci_data.regmap)
+               return dev_err_probe(dev, -ENODEV, "Failed to init regmap\n");
+
+       ret = mt6370_check_vendor_info(priv);
+       if (ret)
+               return ret;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return dev_err_probe(dev, irq, "Failed to get irq\n");
+
+       /* Assign TCPCI feature and ops */
+       priv->tcpci_data.auto_discharge_disconnect = 1;
+       priv->tcpci_data.init = mt6370_tcpc_init;
+       priv->tcpci_data.set_vconn = mt6370_tcpc_set_vconn;
+
+       priv->vbus = devm_regulator_get_optional(dev, "vbus");
+       if (!IS_ERR(priv->vbus))
+               priv->tcpci_data.set_vbus = mt6370_tcpc_set_vbus;
+
+       priv->tcpci = tcpci_register_port(dev, &priv->tcpci_data);
+       if (IS_ERR(priv->tcpci))
+               return dev_err_probe(dev, PTR_ERR(priv->tcpci),
+                                    "Failed to register tcpci port\n");
+
+       ret = devm_add_action_or_reset(dev, mt6370_unregister_tcpci_port, priv->tcpci);
+       if (ret)
+               return ret;
+
+       ret = devm_request_threaded_irq(dev, irq, NULL, mt6370_irq_handler,
+                                       IRQF_ONESHOT, dev_name(dev), priv);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to allocate irq\n");
+
+       device_init_wakeup(dev, true);
+       dev_pm_set_wake_irq(dev, irq);
+
+       return 0;
+}
+
+static int mt6370_tcpc_remove(struct platform_device *pdev)
+{
+       dev_pm_clear_wake_irq(&pdev->dev);
+       device_init_wakeup(&pdev->dev, false);
+
+       return 0;
+}
+
+static const struct of_device_id mt6370_tcpc_devid_table[] = {
+       { .compatible = "mediatek,mt6370-tcpc" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, mt6370_tcpc_devid_table);
+
+static struct platform_driver mt6370_tcpc_driver = {
+       .driver = {
+               .name = "mt6370-tcpc",
+               .of_match_table = mt6370_tcpc_devid_table,
+       },
+       .probe = mt6370_tcpc_probe,
+       .remove = mt6370_tcpc_remove,
+};
+module_platform_driver(mt6370_tcpc_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("MT6370 USB Type-C Port Controller Interface Driver");
+MODULE_LICENSE("GPL v2");
index c132771..7b217c7 100644 (file)
@@ -5,6 +5,7 @@
  * Richtek RT1711H Type-C Chip Driver
  */
 
+#include <linux/bits.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/usb/tcpci.h>
 #include <linux/usb/tcpm.h>
 #include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
 
 #define RT1711H_VID            0x29CF
 #define RT1711H_PID            0x1711
+#define RT1711H_DID            0x2171
+#define RT1715_DID             0x2173
 
-#define RT1711H_RTCTRL8                0x9B
+#define RT1711H_PHYCTRL1       0x80
+#define RT1711H_PHYCTRL2       0x81
+
+#define RT1711H_RTCTRL4                0x93
+/* rx threshold of rd/rp: 1b0 for level 0.4V/0.7V, 1b1 for 0.35V/0.75V */
+#define RT1711H_BMCIO_RXDZSEL  BIT(0)
 
+#define RT1711H_RTCTRL8                0x9B
 /* Autoidle timeout = (tout * 2 + 1) * 6.4ms */
 #define RT1711H_RTCTRL8_SET(ck300, ship_off, auto_idle, tout) \
                            (((ck300) << 7) | ((ship_off) << 5) | \
                            ((auto_idle) << 3) | ((tout) & 0x07))
+#define RT1711H_AUTOIDLEEN     BIT(3)
+#define RT1711H_ENEXTMSG       BIT(4)
 
 #define RT1711H_RTCTRL11       0x9E
 
 #define RT1711H_RTCTRL15       0xA2
 #define RT1711H_RTCTRL16       0xA3
 
+#define RT1711H_RTCTRL18       0xAF
+/* 1b0 as fixed rx threshold of rd/rp 0.55V, 1b1 depends on RTCRTL4[0] */
+#define BMCIO_RXDZEN   BIT(0)
+
 struct rt1711h_chip {
        struct tcpci_data data;
        struct tcpci *tcpci;
        struct device *dev;
+       struct regulator *vbus;
+       bool src_en;
+       u16 did;
 };
 
 static int rt1711h_read16(struct rt1711h_chip *chip, unsigned int reg, u16 *val)
@@ -75,8 +94,9 @@ static struct rt1711h_chip *tdata_to_rt1711h(struct tcpci_data *tdata)
 
 static int rt1711h_init(struct tcpci *tcpci, struct tcpci_data *tdata)
 {
-       int ret;
        struct rt1711h_chip *chip = tdata_to_rt1711h(tdata);
+       struct regmap *regmap = chip->data.regmap;
+       int ret;
 
        /* CK 300K from 320K, shipping off, auto_idle enable, tout = 32ms */
        ret = rt1711h_write8(chip, RT1711H_RTCTRL8,
@@ -84,6 +104,14 @@ static int rt1711h_init(struct tcpci *tcpci, struct tcpci_data *tdata)
        if (ret < 0)
                return ret;
 
+       /* Enable PD30 extended message for RT1715 */
+       if (chip->did == RT1715_DID) {
+               ret = regmap_update_bits(regmap, RT1711H_RTCTRL8,
+                                        RT1711H_ENEXTMSG, RT1711H_ENEXTMSG);
+               if (ret < 0)
+                       return ret;
+       }
+
        /* I2C reset : (val + 1) * 12.5ms */
        ret = rt1711h_write8(chip, RT1711H_RTCTRL11,
                             RT1711H_RTCTRL11_SET(1, 0x0F));
@@ -101,7 +129,37 @@ static int rt1711h_init(struct tcpci *tcpci, struct tcpci_data *tdata)
                return ret;
 
        /* dcSRC.DRP : 33% */
-       return rt1711h_write16(chip, RT1711H_RTCTRL16, 330);
+       ret = rt1711h_write16(chip, RT1711H_RTCTRL16, 330);
+       if (ret < 0)
+               return ret;
+
+       /* Enable phy discard retry, retry count 7, rx filter deglitch 100 us */
+       ret = rt1711h_write8(chip, RT1711H_PHYCTRL1, 0xF1);
+       if (ret < 0)
+               return ret;
+
+       /* Decrease wait time of BMC-encoded 1 bit from 2.67us to 2.55us */
+       /* wait time : (val * .4167) us */
+       return rt1711h_write8(chip, RT1711H_PHYCTRL2, 62);
+}
+
+static int rt1711h_set_vbus(struct tcpci *tcpci, struct tcpci_data *tdata,
+                           bool src, bool snk)
+{
+       struct rt1711h_chip *chip = tdata_to_rt1711h(tdata);
+       int ret;
+
+       if (chip->src_en == src)
+               return 0;
+
+       if (src)
+               ret = regulator_enable(chip->vbus);
+       else
+               ret = regulator_disable(chip->vbus);
+
+       if (!ret)
+               chip->src_en = src;
+       return ret;
 }
 
 static int rt1711h_set_vconn(struct tcpci *tcpci, struct tcpci_data *tdata,
@@ -109,8 +167,55 @@ static int rt1711h_set_vconn(struct tcpci *tcpci, struct tcpci_data *tdata,
 {
        struct rt1711h_chip *chip = tdata_to_rt1711h(tdata);
 
-       return rt1711h_write8(chip, RT1711H_RTCTRL8,
-                             RT1711H_RTCTRL8_SET(0, 1, !enable, 2));
+       return regmap_update_bits(chip->data.regmap, RT1711H_RTCTRL8,
+                                 RT1711H_AUTOIDLEEN, enable ? 0 : RT1711H_AUTOIDLEEN);
+}
+
+/*
+ * Selects the CC PHY noise filter voltage level according to the remote current
+ * CC voltage level.
+ *
+ * @status: The port's current cc status read from IC
+ * Return 0 if writes succeed; failure code otherwise
+ */
+static inline int rt1711h_init_cc_params(struct rt1711h_chip *chip, u8 status)
+{
+       int ret, cc1, cc2;
+       u8 role = 0;
+       u32 rxdz_en, rxdz_sel;
+
+       ret = rt1711h_read8(chip, TCPC_ROLE_CTRL, &role);
+       if (ret < 0)
+               return ret;
+
+       cc1 = tcpci_to_typec_cc((status >> TCPC_CC_STATUS_CC1_SHIFT) &
+                               TCPC_CC_STATUS_CC1_MASK,
+                               status & TCPC_CC_STATUS_TERM ||
+                               tcpc_presenting_rd(role, CC1));
+       cc2 = tcpci_to_typec_cc((status >> TCPC_CC_STATUS_CC2_SHIFT) &
+                               TCPC_CC_STATUS_CC2_MASK,
+                               status & TCPC_CC_STATUS_TERM ||
+                               tcpc_presenting_rd(role, CC2));
+
+       if ((cc1 >= TYPEC_CC_RP_1_5 && cc2 < TYPEC_CC_RP_DEF) ||
+           (cc2 >= TYPEC_CC_RP_1_5 && cc1 < TYPEC_CC_RP_DEF)) {
+               rxdz_en = BMCIO_RXDZEN;
+               if (chip->did == RT1715_DID)
+                       rxdz_sel = RT1711H_BMCIO_RXDZSEL;
+               else
+                       rxdz_sel = 0;
+       } else {
+               rxdz_en = 0;
+               rxdz_sel = RT1711H_BMCIO_RXDZSEL;
+       }
+
+       ret = regmap_update_bits(chip->data.regmap, RT1711H_RTCTRL18,
+                                BMCIO_RXDZEN, rxdz_en);
+       if (ret < 0)
+               return ret;
+
+       return regmap_update_bits(chip->data.regmap, RT1711H_RTCTRL4,
+                                 RT1711H_BMCIO_RXDZSEL, rxdz_sel);
 }
 
 static int rt1711h_start_drp_toggling(struct tcpci *tcpci,
@@ -173,6 +278,8 @@ static irqreturn_t rt1711h_irq(int irq, void *dev_id)
                /* Clear cc change event triggered by starting toggling */
                if (status & TCPC_CC_STATUS_TOGGLING)
                        rt1711h_write8(chip, TCPC_ALERT, TCPC_ALERT_CC_STATUS);
+               else
+                       rt1711h_init_cc_params(chip, status);
        }
 
 out:
@@ -191,7 +298,7 @@ static int rt1711h_sw_reset(struct rt1711h_chip *chip)
        return 0;
 }
 
-static int rt1711h_check_revision(struct i2c_client *i2c)
+static int rt1711h_check_revision(struct i2c_client *i2c, struct rt1711h_chip *chip)
 {
        int ret;
 
@@ -209,7 +316,15 @@ static int rt1711h_check_revision(struct i2c_client *i2c)
                dev_err(&i2c->dev, "pid is not correct, 0x%04x\n", ret);
                return -ENODEV;
        }
-       return 0;
+       ret = i2c_smbus_read_word_data(i2c, TCPC_BCD_DEV);
+       if (ret < 0)
+               return ret;
+       if (ret != chip->did) {
+               dev_err(&i2c->dev, "did is not correct, 0x%04x\n", ret);
+               return -ENODEV;
+       }
+       dev_dbg(&i2c->dev, "did is 0x%04x\n", ret);
+       return ret;
 }
 
 static int rt1711h_probe(struct i2c_client *client,
@@ -218,16 +333,18 @@ static int rt1711h_probe(struct i2c_client *client,
        int ret;
        struct rt1711h_chip *chip;
 
-       ret = rt1711h_check_revision(client);
+       chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       chip->did = (size_t)device_get_match_data(&client->dev);
+
+       ret = rt1711h_check_revision(client, chip);
        if (ret < 0) {
                dev_err(&client->dev, "check vid/pid fail\n");
                return ret;
        }
 
-       chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
-       if (!chip)
-               return -ENOMEM;
-
        chip->data.regmap = devm_regmap_init_i2c(client,
                                                 &rt1711h_regmap_config);
        if (IS_ERR(chip->data.regmap))
@@ -245,7 +362,12 @@ static int rt1711h_probe(struct i2c_client *client,
        if (ret < 0)
                return ret;
 
+       chip->vbus = devm_regulator_get(&client->dev, "vbus");
+       if (IS_ERR(chip->vbus))
+               return PTR_ERR(chip->vbus);
+
        chip->data.init = rt1711h_init;
+       chip->data.set_vbus = rt1711h_set_vbus;
        chip->data.set_vconn = rt1711h_set_vconn;
        chip->data.start_drp_toggling = rt1711h_start_drp_toggling;
        chip->tcpci = tcpci_register_port(chip->dev, &chip->data);
@@ -272,13 +394,15 @@ static void rt1711h_remove(struct i2c_client *client)
 
 static const struct i2c_device_id rt1711h_id[] = {
        { "rt1711h", 0 },
+       { "rt1715", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, rt1711h_id);
 
 #ifdef CONFIG_OF
 static const struct of_device_id rt1711h_of_match[] = {
-       { .compatible = "richtek,rt1711h", },
+       { .compatible = "richtek,rt1711h", .data = (void *)RT1711H_DID },
+       { .compatible = "richtek,rt1715", .data = (void *)RT1715_DID },
        {},
 };
 MODULE_DEVICE_TABLE(of, rt1711h_of_match);
index 6364f0d..74fb5a4 100644 (file)
@@ -1067,11 +1067,9 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
 
        cap->fwnode = ucsi_find_fwnode(con);
        con->usb_role_sw = fwnode_usb_role_switch_get(cap->fwnode);
-       if (IS_ERR(con->usb_role_sw)) {
-               dev_err(ucsi->dev, "con%d: failed to get usb role switch\n",
-                       con->num);
-               return PTR_ERR(con->usb_role_sw);
-       }
+       if (IS_ERR(con->usb_role_sw))
+               return dev_err_probe(ucsi->dev, PTR_ERR(con->usb_role_sw),
+                       "con%d: failed to get usb role switch\n", con->num);
 
        /* Delay other interactions with the con until registration is complete */
        mutex_lock(&con->lock);
index 3497563..835f1c4 100644 (file)
@@ -125,6 +125,11 @@ struct version_format {
 #define CCG_FW_BUILD_NVIDIA    (('n' << 8) | 'v')
 #define CCG_OLD_FW_VERSION     (CCG_VERSION(0x31) | CCG_VERSION_PATCH(10))
 
+/* Firmware for Tegra doesn't support UCSI ALT command, built
+ * for NVIDIA has known issue of reporting wrong capability info
+ */
+#define CCG_FW_BUILD_NVIDIA_TEGRA      (('g' << 8) | 'n')
+
 /* Altmode offset for NVIDIA Function Test Board (FTB) */
 #define NVIDIA_FTB_DP_OFFSET   (2)
 #define NVIDIA_FTB_DBG_OFFSET  (3)
@@ -513,6 +518,7 @@ static int ucsi_ccg_read(struct ucsi *ucsi, unsigned int offset,
 {
        struct ucsi_ccg *uc = ucsi_get_drvdata(ucsi);
        u16 reg = CCGX_RAB_UCSI_DATA_BLOCK(offset);
+       struct ucsi_capability *cap;
        struct ucsi_altmode *alt;
        int ret;
 
@@ -536,6 +542,12 @@ static int ucsi_ccg_read(struct ucsi *ucsi, unsigned int offset,
                                ucsi_ccg_nvidia_altmode(uc, alt);
                }
                break;
+       case UCSI_GET_CAPABILITY:
+               if (uc->fw_build == CCG_FW_BUILD_NVIDIA_TEGRA) {
+                       cap = val;
+                       cap->features &= ~UCSI_CAP_ALT_MODE_DETAILS;
+               }
+               break;
        default:
                break;
        }
index 16289ff..7b92f0c 100644 (file)
@@ -599,7 +599,7 @@ static int ucsi_stm32g0_probe_bootloader(struct ucsi *ucsi)
                g0->i2c_bl = i2c_new_dummy_device(g0->client->adapter, STM32G0_I2C_BL_ADDR);
                if (IS_ERR(g0->i2c_bl)) {
                        ret = dev_err_probe(g0->dev, PTR_ERR(g0->i2c_bl),
-                                           "Failed to register booloader I2C address\n");
+                                           "Failed to register bootloader I2C address\n");
                        return ret;
                }
        }
index 77a5b3f..e8c3131 100644 (file)
@@ -100,7 +100,7 @@ static int add_match_busid(char *busid)
        for (i = 0; i < MAX_BUSID; i++) {
                spin_lock(&busid_table[i].busid_lock);
                if (!busid_table[i].name[0]) {
-                       strlcpy(busid_table[i].name, busid, BUSID_SIZE);
+                       strscpy(busid_table[i].name, busid, BUSID_SIZE);
                        if ((busid_table[i].status != STUB_BUSID_ALLOC) &&
                            (busid_table[i].status != STUB_BUSID_REMOV))
                                busid_table[i].status = STUB_BUSID_ADDED;
index 5dd41e8..fc01b31 100644 (file)
@@ -464,7 +464,7 @@ static void stub_recv_cmd_submit(struct stub_device *sdev,
        int nents;
        int num_urbs = 1;
        int pipe = get_pipe(sdev, pdu);
-       int use_sg = pdu->u.cmd_submit.transfer_flags & URB_DMA_MAP_SG;
+       int use_sg = pdu->u.cmd_submit.transfer_flags & USBIP_URB_DMA_MAP_SG;
        int support_sg = 1;
        int np = 0;
        int ret, i;
@@ -514,7 +514,7 @@ static void stub_recv_cmd_submit(struct stub_device *sdev,
                                num_urbs = nents;
                                priv->completed_urbs = 0;
                                pdu->u.cmd_submit.transfer_flags &=
-                                                               ~URB_DMA_MAP_SG;
+                                                               ~USBIP_URB_DMA_MAP_SG;
                        }
                } else {
                        buffer = kzalloc(buf_len, GFP_KERNEL);
index 2ab9924..053a2bc 100644 (file)
@@ -344,6 +344,91 @@ static unsigned int tweak_transfer_flags(unsigned int flags)
        return flags;
 }
 
+/*
+ * USBIP driver packs URB transfer flags in PDUs that are exchanged
+ * between Server (usbip_host) and Client (vhci_hcd). URB_* flags
+ * are internal to kernel and could change. Where as USBIP URB flags
+ * exchanged in PDUs are USBIP user API must not change.
+ *
+ * USBIP_URB* flags are exported as explicit API and client and server
+ * do mapping from kernel flags to USBIP_URB*. Details as follows:
+ *
+ * Client tx path (USBIP_CMD_SUBMIT):
+ * - Maps URB_* to USBIP_URB_* when it sends USBIP_CMD_SUBMIT packet.
+ *
+ * Server rx path (USBIP_CMD_SUBMIT):
+ * - Maps USBIP_URB_* to URB_* when it receives USBIP_CMD_SUBMIT packet.
+ *
+ * Flags aren't included in USBIP_CMD_UNLINK and USBIP_RET_SUBMIT packets
+ * and no special handling is needed for them in the following cases:
+ * - Server rx path (USBIP_CMD_UNLINK)
+ * - Client rx path & Server tx path (USBIP_RET_SUBMIT)
+ *
+ * Code paths:
+ * usbip_pack_pdu() is the common routine that handles packing pdu from
+ * urb and unpack pdu to an urb.
+ *
+ * usbip_pack_cmd_submit() and usbip_pack_ret_submit() handle
+ * USBIP_CMD_SUBMIT and USBIP_RET_SUBMIT respectively.
+ *
+ * usbip_map_urb_to_usbip() and usbip_map_usbip_to_urb() are used
+ * by usbip_pack_cmd_submit() and usbip_pack_ret_submit() to map
+ * flags.
+ */
+
+struct urb_to_usbip_flags {
+       u32 urb_flag;
+       u32 usbip_flag;
+};
+
+#define NUM_USBIP_FLAGS        17
+
+static const struct urb_to_usbip_flags flag_map[NUM_USBIP_FLAGS] = {
+       {URB_SHORT_NOT_OK, USBIP_URB_SHORT_NOT_OK},
+       {URB_ISO_ASAP, USBIP_URB_ISO_ASAP},
+       {URB_NO_TRANSFER_DMA_MAP, USBIP_URB_NO_TRANSFER_DMA_MAP},
+       {URB_ZERO_PACKET, USBIP_URB_ZERO_PACKET},
+       {URB_NO_INTERRUPT, USBIP_URB_NO_INTERRUPT},
+       {URB_FREE_BUFFER, USBIP_URB_FREE_BUFFER},
+       {URB_DIR_IN, USBIP_URB_DIR_IN},
+       {URB_DIR_OUT, USBIP_URB_DIR_OUT},
+       {URB_DIR_MASK, USBIP_URB_DIR_MASK},
+       {URB_DMA_MAP_SINGLE, USBIP_URB_DMA_MAP_SINGLE},
+       {URB_DMA_MAP_PAGE, USBIP_URB_DMA_MAP_PAGE},
+       {URB_DMA_MAP_SG, USBIP_URB_DMA_MAP_SG},
+       {URB_MAP_LOCAL, USBIP_URB_MAP_LOCAL},
+       {URB_SETUP_MAP_SINGLE, USBIP_URB_SETUP_MAP_SINGLE},
+       {URB_SETUP_MAP_LOCAL, USBIP_URB_SETUP_MAP_LOCAL},
+       {URB_DMA_SG_COMBINED, USBIP_URB_DMA_SG_COMBINED},
+       {URB_ALIGNED_TEMP_BUFFER, USBIP_URB_ALIGNED_TEMP_BUFFER},
+};
+
+static unsigned int urb_to_usbip(unsigned int flags)
+{
+       unsigned int map_flags = 0;
+       int loop;
+
+       for (loop = 0; loop < NUM_USBIP_FLAGS; loop++) {
+               if (flags & flag_map[loop].urb_flag)
+                       map_flags |= flag_map[loop].usbip_flag;
+       }
+
+       return map_flags;
+}
+
+static unsigned int usbip_to_urb(unsigned int flags)
+{
+       unsigned int map_flags = 0;
+       int loop;
+
+       for (loop = 0; loop < NUM_USBIP_FLAGS; loop++) {
+               if (flags & flag_map[loop].usbip_flag)
+                       map_flags |= flag_map[loop].urb_flag;
+       }
+
+       return map_flags;
+}
+
 static void usbip_pack_cmd_submit(struct usbip_header *pdu, struct urb *urb,
                                  int pack)
 {
@@ -354,14 +439,14 @@ static void usbip_pack_cmd_submit(struct usbip_header *pdu, struct urb *urb,
         * will be discussed when usbip is ported to other operating systems.
         */
        if (pack) {
-               spdu->transfer_flags =
-                       tweak_transfer_flags(urb->transfer_flags);
+               /* map after tweaking the urb flags */
+               spdu->transfer_flags = urb_to_usbip(tweak_transfer_flags(urb->transfer_flags));
                spdu->transfer_buffer_length    = urb->transfer_buffer_length;
                spdu->start_frame               = urb->start_frame;
                spdu->number_of_packets         = urb->number_of_packets;
                spdu->interval                  = urb->interval;
        } else  {
-               urb->transfer_flags         = spdu->transfer_flags;
+               urb->transfer_flags         = usbip_to_urb(spdu->transfer_flags);
                urb->transfer_buffer_length = spdu->transfer_buffer_length;
                urb->start_frame            = spdu->start_frame;
                urb->number_of_packets      = spdu->number_of_packets;
index 3a35e74..70998e6 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2016-2020, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2016-2022, NVIDIA CORPORATION.  All rights reserved.
  */
 
 #ifndef PHY_TEGRA_XUSB_H
@@ -21,6 +21,8 @@ int tegra_xusb_padctl_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl,
                                           unsigned int port, bool enable);
 int tegra_xusb_padctl_set_vbus_override(struct tegra_xusb_padctl *padctl,
                                        bool val);
+void tegra_phy_xusb_utmi_pad_power_on(struct phy *phy);
+void tegra_phy_xusb_utmi_pad_power_down(struct phy *phy);
 int tegra_phy_xusb_utmi_port_reset(struct phy *phy);
 int tegra_xusb_padctl_get_usb3_companion(struct tegra_xusb_padctl *padctl,
                                         unsigned int port);
index 0739481..c0fbe1f 100644 (file)
@@ -22,12 +22,6 @@ enum s3c2410_udc_cmd_e {
 struct s3c2410_udc_mach_info {
        void    (*udc_command)(enum s3c2410_udc_cmd_e);
        void    (*vbus_draw)(unsigned int ma);
-
-       unsigned int pullup_pin;
-       unsigned int pullup_pin_inverted;
-
-       unsigned int vbus_pin;
-       unsigned char vbus_pin_inverted;
 };
 
 extern void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *);
index edf3342..ee38835 100644 (file)
@@ -62,6 +62,7 @@ struct ci_hdrc_platform_data {
 #define CI_HDRC_REQUIRES_ALIGNED_DMA   BIT(13)
 #define CI_HDRC_IMX_IS_HSIC            BIT(14)
 #define CI_HDRC_PMQOS                  BIT(15)
+#define CI_HDRC_PHY_VBUS_CONTROL       BIT(16)
        enum usb_dr_mode        dr_mode;
 #define CI_HDRC_CONTROLLER_RESET_EVENT         0
 #define CI_HDRC_CONTROLLER_STOPPED_EVENT       1
index 67f8713..78cd566 100644 (file)
@@ -479,7 +479,6 @@ static inline int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
 struct pci_dev;
 struct pci_device_id;
 extern int usb_hcd_pci_probe(struct pci_dev *dev,
-                            const struct pci_device_id *id,
                             const struct hc_driver *driver);
 extern void usb_hcd_pci_remove(struct pci_dev *dev);
 extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
index 20c0bed..1765745 100644 (file)
 /* I2C_WRITE_BYTE_COUNT + 1 when TX_BUF_BYTE_x is only accessible I2C_WRITE_BYTE_COUNT */
 #define TCPC_TRANSMIT_BUFFER_MAX_LEN           31
 
+#define tcpc_presenting_rd(reg, cc) \
+       (!(TCPC_ROLE_CTRL_DRP & (reg)) && \
+        (((reg) & (TCPC_ROLE_CTRL_## cc ##_MASK << TCPC_ROLE_CTRL_## cc ##_SHIFT)) == \
+         (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_## cc ##_SHIFT)))
+
 struct tcpci;
 
 /*
@@ -207,4 +212,21 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci);
 
 struct tcpm_port;
 struct tcpm_port *tcpci_get_tcpm_port(struct tcpci *tcpci);
+
+static inline enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink)
+{
+       switch (cc) {
+       case 0x1:
+               return sink ? TYPEC_CC_RP_DEF : TYPEC_CC_RA;
+       case 0x2:
+               return sink ? TYPEC_CC_RP_1_5 : TYPEC_CC_RD;
+       case 0x3:
+               if (sink)
+                       return TYPEC_CC_RP_3_0;
+               fallthrough;
+       case 0x0:
+       default:
+               return TYPEC_CC_OPEN;
+       }
+}
 #endif /* __LINUX_USB_TCPCI_H */
index b708d63..725ff91 100644 (file)
@@ -540,6 +540,10 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, u32 pixelformat,
 s64 v4l2_get_link_freq(struct v4l2_ctrl_handler *handler, unsigned int mul,
                       unsigned int div);
 
+void v4l2_simplify_fraction(u32 *numerator, u32 *denominator,
+               unsigned int n_terms, unsigned int threshold);
+u32 v4l2_fraction_to_interval(u32 numerator, u32 denominator);
+
 static inline u64 v4l2_buffer_get_timestamp(const struct v4l2_buffer *buf)
 {
        /*
diff --git a/include/media/v4l2-uvc.h b/include/media/v4l2-uvc.h
new file mode 100644 (file)
index 0000000..f83e316
--- /dev/null
@@ -0,0 +1,359 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *  v4l2 uvc internal API header
+ *
+ *  Some commonly needed functions for uvc drivers
+ */
+
+#ifndef __LINUX_V4L2_UVC_H
+#define __LINUX_V4L2_UVC_H
+
+/* ------------------------------------------------------------------------
+ * GUIDs
+ */
+#define UVC_GUID_UVC_CAMERA \
+       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
+#define UVC_GUID_UVC_OUTPUT \
+       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}
+#define UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT \
+       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
+#define UVC_GUID_UVC_PROCESSING \
+       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01}
+#define UVC_GUID_UVC_SELECTOR \
+       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}
+#define UVC_GUID_EXT_GPIO_CONTROLLER \
+       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03}
+
+#define UVC_GUID_FORMAT_MJPEG \
+       { 'M',  'J',  'P',  'G', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YUY2 \
+       { 'Y',  'U',  'Y',  '2', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YUY2_ISIGHT \
+       { 'Y',  'U',  'Y',  '2', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0x00, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_NV12 \
+       { 'N',  'V',  '1',  '2', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YV12 \
+       { 'Y',  'V',  '1',  '2', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_I420 \
+       { 'I',  '4',  '2',  '0', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_UYVY \
+       { 'U',  'Y',  'V',  'Y', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y800 \
+       { 'Y',  '8',  '0',  '0', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y8 \
+       { 'Y',  '8',  ' ',  ' ', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y10 \
+       { 'Y',  '1',  '0',  ' ', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y12 \
+       { 'Y',  '1',  '2',  ' ', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y16 \
+       { 'Y',  '1',  '6',  ' ', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_BY8 \
+       { 'B',  'Y',  '8',  ' ', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_BA81 \
+       { 'B',  'A',  '8',  '1', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_GBRG \
+       { 'G',  'B',  'R',  'G', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_GRBG \
+       { 'G',  'R',  'B',  'G', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_RGGB \
+       { 'R',  'G',  'G',  'B', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_BG16 \
+       { 'B',  'G',  '1',  '6', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_GB16 \
+       { 'G',  'B',  '1',  '6', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_RG16 \
+       { 'R',  'G',  '1',  '6', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_GR16 \
+       { 'G',  'R',  '1',  '6', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_RGBP \
+       { 'R',  'G',  'B',  'P', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_BGR3 \
+       { 0x7d, 0xeb, 0x36, 0xe4, 0x4f, 0x52, 0xce, 0x11, \
+        0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}
+#define UVC_GUID_FORMAT_M420 \
+       { 'M',  '4',  '2',  '0', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+
+#define UVC_GUID_FORMAT_H264 \
+       { 'H',  '2',  '6',  '4', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_H265 \
+       { 'H',  '2',  '6',  '5', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y8I \
+       { 'Y',  '8',  'I',  ' ', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y12I \
+       { 'Y',  '1',  '2',  'I', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Z16 \
+       { 'Z',  '1',  '6',  ' ', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_RW10 \
+       { 'R',  'W',  '1',  '0', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_INVZ \
+       { 'I',  'N',  'V',  'Z', 0x90, 0x2d, 0x58, 0x4a, \
+        0x92, 0x0b, 0x77, 0x3f, 0x1f, 0x2c, 0x55, 0x6b}
+#define UVC_GUID_FORMAT_INZI \
+       { 'I',  'N',  'Z',  'I', 0x66, 0x1a, 0x42, 0xa2, \
+        0x90, 0x65, 0xd0, 0x18, 0x14, 0xa8, 0xef, 0x8a}
+#define UVC_GUID_FORMAT_INVI \
+       { 'I',  'N',  'V',  'I', 0xdb, 0x57, 0x49, 0x5e, \
+        0x8e, 0x3f, 0xf4, 0x79, 0x53, 0x2b, 0x94, 0x6f}
+#define UVC_GUID_FORMAT_CNF4 \
+       { 'C',  ' ',  ' ',  ' ', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+
+#define UVC_GUID_FORMAT_D3DFMT_L8 \
+       {0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_KSMEDIA_L8_IR \
+       {0x32, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+
+#define UVC_GUID_FORMAT_HEVC \
+       { 'H',  'E',  'V',  'C', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+
+/* ------------------------------------------------------------------------
+ * Video formats
+ */
+
+struct uvc_format_desc {
+       char *name;
+       u8 guid[16];
+       u32 fcc;
+};
+
+static struct uvc_format_desc uvc_fmts[] = {
+       {
+               .name           = "YUV 4:2:2 (YUYV)",
+               .guid           = UVC_GUID_FORMAT_YUY2,
+               .fcc            = V4L2_PIX_FMT_YUYV,
+       },
+       {
+               .name           = "YUV 4:2:2 (YUYV)",
+               .guid           = UVC_GUID_FORMAT_YUY2_ISIGHT,
+               .fcc            = V4L2_PIX_FMT_YUYV,
+       },
+       {
+               .name           = "YUV 4:2:0 (NV12)",
+               .guid           = UVC_GUID_FORMAT_NV12,
+               .fcc            = V4L2_PIX_FMT_NV12,
+       },
+       {
+               .name           = "MJPEG",
+               .guid           = UVC_GUID_FORMAT_MJPEG,
+               .fcc            = V4L2_PIX_FMT_MJPEG,
+       },
+       {
+               .name           = "YVU 4:2:0 (YV12)",
+               .guid           = UVC_GUID_FORMAT_YV12,
+               .fcc            = V4L2_PIX_FMT_YVU420,
+       },
+       {
+               .name           = "YUV 4:2:0 (I420)",
+               .guid           = UVC_GUID_FORMAT_I420,
+               .fcc            = V4L2_PIX_FMT_YUV420,
+       },
+       {
+               .name           = "YUV 4:2:0 (M420)",
+               .guid           = UVC_GUID_FORMAT_M420,
+               .fcc            = V4L2_PIX_FMT_M420,
+       },
+       {
+               .name           = "YUV 4:2:2 (UYVY)",
+               .guid           = UVC_GUID_FORMAT_UYVY,
+               .fcc            = V4L2_PIX_FMT_UYVY,
+       },
+       {
+               .name           = "Greyscale 8-bit (Y800)",
+               .guid           = UVC_GUID_FORMAT_Y800,
+               .fcc            = V4L2_PIX_FMT_GREY,
+       },
+       {
+               .name           = "Greyscale 8-bit (Y8  )",
+               .guid           = UVC_GUID_FORMAT_Y8,
+               .fcc            = V4L2_PIX_FMT_GREY,
+       },
+       {
+               .name           = "Greyscale 8-bit (D3DFMT_L8)",
+               .guid           = UVC_GUID_FORMAT_D3DFMT_L8,
+               .fcc            = V4L2_PIX_FMT_GREY,
+       },
+       {
+               .name           = "IR 8-bit (L8_IR)",
+               .guid           = UVC_GUID_FORMAT_KSMEDIA_L8_IR,
+               .fcc            = V4L2_PIX_FMT_GREY,
+       },
+       {
+               .name           = "Greyscale 10-bit (Y10 )",
+               .guid           = UVC_GUID_FORMAT_Y10,
+               .fcc            = V4L2_PIX_FMT_Y10,
+       },
+       {
+               .name           = "Greyscale 12-bit (Y12 )",
+               .guid           = UVC_GUID_FORMAT_Y12,
+               .fcc            = V4L2_PIX_FMT_Y12,
+       },
+       {
+               .name           = "Greyscale 16-bit (Y16 )",
+               .guid           = UVC_GUID_FORMAT_Y16,
+               .fcc            = V4L2_PIX_FMT_Y16,
+       },
+       {
+               .name           = "BGGR Bayer (BY8 )",
+               .guid           = UVC_GUID_FORMAT_BY8,
+               .fcc            = V4L2_PIX_FMT_SBGGR8,
+       },
+       {
+               .name           = "BGGR Bayer (BA81)",
+               .guid           = UVC_GUID_FORMAT_BA81,
+               .fcc            = V4L2_PIX_FMT_SBGGR8,
+       },
+       {
+               .name           = "GBRG Bayer (GBRG)",
+               .guid           = UVC_GUID_FORMAT_GBRG,
+               .fcc            = V4L2_PIX_FMT_SGBRG8,
+       },
+       {
+               .name           = "GRBG Bayer (GRBG)",
+               .guid           = UVC_GUID_FORMAT_GRBG,
+               .fcc            = V4L2_PIX_FMT_SGRBG8,
+       },
+       {
+               .name           = "RGGB Bayer (RGGB)",
+               .guid           = UVC_GUID_FORMAT_RGGB,
+               .fcc            = V4L2_PIX_FMT_SRGGB8,
+       },
+       {
+               .name           = "RGB565",
+               .guid           = UVC_GUID_FORMAT_RGBP,
+               .fcc            = V4L2_PIX_FMT_RGB565,
+       },
+       {
+               .name           = "BGR 8:8:8 (BGR3)",
+               .guid           = UVC_GUID_FORMAT_BGR3,
+               .fcc            = V4L2_PIX_FMT_BGR24,
+       },
+       {
+               .name           = "H.264",
+               .guid           = UVC_GUID_FORMAT_H264,
+               .fcc            = V4L2_PIX_FMT_H264,
+       },
+       {
+               .name           = "H.265",
+               .guid           = UVC_GUID_FORMAT_H265,
+               .fcc            = V4L2_PIX_FMT_HEVC,
+       },
+       {
+               .name           = "Greyscale 8 L/R (Y8I)",
+               .guid           = UVC_GUID_FORMAT_Y8I,
+               .fcc            = V4L2_PIX_FMT_Y8I,
+       },
+       {
+               .name           = "Greyscale 12 L/R (Y12I)",
+               .guid           = UVC_GUID_FORMAT_Y12I,
+               .fcc            = V4L2_PIX_FMT_Y12I,
+       },
+       {
+               .name           = "Depth data 16-bit (Z16)",
+               .guid           = UVC_GUID_FORMAT_Z16,
+               .fcc            = V4L2_PIX_FMT_Z16,
+       },
+       {
+               .name           = "Bayer 10-bit (SRGGB10P)",
+               .guid           = UVC_GUID_FORMAT_RW10,
+               .fcc            = V4L2_PIX_FMT_SRGGB10P,
+       },
+       {
+               .name           = "Bayer 16-bit (SBGGR16)",
+               .guid           = UVC_GUID_FORMAT_BG16,
+               .fcc            = V4L2_PIX_FMT_SBGGR16,
+       },
+       {
+               .name           = "Bayer 16-bit (SGBRG16)",
+               .guid           = UVC_GUID_FORMAT_GB16,
+               .fcc            = V4L2_PIX_FMT_SGBRG16,
+       },
+       {
+               .name           = "Bayer 16-bit (SRGGB16)",
+               .guid           = UVC_GUID_FORMAT_RG16,
+               .fcc            = V4L2_PIX_FMT_SRGGB16,
+       },
+       {
+               .name           = "Bayer 16-bit (SGRBG16)",
+               .guid           = UVC_GUID_FORMAT_GR16,
+               .fcc            = V4L2_PIX_FMT_SGRBG16,
+       },
+       {
+               .name           = "Depth data 16-bit (Z16)",
+               .guid           = UVC_GUID_FORMAT_INVZ,
+               .fcc            = V4L2_PIX_FMT_Z16,
+       },
+       {
+               .name           = "Greyscale 10-bit (Y10 )",
+               .guid           = UVC_GUID_FORMAT_INVI,
+               .fcc            = V4L2_PIX_FMT_Y10,
+       },
+       {
+               .name           = "IR:Depth 26-bit (INZI)",
+               .guid           = UVC_GUID_FORMAT_INZI,
+               .fcc            = V4L2_PIX_FMT_INZI,
+       },
+       {
+               .name           = "4-bit Depth Confidence (Packed)",
+               .guid           = UVC_GUID_FORMAT_CNF4,
+               .fcc            = V4L2_PIX_FMT_CNF4,
+       },
+       {
+               .name           = "HEVC",
+               .guid           = UVC_GUID_FORMAT_HEVC,
+               .fcc            = V4L2_PIX_FMT_HEVC,
+       },
+};
+
+static inline struct uvc_format_desc *uvc_format_by_guid(const u8 guid[16])
+{
+       unsigned int len = ARRAY_SIZE(uvc_fmts);
+       unsigned int i;
+
+       for (i = 0; i < len; ++i) {
+               if (memcmp(guid, uvc_fmts[i].guid, 16) == 0)
+                       return &uvc_fmts[i];
+       }
+
+       return NULL;
+}
+
+#endif /* __LINUX_V4L2_UVC_H */
index fd393d9..e4421ad 100644 (file)
@@ -24,4 +24,30 @@ enum usbip_device_status {
        VDEV_ST_USED,
        VDEV_ST_ERROR
 };
+
+/* USB URB Transfer flags:
+ *
+ * USBIP server and client (vchi) pack URBs in TCP packets. The following
+ * are the transfer type defines used in USBIP protocol.
+ */
+
+#define USBIP_URB_SHORT_NOT_OK         0x0001
+#define USBIP_URB_ISO_ASAP             0x0002
+#define USBIP_URB_NO_TRANSFER_DMA_MAP  0x0004
+#define USBIP_URB_ZERO_PACKET          0x0040
+#define USBIP_URB_NO_INTERRUPT         0x0080
+#define USBIP_URB_FREE_BUFFER          0x0100
+#define USBIP_URB_DIR_IN               0x0200
+#define USBIP_URB_DIR_OUT              0
+#define USBIP_URB_DIR_MASK             USBIP_URB_DIR_IN
+
+#define USBIP_URB_DMA_MAP_SINGLE       0x00010000
+#define USBIP_URB_DMA_MAP_PAGE         0x00020000
+#define USBIP_URB_DMA_MAP_SG           0x00040000
+#define USBIP_URB_MAP_LOCAL            0x00080000
+#define USBIP_URB_SETUP_MAP_SINGLE     0x00100000
+#define USBIP_URB_SETUP_MAP_LOCAL      0x00200000
+#define USBIP_URB_DMA_SG_COMBINED      0x00400000
+#define USBIP_URB_ALIGNED_TEMP_BUFFER  0x00800000
+
 #endif /* _UAPI_LINUX_USBIP_H */