summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-04-27 11:42:11 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2023-04-27 11:42:11 -0700
commit4010e62b5b684d7a6090f3f9c69f8a5be31910e5 (patch)
treee93238efb1f254a60ae1e728872a62efc7401601
parentb02847fc2e7a55b7247cf80c14527555bdc965af (diff)
parent8f40fc0808137c157dd408d2632e63bfca2aecdb (diff)
Merge tag 'usb-6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB / Thunderbolt updates from Greg KH: "Here is the large set of USB and Thunderbolt changes for 6.4-rc1. The "biggest" thing in here is the removal of two obsolete drivers, u132-hcd and ftdi-elan, making this a net-removal of code overall. Other than the driver removals, included in here are: - Thunderbolt updates for new hardware and features - xhci driver updates and fixes - dwc3 driver updates and fixes - gadget core and driver updates and features added - mtu3 driver updates - dwc2 driver fixes and updates - usb-serial driver updates - typec driver updates and fixes - platform remove callback changes - dts updates and conversions - other small changes All have been in linux-next for a while with no reported problems" * tag 'usb-6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (177 commits) usb: dwc3: gadget: Refactor EP0 forced stall/restart into a separate API usb: dwc3: gadget: Execute gadget stop after halting the controller media: radio-shark: Add endpoint checks USB: sisusbvga: Add endpoint checks USB: core: Add routines for endpoint checks in old drivers usb: dwc3: gadget: Stall and restart EP0 if host is unresponsive dt-bindings: usb: snps,dwc3: Add 'snps,parkmode-disable-hs-quirk' quirk usb: dwc3: core: add support for disabling High-speed park mode dt-bindings: usb: ci-hdrc-usb2: allow multiple PHYs usb: mtu3: add optional clock xhci_ck and frmcnt_ck dt-bindings: usb: mtu3: add two optional clocks usb: mtu3: expose role-switch control to userspace usb: mtu3: unlock @mtu->lock just before giving back request usb: mtu3: fix kernel panic at qmu transfer done irq handler usb: mtu3: use boolean return value usb: mtu3: give back request when rx error happens usb: chipidea: fix missing goto in `ci_hdrc_probe` usb: gadget: udc: core: Prevent redundant calls to pullup usb: gadget: udc: core: Invoke usb_gadget_connect only when started usb: typec: ucsi: don't print PPM init deferred errors ...
-rw-r--r--Documentation/ABI/testing/configfs-usb-gadget-uvc4
-rw-r--r--Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd52
-rw-r--r--Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml4
-rw-r--r--Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml2
-rw-r--r--Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt159
-rw-r--r--Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml448
-rw-r--r--Documentation/devicetree/bindings/usb/dwc2.yaml5
-rw-r--r--Documentation/devicetree/bindings/usb/fcs,fsa4480.yaml4
-rw-r--r--Documentation/devicetree/bindings/usb/fsl,imx8mq-dwc3.yaml48
-rw-r--r--Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml68
-rw-r--r--Documentation/devicetree/bindings/usb/generic-ehci.yaml2
-rw-r--r--Documentation/devicetree/bindings/usb/generic-ohci.yaml2
-rw-r--r--Documentation/devicetree/bindings/usb/generic-xhci.yaml2
-rw-r--r--Documentation/devicetree/bindings/usb/gpio-sbu-mux.yaml4
-rw-r--r--Documentation/devicetree/bindings/usb/maxim,max33359.yaml4
-rw-r--r--Documentation/devicetree/bindings/usb/mediatek,mt6360-tcpc.yaml4
-rw-r--r--Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml4
-rw-r--r--Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml12
-rw-r--r--Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml12
-rw-r--r--Documentation/devicetree/bindings/usb/mediatek,musb.yaml4
-rw-r--r--Documentation/devicetree/bindings/usb/nvidia,tegra-xudc.yaml4
-rw-r--r--Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml72
-rw-r--r--Documentation/devicetree/bindings/usb/qcom,dwc3.yaml2
-rw-r--r--Documentation/devicetree/bindings/usb/realtek,rts5411.yaml2
-rw-r--r--Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml4
-rw-r--r--Documentation/devicetree/bindings/usb/richtek,rt1719.yaml4
-rw-r--r--Documentation/devicetree/bindings/usb/smsc,usb3503.yaml54
-rw-r--r--Documentation/devicetree/bindings/usb/snps,dwc3.yaml33
-rw-r--r--Documentation/devicetree/bindings/usb/st,stusb160x.yaml4
-rw-r--r--Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml10
-rw-r--r--Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml8
-rw-r--r--Documentation/devicetree/bindings/usb/ti,tps6598x.yaml6
-rw-r--r--Documentation/devicetree/bindings/usb/typec-tcpci.txt49
-rw-r--r--Documentation/devicetree/bindings/usb/usb-device.yaml1
-rw-r--r--Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml3
-rw-r--r--Documentation/devicetree/bindings/usb/usb-xhci.yaml2
-rw-r--r--Documentation/devicetree/bindings/usb/usbmisc-imx.txt19
-rw-r--r--Documentation/usb/gadget_uvc.rst28
-rw-r--r--arch/arm/boot/dts/imx7ulp.dtsi5
-rw-r--r--arch/arm/boot/dts/stm32mp151.dtsi4
-rw-r--r--arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi4
-rw-r--r--arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi5
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mm.dtsi10
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mn.dtsi5
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mq.dtsi2
-rw-r--r--arch/mips/configs/mtx1_defconfig2
-rw-r--r--arch/powerpc/configs/ppc6xx_defconfig2
-rw-r--r--drivers/media/radio/radio-shark.c10
-rw-r--r--drivers/media/radio/radio-shark2.c10
-rw-r--r--drivers/thunderbolt/acpi.c2
-rw-r--r--drivers/thunderbolt/ctl.c2
-rw-r--r--drivers/thunderbolt/eeprom.c204
-rw-r--r--drivers/thunderbolt/nhi.c3
-rw-r--r--drivers/thunderbolt/switch.c4
-rw-r--r--drivers/thunderbolt/usb4.c52
-rw-r--r--drivers/thunderbolt/xdomain.c24
-rw-r--r--drivers/usb/Kconfig29
-rw-r--r--drivers/usb/Makefile1
-rw-r--r--drivers/usb/cdns3/cdns3-debug.h8
-rw-r--r--drivers/usb/cdns3/cdns3-trace.h28
-rw-r--r--drivers/usb/cdns3/cdnsp-trace.h12
-rw-r--r--drivers/usb/chipidea/Makefile2
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c6
-rw-r--r--drivers/usb/chipidea/core.c4
-rw-r--r--drivers/usb/chipidea/debug.c55
-rw-r--r--drivers/usb/core/usb-acpi.c12
-rw-r--r--drivers/usb/core/usb.c76
-rw-r--r--drivers/usb/dwc2/core.h2
-rw-r--r--drivers/usb/dwc2/hcd_queue.c2
-rw-r--r--drivers/usb/dwc2/params.c3
-rw-r--r--drivers/usb/dwc2/platform.c37
-rw-r--r--drivers/usb/dwc3/core.c443
-rw-r--r--drivers/usb/dwc3/core.h21
-rw-r--r--drivers/usb/dwc3/debug.h2
-rw-r--r--drivers/usb/dwc3/debugfs.c5
-rw-r--r--drivers/usb/dwc3/dwc3-am62.c52
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c136
-rw-r--r--drivers/usb/dwc3/ep0.c19
-rw-r--r--drivers/usb/dwc3/gadget.c279
-rw-r--r--drivers/usb/dwc3/host.c7
-rw-r--r--drivers/usb/dwc3/trace.h6
-rw-r--r--drivers/usb/gadget/composite.c127
-rw-r--r--drivers/usb/gadget/configfs.c3
-rw-r--r--drivers/usb/gadget/function/f_ecm.c22
-rw-r--r--drivers/usb/gadget/function/f_fs.c101
-rw-r--r--drivers/usb/gadget/function/u_ether.c63
-rw-r--r--drivers/usb/gadget/function/u_ether.h4
-rw-r--r--drivers/usb/gadget/function/u_fs.h2
-rw-r--r--drivers/usb/gadget/function/uvc_configfs.c121
-rw-r--r--drivers/usb/gadget/legacy/g_ffs.c9
-rw-r--r--drivers/usb/gadget/udc/aspeed-vhub/core.c1
-rw-r--r--drivers/usb/gadget/udc/aspeed-vhub/dev.c1
-rw-r--r--drivers/usb/gadget/udc/aspeed-vhub/ep0.c1
-rw-r--r--drivers/usb/gadget/udc/aspeed-vhub/epn.c1
-rw-r--r--drivers/usb/gadget/udc/aspeed-vhub/hub.c1
-rw-r--r--drivers/usb/gadget/udc/core.c178
-rw-r--r--drivers/usb/gadget/udc/max3420_udc.c2
-rw-r--r--drivers/usb/gadget/udc/mv_udc_core.c6
-rw-r--r--drivers/usb/gadget/udc/renesas_usb3.c26
-rw-r--r--drivers/usb/gadget/udc/renesas_usbf.c11
-rw-r--r--drivers/usb/gadget/udc/rzv2m_usb3drd.c4
-rw-r--r--drivers/usb/gadget/udc/snps_udc_plat.c2
-rw-r--r--drivers/usb/gadget/udc/tegra-xudc.c7
-rw-r--r--drivers/usb/gadget/udc/trace.h5
-rw-r--r--drivers/usb/host/Kconfig27
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-ppc-of.c6
-rw-r--r--drivers/usb/host/fsl-mph-dr-of.c11
-rw-r--r--drivers/usb/host/max3421-hcd.c2
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c2
-rw-r--r--drivers/usb/host/pci-quirks.c4
-rw-r--r--drivers/usb/host/u132-hcd.c3219
-rw-r--r--drivers/usb/host/xhci-dbgcap.c191
-rw-r--r--drivers/usb/host/xhci-dbgcap.h4
-rw-r--r--drivers/usb/host/xhci-debugfs.c1
-rw-r--r--drivers/usb/host/xhci-mem.c83
-rw-r--r--drivers/usb/host/xhci-mtk.c1
-rw-r--r--drivers/usb/host/xhci-mtk.h2
-rw-r--r--drivers/usb/host/xhci-pci.c215
-rw-r--r--drivers/usb/host/xhci-plat.c19
-rw-r--r--drivers/usb/host/xhci-rcar.c36
-rw-r--r--drivers/usb/host/xhci-ring.c1
-rw-r--r--drivers/usb/host/xhci-tegra.c17
-rw-r--r--drivers/usb/host/xhci-trace.c1
-rw-r--r--drivers/usb/host/xhci-trace.h20
-rw-r--r--drivers/usb/host/xhci.c202
-rw-r--r--drivers/usb/host/xhci.h1
-rw-r--r--drivers/usb/misc/Kconfig51
-rw-r--r--drivers/usb/misc/Makefile1
-rw-r--r--drivers/usb/misc/ftdi-elan.c2780
-rw-r--r--drivers/usb/misc/sisusbvga/sisusbvga.c14
-rw-r--r--drivers/usb/misc/usb251xb.c43
-rw-r--r--drivers/usb/misc/usb3503.c64
-rw-r--r--drivers/usb/mtu3/mtu3.h2
-rw-r--r--drivers/usb/mtu3/mtu3_dr.c1
-rw-r--r--drivers/usb/mtu3/mtu3_gadget.c2
-rw-r--r--drivers/usb/mtu3/mtu3_host.c2
-rw-r--r--drivers/usb/mtu3/mtu3_plat.c2
-rw-r--r--drivers/usb/mtu3/mtu3_qmu.c44
-rw-r--r--drivers/usb/musb/Kconfig2
-rw-r--r--drivers/usb/musb/da8xx.c6
-rw-r--r--drivers/usb/musb/jz4740.c6
-rw-r--r--drivers/usb/musb/mediatek.c6
-rw-r--r--drivers/usb/musb/mpfs.c6
-rw-r--r--drivers/usb/musb/musb_core.c5
-rw-r--r--drivers/usb/musb/musb_dsps.c6
-rw-r--r--drivers/usb/musb/omap2430.c8
-rw-r--r--drivers/usb/musb/sunxi.c6
-rw-r--r--drivers/usb/musb/tusb6010.c6
-rw-r--r--drivers/usb/musb/ux500.c6
-rw-r--r--drivers/usb/phy/phy-ab8500-usb.c6
-rw-r--r--drivers/usb/phy/phy-am335x.c5
-rw-r--r--drivers/usb/phy/phy-fsl-usb.c6
-rw-r--r--drivers/usb/phy/phy-generic.c6
-rw-r--r--drivers/usb/phy/phy-gpio-vbus-usb.c6
-rw-r--r--drivers/usb/phy/phy-keystone.c6
-rw-r--r--drivers/usb/phy/phy-mv-usb.c6
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c8
-rw-r--r--drivers/usb/phy/phy-tahvo.c6
-rw-r--r--drivers/usb/phy/phy-tegra-usb.c8
-rw-r--r--drivers/usb/phy/phy-twl6030-usb.c6
-rw-r--r--drivers/usb/renesas_usbhs/common.c2
-rw-r--r--drivers/usb/serial/option.c6
-rw-r--r--drivers/usb/serial/quatech2.c8
-rw-r--r--drivers/usb/typec/hd3ss3220.c2
-rw-r--r--drivers/usb/typec/tcpm/fusb302.c4
-rw-r--r--drivers/usb/typec/tcpm/tcpci_mt6360.c6
-rw-r--r--drivers/usb/typec/tcpm/tcpm.c20
-rw-r--r--drivers/usb/typec/tipd/core.c51
-rw-r--r--drivers/usb/typec/ucsi/Kconfig10
-rw-r--r--drivers/usb/typec/ucsi/Makefile1
-rw-r--r--drivers/usb/typec/ucsi/ucsi.c6
-rw-r--r--drivers/usb/typec/ucsi/ucsi_acpi.c44
-rw-r--r--drivers/usb/typec/ucsi/ucsi_glink.c345
-rw-r--r--include/linux/platform_data/usb3503.h1
-rw-r--r--include/linux/usb.h8
-rw-r--r--include/linux/usb/composite.h8
-rw-r--r--include/linux/usb/gadget.h9
-rw-r--r--include/linux/usb/hcd.h2
179 files changed, 3323 insertions, 7858 deletions
diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc
index 80b98a4a4d0f..4feb692c4c1d 100644
--- a/Documentation/ABI/testing/configfs-usb-gadget-uvc
+++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc
@@ -76,7 +76,7 @@ Date: Dec 2014
KernelVersion: 4.0
Description: Default camera terminal descriptors
- All attributes read only:
+ All attributes read only except bmControls, which is read/write:
======================== ====================================
bmControls bitmap specifying which controls are
@@ -101,7 +101,7 @@ Date: Dec 2014
KernelVersion: 4.0
Description: Default processing unit descriptors
- All attributes read only:
+ All attributes read only except bmControls, which is read/write:
=============== ========================================
iProcessing index of string descriptor
diff --git a/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd b/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd
index 0088aba4caa8..5a775b8f6543 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd
+++ b/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd
@@ -23,3 +23,55 @@ Description:
Reading this attribute gives the state of the DbC. It
can be one of the following states: disabled, enabled,
initialized, connected, configured and stalled.
+
+What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_idVendor
+Date: March 2023
+Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
+Description:
+ This dbc_idVendor attribute lets us change the idVendor field
+ presented in the USB device descriptor by this xhci debug
+ device.
+ Value can only be changed while debug capability (DbC) is in
+ disabled state to prevent USB device descriptor change while
+ connected to a USB host.
+ The default value is 0x1d6b (Linux Foundation).
+ It can be any 16-bit integer.
+
+What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_idProduct
+Date: March 2023
+Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
+Description:
+ This dbc_idProduct attribute lets us change the idProduct field
+ presented in the USB device descriptor by this xhci debug
+ device.
+ Value can only be changed while debug capability (DbC) is in
+ disabled state to prevent USB device descriptor change while
+ connected to a USB host.
+ The default value is 0x0010. It can be any 16-bit integer.
+
+What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_bcdDevice
+Date: March 2023
+Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
+Description:
+ This dbc_bcdDevice attribute lets us change the bcdDevice field
+ presented in the USB device descriptor by this xhci debug
+ device.
+ Value can only be changed while debug capability (DbC) is in
+ disabled state to prevent USB device descriptor change while
+ connected to a USB host.
+ The default value is 0x0010. (device rev 0.10)
+ It can be any 16-bit integer.
+
+What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_bInterfaceProtocol
+Date: March 2023
+Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
+Description:
+ This attribute lets us change the bInterfaceProtocol field
+ presented in the USB Interface descriptor by the xhci debug
+ device.
+ Value can only be changed while debug capability (DbC) is in
+ disabled state to prevent USB descriptor change while
+ connected to a USB host.
+ The default value is 1 (GNU Remote Debug command).
+ Other permissible value is 0 which is for vendor defined debug
+ target.
diff --git a/Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml b/Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml
index f38a2be07eda..da757c1155d4 100644
--- a/Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml
+++ b/Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml
@@ -2,8 +2,8 @@
# Copyright 2019 BayLibre, SAS
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/usb/amlogic,meson-g12a-usb-ctrl.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/usb/amlogic,meson-g12a-usb-ctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic Meson G12A DWC3 USB SoC Controller Glue
diff --git a/Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml b/Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml
index ad075407d85e..1536cbec6334 100644
--- a/Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml
+++ b/Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Broadcom STB USB EHCI Controller
allOf:
- - $ref: "usb-hcd.yaml"
+ - $ref: usb-hcd.yaml
maintainers:
- Al Cooper <alcooperx@gmail.com>
diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt
deleted file mode 100644
index 72ceea575d58..000000000000
--- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt
+++ /dev/null
@@ -1,159 +0,0 @@
-* USB2 ChipIdea USB controller for ci13xxx
-
-Required properties:
-- compatible: should be one of:
- "fsl,imx23-usb"
- "fsl,imx27-usb"
- "fsl,imx28-usb"
- "fsl,imx6q-usb"
- "fsl,imx6sl-usb"
- "fsl,imx6sx-usb"
- "fsl,imx6ul-usb"
- "fsl,imx7d-usb"
- "fsl,imx7ulp-usb"
- "fsl,imx8mm-usb"
- "lsi,zevio-usb"
- "qcom,ci-hdrc"
- "chipidea,usb2"
- "xlnx,zynq-usb-2.20a"
- "nvidia,tegra20-udc"
- "nvidia,tegra30-udc"
- "nvidia,tegra114-udc"
- "nvidia,tegra124-udc"
-- reg: base address and length of the registers
-- interrupts: interrupt for the USB controller
-
-Recommended properies:
-- phy_type: the type of the phy connected to the core. Should be one
- of "utmi", "utmi_wide", "ulpi", "serial" or "hsic". Without this
- property the PORTSC register won't be touched.
-- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg"
-
-Deprecated properties:
-- usb-phy: phandle for the PHY device. Use "phys" instead.
-- fsl,usbphy: phandle of usb phy that connects to the port. Use "phys" instead.
-
-Optional properties:
-- clocks: reference to the USB clock
-- phys: reference to the USB PHY
-- phy-names: should be "usb-phy"
-- vbus-supply: reference to the VBUS regulator
-- maximum-speed: limit the maximum connection speed to "full-speed".
-- tpl-support: TPL (Targeted Peripheral List) feature for targeted hosts
-- itc-setting: interrupt threshold control register control, the setting
- should be aligned with ITC bits at register USBCMD.
-- ahb-burst-config: it is vendor dependent, the required value should be
- aligned with AHBBRST at SBUSCFG, the range is from 0x0 to 0x7. This
- property is used to change AHB burst configuration, check the chipidea
- spec for meaning of each value. If this property is not existed, it
- will use the reset value.
-- tx-burst-size-dword: it is vendor dependent, the tx burst size in dword
- (4 bytes), This register represents the maximum length of a the burst
- in 32-bit words while moving data from system memory to the USB
- bus, the value of this property will only take effect if property
- "ahb-burst-config" is set to 0, if this property is missing the reset
- default of the hardware implementation will be used.
-- rx-burst-size-dword: it is vendor dependent, the rx burst size in dword
- (4 bytes), This register represents the maximum length of a the burst
- in 32-bit words while moving data from the USB bus to system memory,
- the value of this property will only take effect if property
- "ahb-burst-config" is set to 0, if this property is missing the reset
- default of the hardware implementation will be used.
-- extcon: phandles to external connector devices. First phandle should point to
- external connector, which provide "USB" cable events, the second should point
- to external connector device, which provide "USB-HOST" cable events. If one
- of the external connector devices is not required, empty <0> phandle should
- be specified.
-- phy-clkgate-delay-us: the delay time (us) between putting the PHY into
- low power mode and gating the PHY clock.
-- non-zero-ttctrl-ttha: after setting this property, the value of register
- ttctrl.ttha will be 0x7f; if not, the value will be 0x0, this is the default
- value. It needs to be very carefully for setting this property, it is
- recommended that consult with your IC engineer before setting this value.
- On the most of chipidea platforms, the "usage_tt" flag at RTL is 0, so this
- property only affects siTD.
- If this property is not set, the max packet size is 1023 bytes, and if
- the total of packet size for pervious transactions are more than 256 bytes,
- it can't accept any transactions within this frame. The use case is single
- transaction, but higher frame rate.
- If this property is set, the max packet size is 188 bytes, it can handle
- more transactions than above case, it can accept transactions until it
- considers the left room size within frame is less than 188 bytes, software
- needs to make sure it does not send more than 90%
- maximum_periodic_data_per_frame. The use case is multiple transactions, but
- less frame rate.
-- mux-controls: The mux control for toggling host/device output of this
- controller. It's expected that a mux state of 0 indicates device mode and a
- mux state of 1 indicates host mode.
-- mux-control-names: Shall be "usb_switch" if mux-controls is specified.
-- pinctrl-names: Names for optional pin modes in "default", "host", "device".
- In case of HSIC-mode, "idle" and "active" pin modes are mandatory. In this
- case, the "idle" state needs to pull down the data and strobe pin
- and the "active" state needs to pull up the strobe pin.
-- pinctrl-n: alternate pin modes
-
-i.mx specific properties
-- fsl,usbmisc: phandler of non-core register device, with one
- argument that indicate usb controller index
-- disable-over-current: disable over current detect
-- over-current-active-low: over current signal polarity is active low.
-- over-current-active-high: over current signal polarity is active high.
- It's recommended to specify the over current polarity.
-- power-active-high: power signal polarity is active high
-- external-vbus-divider: enables off-chip resistor divider for Vbus
-- samsung,picophy-pre-emp-curr-control: HS Transmitter Pre-Emphasis Current
- Control. This signal controls the amount of current sourced to the
- USB_OTG*_DP and USB_OTG*_DN pins after a J-to-K or K-to-J transition.
- The range is from 0x0 to 0x3, the default value is 0x1.
- Details can refer to TXPREEMPAMPTUNE0 bits of USBNC_n_PHY_CFG1.
-- samsung,picophy-dc-vol-level-adjust: HS DC Voltage Level Adjustment.
- Adjust the high-speed transmitter DC level voltage.
- The range is from 0x0 to 0xf, the default value is 0x3.
- Details can refer to TXVREFTUNE0 bits of USBNC_n_PHY_CFG1.
-
-Example:
-
- usb@f7ed0000 {
- compatible = "chipidea,usb2";
- reg = <0xf7ed0000 0x10000>;
- interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&chip CLKID_USB0>;
- phys = <&usb_phy0>;
- phy-names = "usb-phy";
- vbus-supply = <&reg_usb0_vbus>;
- itc-setting = <0x4>; /* 4 micro-frames */
- /* Incremental burst of unspecified length */
- ahb-burst-config = <0x0>;
- tx-burst-size-dword = <0x10>; /* 64 bytes */
- rx-burst-size-dword = <0x10>;
- extcon = <0>, <&usb_id>;
- phy-clkgate-delay-us = <400>;
- mux-controls = <&usb_switch>;
- mux-control-names = "usb_switch";
- };
-
-Example for HSIC:
-
- usb@2184400 {
- compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
- reg = <0x02184400 0x200>;
- interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks IMX6QDL_CLK_USBOH3>;
- fsl,usbphy = <&usbphynop1>;
- fsl,usbmisc = <&usbmisc 2>;
- phy_type = "hsic";
- dr_mode = "host";
- ahb-burst-config = <0x0>;
- tx-burst-size-dword = <0x10>;
- rx-burst-size-dword = <0x10>;
- pinctrl-names = "idle", "active";
- pinctrl-0 = <&pinctrl_usbh2_idle>;
- pinctrl-1 = <&pinctrl_usbh2_active>;
- #address-cells = <1>;
- #size-cells = <0>;
-
- usbnet: ethernet@1 {
- compatible = "usb424,9730";
- reg = <1>;
- };
- };
diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml
new file mode 100644
index 000000000000..b26d26c2b023
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml
@@ -0,0 +1,448 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/ci-hdrc-usb2.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: USB2 ChipIdea USB controller
+
+maintainers:
+ - Xu Yang <xu.yang_2@nxp.com>
+ - Peng Fan <peng.fan@nxp.com>
+
+properties:
+ compatible:
+ oneOf:
+ - enum:
+ - chipidea,usb2
+ - lsi,zevio-usb
+ - nvidia,tegra20-ehci
+ - nvidia,tegra20-udc
+ - nvidia,tegra30-ehci
+ - nvidia,tegra30-udc
+ - nvidia,tegra114-udc
+ - nvidia,tegra124-udc
+ - qcom,ci-hdrc
+ - items:
+ - enum:
+ - nvidia,tegra114-ehci
+ - nvidia,tegra124-ehci
+ - nvidia,tegra210-ehci
+ - const: nvidia,tegra30-ehci
+ - items:
+ - enum:
+ - fsl,imx23-usb
+ - fsl,imx25-usb
+ - fsl,imx28-usb
+ - fsl,imx50-usb
+ - fsl,imx51-usb
+ - fsl,imx53-usb
+ - fsl,imx6q-usb
+ - fsl,imx6sl-usb
+ - fsl,imx6sx-usb
+ - fsl,imx6ul-usb
+ - fsl,imx7d-usb
+ - fsl,vf610-usb
+ - const: fsl,imx27-usb
+ - items:
+ - const: fsl,imx8dxl-usb
+ - const: fsl,imx7ulp-usb
+ - const: fsl,imx6ul-usb
+ - items:
+ - enum:
+ - fsl,imx8mm-usb
+ - fsl,imx8mn-usb
+ - const: fsl,imx7d-usb
+ - const: fsl,imx27-usb
+ - items:
+ - enum:
+ - fsl,imx6sll-usb
+ - fsl,imx7ulp-usb
+ - const: fsl,imx6ul-usb
+ - const: fsl,imx27-usb
+ - items:
+ - const: xlnx,zynq-usb-2.20a
+ - const: chipidea,usb2
+
+ reg:
+ minItems: 1
+ maxItems: 2
+
+ interrupts:
+ minItems: 1
+ maxItems: 2
+
+ clocks:
+ minItems: 1
+ maxItems: 2
+
+ clock-names:
+ minItems: 1
+ maxItems: 2
+
+ dr_mode: true
+
+ power-domains:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+ reset-names:
+ maxItems: 1
+
+ "#reset-cells":
+ const: 1
+
+ phy_type: true
+
+ itc-setting:
+ description:
+ interrupt threshold control register control, the setting should be
+ aligned with ITC bits at register USBCMD.
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+ ahb-burst-config:
+ description:
+ it is vendor dependent, the required value should be aligned with
+ AHBBRST at SBUSCFG, the range is from 0x0 to 0x7. This property is
+ used to change AHB burst configuration, check the chipidea spec for
+ meaning of each value. If this property is not existed, it will use
+ the reset value.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0x0
+ maximum: 0x7
+
+ tx-burst-size-dword:
+ description:
+ it is vendor dependent, the tx burst size in dword (4 bytes), This
+ register represents the maximum length of a the burst in 32-bit
+ words while moving data from system memory to the USB bus, the value
+ of this property will only take effect if property "ahb-burst-config"
+ is set to 0, if this property is missing the reset default of the
+ hardware implementation will be used.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0x0
+ maximum: 0x20
+
+ rx-burst-size-dword:
+ description:
+ it is vendor dependent, the rx burst size in dword (4 bytes), This
+ register represents the maximum length of a the burst in 32-bit words
+ while moving data from the USB bus to system memory, the value of
+ this property will only take effect if property "ahb-burst-config"
+ is set to 0, if this property is missing the reset default of the
+ hardware implementation will be used.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0x0
+ maximum: 0x20
+
+ extcon:
+ description:
+ Phandles to external connector devices. First phandle should point
+ to external connector, which provide "USB" cable events, the second
+ should point to external connector device, which provide "USB-HOST"
+ cable events. If one of the external connector devices is not
+ required, empty <0> phandle should be specified.
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ minItems: 1
+ items:
+ - description: vbus extcon
+ - description: id extcon
+
+ phy-clkgate-delay-us:
+ description:
+ The delay time (us) between putting the PHY into low power mode and
+ gating the PHY clock.
+
+ non-zero-ttctrl-ttha:
+ description:
+ After setting this property, the value of register ttctrl.ttha
+ will be 0x7f; if not, the value will be 0x0, this is the default
+ value. It needs to be very carefully for setting this property, it
+ is recommended that consult with your IC engineer before setting
+ this value. On the most of chipidea platforms, the "usage_tt" flag
+ at RTL is 0, so this property only affects siTD.
+
+ If this property is not set, the max packet size is 1023 bytes, and
+ if the total of packet size for pervious transactions are more than
+ 256 bytes, it can't accept any transactions within this frame. The
+ use case is single transaction, but higher frame rate.
+
+ If this property is set, the max packet size is 188 bytes, it can
+ handle more transactions than above case, it can accept transactions
+ until it considers the left room size within frame is less than 188
+ bytes, software needs to make sure it does not send more than 90%
+ maximum_periodic_data_per_frame. The use case is multiple
+ transactions, but less frame rate.
+ type: boolean
+
+ mux-controls:
+ description:
+ The mux control for toggling host/device output of this controller.
+ It's expected that a mux state of 0 indicates device mode and a mux
+ state of 1 indicates host mode.
+ maxItems: 1
+
+ mux-control-names:
+ const: usb_switch
+
+ operating-points-v2:
+ description: A phandle to the OPP table containing the performance states.
+ $ref: /schemas/types.yaml#/definitions/phandle
+
+ pinctrl-names:
+ description:
+ Names for optional pin modes in "default", "host", "device".
+ In case of HSIC-mode, "idle" and "active" pin modes are mandatory.
+ In this case, the "idle" state needs to pull down the data and
+ strobe pin and the "active" state needs to pull up the strobe pin.
+ oneOf:
+ - items:
+ - const: idle
+ - const: active
+ - items:
+ - const: default
+ - enum:
+ - host
+ - device
+ - items:
+ - const: default
+
+ pinctrl-0:
+ maxItems: 1
+
+ pinctrl-1:
+ maxItems: 1
+
+ phys:
+ maxItems: 1
+
+ phy-names:
+ const: usb-phy
+
+ phy-select:
+ description:
+ Phandler of TCSR node with two argument that indicate register
+ offset, and phy index
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ items:
+ - description: phandle to TCSR node
+ - description: register offset
+ - description: phy index
+
+ vbus-supply:
+ description: reference to the VBUS regulator.
+
+ fsl,usbmisc:
+ description:
+ Phandler of non-core register device, with one argument that
+ indicate usb controller index
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ items:
+ - items:
+ - description: phandle to usbmisc node
+ - description: index of usb controller
+
+ fsl,anatop:
+ description: phandle for the anatop node.
+ $ref: /schemas/types.yaml#/definitions/phandle
+
+ disable-over-current:
+ type: boolean
+ description: disable over current detect
+
+ over-current-active-low:
+ type: boolean
+ description: over current signal polarity is active low
+
+ over-current-active-high:
+ type: boolean
+ description:
+ Over current signal polarity is active high. It's recommended to
+ specify the over current polarity.
+
+ power-active-high:
+ type: boolean
+ description: power signal polarity is active high
+
+ external-vbus-divider:
+ type: boolean
+ description: enables off-chip resistor divider for Vbus
+
+ samsung,picophy-pre-emp-curr-control:
+ description:
+ HS Transmitter Pre-Emphasis Current Control. This signal controls
+ the amount of current sourced to the USB_OTG*_DP and USB_OTG*_DN
+ pins after a J-to-K or K-to-J transition. The range is from 0x0 to
+ 0x3, the default value is 0x1. Details can refer to TXPREEMPAMPTUNE0
+ bits of USBNC_n_PHY_CFG1.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0x0
+ maximum: 0x3
+
+ samsung,picophy-dc-vol-level-adjust:
+ description:
+ HS DC Voltage Level Adjustment. Adjust the high-speed transmitter DC
+ level voltage. The range is from 0x0 to 0xf, the default value is
+ 0x3. Details can refer to TXVREFTUNE0 bits of USBNC_n_PHY_CFG1.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0x0
+ maximum: 0xf
+
+ usb-phy:
+ description: phandle for the PHY device. Use "phys" instead.
+ $ref: /schemas/types.yaml#/definitions/phandle
+ deprecated: true
+
+ fsl,usbphy:
+ description: phandle of usb phy that connects to the port. Use "phys" instead.
+ $ref: /schemas/types.yaml#/definitions/phandle
+ deprecated: true
+
+ nvidia,phy:
+ description: phandle of usb phy that connects to the port. Use "phys" instead.
+ $ref: /schemas/types.yaml#/definitions/phandle
+ deprecated: true
+
+ nvidia,needs-double-reset:
+ description: Indicates double reset or not.
+ type: boolean
+ deprecated: true
+
+ port:
+ description:
+ Any connector to the data bus of this controller should be modelled
+ using the OF graph bindings specified, if the "usb-role-switch"
+ property is used.
+ $ref: /schemas/graph.yaml#/properties/port
+
+ reset-gpios:
+ maxItems: 1
+
+ ulpi:
+ type: object
+ additionalProperties: false
+ patternProperties:
+ "^phy(-[0-9])?$":
+ description: The phy child node for Qcom chips.
+ type: object
+ $ref: /schemas/phy/qcom,usb-hs-phy.yaml
+
+dependencies:
+ port: [ usb-role-switch ]
+ mux-controls: [ mux-control-names ]
+
+required:
+ - compatible
+ - reg
+ - interrupts
+
+allOf:
+ - $ref: usb-hcd.yaml#
+ - $ref: usb-drd.yaml#
+ - if:
+ properties:
+ phy_type:
+ const: hsic
+ required:
+ - phy_type
+ then:
+ properties:
+ pinctrl-names:
+ items:
+ - const: idle
+ - const: active
+ else:
+ properties:
+ pinctrl-names:
+ minItems: 1
+ maxItems: 2
+ oneOf:
+ - items:
+ - const: default
+ - enum:
+ - host
+ - device
+ - items:
+ - const: default
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - chipidea,usb2
+ - lsi,zevio-usb
+ - nvidia,tegra20-udc
+ - nvidia,tegra30-udc
+ - nvidia,tegra114-udc
+ - nvidia,tegra124-udc
+ - qcom,ci-hdrc
+ - xlnx,zynq-usb-2.20a
+ then:
+ properties:
+ fsl,usbmisc: false
+ disable-over-current: false
+ over-current-active-low: false
+ over-current-active-high: false
+ power-active-high: false
+ external-vbus-divider: false
+ samsung,picophy-pre-emp-curr-control: false
+ samsung,picophy-dc-vol-level-adjust: false
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/berlin2.h>
+
+ usb@f7ed0000 {
+ compatible = "chipidea,usb2";
+ reg = <0xf7ed0000 0x10000>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&chip CLKID_USB0>;
+ phys = <&usb_phy0>;
+ phy-names = "usb-phy";
+ vbus-supply = <&reg_usb0_vbus>;
+ itc-setting = <0x4>; /* 4 micro-frames */
+ /* Incremental burst of unspecified length */
+ ahb-burst-config = <0x0>;
+ tx-burst-size-dword = <0x10>; /* 64 bytes */
+ rx-burst-size-dword = <0x10>;
+ extcon = <0>, <&usb_id>;
+ phy-clkgate-delay-us = <400>;
+ mux-controls = <&usb_switch>;
+ mux-control-names = "usb_switch";
+ };
+
+ # Example for HSIC:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/imx6qdl-clock.h>
+
+ usb@2184400 {
+ compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
+ reg = <0x02184400 0x200>;
+ interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX6QDL_CLK_USBOH3>;
+ fsl,usbphy = <&usbphynop1>;
+ fsl,usbmisc = <&usbmisc 2>;
+ phy_type = "hsic";
+ dr_mode = "host";
+ ahb-burst-config = <0x0>;
+ tx-burst-size-dword = <0x10>;
+ rx-burst-size-dword = <0x10>;
+ pinctrl-names = "idle", "active";
+ pinctrl-0 = <&pinctrl_usbh2_idle>;
+ pinctrl-1 = <&pinctrl_usbh2_active>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethernet@1 {
+ compatible = "usb424,9730";
+ reg = <1>;
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/usb/dwc2.yaml b/Documentation/devicetree/bindings/usb/dwc2.yaml
index 371ba93f3ce5..d3506090f8b1 100644
--- a/Documentation/devicetree/bindings/usb/dwc2.yaml
+++ b/Documentation/devicetree/bindings/usb/dwc2.yaml
@@ -75,11 +75,14 @@ properties:
maxItems: 1
clocks:
- maxItems: 1
+ minItems: 1
+ maxItems: 2
clock-names:
items:
- const: otg
+ - const: utmi
+ minItems: 1
disable-over-current:
type: boolean
diff --git a/Documentation/devicetree/bindings/usb/fcs,fsa4480.yaml b/Documentation/devicetree/bindings/usb/fcs,fsa4480.yaml
index 51120fe90322..f6e7a5c1ff0b 100644
--- a/Documentation/devicetree/bindings/usb/fcs,fsa4480.yaml
+++ b/Documentation/devicetree/bindings/usb/fcs,fsa4480.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/usb/fcs,fsa4480.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/usb/fcs,fsa4480.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ON Semiconductor Analog Audio Switch
diff --git a/Documentation/devicetree/bindings/usb/fsl,imx8mq-dwc3.yaml b/Documentation/devicetree/bindings/usb/fsl,imx8mq-dwc3.yaml
new file mode 100644
index 000000000000..50569d3ee767
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/fsl,imx8mq-dwc3.yaml
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/fsl,imx8mq-dwc3.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP iMX8MQ Soc USB Controller
+
+maintainers:
+ - Li Jun <jun.li@nxp.com>
+ - Peng Fan <peng.fan@nxp.com>
+
+select:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - fsl,imx8mq-dwc3
+ required:
+ - compatible
+
+properties:
+ compatible:
+ items:
+ - const: fsl,imx8mq-dwc3
+ - const: snps,dwc3
+
+allOf:
+ - $ref: snps,dwc3.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/imx8mq-clock.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ usb_dwc3_1: usb@38200000 {
+ compatible = "fsl,imx8mq-dwc3", "snps,dwc3";
+ reg = <0x38200000 0x10000>;
+ clocks = <&clk IMX8MQ_CLK_USB2_CTRL_ROOT>,
+ <&clk IMX8MQ_CLK_USB_CORE_REF>,
+ <&clk IMX8MQ_CLK_32K>;
+ clock-names = "bus_early", "ref", "suspend";
+ interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&usb3_phy1>, <&usb3_phy1>;
+ phy-names = "usb2-phy", "usb3-phy";
+ };
diff --git a/Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml b/Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml
new file mode 100644
index 000000000000..2d3589d284b2
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/fsl,usbmisc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale i.MX wrapper module for Chipidea USB2 controller
+
+maintainers:
+ - Xu Yang <xu.yang_2@nxp.com>
+ - Peng Fan <peng.fan@nxp.com>
+
+properties:
+ compatible:
+ oneOf:
+ - enum:
+ - fsl,imx25-usbmisc
+ - fsl,imx27-usbmisc
+ - fsl,imx35-usbmisc
+ - fsl,imx51-usbmisc
+ - fsl,imx53-usbmisc
+ - fsl,imx6q-usbmisc
+ - fsl,vf610-usbmisc
+ - items:
+ - enum:
+ - fsl,imx6ul-usbmisc
+ - fsl,imx6sl-usbmisc
+ - fsl,imx6sx-usbmisc
+ - fsl,imx7d-usbmisc
+ - const: fsl,imx6q-usbmisc
+ - items:
+ - enum:
+ - fsl,imx7ulp-usbmisc
+ - fsl,imx8mm-usbmisc
+ - fsl,imx8mn-usbmisc
+ - const: fsl,imx7d-usbmisc
+ - const: fsl,imx6q-usbmisc
+ - items:
+ - const: fsl,imx6sll-usbmisc
+ - const: fsl,imx6ul-usbmisc
+ - const: fsl,imx6q-usbmisc
+
+ clocks:
+ maxItems: 1
+
+ reg:
+ maxItems: 1
+
+ '#index-cells':
+ const: 1
+ description: Cells used to describe usb controller index.
+ deprecated: true
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ usbmisc@2184800 {
+ compatible = "fsl,imx6q-usbmisc";
+ reg = <0x02184800 0x200>;
+ #index-cells = <1>;
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/usb/generic-ehci.yaml b/Documentation/devicetree/bindings/usb/generic-ehci.yaml
index 050cfd5acdaa..9445764bd8de 100644
--- a/Documentation/devicetree/bindings/usb/generic-ehci.yaml
+++ b/Documentation/devicetree/bindings/usb/generic-ehci.yaml
@@ -10,7 +10,7 @@ maintainers:
- Greg Kroah-Hartman <gregkh@linuxfoundation.org>
allOf:
- - $ref: "usb-hcd.yaml"
+ - $ref: usb-hcd.yaml
- if:
properties:
compatible:
diff --git a/Documentation/devicetree/bindings/usb/generic-ohci.yaml b/Documentation/devicetree/bindings/usb/generic-ohci.yaml
index a9ba7257b884..d06d1e7d8876 100644
--- a/Documentation/devicetree/bindings/usb/generic-ohci.yaml
+++ b/Documentation/devicetree/bindings/usb/generic-ohci.yaml
@@ -148,7 +148,7 @@ allOf:
properties:
transceiver: false
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/usb/generic-xhci.yaml b/Documentation/devicetree/bindings/usb/generic-xhci.yaml
index db841589fc33..594ebb3ee432 100644
--- a/Documentation/devicetree/bindings/usb/generic-xhci.yaml
+++ b/Documentation/devicetree/bindings/usb/generic-xhci.yaml
@@ -10,7 +10,7 @@ maintainers:
- Mathias Nyman <mathias.nyman@intel.com>
allOf:
- - $ref: "usb-xhci.yaml#"
+ - $ref: usb-xhci.yaml#
properties:
compatible:
diff --git a/Documentation/devicetree/bindings/usb/gpio-sbu-mux.yaml b/Documentation/devicetree/bindings/usb/gpio-sbu-mux.yaml
index bf4b1d016e1f..f196beb826d8 100644
--- a/Documentation/devicetree/bindings/usb/gpio-sbu-mux.yaml
+++ b/Documentation/devicetree/bindings/usb/gpio-sbu-mux.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/usb/gpio-sbu-mux.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/usb/gpio-sbu-mux.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: GPIO-based SBU mux
diff --git a/Documentation/devicetree/bindings/usb/maxim,max33359.yaml b/Documentation/devicetree/bindings/usb/maxim,max33359.yaml
index 3cb631ea7079..276bf7554215 100644
--- a/Documentation/devicetree/bindings/usb/maxim,max33359.yaml
+++ b/Documentation/devicetree/bindings/usb/maxim,max33359.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/usb/maxim,max33359.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/usb/maxim,max33359.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Maxim TCPCI Type-C PD controller
diff --git a/Documentation/devicetree/bindings/usb/mediatek,mt6360-tcpc.yaml b/Documentation/devicetree/bindings/usb/mediatek,mt6360-tcpc.yaml
index 6cad7ae2c70d..053264e60583 100644
--- a/Documentation/devicetree/bindings/usb/mediatek,mt6360-tcpc.yaml
+++ b/Documentation/devicetree/bindings/usb/mediatek,mt6360-tcpc.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/usb/mediatek,mt6360-tcpc.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/usb/mediatek,mt6360-tcpc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Mediatek MT6360 Type-C Port Switch and Power Delivery controller
diff --git a/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml
index 72f56cc88457..747d0f16d9b6 100644
--- a/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml
+++ b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml
@@ -1,8 +1,8 @@
# 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#"
+$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
diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml
index c119caa9ad16..e9644e333d78 100644
--- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml
+++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml
@@ -11,7 +11,7 @@ maintainers:
- Chunfeng Yun <chunfeng.yun@mediatek.com>
allOf:
- - $ref: "usb-xhci.yaml"
+ - $ref: usb-xhci.yaml
description: |
There are two scenarios:
@@ -77,6 +77,7 @@ properties:
- description: Mcu bus clock for register access
- description: DMA bus clock for data transfer
- description: controller clock
+ - description: frame count clock
clock-names:
minItems: 1
@@ -86,14 +87,7 @@ properties:
- const: mcu_ck
- const: dma_ck
- const: xhci_ck
-
- assigned-clocks:
- minItems: 1
- maxItems: 5
-
- assigned-clock-parents:
- minItems: 1
- maxItems: 5
+ - const: frmcnt_ck
phys:
description:
diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml
index d2655173e108..478214ab045e 100644
--- a/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml
+++ b/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml
@@ -11,7 +11,7 @@ maintainers:
- Chunfeng Yun <chunfeng.yun@mediatek.com>
allOf:
- - $ref: "usb-drd.yaml"
+ - $ref: usb-drd.yaml
description: |
The DRD controller has a glue layer IPPC (IP Port Control), and its host is
@@ -66,6 +66,8 @@ properties:
- description: Reference clock used by low power mode etc
- description: Mcu bus clock for register access
- description: DMA bus clock for data transfer
+ - description: DRD controller clock
+ - description: Frame count clock
clock-names:
minItems: 1
@@ -74,6 +76,8 @@ properties:
- const: ref_ck
- const: mcu_ck
- const: dma_ck
+ - const: xhci_ck
+ - const: frmcnt_ck
phys:
description:
@@ -204,9 +208,9 @@ patternProperties:
example if the host mode is enabled.
dependencies:
- connector: [ 'usb-role-switch' ]
- port: [ 'usb-role-switch' ]
- role-switch-default-mode: [ 'usb-role-switch' ]
+ connector: [ usb-role-switch ]
+ port: [ usb-role-switch ]
+ role-switch-default-mode: [ usb-role-switch ]
wakeup-source: [ 'mediatek,syscon-wakeup' ]
required:
diff --git a/Documentation/devicetree/bindings/usb/mediatek,musb.yaml b/Documentation/devicetree/bindings/usb/mediatek,musb.yaml
index f16ab30a95d2..a39d38db7714 100644
--- a/Documentation/devicetree/bindings/usb/mediatek,musb.yaml
+++ b/Documentation/devicetree/bindings/usb/mediatek,musb.yaml
@@ -68,8 +68,8 @@ properties:
type: object
dependencies:
- usb-role-switch: [ 'connector' ]
- connector: [ 'usb-role-switch' ]
+ usb-role-switch: [ connector ]
+ connector: [ usb-role-switch ]
required:
- compatible
diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra-xudc.yaml b/Documentation/devicetree/bindings/usb/nvidia,tegra-xudc.yaml
index e638f77658fc..e2270ce0c56b 100644
--- a/Documentation/devicetree/bindings/usb/nvidia,tegra-xudc.yaml
+++ b/Documentation/devicetree/bindings/usb/nvidia,tegra-xudc.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/usb/nvidia,tegra-xudc.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/usb/nvidia,tegra-xudc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NVIDIA Tegra XUSB device mode controller (XUDC)
diff --git a/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml b/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml
new file mode 100644
index 000000000000..28eb25ecba74
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/nxp,ptn5110.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP PTN5110 Typec Port Cotroller
+
+maintainers:
+ - Li Jun <jun.li@nxp.com>
+
+properties:
+ compatible:
+ const: nxp,ptn5110
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ connector:
+ type: object
+ $ref: /schemas/connector/usb-connector.yaml#
+ unevaluatedProperties: false
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - connector
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/usb/pd.h>
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tcpci@50 {
+ compatible = "nxp,ptn5110";
+ reg = <0x50>;
+ interrupt-parent = <&gpio3>;
+ interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+
+ usb_con: 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_USB_COMM)>;
+ sink-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_USB_COMM) PDO_VAR(5000, 12000, 2000)>;
+ op-sink-microwatt = <10000000>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ typec1_dr_sw: endpoint {
+ remote-endpoint = <&usb1_drd_sw>;
+ };
+ };
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml
index 3e401014e3bc..d84281926f10 100644
--- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml
+++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml
@@ -21,6 +21,7 @@ properties:
- qcom,msm8994-dwc3
- qcom,msm8996-dwc3
- qcom,msm8998-dwc3
+ - qcom,qcm2290-dwc3
- qcom,qcs404-dwc3
- qcom,sc7180-dwc3
- qcom,sc7280-dwc3
@@ -301,6 +302,7 @@ allOf:
compatible:
contains:
enum:
+ - qcom,qcm2290-dwc3
- qcom,sm6115-dwc3
- qcom,sm6125-dwc3
- qcom,sm8150-dwc3
diff --git a/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml b/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml
index 623d04a88a81..9309f003cd07 100644
--- a/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml
+++ b/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml
@@ -26,7 +26,7 @@ properties:
phandle to the regulator that provides power to the hub.
peer-hub:
- $ref: '/schemas/types.yaml#/definitions/phandle'
+ $ref: /schemas/types.yaml#/definitions/phandle
description:
phandle to the peer hub on the controller.
diff --git a/Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml b/Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml
index dd864b25a148..8da4d2ad1a91 100644
--- a/Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml
+++ b/Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml
@@ -1,8 +1,8 @@
# 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#"
+$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
diff --git a/Documentation/devicetree/bindings/usb/richtek,rt1719.yaml b/Documentation/devicetree/bindings/usb/richtek,rt1719.yaml
index 8b9bd2cc58e9..4ced2f68e2a9 100644
--- a/Documentation/devicetree/bindings/usb/richtek,rt1719.yaml
+++ b/Documentation/devicetree/bindings/usb/richtek,rt1719.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/usb/richtek,rt1719.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/usb/richtek,rt1719.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Richtek RT1719 sink-only Type-C PD controller
diff --git a/Documentation/devicetree/bindings/usb/smsc,usb3503.yaml b/Documentation/devicetree/bindings/usb/smsc,usb3503.yaml
index a09f4528aea3..6156dc26e65c 100644
--- a/Documentation/devicetree/bindings/usb/smsc,usb3503.yaml
+++ b/Documentation/devicetree/bindings/usb/smsc,usb3503.yaml
@@ -14,6 +14,7 @@ properties:
enum:
- smsc,usb3503
- smsc,usb3503a
+ - smsc,usb3803
reg:
maxItems: 1
@@ -33,6 +34,12 @@ properties:
description: >
GPIO for reset
+ bypass-gpios:
+ maxItems: 1
+ description: >
+ GPIO for bypass.
+ Control signal to select between HUB MODE and BYPASS MODE.
+
disabled-ports:
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
@@ -46,9 +53,10 @@ properties:
initial-mode:
$ref: /schemas/types.yaml#/definitions/uint32
- enum: [1, 2]
description: >
- Specifies initial mode. 1 for Hub mode, 2 for standby mode.
+ Specifies initial mode. 1 for Hub mode, 2 for standby mode and 3 for bypass mode.
+ In bypass mode the downstream port 3 is connected to the upstream port with low
+ switch resistance R_on.
clocks:
maxItems: 1
@@ -71,6 +79,29 @@ properties:
required:
- compatible
+allOf:
+ - if:
+ not:
+ properties:
+ compatible:
+ enum:
+ - smsc,usb3803
+ then:
+ properties:
+ bypass-gpios: false
+
+ - if:
+ required:
+ - bypass-gpios
+ then:
+ properties:
+ initial-mode:
+ enum: [1, 2, 3]
+ else:
+ properties:
+ initial-mode:
+ enum: [1, 2]
+
additionalProperties: false
examples:
@@ -93,6 +124,25 @@ examples:
};
- |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ usb-hub@8 {
+ compatible = "smsc,usb3803";
+ reg = <0x08>;
+ connect-gpios = <&gpx3 0 1>;
+ disabled-ports = <2 3>;
+ intn-gpios = <&gpx3 4 1>;
+ reset-gpios = <&gpx3 5 1>;
+ bypass-gpios = <&gpx3 6 1>;
+ initial-mode = <3>;
+ clocks = <&clks 80>;
+ clock-names = "refclk";
+ };
+ };
+
+ - |
#include <dt-bindings/gpio/gpio.h>
usb-hub {
diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml
index be36956af53b..50edc4da780e 100644
--- a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml
+++ b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml
@@ -70,6 +70,10 @@ properties:
dma-coherent: true
+ extcon:
+ maxItems: 1
+ deprecated: true
+
iommus:
maxItems: 1
@@ -232,6 +236,11 @@ properties:
When set, all SuperSpeed bus instances in park mode are disabled.
type: boolean
+ snps,parkmode-disable-hs-quirk:
+ description:
+ When set, all HighSpeed bus instances in park mode are disabled.
+ type: boolean
+
snps,dis_metastability_quirk:
description:
When set, disable metastability workaround. CAUTION! Use only if you are
@@ -256,6 +265,14 @@ properties:
of resume. This option is to support certain legacy ULPI PHYs.
type: boolean
+ snps,ulpi-ext-vbus-drv:
+ description:
+ Some ULPI USB PHY does not support internal VBUS supply, and driving
+ the CPEN pin, requires the configuration of the ulpi DRVVBUSEXTERNAL
+ bit. When set, the xhci host will configure the USB2 PHY drives VBUS
+ with an external supply.
+ type: boolean
+
snps,is-utmi-l1-suspend:
description:
True when DWC3 asserts output signal utmi_l1_suspend_n, false when
@@ -365,6 +382,22 @@ properties:
This port is used with the 'usb-role-switch' property to connect the
dwc3 to type C connector.
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+ description:
+ Those ports should be used with any connector to the data bus of this
+ controller using the OF graph bindings specified if the "usb-role-switch"
+ property is used.
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: High Speed (HS) data bus.
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: Super Speed (SS) data bus.
+
wakeup-source:
$ref: /schemas/types.yaml#/definitions/flag
description:
diff --git a/Documentation/devicetree/bindings/usb/st,stusb160x.yaml b/Documentation/devicetree/bindings/usb/st,stusb160x.yaml
index f6840cd5750d..acda2f47fbc9 100644
--- a/Documentation/devicetree/bindings/usb/st,stusb160x.yaml
+++ b/Documentation/devicetree/bindings/usb/st,stusb160x.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/usb/st,stusb160x.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/usb/st,stusb160x.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: STMicroelectronics STUSB160x Type-C controller
diff --git a/Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml b/Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml
index f81ba3e90297..95ff9791baea 100644
--- a/Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml
+++ b/Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/usb/ti,j721e-usb.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/usb/ti,j721e-usb.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TI wrapper module for the Cadence USBSS-DRD controller
@@ -53,12 +53,6 @@ properties:
VBUS pin of the SoC via a 1/3 voltage divider.
type: boolean
- assigned-clocks:
- maxItems: 1
-
- assigned-clock-parents:
- maxItems: 1
-
'#address-cells':
const: 2
diff --git a/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml b/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml
index c1f0194ad0d5..9252d893f694 100644
--- a/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml
+++ b/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml
@@ -34,14 +34,6 @@ properties:
minItems: 1
maxItems: 2
- assigned-clocks:
- minItems: 1
- maxItems: 2
-
- assigned-clock-parents:
- minItems: 1
- maxItems: 2
-
power-domains:
maxItems: 1
description: Should contain a phandle to a PM domain provider node
diff --git a/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml b/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml
index 7dfa34d11b0e..5497a60cddbc 100644
--- a/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml
+++ b/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/usb/ti,tps6598x.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/usb/ti,tps6598x.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments 6598x Type-C Port Switch and Power Delivery controller
@@ -35,8 +35,6 @@ properties:
required:
- compatible
- reg
- - interrupts
- - interrupt-names
additionalProperties: true
diff --git a/Documentation/devicetree/bindings/usb/typec-tcpci.txt b/Documentation/devicetree/bindings/usb/typec-tcpci.txt
deleted file mode 100644
index 2082522b1c32..000000000000
--- a/Documentation/devicetree/bindings/usb/typec-tcpci.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-TCPCI(Typec port cotroller interface) binding
----------------------------------------------
-
-Required properties:
-- compatible: should be set one of following:
- - "nxp,ptn5110" for NXP USB PD TCPC PHY IC ptn5110.
-
-- reg: the i2c slave address of typec port controller device.
-- interrupt-parent: the phandle to the interrupt controller which provides
- the interrupt.
-- interrupts: interrupt specification for tcpci alert.
-
-Required sub-node:
-- connector: The "usb-c-connector" attached to the tcpci chip, the bindings
- of connector node are specified in
- Documentation/devicetree/bindings/connector/usb-connector.yaml
-
-Example:
-
-ptn5110@50 {
- compatible = "nxp,ptn5110";
- reg = <0x50>;
- interrupt-parent = <&gpio3>;
- interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
-
- usb_con: 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_USB_COMM)>;
- sink-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_USB_COMM)
- PDO_VAR(5000, 12000, 2000)>;
- op-sink-microwatt = <10000000>;
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@1 {
- reg = <1>;
- usb_con_ss: endpoint {
- remote-endpoint = <&usb3_data_ss>;
- };
- };
- };
- };
-};
diff --git a/Documentation/devicetree/bindings/usb/usb-device.yaml b/Documentation/devicetree/bindings/usb/usb-device.yaml
index 7a771125ec76..da890ee60ce6 100644
--- a/Documentation/devicetree/bindings/usb/usb-device.yaml
+++ b/Documentation/devicetree/bindings/usb/usb-device.yaml
@@ -76,7 +76,6 @@ patternProperties:
maxItems: 1
required:
- - compatible
- reg
additionalProperties: true
diff --git a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml
index 921b986adc47..6734f4d3aa78 100644
--- a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml
+++ b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml
@@ -27,6 +27,9 @@ properties:
vcc-supply:
description: phandle to the regulator that provides power to the PHY.
+ power-domains:
+ maxItems: 1
+
reset-gpios:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.yaml b/Documentation/devicetree/bindings/usb/usb-xhci.yaml
index f2139a9f35fb..180a261c3e8f 100644
--- a/Documentation/devicetree/bindings/usb/usb-xhci.yaml
+++ b/Documentation/devicetree/bindings/usb/usb-xhci.yaml
@@ -10,7 +10,7 @@ maintainers:
- Mathias Nyman <mathias.nyman@intel.com>
allOf:
- - $ref: "usb-hcd.yaml#"
+ - $ref: usb-hcd.yaml#
properties:
usb2-lpm-disable:
diff --git a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt b/Documentation/devicetree/bindings/usb/usbmisc-imx.txt
deleted file mode 100644
index 29b8f65ff849..000000000000
--- a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-* Freescale i.MX non-core registers
-
-Required properties:
-- #index-cells: Cells used to describe usb controller index. Should be <1>
-- compatible: Should be one of below:
- "fsl,imx6q-usbmisc" for imx6q
- "fsl,vf610-usbmisc" for Vybrid vf610
- "fsl,imx6sx-usbmisc" for imx6sx
- "fsl,imx7d-usbmisc" for imx7d
- "fsl,imx7ulp-usbmisc" for imx7ulp
- "fsl,imx8mm-usbmisc" for imx8mm
-- reg: Should contain registers location and length
-
-Examples:
-usbmisc@2184800 {
- #index-cells = <1>;
- compatible = "fsl,imx6q-usbmisc";
- reg = <0x02184800 0x200>;
-};
diff --git a/Documentation/usb/gadget_uvc.rst b/Documentation/usb/gadget_uvc.rst
index 6d22faceb1a0..62bd81ba3dd1 100644
--- a/Documentation/usb/gadget_uvc.rst
+++ b/Documentation/usb/gadget_uvc.rst
@@ -275,6 +275,34 @@ out with 0x00, for example:
bNrInPins and baSourceID function in the same way.
+Configuring Supported Controls for Camera Terminal and Processing Unit
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The Camera Terminal and Processing Units in the UVC chain also have bmControls
+attributes which function similarly to the same field in an Extension Unit.
+Unlike XUs however, the meaning of the bitflag for these units is defined in
+the UVC specification; you should consult the "Camera Terminal Descriptor" and
+"Processing Unit Descriptor" sections for an enumeration of the flags.
+
+.. code-block:: bash
+
+ # Set the Processing Unit's bmControls, flagging Brightness, Contrast
+ # and Hue as available controls:
+ echo 0x05 > $FUNCTION/control/processing/default/bmControls
+
+ # Set the Camera Terminal's bmControls, flagging Focus Absolute and
+ # Focus Relative as available controls:
+ echo 0x60 > $FUNCTION/control/terminal/camera/default/bmControls
+
+If you do not set these fields then by default the Auto-Exposure Mode control
+for the Camera Terminal and the Brightness control for the Processing Unit will
+be flagged as available; if they are not supported you should set the field to
+0x00.
+
+Note that the size of the bmControls field for a Camera Terminal or Processing
+Unit is fixed by the UVC specification, and so the bControlSize attribute is
+read-only here.
+
Custom Strings Support
~~~~~~~~~~~~~~~~~~~~~~
diff --git a/arch/arm/boot/dts/imx7ulp.dtsi b/arch/arm/boot/dts/imx7ulp.dtsi
index 7f7d2d5122fb..f91bf719d4e2 100644
--- a/arch/arm/boot/dts/imx7ulp.dtsi
+++ b/arch/arm/boot/dts/imx7ulp.dtsi
@@ -189,7 +189,7 @@
};
usbotg1: usb@40330000 {
- compatible = "fsl,imx7ulp-usb", "fsl,imx6ul-usb";
+ compatible = "fsl,imx7ulp-usb", "fsl,imx6ul-usb", "fsl,imx27-usb";
reg = <0x40330000 0x200>;
interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&pcc2 IMX7ULP_CLK_USB0>;
@@ -202,7 +202,8 @@
};
usbmisc1: usbmisc@40330200 {
- compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc";
+ compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc",
+ "fsl,imx6q-usbmisc";
#index-cells = <1>;
reg = <0x40330200 0x200>;
};
diff --git a/arch/arm/boot/dts/stm32mp151.dtsi b/arch/arm/boot/dts/stm32mp151.dtsi
index 4e437d3f2ed6..63f4c78fcc1d 100644
--- a/arch/arm/boot/dts/stm32mp151.dtsi
+++ b/arch/arm/boot/dts/stm32mp151.dtsi
@@ -1130,8 +1130,8 @@
usbotg_hs: usb-otg@49000000 {
compatible = "st,stm32mp15-hsotg", "snps,dwc2";
reg = <0x49000000 0x10000>;
- clocks = <&rcc USBO_K>;
- clock-names = "otg";
+ clocks = <&rcc USBO_K>, <&usbphyc>;
+ clock-names = "otg", "utmi";
resets = <&rcc USBO_R>;
reset-names = "dwc2";
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi
index b32c2e199c16..2209c1ac6e9b 100644
--- a/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi
@@ -35,7 +35,7 @@ conn_subsys: bus@5b000000 {
};
usbotg1: usb@5b0d0000 {
- compatible = "fsl,imx7ulp-usb";
+ compatible = "fsl,imx7ulp-usb", "fsl,imx6ul-usb", "fsl,imx27-usb";
reg = <0x5b0d0000 0x200>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
@@ -51,7 +51,7 @@ conn_subsys: bus@5b000000 {
usbmisc1: usbmisc@5b0d0200 {
#index-cells = <1>;
- compatible = "fsl,imx7ulp-usbmisc", "fsl,imx6q-usbmisc";
+ compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc", "fsl,imx6q-usbmisc";
reg = <0x5b0d0200 0x200>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi
index ca195e6d8f37..652493ae4bb5 100644
--- a/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi
@@ -34,7 +34,7 @@
};
usbotg2: usb@5b0e0000 {
- compatible = "fsl,imx8dxl-usb", "fsl,imx7ulp-usb";
+ compatible = "fsl,imx8dxl-usb", "fsl,imx7ulp-usb", "fsl,imx6ul-usb";
reg = <0x5b0e0000 0x200>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>;
@@ -49,7 +49,6 @@
ahb-burst-config = <0x0>;
tx-burst-size-dword = <0x10>;
rx-burst-size-dword = <0x10>;
- #stream-id-cells = <1>;
power-domains = <&pd IMX_SC_R_USB_1>;
status = "disabled";
@@ -63,7 +62,7 @@
usbmisc2: usbmisc@5b0e0200 {
#index-cells = <1>;
- compatible = "fsl,imx7ulp-usbmisc";
+ compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc", "fsl,imx6q-usbmisc";
reg = <0x5b0e0200 0x200>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
index ba06b5273b91..d6b36f04f3dc 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
@@ -1253,7 +1253,7 @@
};
usbotg1: usb@32e40000 {
- compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb";
+ compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb", "fsl,imx27-usb";
reg = <0x32e40000 0x200>;
interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MM_CLK_USB1_CTRL_ROOT>;
@@ -1267,13 +1267,14 @@
};
usbmisc1: usbmisc@32e40200 {
- compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc";
+ compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc",
+ "fsl,imx6q-usbmisc";
#index-cells = <1>;
reg = <0x32e40200 0x200>;
};
usbotg2: usb@32e50000 {
- compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb";
+ compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb", "fsl,imx27-usb";
reg = <0x32e50000 0x200>;
interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MM_CLK_USB1_CTRL_ROOT>;
@@ -1287,7 +1288,8 @@
};
usbmisc2: usbmisc@32e50200 {
- compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc";
+ compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc",
+ "fsl,imx6q-usbmisc";
#index-cells = <1>;
reg = <0x32e50200 0x200>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn.dtsi b/arch/arm64/boot/dts/freescale/imx8mn.dtsi
index c94ab45ee96c..bd84db550053 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mn.dtsi
@@ -1146,7 +1146,7 @@
};
usbotg1: usb@32e40000 {
- compatible = "fsl,imx8mn-usb", "fsl,imx7d-usb";
+ compatible = "fsl,imx8mn-usb", "fsl,imx7d-usb", "fsl,imx27-usb";
reg = <0x32e40000 0x200>;
interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MN_CLK_USB1_CTRL_ROOT>;
@@ -1160,7 +1160,8 @@
};
usbmisc1: usbmisc@32e40200 {
- compatible = "fsl,imx8mn-usbmisc", "fsl,imx7d-usbmisc";
+ compatible = "fsl,imx8mn-usbmisc", "fsl,imx7d-usbmisc",
+ "fsl,imx6q-usbmisc";
#index-cells = <1>;
reg = <0x32e40200 0x200>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
index cd925c0ac911..0492556a10db 100644
--- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
@@ -1453,7 +1453,6 @@
phys = <&usb3_phy0>, <&usb3_phy0>;
phy-names = "usb2-phy", "usb3-phy";
power-domains = <&pgc_otg1>;
- usb3-resume-missing-cas;
status = "disabled";
};
@@ -1485,7 +1484,6 @@
phys = <&usb3_phy1>, <&usb3_phy1>;
phy-names = "usb2-phy", "usb3-phy";
power-domains = <&pgc_otg2>;
- usb3-resume-missing-cas;
status = "disabled";
};
diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig
index e1b66aac7025..a5c68e9b0482 100644
--- a/arch/mips/configs/mtx1_defconfig
+++ b/arch/mips/configs/mtx1_defconfig
@@ -497,7 +497,6 @@ CONFIG_USB_EHCI_ROOT_HUB_TT=y
CONFIG_USB_OHCI_HCD=m
CONFIG_USB_OHCI_HCD_PLATFORM=m
CONFIG_USB_UHCI_HCD=m
-CONFIG_USB_U132_HCD=m
CONFIG_USB_SL811_HCD=m
CONFIG_USB_SL811_CS=m
CONFIG_USB_ACM=m
@@ -554,7 +553,6 @@ CONFIG_USB_LCD=m
CONFIG_USB_CYPRESS_CY7C63=m
CONFIG_USB_CYTHERM=m
CONFIG_USB_IDMOUSE=m
-CONFIG_USB_FTDI_ELAN=m
CONFIG_USB_APPLEDISPLAY=m
CONFIG_USB_SISUSBVGA=m
CONFIG_USB_LD=m
diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig
index 5927b2312936..adc314049fdd 100644
--- a/arch/powerpc/configs/ppc6xx_defconfig
+++ b/arch/powerpc/configs/ppc6xx_defconfig
@@ -845,7 +845,6 @@ CONFIG_USB_OHCI_HCD=m
CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
CONFIG_USB_OHCI_HCD_PPC_OF_LE=y
CONFIG_USB_UHCI_HCD=m
-CONFIG_USB_U132_HCD=m
CONFIG_USB_SL811_HCD=m
CONFIG_USB_ACM=m
CONFIG_USB_PRINTER=m
@@ -908,7 +907,6 @@ CONFIG_USB_SEVSEG=m
CONFIG_USB_LEGOTOWER=m
CONFIG_USB_LCD=m
CONFIG_USB_IDMOUSE=m
-CONFIG_USB_FTDI_ELAN=m
CONFIG_USB_APPLEDISPLAY=m
CONFIG_USB_SISUSBVGA=m
CONFIG_USB_LD=m
diff --git a/drivers/media/radio/radio-shark.c b/drivers/media/radio/radio-shark.c
index 8230da828d0e..127a3be0e0f0 100644
--- a/drivers/media/radio/radio-shark.c
+++ b/drivers/media/radio/radio-shark.c
@@ -316,6 +316,16 @@ static int usb_shark_probe(struct usb_interface *intf,
{
struct shark_device *shark;
int retval = -ENOMEM;
+ static const u8 ep_addresses[] = {
+ SHARK_IN_EP | USB_DIR_IN,
+ SHARK_OUT_EP | USB_DIR_OUT,
+ 0};
+
+ /* Are the expected endpoints present? */
+ if (!usb_check_int_endpoints(intf, ep_addresses)) {
+ dev_err(&intf->dev, "Invalid radioSHARK device\n");
+ return -EINVAL;
+ }
shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL);
if (!shark)
diff --git a/drivers/media/radio/radio-shark2.c b/drivers/media/radio/radio-shark2.c
index d150f12382c6..f1c5c0a6a335 100644
--- a/drivers/media/radio/radio-shark2.c
+++ b/drivers/media/radio/radio-shark2.c
@@ -282,6 +282,16 @@ static int usb_shark_probe(struct usb_interface *intf,
{
struct shark_device *shark;
int retval = -ENOMEM;
+ static const u8 ep_addresses[] = {
+ SHARK_IN_EP | USB_DIR_IN,
+ SHARK_OUT_EP | USB_DIR_OUT,
+ 0};
+
+ /* Are the expected endpoints present? */
+ if (!usb_check_int_endpoints(intf, ep_addresses)) {
+ dev_err(&intf->dev, "Invalid radioSHARK2 device\n");
+ return -EINVAL;
+ }
shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL);
if (!shark)
diff --git a/drivers/thunderbolt/acpi.c b/drivers/thunderbolt/acpi.c
index 628225deb8fe..3514bf65b7a4 100644
--- a/drivers/thunderbolt/acpi.c
+++ b/drivers/thunderbolt/acpi.c
@@ -341,7 +341,7 @@ static struct acpi_device *tb_acpi_find_companion(struct device *dev)
*/
if (tb_is_switch(dev))
return tb_acpi_switch_find_companion(tb_to_switch(dev));
- else if (tb_is_usb4_port_device(dev))
+ if (tb_is_usb4_port_device(dev))
return acpi_find_child_by_adr(ACPI_COMPANION(dev->parent),
tb_to_usb4_port_device(dev)->port->port);
return NULL;
diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c
index 6e7d28e8d81a..3a213322ec7a 100644
--- a/drivers/thunderbolt/ctl.c
+++ b/drivers/thunderbolt/ctl.c
@@ -1033,7 +1033,7 @@ static int tb_cfg_get_error(struct tb_ctl *ctl, enum tb_cfg_space space,
if (res->tb_error == TB_CFG_ERROR_LOCK)
return -EACCES;
- else if (res->tb_error == TB_CFG_ERROR_PORT_NOT_CONNECTED)
+ if (res->tb_error == TB_CFG_ERROR_PORT_NOT_CONNECTED)
return -ENOTCONN;
return -EIO;
diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c
index c90d22f56d4e..0f6099c18a94 100644
--- a/drivers/thunderbolt/eeprom.c
+++ b/drivers/thunderbolt/eeprom.c
@@ -416,7 +416,7 @@ static int tb_drom_parse_entries(struct tb_switch *sw, size_t header_size)
if (pos + 1 == drom_size || pos + entry->len > drom_size
|| !entry->len) {
tb_sw_warn(sw, "DROM buffer overrun\n");
- return -EILSEQ;
+ return -EIO;
}
switch (entry->type) {
@@ -471,14 +471,13 @@ err:
static int tb_drom_copy_nvm(struct tb_switch *sw, u16 *size)
{
- u32 drom_offset;
+ u16 drom_offset;
int ret;
if (!sw->dma_port)
return -ENODEV;
- ret = tb_sw_read(sw, &drom_offset, TB_CFG_SWITCH,
- sw->cap_plug_events + 12, 1);
+ ret = tb_eeprom_get_drom_offset(sw, &drom_offset);
if (ret)
return ret;
@@ -513,7 +512,7 @@ err_free:
return ret;
}
-static int usb4_copy_host_drom(struct tb_switch *sw, u16 *size)
+static int usb4_copy_drom(struct tb_switch *sw, u16 *size)
{
int ret;
@@ -536,15 +535,40 @@ static int usb4_copy_host_drom(struct tb_switch *sw, u16 *size)
return ret;
}
-static int tb_drom_read_n(struct tb_switch *sw, u16 offset, u8 *val,
- size_t count)
+static int tb_drom_bit_bang(struct tb_switch *sw, u16 *size)
{
- if (tb_switch_is_usb4(sw))
- return usb4_switch_drom_read(sw, offset, val, count);
- return tb_eeprom_read_n(sw, offset, val, count);
+ int ret;
+
+ ret = tb_eeprom_read_n(sw, 14, (u8 *)size, 2);
+ if (ret)
+ return ret;
+
+ *size &= 0x3ff;
+ *size += TB_DROM_DATA_START;
+
+ tb_sw_dbg(sw, "reading DROM (length: %#x)\n", *size);
+ if (*size < sizeof(struct tb_drom_header)) {
+ tb_sw_warn(sw, "DROM too small, aborting\n");
+ return -EIO;
+ }
+
+ sw->drom = kzalloc(*size, GFP_KERNEL);
+ if (!sw->drom)
+ return -ENOMEM;
+
+ ret = tb_eeprom_read_n(sw, 0, sw->drom, *size);
+ if (ret)
+ goto err;
+
+ return 0;
+
+err:
+ kfree(sw->drom);
+ sw->drom = NULL;
+ return ret;
}
-static int tb_drom_parse(struct tb_switch *sw)
+static int tb_drom_parse_v1(struct tb_switch *sw)
{
const struct tb_drom_header *header =
(const struct tb_drom_header *)sw->drom;
@@ -555,7 +579,7 @@ static int tb_drom_parse(struct tb_switch *sw)
tb_sw_warn(sw,
"DROM UID CRC8 mismatch (expected: %#x, got: %#x)\n",
header->uid_crc8, crc);
- return -EILSEQ;
+ return -EIO;
}
if (!sw->uid)
sw->uid = header->uid;
@@ -589,85 +613,14 @@ static int usb4_drom_parse(struct tb_switch *sw)
return tb_drom_parse_entries(sw, USB4_DROM_HEADER_SIZE);
}
-/**
- * tb_drom_read() - Copy DROM to sw->drom and parse it
- * @sw: Router whose DROM to read and parse
- *
- * This function reads router DROM and if successful parses the entries and
- * populates the fields in @sw accordingly. Can be called for any router
- * generation.
- *
- * Returns %0 in case of success and negative errno otherwise.
- */
-int tb_drom_read(struct tb_switch *sw)
+static int tb_drom_parse(struct tb_switch *sw, u16 size)
{
- u16 size;
- struct tb_drom_header *header;
- int res, retries = 1;
-
- if (sw->drom)
- return 0;
-
- if (tb_route(sw) == 0) {
- /*
- * Apple's NHI EFI driver supplies a DROM for the root switch
- * in a device property. Use it if available.
- */
- if (tb_drom_copy_efi(sw, &size) == 0)
- goto parse;
-
- /* Non-Apple hardware has the DROM as part of NVM */
- if (tb_drom_copy_nvm(sw, &size) == 0)
- goto parse;
-
- /*
- * USB4 hosts may support reading DROM through router
- * operations.
- */
- if (tb_switch_is_usb4(sw)) {
- usb4_switch_read_uid(sw, &sw->uid);
- if (!usb4_copy_host_drom(sw, &size))
- goto parse;
- } else {
- /*
- * The root switch contains only a dummy drom
- * (header only, no entries). Hardcode the
- * configuration here.
- */
- tb_drom_read_uid_only(sw, &sw->uid);
- }
-
- return 0;
- }
-
- res = tb_drom_read_n(sw, 14, (u8 *) &size, 2);
- if (res)
- return res;
- size &= 0x3ff;
- size += TB_DROM_DATA_START;
- tb_sw_dbg(sw, "reading drom (length: %#x)\n", size);
- if (size < sizeof(*header)) {
- tb_sw_warn(sw, "drom too small, aborting\n");
- return -EIO;
- }
-
- sw->drom = kzalloc(size, GFP_KERNEL);
- if (!sw->drom)
- return -ENOMEM;
-read:
- res = tb_drom_read_n(sw, 0, sw->drom, size);
- if (res)
- goto err;
-
-parse:
- header = (void *) sw->drom;
+ const struct tb_drom_header *header = (const void *)sw->drom;
+ int ret;
if (header->data_len + TB_DROM_DATA_START != size) {
- tb_sw_warn(sw, "drom size mismatch\n");
- if (retries--) {
- msleep(100);
- goto read;
- }
+ tb_sw_warn(sw, "DROM size mismatch\n");
+ ret = -EIO;
goto err;
}
@@ -675,29 +628,86 @@ parse:
switch (header->device_rom_revision) {
case 3:
- res = usb4_drom_parse(sw);
+ ret = usb4_drom_parse(sw);
break;
default:
tb_sw_warn(sw, "DROM device_rom_revision %#x unknown\n",
header->device_rom_revision);
fallthrough;
case 1:
- res = tb_drom_parse(sw);
+ ret = tb_drom_parse_v1(sw);
break;
}
- /* If the DROM parsing fails, wait a moment and retry once */
- if (res == -EILSEQ && retries--) {
+ if (ret) {
tb_sw_warn(sw, "parsing DROM failed\n");
- msleep(100);
- goto read;
+ goto err;
}
- if (!res)
- return 0;
+ return 0;
err:
kfree(sw->drom);
sw->drom = NULL;
- return -EIO;
+
+ return ret;
+}
+
+static int tb_drom_host_read(struct tb_switch *sw)
+{
+ u16 size;
+
+ if (tb_switch_is_usb4(sw)) {
+ usb4_switch_read_uid(sw, &sw->uid);
+ if (!usb4_copy_drom(sw, &size))
+ return tb_drom_parse(sw, size);
+ } else {
+ if (!tb_drom_copy_efi(sw, &size))
+ return tb_drom_parse(sw, size);
+
+ if (!tb_drom_copy_nvm(sw, &size))
+ return tb_drom_parse(sw, size);
+
+ tb_drom_read_uid_only(sw, &sw->uid);
+ }
+
+ return 0;
+}
+
+static int tb_drom_device_read(struct tb_switch *sw)
+{
+ u16 size;
+ int ret;
+
+ if (tb_switch_is_usb4(sw)) {
+ usb4_switch_read_uid(sw, &sw->uid);
+ ret = usb4_copy_drom(sw, &size);
+ } else {
+ ret = tb_drom_bit_bang(sw, &size);
+ }
+
+ if (ret)
+ return ret;
+
+ return tb_drom_parse(sw, size);
+}
+
+/**
+ * tb_drom_read() - Copy DROM to sw->drom and parse it
+ * @sw: Router whose DROM to read and parse
+ *
+ * This function reads router DROM and if successful parses the entries and
+ * populates the fields in @sw accordingly. Can be called for any router
+ * generation.
+ *
+ * Returns %0 in case of success and negative errno otherwise.
+ */
+int tb_drom_read(struct tb_switch *sw)
+{
+ if (sw->drom)
+ return 0;
+
+ if (!tb_route(sw))
+ return tb_drom_host_read(sw);
+ return tb_drom_device_read(sw);
}
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
index cfebec107f3f..d76e923fbc6a 100644
--- a/drivers/thunderbolt/nhi.c
+++ b/drivers/thunderbolt/nhi.c
@@ -526,7 +526,8 @@ static int nhi_alloc_hop(struct tb_nhi *nhi, struct tb_ring *ring)
ring->hop);
ret = -EBUSY;
goto err_unlock;
- } else if (!ring->is_tx && nhi->rx_rings[ring->hop]) {
+ }
+ if (!ring->is_tx && nhi->rx_rings[ring->hop]) {
dev_warn(&nhi->pdev->dev, "RX hop %d already allocated\n",
ring->hop);
ret = -EBUSY;
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index da373ac38285..51e86b5171c7 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -271,9 +271,9 @@ static int nvm_authenticate(struct tb_switch *sw, bool auth_only)
}
sw->nvm->authenticating = true;
return usb4_switch_nvm_authenticate(sw);
- } else if (auth_only) {
- return -EOPNOTSUPP;
}
+ if (auth_only)
+ return -EOPNOTSUPP;
sw->nvm->authenticating = true;
if (!tb_route(sw)) {
diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c
index a0996cb2893c..485b6e430686 100644
--- a/drivers/thunderbolt/usb4.c
+++ b/drivers/thunderbolt/usb4.c
@@ -9,6 +9,7 @@
#include <linux/delay.h>
#include <linux/ktime.h>
+#include <linux/units.h>
#include "sb_regs.h"
#include "tb.h"
@@ -851,7 +852,7 @@ bool usb4_switch_query_dp_resource(struct tb_switch *sw, struct tb_port *in)
*/
if (ret == -EOPNOTSUPP)
return true;
- else if (ret)
+ if (ret)
return false;
return !status;
@@ -877,7 +878,7 @@ int usb4_switch_alloc_dp_resource(struct tb_switch *sw, struct tb_port *in)
&status);
if (ret == -EOPNOTSUPP)
return 0;
- else if (ret)
+ if (ret)
return ret;
return status ? -EBUSY : 0;
@@ -900,7 +901,7 @@ int usb4_switch_dealloc_dp_resource(struct tb_switch *sw, struct tb_port *in)
&status);
if (ret == -EOPNOTSUPP)
return 0;
- else if (ret)
+ if (ret)
return ret;
return status ? -EIO : 0;
@@ -1302,6 +1303,20 @@ static int usb4_port_sb_write(struct tb_port *port, enum usb4_sb_target target,
return 0;
}
+static int usb4_port_sb_opcode_err_to_errno(u32 val)
+{
+ switch (val) {
+ case 0:
+ return 0;
+ case USB4_SB_OPCODE_ERR:
+ return -EAGAIN;
+ case USB4_SB_OPCODE_ONS:
+ return -EOPNOTSUPP;
+ default:
+ return -EIO;
+ }
+}
+
static int usb4_port_sb_op(struct tb_port *port, enum usb4_sb_target target,
u8 index, enum usb4_sb_opcode opcode, int timeout_msec)
{
@@ -1324,21 +1339,8 @@ static int usb4_port_sb_op(struct tb_port *port, enum usb4_sb_target target,
if (ret)
return ret;
- switch (val) {
- case 0:
- return 0;
-
- case USB4_SB_OPCODE_ERR:
- return -EAGAIN;
-
- case USB4_SB_OPCODE_ONS:
- return -EOPNOTSUPP;
-
- default:
- if (val != opcode)
- return -EIO;
- break;
- }
+ if (val != opcode)
+ return usb4_port_sb_opcode_err_to_errno(val);
} while (ktime_before(ktime_get(), timeout));
return -ETIMEDOUT;
@@ -1813,12 +1815,13 @@ int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index,
if (ret)
return ret;
- switch (val) {
+ ret = usb4_port_sb_opcode_err_to_errno(val);
+ switch (ret) {
case 0:
*status = 0;
return 0;
- case USB4_SB_OPCODE_ERR:
+ case -EAGAIN:
ret = usb4_port_retimer_read(port, index, USB4_SB_METADATA,
&metadata, sizeof(metadata));
if (ret)
@@ -1827,11 +1830,8 @@ int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index,
*status = metadata & USB4_SB_METADATA_NVM_AUTH_WRITE_MASK;
return 0;
- case USB4_SB_OPCODE_ONS:
- return -EOPNOTSUPP;
-
default:
- return -EIO;
+ return ret;
}
}
@@ -1995,7 +1995,7 @@ static unsigned int usb3_bw_to_mbps(u32 bw, u8 scale)
unsigned long uframes;
uframes = bw * 512UL << scale;
- return DIV_ROUND_CLOSEST(uframes * 8000, 1000 * 1000);
+ return DIV_ROUND_CLOSEST(uframes * 8000, MEGA);
}
static u32 mbps_to_usb3_bw(unsigned int mbps, u8 scale)
@@ -2003,7 +2003,7 @@ static u32 mbps_to_usb3_bw(unsigned int mbps, u8 scale)
unsigned long uframes;
/* 1 uframe is 1/8 ms (125 us) -> 1 / 8000 s */
- uframes = ((unsigned long)mbps * 1000 * 1000) / 8000;
+ uframes = ((unsigned long)mbps * MEGA) / 8000;
return DIV_ROUND_UP(uframes, 512UL << scale);
}
diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c
index a48335c95d39..e2b54887d331 100644
--- a/drivers/thunderbolt/xdomain.c
+++ b/drivers/thunderbolt/xdomain.c
@@ -1178,9 +1178,8 @@ static int tb_xdomain_get_uuid(struct tb_xdomain *xd)
if (xd->state_retries-- > 0) {
dev_dbg(&xd->dev, "failed to request UUID, retrying\n");
return -EAGAIN;
- } else {
- dev_dbg(&xd->dev, "failed to read remote UUID\n");
}
+ dev_dbg(&xd->dev, "failed to read remote UUID\n");
return ret;
}
@@ -1367,12 +1366,10 @@ static int tb_xdomain_get_properties(struct tb_xdomain *xd)
dev_dbg(&xd->dev,
"failed to request remote properties, retrying\n");
return -EAGAIN;
- } else {
- /* Give up now */
- dev_err(&xd->dev,
- "failed read XDomain properties from %pUb\n",
- xd->remote_uuid);
}
+ /* Give up now */
+ dev_err(&xd->dev, "failed read XDomain properties from %pUb\n",
+ xd->remote_uuid);
return ret;
}
@@ -2179,13 +2176,12 @@ static struct tb_xdomain *switch_find_xdomain(struct tb_switch *sw,
if (xd->remote_uuid &&
uuid_equal(xd->remote_uuid, lookup->uuid))
return xd;
- } else if (lookup->link &&
- lookup->link == xd->link &&
- lookup->depth == xd->depth) {
- return xd;
- } else if (lookup->route &&
- lookup->route == xd->route) {
- return xd;
+ } else {
+ if (lookup->link && lookup->link == xd->link &&
+ lookup->depth == xd->depth)
+ return xd;
+ if (lookup->route && lookup->route == xd->route)
+ return xd;
}
} else if (tb_port_has_remote(port)) {
xd = switch_find_xdomain(port->remote->sw, lookup);
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index a871a988829d..7f33bcc315f2 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -133,35 +133,6 @@ comment "USB port drivers"
if USB
-config USB_USS720
- tristate "USS720 parport driver"
- depends on PARPORT
- select PARPORT_NOT_PC
- help
- This driver is for USB parallel port adapters that use the Lucent
- Technologies USS-720 chip. These cables are plugged into your USB
- port and provide USB compatibility to peripherals designed with
- parallel port interfaces.
-
- The chip has two modes: automatic mode and manual mode. In automatic
- mode, it looks to the computer like a standard USB printer. Only
- printers may be connected to the USS-720 in this mode. The generic
- USB printer driver ("USB Printer support", above) may be used in
- that mode, and you can say N here if you want to use the chip only
- in this mode.
-
- Manual mode is not limited to printers, any parallel port
- device should work. This driver utilizes manual mode.
- Note however that some operations are three orders of magnitude
- slower than on a PCI/ISA Parallel Port, so timing critical
- applications might not work.
-
- Say Y here if you own an USS-720 USB->Parport cable and intend to
- connect anything other than a printer to it.
-
- To compile this driver as a module, choose M here: the
- module will be called uss720.
-
source "drivers/usb/serial/Kconfig"
source "drivers/usb/misc/Kconfig"
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index a81e6ef293af..3a9a0dd4be70 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -31,7 +31,6 @@ obj-$(CONFIG_USB_FHCI_HCD) += host/
obj-$(CONFIG_USB_XHCI_HCD) += host/
obj-$(CONFIG_USB_SL811_HCD) += host/
obj-$(CONFIG_USB_ISP1362_HCD) += host/
-obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_USB_R8A66597_HCD) += host/
obj-$(CONFIG_USB_FSL_USB2) += host/
obj-$(CONFIG_USB_FOTG210_HCD) += host/
diff --git a/drivers/usb/cdns3/cdns3-debug.h b/drivers/usb/cdns3/cdns3-debug.h
index a5c6a29e1340..4618cfe85a4f 100644
--- a/drivers/usb/cdns3/cdns3-debug.h
+++ b/drivers/usb/cdns3/cdns3-debug.h
@@ -107,8 +107,7 @@ static inline char *cdns3_decode_ep0_irq(char *str,
* Prints out all TRBs in the endpoint ring, even those after the Link TRB.
*.
*/
-static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep,
- struct cdns3_trb *ring, char *str)
+static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep, char *str)
{
dma_addr_t addr = priv_ep->trb_pool_dma;
struct cdns3_trb *trb;
@@ -136,9 +135,6 @@ static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep,
"\t\tfree trbs: %d, CCS=%d, PCS=%d\n",
priv_ep->free_trbs, priv_ep->ccs, priv_ep->pcs);
- if (trb_per_sector > TRBS_PER_SEGMENT)
- trb_per_sector = TRBS_PER_SEGMENT;
-
if (trb_per_sector > TRBS_PER_SEGMENT) {
sprintf(str + ret, "\t\tTransfer ring %d too big\n",
trb_per_sector);
@@ -146,7 +142,7 @@ static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep,
}
for (i = 0; i < trb_per_sector; ++i) {
- trb = &ring[i];
+ trb = &priv_ep->trb_pool[i];
ret += sprintf(str + ret,
"\t\t@%pad %08x %08x %08x\n", &addr,
le32_to_cpu(trb->buffer),
diff --git a/drivers/usb/cdns3/cdns3-trace.h b/drivers/usb/cdns3/cdns3-trace.h
index 7574b4a62813..40db89e3333c 100644
--- a/drivers/usb/cdns3/cdns3-trace.h
+++ b/drivers/usb/cdns3/cdns3-trace.h
@@ -100,13 +100,12 @@ DECLARE_EVENT_CLASS(cdns3_log_usb_irq,
TP_STRUCT__entry(
__field(enum usb_device_speed, speed)
__field(u32, usb_ists)
- __dynamic_array(char, str, CDNS3_MSG_MAX)
),
TP_fast_assign(
__entry->speed = cdns3_get_speed(priv_dev);
__entry->usb_ists = usb_ists;
),
- TP_printk("%s", cdns3_decode_usb_irq(__get_str(str), __entry->speed,
+ TP_printk("%s", cdns3_decode_usb_irq(__get_buf(CDNS3_MSG_MAX), __entry->speed,
__entry->usb_ists))
);
@@ -124,7 +123,6 @@ DECLARE_EVENT_CLASS(cdns3_log_epx_irq,
__field(u32, ep_traddr)
__field(u32, ep_last_sid)
__field(u32, use_streams)
- __dynamic_array(char, str, CDNS3_MSG_MAX)
),
TP_fast_assign(
__assign_str(ep_name, priv_ep->name);
@@ -134,7 +132,7 @@ DECLARE_EVENT_CLASS(cdns3_log_epx_irq,
__entry->use_streams = priv_ep->use_streams;
),
TP_printk("%s, ep_traddr: %08x ep_last_sid: %08x use_streams: %d",
- cdns3_decode_epx_irq(__get_str(str),
+ cdns3_decode_epx_irq(__get_buf(CDNS3_MSG_MAX),
__get_str(ep_name),
__entry->ep_sts),
__entry->ep_traddr,
@@ -153,13 +151,12 @@ DECLARE_EVENT_CLASS(cdns3_log_ep0_irq,
TP_STRUCT__entry(
__field(int, ep_dir)
__field(u32, ep_sts)
- __dynamic_array(char, str, CDNS3_MSG_MAX)
),
TP_fast_assign(
__entry->ep_dir = priv_dev->selected_ep;
__entry->ep_sts = ep_sts;
),
- TP_printk("%s", cdns3_decode_ep0_irq(__get_str(str),
+ TP_printk("%s", cdns3_decode_ep0_irq(__get_buf(CDNS3_MSG_MAX),
__entry->ep_dir,
__entry->ep_sts))
);
@@ -178,7 +175,6 @@ DECLARE_EVENT_CLASS(cdns3_log_ctrl,
__field(u16, wValue)
__field(u16, wIndex)
__field(u16, wLength)
- __dynamic_array(char, str, CDNS3_MSG_MAX)
),
TP_fast_assign(
__entry->bRequestType = ctrl->bRequestType;
@@ -187,7 +183,7 @@ DECLARE_EVENT_CLASS(cdns3_log_ctrl,
__entry->wIndex = le16_to_cpu(ctrl->wIndex);
__entry->wLength = le16_to_cpu(ctrl->wLength);
),
- TP_printk("%s", usb_decode_ctrl(__get_str(str), CDNS3_MSG_MAX,
+ TP_printk("%s", usb_decode_ctrl(__get_buf(CDNS3_MSG_MAX), CDNS3_MSG_MAX,
__entry->bRequestType,
__entry->bRequest, __entry->wValue,
__entry->wIndex, __entry->wLength)
@@ -438,22 +434,16 @@ DECLARE_EVENT_CLASS(cdns3_log_ring,
TP_PROTO(struct cdns3_endpoint *priv_ep),
TP_ARGS(priv_ep),
TP_STRUCT__entry(
- __dynamic_array(u8, ring, TRB_RING_SIZE)
- __dynamic_array(u8, priv_ep, sizeof(struct cdns3_endpoint))
__dynamic_array(char, buffer,
- (TRBS_PER_SEGMENT * 65) + CDNS3_MSG_MAX)
+ GET_TRBS_PER_SEGMENT(priv_ep->type) > TRBS_PER_SEGMENT ?
+ CDNS3_MSG_MAX :
+ (GET_TRBS_PER_SEGMENT(priv_ep->type) * 65) + CDNS3_MSG_MAX)
),
TP_fast_assign(
- memcpy(__get_dynamic_array(priv_ep), priv_ep,
- sizeof(struct cdns3_endpoint));
- memcpy(__get_dynamic_array(ring), priv_ep->trb_pool,
- TRB_RING_SIZE);
+ cdns3_dbg_ring(priv_ep, __get_str(buffer));
),
- TP_printk("%s",
- cdns3_dbg_ring((struct cdns3_endpoint *)__get_str(priv_ep),
- (struct cdns3_trb *)__get_str(ring),
- __get_str(buffer)))
+ TP_printk("%s", __get_str(buffer))
);
DEFINE_EVENT(cdns3_log_ring, cdns3_ring,
diff --git a/drivers/usb/cdns3/cdnsp-trace.h b/drivers/usb/cdns3/cdnsp-trace.h
index 5983dfb99653..4b51011eb00b 100644
--- a/drivers/usb/cdns3/cdnsp-trace.h
+++ b/drivers/usb/cdns3/cdnsp-trace.h
@@ -271,7 +271,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_ctrl,
__field(u16, wValue)
__field(u16, wIndex)
__field(u16, wLength)
- __dynamic_array(char, str, CDNSP_MSG_MAX)
),
TP_fast_assign(
__entry->bRequestType = ctrl->bRequestType;
@@ -280,7 +279,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_ctrl,
__entry->wIndex = le16_to_cpu(ctrl->wIndex);
__entry->wLength = le16_to_cpu(ctrl->wLength);
),
- TP_printk("%s", usb_decode_ctrl(__get_str(str), CDNSP_MSG_MAX,
+ TP_printk("%s", usb_decode_ctrl(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX,
__entry->bRequestType,
__entry->bRequest, __entry->wValue,
__entry->wIndex, __entry->wLength)
@@ -345,7 +344,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_trb,
__field(u32, field3)
__field(union cdnsp_trb *, trb)
__field(dma_addr_t, trb_dma)
- __dynamic_array(char, str, CDNSP_MSG_MAX)
),
TP_fast_assign(
__entry->type = ring->type;
@@ -359,7 +357,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_trb,
),
TP_printk("%s: %s trb: %p(%pad)", cdnsp_ring_type_string(__entry->type),
- cdnsp_decode_trb(__get_str(str), CDNSP_MSG_MAX,
+ cdnsp_decode_trb(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX,
__entry->field0, __entry->field1,
__entry->field2, __entry->field3),
__entry->trb, &__entry->trb_dma
@@ -544,7 +542,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_ep_ctx,
__field(u32, info2)
__field(u64, deq)
__field(u32, tx_info)
- __dynamic_array(char, str, CDNSP_MSG_MAX)
),
TP_fast_assign(
__entry->info = le32_to_cpu(ctx->ep_info);
@@ -552,7 +549,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_ep_ctx,
__entry->deq = le64_to_cpu(ctx->deq);
__entry->tx_info = le32_to_cpu(ctx->tx_info);
),
- TP_printk("%s", cdnsp_decode_ep_context(__get_str(str), CDNSP_MSG_MAX,
+ TP_printk("%s", cdnsp_decode_ep_context(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX,
__entry->info, __entry->info2,
__entry->deq, __entry->tx_info)
)
@@ -777,7 +774,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_portsc,
TP_STRUCT__entry(
__field(u32, portnum)
__field(u32, portsc)
- __dynamic_array(char, str, CDNSP_MSG_MAX)
),
TP_fast_assign(
__entry->portnum = portnum;
@@ -785,7 +781,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_portsc,
),
TP_printk("port-%d: %s",
__entry->portnum,
- cdnsp_decode_portsc(__get_str(str), CDNSP_MSG_MAX,
+ cdnsp_decode_portsc(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX,
__entry->portsc)
)
);
diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile
index 6f4a3deced35..71afeab97e83 100644
--- a/drivers/usb/chipidea/Makefile
+++ b/drivers/usb/chipidea/Makefile
@@ -14,5 +14,5 @@ ci_hdrc-$(CONFIG_USB_OTG_FSM) += otg_fsm.o
obj-$(CONFIG_USB_CHIPIDEA_GENERIC) += ci_hdrc_usb2.o
obj-$(CONFIG_USB_CHIPIDEA_MSM) += ci_hdrc_msm.o
obj-$(CONFIG_USB_CHIPIDEA_PCI) += ci_hdrc_pci.o
-obj-$(CONFIG_USB_CHIPIDEA_IMX) += ci_hdrc_imx.o usbmisc_imx.o
+obj-$(CONFIG_USB_CHIPIDEA_IMX) += usbmisc_imx.o ci_hdrc_imx.o
obj-$(CONFIG_USB_CHIPIDEA_TEGRA) += ci_hdrc_tegra.o
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index 2eeccf4ec9d6..2855ac303001 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -152,12 +152,12 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
* Check the various over current related properties. If over current
* detection is disabled we're not interested in the polarity.
*/
- if (of_find_property(np, "disable-over-current", NULL)) {
+ if (of_property_read_bool(np, "disable-over-current")) {
data->disable_oc = 1;
- } else if (of_find_property(np, "over-current-active-high", NULL)) {
+ } else if (of_property_read_bool(np, "over-current-active-high")) {
data->oc_pol_active_low = 0;
data->oc_pol_configured = 1;
- } else if (of_find_property(np, "over-current-active-low", NULL)) {
+ } else if (of_property_read_bool(np, "over-current-active-low")) {
data->oc_pol_active_low = 1;
data->oc_pol_configured = 1;
} else {
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 281fc51720ce..798cb077867a 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -753,7 +753,7 @@ static int ci_get_platdata(struct device *dev,
return ret;
}
- if (of_find_property(dev->of_node, "non-zero-ttctrl-ttha", NULL))
+ if (of_property_read_bool(dev->of_node, "non-zero-ttctrl-ttha"))
platdata->flags |= CI_HDRC_SET_NON_ZERO_TTHA;
ext_id = ERR_PTR(-ENODEV);
@@ -1108,7 +1108,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
ret = ci_usb_phy_init(ci);
if (ret) {
dev_err(dev, "unable to init phy: %d\n", ret);
- return ret;
+ goto ulpi_exit;
}
ci->hw_bank.phys = res->start;
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index bbc610e5bd69..e72c43615d77 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -247,60 +247,6 @@ static int ci_otg_show(struct seq_file *s, void *unused)
}
DEFINE_SHOW_ATTRIBUTE(ci_otg);
-static int ci_role_show(struct seq_file *s, void *data)
-{
- struct ci_hdrc *ci = s->private;
-
- if (ci->role != CI_ROLE_END)
- seq_printf(s, "%s\n", ci_role(ci)->name);
-
- return 0;
-}
-
-static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- struct seq_file *s = file->private_data;
- struct ci_hdrc *ci = s->private;
- enum ci_role role;
- char buf[8];
- int ret;
-
- if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
- return -EFAULT;
-
- for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
- if (ci->roles[role] &&
- !strncmp(buf, ci->roles[role]->name,
- strlen(ci->roles[role]->name)))
- break;
-
- if (role == CI_ROLE_END || role == ci->role)
- return -EINVAL;
-
- pm_runtime_get_sync(ci->dev);
- disable_irq(ci->irq);
- ci_role_stop(ci);
- ret = ci_role_start(ci, role);
- enable_irq(ci->irq);
- pm_runtime_put_sync(ci->dev);
-
- return ret ? ret : count;
-}
-
-static int ci_role_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ci_role_show, inode->i_private);
-}
-
-static const struct file_operations ci_role_fops = {
- .open = ci_role_open,
- .write = ci_role_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
static int ci_registers_show(struct seq_file *s, void *unused)
{
struct ci_hdrc *ci = s->private;
@@ -354,7 +300,6 @@ void dbg_create_files(struct ci_hdrc *ci)
if (ci_otg_is_fsm_mode(ci))
debugfs_create_file("otg", S_IRUGO, dir, ci, &ci_otg_fops);
- debugfs_create_file("role", S_IRUGO | S_IWUSR, dir, ci, &ci_role_fops);
debugfs_create_file("registers", S_IRUGO, dir, ci, &ci_registers_fops);
}
diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
index 533baa85083c..a34b22537d7c 100644
--- a/drivers/usb/core/usb-acpi.c
+++ b/drivers/usb/core/usb-acpi.c
@@ -81,15 +81,11 @@ int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index)
return -ENODEV;
}
- obj = acpi_evaluate_dsm(port_handle, &guid, 0,
- USB_DSM_DISABLE_U1_U2_FOR_PORT, NULL);
-
- if (!obj)
- return -ENODEV;
-
- if (obj->type != ACPI_TYPE_INTEGER) {
+ obj = acpi_evaluate_dsm_typed(port_handle, &guid, 0,
+ USB_DSM_DISABLE_U1_U2_FOR_PORT, NULL,
+ ACPI_TYPE_INTEGER);
+ if (!obj) {
dev_dbg(&hdev->dev, "evaluate port-%d _DSM failed\n", port1);
- ACPI_FREE(obj);
return -EINVAL;
}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 34742fbbd84d..901ec732321c 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -207,6 +207,82 @@ int usb_find_common_endpoints_reverse(struct usb_host_interface *alt,
EXPORT_SYMBOL_GPL(usb_find_common_endpoints_reverse);
/**
+ * usb_find_endpoint() - Given an endpoint address, search for the endpoint's
+ * usb_host_endpoint structure in an interface's current altsetting.
+ * @intf: the interface whose current altsetting should be searched
+ * @ep_addr: the endpoint address (number and direction) to find
+ *
+ * Search the altsetting's list of endpoints for one with the specified address.
+ *
+ * Return: Pointer to the usb_host_endpoint if found, %NULL otherwise.
+ */
+static const struct usb_host_endpoint *usb_find_endpoint(
+ const struct usb_interface *intf, unsigned int ep_addr)
+{
+ int n;
+ const struct usb_host_endpoint *ep;
+
+ n = intf->cur_altsetting->desc.bNumEndpoints;
+ ep = intf->cur_altsetting->endpoint;
+ for (; n > 0; (--n, ++ep)) {
+ if (ep->desc.bEndpointAddress == ep_addr)
+ return ep;
+ }
+ return NULL;
+}
+
+/**
+ * usb_check_bulk_endpoints - Check whether an interface's current altsetting
+ * contains a set of bulk endpoints with the given addresses.
+ * @intf: the interface whose current altsetting should be searched
+ * @ep_addrs: 0-terminated array of the endpoint addresses (number and
+ * direction) to look for
+ *
+ * Search for endpoints with the specified addresses and check their types.
+ *
+ * Return: %true if all the endpoints are found and are bulk, %false otherwise.
+ */
+bool usb_check_bulk_endpoints(
+ const struct usb_interface *intf, const u8 *ep_addrs)
+{
+ const struct usb_host_endpoint *ep;
+
+ for (; *ep_addrs; ++ep_addrs) {
+ ep = usb_find_endpoint(intf, *ep_addrs);
+ if (!ep || !usb_endpoint_xfer_bulk(&ep->desc))
+ return false;
+ }
+ return true;
+}
+EXPORT_SYMBOL_GPL(usb_check_bulk_endpoints);
+
+/**
+ * usb_check_int_endpoints - Check whether an interface's current altsetting
+ * contains a set of interrupt endpoints with the given addresses.
+ * @intf: the interface whose current altsetting should be searched
+ * @ep_addrs: 0-terminated array of the endpoint addresses (number and
+ * direction) to look for
+ *
+ * Search for endpoints with the specified addresses and check their types.
+ *
+ * Return: %true if all the endpoints are found and are interrupt,
+ * %false otherwise.
+ */
+bool usb_check_int_endpoints(
+ const struct usb_interface *intf, const u8 *ep_addrs)
+{
+ const struct usb_host_endpoint *ep;
+
+ for (; *ep_addrs; ++ep_addrs) {
+ ep = usb_find_endpoint(intf, *ep_addrs);
+ if (!ep || !usb_endpoint_xfer_int(&ep->desc))
+ return false;
+ }
+ return true;
+}
+EXPORT_SYMBOL_GPL(usb_check_int_endpoints);
+
+/**
* usb_find_alt_setting() - Given a configuration, find the alternate setting
* for the given interface.
* @config: the configuration to search (not necessarily the current config).
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 40cf2880d7e5..0bb4c0c845bf 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -1003,6 +1003,7 @@ struct dwc2_hregs_backup {
* @ctrl_out_desc: EP0 OUT data phase desc chain pointer
* @irq: Interrupt request line number
* @clk: Pointer to otg clock
+ * @utmi_clk: Pointer to utmi_clk clock
* @reset: Pointer to dwc2 reset controller
* @reset_ecc: Pointer to dwc2 optional reset controller in Stratix10.
* @regset: A pointer to a struct debugfs_regset32, which contains
@@ -1065,6 +1066,7 @@ struct dwc2_hsotg {
void *priv;
int irq;
struct clk *clk;
+ struct clk *utmi_clk;
struct reset_control *reset;
struct reset_control *reset_ecc;
diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c
index 0a1145592fc7..0d4495c6b9f7 100644
--- a/drivers/usb/dwc2/hcd_queue.c
+++ b/drivers/usb/dwc2/hcd_queue.c
@@ -1078,7 +1078,7 @@ static void dwc2_pick_first_frame(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
earliest_frame = dwc2_frame_num_inc(frame_number, 1);
next_active_frame = earliest_frame;
- /* Get the "no microframe schduler" out of the way... */
+ /* Get the "no microframe scheduler" out of the way... */
if (!hsotg->params.uframe_sched) {
if (qh->do_split)
/* Splits are active at microframe 0 minus 1 */
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
index 9ed9fd956940..21d16533bd2f 100644
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -508,8 +508,7 @@ static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg)
of_usb_update_otg_caps(hsotg->dev->of_node, &p->otg_caps);
}
- if (of_find_property(hsotg->dev->of_node, "disable-over-current", NULL))
- p->oc_disable = true;
+ p->oc_disable = of_property_read_bool(hsotg->dev->of_node, "disable-over-current");
}
static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg)
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index d1589ba7d322..5aee284018c0 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -101,10 +101,16 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
if (ret)
return ret;
+ if (hsotg->utmi_clk) {
+ ret = clk_prepare_enable(hsotg->utmi_clk);
+ if (ret)
+ goto err_dis_reg;
+ }
+
if (hsotg->clk) {
ret = clk_prepare_enable(hsotg->clk);
if (ret)
- return ret;
+ goto err_dis_utmi_clk;
}
if (hsotg->uphy) {
@@ -113,10 +119,29 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
ret = hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
} else {
ret = phy_init(hsotg->phy);
- if (ret == 0)
+ if (ret == 0) {
ret = phy_power_on(hsotg->phy);
+ if (ret)
+ phy_exit(hsotg->phy);
+ }
}
+ if (ret)
+ goto err_dis_clk;
+
+ return 0;
+
+err_dis_clk:
+ if (hsotg->clk)
+ clk_disable_unprepare(hsotg->clk);
+
+err_dis_utmi_clk:
+ if (hsotg->utmi_clk)
+ clk_disable_unprepare(hsotg->utmi_clk);
+
+err_dis_reg:
+ regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
+
return ret;
}
@@ -156,6 +181,9 @@ static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg)
if (hsotg->clk)
clk_disable_unprepare(hsotg->clk);
+ if (hsotg->utmi_clk)
+ clk_disable_unprepare(hsotg->utmi_clk);
+
return regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
}
@@ -232,6 +260,11 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
if (IS_ERR(hsotg->clk))
return dev_err_probe(hsotg->dev, PTR_ERR(hsotg->clk), "cannot get otg clock\n");
+ hsotg->utmi_clk = devm_clk_get_optional(hsotg->dev, "utmi");
+ if (IS_ERR(hsotg->utmi_clk))
+ return dev_err_probe(hsotg->dev, PTR_ERR(hsotg->utmi_clk),
+ "cannot get utmi clock\n");
+
/* Regulators */
for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++)
hsotg->supplies[i].supply = dwc2_hsotg_supply_names[i];
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 476b63618511..0beaab932e7d 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -534,90 +534,6 @@ void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
}
-static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
-{
- if (!dwc->has_hibernation)
- return 0;
-
- if (!dwc->nr_scratch)
- return 0;
-
- dwc->scratchbuf = kmalloc_array(dwc->nr_scratch,
- DWC3_SCRATCHBUF_SIZE, GFP_KERNEL);
- if (!dwc->scratchbuf)
- return -ENOMEM;
-
- return 0;
-}
-
-static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
-{
- dma_addr_t scratch_addr;
- u32 param;
- int ret;
-
- if (!dwc->has_hibernation)
- return 0;
-
- if (!dwc->nr_scratch)
- return 0;
-
- /* should never fall here */
- if (!WARN_ON(dwc->scratchbuf))
- return 0;
-
- scratch_addr = dma_map_single(dwc->sysdev, dwc->scratchbuf,
- dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
- DMA_BIDIRECTIONAL);
- if (dma_mapping_error(dwc->sysdev, scratch_addr)) {
- dev_err(dwc->sysdev, "failed to map scratch buffer\n");
- ret = -EFAULT;
- goto err0;
- }
-
- dwc->scratch_addr = scratch_addr;
-
- param = lower_32_bits(scratch_addr);
-
- ret = dwc3_send_gadget_generic_command(dwc,
- DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param);
- if (ret < 0)
- goto err1;
-
- param = upper_32_bits(scratch_addr);
-
- ret = dwc3_send_gadget_generic_command(dwc,
- DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param);
- if (ret < 0)
- goto err1;
-
- return 0;
-
-err1:
- dma_unmap_single(dwc->sysdev, dwc->scratch_addr, dwc->nr_scratch *
- DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
-
-err0:
- return ret;
-}
-
-static void dwc3_free_scratch_buffers(struct dwc3 *dwc)
-{
- if (!dwc->has_hibernation)
- return;
-
- if (!dwc->nr_scratch)
- return;
-
- /* should never fall here */
- if (!WARN_ON(dwc->scratchbuf))
- return;
-
- dma_unmap_single(dwc->sysdev, dwc->scratch_addr, dwc->nr_scratch *
- DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
- kfree(dwc->scratchbuf);
-}
-
static void dwc3_core_num_eps(struct dwc3 *dwc)
{
struct dwc3_hwparams *parms = &dwc->hwparams;
@@ -800,11 +716,91 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
if (dwc->dis_u2_freeclk_exists_quirk || dwc->gfladj_refclk_lpm_sel)
reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
+ /*
+ * Some ULPI USB PHY does not support internal VBUS supply, to drive
+ * the CPEN pin requires the configuration of the ULPI DRVVBUSEXTERNAL
+ * bit of OTG_CTRL register. Controller configures the USB2 PHY
+ * ULPIEXTVBUSDRV bit[17] of the GUSB2PHYCFG register to drive vBus
+ * with an external supply.
+ */
+ if (dwc->ulpi_ext_vbus_drv)
+ reg |= DWC3_GUSB2PHYCFG_ULPIEXTVBUSDRV;
+
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
return 0;
}
+static int dwc3_phy_init(struct dwc3 *dwc)
+{
+ int ret;
+
+ usb_phy_init(dwc->usb2_phy);
+ usb_phy_init(dwc->usb3_phy);
+
+ ret = phy_init(dwc->usb2_generic_phy);
+ if (ret < 0)
+ goto err_shutdown_usb3_phy;
+
+ ret = phy_init(dwc->usb3_generic_phy);
+ if (ret < 0)
+ goto err_exit_usb2_phy;
+
+ return 0;
+
+err_exit_usb2_phy:
+ phy_exit(dwc->usb2_generic_phy);
+err_shutdown_usb3_phy:
+ usb_phy_shutdown(dwc->usb3_phy);
+ usb_phy_shutdown(dwc->usb2_phy);
+
+ return ret;
+}
+
+static void dwc3_phy_exit(struct dwc3 *dwc)
+{
+ phy_exit(dwc->usb3_generic_phy);
+ phy_exit(dwc->usb2_generic_phy);
+
+ usb_phy_shutdown(dwc->usb3_phy);
+ usb_phy_shutdown(dwc->usb2_phy);
+}
+
+static int dwc3_phy_power_on(struct dwc3 *dwc)
+{
+ int ret;
+
+ usb_phy_set_suspend(dwc->usb2_phy, 0);
+ usb_phy_set_suspend(dwc->usb3_phy, 0);
+
+ ret = phy_power_on(dwc->usb2_generic_phy);
+ if (ret < 0)
+ goto err_suspend_usb3_phy;
+
+ ret = phy_power_on(dwc->usb3_generic_phy);
+ if (ret < 0)
+ goto err_power_off_usb2_phy;
+
+ return 0;
+
+err_power_off_usb2_phy:
+ phy_power_off(dwc->usb2_generic_phy);
+err_suspend_usb3_phy:
+ usb_phy_set_suspend(dwc->usb3_phy, 1);
+ usb_phy_set_suspend(dwc->usb2_phy, 1);
+
+ return ret;
+}
+
+static void dwc3_phy_power_off(struct dwc3 *dwc)
+{
+ phy_power_off(dwc->usb3_generic_phy);
+ phy_power_off(dwc->usb2_generic_phy);
+
+ usb_phy_set_suspend(dwc->usb3_phy, 1);
+ usb_phy_set_suspend(dwc->usb2_phy, 1);
+}
+
static int dwc3_clk_enable(struct dwc3 *dwc)
{
int ret;
@@ -840,17 +836,8 @@ static void dwc3_clk_disable(struct dwc3 *dwc)
static void dwc3_core_exit(struct dwc3 *dwc)
{
dwc3_event_buffers_cleanup(dwc);
-
- usb_phy_set_suspend(dwc->usb2_phy, 1);
- usb_phy_set_suspend(dwc->usb3_phy, 1);
- phy_power_off(dwc->usb2_generic_phy);
- phy_power_off(dwc->usb3_generic_phy);
-
- usb_phy_shutdown(dwc->usb2_phy);
- usb_phy_shutdown(dwc->usb3_phy);
- phy_exit(dwc->usb2_generic_phy);
- phy_exit(dwc->usb3_generic_phy);
-
+ dwc3_phy_power_off(dwc);
+ dwc3_phy_exit(dwc);
dwc3_clk_disable(dwc);
reset_control_assert(dwc->reset);
}
@@ -877,7 +864,6 @@ static bool dwc3_core_is_valid(struct dwc3 *dwc)
static void dwc3_core_setup_global_control(struct dwc3 *dwc)
{
- u32 hwparams4 = dwc->hwparams.hwparams4;
u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
@@ -905,9 +891,6 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc)
reg &= ~DWC3_GCTL_DSBLCLKGTNG;
break;
case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
- /* enable hibernation here */
- dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);
-
/*
* REVISIT Enabling this bit so that host-mode hibernation
* will work. Device-mode hibernation is not yet implemented.
@@ -1096,7 +1079,7 @@ static int dwc3_core_init(struct dwc3 *dwc)
ret = dwc3_phy_setup(dwc);
if (ret)
- goto err0;
+ return ret;
if (!dwc->ulpi_ready) {
ret = dwc3_core_ulpi_init(dwc);
@@ -1105,7 +1088,7 @@ static int dwc3_core_init(struct dwc3 *dwc)
dwc3_core_soft_reset(dwc);
ret = -EPROBE_DEFER;
}
- goto err0;
+ return ret;
}
dwc->ulpi_ready = true;
}
@@ -1113,25 +1096,17 @@ static int dwc3_core_init(struct dwc3 *dwc)
if (!dwc->phys_ready) {
ret = dwc3_core_get_phy(dwc);
if (ret)
- goto err0a;
+ goto err_exit_ulpi;
dwc->phys_ready = true;
}
- usb_phy_init(dwc->usb2_phy);
- usb_phy_init(dwc->usb3_phy);
- ret = phy_init(dwc->usb2_generic_phy);
- if (ret < 0)
- goto err0a;
-
- ret = phy_init(dwc->usb3_generic_phy);
- if (ret < 0) {
- phy_exit(dwc->usb2_generic_phy);
- goto err0a;
- }
+ ret = dwc3_phy_init(dwc);
+ if (ret)
+ goto err_exit_ulpi;
ret = dwc3_core_soft_reset(dwc);
if (ret)
- goto err1;
+ goto err_exit_phy;
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD &&
!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) {
@@ -1151,10 +1126,6 @@ static int dwc3_core_init(struct dwc3 *dwc)
dwc3_core_setup_global_control(dwc);
dwc3_core_num_eps(dwc);
- ret = dwc3_setup_scratch_buffers(dwc);
- if (ret)
- goto err1;
-
/* Set power down scale of suspend_clk */
dwc3_set_power_down_clk_scale(dwc);
@@ -1166,20 +1137,14 @@ static int dwc3_core_init(struct dwc3 *dwc)
dwc3_set_incr_burst_type(dwc);
- usb_phy_set_suspend(dwc->usb2_phy, 0);
- usb_phy_set_suspend(dwc->usb3_phy, 0);
- ret = phy_power_on(dwc->usb2_generic_phy);
- if (ret < 0)
- goto err2;
-
- ret = phy_power_on(dwc->usb3_generic_phy);
- if (ret < 0)
- goto err3;
+ dwc3_phy_power_on(dwc);
+ if (ret)
+ goto err_exit_phy;
ret = dwc3_event_buffers_setup(dwc);
if (ret) {
dev_err(dwc->dev, "failed to setup event buffers\n");
- goto err4;
+ goto err_power_off_phy;
}
/*
@@ -1233,6 +1198,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
if (dwc->parkmode_disable_ss_quirk)
reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS;
+ if (dwc->parkmode_disable_hs_quirk)
+ reg |= DWC3_GUCTL1_PARKMODE_DISABLE_HS;
+
if (DWC3_VER_IS_WITHIN(DWC3, 290A, ANY) &&
(dwc->maximum_speed == USB_SPEED_HIGH ||
dwc->maximum_speed == USB_SPEED_FULL))
@@ -1296,26 +1264,13 @@ static int dwc3_core_init(struct dwc3 *dwc)
return 0;
-err4:
- phy_power_off(dwc->usb3_generic_phy);
-
-err3:
- phy_power_off(dwc->usb2_generic_phy);
-
-err2:
- usb_phy_set_suspend(dwc->usb2_phy, 1);
- usb_phy_set_suspend(dwc->usb3_phy, 1);
-
-err1:
- usb_phy_shutdown(dwc->usb2_phy);
- usb_phy_shutdown(dwc->usb3_phy);
- phy_exit(dwc->usb2_generic_phy);
- phy_exit(dwc->usb3_generic_phy);
-
-err0a:
+err_power_off_phy:
+ dwc3_phy_power_off(dwc);
+err_exit_phy:
+ dwc3_phy_exit(dwc);
+err_exit_ulpi:
dwc3_ulpi_exit(dwc);
-err0:
return ret;
}
@@ -1553,8 +1508,12 @@ static void dwc3_get_properties(struct dwc3 *dwc)
"snps,dis-tx-ipgap-linecheck-quirk");
dwc->resume_hs_terminations = device_property_read_bool(dev,
"snps,resume-hs-terminations");
+ dwc->ulpi_ext_vbus_drv = device_property_read_bool(dev,
+ "snps,ulpi-ext-vbus-drv");
dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev,
"snps,parkmode-disable-ss-quirk");
+ dwc->parkmode_disable_hs_quirk = device_property_read_bool(dev,
+ "snps,parkmode-disable-hs-quirk");
dwc->gfladj_refclk_lpm_sel = device_property_read_bool(dev,
"snps,gfladj-refclk-lpm-sel-quirk");
@@ -1750,16 +1709,72 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
return edev;
}
+static int dwc3_get_clocks(struct dwc3 *dwc)
+{
+ struct device *dev = dwc->dev;
+
+ if (!dev->of_node)
+ return 0;
+
+ /*
+ * Clocks are optional, but new DT platforms should support all clocks
+ * as required by the DT-binding.
+ * Some devices have different clock names in legacy device trees,
+ * 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 (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");
+ }
+ }
+
+ 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 (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");
+ }
+ }
+
+ 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 (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");
+ }
+ }
+
+ return 0;
+}
+
static int dwc3_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res, dwc_res;
+ void __iomem *regs;
struct dwc3 *dwc;
-
int ret;
- void __iomem *regs;
-
dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
if (!dwc)
return -ENOMEM;
@@ -1797,77 +1812,25 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->reset = devm_reset_control_array_get_optional_shared(dev);
if (IS_ERR(dwc->reset)) {
ret = PTR_ERR(dwc->reset);
- goto put_usb_psy;
+ goto err_put_psy;
}
- if (dev->of_node) {
- /*
- * Clocks are optional, but new DT platforms should support all
- * clocks as required by the DT-binding.
- * Some devices have different clock names in legacy device trees,
- * check for them to retain backwards compatibility.
- */
- dwc->bus_clk = devm_clk_get_optional(dev, "bus_early");
- 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)) {
- 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)) {
- 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)) {
- 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)) {
- 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)) {
- ret = dev_err_probe(dev, PTR_ERR(dwc->susp_clk),
- "could not get suspend clock\n");
- goto put_usb_psy;
- }
- }
- }
+ ret = dwc3_get_clocks(dwc);
+ if (ret)
+ goto err_put_psy;
ret = reset_control_deassert(dwc->reset);
if (ret)
- goto put_usb_psy;
+ goto err_put_psy;
ret = dwc3_clk_enable(dwc);
if (ret)
- goto assert_reset;
+ goto err_assert_reset;
if (!dwc3_core_is_valid(dwc)) {
dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
ret = -ENODEV;
- goto disable_clks;
+ goto err_disable_clks;
}
platform_set_drvdata(pdev, dwc);
@@ -1877,19 +1840,17 @@ static int dwc3_probe(struct platform_device *pdev)
DWC3_GHWPARAMS0_AWIDTH(dwc->hwparams.hwparams0) == 64) {
ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64));
if (ret)
- goto disable_clks;
+ goto err_disable_clks;
}
spin_lock_init(&dwc->lock);
mutex_init(&dwc->mutex);
+ pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
pm_runtime_use_autosuspend(dev);
pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY);
pm_runtime_enable(dev);
- ret = pm_runtime_get_sync(dev);
- if (ret < 0)
- goto err1;
pm_runtime_forbid(dev);
@@ -1897,27 +1858,23 @@ static int dwc3_probe(struct platform_device *pdev)
if (ret) {
dev_err(dwc->dev, "failed to allocate event buffers\n");
ret = -ENOMEM;
- goto err2;
+ goto err_allow_rpm;
}
dwc->edev = dwc3_get_extcon(dwc);
if (IS_ERR(dwc->edev)) {
ret = dev_err_probe(dwc->dev, PTR_ERR(dwc->edev), "failed to get extcon\n");
- goto err3;
+ goto err_free_event_buffers;
}
ret = dwc3_get_dr_mode(dwc);
if (ret)
- goto err3;
-
- ret = dwc3_alloc_scratch_buffers(dwc);
- if (ret)
- goto err3;
+ goto err_free_event_buffers;
ret = dwc3_core_init(dwc);
if (ret) {
dev_err_probe(dev, ret, "failed to initialize core\n");
- goto err4;
+ goto err_free_event_buffers;
}
dwc3_check_params(dwc);
@@ -1925,46 +1882,31 @@ static int dwc3_probe(struct platform_device *pdev)
ret = dwc3_core_init_mode(dwc);
if (ret)
- goto err5;
+ goto err_exit_debugfs;
pm_runtime_put(dev);
return 0;
-err5:
+err_exit_debugfs:
dwc3_debugfs_exit(dwc);
dwc3_event_buffers_cleanup(dwc);
-
- usb_phy_set_suspend(dwc->usb2_phy, 1);
- usb_phy_set_suspend(dwc->usb3_phy, 1);
- phy_power_off(dwc->usb2_generic_phy);
- phy_power_off(dwc->usb3_generic_phy);
-
- usb_phy_shutdown(dwc->usb2_phy);
- usb_phy_shutdown(dwc->usb3_phy);
- phy_exit(dwc->usb2_generic_phy);
- phy_exit(dwc->usb3_generic_phy);
-
+ dwc3_phy_power_off(dwc);
+ dwc3_phy_exit(dwc);
dwc3_ulpi_exit(dwc);
-
-err4:
- dwc3_free_scratch_buffers(dwc);
-
-err3:
+err_free_event_buffers:
dwc3_free_event_buffers(dwc);
-
-err2:
- pm_runtime_allow(&pdev->dev);
-
-err1:
- pm_runtime_put_sync(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
-
-disable_clks:
+err_allow_rpm:
+ pm_runtime_allow(dev);
+ pm_runtime_disable(dev);
+ pm_runtime_dont_use_autosuspend(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_put_noidle(dev);
+err_disable_clks:
dwc3_clk_disable(dwc);
-assert_reset:
+err_assert_reset:
reset_control_assert(dwc->reset);
-put_usb_psy:
+err_put_psy:
if (dwc->usb_psy)
power_supply_put(dwc->usb_psy);
@@ -1983,12 +1925,13 @@ static int dwc3_remove(struct platform_device *pdev)
dwc3_core_exit(dwc);
dwc3_ulpi_exit(dwc);
+ pm_runtime_allow(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
dwc3_free_event_buffers(dwc);
- dwc3_free_scratch_buffers(dwc);
if (dwc->usb_psy)
power_supply_put(dwc->usb_psy);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 4743e918dcaf..d56457c02996 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -263,6 +263,7 @@
#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_PARKMODE_DISABLE_HS BIT(16)
#define DWC3_GUCTL1_RESUME_OPMODE_HS_HOST BIT(10)
/* Global Status Register */
@@ -280,6 +281,7 @@
/* Global USB2 PHY Configuration Register */
#define DWC3_GUSB2PHYCFG_PHYSOFTRST BIT(31)
#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS BIT(30)
+#define DWC3_GUSB2PHYCFG_ULPIEXTVBUSDRV BIT(17)
#define DWC3_GUSB2PHYCFG_SUSPHY BIT(6)
#define DWC3_GUSB2PHYCFG_ULPI_UTMI BIT(4)
#define DWC3_GUSB2PHYCFG_ENBLSLPM BIT(8)
@@ -526,6 +528,7 @@
#define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c
#define DWC3_DGCMD_SET_ENDPOINT_PRIME 0x0d
#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10
+#define DWC3_DGCMD_DEV_NOTIFICATION 0x07
#define DWC3_DGCMD_STATUS(n) (((n) >> 12) & 0x0F)
#define DWC3_DGCMD_CMDACT BIT(10)
@@ -538,6 +541,8 @@
#define DWC3_DGCMDPAR_TX_FIFO BIT(5)
#define DWC3_DGCMDPAR_LOOPBACK_DIS (0 << 0)
#define DWC3_DGCMDPAR_LOOPBACK_ENA BIT(0)
+#define DWC3_DGCMDPAR_DN_FUNC_WAKE BIT(0)
+#define DWC3_DGCMDPAR_INTF_SEL(n) ((n) << 4)
/* Device Endpoint Command Register */
#define DWC3_DEPCMD_PARAM_SHIFT 16
@@ -969,12 +974,10 @@ struct dwc3_scratchpad_array {
* @drd_work: workqueue used for role swapping
* @ep0_trb: trb which is used for the ctrl_req
* @bounce: address of bounce buffer
- * @scratchbuf: address of scratch buffer
* @setup_buf: used while precessing STD USB requests
* @ep0_trb_addr: dma address of @ep0_trb
* @bounce_addr: dma address of @bounce
* @ep0_usb_req: dummy req used while handling STD USB requests
- * @scratch_addr: dma address of scratchbuf
* @ep0_in_setup: one control transfer is completed and enter setup phase
* @lock: for synchronizing
* @mutex: for mode switching
@@ -999,7 +1002,6 @@ struct dwc3_scratchpad_array {
* @current_otg_role: current role of operation while using the OTG block
* @desired_otg_role: desired role of operation while using the OTG block
* @otg_restart_host: flag that OTG controller needs to restart host
- * @nr_scratch: number of scratch buffers
* @u1u2: only used on revisions <1.83a for workaround
* @maximum_speed: maximum speed requested (mainly for testing purposes)
* @max_ssp_rate: SuperSpeed Plus maximum signaling rate and lane count
@@ -1056,7 +1058,6 @@ struct dwc3_scratchpad_array {
* @delayed_status: true when gadget driver asks for delayed status
* @ep0_bounced: true when we used bounce buffer
* @ep0_expect_in: true when we expect a DATA IN transfer
- * @has_hibernation: true when dwc3 was configured with Hibernation
* @sysdev_is_parent: true when dwc3 device has a parent driver
* @has_lpm_erratum: true when core was configured with LPM Erratum. Note that
* there's now way for software to detect this in runtime.
@@ -1100,8 +1101,12 @@ struct dwc3_scratchpad_array {
* check during HS transmit.
* @resume_hs_terminations: Set if we enable quirk for fixing improper crc
* generation after resume from suspend.
+ * @ulpi_ext_vbus_drv: Set to confiure the upli chip to drives CPEN pin
+ * VBUS with an external supply.
* @parkmode_disable_ss_quirk: set if we need to disable all SuperSpeed
* instances in park mode.
+ * @parkmode_disable_hs_quirk: set if we need to disable all HishSpeed
+ * instances in park mode.
* @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
* @tx_de_emphasis: Tx de-emphasis value
* 0 - -6dB de-emphasis
@@ -1110,6 +1115,7 @@ struct dwc3_scratchpad_array {
* 3 - Reserved
* @dis_metastability_quirk: set to disable metastability quirk.
* @dis_split_quirk: set to disable split boundary.
+ * @wakeup_configured: set if the device is configured for remote wakeup.
* @imod_interval: set the interrupt moderation interval in 250ns
* increments or 0 to disable.
* @max_cfg_eps: current max number of IN eps used across all USB configs.
@@ -1123,11 +1129,9 @@ struct dwc3 {
struct work_struct drd_work;
struct dwc3_trb *ep0_trb;
void *bounce;
- void *scratchbuf;
u8 *setup_buf;
dma_addr_t ep0_trb_addr;
dma_addr_t bounce_addr;
- dma_addr_t scratch_addr;
struct dwc3_request ep0_usb_req;
struct completion ep0_in_setup;
@@ -1187,7 +1191,6 @@ struct dwc3 {
u32 current_otg_role;
u32 desired_otg_role;
bool otg_restart_host;
- u32 nr_scratch;
u32 u1u2;
u32 maximum_speed;
u32 gadget_max_speed;
@@ -1284,7 +1287,6 @@ struct dwc3 {
unsigned delayed_status:1;
unsigned ep0_bounced:1;
unsigned ep0_expect_in:1;
- unsigned has_hibernation:1;
unsigned sysdev_is_parent:1;
unsigned has_lpm_erratum:1;
unsigned is_utmi_l1_suspend:1;
@@ -1317,7 +1319,9 @@ struct dwc3 {
unsigned dis_del_phy_power_chg_quirk:1;
unsigned dis_tx_ipgap_linecheck_quirk:1;
unsigned resume_hs_terminations:1;
+ unsigned ulpi_ext_vbus_drv:1;
unsigned parkmode_disable_ss_quirk:1;
+ unsigned parkmode_disable_hs_quirk:1;
unsigned gfladj_refclk_lpm_sel:1;
unsigned tx_de_emphasis_quirk:1;
@@ -1327,6 +1331,7 @@ struct dwc3 {
unsigned dis_split_quirk:1;
unsigned async_callbacks:1;
+ unsigned wakeup_configured:1;
u16 imod_interval;
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
index 8bb2c9e3b9ac..09d703852a92 100644
--- a/drivers/usb/dwc3/debug.h
+++ b/drivers/usb/dwc3/debug.h
@@ -72,6 +72,8 @@ dwc3_gadget_generic_cmd_string(u8 cmd)
return "Set Endpoint Prime";
case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK:
return "Run SoC Bus Loopback Test";
+ case DWC3_DGCMD_DEV_NOTIFICATION:
+ return "Device Notification";
default:
return "UNKNOWN";
}
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index 850df0e6bcab..e4a2560b9dc0 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -88,6 +88,9 @@ static const struct debugfs_reg32 dwc3_regs[] = {
dump_register(GPRTBIMAP_HS1),
dump_register(GPRTBIMAP_FS0),
dump_register(GPRTBIMAP_FS1),
+ dump_register(GUCTL2),
+ dump_register(VER_NUMBER),
+ dump_register(VER_TYPE),
dump_register(GUSB2PHYCFG(0)),
dump_register(GUSB2PHYCFG(1)),
@@ -229,6 +232,8 @@ static const struct debugfs_reg32 dwc3_regs[] = {
dump_register(GEVNTCOUNT(0)),
dump_register(GHWPARAMS8),
+ dump_register(GUCTL3),
+ dump_register(GFLADJ),
dump_register(DCFG),
dump_register(DCTL),
dump_register(DEVTEN),
diff --git a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c
index 173cf3579c55..cda9458c809b 100644
--- a/drivers/usb/dwc3/dwc3-am62.c
+++ b/drivers/usb/dwc3/dwc3-am62.c
@@ -11,12 +11,14 @@
#include <linux/platform_device.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <linux/regmap.h>
#include <linux/pinctrl/consumer.h>
+#include "core.h"
+
/* USB WRAPPER register offsets */
#define USBSS_PID 0x0
#define USBSS_OVERCURRENT_CTRL 0x4
@@ -45,6 +47,10 @@
#define USBSS_PHY_VBUS_SEL_SHIFT 1
#define USBSS_PHY_LANE_REVERSE BIT(0)
+/* CORE STAT register bits */
+#define USBSS_CORE_OPERATIONAL_MODE_MASK GENMASK(13, 12)
+#define USBSS_CORE_OPERATIONAL_MODE_SHIFT 12
+
/* MODE CONTROL register bits */
#define USBSS_MODE_VALID BIT(0)
@@ -54,6 +60,13 @@
#define USBSS_WAKEUP_CFG_SESSVALID_EN BIT(1)
#define USBSS_WAKEUP_CFG_VBUSVALID_EN BIT(0)
+#define USBSS_WAKEUP_CFG_ALL (USBSS_WAKEUP_CFG_VBUSVALID_EN | \
+ USBSS_WAKEUP_CFG_SESSVALID_EN | \
+ USBSS_WAKEUP_CFG_LINESTATE_EN | \
+ USBSS_WAKEUP_CFG_OVERCURRENT_EN)
+
+#define USBSS_WAKEUP_CFG_NONE 0
+
/* WAKEUP STAT register bits */
#define USBSS_WAKEUP_STAT_OVERCURRENT BIT(4)
#define USBSS_WAKEUP_STAT_LINESTATE BIT(3)
@@ -97,6 +110,7 @@ struct dwc3_data {
struct regmap *syscon;
unsigned int offset;
unsigned int vbus_divider;
+ u32 wakeup_stat;
};
static const int dwc3_ti_rate_table[] = { /* in KHZ */
@@ -233,6 +247,12 @@ static int dwc3_ti_probe(struct platform_device *pdev)
reg |= USBSS_MODE_VALID;
dwc3_ti_writel(data, USBSS_MODE_CONTROL, reg);
+ /* Device has capability to wakeup system from sleep */
+ device_set_wakeup_capable(dev, true);
+ ret = device_wakeup_enable(dev);
+ if (ret)
+ dev_err(dev, "couldn't enable device as a wakeup source: %d\n", ret);
+
/* Setting up autosuspend */
pm_runtime_set_autosuspend_delay(dev, DWC3_AM62_AUTOSUSPEND_DELAY);
pm_runtime_use_autosuspend(dev);
@@ -281,6 +301,27 @@ static int dwc3_ti_remove(struct platform_device *pdev)
static int dwc3_ti_suspend_common(struct device *dev)
{
struct dwc3_data *data = dev_get_drvdata(dev);
+ u32 reg, current_prtcap_dir;
+
+ if (device_may_wakeup(dev)) {
+ reg = dwc3_ti_readl(data, USBSS_CORE_STAT);
+ current_prtcap_dir = (reg & USBSS_CORE_OPERATIONAL_MODE_MASK)
+ >> USBSS_CORE_OPERATIONAL_MODE_SHIFT;
+ /* Set wakeup config enable bits */
+ reg = dwc3_ti_readl(data, USBSS_WAKEUP_CONFIG);
+ if (current_prtcap_dir == DWC3_GCTL_PRTCAP_HOST) {
+ reg = USBSS_WAKEUP_CFG_LINESTATE_EN | USBSS_WAKEUP_CFG_OVERCURRENT_EN;
+ } else {
+ reg = USBSS_WAKEUP_CFG_VBUSVALID_EN | USBSS_WAKEUP_CFG_SESSVALID_EN;
+ /*
+ * Enable LINESTATE wake up only if connected to bus
+ * and in U2/L3 state else it causes spurious wake-up.
+ */
+ }
+ dwc3_ti_writel(data, USBSS_WAKEUP_CONFIG, reg);
+ /* clear wakeup status so we know what caused the wake up */
+ dwc3_ti_writel(data, USBSS_WAKEUP_STAT, USBSS_WAKEUP_STAT_CLR);
+ }
clk_disable_unprepare(data->usb2_refclk);
@@ -290,9 +331,18 @@ static int dwc3_ti_suspend_common(struct device *dev)
static int dwc3_ti_resume_common(struct device *dev)
{
struct dwc3_data *data = dev_get_drvdata(dev);
+ u32 reg;
clk_prepare_enable(data->usb2_refclk);
+ if (device_may_wakeup(dev)) {
+ /* Clear wakeup config enable bits */
+ dwc3_ti_writel(data, USBSS_WAKEUP_CONFIG, USBSS_WAKEUP_CFG_NONE);
+ }
+
+ reg = dwc3_ti_readl(data, USBSS_WAKEUP_STAT);
+ data->wakeup_stat = reg;
+
return 0;
}
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 560793545362..44a04c9b2073 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -388,107 +388,41 @@ static void dwc3_pci_remove(struct pci_dev *pci)
}
static const struct pci_device_id dwc3_pci_id_table[] = {
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BSW),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BYT),
- (kernel_ulong_t) &dwc3_pci_intel_byt_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MRFLD),
- (kernel_ulong_t) &dwc3_pci_intel_mrfld_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CMLLP),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CMLH),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTLP),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTH),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT_M),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_APL),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_KBP),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_GLK),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPLP),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPH),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPV),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHL),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPLP),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPH),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_JSP),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL_PCH),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { 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),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPL),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPLS),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLM),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLP),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLS),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGL),
- (kernel_ulong_t) &dwc3_pci_intel_swnode, },
-
- { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_NL_USB),
- (kernel_ulong_t) &dwc3_pci_amd_swnode, },
-
- { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MR),
- (kernel_ulong_t)&dwc3_pci_amd_mr_swnode, },
+ { PCI_DEVICE_DATA(INTEL, BSW, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, BYT, &dwc3_pci_intel_byt_swnode) },
+ { PCI_DEVICE_DATA(INTEL, MRFLD, &dwc3_pci_intel_mrfld_swnode) },
+ { PCI_DEVICE_DATA(INTEL, CMLLP, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, CMLH, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, SPTLP, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, SPTH, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, BXT, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, BXT_M, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, APL, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, KBP, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, GLK, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, CNPLP, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, CNPH, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, CNPV, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, ICLLP, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, EHL, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, TGPLP, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, TGPH, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, JSP, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, ADL, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, ADL_PCH, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, ADLN, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, ADLN_PCH, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, ADLS, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, RPL, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, RPLS, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, MTLM, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, MTLP, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, MTL, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, MTLS, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, TGL, &dwc3_pci_intel_swnode) },
+
+ { PCI_DEVICE_DATA(AMD, NL_USB, &dwc3_pci_amd_swnode) },
+ { PCI_DEVICE_DATA(AMD, MR, &dwc3_pci_amd_mr_swnode) },
{ } /* Terminating Entry */
};
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 61de693461da..953b752a5052 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -30,6 +30,8 @@
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep);
static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
struct dwc3_ep *dep, struct dwc3_request *req);
+static int dwc3_ep0_delegate_req(struct dwc3 *dwc,
+ struct usb_ctrlrequest *ctrl);
static void dwc3_ep0_prepare_one_trb(struct dwc3_ep *dep,
dma_addr_t buf_dma, u32 len, u32 type, bool chain)
@@ -356,6 +358,9 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
usb_status |= 1 << USB_DEV_STAT_U1_ENABLED;
if (reg & DWC3_DCTL_INITU2ENA)
usb_status |= 1 << USB_DEV_STAT_U2_ENABLED;
+ } else {
+ usb_status |= dwc->gadget->wakeup_armed <<
+ USB_DEVICE_REMOTE_WAKEUP;
}
break;
@@ -365,7 +370,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
* Function Remote Wake Capable D0
* Function Remote Wakeup D1
*/
- break;
+ return dwc3_ep0_delegate_req(dwc, ctrl);
case USB_RECIP_ENDPOINT:
dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
@@ -476,6 +481,10 @@ static int dwc3_ep0_handle_device(struct dwc3 *dwc,
switch (wValue) {
case USB_DEVICE_REMOTE_WAKEUP:
+ if (dwc->wakeup_configured)
+ dwc->gadget->wakeup_armed = set;
+ else
+ ret = -EINVAL;
break;
/*
* 9.4.1 says only for SS, in AddressState only for
@@ -510,13 +519,7 @@ static int dwc3_ep0_handle_intf(struct dwc3 *dwc,
switch (wValue) {
case USB_INTRF_FUNC_SUSPEND:
- /*
- * REVISIT: Ideally we would enable some low power mode here,
- * however it's unclear what we should be doing here.
- *
- * For now, we're not doing anything, just making sure we return
- * 0 so USB Command Verifier tests pass without any errors.
- */
+ ret = dwc3_ep0_delegate_req(dwc, ctrl);
break;
default:
ret = -EINVAL;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index cf5b4f49c3ed..c0ca4d12f95d 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -139,6 +139,24 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
return -ETIMEDOUT;
}
+static void dwc3_ep0_reset_state(struct dwc3 *dwc)
+{
+ unsigned int dir;
+
+ if (dwc->ep0state != EP0_SETUP_PHASE) {
+ 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]);
+
+ dwc->eps[0]->trb_enqueue = 0;
+ dwc->eps[1]->trb_enqueue = 0;
+
+ dwc3_ep0_stall_and_restart(dwc);
+ }
+}
+
/**
* dwc3_ep_inc_trb - increment a trb index.
* @index: Pointer to the TRB index to increment.
@@ -258,7 +276,7 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned int cmd,
return ret;
}
-static int __dwc3_gadget_wakeup(struct dwc3 *dwc);
+static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async);
/**
* dwc3_send_gadget_ep_cmd - issue an endpoint command
@@ -325,7 +343,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd,
fallthrough;
case DWC3_LINK_STATE_U3:
- ret = __dwc3_gadget_wakeup(dwc);
+ ret = __dwc3_gadget_wakeup(dwc, false);
dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n",
ret);
break;
@@ -2273,6 +2291,22 @@ static const struct usb_ep_ops dwc3_gadget_ep_ops = {
/* -------------------------------------------------------------------------- */
+static void dwc3_gadget_enable_linksts_evts(struct dwc3 *dwc, bool set)
+{
+ u32 reg;
+
+ if (DWC3_VER_IS_PRIOR(DWC3, 250A))
+ return;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DEVTEN);
+ if (set)
+ reg |= DWC3_DEVTEN_ULSTCNGEN;
+ else
+ reg &= ~DWC3_DEVTEN_ULSTCNGEN;
+
+ dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
+}
+
static int dwc3_gadget_get_frame(struct usb_gadget *g)
{
struct dwc3 *dwc = gadget_to_dwc(g);
@@ -2280,7 +2314,7 @@ static int dwc3_gadget_get_frame(struct usb_gadget *g)
return __dwc3_gadget_get_frame(dwc);
}
-static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
+static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async)
{
int retries;
@@ -2311,9 +2345,13 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
return -EINVAL;
}
+ if (async)
+ dwc3_gadget_enable_linksts_evts(dwc, true);
+
ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV);
if (ret < 0) {
dev_err(dwc->dev, "failed to put link in Recovery\n");
+ dwc3_gadget_enable_linksts_evts(dwc, false);
return ret;
}
@@ -2325,6 +2363,13 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
}
+ /*
+ * Since link status change events are enabled we will receive
+ * an U0 event when wakeup is successful. So bail out.
+ */
+ if (async)
+ return 0;
+
/* poll until Link State changes to ON */
retries = 20000;
@@ -2350,13 +2395,77 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
unsigned long flags;
int ret;
+ if (!dwc->wakeup_configured) {
+ dev_err(dwc->dev, "remote wakeup not configured\n");
+ return -EINVAL;
+ }
+
spin_lock_irqsave(&dwc->lock, flags);
- ret = __dwc3_gadget_wakeup(dwc);
+ if (!dwc->gadget->wakeup_armed) {
+ dev_err(dwc->dev, "not armed for remote wakeup\n");
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return -EINVAL;
+ }
+ ret = __dwc3_gadget_wakeup(dwc, true);
+
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
}
+static void dwc3_resume_gadget(struct dwc3 *dwc);
+
+static int dwc3_gadget_func_wakeup(struct usb_gadget *g, int intf_id)
+{
+ struct dwc3 *dwc = gadget_to_dwc(g);
+ unsigned long flags;
+ int ret;
+ int link_state;
+
+ if (!dwc->wakeup_configured) {
+ dev_err(dwc->dev, "remote wakeup not configured\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ /*
+ * If the link is in U3, signal for remote wakeup and wait for the
+ * link to transition to U0 before sending device notification.
+ */
+ link_state = dwc3_gadget_get_link_state(dwc);
+ if (link_state == DWC3_LINK_STATE_U3) {
+ ret = __dwc3_gadget_wakeup(dwc, false);
+ if (ret) {
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return -EINVAL;
+ }
+ dwc3_resume_gadget(dwc);
+ dwc->link_state = DWC3_LINK_STATE_U0;
+ }
+
+ ret = dwc3_send_gadget_generic_command(dwc, DWC3_DGCMD_DEV_NOTIFICATION,
+ DWC3_DGCMDPAR_DN_FUNC_WAKE |
+ DWC3_DGCMDPAR_INTF_SEL(intf_id));
+ if (ret)
+ dev_err(dwc->dev, "function remote wakeup failed, ret:%d\n", ret);
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
+static int dwc3_gadget_set_remote_wakeup(struct usb_gadget *g, int set)
+{
+ struct dwc3 *dwc = gadget_to_dwc(g);
+ unsigned long flags;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ dwc->wakeup_configured = !!set;
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return 0;
+}
+
static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
int is_selfpowered)
{
@@ -2478,7 +2587,7 @@ static void __dwc3_gadget_set_speed(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
}
-static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
+static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
{
u32 reg;
u32 timeout = 2000;
@@ -2497,17 +2606,11 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
reg &= ~DWC3_DCTL_KEEP_CONNECT;
reg |= DWC3_DCTL_RUN_STOP;
- if (dwc->has_hibernation)
- reg |= DWC3_DCTL_KEEP_CONNECT;
-
__dwc3_gadget_set_speed(dwc);
dwc->pullups_connected = true;
} else {
reg &= ~DWC3_DCTL_RUN_STOP;
- if (dwc->has_hibernation && !suspend)
- reg &= ~DWC3_DCTL_KEEP_CONNECT;
-
dwc->pullups_connected = false;
}
@@ -2532,29 +2635,17 @@ static int __dwc3_gadget_start(struct dwc3 *dwc);
static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc)
{
unsigned long flags;
+ int ret;
spin_lock_irqsave(&dwc->lock, flags);
dwc->connected = false;
/*
- * Per databook, when we want to stop the gadget, if a control transfer
- * is still in process, complete it and get the core into setup phase.
+ * Attempt to end pending SETUP status phase, and not wait for the
+ * function to do so.
*/
- 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);
- ret = wait_for_completion_timeout(&dwc->ep0_in_setup,
- msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT));
- spin_lock_irqsave(&dwc->lock, flags);
- if (ret == 0)
- dev_warn(dwc->dev, "timed out waiting for SETUP phase\n");
- }
+ if (dwc->delayed_status)
+ dwc3_ep0_send_delayed_status(dwc);
/*
* In the Synopsys DesignWare Cores USB3 Databook Rev. 3.30a
@@ -2564,17 +2655,48 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc)
* bit.
*/
dwc3_stop_active_transfers(dwc);
- __dwc3_gadget_stop(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
/*
+ * Per databook, when we want to stop the gadget, if a control transfer
+ * is still in process, complete it and get the core into setup phase.
+ * In case the host is unresponsive to a SETUP transaction, forcefully
+ * stall the transfer, and move back to the SETUP phase, so that any
+ * pending endxfers can be executed.
+ */
+ if (dwc->ep0state != EP0_SETUP_PHASE) {
+ reinit_completion(&dwc->ep0_in_setup);
+
+ ret = wait_for_completion_timeout(&dwc->ep0_in_setup,
+ msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT));
+ if (ret == 0) {
+ dev_warn(dwc->dev, "wait for SETUP phase timed out\n");
+ spin_lock_irqsave(&dwc->lock, flags);
+ dwc3_ep0_reset_state(dwc);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ }
+ }
+
+ /*
* Note: if the GEVNTCOUNT indicates events in the event buffer, the
* driver needs to acknowledge them before the controller can halt.
* Simply let the interrupt handler acknowledges and handle the
* remaining event generated by the controller while polling for
* DSTS.DEVCTLHLT.
*/
- return dwc3_gadget_run_stop(dwc, false, false);
+ ret = dwc3_gadget_run_stop(dwc, false);
+
+ /*
+ * Stop the gadget after controller is halted, so that if needed, the
+ * events to update EP0 state can still occur while the run/stop
+ * routine polls for the halted state. DEVTEN is cleared as part of
+ * gadget stop.
+ */
+ spin_lock_irqsave(&dwc->lock, flags);
+ __dwc3_gadget_stop(dwc);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
}
static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
@@ -2628,7 +2750,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
dwc3_event_buffers_setup(dwc);
__dwc3_gadget_start(dwc);
- ret = dwc3_gadget_run_stop(dwc, true, false);
+ ret = dwc3_gadget_run_stop(dwc, true);
}
pm_runtime_put(dwc->dev);
@@ -2982,6 +3104,8 @@ static void dwc3_gadget_async_callbacks(struct usb_gadget *g, bool enable)
static const struct usb_gadget_ops dwc3_gadget_ops = {
.get_frame = dwc3_gadget_get_frame,
.wakeup = dwc3_gadget_wakeup,
+ .func_wakeup = dwc3_gadget_func_wakeup,
+ .set_remote_wakeup = dwc3_gadget_set_remote_wakeup,
.set_selfpowered = dwc3_gadget_set_selfpowered,
.pullup = dwc3_gadget_pullup,
.udc_start = dwc3_gadget_start,
@@ -3827,18 +3951,11 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
dwc->gadget->speed = USB_SPEED_UNKNOWN;
dwc->setup_packet_pending = false;
+ dwc->gadget->wakeup_armed = false;
+ dwc3_gadget_enable_linksts_evts(dwc, false);
usb_gadget_set_state(dwc->gadget, USB_STATE_NOTATTACHED);
- 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);
- }
+ dwc3_ep0_reset_state(dwc);
}
static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
@@ -3892,20 +4009,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
* phase. So ensure that EP0 is in setup phase by issuing a stall
* and restart if EP0 is not in setup phase.
*/
- 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]);
-
- dwc->eps[0]->trb_enqueue = 0;
- dwc->eps[1]->trb_enqueue = 0;
-
- dwc3_ep0_stall_and_restart(dwc);
- }
+ dwc3_ep0_reset_state(dwc);
/*
* In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a
@@ -3920,6 +4024,8 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
reg &= ~DWC3_DCTL_TSTCTRL_MASK;
dwc3_gadget_dctl_write_safe(dwc, reg);
dwc->test_mode = false;
+ dwc->gadget->wakeup_armed = false;
+ dwc3_gadget_enable_linksts_evts(dwc, false);
dwc3_clear_stall_all_ep(dwc);
/* Reset device address to zero */
@@ -4072,7 +4178,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
*/
}
-static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
+static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc, unsigned int evtinfo)
{
/*
* TODO take core out of low power mode when that's
@@ -4084,6 +4190,8 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
dwc->gadget_driver->resume(dwc->gadget);
spin_lock(&dwc->lock);
}
+
+ dwc->link_state = evtinfo & DWC3_LINK_STATE_MASK;
}
static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
@@ -4165,6 +4273,12 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
}
switch (next) {
+ case DWC3_LINK_STATE_U0:
+ if (dwc->gadget->wakeup_armed) {
+ dwc3_gadget_enable_linksts_evts(dwc, false);
+ dwc3_resume_gadget(dwc);
+ }
+ break;
case DWC3_LINK_STATE_U1:
if (dwc->speed == USB_SPEED_SUPER)
dwc3_suspend_gadget(dwc);
@@ -4195,30 +4309,6 @@ static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc,
dwc->link_state = next;
}
-static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc,
- unsigned int evtinfo)
-{
- unsigned int is_ss = evtinfo & BIT(4);
-
- /*
- * WORKAROUND: DWC3 revision 2.20a with hibernation support
- * have a known issue which can cause USB CV TD.9.23 to fail
- * randomly.
- *
- * Because of this issue, core could generate bogus hibernation
- * events which SW needs to ignore.
- *
- * Refers to:
- *
- * STAR#9000546576: Device Mode Hibernation: Issue in USB 2.0
- * Device Fallback from SuperSpeed
- */
- if (is_ss ^ (dwc->speed == USB_SPEED_SUPER))
- return;
-
- /* enter hibernation here */
-}
-
static void dwc3_gadget_interrupt(struct dwc3 *dwc,
const struct dwc3_event_devt *event)
{
@@ -4233,29 +4323,18 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
dwc3_gadget_conndone_interrupt(dwc);
break;
case DWC3_DEVICE_EVENT_WAKEUP:
- dwc3_gadget_wakeup_interrupt(dwc);
+ dwc3_gadget_wakeup_interrupt(dwc, event->event_info);
break;
case DWC3_DEVICE_EVENT_HIBER_REQ:
- if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation,
- "unexpected hibernation event\n"))
- break;
-
- dwc3_gadget_hibernation_interrupt(dwc, event->event_info);
+ dev_WARN_ONCE(dwc->dev, true, "unexpected hibernation event\n");
break;
case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
break;
case DWC3_DEVICE_EVENT_SUSPEND:
/* It changed to be suspend event for version 2.30a and above */
- if (!DWC3_VER_IS_PRIOR(DWC3, 230A)) {
- /*
- * Ignore suspend event until the gadget enters into
- * USB_STATE_CONFIGURED state.
- */
- if (dwc->gadget->state >= USB_STATE_CONFIGURED)
- dwc3_gadget_suspend_interrupt(dwc,
- event->event_info);
- }
+ if (!DWC3_VER_IS_PRIOR(DWC3, 230A))
+ dwc3_gadget_suspend_interrupt(dwc, event->event_info);
break;
case DWC3_DEVICE_EVENT_SOF:
case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
@@ -4417,11 +4496,6 @@ static int dwc3_gadget_get_irq(struct dwc3 *dwc)
goto out;
irq = platform_get_irq(dwc3_pdev, 0);
- if (irq > 0)
- goto out;
-
- if (!irq)
- irq = -EINVAL;
out:
return irq;
@@ -4493,6 +4567,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
dwc->gadget->sg_supported = true;
dwc->gadget->name = "dwc3-gadget";
dwc->gadget->lpm_capable = !dwc->usb2_gadget_lpm_disable;
+ dwc->gadget->wakeup_capable = true;
/*
* FIXME We might be setting max_speed to <SUPER, however versions
@@ -4584,7 +4659,7 @@ int dwc3_gadget_suspend(struct dwc3 *dwc)
if (!dwc->gadget_driver)
return 0;
- dwc3_gadget_run_stop(dwc, false, false);
+ dwc3_gadget_run_stop(dwc, false);
spin_lock_irqsave(&dwc->lock, flags);
dwc3_disconnect_gadget(dwc);
@@ -4605,7 +4680,7 @@ int dwc3_gadget_resume(struct dwc3 *dwc)
if (ret < 0)
goto err0;
- ret = dwc3_gadget_run_stop(dwc, true, false);
+ ret = dwc3_gadget_run_stop(dwc, true);
if (ret < 0)
goto err1;
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index f6f13e7f1ba1..61f57fe5bb78 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -52,13 +52,8 @@ static int dwc3_host_get_irq(struct dwc3 *dwc)
goto out;
irq = platform_get_irq(dwc3_pdev, 0);
- if (irq > 0) {
+ if (irq > 0)
dwc3_host_fill_xhci_irq_res(dwc, irq, NULL);
- goto out;
- }
-
- if (!irq)
- irq = -EINVAL;
out:
return irq;
diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h
index 1975aec8d36d..d2997d17cfbe 100644
--- a/drivers/usb/dwc3/trace.h
+++ b/drivers/usb/dwc3/trace.h
@@ -54,14 +54,13 @@ DECLARE_EVENT_CLASS(dwc3_log_event,
TP_STRUCT__entry(
__field(u32, event)
__field(u32, ep0state)
- __dynamic_array(char, str, DWC3_MSG_MAX)
),
TP_fast_assign(
__entry->event = event;
__entry->ep0state = dwc->ep0state;
),
TP_printk("event (%08x): %s", __entry->event,
- dwc3_decode_event(__get_str(str), DWC3_MSG_MAX,
+ dwc3_decode_event(__get_buf(DWC3_MSG_MAX), DWC3_MSG_MAX,
__entry->event, __entry->ep0state))
);
@@ -79,7 +78,6 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl,
__field(__u16, wValue)
__field(__u16, wIndex)
__field(__u16, wLength)
- __dynamic_array(char, str, DWC3_MSG_MAX)
),
TP_fast_assign(
__entry->bRequestType = ctrl->bRequestType;
@@ -88,7 +86,7 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl,
__entry->wIndex = le16_to_cpu(ctrl->wIndex);
__entry->wLength = le16_to_cpu(ctrl->wLength);
),
- TP_printk("%s", usb_decode_ctrl(__get_str(str), DWC3_MSG_MAX,
+ TP_printk("%s", usb_decode_ctrl(__get_buf(DWC3_MSG_MAX), DWC3_MSG_MAX,
__entry->bRequestType,
__entry->bRequest, __entry->wValue,
__entry->wIndex, __entry->wLength)
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 5377d873c08e..1b3489149e5e 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -492,6 +492,46 @@ int usb_interface_id(struct usb_configuration *config,
}
EXPORT_SYMBOL_GPL(usb_interface_id);
+/**
+ * usb_func_wakeup - sends function wake notification to the host.
+ * @func: function that sends the remote wakeup notification.
+ *
+ * Applicable to devices operating at enhanced superspeed when usb
+ * functions are put in function suspend state and armed for function
+ * remote wakeup. On completion, function wake notification is sent. If
+ * the device is in low power state it tries to bring the device to active
+ * state before sending the wake notification. Since it is a synchronous
+ * call, caller must take care of not calling it in interrupt context.
+ * For devices operating at lower speeds returns negative errno.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_func_wakeup(struct usb_function *func)
+{
+ struct usb_gadget *gadget = func->config->cdev->gadget;
+ int id;
+
+ if (!gadget->ops->func_wakeup)
+ return -EOPNOTSUPP;
+
+ if (!func->func_wakeup_armed) {
+ ERROR(func->config->cdev, "not armed for func remote wakeup\n");
+ return -EINVAL;
+ }
+
+ for (id = 0; id < MAX_CONFIG_INTERFACES; id++)
+ if (func->config->interface[id] == func)
+ break;
+
+ if (id == MAX_CONFIG_INTERFACES) {
+ ERROR(func->config->cdev, "Invalid function\n");
+ return -EINVAL;
+ }
+
+ return gadget->ops->func_wakeup(gadget, id);
+}
+EXPORT_SYMBOL_GPL(usb_func_wakeup);
+
static u8 encode_bMaxPower(enum usb_device_speed speed,
struct usb_configuration *c)
{
@@ -513,6 +553,19 @@ static u8 encode_bMaxPower(enum usb_device_speed speed,
return min(val, 900U) / 8;
}
+void check_remote_wakeup_config(struct usb_gadget *g,
+ struct usb_configuration *c)
+{
+ if (USB_CONFIG_ATT_WAKEUP & c->bmAttributes) {
+ /* Reset the rw bit if gadget is not capable of it */
+ if (!g->wakeup_capable && g->ops->set_remote_wakeup) {
+ WARN(c->cdev, "Clearing wakeup bit for config c.%d\n",
+ c->bConfigurationValue);
+ c->bmAttributes &= ~USB_CONFIG_ATT_WAKEUP;
+ }
+ }
+}
+
static int config_buf(struct usb_configuration *config,
enum usb_device_speed speed, void *buf, u8 type)
{
@@ -888,6 +941,9 @@ static void reset_config(struct usb_composite_dev *cdev)
if (f->disable)
f->disable(f);
+ /* Section 9.1.1.6, disable remote wakeup when device is reset */
+ f->func_wakeup_armed = false;
+
bitmap_zero(f->endpoints, 32);
}
cdev->config = NULL;
@@ -994,6 +1050,11 @@ static int set_config(struct usb_composite_dev *cdev,
power = min(power, 500U);
else
power = min(power, 900U);
+
+ if (USB_CONFIG_ATT_WAKEUP & c->bmAttributes)
+ usb_gadget_set_remote_wakeup(gadget, 1);
+ else
+ usb_gadget_set_remote_wakeup(gadget, 0);
done:
if (power <= USB_SELF_POWER_VBUS_MAX_DRAW)
usb_gadget_set_selfpowered(gadget);
@@ -1948,9 +2009,20 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
f = cdev->config->interface[intf];
if (!f)
break;
- status = f->get_status ? f->get_status(f) : 0;
- if (status < 0)
- break;
+
+ if (f->get_status) {
+ status = f->get_status(f);
+ if (status < 0)
+ break;
+ } else {
+ /* Set D0 and D1 bits based on func wakeup capability */
+ if (f->config->bmAttributes & USB_CONFIG_ATT_WAKEUP) {
+ status |= USB_INTRF_STAT_FUNC_RW_CAP;
+ if (f->func_wakeup_armed)
+ status |= USB_INTRF_STAT_FUNC_RW;
+ }
+ }
+
put_unaligned_le16(status & 0x0000ffff, req->buf);
break;
/*
@@ -1972,8 +2044,44 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
if (!f)
break;
value = 0;
- if (f->func_suspend)
+ if (f->func_suspend) {
value = f->func_suspend(f, w_index >> 8);
+ /* SetFeature(FUNCTION_SUSPEND) */
+ } else if (ctrl->bRequest == USB_REQ_SET_FEATURE) {
+ if (!(f->config->bmAttributes &
+ USB_CONFIG_ATT_WAKEUP) &&
+ (w_index & USB_INTRF_FUNC_SUSPEND_RW))
+ break;
+
+ f->func_wakeup_armed = !!(w_index &
+ USB_INTRF_FUNC_SUSPEND_RW);
+
+ if (w_index & USB_INTRF_FUNC_SUSPEND_LP) {
+ if (f->suspend && !f->func_suspended) {
+ f->suspend(f);
+ f->func_suspended = true;
+ }
+ /*
+ * Handle cases where host sends function resume
+ * through SetFeature(FUNCTION_SUSPEND) but low power
+ * bit reset
+ */
+ } else {
+ if (f->resume && f->func_suspended) {
+ f->resume(f);
+ f->func_suspended = false;
+ }
+ }
+ /* ClearFeature(FUNCTION_SUSPEND) */
+ } else if (ctrl->bRequest == USB_REQ_CLEAR_FEATURE) {
+ f->func_wakeup_armed = false;
+
+ if (f->resume && f->func_suspended) {
+ f->resume(f);
+ f->func_suspended = false;
+ }
+ }
+
if (value < 0) {
ERROR(cdev,
"func_suspend() returned error %d\n",
@@ -2515,7 +2623,12 @@ void composite_resume(struct usb_gadget *gadget)
cdev->driver->resume(cdev);
if (cdev->config) {
list_for_each_entry(f, &cdev->config->functions, list) {
- if (f->resume)
+ /*
+ * Check for func_suspended flag to see if the function is
+ * in USB3 FUNCTION_SUSPEND state. In this case resume is
+ * done via FUNCTION_SUSPEND feature selector.
+ */
+ if (f->resume && !f->func_suspended)
f->resume(f);
}
@@ -2530,6 +2643,10 @@ void composite_resume(struct usb_gadget *gadget)
usb_gadget_clear_selfpowered(gadget);
usb_gadget_vbus_draw(gadget, maxpower);
+ } else {
+ maxpower = CONFIG_USB_GADGET_VBUS_DRAW;
+ maxpower = min(maxpower, 100U);
+ usb_gadget_vbus_draw(gadget, maxpower);
}
cdev->suspended = 0;
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index b9f1136aa0a2..4c639e9ddedc 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -1761,6 +1761,9 @@ static int configfs_composite_bind(struct usb_gadget *gadget,
if (gadget_is_otg(gadget))
c->descriptors = otg_desc;
+ /* Properly configure the bmAttributes wakeup bit */
+ check_remote_wakeup_config(gadget, c);
+
cfg = container_of(c, struct config_usb_cfg, c);
if (!list_empty(&cfg->string_list)) {
i = 0;
diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c
index a7ab30e603e2..c6e63ad77a40 100644
--- a/drivers/usb/gadget/function/f_ecm.c
+++ b/drivers/usb/gadget/function/f_ecm.c
@@ -885,6 +885,26 @@ static struct usb_function_instance *ecm_alloc_inst(void)
return &opts->func_inst;
}
+static void ecm_suspend(struct usb_function *f)
+{
+ struct f_ecm *ecm = func_to_ecm(f);
+ struct usb_composite_dev *cdev = ecm->port.func.config->cdev;
+
+ DBG(cdev, "ECM Suspend\n");
+
+ gether_suspend(&ecm->port);
+}
+
+static void ecm_resume(struct usb_function *f)
+{
+ struct f_ecm *ecm = func_to_ecm(f);
+ struct usb_composite_dev *cdev = ecm->port.func.config->cdev;
+
+ DBG(cdev, "ECM Resume\n");
+
+ gether_resume(&ecm->port);
+}
+
static void ecm_free(struct usb_function *f)
{
struct f_ecm *ecm;
@@ -952,6 +972,8 @@ static struct usb_function *ecm_alloc(struct usb_function_instance *fi)
ecm->port.func.setup = ecm_setup;
ecm->port.func.disable = ecm_disable;
ecm->port.func.free_func = ecm_free;
+ ecm->port.func.suspend = ecm_suspend;
+ ecm->port.func.resume = ecm_resume;
return &ecm->port.func;
}
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 56cdfb2e4211..a13c946e0663 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -335,8 +335,6 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
ssize_t ret;
char *data;
- ENTER();
-
/* Fast check if setup was canceled */
if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
return -EIDRM;
@@ -512,8 +510,6 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
size_t n;
int ret;
- ENTER();
-
/* Fast check if setup was canceled */
if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
return -EIDRM;
@@ -612,8 +608,6 @@ static int ffs_ep0_open(struct inode *inode, struct file *file)
{
struct ffs_data *ffs = inode->i_private;
- ENTER();
-
if (ffs->state == FFS_CLOSING)
return -EBUSY;
@@ -627,8 +621,6 @@ static int ffs_ep0_release(struct inode *inode, struct file *file)
{
struct ffs_data *ffs = file->private_data;
- ENTER();
-
ffs_data_closed(ffs);
return 0;
@@ -640,8 +632,6 @@ static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)
struct usb_gadget *gadget = ffs->gadget;
long ret;
- ENTER();
-
if (code == FUNCTIONFS_INTERFACE_REVMAP) {
struct ffs_function *func = ffs->func;
ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV;
@@ -715,7 +705,6 @@ static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
{
struct ffs_io_data *io_data = req->context;
- ENTER();
if (req->status)
io_data->status = req->status;
else
@@ -856,8 +845,6 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
struct ffs_io_data *io_data = req->context;
struct ffs_data *ffs = io_data->ffs;
- ENTER();
-
io_data->status = req->status ? req->status : req->actual;
usb_ep_free_request(_ep, req);
@@ -1161,8 +1148,6 @@ ffs_epfile_open(struct inode *inode, struct file *file)
{
struct ffs_epfile *epfile = inode->i_private;
- ENTER();
-
if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
return -ENODEV;
@@ -1179,8 +1164,6 @@ static int ffs_aio_cancel(struct kiocb *kiocb)
unsigned long flags;
int value;
- ENTER();
-
spin_lock_irqsave(&epfile->ffs->eps_lock, flags);
if (io_data && io_data->ep && io_data->req)
@@ -1198,8 +1181,6 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
struct ffs_io_data io_data, *p = &io_data;
ssize_t res;
- ENTER();
-
if (!is_sync_kiocb(kiocb)) {
p = kzalloc(sizeof(io_data), GFP_KERNEL);
if (!p)
@@ -1235,8 +1216,6 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
struct ffs_io_data io_data, *p = &io_data;
ssize_t res;
- ENTER();
-
if (!is_sync_kiocb(kiocb)) {
p = kzalloc(sizeof(io_data), GFP_KERNEL);
if (!p)
@@ -1284,8 +1263,6 @@ ffs_epfile_release(struct inode *inode, struct file *file)
{
struct ffs_epfile *epfile = inode->i_private;
- ENTER();
-
__ffs_epfile_read_buffer_free(epfile);
ffs_data_closed(epfile->ffs);
@@ -1299,8 +1276,6 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code,
struct ffs_ep *ep;
int ret;
- ENTER();
-
if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
return -ENODEV;
@@ -1399,8 +1374,6 @@ ffs_sb_make_inode(struct super_block *sb, void *data,
{
struct inode *inode;
- ENTER();
-
inode = new_inode(sb);
if (inode) {
@@ -1432,8 +1405,6 @@ static struct dentry *ffs_sb_create_file(struct super_block *sb,
struct dentry *dentry;
struct inode *inode;
- ENTER();
-
dentry = d_alloc_name(sb->s_root, name);
if (!dentry)
return NULL;
@@ -1468,8 +1439,6 @@ static int ffs_sb_fill(struct super_block *sb, struct fs_context *fc)
struct inode *inode;
struct ffs_data *ffs = data->ffs_data;
- ENTER();
-
ffs->sb = sb;
data->ffs_data = NULL;
sb->s_fs_info = ffs;
@@ -1521,8 +1490,6 @@ static int ffs_fs_parse_param(struct fs_context *fc, struct fs_parameter *param)
struct fs_parse_result result;
int opt;
- ENTER();
-
opt = fs_parse(fc, ffs_fs_fs_parameters, param, &result);
if (opt < 0)
return opt;
@@ -1572,8 +1539,6 @@ static int ffs_fs_get_tree(struct fs_context *fc)
struct ffs_data *ffs;
int ret;
- ENTER();
-
if (!fc->source)
return invalf(fc, "No source specified");
@@ -1640,8 +1605,6 @@ static int ffs_fs_init_fs_context(struct fs_context *fc)
static void
ffs_fs_kill_sb(struct super_block *sb)
{
- ENTER();
-
kill_litter_super(sb);
if (sb->s_fs_info)
ffs_data_closed(sb->s_fs_info);
@@ -1663,8 +1626,6 @@ static int functionfs_init(void)
{
int ret;
- ENTER();
-
ret = register_filesystem(&ffs_fs_type);
if (!ret)
pr_info("file system registered\n");
@@ -1676,8 +1637,6 @@ static int functionfs_init(void)
static void functionfs_cleanup(void)
{
- ENTER();
-
pr_info("unloading\n");
unregister_filesystem(&ffs_fs_type);
}
@@ -1690,15 +1649,11 @@ static void ffs_data_reset(struct ffs_data *ffs);
static void ffs_data_get(struct ffs_data *ffs)
{
- ENTER();
-
refcount_inc(&ffs->ref);
}
static void ffs_data_opened(struct ffs_data *ffs)
{
- ENTER();
-
refcount_inc(&ffs->ref);
if (atomic_add_return(1, &ffs->opened) == 1 &&
ffs->state == FFS_DEACTIVATED) {
@@ -1709,8 +1664,6 @@ static void ffs_data_opened(struct ffs_data *ffs)
static void ffs_data_put(struct ffs_data *ffs)
{
- ENTER();
-
if (refcount_dec_and_test(&ffs->ref)) {
pr_info("%s(): freeing\n", __func__);
ffs_data_clear(ffs);
@@ -1729,8 +1682,6 @@ static void ffs_data_closed(struct ffs_data *ffs)
struct ffs_epfile *epfiles;
unsigned long flags;
- ENTER();
-
if (atomic_dec_and_test(&ffs->opened)) {
if (ffs->no_disconnect) {
ffs->state = FFS_DEACTIVATED;
@@ -1765,8 +1716,6 @@ static struct ffs_data *ffs_data_new(const char *dev_name)
if (!ffs)
return NULL;
- ENTER();
-
ffs->io_completion_wq = alloc_ordered_workqueue("%s", 0, dev_name);
if (!ffs->io_completion_wq) {
kfree(ffs);
@@ -1793,8 +1742,6 @@ static void ffs_data_clear(struct ffs_data *ffs)
struct ffs_epfile *epfiles;
unsigned long flags;
- ENTER();
-
ffs_closed(ffs);
BUG_ON(ffs->gadget);
@@ -1826,8 +1773,6 @@ static void ffs_data_clear(struct ffs_data *ffs)
static void ffs_data_reset(struct ffs_data *ffs)
{
- ENTER();
-
ffs_data_clear(ffs);
ffs->raw_descs_data = NULL;
@@ -1861,8 +1806,6 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
struct usb_gadget_strings **lang;
int first_id;
- ENTER();
-
if (WARN_ON(ffs->state != FFS_ACTIVE
|| test_and_set_bit(FFS_FL_BOUND, &ffs->flags)))
return -EBADFD;
@@ -1894,8 +1837,6 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
static void functionfs_unbind(struct ffs_data *ffs)
{
- ENTER();
-
if (!WARN_ON(!ffs->gadget)) {
/* dequeue before freeing ep0req */
usb_ep_dequeue(ffs->gadget->ep0, ffs->ep0req);
@@ -1914,8 +1855,6 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
struct ffs_epfile *epfile, *epfiles;
unsigned i, count;
- ENTER();
-
count = ffs->eps_count;
epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL);
if (!epfiles)
@@ -1946,8 +1885,6 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
{
struct ffs_epfile *epfile = epfiles;
- ENTER();
-
for (; count; --count, ++epfile) {
BUG_ON(mutex_is_locked(&epfile->mutex));
if (epfile->dentry) {
@@ -2064,8 +2001,6 @@ static int __must_check ffs_do_single_desc(char *data, unsigned len,
u8 length;
int ret;
- ENTER();
-
/* At least two bytes are required: length and type */
if (len < 2) {
pr_vdebug("descriptor too short\n");
@@ -2204,8 +2139,6 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
unsigned long num = 0;
int current_class = -1;
- ENTER();
-
for (;;) {
int ret;
@@ -2243,8 +2176,6 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
struct ffs_desc_helper *helper = priv;
struct usb_endpoint_descriptor *d;
- ENTER();
-
switch (type) {
case FFS_DESCRIPTOR:
break;
@@ -2292,8 +2223,11 @@ static int __ffs_do_os_desc_header(enum ffs_os_desc_type *next_type,
u16 bcd_version = le16_to_cpu(desc->bcdVersion);
u16 w_index = le16_to_cpu(desc->wIndex);
- if (bcd_version != 1) {
- pr_vdebug("unsupported os descriptors version: %d",
+ if (bcd_version == 0x1) {
+ pr_warn("bcdVersion must be 0x0100, stored in Little Endian order. "
+ "Userspace driver should be fixed, accepting 0x0001 for compatibility.\n");
+ } else if (bcd_version != 0x100) {
+ pr_vdebug("unsupported os descriptors version: 0x%x\n",
bcd_version);
return -EINVAL;
}
@@ -2326,8 +2260,6 @@ static int __must_check ffs_do_single_os_desc(char *data, unsigned len,
int ret;
const unsigned _len = len;
- ENTER();
-
/* loop over all ext compat/ext prop descriptors */
while (feature_count--) {
ret = entity(type, h, data, len, priv);
@@ -2349,8 +2281,6 @@ static int __must_check ffs_do_os_descs(unsigned count,
const unsigned _len = len;
unsigned long num = 0;
- ENTER();
-
for (num = 0; num < count; ++num) {
int ret;
enum ffs_os_desc_type type;
@@ -2413,8 +2343,6 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type,
struct ffs_data *ffs = priv;
u8 length;
- ENTER();
-
switch (type) {
case FFS_OS_DESC_EXT_COMPAT: {
struct usb_ext_compat_desc *d = data;
@@ -2490,8 +2418,6 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
int ret = -EINVAL, i;
struct ffs_desc_helper helper;
- ENTER();
-
if (get_unaligned_le32(data + 4) != len)
goto error;
@@ -2622,8 +2548,6 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
const char *data = _data;
struct usb_string *s;
- ENTER();
-
if (len < 16 ||
get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
get_unaligned_le32(data + 4) != len)
@@ -3082,8 +3006,6 @@ static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f,
struct ffs_data *ffs_data;
int ret;
- ENTER();
-
/*
* Legacy gadget triggers binding in functionfs_ready_callback,
* which already uses locking; taking the same lock here would
@@ -3160,8 +3082,6 @@ static int _ffs_func_bind(struct usb_configuration *c,
vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length);
char *vlabuf;
- ENTER();
-
/* Has descriptors only for speeds gadget does not support */
if (!(full | high | super))
return -ENOTSUPP;
@@ -3365,8 +3285,6 @@ static int ffs_func_setup(struct usb_function *f,
unsigned long flags;
int ret;
- ENTER();
-
pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType);
pr_vdebug("creq->bRequest = %02x\n", creq->bRequest);
pr_vdebug("creq->wValue = %04x\n", le16_to_cpu(creq->wValue));
@@ -3441,13 +3359,11 @@ static bool ffs_func_req_match(struct usb_function *f,
static void ffs_func_suspend(struct usb_function *f)
{
- ENTER();
ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND);
}
static void ffs_func_resume(struct usb_function *f)
{
- ENTER();
ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME);
}
@@ -3611,7 +3527,6 @@ static void ffs_func_unbind(struct usb_configuration *c,
unsigned count = ffs->eps_count;
unsigned long flags;
- ENTER();
if (ffs->func == func) {
ffs_func_eps_disable(func);
ffs->func = NULL;
@@ -3651,8 +3566,6 @@ static struct usb_function *ffs_alloc(struct usb_function_instance *fi)
{
struct ffs_function *func;
- ENTER();
-
func = kzalloc(sizeof(*func), GFP_KERNEL);
if (!func)
return ERR_PTR(-ENOMEM);
@@ -3753,7 +3666,6 @@ static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data)
int ret = 0;
struct ffs_dev *ffs_dev;
- ENTER();
ffs_dev_lock();
ffs_dev = _ffs_find_dev(dev_name);
@@ -3776,7 +3688,6 @@ static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data)
static void ffs_release_dev(struct ffs_dev *ffs_dev)
{
- ENTER();
ffs_dev_lock();
if (ffs_dev && ffs_dev->mounted) {
@@ -3798,7 +3709,6 @@ static int ffs_ready(struct ffs_data *ffs)
struct ffs_dev *ffs_obj;
int ret = 0;
- ENTER();
ffs_dev_lock();
ffs_obj = ffs->private_data;
@@ -3831,7 +3741,6 @@ static void ffs_closed(struct ffs_data *ffs)
struct f_fs_opts *opts;
struct config_item *ci;
- ENTER();
ffs_dev_lock();
ffs_obj = ffs->private_data;
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index f259975dfba4..6956ad8ba8dd 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -437,6 +437,20 @@ static inline int is_promisc(u16 cdc_filter)
return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
}
+static int ether_wakeup_host(struct gether *port)
+{
+ int ret;
+ struct usb_function *func = &port->func;
+ struct usb_gadget *gadget = func->config->cdev->gadget;
+
+ if (func->func_suspended)
+ ret = usb_func_wakeup(func);
+ else
+ ret = usb_gadget_wakeup(gadget);
+
+ return ret;
+}
+
static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
struct net_device *net)
{
@@ -456,6 +470,15 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
in = NULL;
cdc_filter = 0;
}
+
+ if (dev->port_usb && dev->port_usb->is_suspend) {
+ DBG(dev, "Port suspended. Triggering wakeup\n");
+ netif_stop_queue(net);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ ether_wakeup_host(dev->port_usb);
+ return NETDEV_TX_BUSY;
+ }
+
spin_unlock_irqrestore(&dev->lock, flags);
if (!in) {
@@ -1014,6 +1037,45 @@ int gether_set_ifname(struct net_device *net, const char *name, int len)
}
EXPORT_SYMBOL_GPL(gether_set_ifname);
+void gether_suspend(struct gether *link)
+{
+ struct eth_dev *dev = link->ioport;
+ unsigned long flags;
+
+ if (!dev)
+ return;
+
+ if (atomic_read(&dev->tx_qlen)) {
+ /*
+ * There is a transfer in progress. So we trigger a remote
+ * wakeup to inform the host.
+ */
+ ether_wakeup_host(dev->port_usb);
+ return;
+ }
+ spin_lock_irqsave(&dev->lock, flags);
+ link->is_suspend = true;
+ spin_unlock_irqrestore(&dev->lock, flags);
+}
+EXPORT_SYMBOL_GPL(gether_suspend);
+
+void gether_resume(struct gether *link)
+{
+ struct eth_dev *dev = link->ioport;
+ unsigned long flags;
+
+ if (!dev)
+ return;
+
+ if (netif_queue_stopped(dev->net))
+ netif_start_queue(dev->net);
+
+ spin_lock_irqsave(&dev->lock, flags);
+ link->is_suspend = false;
+ spin_unlock_irqrestore(&dev->lock, flags);
+}
+EXPORT_SYMBOL_GPL(gether_resume);
+
/*
* gether_cleanup - remove Ethernet-over-USB device
* Context: may sleep
@@ -1176,6 +1238,7 @@ void gether_disconnect(struct gether *link)
spin_lock(&dev->lock);
dev->port_usb = NULL;
+ link->is_suspend = false;
spin_unlock(&dev->lock);
}
EXPORT_SYMBOL_GPL(gether_disconnect);
diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h
index 40144546d1b0..851ee10d6e63 100644
--- a/drivers/usb/gadget/function/u_ether.h
+++ b/drivers/usb/gadget/function/u_ether.h
@@ -79,6 +79,7 @@ struct gether {
/* called on network open/close */
void (*open)(struct gether *);
void (*close)(struct gether *);
+ bool is_suspend;
};
#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \
@@ -258,6 +259,9 @@ int gether_set_ifname(struct net_device *net, const char *name, int len);
void gether_cleanup(struct eth_dev *dev);
+void gether_suspend(struct gether *link);
+void gether_resume(struct gether *link);
+
/* connect/disconnect is handled by individual functions */
struct net_device *gether_connect(struct gether *);
void gether_disconnect(struct gether *);
diff --git a/drivers/usb/gadget/function/u_fs.h b/drivers/usb/gadget/function/u_fs.h
index f102ec23f3af..4b3365f23fd7 100644
--- a/drivers/usb/gadget/function/u_fs.h
+++ b/drivers/usb/gadget/function/u_fs.h
@@ -32,8 +32,6 @@
# define ffs_dump_mem(prefix, ptr, len) do { } while (0)
#endif /* VERBOSE_DEBUG */
-#define ENTER() pr_vdebug("%s()\n", __func__)
-
struct f_fs_opts;
struct ffs_dev {
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index 62b759bb7613..9bf0e985acfa 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -334,6 +334,64 @@ UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, 8);
#undef UVCG_DEFAULT_PROCESSING_ATTR
+static ssize_t uvcg_default_processing_bm_controls_store(
+ struct config_item *item, const char *page, size_t len)
+{
+ struct config_group *group = to_config_group(item);
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex;
+ struct uvc_processing_unit_descriptor *pd;
+ struct config_item *opts_item;
+ struct f_uvc_opts *opts;
+ u8 *bm_controls, *tmp;
+ unsigned int i;
+ int ret, n = 0;
+
+ mutex_lock(su_mutex);
+
+ opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+ pd = &opts->uvc_processing;
+
+ mutex_lock(&opts->lock);
+ if (opts->refcnt) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ ret = __uvcg_iter_item_entries(page, len, __uvcg_count_item_entries, &n,
+ sizeof(u8));
+ if (ret)
+ goto unlock;
+
+ if (n > pd->bControlSize) {
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ tmp = bm_controls = kcalloc(n, sizeof(u8), GFP_KERNEL);
+ if (!bm_controls) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ ret = __uvcg_iter_item_entries(page, len, __uvcg_fill_item_entries, &tmp,
+ sizeof(u8));
+ if (ret)
+ goto free_mem;
+
+ for (i = 0; i < n; i++)
+ pd->bmControls[i] = bm_controls[i];
+
+ ret = len;
+
+free_mem:
+ kfree(bm_controls);
+unlock:
+ mutex_unlock(&opts->lock);
+ mutex_unlock(su_mutex);
+ return ret;
+}
+
static ssize_t uvcg_default_processing_bm_controls_show(
struct config_item *item, char *page)
{
@@ -363,7 +421,7 @@ static ssize_t uvcg_default_processing_bm_controls_show(
return result;
}
-UVC_ATTR_RO(uvcg_default_processing_, bm_controls, bmControls);
+UVC_ATTR(uvcg_default_processing_, bm_controls, bmControls);
static struct configfs_attribute *uvcg_default_processing_attrs[] = {
&uvcg_default_processing_attr_b_unit_id,
@@ -445,6 +503,65 @@ UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength,
#undef UVCG_DEFAULT_CAMERA_ATTR
+static ssize_t uvcg_default_camera_bm_controls_store(
+ struct config_item *item, const char *page, size_t len)
+{
+ struct config_group *group = to_config_group(item);
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex;
+ struct uvc_camera_terminal_descriptor *cd;
+ struct config_item *opts_item;
+ struct f_uvc_opts *opts;
+ u8 *bm_controls, *tmp;
+ unsigned int i;
+ int ret, n = 0;
+
+ mutex_lock(su_mutex);
+
+ opts_item = group->cg_item.ci_parent->ci_parent->ci_parent->
+ ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+ cd = &opts->uvc_camera_terminal;
+
+ mutex_lock(&opts->lock);
+ if (opts->refcnt) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ ret = __uvcg_iter_item_entries(page, len, __uvcg_count_item_entries, &n,
+ sizeof(u8));
+ if (ret)
+ goto unlock;
+
+ if (n > cd->bControlSize) {
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ tmp = bm_controls = kcalloc(n, sizeof(u8), GFP_KERNEL);
+ if (!bm_controls) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ ret = __uvcg_iter_item_entries(page, len, __uvcg_fill_item_entries, &tmp,
+ sizeof(u8));
+ if (ret)
+ goto free_mem;
+
+ for (i = 0; i < n; i++)
+ cd->bmControls[i] = bm_controls[i];
+
+ ret = len;
+
+free_mem:
+ kfree(bm_controls);
+unlock:
+ mutex_unlock(&opts->lock);
+ mutex_unlock(su_mutex);
+ return ret;
+}
+
static ssize_t uvcg_default_camera_bm_controls_show(
struct config_item *item, char *page)
{
@@ -474,7 +591,7 @@ static ssize_t uvcg_default_camera_bm_controls_show(
return result;
}
-UVC_ATTR_RO(uvcg_default_camera_, bm_controls, bmControls);
+UVC_ATTR(uvcg_default_camera_, bm_controls, bmControls);
static struct configfs_attribute *uvcg_default_camera_attrs[] = {
&uvcg_default_camera_attr_b_terminal_id,
diff --git a/drivers/usb/gadget/legacy/g_ffs.c b/drivers/usb/gadget/legacy/g_ffs.c
index ae6d8f7092b8..097854683e5b 100644
--- a/drivers/usb/gadget/legacy/g_ffs.c
+++ b/drivers/usb/gadget/legacy/g_ffs.c
@@ -180,8 +180,6 @@ static int __init gfs_init(void)
int i;
int ret = 0;
- ENTER();
-
if (func_num < 2) {
gfs_single_func = true;
func_num = 1;
@@ -242,8 +240,6 @@ static void __exit gfs_exit(void)
{
int i;
- ENTER();
-
if (gfs_registered)
usb_composite_unregister(&gfs_driver);
gfs_registered = false;
@@ -316,8 +312,6 @@ static int gfs_bind(struct usb_composite_dev *cdev)
#endif
int ret, i;
- ENTER();
-
if (missing_funcs)
return -ENODEV;
#if defined CONFIG_USB_FUNCTIONFS_ETH
@@ -445,9 +439,6 @@ static int gfs_unbind(struct usb_composite_dev *cdev)
{
int i;
- ENTER();
-
-
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
usb_put_function(f_rndis);
usb_put_function_instance(fi_rndis);
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/aspeed-vhub/core.c
index ac3ca24f8b04..86398a04a012 100644
--- a/drivers/usb/gadget/udc/aspeed-vhub/core.c
+++ b/drivers/usb/gadget/udc/aspeed-vhub/core.c
@@ -21,7 +21,6 @@
#include <linux/clk.h>
#include <linux/usb/gadget.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c
index 4f3bc27c1c62..573109ca5b79 100644
--- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c
+++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c
@@ -21,7 +21,6 @@
#include <linux/clk.h>
#include <linux/usb/gadget.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/dma-mapping.h>
#include <linux/usb.h>
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/ep0.c b/drivers/usb/gadget/udc/aspeed-vhub/ep0.c
index b4cf46249fea..e9aa74231760 100644
--- a/drivers/usb/gadget/udc/aspeed-vhub/ep0.c
+++ b/drivers/usb/gadget/udc/aspeed-vhub/ep0.c
@@ -21,7 +21,6 @@
#include <linux/clk.h>
#include <linux/usb/gadget.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/aspeed-vhub/epn.c
index 56e55472daa1..148d7ec3ebf4 100644
--- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c
+++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c
@@ -21,7 +21,6 @@
#include <linux/clk.h>
#include <linux/usb/gadget.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/hub.c b/drivers/usb/gadget/udc/aspeed-vhub/hub.c
index e2207d014620..a63e4af60a56 100644
--- a/drivers/usb/gadget/udc/aspeed-vhub/hub.c
+++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c
@@ -21,7 +21,6 @@
#include <linux/clk.h>
#include <linux/usb/gadget.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/dma-mapping.h>
#include <linux/bcd.h>
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 23b0629a8774..1c5403ce9e7c 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -37,6 +37,10 @@ static struct bus_type gadget_bus_type;
* @vbus: for udcs who care about vbus status, this value is real vbus status;
* for udcs who do not care about vbus status, this value is always true
* @started: the UDC's started state. True if the UDC had started.
+ * @connect_lock: protects udc->vbus, udc->started, gadget->connect, gadget->deactivate related
+ * functions. usb_gadget_connect_locked, usb_gadget_disconnect_locked,
+ * usb_udc_connect_control_locked, usb_gadget_udc_start_locked, usb_gadget_udc_stop_locked are
+ * called with this lock held.
*
* This represents the internal data structure which is used by the UDC-class
* to hold information about udc driver and gadget together.
@@ -48,6 +52,7 @@ struct usb_udc {
struct list_head list;
bool vbus;
bool started;
+ struct mutex connect_lock;
};
static struct class *udc_class;
@@ -514,6 +519,33 @@ out:
EXPORT_SYMBOL_GPL(usb_gadget_wakeup);
/**
+ * usb_gadget_set_remote_wakeup - configures the device remote wakeup feature.
+ * @gadget:the device being configured for remote wakeup
+ * @set:value to be configured.
+ *
+ * set to one to enable remote wakeup feature and zero to disable it.
+ *
+ * returns zero on success, else negative errno.
+ */
+int usb_gadget_set_remote_wakeup(struct usb_gadget *gadget, int set)
+{
+ int ret = 0;
+
+ if (!gadget->ops->set_remote_wakeup) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ ret = gadget->ops->set_remote_wakeup(gadget, set);
+
+out:
+ trace_usb_gadget_set_remote_wakeup(gadget, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_set_remote_wakeup);
+
+/**
* usb_gadget_set_selfpowered - sets the device selfpowered feature.
* @gadget:the device being declared as self-powered
*
@@ -660,17 +692,9 @@ out:
}
EXPORT_SYMBOL_GPL(usb_gadget_vbus_disconnect);
-/**
- * usb_gadget_connect - software-controlled connect to USB host
- * @gadget:the peripheral being connected
- *
- * Enables the D+ (or potentially D-) pullup. The host will start
- * enumerating this gadget when the pullup is active and a VBUS session
- * is active (the link is powered).
- *
- * Returns zero on success, else negative errno.
- */
-int usb_gadget_connect(struct usb_gadget *gadget)
+/* Internal version of usb_gadget_connect needs to be called with connect_lock held. */
+static int usb_gadget_connect_locked(struct usb_gadget *gadget)
+ __must_hold(&gadget->udc->connect_lock)
{
int ret = 0;
@@ -679,10 +703,15 @@ int usb_gadget_connect(struct usb_gadget *gadget)
goto out;
}
- if (gadget->deactivated) {
+ if (gadget->connected)
+ goto out;
+
+ if (gadget->deactivated || !gadget->udc->started) {
/*
* If gadget is deactivated we only save new state.
* Gadget will be connected automatically after activation.
+ *
+ * udc first needs to be started before gadget can be pulled up.
*/
gadget->connected = true;
goto out;
@@ -697,22 +726,32 @@ out:
return ret;
}
-EXPORT_SYMBOL_GPL(usb_gadget_connect);
/**
- * usb_gadget_disconnect - software-controlled disconnect from USB host
- * @gadget:the peripheral being disconnected
- *
- * Disables the D+ (or potentially D-) pullup, which the host may see
- * as a disconnect (when a VBUS session is active). Not all systems
- * support software pullup controls.
+ * usb_gadget_connect - software-controlled connect to USB host
+ * @gadget:the peripheral being connected
*
- * Following a successful disconnect, invoke the ->disconnect() callback
- * for the current gadget driver so that UDC drivers don't need to.
+ * Enables the D+ (or potentially D-) pullup. The host will start
+ * enumerating this gadget when the pullup is active and a VBUS session
+ * is active (the link is powered).
*
* Returns zero on success, else negative errno.
*/
-int usb_gadget_disconnect(struct usb_gadget *gadget)
+int usb_gadget_connect(struct usb_gadget *gadget)
+{
+ int ret;
+
+ mutex_lock(&gadget->udc->connect_lock);
+ ret = usb_gadget_connect_locked(gadget);
+ mutex_unlock(&gadget->udc->connect_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_connect);
+
+/* Internal version of usb_gadget_disconnect needs to be called with connect_lock held. */
+static int usb_gadget_disconnect_locked(struct usb_gadget *gadget)
+ __must_hold(&gadget->udc->connect_lock)
{
int ret = 0;
@@ -724,10 +763,12 @@ int usb_gadget_disconnect(struct usb_gadget *gadget)
if (!gadget->connected)
goto out;
- if (gadget->deactivated) {
+ if (gadget->deactivated || !gadget->udc->started) {
/*
* If gadget is deactivated we only save new state.
* Gadget will stay disconnected after activation.
+ *
+ * udc should have been started before gadget being pulled down.
*/
gadget->connected = false;
goto out;
@@ -747,6 +788,30 @@ out:
return ret;
}
+
+/**
+ * usb_gadget_disconnect - software-controlled disconnect from USB host
+ * @gadget:the peripheral being disconnected
+ *
+ * Disables the D+ (or potentially D-) pullup, which the host may see
+ * as a disconnect (when a VBUS session is active). Not all systems
+ * support software pullup controls.
+ *
+ * Following a successful disconnect, invoke the ->disconnect() callback
+ * for the current gadget driver so that UDC drivers don't need to.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_gadget_disconnect(struct usb_gadget *gadget)
+{
+ int ret;
+
+ mutex_lock(&gadget->udc->connect_lock);
+ ret = usb_gadget_disconnect_locked(gadget);
+ mutex_unlock(&gadget->udc->connect_lock);
+
+ return ret;
+}
EXPORT_SYMBOL_GPL(usb_gadget_disconnect);
/**
@@ -767,10 +832,11 @@ int usb_gadget_deactivate(struct usb_gadget *gadget)
if (gadget->deactivated)
goto out;
+ mutex_lock(&gadget->udc->connect_lock);
if (gadget->connected) {
- ret = usb_gadget_disconnect(gadget);
+ ret = usb_gadget_disconnect_locked(gadget);
if (ret)
- goto out;
+ goto unlock;
/*
* If gadget was being connected before deactivation, we want
@@ -780,6 +846,8 @@ int usb_gadget_deactivate(struct usb_gadget *gadget)
}
gadget->deactivated = true;
+unlock:
+ mutex_unlock(&gadget->udc->connect_lock);
out:
trace_usb_gadget_deactivate(gadget, ret);
@@ -803,6 +871,7 @@ int usb_gadget_activate(struct usb_gadget *gadget)
if (!gadget->deactivated)
goto out;
+ mutex_lock(&gadget->udc->connect_lock);
gadget->deactivated = false;
/*
@@ -810,7 +879,8 @@ int usb_gadget_activate(struct usb_gadget *gadget)
* while it was being deactivated, we call usb_gadget_connect().
*/
if (gadget->connected)
- ret = usb_gadget_connect(gadget);
+ ret = usb_gadget_connect_locked(gadget);
+ mutex_unlock(&gadget->udc->connect_lock);
out:
trace_usb_gadget_activate(gadget, ret);
@@ -1051,12 +1121,13 @@ EXPORT_SYMBOL_GPL(usb_gadget_set_state);
/* ------------------------------------------------------------------------- */
-static void usb_udc_connect_control(struct usb_udc *udc)
+/* Acquire connect_lock before calling this function. */
+static void usb_udc_connect_control_locked(struct usb_udc *udc) __must_hold(&udc->connect_lock)
{
- if (udc->vbus)
- usb_gadget_connect(udc->gadget);
+ if (udc->vbus && udc->started)
+ usb_gadget_connect_locked(udc->gadget);
else
- usb_gadget_disconnect(udc->gadget);
+ usb_gadget_disconnect_locked(udc->gadget);
}
/**
@@ -1072,10 +1143,12 @@ void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status)
{
struct usb_udc *udc = gadget->udc;
+ mutex_lock(&udc->connect_lock);
if (udc) {
udc->vbus = status;
- usb_udc_connect_control(udc);
+ usb_udc_connect_control_locked(udc);
}
+ mutex_unlock(&udc->connect_lock);
}
EXPORT_SYMBOL_GPL(usb_udc_vbus_handler);
@@ -1097,7 +1170,7 @@ void usb_gadget_udc_reset(struct usb_gadget *gadget,
EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
/**
- * usb_gadget_udc_start - tells usb device controller to start up
+ * usb_gadget_udc_start_locked - tells usb device controller to start up
* @udc: The UDC to be started
*
* This call is issued by the UDC Class driver when it's about
@@ -1108,8 +1181,11 @@ EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
* necessary to have it powered on.
*
* Returns zero on success, else negative errno.
+ *
+ * Caller should acquire connect_lock before invoking this function.
*/
-static inline int usb_gadget_udc_start(struct usb_udc *udc)
+static inline int usb_gadget_udc_start_locked(struct usb_udc *udc)
+ __must_hold(&udc->connect_lock)
{
int ret;
@@ -1126,7 +1202,7 @@ static inline int usb_gadget_udc_start(struct usb_udc *udc)
}
/**
- * usb_gadget_udc_stop - tells usb device controller we don't need it anymore
+ * usb_gadget_udc_stop_locked - tells usb device controller we don't need it anymore
* @udc: The UDC to be stopped
*
* This call is issued by the UDC Class driver after calling
@@ -1135,8 +1211,11 @@ static inline int usb_gadget_udc_start(struct usb_udc *udc)
* The details are implementation specific, but it can go as
* far as powering off UDC completely and disable its data
* line pullups.
+ *
+ * Caller should acquire connect lock before invoking this function.
*/
-static inline void usb_gadget_udc_stop(struct usb_udc *udc)
+static inline void usb_gadget_udc_stop_locked(struct usb_udc *udc)
+ __must_hold(&udc->connect_lock)
{
if (!udc->started) {
dev_err(&udc->dev, "UDC had already stopped\n");
@@ -1295,6 +1374,7 @@ int usb_add_gadget(struct usb_gadget *gadget)
udc->gadget = gadget;
gadget->udc = udc;
+ mutex_init(&udc->connect_lock);
udc->started = false;
@@ -1496,11 +1576,15 @@ static int gadget_bind_driver(struct device *dev)
if (ret)
goto err_bind;
- ret = usb_gadget_udc_start(udc);
- if (ret)
+ mutex_lock(&udc->connect_lock);
+ ret = usb_gadget_udc_start_locked(udc);
+ if (ret) {
+ mutex_unlock(&udc->connect_lock);
goto err_start;
+ }
usb_gadget_enable_async_callbacks(udc);
- usb_udc_connect_control(udc);
+ usb_udc_connect_control_locked(udc);
+ mutex_unlock(&udc->connect_lock);
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
return 0;
@@ -1531,12 +1615,14 @@ static void gadget_unbind_driver(struct device *dev)
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
- usb_gadget_disconnect(gadget);
+ mutex_lock(&udc->connect_lock);
+ usb_gadget_disconnect_locked(gadget);
usb_gadget_disable_async_callbacks(udc);
if (gadget->irq)
synchronize_irq(gadget->irq);
udc->driver->unbind(gadget);
- usb_gadget_udc_stop(udc);
+ usb_gadget_udc_stop_locked(udc);
+ mutex_unlock(&udc->connect_lock);
mutex_lock(&udc_lock);
driver->is_bound = false;
@@ -1622,11 +1708,15 @@ static ssize_t soft_connect_store(struct device *dev,
}
if (sysfs_streq(buf, "connect")) {
- usb_gadget_udc_start(udc);
- usb_gadget_connect(udc->gadget);
+ mutex_lock(&udc->connect_lock);
+ usb_gadget_udc_start_locked(udc);
+ usb_gadget_connect_locked(udc->gadget);
+ mutex_unlock(&udc->connect_lock);
} else if (sysfs_streq(buf, "disconnect")) {
- usb_gadget_disconnect(udc->gadget);
- usb_gadget_udc_stop(udc);
+ mutex_lock(&udc->connect_lock);
+ usb_gadget_disconnect_locked(udc->gadget);
+ usb_gadget_udc_stop_locked(udc);
+ mutex_unlock(&udc->connect_lock);
} else {
dev_err(dev, "unsupported command '%s'\n", buf);
ret = -EINVAL;
diff --git a/drivers/usb/gadget/udc/max3420_udc.c b/drivers/usb/gadget/udc/max3420_udc.c
index ddf0ed3eb4f2..12c519f32bf7 100644
--- a/drivers/usb/gadget/udc/max3420_udc.c
+++ b/drivers/usb/gadget/udc/max3420_udc.c
@@ -1319,7 +1319,7 @@ MODULE_DEVICE_TABLE(of, max3420_udc_of_match);
static struct spi_driver max3420_driver = {
.driver = {
.name = "max3420-udc",
- .of_match_table = of_match_ptr(max3420_udc_of_match),
+ .of_match_table = max3420_udc_of_match,
},
.probe = max3420_probe,
.remove = max3420_remove,
diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c
index b397f3a848cf..08474c08d874 100644
--- a/drivers/usb/gadget/udc/mv_udc_core.c
+++ b/drivers/usb/gadget/udc/mv_udc_core.c
@@ -2229,7 +2229,11 @@ static int mv_udc_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&udc->status_req->queue);
/* allocate a small amount of memory to get valid address */
- udc->status_req->req.buf = kzalloc(8, GFP_KERNEL);
+ udc->status_req->req.buf = devm_kzalloc(&pdev->dev, 8, GFP_KERNEL);
+ if (!udc->status_req->req.buf) {
+ retval = -ENOMEM;
+ goto err_destroy_dma;
+ }
udc->status_req->req.dma = DMA_ADDR_INVALID;
udc->resume_state = USB_STATE_NOTATTACHED;
diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
index bee6bceafc4f..aac8bc185afa 100644
--- a/drivers/usb/gadget/udc/renesas_usb3.c
+++ b/drivers/usb/gadget/udc/renesas_usb3.c
@@ -22,7 +22,6 @@
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/string.h>
-#include <linux/sys_soc.h>
#include <linux/uaccess.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@@ -2661,6 +2660,7 @@ static int renesas_usb3_remove(struct platform_device *pdev)
debugfs_remove_recursive(usb3->dentry);
device_remove_file(&pdev->dev, &dev_attr_role);
+ cancel_work_sync(&usb3->role_work);
usb_role_switch_unregister(usb3->role_sw);
usb_del_gadget_udc(&usb3->gadget);
@@ -2781,13 +2781,6 @@ static void renesas_usb3_init_ram(struct renesas_usb3 *usb3, struct device *dev,
}
}
-static const struct renesas_usb3_priv renesas_usb3_priv_r8a7795_es1 = {
- .ramsize_per_ramif = SZ_16K,
- .num_ramif = 2,
- .ramsize_per_pipe = SZ_4K,
- .workaround_for_vbus = true,
-};
-
static const struct renesas_usb3_priv renesas_usb3_priv_gen3 = {
.ramsize_per_ramif = SZ_16K,
.num_ramif = 4,
@@ -2829,14 +2822,6 @@ static const struct of_device_id usb3_of_match[] = {
};
MODULE_DEVICE_TABLE(of, usb3_of_match);
-static const struct soc_device_attribute renesas_usb3_quirks_match[] = {
- {
- .soc_id = "r8a7795", .revision = "ES1.*",
- .data = &renesas_usb3_priv_r8a7795_es1,
- },
- { /* sentinel */ }
-};
-
static const unsigned int renesas_usb3_cable[] = {
EXTCON_USB,
EXTCON_USB_HOST,
@@ -2854,13 +2839,8 @@ static int renesas_usb3_probe(struct platform_device *pdev)
struct renesas_usb3 *usb3;
int irq, ret;
const struct renesas_usb3_priv *priv;
- const struct soc_device_attribute *attr;
- attr = soc_device_match(renesas_usb3_quirks_match);
- if (attr)
- priv = attr->data;
- else
- priv = of_device_get_match_data(&pdev->dev);
+ priv = of_device_get_match_data(&pdev->dev);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
@@ -3039,7 +3019,7 @@ static struct platform_driver renesas_usb3_driver = {
.driver = {
.name = udc_name,
.pm = &renesas_usb3_pm_ops,
- .of_match_table = of_match_ptr(usb3_of_match),
+ .of_match_table = usb3_of_match,
},
};
module_platform_driver(renesas_usb3_driver);
diff --git a/drivers/usb/gadget/udc/renesas_usbf.c b/drivers/usb/gadget/udc/renesas_usbf.c
index cb23e62e8a87..84ac9fe4ce7f 100644
--- a/drivers/usb/gadget/udc/renesas_usbf.c
+++ b/drivers/usb/gadget/udc/renesas_usbf.c
@@ -545,17 +545,6 @@ static inline void usbf_ep_dma_reg_bitclr(struct usbf_ep *ep, uint offset,
usbf_ep_dma_reg_writel(ep, offset, tmp);
}
-static inline void usbf_ep_dma_reg_clrset(struct usbf_ep *ep, uint offset,
- u32 clr, u32 set)
-{
- u32 tmp;
-
- tmp = usbf_ep_dma_reg_readl(ep, offset);
- tmp &= ~clr;
- tmp |= set;
- usbf_ep_dma_reg_writel(ep, offset, tmp);
-}
-
static void usbf_ep0_send_null(struct usbf_ep *ep0, bool is_data1)
{
u32 set;
diff --git a/drivers/usb/gadget/udc/rzv2m_usb3drd.c b/drivers/usb/gadget/udc/rzv2m_usb3drd.c
index 3c8bbf843038..589c7252e014 100644
--- a/drivers/usb/gadget/udc/rzv2m_usb3drd.c
+++ b/drivers/usb/gadget/udc/rzv2m_usb3drd.c
@@ -6,7 +6,7 @@
*/
#include <linux/io.h>
-#include <linux/of_device.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
@@ -126,7 +126,7 @@ MODULE_DEVICE_TABLE(of, rzv2m_usb3drd_of_match);
static struct platform_driver rzv2m_usb3drd_driver = {
.driver = {
.name = "rzv2m-usb3drd",
- .of_match_table = of_match_ptr(rzv2m_usb3drd_of_match),
+ .of_match_table = rzv2m_usb3drd_of_match,
},
.probe = rzv2m_usb3drd_probe,
.remove = rzv2m_usb3drd_remove,
diff --git a/drivers/usb/gadget/udc/snps_udc_plat.c b/drivers/usb/gadget/udc/snps_udc_plat.c
index 8bbb89c80348..0d3e705655b9 100644
--- a/drivers/usb/gadget/udc/snps_udc_plat.c
+++ b/drivers/usb/gadget/udc/snps_udc_plat.c
@@ -158,7 +158,7 @@ static int udc_plat_probe(struct platform_device *pdev)
}
/* Register for extcon if supported */
- if (of_get_property(dev->of_node, "extcon", NULL)) {
+ if (of_property_present(dev->of_node, "extcon")) {
udc->edev = extcon_get_edev_by_phandle(dev, 0);
if (IS_ERR(udc->edev)) {
if (PTR_ERR(udc->edev) == -EPROBE_DEFER)
diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c
index 2b71b33725f1..34e9c1df54c7 100644
--- a/drivers/usb/gadget/udc/tegra-xudc.c
+++ b/drivers/usb/gadget/udc/tegra-xudc.c
@@ -2162,15 +2162,14 @@ static int tegra_xudc_gadget_stop(struct usb_gadget *gadget)
static int tegra_xudc_gadget_vbus_draw(struct usb_gadget *gadget,
unsigned int m_a)
{
- int ret = 0;
struct tegra_xudc *xudc = to_xudc(gadget);
dev_dbg(xudc->dev, "%s: %u mA\n", __func__, m_a);
- if (xudc->curr_usbphy->chg_type == SDP_TYPE)
- ret = usb_phy_set_power(xudc->curr_usbphy, m_a);
+ if (xudc->curr_usbphy && xudc->curr_usbphy->chg_type == SDP_TYPE)
+ return usb_phy_set_power(xudc->curr_usbphy, m_a);
- return ret;
+ return 0;
}
static int tegra_xudc_set_selfpowered(struct usb_gadget *gadget, int is_on)
diff --git a/drivers/usb/gadget/udc/trace.h b/drivers/usb/gadget/udc/trace.h
index abdbcb1bacb0..a5ed26fbc2da 100644
--- a/drivers/usb/gadget/udc/trace.h
+++ b/drivers/usb/gadget/udc/trace.h
@@ -91,6 +91,11 @@ DEFINE_EVENT(udc_log_gadget, usb_gadget_wakeup,
TP_ARGS(g, ret)
);
+DEFINE_EVENT(udc_log_gadget, usb_gadget_set_remote_wakeup,
+ TP_PROTO(struct usb_gadget *g, int ret),
+ TP_ARGS(g, ret)
+);
+
DEFINE_EVENT(udc_log_gadget, usb_gadget_set_selfpowered,
TP_PROTO(struct usb_gadget *g, int ret),
TP_ARGS(g, ret)
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index eacb603ad1b2..c170672f847e 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -622,33 +622,6 @@ config FHCI_DEBUG
Say "y" to see some FHCI debug information and statistics
through debugfs.
-config USB_U132_HCD
- tristate "Elan U132 Adapter Host Controller"
- depends on USB_FTDI_ELAN
- help
- The U132 adapter is a USB to CardBus adapter specifically designed
- for PC cards that contain an OHCI host controller. Typical PC cards
- are the Orange Mobile 3G Option GlobeTrotter Fusion card. The U132
- adapter will *NOT* work with PC cards that do not contain an OHCI
- controller.
-
- For those PC cards that contain multiple OHCI controllers only the
- first one is used.
-
- The driver consists of two modules, the "ftdi-elan" module is a
- USB client driver that interfaces to the FTDI chip within ELAN's
- USB-to-PCMCIA adapter, and this "u132-hcd" module is a USB host
- controller driver that talks to the OHCI controller within the
- CardBus cards that are inserted in the U132 adapter.
-
- This driver has been tested with a CardBus OHCI USB adapter, and
- worked with a USB PEN Drive inserted into the first USB port of
- the PCCARD. A rather pointless thing to do, but useful for testing.
-
- It is safe to say M here.
-
- See also <http://www.elandigitalsystems.com/support/ufaq/u132linux.php>
-
config USB_SL811_HCD
tristate "SL811HS HCD support"
depends on HAS_IOMEM
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 5a13712f367d..be4e5245c52f 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -76,7 +76,6 @@ obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk-hcd.o
obj-$(CONFIG_USB_XHCI_TEGRA) += xhci-tegra.o
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
-obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
obj-$(CONFIG_USB_FSL_USB2) += fsl-mph-dr-of.o
obj-$(CONFIG_USB_EHCI_FSL) += fsl-mph-dr-of.o
diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
index 62a0a193798c..b3aa464e9d2c 100644
--- a/drivers/usb/host/ehci-ppc-of.c
+++ b/drivers/usb/host/ehci-ppc-of.c
@@ -151,13 +151,13 @@ static int ehci_hcd_ppc_of_probe(struct platform_device *op)
of_node_put(np);
}
- if (of_get_property(dn, "big-endian", NULL)) {
+ if (of_property_read_bool(dn, "big-endian")) {
ehci->big_endian_mmio = 1;
ehci->big_endian_desc = 1;
}
- if (of_get_property(dn, "big-endian-regs", NULL))
+ if (of_property_read_bool(dn, "big-endian-regs"))
ehci->big_endian_mmio = 1;
- if (of_get_property(dn, "big-endian-desc", NULL))
+ if (of_property_read_bool(dn, "big-endian-desc"))
ehci->big_endian_desc = 1;
ehci->caps = hcd->regs;
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index 46c6a152b865..9db909d12354 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -200,19 +200,16 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev)
dev_data = get_dr_mode_data(np);
if (of_device_is_compatible(np, "fsl-usb2-mph")) {
- if (of_get_property(np, "port0", NULL))
+ if (of_property_present(np, "port0"))
pdata->port_enables |= FSL_USB2_PORT0_ENABLED;
- if (of_get_property(np, "port1", NULL))
+ if (of_property_present(np, "port1"))
pdata->port_enables |= FSL_USB2_PORT1_ENABLED;
pdata->operating_mode = FSL_USB2_MPH_HOST;
} else {
- if (of_get_property(np, "fsl,invert-drvvbus", NULL))
- pdata->invert_drvvbus = 1;
-
- if (of_get_property(np, "fsl,invert-pwr-fault", NULL))
- pdata->invert_pwr_fault = 1;
+ pdata->invert_drvvbus = of_property_read_bool(np, "fsl,invert-drvvbus");
+ pdata->invert_pwr_fault = of_property_read_bool(np, "fsl,invert-pwr-fault");
/* setup mode selected in the device tree */
pdata->operating_mode = dev_data->op_mode;
diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c
index 28d1524ee2fa..d152d72de126 100644
--- a/drivers/usb/host/max3421-hcd.c
+++ b/drivers/usb/host/max3421-hcd.c
@@ -1951,7 +1951,7 @@ static struct spi_driver max3421_driver = {
.remove = max3421_remove,
.driver = {
.name = "max3421-hcd",
- .of_match_table = of_match_ptr(max3421_of_match_table),
+ .of_match_table = max3421_of_match_table,
},
};
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index 3a441310c713..f998d3f1a78a 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -169,7 +169,7 @@ struct ehci_regs {
#define FLAG_CF (1<<0) /* true: we'll support "high speed" */
/* PORTSC: offset 0x44 */
- u32 port_status[0]; /* up to N_PORTS */
+ u32 port_status[]; /* up to N_PORTS */
/* 31:23 reserved */
#define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */
#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index ef08d68b9714..2665832f9add 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -207,8 +207,7 @@ EXPORT_SYMBOL_GPL(sb800_prefetch);
static void usb_amd_find_chipset_info(void)
{
unsigned long flags;
- struct amd_chipset_info info;
- info.need_pll_quirk = false;
+ struct amd_chipset_info info = { };
spin_lock_irqsave(&amd_lock, flags);
@@ -218,7 +217,6 @@ static void usb_amd_find_chipset_info(void)
spin_unlock_irqrestore(&amd_lock, flags);
return;
}
- memset(&info, 0, sizeof(info));
spin_unlock_irqrestore(&amd_lock, flags);
if (!amd_chipset_sb_type_init(&info)) {
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
deleted file mode 100644
index 95240c9c45bd..000000000000
--- a/drivers/usb/host/u132-hcd.c
+++ /dev/null
@@ -1,3219 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
-* Host Controller Driver for the Elan Digital Systems U132 adapter
-*
-* Copyright(C) 2006 Elan Digital Systems Limited
-* http://www.elandigitalsystems.com
-*
-* Author and Maintainer - Tony Olech - Elan Digital Systems
-* tony.olech@elandigitalsystems.com
-*
-* This driver was written by Tony Olech(tony.olech@elandigitalsystems.com)
-* based on various USB host drivers in the 2.6.15 linux kernel
-* with constant reference to the 3rd Edition of Linux Device Drivers
-* published by O'Reilly
-*
-* The U132 adapter is a USB to CardBus adapter specifically designed
-* for PC cards that contain an OHCI host controller. Typical PC cards
-* are the Orange Mobile 3G Option GlobeTrotter Fusion card.
-*
-* The U132 adapter will *NOT *work with PC cards that do not contain
-* an OHCI controller. A simple way to test whether a PC card has an
-* OHCI controller as an interface is to insert the PC card directly
-* into a laptop(or desktop) with a CardBus slot and if "lspci" shows
-* a new USB controller and "lsusb -v" shows a new OHCI Host Controller
-* then there is a good chance that the U132 adapter will support the
-* PC card.(you also need the specific client driver for the PC card)
-*
-* Please inform the Author and Maintainer about any PC cards that
-* contain OHCI Host Controller and work when directly connected to
-* an embedded CardBus slot but do not work when they are connected
-* via an ELAN U132 adapter.
-*
-*/
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/pci_ids.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
-#include <linux/usb.h>
-#include <linux/usb/hcd.h>
-#include <linux/workqueue.h>
-#include <linux/platform_device.h>
-#include <linux/mutex.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/byteorder.h>
-
- /* FIXME ohci.h is ONLY for internal use by the OHCI driver.
- * If you're going to try stuff like this, you need to split
- * out shareable stuff (register declarations?) into its own
- * file, maybe name <linux/usb/ohci.h>
- */
-
-#include "ohci.h"
-#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
-#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \
- OHCI_INTR_WDH)
-MODULE_AUTHOR("Tony Olech - Elan Digital Systems Limited");
-MODULE_DESCRIPTION("U132 USB Host Controller Driver");
-MODULE_LICENSE("GPL");
-#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444)
-INT_MODULE_PARM(testing, 0);
-/* Some boards misreport power switching/overcurrent*/
-static bool distrust_firmware = true;
-module_param(distrust_firmware, bool, 0);
-MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurrent"
- "t setup");
-static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait);
-/*
-* u132_module_lock exists to protect access to global variables
-*
-*/
-static DEFINE_MUTEX(u132_module_lock);
-static int u132_exiting;
-static int u132_instances;
-/*
-* end of the global variables protected by u132_module_lock
-*/
-static struct workqueue_struct *workqueue;
-#define MAX_U132_PORTS 7
-#define MAX_U132_ADDRS 128
-#define MAX_U132_UDEVS 4
-#define MAX_U132_ENDPS 100
-#define MAX_U132_RINGS 4
-static const char *cc_to_text[16] = {
- "No Error ",
- "CRC Error ",
- "Bit Stuff ",
- "Data Togg ",
- "Stall ",
- "DevNotResp ",
- "PIDCheck ",
- "UnExpPID ",
- "DataOver ",
- "DataUnder ",
- "(for hw) ",
- "(for hw) ",
- "BufferOver ",
- "BuffUnder ",
- "(for HCD) ",
- "(for HCD) "
-};
-struct u132_port {
- struct u132 *u132;
- int reset;
- int enable;
- int power;
- int Status;
-};
-struct u132_addr {
- u8 address;
-};
-struct u132_udev {
- struct kref kref;
- struct usb_device *usb_device;
- u8 enumeration;
- u8 udev_number;
- u8 usb_addr;
- u8 portnumber;
- u8 endp_number_in[16];
- u8 endp_number_out[16];
-};
-#define ENDP_QUEUE_SHIFT 3
-#define ENDP_QUEUE_SIZE (1<<ENDP_QUEUE_SHIFT)
-#define ENDP_QUEUE_MASK (ENDP_QUEUE_SIZE-1)
-struct u132_urbq {
- struct list_head urb_more;
- struct urb *urb;
-};
-struct u132_spin {
- spinlock_t slock;
-};
-struct u132_endp {
- struct kref kref;
- u8 udev_number;
- u8 endp_number;
- u8 usb_addr;
- u8 usb_endp;
- struct u132 *u132;
- struct list_head endp_ring;
- struct u132_ring *ring;
- unsigned toggle_bits:2;
- unsigned active:1;
- unsigned delayed:1;
- unsigned input:1;
- unsigned output:1;
- unsigned pipetype:2;
- unsigned dequeueing:1;
- unsigned edset_flush:1;
- unsigned spare_bits:14;
- unsigned long jiffies;
- struct usb_host_endpoint *hep;
- struct u132_spin queue_lock;
- u16 queue_size;
- u16 queue_last;
- u16 queue_next;
- struct urb *urb_list[ENDP_QUEUE_SIZE];
- struct list_head urb_more;
- struct delayed_work scheduler;
-};
-struct u132_ring {
- unsigned in_use:1;
- unsigned length:7;
- u8 number;
- struct u132 *u132;
- struct u132_endp *curr_endp;
- struct delayed_work scheduler;
-};
-struct u132 {
- struct kref kref;
- struct mutex sw_lock;
- struct mutex scheduler_lock;
- struct u132_platform_data *board;
- struct platform_device *platform_dev;
- struct u132_ring ring[MAX_U132_RINGS];
- int sequence_num;
- int going;
- int power;
- int reset;
- int num_ports;
- u32 hc_control;
- u32 hc_fminterval;
- u32 hc_roothub_status;
- u32 hc_roothub_a;
- u32 hc_roothub_portstatus[MAX_ROOT_PORTS];
- int flags;
- unsigned long next_statechange;
- struct delayed_work monitor;
- int num_endpoints;
- struct u132_addr addr[MAX_U132_ADDRS];
- struct u132_udev udev[MAX_U132_UDEVS];
- struct u132_port port[MAX_U132_PORTS];
- struct u132_endp *endp[MAX_U132_ENDPS];
-};
-
-/*
-* these cannot be inlines because we need the structure offset!!
-* Does anyone have a better way?????
-*/
-#define ftdi_read_pcimem(pdev, member, data) usb_ftdi_elan_read_pcimem(pdev, \
- offsetof(struct ohci_regs, member), 0, data);
-#define ftdi_write_pcimem(pdev, member, data) usb_ftdi_elan_write_pcimem(pdev, \
- offsetof(struct ohci_regs, member), 0, data)
-#define u132_read_pcimem(u132, member, data) \
- usb_ftdi_elan_read_pcimem(u132->platform_dev, offsetof(struct \
- ohci_regs, member), 0, data)
-#define u132_write_pcimem(u132, member, data) \
- usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \
- ohci_regs, member), 0, data)
-static inline struct u132 *udev_to_u132(struct u132_udev *udev)
-{
- u8 udev_number = udev->udev_number;
- return container_of(udev, struct u132, udev[udev_number]);
-}
-
-static inline struct u132 *hcd_to_u132(struct usb_hcd *hcd)
-{
- return (struct u132 *)(hcd->hcd_priv);
-}
-
-static inline struct usb_hcd *u132_to_hcd(struct u132 *u132)
-{
- return container_of((void *)u132, struct usb_hcd, hcd_priv);
-}
-
-static inline void u132_disable(struct u132 *u132)
-{
- u132_to_hcd(u132)->state = HC_STATE_HALT;
-}
-
-
-#define kref_to_u132(d) container_of(d, struct u132, kref)
-#define kref_to_u132_endp(d) container_of(d, struct u132_endp, kref)
-#define kref_to_u132_udev(d) container_of(d, struct u132_udev, kref)
-#include "../misc/usb_u132.h"
-static const char hcd_name[] = "u132_hcd";
-#define PORT_C_MASK ((USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | \
- USB_PORT_STAT_C_SUSPEND | USB_PORT_STAT_C_OVERCURRENT | \
- USB_PORT_STAT_C_RESET) << 16)
-static void u132_hcd_delete(struct kref *kref)
-{
- struct u132 *u132 = kref_to_u132(kref);
- struct platform_device *pdev = u132->platform_dev;
- struct usb_hcd *hcd = u132_to_hcd(u132);
- u132->going += 1;
- mutex_lock(&u132_module_lock);
- u132_instances -= 1;
- mutex_unlock(&u132_module_lock);
- dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13"
- "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev);
- usb_put_hcd(hcd);
-}
-
-static inline void u132_u132_put_kref(struct u132 *u132)
-{
- kref_put(&u132->kref, u132_hcd_delete);
-}
-
-static inline void u132_u132_init_kref(struct u132 *u132)
-{
- kref_init(&u132->kref);
-}
-
-static void u132_udev_delete(struct kref *kref)
-{
- struct u132_udev *udev = kref_to_u132_udev(kref);
- udev->udev_number = 0;
- udev->usb_device = NULL;
- udev->usb_addr = 0;
- udev->enumeration = 0;
-}
-
-static inline void u132_udev_put_kref(struct u132 *u132, struct u132_udev *udev)
-{
- kref_put(&udev->kref, u132_udev_delete);
-}
-
-static inline void u132_udev_get_kref(struct u132 *u132, struct u132_udev *udev)
-{
- kref_get(&udev->kref);
-}
-
-static inline void u132_udev_init_kref(struct u132 *u132,
- struct u132_udev *udev)
-{
- kref_init(&udev->kref);
-}
-
-static inline void u132_ring_put_kref(struct u132 *u132, struct u132_ring *ring)
-{
- kref_put(&u132->kref, u132_hcd_delete);
-}
-
-static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring,
- unsigned int delta)
-{
- if (delta > 0) {
- if (queue_delayed_work(workqueue, &ring->scheduler, delta))
- return;
- } else if (queue_delayed_work(workqueue, &ring->scheduler, 0))
- return;
- kref_put(&u132->kref, u132_hcd_delete);
-}
-
-static void u132_ring_queue_work(struct u132 *u132, struct u132_ring *ring,
- unsigned int delta)
-{
- kref_get(&u132->kref);
- u132_ring_requeue_work(u132, ring, delta);
-}
-
-static void u132_ring_cancel_work(struct u132 *u132, struct u132_ring *ring)
-{
- if (cancel_delayed_work(&ring->scheduler))
- kref_put(&u132->kref, u132_hcd_delete);
-}
-
-static void u132_endp_delete(struct kref *kref)
-{
- struct u132_endp *endp = kref_to_u132_endp(kref);
- struct u132 *u132 = endp->u132;
- u8 usb_addr = endp->usb_addr;
- u8 usb_endp = endp->usb_endp;
- u8 address = u132->addr[usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- u8 endp_number = endp->endp_number;
- struct usb_host_endpoint *hep = endp->hep;
- struct u132_ring *ring = endp->ring;
- struct list_head *head = &endp->endp_ring;
- ring->length -= 1;
- if (endp == ring->curr_endp) {
- if (list_empty(head)) {
- ring->curr_endp = NULL;
- list_del(head);
- } else {
- struct u132_endp *next_endp = list_entry(head->next,
- struct u132_endp, endp_ring);
- ring->curr_endp = next_endp;
- list_del(head);
- }
- } else
- list_del(head);
- if (endp->input) {
- udev->endp_number_in[usb_endp] = 0;
- u132_udev_put_kref(u132, udev);
- }
- if (endp->output) {
- udev->endp_number_out[usb_endp] = 0;
- u132_udev_put_kref(u132, udev);
- }
- u132->endp[endp_number - 1] = NULL;
- hep->hcpriv = NULL;
- kfree(endp);
- u132_u132_put_kref(u132);
-}
-
-static inline void u132_endp_put_kref(struct u132 *u132, struct u132_endp *endp)
-{
- kref_put(&endp->kref, u132_endp_delete);
-}
-
-static inline void u132_endp_get_kref(struct u132 *u132, struct u132_endp *endp)
-{
- kref_get(&endp->kref);
-}
-
-static inline void u132_endp_init_kref(struct u132 *u132,
- struct u132_endp *endp)
-{
- kref_init(&endp->kref);
- kref_get(&u132->kref);
-}
-
-static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp,
- unsigned int delta)
-{
- if (queue_delayed_work(workqueue, &endp->scheduler, delta))
- kref_get(&endp->kref);
-}
-
-static void u132_endp_cancel_work(struct u132 *u132, struct u132_endp *endp)
-{
- if (cancel_delayed_work(&endp->scheduler))
- kref_put(&endp->kref, u132_endp_delete);
-}
-
-static inline void u132_monitor_put_kref(struct u132 *u132)
-{
- kref_put(&u132->kref, u132_hcd_delete);
-}
-
-static void u132_monitor_queue_work(struct u132 *u132, unsigned int delta)
-{
- if (queue_delayed_work(workqueue, &u132->monitor, delta))
- kref_get(&u132->kref);
-}
-
-static void u132_monitor_requeue_work(struct u132 *u132, unsigned int delta)
-{
- if (!queue_delayed_work(workqueue, &u132->monitor, delta))
- kref_put(&u132->kref, u132_hcd_delete);
-}
-
-static void u132_monitor_cancel_work(struct u132 *u132)
-{
- if (cancel_delayed_work(&u132->monitor))
- kref_put(&u132->kref, u132_hcd_delete);
-}
-
-static int read_roothub_info(struct u132 *u132)
-{
- u32 revision;
- int retval;
- retval = u132_read_pcimem(u132, revision, &revision);
- if (retval) {
- dev_err(&u132->platform_dev->dev, "error %d accessing device co"
- "ntrol\n", retval);
- return retval;
- } else if ((revision & 0xFF) == 0x10) {
- } else if ((revision & 0xFF) == 0x11) {
- } else {
- dev_err(&u132->platform_dev->dev, "device revision is not valid"
- " %08X\n", revision);
- return -ENODEV;
- }
- retval = u132_read_pcimem(u132, control, &u132->hc_control);
- if (retval) {
- dev_err(&u132->platform_dev->dev, "error %d accessing device co"
- "ntrol\n", retval);
- return retval;
- }
- retval = u132_read_pcimem(u132, roothub.status,
- &u132->hc_roothub_status);
- if (retval) {
- dev_err(&u132->platform_dev->dev, "error %d accessing device re"
- "g roothub.status\n", retval);
- return retval;
- }
- retval = u132_read_pcimem(u132, roothub.a, &u132->hc_roothub_a);
- if (retval) {
- dev_err(&u132->platform_dev->dev, "error %d accessing device re"
- "g roothub.a\n", retval);
- return retval;
- }
- {
- int I = u132->num_ports;
- int i = 0;
- while (I-- > 0) {
- retval = u132_read_pcimem(u132, roothub.portstatus[i],
- &u132->hc_roothub_portstatus[i]);
- if (retval) {
- dev_err(&u132->platform_dev->dev, "error %d acc"
- "essing device roothub.portstatus[%d]\n"
- , retval, i);
- return retval;
- } else
- i += 1;
- }
- }
- return 0;
-}
-
-static void u132_hcd_monitor_work(struct work_struct *work)
-{
- struct u132 *u132 = container_of(work, struct u132, monitor.work);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- u132_monitor_put_kref(u132);
- return;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- u132_monitor_put_kref(u132);
- return;
- } else {
- int retval;
- mutex_lock(&u132->sw_lock);
- retval = read_roothub_info(u132);
- if (retval) {
- struct usb_hcd *hcd = u132_to_hcd(u132);
- u132_disable(u132);
- u132->going = 1;
- mutex_unlock(&u132->sw_lock);
- usb_hc_died(hcd);
- ftdi_elan_gone_away(u132->platform_dev);
- u132_monitor_put_kref(u132);
- return;
- } else {
- u132_monitor_requeue_work(u132, 500);
- mutex_unlock(&u132->sw_lock);
- return;
- }
- }
-}
-
-static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
- struct urb *urb, int status)
-{
- struct u132_ring *ring;
- unsigned long irqs;
- struct usb_hcd *hcd = u132_to_hcd(u132);
- urb->error_count = 0;
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
- usb_hcd_unlink_urb_from_ep(hcd, urb);
- endp->queue_next += 1;
- if (ENDP_QUEUE_SIZE > --endp->queue_size) {
- endp->active = 0;
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- } else {
- struct list_head *next = endp->urb_more.next;
- struct u132_urbq *urbq = list_entry(next, struct u132_urbq,
- urb_more);
- list_del(next);
- endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
- urbq->urb;
- endp->active = 0;
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- kfree(urbq);
- }
- mutex_lock(&u132->scheduler_lock);
- ring = endp->ring;
- ring->in_use = 0;
- u132_ring_cancel_work(u132, ring);
- u132_ring_queue_work(u132, ring, 0);
- mutex_unlock(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
- usb_hcd_giveback_urb(hcd, urb, status);
-}
-
-static void u132_hcd_forget_urb(struct u132 *u132, struct u132_endp *endp,
- struct urb *urb, int status)
-{
- u132_endp_put_kref(u132, endp);
-}
-
-static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
- struct urb *urb, int status)
-{
- unsigned long irqs;
- struct usb_hcd *hcd = u132_to_hcd(u132);
- urb->error_count = 0;
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
- usb_hcd_unlink_urb_from_ep(hcd, urb);
- endp->queue_next += 1;
- if (ENDP_QUEUE_SIZE > --endp->queue_size) {
- endp->active = 0;
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- } else {
- struct list_head *next = endp->urb_more.next;
- struct u132_urbq *urbq = list_entry(next, struct u132_urbq,
- urb_more);
- list_del(next);
- endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
- urbq->urb;
- endp->active = 0;
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- kfree(urbq);
- }
- usb_hcd_giveback_urb(hcd, urb, status);
-}
-
-static inline int edset_input(struct u132 *u132, struct u132_ring *ring,
- struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
- void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
- int toggle_bits, int error_count, int condition_code, int repeat_number,
- int halted, int skipped, int actual, int non_null))
-{
- return usb_ftdi_elan_edset_input(u132->platform_dev, ring->number, endp,
- urb, address, endp->usb_endp, toggle_bits, callback);
-}
-
-static inline int edset_setup(struct u132 *u132, struct u132_ring *ring,
- struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
- void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
- int toggle_bits, int error_count, int condition_code, int repeat_number,
- int halted, int skipped, int actual, int non_null))
-{
- return usb_ftdi_elan_edset_setup(u132->platform_dev, ring->number, endp,
- urb, address, endp->usb_endp, toggle_bits, callback);
-}
-
-static inline int edset_single(struct u132 *u132, struct u132_ring *ring,
- struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
- void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
- int toggle_bits, int error_count, int condition_code, int repeat_number,
- int halted, int skipped, int actual, int non_null))
-{
- return usb_ftdi_elan_edset_single(u132->platform_dev, ring->number,
- endp, urb, address, endp->usb_endp, toggle_bits, callback);
-}
-
-static inline int edset_output(struct u132 *u132, struct u132_ring *ring,
- struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
- void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
- int toggle_bits, int error_count, int condition_code, int repeat_number,
- int halted, int skipped, int actual, int non_null))
-{
- return usb_ftdi_elan_edset_output(u132->platform_dev, ring->number,
- endp, urb, address, endp->usb_endp, toggle_bits, callback);
-}
-
-
-/*
-* must not LOCK sw_lock
-*
-*/
-static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- u8 address = u132->addr[endp->usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- mutex_lock(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed "
- "urb=%p\n", urb);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (!urb->unlinked) {
- struct u132_ring *ring = endp->ring;
- u8 *u = urb->transfer_buffer + urb->actual_length;
- u8 *b = buf;
- int L = len;
-
- while (L-- > 0)
- *u++ = *b++;
-
- urb->actual_length += len;
- if ((condition_code == TD_CC_NOERROR) &&
- (urb->transfer_buffer_length > urb->actual_length)) {
- endp->toggle_bits = toggle_bits;
- usb_settoggle(udev->usb_device, endp->usb_endp, 0,
- 1 & toggle_bits);
- if (urb->actual_length > 0) {
- int retval;
- mutex_unlock(&u132->scheduler_lock);
- retval = edset_single(u132, ring, endp, urb,
- address, endp->toggle_bits,
- u132_hcd_interrupt_recv);
- if (retval != 0)
- u132_hcd_giveback_urb(u132, endp, urb,
- retval);
- } else {
- ring->in_use = 0;
- endp->active = 0;
- endp->jiffies = jiffies +
- msecs_to_jiffies(urb->interval);
- u132_ring_cancel_work(u132, ring);
- u132_ring_queue_work(u132, ring, 0);
- mutex_unlock(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
- }
- return;
- } else if ((condition_code == TD_DATAUNDERRUN) &&
- ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) {
- endp->toggle_bits = toggle_bits;
- usb_settoggle(udev->usb_device, endp->usb_endp, 0,
- 1 & toggle_bits);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- } else {
- if (condition_code == TD_CC_NOERROR) {
- endp->toggle_bits = toggle_bits;
- usb_settoggle(udev->usb_device, endp->usb_endp,
- 0, 1 & toggle_bits);
- } else if (condition_code == TD_CC_STALL) {
- endp->toggle_bits = 0x2;
- usb_settoggle(udev->usb_device, endp->usb_endp,
- 0, 0);
- } else {
- endp->toggle_bits = 0x2;
- usb_settoggle(udev->usb_device, endp->usb_endp,
- 0, 0);
- dev_err(&u132->platform_dev->dev, "urb=%p givin"
- "g back INTERRUPT %s\n", urb,
- cc_to_text[condition_code]);
- }
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb,
- cc_to_error[condition_code]);
- return;
- }
- } else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
- "unlinked=%d\n", urb, urb->unlinked);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
-}
-
-static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- u8 address = u132->addr[endp->usb_addr].address;
- mutex_lock(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed "
- "urb=%p\n", urb);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (!urb->unlinked) {
- struct u132_ring *ring = endp->ring;
- urb->actual_length += len;
- endp->toggle_bits = toggle_bits;
- if (urb->transfer_buffer_length > urb->actual_length) {
- int retval;
- mutex_unlock(&u132->scheduler_lock);
- retval = edset_output(u132, ring, endp, urb, address,
- endp->toggle_bits, u132_hcd_bulk_output_sent);
- if (retval != 0)
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- } else {
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
- } else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
- "unlinked=%d\n", urb, urb->unlinked);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
-}
-
-static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- u8 address = u132->addr[endp->usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- mutex_lock(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed "
- "urb=%p\n", urb);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (!urb->unlinked) {
- struct u132_ring *ring = endp->ring;
- u8 *u = urb->transfer_buffer + urb->actual_length;
- u8 *b = buf;
- int L = len;
-
- while (L-- > 0)
- *u++ = *b++;
-
- urb->actual_length += len;
- if ((condition_code == TD_CC_NOERROR) &&
- (urb->transfer_buffer_length > urb->actual_length)) {
- int retval;
- endp->toggle_bits = toggle_bits;
- usb_settoggle(udev->usb_device, endp->usb_endp, 0,
- 1 & toggle_bits);
- mutex_unlock(&u132->scheduler_lock);
- retval = usb_ftdi_elan_edset_input(u132->platform_dev,
- ring->number, endp, urb, address,
- endp->usb_endp, endp->toggle_bits,
- u132_hcd_bulk_input_recv);
- if (retval != 0)
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- } else if (condition_code == TD_CC_NOERROR) {
- endp->toggle_bits = toggle_bits;
- usb_settoggle(udev->usb_device, endp->usb_endp, 0,
- 1 & toggle_bits);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb,
- cc_to_error[condition_code]);
- return;
- } else if ((condition_code == TD_DATAUNDERRUN) &&
- ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) {
- endp->toggle_bits = toggle_bits;
- usb_settoggle(udev->usb_device, endp->usb_endp, 0,
- 1 & toggle_bits);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- } else if (condition_code == TD_DATAUNDERRUN) {
- endp->toggle_bits = toggle_bits;
- usb_settoggle(udev->usb_device, endp->usb_endp, 0,
- 1 & toggle_bits);
- dev_warn(&u132->platform_dev->dev, "urb=%p(SHORT NOT OK"
- ") giving back BULK IN %s\n", urb,
- cc_to_text[condition_code]);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- } else if (condition_code == TD_CC_STALL) {
- endp->toggle_bits = 0x2;
- usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb,
- cc_to_error[condition_code]);
- return;
- } else {
- endp->toggle_bits = 0x2;
- usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0);
- dev_err(&u132->platform_dev->dev, "urb=%p giving back B"
- "ULK IN code=%d %s\n", urb, condition_code,
- cc_to_text[condition_code]);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb,
- cc_to_error[condition_code]);
- return;
- }
- } else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
- "unlinked=%d\n", urb, urb->unlinked);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
-}
-
-static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- mutex_lock(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed "
- "urb=%p\n", urb);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (!urb->unlinked) {
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- } else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
- "unlinked=%d\n", urb, urb->unlinked);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
-}
-
-static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- u8 address = u132->addr[endp->usb_addr].address;
- mutex_lock(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed "
- "urb=%p\n", urb);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (!urb->unlinked) {
- struct u132_ring *ring = endp->ring;
- u8 *u = urb->transfer_buffer;
- u8 *b = buf;
- int L = len;
-
- while (L-- > 0)
- *u++ = *b++;
-
- urb->actual_length = len;
- if ((condition_code == TD_CC_NOERROR) || ((condition_code ==
- TD_DATAUNDERRUN) && ((urb->transfer_flags &
- URB_SHORT_NOT_OK) == 0))) {
- int retval;
- mutex_unlock(&u132->scheduler_lock);
- retval = usb_ftdi_elan_edset_empty(u132->platform_dev,
- ring->number, endp, urb, address,
- endp->usb_endp, 0x3,
- u132_hcd_configure_empty_sent);
- if (retval != 0)
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- } else if (condition_code == TD_CC_STALL) {
- mutex_unlock(&u132->scheduler_lock);
- dev_warn(&u132->platform_dev->dev, "giving back SETUP I"
- "NPUT STALL urb %p\n", urb);
- u132_hcd_giveback_urb(u132, endp, urb,
- cc_to_error[condition_code]);
- return;
- } else {
- mutex_unlock(&u132->scheduler_lock);
- dev_err(&u132->platform_dev->dev, "giving back SETUP IN"
- "PUT %s urb %p\n", cc_to_text[condition_code],
- urb);
- u132_hcd_giveback_urb(u132, endp, urb,
- cc_to_error[condition_code]);
- return;
- }
- } else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
- "unlinked=%d\n", urb, urb->unlinked);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
-}
-
-static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- mutex_lock(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed "
- "urb=%p\n", urb);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (!urb->unlinked) {
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- } else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
- "unlinked=%d\n", urb, urb->unlinked);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
-}
-
-static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- u8 address = u132->addr[endp->usb_addr].address;
- mutex_lock(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed "
- "urb=%p\n", urb);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (!urb->unlinked) {
- if (usb_pipein(urb->pipe)) {
- int retval;
- struct u132_ring *ring = endp->ring;
- mutex_unlock(&u132->scheduler_lock);
- retval = usb_ftdi_elan_edset_input(u132->platform_dev,
- ring->number, endp, urb, address,
- endp->usb_endp, 0,
- u132_hcd_configure_input_recv);
- if (retval != 0)
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- } else {
- int retval;
- struct u132_ring *ring = endp->ring;
- mutex_unlock(&u132->scheduler_lock);
- retval = usb_ftdi_elan_edset_input(u132->platform_dev,
- ring->number, endp, urb, address,
- endp->usb_endp, 0,
- u132_hcd_configure_empty_recv);
- if (retval != 0)
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- }
- } else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
- "unlinked=%d\n", urb, urb->unlinked);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
-}
-
-static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb,
- u8 *buf, int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- u8 address = u132->addr[endp->usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- mutex_lock(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed "
- "urb=%p\n", urb);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (!urb->unlinked) {
- u132->addr[0].address = 0;
- endp->usb_addr = udev->usb_addr;
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- } else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
- "unlinked=%d\n", urb, urb->unlinked);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
-}
-
-static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
- u8 *buf, int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- mutex_lock(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed "
- "urb=%p\n", urb);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (!urb->unlinked) {
- int retval;
- struct u132_ring *ring = endp->ring;
- mutex_unlock(&u132->scheduler_lock);
- retval = usb_ftdi_elan_edset_input(u132->platform_dev,
- ring->number, endp, urb, 0, endp->usb_endp, 0,
- u132_hcd_enumeration_empty_recv);
- if (retval != 0)
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- } else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
- "unlinked=%d\n", urb, urb->unlinked);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
-}
-
-static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- mutex_lock(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed "
- "urb=%p\n", urb);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (!urb->unlinked) {
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- } else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
- "unlinked=%d\n", urb, urb->unlinked);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
-}
-
-static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- u8 address = u132->addr[endp->usb_addr].address;
- mutex_lock(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed "
- "urb=%p\n", urb);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (!urb->unlinked) {
- int retval;
- struct u132_ring *ring = endp->ring;
- u8 *u = urb->transfer_buffer;
- u8 *b = buf;
- int L = len;
-
- while (L-- > 0)
- *u++ = *b++;
-
- urb->actual_length = len;
- mutex_unlock(&u132->scheduler_lock);
- retval = usb_ftdi_elan_edset_empty(u132->platform_dev,
- ring->number, endp, urb, address, endp->usb_endp, 0x3,
- u132_hcd_initial_empty_sent);
- if (retval != 0)
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- } else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
- "unlinked=%d\n", urb, urb->unlinked);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
-}
-
-static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- u8 address = u132->addr[endp->usb_addr].address;
- mutex_lock(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed "
- "urb=%p\n", urb);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (!urb->unlinked) {
- int retval;
- struct u132_ring *ring = endp->ring;
- mutex_unlock(&u132->scheduler_lock);
- retval = usb_ftdi_elan_edset_input(u132->platform_dev,
- ring->number, endp, urb, address, endp->usb_endp, 0,
- u132_hcd_initial_input_recv);
- if (retval != 0)
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- } else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
- "unlinked=%d\n", urb, urb->unlinked);
- mutex_unlock(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
-}
-
-/*
-* this work function is only executed from the work queue
-*
-*/
-static void u132_hcd_ring_work_scheduler(struct work_struct *work)
-{
- struct u132_ring *ring =
- container_of(work, struct u132_ring, scheduler.work);
- struct u132 *u132 = ring->u132;
- mutex_lock(&u132->scheduler_lock);
- if (ring->in_use) {
- mutex_unlock(&u132->scheduler_lock);
- u132_ring_put_kref(u132, ring);
- return;
- } else if (ring->curr_endp) {
- struct u132_endp *endp, *last_endp = ring->curr_endp;
- unsigned long wakeup = 0;
- list_for_each_entry(endp, &last_endp->endp_ring, endp_ring) {
- if (endp->queue_next == endp->queue_last) {
- } else if ((endp->delayed == 0)
- || time_after_eq(jiffies, endp->jiffies)) {
- ring->curr_endp = endp;
- u132_endp_cancel_work(u132, last_endp);
- u132_endp_queue_work(u132, last_endp, 0);
- mutex_unlock(&u132->scheduler_lock);
- u132_ring_put_kref(u132, ring);
- return;
- } else {
- unsigned long delta = endp->jiffies - jiffies;
- if (delta > wakeup)
- wakeup = delta;
- }
- }
- if (last_endp->queue_next == last_endp->queue_last) {
- } else if ((last_endp->delayed == 0) || time_after_eq(jiffies,
- last_endp->jiffies)) {
- u132_endp_cancel_work(u132, last_endp);
- u132_endp_queue_work(u132, last_endp, 0);
- mutex_unlock(&u132->scheduler_lock);
- u132_ring_put_kref(u132, ring);
- return;
- } else {
- unsigned long delta = last_endp->jiffies - jiffies;
- if (delta > wakeup)
- wakeup = delta;
- }
- if (wakeup > 0) {
- u132_ring_requeue_work(u132, ring, wakeup);
- mutex_unlock(&u132->scheduler_lock);
- return;
- } else {
- mutex_unlock(&u132->scheduler_lock);
- u132_ring_put_kref(u132, ring);
- return;
- }
- } else {
- mutex_unlock(&u132->scheduler_lock);
- u132_ring_put_kref(u132, ring);
- return;
- }
-}
-
-static void u132_hcd_endp_work_scheduler(struct work_struct *work)
-{
- struct u132_ring *ring;
- struct u132_endp *endp =
- container_of(work, struct u132_endp, scheduler.work);
- struct u132 *u132 = endp->u132;
- mutex_lock(&u132->scheduler_lock);
- ring = endp->ring;
- if (endp->edset_flush) {
- endp->edset_flush = 0;
- if (endp->dequeueing)
- usb_ftdi_elan_edset_flush(u132->platform_dev,
- ring->number, endp);
- mutex_unlock(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
- return;
- } else if (endp->active) {
- mutex_unlock(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
- return;
- } else if (ring->in_use) {
- mutex_unlock(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
- return;
- } else if (endp->queue_next == endp->queue_last) {
- mutex_unlock(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
- return;
- } else if (endp->pipetype == PIPE_INTERRUPT) {
- u8 address = u132->addr[endp->usb_addr].address;
- if (ring->in_use) {
- mutex_unlock(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
- return;
- } else {
- int retval;
- struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
- endp->queue_next];
- endp->active = 1;
- ring->curr_endp = endp;
- ring->in_use = 1;
- mutex_unlock(&u132->scheduler_lock);
- retval = edset_single(u132, ring, endp, urb, address,
- endp->toggle_bits, u132_hcd_interrupt_recv);
- if (retval != 0)
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- }
- } else if (endp->pipetype == PIPE_CONTROL) {
- u8 address = u132->addr[endp->usb_addr].address;
- if (ring->in_use) {
- mutex_unlock(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
- return;
- } else if (address == 0) {
- int retval;
- struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
- endp->queue_next];
- endp->active = 1;
- ring->curr_endp = endp;
- ring->in_use = 1;
- mutex_unlock(&u132->scheduler_lock);
- retval = edset_setup(u132, ring, endp, urb, address,
- 0x2, u132_hcd_initial_setup_sent);
- if (retval != 0)
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- } else if (endp->usb_addr == 0) {
- int retval;
- struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
- endp->queue_next];
- endp->active = 1;
- ring->curr_endp = endp;
- ring->in_use = 1;
- mutex_unlock(&u132->scheduler_lock);
- retval = edset_setup(u132, ring, endp, urb, 0, 0x2,
- u132_hcd_enumeration_address_sent);
- if (retval != 0)
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- } else {
- int retval;
- struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
- endp->queue_next];
- address = u132->addr[endp->usb_addr].address;
- endp->active = 1;
- ring->curr_endp = endp;
- ring->in_use = 1;
- mutex_unlock(&u132->scheduler_lock);
- retval = edset_setup(u132, ring, endp, urb, address,
- 0x2, u132_hcd_configure_setup_sent);
- if (retval != 0)
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- }
- } else {
- if (endp->input) {
- u8 address = u132->addr[endp->usb_addr].address;
- if (ring->in_use) {
- mutex_unlock(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
- return;
- } else {
- int retval;
- struct urb *urb = endp->urb_list[
- ENDP_QUEUE_MASK & endp->queue_next];
- endp->active = 1;
- ring->curr_endp = endp;
- ring->in_use = 1;
- mutex_unlock(&u132->scheduler_lock);
- retval = edset_input(u132, ring, endp, urb,
- address, endp->toggle_bits,
- u132_hcd_bulk_input_recv);
- if (retval == 0) {
- } else
- u132_hcd_giveback_urb(u132, endp, urb,
- retval);
- return;
- }
- } else { /* output pipe */
- u8 address = u132->addr[endp->usb_addr].address;
- if (ring->in_use) {
- mutex_unlock(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
- return;
- } else {
- int retval;
- struct urb *urb = endp->urb_list[
- ENDP_QUEUE_MASK & endp->queue_next];
- endp->active = 1;
- ring->curr_endp = endp;
- ring->in_use = 1;
- mutex_unlock(&u132->scheduler_lock);
- retval = edset_output(u132, ring, endp, urb,
- address, endp->toggle_bits,
- u132_hcd_bulk_output_sent);
- if (retval == 0) {
- } else
- u132_hcd_giveback_urb(u132, endp, urb,
- retval);
- return;
- }
- }
- }
-}
-#ifdef CONFIG_PM
-
-static void port_power(struct u132 *u132, int pn, int is_on)
-{
- u132->port[pn].power = is_on;
-}
-
-#endif
-
-static void u132_power(struct u132 *u132, int is_on)
-{
- struct usb_hcd *hcd = u132_to_hcd(u132)
- ; /* hub is inactive unless the port is powered */
- if (is_on) {
- if (u132->power)
- return;
- u132->power = 1;
- } else {
- u132->power = 0;
- hcd->state = HC_STATE_HALT;
- }
-}
-
-static int u132_periodic_reinit(struct u132 *u132)
-{
- int retval;
- u32 fi = u132->hc_fminterval & 0x03fff;
- u32 fit;
- u32 fminterval;
- retval = u132_read_pcimem(u132, fminterval, &fminterval);
- if (retval)
- return retval;
- fit = fminterval & FIT;
- retval = u132_write_pcimem(u132, fminterval,
- (fit ^ FIT) | u132->hc_fminterval);
- if (retval)
- return retval;
- return u132_write_pcimem(u132, periodicstart,
- ((9 * fi) / 10) & 0x3fff);
-}
-
-static char *hcfs2string(int state)
-{
- switch (state) {
- case OHCI_USB_RESET:
- return "reset";
- case OHCI_USB_RESUME:
- return "resume";
- case OHCI_USB_OPER:
- return "operational";
- case OHCI_USB_SUSPEND:
- return "suspend";
- }
- return "?";
-}
-
-static int u132_init(struct u132 *u132)
-{
- int retval;
- u32 control;
- u132_disable(u132);
- u132->next_statechange = jiffies;
- retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE);
- if (retval)
- return retval;
- retval = u132_read_pcimem(u132, control, &control);
- if (retval)
- return retval;
- if (u132->num_ports == 0) {
- u32 rh_a = -1;
- retval = u132_read_pcimem(u132, roothub.a, &rh_a);
- if (retval)
- return retval;
- u132->num_ports = rh_a & RH_A_NDP;
- retval = read_roothub_info(u132);
- if (retval)
- return retval;
- }
- if (u132->num_ports > MAX_U132_PORTS)
- return -EINVAL;
-
- return 0;
-}
-
-
-/* Start an OHCI controller, set the BUS operational
-* resets USB and controller
-* enable interrupts
-*/
-static int u132_run(struct u132 *u132)
-{
- int retval;
- u32 control;
- u32 status;
- u32 fminterval;
- u32 periodicstart;
- u32 cmdstatus;
- u32 roothub_a;
- int mask = OHCI_INTR_INIT;
- int first = u132->hc_fminterval == 0;
- int sleep_time = 0;
- int reset_timeout = 30; /* ... allow extra time */
- u132_disable(u132);
- if (first) {
- u32 temp;
- retval = u132_read_pcimem(u132, fminterval, &temp);
- if (retval)
- return retval;
- u132->hc_fminterval = temp & 0x3fff;
- u132->hc_fminterval |= FSMP(u132->hc_fminterval) << 16;
- }
- retval = u132_read_pcimem(u132, control, &u132->hc_control);
- if (retval)
- return retval;
- dev_info(&u132->platform_dev->dev, "resetting from state '%s', control "
- "= %08X\n", hcfs2string(u132->hc_control & OHCI_CTRL_HCFS),
- u132->hc_control);
- switch (u132->hc_control & OHCI_CTRL_HCFS) {
- case OHCI_USB_OPER:
- sleep_time = 0;
- break;
- case OHCI_USB_SUSPEND:
- case OHCI_USB_RESUME:
- u132->hc_control &= OHCI_CTRL_RWC;
- u132->hc_control |= OHCI_USB_RESUME;
- sleep_time = 10;
- break;
- default:
- u132->hc_control &= OHCI_CTRL_RWC;
- u132->hc_control |= OHCI_USB_RESET;
- sleep_time = 50;
- break;
- }
- retval = u132_write_pcimem(u132, control, u132->hc_control);
- if (retval)
- return retval;
- retval = u132_read_pcimem(u132, control, &control);
- if (retval)
- return retval;
- msleep(sleep_time);
- retval = u132_read_pcimem(u132, roothub.a, &roothub_a);
- if (retval)
- return retval;
- if (!(roothub_a & RH_A_NPS)) {
- int temp; /* power down each port */
- for (temp = 0; temp < u132->num_ports; temp++) {
- retval = u132_write_pcimem(u132,
- roothub.portstatus[temp], RH_PS_LSDA);
- if (retval)
- return retval;
- }
- }
- retval = u132_read_pcimem(u132, control, &control);
- if (retval)
- return retval;
-retry:
- retval = u132_read_pcimem(u132, cmdstatus, &status);
- if (retval)
- return retval;
- retval = u132_write_pcimem(u132, cmdstatus, OHCI_HCR);
- if (retval)
- return retval;
-extra: {
- retval = u132_read_pcimem(u132, cmdstatus, &status);
- if (retval)
- return retval;
- if (0 != (status & OHCI_HCR)) {
- if (--reset_timeout == 0) {
- dev_err(&u132->platform_dev->dev, "USB HC reset"
- " timed out!\n");
- return -ENODEV;
- } else {
- msleep(5);
- goto extra;
- }
- }
- }
- if (u132->flags & OHCI_QUIRK_INITRESET) {
- retval = u132_write_pcimem(u132, control, u132->hc_control);
- if (retval)
- return retval;
- retval = u132_read_pcimem(u132, control, &control);
- if (retval)
- return retval;
- }
- retval = u132_write_pcimem(u132, ed_controlhead, 0x00000000);
- if (retval)
- return retval;
- retval = u132_write_pcimem(u132, ed_bulkhead, 0x11000000);
- if (retval)
- return retval;
- retval = u132_write_pcimem(u132, hcca, 0x00000000);
- if (retval)
- return retval;
- retval = u132_periodic_reinit(u132);
- if (retval)
- return retval;
- retval = u132_read_pcimem(u132, fminterval, &fminterval);
- if (retval)
- return retval;
- retval = u132_read_pcimem(u132, periodicstart, &periodicstart);
- if (retval)
- return retval;
- if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) {
- if (!(u132->flags & OHCI_QUIRK_INITRESET)) {
- u132->flags |= OHCI_QUIRK_INITRESET;
- goto retry;
- } else
- dev_err(&u132->platform_dev->dev, "init err(%08x %04x)"
- "\n", fminterval, periodicstart);
- } /* start controller operations */
- u132->hc_control &= OHCI_CTRL_RWC;
- u132->hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER;
- retval = u132_write_pcimem(u132, control, u132->hc_control);
- if (retval)
- return retval;
- retval = u132_write_pcimem(u132, cmdstatus, OHCI_BLF);
- if (retval)
- return retval;
- retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus);
- if (retval)
- return retval;
- retval = u132_read_pcimem(u132, control, &control);
- if (retval)
- return retval;
- u132_to_hcd(u132)->state = HC_STATE_RUNNING;
- retval = u132_write_pcimem(u132, roothub.status, RH_HS_DRWE);
- if (retval)
- return retval;
- retval = u132_write_pcimem(u132, intrstatus, mask);
- if (retval)
- return retval;
- retval = u132_write_pcimem(u132, intrdisable,
- OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO |
- OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH |
- OHCI_INTR_SO);
- if (retval)
- return retval; /* handle root hub init quirks ... */
- retval = u132_read_pcimem(u132, roothub.a, &roothub_a);
- if (retval)
- return retval;
- roothub_a &= ~(RH_A_PSM | RH_A_OCPM);
- if (u132->flags & OHCI_QUIRK_SUPERIO) {
- roothub_a |= RH_A_NOCP;
- roothub_a &= ~(RH_A_POTPGT | RH_A_NPS);
- retval = u132_write_pcimem(u132, roothub.a, roothub_a);
- if (retval)
- return retval;
- } else if ((u132->flags & OHCI_QUIRK_AMD756) || distrust_firmware) {
- roothub_a |= RH_A_NPS;
- retval = u132_write_pcimem(u132, roothub.a, roothub_a);
- if (retval)
- return retval;
- }
- retval = u132_write_pcimem(u132, roothub.status, RH_HS_LPSC);
- if (retval)
- return retval;
- retval = u132_write_pcimem(u132, roothub.b,
- (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM);
- if (retval)
- return retval;
- retval = u132_read_pcimem(u132, control, &control);
- if (retval)
- return retval;
- mdelay((roothub_a >> 23) & 0x1fe);
- u132_to_hcd(u132)->state = HC_STATE_RUNNING;
- return 0;
-}
-
-static void u132_hcd_stop(struct usb_hcd *hcd)
-{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p) has b"
- "een removed %d\n", u132, hcd, u132->going);
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
- "ed\n", hcd);
- } else {
- mutex_lock(&u132->sw_lock);
- msleep(100);
- u132_power(u132, 0);
- mutex_unlock(&u132->sw_lock);
- }
-}
-
-static int u132_hcd_start(struct usb_hcd *hcd)
-{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else if (hcd->self.controller) {
- int retval;
- struct platform_device *pdev =
- to_platform_device(hcd->self.controller);
- u16 vendor = ((struct u132_platform_data *)
- dev_get_platdata(&pdev->dev))->vendor;
- u16 device = ((struct u132_platform_data *)
- dev_get_platdata(&pdev->dev))->device;
- mutex_lock(&u132->sw_lock);
- msleep(10);
- if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
- u132->flags = OHCI_QUIRK_AMD756;
- } else if (vendor == PCI_VENDOR_ID_OPTI && device == 0xc861) {
- dev_err(&u132->platform_dev->dev, "WARNING: OPTi workar"
- "ounds unavailable\n");
- } else if (vendor == PCI_VENDOR_ID_COMPAQ && device == 0xa0f8)
- u132->flags |= OHCI_QUIRK_ZFMICRO;
- retval = u132_run(u132);
- if (retval) {
- u132_disable(u132);
- u132->going = 1;
- }
- msleep(100);
- mutex_unlock(&u132->sw_lock);
- return retval;
- } else {
- dev_err(&u132->platform_dev->dev, "platform_device missing\n");
- return -ENODEV;
- }
-}
-
-static int u132_hcd_reset(struct usb_hcd *hcd)
-{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else {
- int retval;
- mutex_lock(&u132->sw_lock);
- retval = u132_init(u132);
- if (retval) {
- u132_disable(u132);
- u132->going = 1;
- }
- mutex_unlock(&u132->sw_lock);
- return retval;
- }
-}
-
-static int create_endpoint_and_queue_int(struct u132 *u132,
- struct u132_udev *udev, struct urb *urb,
- struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
- gfp_t mem_flags)
-{
- struct u132_ring *ring;
- unsigned long irqs;
- int rc;
- u8 endp_number;
- struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
-
- if (!endp)
- return -ENOMEM;
-
- spin_lock_init(&endp->queue_lock.slock);
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
- rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
- if (rc) {
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- kfree(endp);
- return rc;
- }
-
- endp_number = ++u132->num_endpoints;
- urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
- INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
- INIT_LIST_HEAD(&endp->urb_more);
- ring = endp->ring = &u132->ring[0];
- if (ring->curr_endp) {
- list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
- } else {
- INIT_LIST_HEAD(&endp->endp_ring);
- ring->curr_endp = endp;
- }
- ring->length += 1;
- endp->dequeueing = 0;
- endp->edset_flush = 0;
- endp->active = 0;
- endp->delayed = 0;
- endp->endp_number = endp_number;
- endp->u132 = u132;
- endp->hep = urb->ep;
- endp->pipetype = usb_pipetype(urb->pipe);
- u132_endp_init_kref(u132, endp);
- if (usb_pipein(urb->pipe)) {
- endp->toggle_bits = 0x2;
- usb_settoggle(udev->usb_device, usb_endp, 0, 0);
- endp->input = 1;
- endp->output = 0;
- udev->endp_number_in[usb_endp] = endp_number;
- u132_udev_get_kref(u132, udev);
- } else {
- endp->toggle_bits = 0x2;
- usb_settoggle(udev->usb_device, usb_endp, 1, 0);
- endp->input = 0;
- endp->output = 1;
- udev->endp_number_out[usb_endp] = endp_number;
- u132_udev_get_kref(u132, udev);
- }
- urb->hcpriv = u132;
- endp->delayed = 1;
- endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
- endp->udev_number = address;
- endp->usb_addr = usb_addr;
- endp->usb_endp = usb_endp;
- endp->queue_size = 1;
- endp->queue_last = 0;
- endp->queue_next = 0;
- endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- u132_endp_queue_work(u132, endp, msecs_to_jiffies(urb->interval));
- return 0;
-}
-
-static int queue_int_on_old_endpoint(struct u132 *u132,
- struct u132_udev *udev, struct urb *urb,
- struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
- u8 usb_endp, u8 address)
-{
- urb->hcpriv = u132;
- endp->delayed = 1;
- endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
- if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
- endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
- } else {
- struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq),
- GFP_ATOMIC);
- if (urbq == NULL) {
- endp->queue_size -= 1;
- return -ENOMEM;
- } else {
- list_add_tail(&urbq->urb_more, &endp->urb_more);
- urbq->urb = urb;
- }
- }
- return 0;
-}
-
-static int create_endpoint_and_queue_bulk(struct u132 *u132,
- struct u132_udev *udev, struct urb *urb,
- struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
- gfp_t mem_flags)
-{
- int ring_number;
- struct u132_ring *ring;
- unsigned long irqs;
- int rc;
- u8 endp_number;
- struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
-
- if (!endp)
- return -ENOMEM;
-
- spin_lock_init(&endp->queue_lock.slock);
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
- rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
- if (rc) {
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- kfree(endp);
- return rc;
- }
-
- endp_number = ++u132->num_endpoints;
- urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
- INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
- INIT_LIST_HEAD(&endp->urb_more);
- endp->dequeueing = 0;
- endp->edset_flush = 0;
- endp->active = 0;
- endp->delayed = 0;
- endp->endp_number = endp_number;
- endp->u132 = u132;
- endp->hep = urb->ep;
- endp->pipetype = usb_pipetype(urb->pipe);
- u132_endp_init_kref(u132, endp);
- if (usb_pipein(urb->pipe)) {
- endp->toggle_bits = 0x2;
- usb_settoggle(udev->usb_device, usb_endp, 0, 0);
- ring_number = 3;
- endp->input = 1;
- endp->output = 0;
- udev->endp_number_in[usb_endp] = endp_number;
- u132_udev_get_kref(u132, udev);
- } else {
- endp->toggle_bits = 0x2;
- usb_settoggle(udev->usb_device, usb_endp, 1, 0);
- ring_number = 2;
- endp->input = 0;
- endp->output = 1;
- udev->endp_number_out[usb_endp] = endp_number;
- u132_udev_get_kref(u132, udev);
- }
- ring = endp->ring = &u132->ring[ring_number - 1];
- if (ring->curr_endp) {
- list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
- } else {
- INIT_LIST_HEAD(&endp->endp_ring);
- ring->curr_endp = endp;
- }
- ring->length += 1;
- urb->hcpriv = u132;
- endp->udev_number = address;
- endp->usb_addr = usb_addr;
- endp->usb_endp = usb_endp;
- endp->queue_size = 1;
- endp->queue_last = 0;
- endp->queue_next = 0;
- endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- u132_endp_queue_work(u132, endp, 0);
- return 0;
-}
-
-static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
- struct urb *urb,
- struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
- u8 usb_endp, u8 address)
-{
- urb->hcpriv = u132;
- if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
- endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
- } else {
- struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq),
- GFP_ATOMIC);
- if (urbq == NULL) {
- endp->queue_size -= 1;
- return -ENOMEM;
- } else {
- list_add_tail(&urbq->urb_more, &endp->urb_more);
- urbq->urb = urb;
- }
- }
- return 0;
-}
-
-static int create_endpoint_and_queue_control(struct u132 *u132,
- struct urb *urb,
- struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp,
- gfp_t mem_flags)
-{
- struct u132_ring *ring;
- unsigned long irqs;
- int rc;
- u8 endp_number;
- struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
-
- if (!endp)
- return -ENOMEM;
-
- spin_lock_init(&endp->queue_lock.slock);
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
- rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
- if (rc) {
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- kfree(endp);
- return rc;
- }
-
- endp_number = ++u132->num_endpoints;
- urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
- INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
- INIT_LIST_HEAD(&endp->urb_more);
- ring = endp->ring = &u132->ring[0];
- if (ring->curr_endp) {
- list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
- } else {
- INIT_LIST_HEAD(&endp->endp_ring);
- ring->curr_endp = endp;
- }
- ring->length += 1;
- endp->dequeueing = 0;
- endp->edset_flush = 0;
- endp->active = 0;
- endp->delayed = 0;
- endp->endp_number = endp_number;
- endp->u132 = u132;
- endp->hep = urb->ep;
- u132_endp_init_kref(u132, endp);
- u132_endp_get_kref(u132, endp);
- if (usb_addr == 0) {
- u8 address = u132->addr[usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- endp->udev_number = address;
- endp->usb_addr = usb_addr;
- endp->usb_endp = usb_endp;
- endp->input = 1;
- endp->output = 1;
- endp->pipetype = usb_pipetype(urb->pipe);
- u132_udev_init_kref(u132, udev);
- u132_udev_get_kref(u132, udev);
- udev->endp_number_in[usb_endp] = endp_number;
- udev->endp_number_out[usb_endp] = endp_number;
- urb->hcpriv = u132;
- endp->queue_size = 1;
- endp->queue_last = 0;
- endp->queue_next = 0;
- endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- u132_endp_queue_work(u132, endp, 0);
- return 0;
- } else { /*(usb_addr > 0) */
- u8 address = u132->addr[usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- endp->udev_number = address;
- endp->usb_addr = usb_addr;
- endp->usb_endp = usb_endp;
- endp->input = 1;
- endp->output = 1;
- endp->pipetype = usb_pipetype(urb->pipe);
- u132_udev_get_kref(u132, udev);
- udev->enumeration = 2;
- udev->endp_number_in[usb_endp] = endp_number;
- udev->endp_number_out[usb_endp] = endp_number;
- urb->hcpriv = u132;
- endp->queue_size = 1;
- endp->queue_last = 0;
- endp->queue_next = 0;
- endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- u132_endp_queue_work(u132, endp, 0);
- return 0;
- }
-}
-
-static int queue_control_on_old_endpoint(struct u132 *u132,
- struct urb *urb,
- struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
- u8 usb_endp)
-{
- if (usb_addr == 0) {
- if (usb_pipein(urb->pipe)) {
- urb->hcpriv = u132;
- if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
- endp->urb_list[ENDP_QUEUE_MASK &
- endp->queue_last++] = urb;
- } else {
- struct u132_urbq *urbq =
- kmalloc(sizeof(struct u132_urbq),
- GFP_ATOMIC);
- if (urbq == NULL) {
- endp->queue_size -= 1;
- return -ENOMEM;
- } else {
- list_add_tail(&urbq->urb_more,
- &endp->urb_more);
- urbq->urb = urb;
- }
- }
- return 0;
- } else { /* usb_pipeout(urb->pipe) */
- struct u132_addr *addr = &u132->addr[usb_dev->devnum];
- int I = MAX_U132_UDEVS;
- int i = 0;
- while (--I > 0) {
- struct u132_udev *udev = &u132->udev[++i];
- if (udev->usb_device) {
- continue;
- } else {
- udev->enumeration = 1;
- u132->addr[0].address = i;
- endp->udev_number = i;
- udev->udev_number = i;
- udev->usb_addr = usb_dev->devnum;
- u132_udev_init_kref(u132, udev);
- udev->endp_number_in[usb_endp] =
- endp->endp_number;
- u132_udev_get_kref(u132, udev);
- udev->endp_number_out[usb_endp] =
- endp->endp_number;
- udev->usb_device = usb_dev;
- ((u8 *) (urb->setup_packet))[2] =
- addr->address = i;
- u132_udev_get_kref(u132, udev);
- break;
- }
- }
- if (I == 0) {
- dev_err(&u132->platform_dev->dev, "run out of d"
- "evice space\n");
- return -EINVAL;
- }
- urb->hcpriv = u132;
- if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
- endp->urb_list[ENDP_QUEUE_MASK &
- endp->queue_last++] = urb;
- } else {
- struct u132_urbq *urbq =
- kmalloc(sizeof(struct u132_urbq),
- GFP_ATOMIC);
- if (urbq == NULL) {
- endp->queue_size -= 1;
- return -ENOMEM;
- } else {
- list_add_tail(&urbq->urb_more,
- &endp->urb_more);
- urbq->urb = urb;
- }
- }
- return 0;
- }
- } else { /*(usb_addr > 0) */
- u8 address = u132->addr[usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- urb->hcpriv = u132;
- if (udev->enumeration != 2)
- udev->enumeration = 2;
- if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
- endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
- urb;
- } else {
- struct u132_urbq *urbq =
- kmalloc(sizeof(struct u132_urbq), GFP_ATOMIC);
- if (urbq == NULL) {
- endp->queue_size -= 1;
- return -ENOMEM;
- } else {
- list_add_tail(&urbq->urb_more, &endp->urb_more);
- urbq->urb = urb;
- }
- }
- return 0;
- }
-}
-
-static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
- gfp_t mem_flags)
-{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (irqs_disabled()) {
- if (gfpflags_allow_blocking(mem_flags)) {
- printk(KERN_ERR "invalid context for function that might sleep\n");
- return -EINVAL;
- }
- }
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed "
- "urb=%p\n", urb);
- return -ESHUTDOWN;
- } else {
- u8 usb_addr = usb_pipedevice(urb->pipe);
- u8 usb_endp = usb_pipeendpoint(urb->pipe);
- struct usb_device *usb_dev = urb->dev;
- if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
- u8 address = u132->addr[usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- struct u132_endp *endp = urb->ep->hcpriv;
- urb->actual_length = 0;
- if (endp) {
- unsigned long irqs;
- int retval;
- spin_lock_irqsave(&endp->queue_lock.slock,
- irqs);
- retval = usb_hcd_link_urb_to_ep(hcd, urb);
- if (retval == 0) {
- retval = queue_int_on_old_endpoint(
- u132, udev, urb,
- usb_dev, endp,
- usb_addr, usb_endp,
- address);
- if (retval)
- usb_hcd_unlink_urb_from_ep(
- hcd, urb);
- }
- spin_unlock_irqrestore(&endp->queue_lock.slock,
- irqs);
- if (retval) {
- return retval;
- } else {
- u132_endp_queue_work(u132, endp,
- msecs_to_jiffies(urb->interval))
- ;
- return 0;
- }
- } else if (u132->num_endpoints == MAX_U132_ENDPS) {
- return -EINVAL;
- } else { /*(endp == NULL) */
- return create_endpoint_and_queue_int(u132, udev,
- urb, usb_dev, usb_addr,
- usb_endp, address, mem_flags);
- }
- } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
- dev_err(&u132->platform_dev->dev, "the hardware does no"
- "t support PIPE_ISOCHRONOUS\n");
- return -EINVAL;
- } else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
- u8 address = u132->addr[usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- struct u132_endp *endp = urb->ep->hcpriv;
- urb->actual_length = 0;
- if (endp) {
- unsigned long irqs;
- int retval;
- spin_lock_irqsave(&endp->queue_lock.slock,
- irqs);
- retval = usb_hcd_link_urb_to_ep(hcd, urb);
- if (retval == 0) {
- retval = queue_bulk_on_old_endpoint(
- u132, udev, urb,
- usb_dev, endp,
- usb_addr, usb_endp,
- address);
- if (retval)
- usb_hcd_unlink_urb_from_ep(
- hcd, urb);
- }
- spin_unlock_irqrestore(&endp->queue_lock.slock,
- irqs);
- if (retval) {
- return retval;
- } else {
- u132_endp_queue_work(u132, endp, 0);
- return 0;
- }
- } else if (u132->num_endpoints == MAX_U132_ENDPS) {
- return -EINVAL;
- } else
- return create_endpoint_and_queue_bulk(u132,
- udev, urb, usb_dev, usb_addr,
- usb_endp, address, mem_flags);
- } else {
- struct u132_endp *endp = urb->ep->hcpriv;
- u16 urb_size = 8;
- u8 *b = urb->setup_packet;
- int i = 0;
- char data[30 * 3 + 4];
- char *d = data;
- int m = (sizeof(data) - 1) / 3;
- int l = 0;
- data[0] = 0;
- while (urb_size-- > 0) {
- if (i > m) {
- } else if (i++ < m) {
- int w = sprintf(d, " %02X", *b++);
- d += w;
- l += w;
- } else
- d += sprintf(d, " ..");
- }
- if (endp) {
- unsigned long irqs;
- int retval;
- spin_lock_irqsave(&endp->queue_lock.slock,
- irqs);
- retval = usb_hcd_link_urb_to_ep(hcd, urb);
- if (retval == 0) {
- retval = queue_control_on_old_endpoint(
- u132, urb, usb_dev,
- endp, usb_addr,
- usb_endp);
- if (retval)
- usb_hcd_unlink_urb_from_ep(
- hcd, urb);
- }
- spin_unlock_irqrestore(&endp->queue_lock.slock,
- irqs);
- if (retval) {
- return retval;
- } else {
- u132_endp_queue_work(u132, endp, 0);
- return 0;
- }
- } else if (u132->num_endpoints == MAX_U132_ENDPS) {
- return -EINVAL;
- } else
- return create_endpoint_and_queue_control(u132,
- urb, usb_dev, usb_addr, usb_endp,
- mem_flags);
- }
- }
-}
-
-static int dequeue_from_overflow_chain(struct u132 *u132,
- struct u132_endp *endp, struct urb *urb)
-{
- struct u132_urbq *urbq;
-
- list_for_each_entry(urbq, &endp->urb_more, urb_more) {
- if (urbq->urb == urb) {
- struct usb_hcd *hcd = u132_to_hcd(u132);
- list_del(&urbq->urb_more);
- endp->queue_size -= 1;
- urb->error_count = 0;
- usb_hcd_giveback_urb(hcd, urb, 0);
- return 0;
- }
- }
- dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]=%p ring"
- "[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X"
- "\n", urb, endp->endp_number, endp, endp->ring->number,
- endp->input ? 'I' : ' ', endp->output ? 'O' : ' ',
- endp->usb_endp, endp->usb_addr, endp->queue_size,
- endp->queue_next, endp->queue_last);
- return -EINVAL;
-}
-
-static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
- struct urb *urb, int status)
-{
- unsigned long irqs;
- int rc;
-
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
- rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status);
- if (rc) {
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- return rc;
- }
- if (endp->queue_size == 0) {
- dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]"
- "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb,
- endp->endp_number, endp, endp->ring->number,
- endp->input ? 'I' : ' ', endp->output ? 'O' : ' ',
- endp->usb_endp, endp->usb_addr);
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- return -EINVAL;
- }
- if (urb == endp->urb_list[ENDP_QUEUE_MASK & endp->queue_next]) {
- if (endp->active) {
- endp->dequeueing = 1;
- endp->edset_flush = 1;
- u132_endp_queue_work(u132, endp, 0);
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- return 0;
- } else {
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- u132_hcd_abandon_urb(u132, endp, urb, status);
- return 0;
- }
- } else {
- u16 queue_list = 0;
- u16 queue_size = endp->queue_size;
- u16 queue_scan = endp->queue_next;
- struct urb **urb_slot = NULL;
- while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
- if (urb == endp->urb_list[ENDP_QUEUE_MASK &
- ++queue_scan]) {
- urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
- queue_scan];
- break;
- }
- }
- while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
- *urb_slot = endp->urb_list[ENDP_QUEUE_MASK &
- ++queue_scan];
- urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
- queue_scan];
- }
- if (urb_slot) {
- struct usb_hcd *hcd = u132_to_hcd(u132);
-
- usb_hcd_unlink_urb_from_ep(hcd, urb);
- endp->queue_size -= 1;
- if (list_empty(&endp->urb_more)) {
- spin_unlock_irqrestore(&endp->queue_lock.slock,
- irqs);
- } else {
- struct list_head *next = endp->urb_more.next;
- struct u132_urbq *urbq = list_entry(next,
- struct u132_urbq, urb_more);
- list_del(next);
- *urb_slot = urbq->urb;
- spin_unlock_irqrestore(&endp->queue_lock.slock,
- irqs);
- kfree(urbq);
- }
- urb->error_count = 0;
- usb_hcd_giveback_urb(hcd, urb, status);
- return 0;
- } else if (list_empty(&endp->urb_more)) {
- dev_err(&u132->platform_dev->dev, "urb=%p not found in "
- "endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr"
- "=%d size=%d next=%04X last=%04X\n", urb,
- endp->endp_number, endp, endp->ring->number,
- endp->input ? 'I' : ' ',
- endp->output ? 'O' : ' ', endp->usb_endp,
- endp->usb_addr, endp->queue_size,
- endp->queue_next, endp->queue_last);
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- return -EINVAL;
- } else {
- int retval;
-
- usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb);
- retval = dequeue_from_overflow_chain(u132, endp,
- urb);
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- return retval;
- }
- }
-}
-
-static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
-{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 2) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else {
- u8 usb_addr = usb_pipedevice(urb->pipe);
- u8 usb_endp = usb_pipeendpoint(urb->pipe);
- u8 address = u132->addr[usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- if (usb_pipein(urb->pipe)) {
- u8 endp_number = udev->endp_number_in[usb_endp];
- struct u132_endp *endp = u132->endp[endp_number - 1];
- return u132_endp_urb_dequeue(u132, endp, urb, status);
- } else {
- u8 endp_number = udev->endp_number_out[usb_endp];
- struct u132_endp *endp = u132->endp[endp_number - 1];
- return u132_endp_urb_dequeue(u132, endp, urb, status);
- }
- }
-}
-
-static void u132_endpoint_disable(struct usb_hcd *hcd,
- struct usb_host_endpoint *hep)
-{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 2) {
- dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p hep=%p"
- ") has been removed %d\n", u132, hcd, hep,
- u132->going);
- } else {
- struct u132_endp *endp = hep->hcpriv;
- if (endp)
- u132_endp_put_kref(u132, endp);
- }
-}
-
-static int u132_get_frame(struct usb_hcd *hcd)
-{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else {
- dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n");
- mdelay(100);
- return 0;
- }
-}
-
-static int u132_roothub_descriptor(struct u132 *u132,
- struct usb_hub_descriptor *desc)
-{
- int retval;
- u16 temp;
- u32 rh_a = -1;
- u32 rh_b = -1;
- retval = u132_read_pcimem(u132, roothub.a, &rh_a);
- if (retval)
- return retval;
- desc->bDescriptorType = USB_DT_HUB;
- desc->bPwrOn2PwrGood = (rh_a & RH_A_POTPGT) >> 24;
- desc->bHubContrCurrent = 0;
- desc->bNbrPorts = u132->num_ports;
- temp = 1 + (u132->num_ports / 8);
- desc->bDescLength = 7 + 2 * temp;
- temp = HUB_CHAR_COMMON_LPSM | HUB_CHAR_COMMON_OCPM;
- if (rh_a & RH_A_NPS)
- temp |= HUB_CHAR_NO_LPSM;
- if (rh_a & RH_A_PSM)
- temp |= HUB_CHAR_INDV_PORT_LPSM;
- if (rh_a & RH_A_NOCP)
- temp |= HUB_CHAR_NO_OCPM;
- else if (rh_a & RH_A_OCPM)
- temp |= HUB_CHAR_INDV_PORT_OCPM;
- desc->wHubCharacteristics = cpu_to_le16(temp);
- retval = u132_read_pcimem(u132, roothub.b, &rh_b);
- if (retval)
- return retval;
- memset(desc->u.hs.DeviceRemovable, 0xff,
- sizeof(desc->u.hs.DeviceRemovable));
- desc->u.hs.DeviceRemovable[0] = rh_b & RH_B_DR;
- if (u132->num_ports > 7) {
- desc->u.hs.DeviceRemovable[1] = (rh_b & RH_B_DR) >> 8;
- desc->u.hs.DeviceRemovable[2] = 0xff;
- } else
- desc->u.hs.DeviceRemovable[1] = 0xff;
- return 0;
-}
-
-static int u132_roothub_status(struct u132 *u132, __le32 *desc)
-{
- u32 rh_status = -1;
- int ret_status = u132_read_pcimem(u132, roothub.status, &rh_status);
- *desc = cpu_to_le32(rh_status);
- return ret_status;
-}
-
-static int u132_roothub_portstatus(struct u132 *u132, __le32 *desc, u16 wIndex)
-{
- if (wIndex == 0 || wIndex > u132->num_ports) {
- return -EINVAL;
- } else {
- int port = wIndex - 1;
- u32 rh_portstatus = -1;
- int ret_portstatus = u132_read_pcimem(u132,
- roothub.portstatus[port], &rh_portstatus);
- *desc = cpu_to_le32(rh_portstatus);
- if (*(u16 *) (desc + 2)) {
- dev_info(&u132->platform_dev->dev, "Port %d Status Chan"
- "ge = %08X\n", port, *desc);
- }
- return ret_portstatus;
- }
-}
-
-
-/* this timer value might be vendor-specific ... */
-#define PORT_RESET_HW_MSEC 10
-#define PORT_RESET_MSEC 10
-/* wrap-aware logic morphed from <linux/jiffies.h> */
-#define tick_before(t1, t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0)
-static int u132_roothub_portreset(struct u132 *u132, int port_index)
-{
- int retval;
- u32 fmnumber;
- u16 now;
- u16 reset_done;
- retval = u132_read_pcimem(u132, fmnumber, &fmnumber);
- if (retval)
- return retval;
- now = fmnumber;
- reset_done = now + PORT_RESET_MSEC;
- do {
- u32 portstat;
- do {
- retval = u132_read_pcimem(u132,
- roothub.portstatus[port_index], &portstat);
- if (retval)
- return retval;
- if (RH_PS_PRS & portstat)
- continue;
- else
- break;
- } while (tick_before(now, reset_done));
- if (RH_PS_PRS & portstat)
- return -ENODEV;
- if (RH_PS_CCS & portstat) {
- if (RH_PS_PRSC & portstat) {
- retval = u132_write_pcimem(u132,
- roothub.portstatus[port_index],
- RH_PS_PRSC);
- if (retval)
- return retval;
- }
- } else
- break; /* start the next reset,
- sleep till it's probably done */
- retval = u132_write_pcimem(u132, roothub.portstatus[port_index],
- RH_PS_PRS);
- if (retval)
- return retval;
- msleep(PORT_RESET_HW_MSEC);
- retval = u132_read_pcimem(u132, fmnumber, &fmnumber);
- if (retval)
- return retval;
- now = fmnumber;
- } while (tick_before(now, reset_done));
- return 0;
-}
-
-static int u132_roothub_setportfeature(struct u132 *u132, u16 wValue,
- u16 wIndex)
-{
- if (wIndex == 0 || wIndex > u132->num_ports) {
- return -EINVAL;
- } else {
- int port_index = wIndex - 1;
- struct u132_port *port = &u132->port[port_index];
- port->Status &= ~(1 << wValue);
- switch (wValue) {
- case USB_PORT_FEAT_SUSPEND:
- return u132_write_pcimem(u132,
- roothub.portstatus[port_index], RH_PS_PSS);
- case USB_PORT_FEAT_POWER:
- return u132_write_pcimem(u132,
- roothub.portstatus[port_index], RH_PS_PPS);
- case USB_PORT_FEAT_RESET:
- return u132_roothub_portreset(u132, port_index);
- default:
- return -EPIPE;
- }
- }
-}
-
-static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue,
- u16 wIndex)
-{
- if (wIndex == 0 || wIndex > u132->num_ports) {
- return -EINVAL;
- } else {
- int port_index = wIndex - 1;
- u32 temp;
- struct u132_port *port = &u132->port[port_index];
- port->Status &= ~(1 << wValue);
- switch (wValue) {
- case USB_PORT_FEAT_ENABLE:
- temp = RH_PS_CCS;
- break;
- case USB_PORT_FEAT_C_ENABLE:
- temp = RH_PS_PESC;
- break;
- case USB_PORT_FEAT_SUSPEND:
- temp = RH_PS_POCI;
- if ((u132->hc_control & OHCI_CTRL_HCFS)
- != OHCI_USB_OPER) {
- dev_err(&u132->platform_dev->dev, "TODO resume_"
- "root_hub\n");
- }
- break;
- case USB_PORT_FEAT_C_SUSPEND:
- temp = RH_PS_PSSC;
- break;
- case USB_PORT_FEAT_POWER:
- temp = RH_PS_LSDA;
- break;
- case USB_PORT_FEAT_C_CONNECTION:
- temp = RH_PS_CSC;
- break;
- case USB_PORT_FEAT_C_OVER_CURRENT:
- temp = RH_PS_OCIC;
- break;
- case USB_PORT_FEAT_C_RESET:
- temp = RH_PS_PRSC;
- break;
- default:
- return -EPIPE;
- }
- return u132_write_pcimem(u132, roothub.portstatus[port_index],
- temp);
- }
-}
-
-
-/* the virtual root hub timer IRQ checks for hub status*/
-static int u132_hub_status_data(struct usb_hcd *hcd, char *buf)
-{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device hcd=%p has been remov"
- "ed %d\n", hcd, u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
- "ed\n", hcd);
- return -ESHUTDOWN;
- } else {
- int i, changed = 0, length = 1;
- if (u132->flags & OHCI_QUIRK_AMD756) {
- if ((u132->hc_roothub_a & RH_A_NDP) > MAX_ROOT_PORTS) {
- dev_err(&u132->platform_dev->dev, "bogus NDP, r"
- "ereads as NDP=%d\n",
- u132->hc_roothub_a & RH_A_NDP);
- goto done;
- }
- }
- if (u132->hc_roothub_status & (RH_HS_LPSC | RH_HS_OCIC))
- buf[0] = changed = 1;
- else
- buf[0] = 0;
- if (u132->num_ports > 7) {
- buf[1] = 0;
- length++;
- }
- for (i = 0; i < u132->num_ports; i++) {
- if (u132->hc_roothub_portstatus[i] & (RH_PS_CSC |
- RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC |
- RH_PS_PRSC)) {
- changed = 1;
- if (i < 7)
- buf[0] |= 1 << (i + 1);
- else
- buf[1] |= 1 << (i - 7);
- continue;
- }
- if (!(u132->hc_roothub_portstatus[i] & RH_PS_CCS))
- continue;
-
- if ((u132->hc_roothub_portstatus[i] & RH_PS_PSS))
- continue;
- }
-done:
- return changed ? length : 0;
- }
-}
-
-static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
- u16 wIndex, char *buf, u16 wLength)
-{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else {
- int retval = 0;
- mutex_lock(&u132->sw_lock);
- switch (typeReq) {
- case ClearHubFeature:
- switch (wValue) {
- case C_HUB_OVER_CURRENT:
- case C_HUB_LOCAL_POWER:
- break;
- default:
- goto stall;
- }
- break;
- case SetHubFeature:
- switch (wValue) {
- case C_HUB_OVER_CURRENT:
- case C_HUB_LOCAL_POWER:
- break;
- default:
- goto stall;
- }
- break;
- case ClearPortFeature:{
- retval = u132_roothub_clearportfeature(u132,
- wValue, wIndex);
- if (retval)
- goto error;
- break;
- }
- case GetHubDescriptor:{
- retval = u132_roothub_descriptor(u132,
- (struct usb_hub_descriptor *)buf);
- if (retval)
- goto error;
- break;
- }
- case GetHubStatus:{
- retval = u132_roothub_status(u132,
- (__le32 *) buf);
- if (retval)
- goto error;
- break;
- }
- case GetPortStatus:{
- retval = u132_roothub_portstatus(u132,
- (__le32 *) buf, wIndex);
- if (retval)
- goto error;
- break;
- }
- case SetPortFeature:{
- retval = u132_roothub_setportfeature(u132,
- wValue, wIndex);
- if (retval)
- goto error;
- break;
- }
- default:
- goto stall;
- error:
- u132_disable(u132);
- u132->going = 1;
- break;
- stall:
- retval = -EPIPE;
- break;
- }
- mutex_unlock(&u132->sw_lock);
- return retval;
- }
-}
-
-static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num)
-{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else
- return 0;
-}
-
-
-#ifdef CONFIG_PM
-static int u132_bus_suspend(struct usb_hcd *hcd)
-{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else
- return 0;
-}
-
-static int u132_bus_resume(struct usb_hcd *hcd)
-{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else
- return 0;
-}
-
-#else
-#define u132_bus_suspend NULL
-#define u132_bus_resume NULL
-#endif
-static const struct hc_driver u132_hc_driver = {
- .description = hcd_name,
- .hcd_priv_size = sizeof(struct u132),
- .irq = NULL,
- .flags = HCD_USB11 | HCD_MEMORY,
- .reset = u132_hcd_reset,
- .start = u132_hcd_start,
- .stop = u132_hcd_stop,
- .urb_enqueue = u132_urb_enqueue,
- .urb_dequeue = u132_urb_dequeue,
- .endpoint_disable = u132_endpoint_disable,
- .get_frame_number = u132_get_frame,
- .hub_status_data = u132_hub_status_data,
- .hub_control = u132_hub_control,
- .bus_suspend = u132_bus_suspend,
- .bus_resume = u132_bus_resume,
- .start_port_reset = u132_start_port_reset,
-};
-
-/*
-* This function may be called by the USB core whilst the "usb_all_devices_rwsem"
-* is held for writing, thus this module must not call usb_remove_hcd()
-* synchronously - but instead should immediately stop activity to the
-* device and asynchronously call usb_remove_hcd()
-*/
-static int u132_remove(struct platform_device *pdev)
-{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
- if (hcd) {
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going++ > 1) {
- dev_err(&u132->platform_dev->dev, "already being remove"
- "d\n");
- return -ENODEV;
- } else {
- int rings = MAX_U132_RINGS;
- int endps = MAX_U132_ENDPS;
- dev_err(&u132->platform_dev->dev, "removing device u132"
- ".%d\n", u132->sequence_num);
- msleep(100);
- mutex_lock(&u132->sw_lock);
- u132_monitor_cancel_work(u132);
- while (rings-- > 0) {
- struct u132_ring *ring = &u132->ring[rings];
- u132_ring_cancel_work(u132, ring);
- }
- while (endps-- > 0) {
- struct u132_endp *endp = u132->endp[endps];
- if (endp)
- u132_endp_cancel_work(u132, endp);
- }
- u132->going += 1;
- printk(KERN_INFO "removing device u132.%d\n",
- u132->sequence_num);
- mutex_unlock(&u132->sw_lock);
- usb_remove_hcd(hcd);
- u132_u132_put_kref(u132);
- return 0;
- }
- } else
- return 0;
-}
-
-static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
-{
- int rings = MAX_U132_RINGS;
- int ports = MAX_U132_PORTS;
- int addrs = MAX_U132_ADDRS;
- int udevs = MAX_U132_UDEVS;
- int endps = MAX_U132_ENDPS;
- u132->board = dev_get_platdata(&pdev->dev);
- u132->platform_dev = pdev;
- u132->power = 0;
- u132->reset = 0;
- mutex_init(&u132->sw_lock);
- mutex_init(&u132->scheduler_lock);
- while (rings-- > 0) {
- struct u132_ring *ring = &u132->ring[rings];
- ring->u132 = u132;
- ring->number = rings + 1;
- ring->length = 0;
- ring->curr_endp = NULL;
- INIT_DELAYED_WORK(&ring->scheduler,
- u132_hcd_ring_work_scheduler);
- }
- mutex_lock(&u132->sw_lock);
- INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work);
- while (ports-- > 0) {
- struct u132_port *port = &u132->port[ports];
- port->u132 = u132;
- port->reset = 0;
- port->enable = 0;
- port->power = 0;
- port->Status = 0;
- }
- while (addrs-- > 0) {
- struct u132_addr *addr = &u132->addr[addrs];
- addr->address = 0;
- }
- while (udevs-- > 0) {
- struct u132_udev *udev = &u132->udev[udevs];
- int i = ARRAY_SIZE(udev->endp_number_in);
- int o = ARRAY_SIZE(udev->endp_number_out);
- udev->usb_device = NULL;
- udev->udev_number = 0;
- udev->usb_addr = 0;
- udev->portnumber = 0;
- while (i-- > 0)
- udev->endp_number_in[i] = 0;
-
- while (o-- > 0)
- udev->endp_number_out[o] = 0;
-
- }
- while (endps-- > 0)
- u132->endp[endps] = NULL;
-
- mutex_unlock(&u132->sw_lock);
-}
-
-static int u132_probe(struct platform_device *pdev)
-{
- struct usb_hcd *hcd;
- int retval;
- u32 control;
- u32 rh_a = -1;
-
- msleep(100);
- if (u132_exiting > 0)
- return -ENODEV;
-
- retval = ftdi_write_pcimem(pdev, intrdisable, OHCI_INTR_MIE);
- if (retval)
- return retval;
- retval = ftdi_read_pcimem(pdev, control, &control);
- if (retval)
- return retval;
- retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a);
- if (retval)
- return retval;
-
- hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, dev_name(&pdev->dev));
- if (!hcd) {
- printk(KERN_ERR "failed to create the usb hcd struct for U132\n"
- );
- ftdi_elan_gone_away(pdev);
- return -ENOMEM;
- } else {
- struct u132 *u132 = hcd_to_u132(hcd);
- retval = 0;
- hcd->rsrc_start = 0;
- mutex_lock(&u132_module_lock);
- u132->sequence_num = ++u132_instances;
- mutex_unlock(&u132_module_lock);
- u132_u132_init_kref(u132);
- u132_initialise(u132, pdev);
- hcd->product_desc = "ELAN U132 Host Controller";
- retval = usb_add_hcd(hcd, 0, 0);
- if (retval != 0) {
- dev_err(&u132->platform_dev->dev, "init error %d\n",
- retval);
- u132_u132_put_kref(u132);
- return retval;
- } else {
- device_wakeup_enable(hcd->self.controller);
- u132_monitor_queue_work(u132, 100);
- return 0;
- }
- }
-}
-
-
-#ifdef CONFIG_PM
-/*
- * for this device there's no useful distinction between the controller
- * and its root hub.
- */
-static int u132_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else {
- int retval = 0, ports;
-
- switch (state.event) {
- case PM_EVENT_FREEZE:
- retval = u132_bus_suspend(hcd);
- break;
- case PM_EVENT_SUSPEND:
- case PM_EVENT_HIBERNATE:
- ports = MAX_U132_PORTS;
- while (ports-- > 0) {
- port_power(u132, ports, 0);
- }
- break;
- }
- return retval;
- }
-}
-
-static int u132_resume(struct platform_device *pdev)
-{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else {
- int retval = 0;
- if (!u132->port[0].power) {
- int ports = MAX_U132_PORTS;
- while (ports-- > 0) {
- port_power(u132, ports, 1);
- }
- retval = 0;
- } else {
- retval = u132_bus_resume(hcd);
- }
- return retval;
- }
-}
-
-#else
-#define u132_suspend NULL
-#define u132_resume NULL
-#endif
-/*
-* this driver is loaded explicitly by ftdi_u132
-*
-* the platform_driver struct is static because it is per type of module
-*/
-static struct platform_driver u132_platform_driver = {
- .probe = u132_probe,
- .remove = u132_remove,
- .suspend = u132_suspend,
- .resume = u132_resume,
- .driver = {
- .name = hcd_name,
- },
-};
-static int __init u132_hcd_init(void)
-{
- int retval;
- u132_instances = 0;
- u132_exiting = 0;
- if (usb_disabled())
- return -ENODEV;
- workqueue = create_singlethread_workqueue("u132");
- if (!workqueue)
- return -ENOMEM;
- retval = platform_driver_register(&u132_platform_driver);
- if (retval)
- destroy_workqueue(workqueue);
-
- return retval;
-}
-
-
-module_init(u132_hcd_init);
-static void __exit u132_hcd_exit(void)
-{
- mutex_lock(&u132_module_lock);
- u132_exiting += 1;
- mutex_unlock(&u132_module_lock);
- platform_driver_unregister(&u132_platform_driver);
- printk(KERN_INFO "u132-hcd driver deregistered\n");
- wait_event(u132_hcd_wait, u132_instances == 0);
- destroy_workqueue(workqueue);
-}
-
-
-module_exit(u132_hcd_exit);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:u132_hcd");
diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c
index f1367b53b260..b40d9238d447 100644
--- a/drivers/usb/host/xhci-dbgcap.c
+++ b/drivers/usb/host/xhci-dbgcap.c
@@ -124,10 +124,10 @@ static void xhci_dbc_init_contexts(struct xhci_dbc *dbc, u32 string_length)
/* Set DbC context and info registers: */
lo_hi_writeq(dbc->ctx->dma, &dbc->regs->dccp);
- dev_info = cpu_to_le32((DBC_VENDOR_ID << 16) | DBC_PROTOCOL);
+ dev_info = (dbc->idVendor << 16) | dbc->bInterfaceProtocol;
writel(dev_info, &dbc->regs->devinfo1);
- dev_info = cpu_to_le32((DBC_DEVICE_REV << 16) | DBC_PRODUCT_ID);
+ dev_info = (dbc->bcdDevice << 16) | dbc->idProduct;
writel(dev_info, &dbc->regs->devinfo2);
}
@@ -971,7 +971,186 @@ static ssize_t dbc_store(struct device *dev,
return count;
}
+static ssize_t dbc_idVendor_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct xhci_dbc *dbc;
+ struct xhci_hcd *xhci;
+
+ xhci = hcd_to_xhci(dev_get_drvdata(dev));
+ dbc = xhci->dbc;
+
+ return sprintf(buf, "%04x\n", dbc->idVendor);
+}
+
+static ssize_t dbc_idVendor_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct xhci_dbc *dbc;
+ struct xhci_hcd *xhci;
+ void __iomem *ptr;
+ u16 value;
+ u32 dev_info;
+
+ if (kstrtou16(buf, 0, &value))
+ return -EINVAL;
+
+ xhci = hcd_to_xhci(dev_get_drvdata(dev));
+ dbc = xhci->dbc;
+ if (dbc->state != DS_DISABLED)
+ return -EBUSY;
+
+ dbc->idVendor = value;
+ ptr = &dbc->regs->devinfo1;
+ dev_info = readl(ptr);
+ dev_info = (dev_info & ~(0xffffu << 16)) | (value << 16);
+ writel(dev_info, ptr);
+
+ return size;
+}
+
+static ssize_t dbc_idProduct_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct xhci_dbc *dbc;
+ struct xhci_hcd *xhci;
+
+ xhci = hcd_to_xhci(dev_get_drvdata(dev));
+ dbc = xhci->dbc;
+
+ return sprintf(buf, "%04x\n", dbc->idProduct);
+}
+
+static ssize_t dbc_idProduct_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct xhci_dbc *dbc;
+ struct xhci_hcd *xhci;
+ void __iomem *ptr;
+ u32 dev_info;
+ u16 value;
+
+ if (kstrtou16(buf, 0, &value))
+ return -EINVAL;
+
+ xhci = hcd_to_xhci(dev_get_drvdata(dev));
+ dbc = xhci->dbc;
+ if (dbc->state != DS_DISABLED)
+ return -EBUSY;
+
+ dbc->idProduct = value;
+ ptr = &dbc->regs->devinfo2;
+ dev_info = readl(ptr);
+ dev_info = (dev_info & ~(0xffffu)) | value;
+ writel(dev_info, ptr);
+ return size;
+}
+
+static ssize_t dbc_bcdDevice_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct xhci_dbc *dbc;
+ struct xhci_hcd *xhci;
+
+ xhci = hcd_to_xhci(dev_get_drvdata(dev));
+ dbc = xhci->dbc;
+
+ return sprintf(buf, "%04x\n", dbc->bcdDevice);
+}
+
+static ssize_t dbc_bcdDevice_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct xhci_dbc *dbc;
+ struct xhci_hcd *xhci;
+ void __iomem *ptr;
+ u32 dev_info;
+ u16 value;
+
+ if (kstrtou16(buf, 0, &value))
+ return -EINVAL;
+
+ xhci = hcd_to_xhci(dev_get_drvdata(dev));
+ dbc = xhci->dbc;
+ if (dbc->state != DS_DISABLED)
+ return -EBUSY;
+
+ dbc->bcdDevice = value;
+ ptr = &dbc->regs->devinfo2;
+ dev_info = readl(ptr);
+ dev_info = (dev_info & ~(0xffffu << 16)) | (value << 16);
+ writel(dev_info, ptr);
+
+ return size;
+}
+
+static ssize_t dbc_bInterfaceProtocol_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct xhci_dbc *dbc;
+ struct xhci_hcd *xhci;
+
+ xhci = hcd_to_xhci(dev_get_drvdata(dev));
+ dbc = xhci->dbc;
+
+ return sprintf(buf, "%02x\n", dbc->bInterfaceProtocol);
+}
+
+static ssize_t dbc_bInterfaceProtocol_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct xhci_dbc *dbc;
+ struct xhci_hcd *xhci;
+ void __iomem *ptr;
+ u32 dev_info;
+ u8 value;
+ int ret;
+
+ /* bInterfaceProtocol is 8 bit, but xhci only supports values 0 and 1 */
+ ret = kstrtou8(buf, 0, &value);
+ if (ret || value > 1)
+ return -EINVAL;
+
+ xhci = hcd_to_xhci(dev_get_drvdata(dev));
+ dbc = xhci->dbc;
+ if (dbc->state != DS_DISABLED)
+ return -EBUSY;
+
+ dbc->bInterfaceProtocol = value;
+ ptr = &dbc->regs->devinfo1;
+ dev_info = readl(ptr);
+ dev_info = (dev_info & ~(0xffu)) | value;
+ writel(dev_info, ptr);
+
+ return size;
+}
+
static DEVICE_ATTR_RW(dbc);
+static DEVICE_ATTR_RW(dbc_idVendor);
+static DEVICE_ATTR_RW(dbc_idProduct);
+static DEVICE_ATTR_RW(dbc_bcdDevice);
+static DEVICE_ATTR_RW(dbc_bInterfaceProtocol);
+
+static struct attribute *dbc_dev_attributes[] = {
+ &dev_attr_dbc.attr,
+ &dev_attr_dbc_idVendor.attr,
+ &dev_attr_dbc_idProduct.attr,
+ &dev_attr_dbc_bcdDevice.attr,
+ &dev_attr_dbc_bInterfaceProtocol.attr,
+ NULL
+};
+
+static const struct attribute_group dbc_dev_attrib_grp = {
+ .attrs = dbc_dev_attributes,
+};
struct xhci_dbc *
xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver *driver)
@@ -986,6 +1165,10 @@ xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver *
dbc->regs = base;
dbc->dev = dev;
dbc->driver = driver;
+ dbc->idProduct = DBC_PRODUCT_ID;
+ dbc->idVendor = DBC_VENDOR_ID;
+ dbc->bcdDevice = DBC_DEVICE_REV;
+ dbc->bInterfaceProtocol = DBC_PROTOCOL;
if (readl(&dbc->regs->control) & DBC_CTRL_DBC_ENABLE)
goto err;
@@ -993,7 +1176,7 @@ xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver *
INIT_DELAYED_WORK(&dbc->event_work, xhci_dbc_handle_events);
spin_lock_init(&dbc->lock);
- ret = device_create_file(dev, &dev_attr_dbc);
+ ret = sysfs_create_group(&dev->kobj, &dbc_dev_attrib_grp);
if (ret)
goto err;
@@ -1012,7 +1195,7 @@ void xhci_dbc_remove(struct xhci_dbc *dbc)
xhci_dbc_stop(dbc);
/* remove sysfs files */
- device_remove_file(dbc->dev, &dev_attr_dbc);
+ sysfs_remove_group(&dbc->dev->kobj, &dbc_dev_attrib_grp);
kfree(dbc);
}
diff --git a/drivers/usb/host/xhci-dbgcap.h b/drivers/usb/host/xhci-dbgcap.h
index ca04192fdab1..51a7ab3ba0ca 100644
--- a/drivers/usb/host/xhci-dbgcap.h
+++ b/drivers/usb/host/xhci-dbgcap.h
@@ -132,6 +132,10 @@ struct xhci_dbc {
struct dbc_str_descs *string;
dma_addr_t string_dma;
size_t string_size;
+ u16 idVendor;
+ u16 idProduct;
+ u16 bcdDevice;
+ u8 bInterfaceProtocol;
enum dbc_state state;
struct delayed_work event_work;
diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
index 0bc7fe11f749..99baa60ef50f 100644
--- a/drivers/usb/host/xhci-debugfs.c
+++ b/drivers/usb/host/xhci-debugfs.c
@@ -133,6 +133,7 @@ static void xhci_debugfs_regset(struct xhci_hcd *xhci, u32 base,
regset->regs = regs;
regset->nregs = nregs;
regset->base = hcd->regs + base;
+ regset->dev = hcd->self.controller;
debugfs_create_regset32((const char *)rgs->name, 0444, parent, regset);
}
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index d0a9467aa5fc..7e106bd804ca 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -9,6 +9,7 @@
*/
#include <linux/usb.h>
+#include <linux/overflow.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/dmapool.h>
@@ -543,14 +544,11 @@ static void xhci_free_stream_ctx(struct xhci_hcd *xhci,
size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs;
if (size > MEDIUM_STREAM_ARRAY_SIZE)
- dma_free_coherent(dev, size,
- stream_ctx, dma);
- else if (size <= SMALL_STREAM_ARRAY_SIZE)
- return dma_pool_free(xhci->small_streams_pool,
- stream_ctx, dma);
+ dma_free_coherent(dev, size, stream_ctx, dma);
+ else if (size > SMALL_STREAM_ARRAY_SIZE)
+ dma_pool_free(xhci->medium_streams_pool, stream_ctx, dma);
else
- return dma_pool_free(xhci->medium_streams_pool,
- stream_ctx, dma);
+ dma_pool_free(xhci->small_streams_pool, stream_ctx, dma);
}
/*
@@ -568,17 +566,14 @@ static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci,
gfp_t mem_flags)
{
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
- size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs;
+ size_t size = size_mul(sizeof(struct xhci_stream_ctx), num_stream_ctxs);
if (size > MEDIUM_STREAM_ARRAY_SIZE)
- return dma_alloc_coherent(dev, size,
- dma, mem_flags);
- else if (size <= SMALL_STREAM_ARRAY_SIZE)
- return dma_pool_alloc(xhci->small_streams_pool,
- mem_flags, dma);
+ return dma_alloc_coherent(dev, size, dma, mem_flags);
+ if (size > SMALL_STREAM_ARRAY_SIZE)
+ return dma_pool_zalloc(xhci->medium_streams_pool, mem_flags, dma);
else
- return dma_pool_alloc(xhci->medium_streams_pool,
- mem_flags, dma);
+ return dma_pool_zalloc(xhci->small_streams_pool, mem_flags, dma);
}
struct xhci_ring *xhci_dma_to_transfer_ring(
@@ -612,8 +607,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
int ret;
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
- xhci_dbg(xhci, "Allocating %u streams and %u "
- "stream context array entries.\n",
+ xhci_dbg(xhci, "Allocating %u streams and %u stream context array entries.\n",
num_streams, num_stream_ctxs);
if (xhci->cmd_ring_reserved_trbs == MAX_RSVD_CMD_TRBS) {
xhci_dbg(xhci, "Command ring has no reserved TRBs available\n");
@@ -642,8 +636,6 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
mem_flags);
if (!stream_info->stream_ctx_array)
goto cleanup_ring_array;
- memset(stream_info->stream_ctx_array, 0,
- sizeof(struct xhci_stream_ctx)*num_stream_ctxs);
/* Allocate everything needed to free the stream rings later */
stream_info->free_streams_command =
@@ -673,8 +665,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
cur_ring->cycle_state;
stream_info->stream_ctx_array[cur_stream].stream_ring =
cpu_to_le64(addr);
- xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n",
- cur_stream, (unsigned long long) addr);
+ xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n", cur_stream, addr);
ret = xhci_update_stream_mapping(cur_ring, mem_flags);
if (ret) {
@@ -984,16 +975,14 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
if (!dev->out_ctx)
goto fail;
- xhci_dbg(xhci, "Slot %d output ctx = 0x%llx (dma)\n", slot_id,
- (unsigned long long)dev->out_ctx->dma);
+ xhci_dbg(xhci, "Slot %d output ctx = 0x%pad (dma)\n", slot_id, &dev->out_ctx->dma);
/* Allocate the (input) device context for address device command */
dev->in_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT, flags);
if (!dev->in_ctx)
goto fail;
- xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id,
- (unsigned long long)dev->in_ctx->dma);
+ xhci_dbg(xhci, "Slot %d input ctx = 0x%pad (dma)\n", slot_id, &dev->in_ctx->dma);
/* Initialize the cancellation and bandwidth list for each ep */
for (i = 0; i < 31; i++) {
@@ -1400,8 +1389,9 @@ static u32 xhci_get_max_esit_payload(struct usb_device *udev,
if ((udev->speed >= USB_SPEED_SUPER_PLUS) &&
USB_SS_SSP_ISOC_COMP(ep->ss_ep_comp.bmAttributes))
return le32_to_cpu(ep->ssp_isoc_ep_comp.dwBytesPerInterval);
+
/* SuperSpeed or SuperSpeedPlus Isoc ep with less than 48k per esit */
- else if (udev->speed >= USB_SPEED_SUPER)
+ if (udev->speed >= USB_SPEED_SUPER)
return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval);
max_packet = usb_endpoint_maxp(&ep->desc);
@@ -1660,7 +1650,7 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
goto fail_sp;
xhci->scratchpad->sp_array = dma_alloc_coherent(dev,
- num_sp * sizeof(u64),
+ size_mul(sizeof(u64), num_sp),
&xhci->scratchpad->sp_dma, flags);
if (!xhci->scratchpad->sp_array)
goto fail_sp2;
@@ -1685,11 +1675,10 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
return 0;
fail_sp4:
- for (i = i - 1; i >= 0; i--) {
+ while (i--)
dma_free_coherent(dev, xhci->page_size,
xhci->scratchpad->sp_buffers[i],
xhci->scratchpad->sp_array[i]);
- }
kfree(xhci->scratchpad->sp_buffers);
@@ -1799,7 +1788,7 @@ int xhci_alloc_erst(struct xhci_hcd *xhci,
struct xhci_segment *seg;
struct xhci_erst_entry *entry;
- size = sizeof(struct xhci_erst_entry) * evt_ring->num_segs;
+ size = size_mul(sizeof(struct xhci_erst_entry), evt_ring->num_segs);
erst->entries = dma_alloc_coherent(xhci_to_hcd(xhci)->self.sysdev,
size, &erst->erst_dma_addr, flags);
if (!erst->entries)
@@ -1830,7 +1819,7 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
if (!ir)
return;
- erst_size = sizeof(struct xhci_erst_entry) * (ir->erst.num_entries);
+ erst_size = sizeof(struct xhci_erst_entry) * ir->erst.num_entries;
if (ir->erst.entries)
dma_free_coherent(dev, erst_size,
ir->erst.entries,
@@ -1960,8 +1949,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter
deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg,
ir->event_ring->dequeue);
if (!deq)
- xhci_warn(xhci, "WARN something wrong with SW event ring "
- "dequeue ptr.\n");
+ xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr.\n");
/* Update HC event ring dequeue pointer */
temp = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
temp &= ERST_PTR_MASK;
@@ -1970,8 +1958,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter
*/
temp &= ~ERST_EHB;
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "// Write event ring dequeue pointer, "
- "preserving EHB bit");
+ "// Write event ring dequeue pointer, preserving EHB bit");
xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp,
&ir->ir_set->erst_dequeue);
}
@@ -2004,8 +1991,7 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
} else if (major_revision <= 0x02) {
rhub = &xhci->usb2_rhub;
} else {
- xhci_warn(xhci, "Ignoring unknown port speed, "
- "Ext Cap %p, revision = 0x%x\n",
+ xhci_warn(xhci, "Ignoring unknown port speed, Ext Cap %p, revision = 0x%x\n",
addr, major_revision);
/* Ignoring port protocol we can't understand. FIXME */
return;
@@ -2020,9 +2006,8 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
port_offset = XHCI_EXT_PORT_OFF(temp);
port_count = XHCI_EXT_PORT_COUNT(temp);
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "Ext Cap %p, port offset = %u, "
- "count = %u, revision = 0x%x",
- addr, port_offset, port_count, major_revision);
+ "Ext Cap %p, port offset = %u, count = %u, revision = 0x%x",
+ addr, port_offset, port_count, major_revision);
/* Port count includes the current port offset */
if (port_offset == 0 || (port_offset + port_count - 1) > num_ports)
/* WTF? "Valid values are ‘1’ to MaxPorts" */
@@ -2079,10 +2064,8 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
struct xhci_port *hw_port = &xhci->hw_ports[i];
/* Duplicate entry. Ignore the port if the revisions differ. */
if (hw_port->rhub) {
- xhci_warn(xhci, "Duplicate port entry, Ext Cap %p,"
- " port %u\n", addr, i);
- xhci_warn(xhci, "Port was marked as USB %u, "
- "duplicated as USB %u\n",
+ xhci_warn(xhci, "Duplicate port entry, Ext Cap %p, port %u\n", addr, i);
+ xhci_warn(xhci, "Port was marked as USB %u, duplicated as USB %u\n",
hw_port->rhub->maj_rev, major_revision);
/* Only adjust the roothub port counts if we haven't
* found a similar duplicate.
@@ -2358,8 +2341,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
goto fail;
xhci->dcbaa->dma = dma;
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "// Device context base array address = 0x%llx (DMA), %p (virt)",
- (unsigned long long)xhci->dcbaa->dma, xhci->dcbaa);
+ "// Device context base array address = 0x%pad (DMA), %p (virt)",
+ &xhci->dcbaa->dma, xhci->dcbaa);
xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr);
/*
@@ -2400,8 +2383,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
goto fail;
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Allocated command ring at %p", xhci->cmd_ring);
- xhci_dbg_trace(xhci, trace_xhci_dbg_init, "First segment DMA is 0x%llx",
- (unsigned long long)xhci->cmd_ring->first_seg->dma);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "First segment DMA is 0x%pad",
+ &xhci->cmd_ring->first_seg->dma);
/* Set the address in the Command Ring Control register */
val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
@@ -2421,8 +2404,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
val = readl(&xhci->cap_regs->db_off);
val &= DBOFF_MASK;
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "// Doorbell array is located at offset 0x%x"
- " from cap regs base addr", val);
+ "// Doorbell array is located at offset 0x%x from cap regs base addr",
+ val);
xhci->dba = (void __iomem *) xhci->cap_regs + val;
/* Set ir_set to interrupt register set 0 */
diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
index f7cbb08fc506..90cf40d6d0c3 100644
--- a/drivers/usb/host/xhci-mtk.c
+++ b/drivers/usb/host/xhci-mtk.c
@@ -398,6 +398,7 @@ static int xhci_mtk_clks_get(struct xhci_hcd_mtk *mtk)
clks[2].id = "ref_ck";
clks[3].id = "mcu_ck";
clks[4].id = "dma_ck";
+ clks[5].id = "frmcnt_ck";
return devm_clk_bulk_get_optional(mtk->dev, BULK_CLKS_NUM, clks);
}
diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h
index 1174a510dd38..faaaf05e36ce 100644
--- a/drivers/usb/host/xhci-mtk.h
+++ b/drivers/usb/host/xhci-mtk.h
@@ -15,7 +15,7 @@
#include "xhci.h"
-#define BULK_CLKS_NUM 5
+#define BULK_CLKS_NUM 6
#define BULK_VREGS_NUM 2
/* support at most 64 ep, use 32 size hash table */
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 6db07ca419c3..ddb79f23fb3b 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -78,14 +78,207 @@ static const char hcd_name[] = "xhci_hcd";
static struct hc_driver __read_mostly xhci_pci_hc_driver;
static int xhci_pci_setup(struct usb_hcd *hcd);
+static int xhci_pci_run(struct usb_hcd *hcd);
static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
struct usb_tt *tt, gfp_t mem_flags);
static const struct xhci_driver_overrides xhci_pci_overrides __initconst = {
.reset = xhci_pci_setup,
+ .start = xhci_pci_run,
.update_hub_device = xhci_pci_update_hub_device,
};
+static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
+{
+ struct usb_hcd *hcd = xhci_to_hcd(xhci);
+
+ if (hcd->msix_enabled) {
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+ int i;
+
+ for (i = 0; i < xhci->msix_count; i++)
+ synchronize_irq(pci_irq_vector(pdev, i));
+ }
+}
+
+/* Free any IRQs and disable MSI-X */
+static void xhci_cleanup_msix(struct xhci_hcd *xhci)
+{
+ struct usb_hcd *hcd = xhci_to_hcd(xhci);
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+
+ if (xhci->quirks & XHCI_PLAT)
+ return;
+
+ /* return if using legacy interrupt */
+ if (hcd->irq > 0)
+ return;
+
+ if (hcd->msix_enabled) {
+ int i;
+
+ for (i = 0; i < xhci->msix_count; i++)
+ free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci));
+ } else {
+ free_irq(pci_irq_vector(pdev, 0), xhci_to_hcd(xhci));
+ }
+
+ pci_free_irq_vectors(pdev);
+ hcd->msix_enabled = 0;
+}
+
+/*
+ * Set up MSI
+ */
+static int xhci_setup_msi(struct xhci_hcd *xhci)
+{
+ int ret;
+ /*
+ * TODO:Check with MSI Soc for sysdev
+ */
+ struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+
+ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
+ if (ret < 0) {
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "failed to allocate MSI entry");
+ return ret;
+ }
+
+ ret = request_irq(pdev->irq, xhci_msi_irq,
+ 0, "xhci_hcd", xhci_to_hcd(xhci));
+ if (ret) {
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "disable MSI interrupt");
+ pci_free_irq_vectors(pdev);
+ }
+
+ return ret;
+}
+
+/*
+ * Set up MSI-X
+ */
+static int xhci_setup_msix(struct xhci_hcd *xhci)
+{
+ int i, ret;
+ struct usb_hcd *hcd = xhci_to_hcd(xhci);
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+
+ /*
+ * calculate number of msi-x vectors supported.
+ * - HCS_MAX_INTRS: the max number of interrupts the host can handle,
+ * with max number of interrupters based on the xhci HCSPARAMS1.
+ * - num_online_cpus: maximum msi-x vectors per CPUs core.
+ * Add additional 1 vector to ensure always available interrupt.
+ */
+ xhci->msix_count = min(num_online_cpus() + 1,
+ HCS_MAX_INTRS(xhci->hcs_params1));
+
+ ret = pci_alloc_irq_vectors(pdev, xhci->msix_count, xhci->msix_count,
+ PCI_IRQ_MSIX);
+ if (ret < 0) {
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Failed to enable MSI-X");
+ return ret;
+ }
+
+ for (i = 0; i < xhci->msix_count; i++) {
+ ret = request_irq(pci_irq_vector(pdev, i), xhci_msi_irq, 0,
+ "xhci_hcd", xhci_to_hcd(xhci));
+ if (ret)
+ goto disable_msix;
+ }
+
+ hcd->msix_enabled = 1;
+ return ret;
+
+disable_msix:
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "disable MSI-X interrupt");
+ while (--i >= 0)
+ free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci));
+ pci_free_irq_vectors(pdev);
+ return ret;
+}
+
+static int xhci_try_enable_msi(struct usb_hcd *hcd)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct pci_dev *pdev;
+ int ret;
+
+ /* The xhci platform device has set up IRQs through usb_add_hcd. */
+ if (xhci->quirks & XHCI_PLAT)
+ return 0;
+
+ pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+ /*
+ * Some Fresco Logic host controllers advertise MSI, but fail to
+ * generate interrupts. Don't even try to enable MSI.
+ */
+ if (xhci->quirks & XHCI_BROKEN_MSI)
+ goto legacy_irq;
+
+ /* unregister the legacy interrupt */
+ if (hcd->irq)
+ free_irq(hcd->irq, hcd);
+ hcd->irq = 0;
+
+ ret = xhci_setup_msix(xhci);
+ if (ret)
+ /* fall back to msi*/
+ ret = xhci_setup_msi(xhci);
+
+ if (!ret) {
+ hcd->msi_enabled = 1;
+ return 0;
+ }
+
+ if (!pdev->irq) {
+ xhci_err(xhci, "No msi-x/msi found and no IRQ in BIOS\n");
+ return -EINVAL;
+ }
+
+ legacy_irq:
+ if (!strlen(hcd->irq_descr))
+ snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
+ hcd->driver->description, hcd->self.busnum);
+
+ /* fall back to legacy interrupt*/
+ ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,
+ hcd->irq_descr, hcd);
+ if (ret) {
+ xhci_err(xhci, "request interrupt %d failed\n",
+ pdev->irq);
+ return ret;
+ }
+ hcd->irq = pdev->irq;
+ return 0;
+}
+
+static int xhci_pci_run(struct usb_hcd *hcd)
+{
+ int ret;
+
+ if (usb_hcd_is_primary_hcd(hcd)) {
+ ret = xhci_try_enable_msi(hcd);
+ if (ret)
+ return ret;
+ }
+
+ return xhci_run(hcd);
+}
+
+static void xhci_pci_stop(struct usb_hcd *hcd)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+ xhci_stop(hcd);
+
+ if (usb_hcd_is_primary_hcd(hcd))
+ xhci_cleanup_msix(xhci);
+}
+
/* called after powerup, by probe or system-pm "wakeup" */
static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev)
{
@@ -535,7 +728,6 @@ static void xhci_pci_remove(struct pci_dev *dev)
usb_hcd_pci_remove(dev);
}
-#ifdef CONFIG_PM
/*
* In some Intel xHCI controllers, in order to get D3 working,
* through a vendor specific SSIC CONFIG register at offset 0x883c,
@@ -622,6 +814,10 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
xhci_sparse_control_quirk(hcd);
ret = xhci_suspend(xhci, do_wakeup);
+
+ /* synchronize irq when using MSI-X */
+ xhci_msix_sync_irqs(xhci);
+
if (ret && (xhci->quirks & XHCI_SSIC_PORT_UNUSED))
xhci_ssic_port_unused_quirk(hcd, false);
@@ -724,12 +920,12 @@ static void xhci_pci_shutdown(struct usb_hcd *hcd)
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
xhci_shutdown(hcd);
+ xhci_cleanup_msix(xhci);
/* Yet another workaround for spurious wakeups at shutdown with HSW */
if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
pci_set_power_state(pdev, PCI_D3hot);
}
-#endif /* CONFIG_PM */
/*-------------------------------------------------------------------------*/
@@ -771,22 +967,19 @@ static struct pci_driver xhci_pci_driver = {
/* suspend and resume implemented later */
.shutdown = usb_hcd_pci_shutdown,
-#ifdef CONFIG_PM
.driver = {
- .pm = &usb_hcd_pci_pm_ops
+ .pm = pm_ptr(&usb_hcd_pci_pm_ops),
},
-#endif
};
static int __init xhci_pci_init(void)
{
xhci_init_driver(&xhci_pci_hc_driver, &xhci_pci_overrides);
-#ifdef CONFIG_PM
- xhci_pci_hc_driver.pci_suspend = xhci_pci_suspend;
- xhci_pci_hc_driver.pci_resume = xhci_pci_resume;
- xhci_pci_hc_driver.pci_poweroff_late = xhci_pci_poweroff_late;
- xhci_pci_hc_driver.shutdown = xhci_pci_shutdown;
-#endif
+ xhci_pci_hc_driver.pci_suspend = pm_ptr(xhci_pci_suspend);
+ xhci_pci_hc_driver.pci_resume = pm_ptr(xhci_pci_resume);
+ xhci_pci_hc_driver.pci_poweroff_late = pm_ptr(xhci_pci_poweroff_late);
+ xhci_pci_hc_driver.shutdown = pm_ptr(xhci_pci_shutdown);
+ xhci_pci_hc_driver.stop = xhci_pci_stop;
return pci_register_driver(&xhci_pci_driver);
}
module_init(xhci_pci_init);
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index b9f9625467d6..b0c8e8efc43b 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -291,6 +291,21 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s
goto dealloc_usb2_hcd;
}
+ xhci->shared_hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev,
+ "usb-phy", 1);
+ if (IS_ERR(xhci->shared_hcd->usb_phy)) {
+ if (PTR_ERR(xhci->shared_hcd->usb_phy) != -ENODEV)
+ dev_err(sysdev, "%s get usb3phy fail (ret=%d)\n",
+ __func__,
+ (int)PTR_ERR(xhci->shared_hcd->usb_phy));
+ xhci->shared_hcd->usb_phy = NULL;
+ } else {
+ ret = usb_phy_init(xhci->shared_hcd->usb_phy);
+ if (ret)
+ dev_err(sysdev, "%s init usb3phy fail (ret=%d)\n",
+ __func__, ret);
+ }
+
xhci->shared_hcd->tpl_support = hcd->tpl_support;
}
@@ -362,10 +377,8 @@ static int xhci_generic_plat_probe(struct platform_device *pdev)
if (is_of_node(sysdev->fwnode) ||
is_acpi_device_node(sysdev->fwnode))
break;
-#ifdef CONFIG_PCI
- else if (sysdev->bus == &pci_bus_type)
+ else if (dev_is_pci(sysdev))
break;
-#endif
}
if (!sysdev)
diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c
index 7f18509a1d39..ad966b797b89 100644
--- a/drivers/usb/host/xhci-rcar.c
+++ b/drivers/usb/host/xhci-rcar.c
@@ -12,26 +12,22 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/usb/phy.h>
-#include <linux/sys_soc.h>
#include "xhci.h"
#include "xhci-plat.h"
#include "xhci-rzv2m.h"
#define XHCI_RCAR_FIRMWARE_NAME_V1 "r8a779x_usb3_v1.dlmem"
-#define XHCI_RCAR_FIRMWARE_NAME_V2 "r8a779x_usb3_v2.dlmem"
#define XHCI_RCAR_FIRMWARE_NAME_V3 "r8a779x_usb3_v3.dlmem"
/*
-* - The V3 firmware is for almost all R-Car Gen3 (except r8a7795 ES1.x)
-* - The V2 firmware is for r8a7795 ES1.x.
+* - The V3 firmware is for all R-Car Gen3
* - The V2 firmware is possible to use on R-Car Gen2. However, the V2 causes
* performance degradation. So, this driver continues to use the V1 if R-Car
* Gen2.
* - The V1 firmware is impossible to use on R-Car Gen3.
*/
MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V1);
-MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V2);
MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3);
/*** Register Offset ***/
@@ -78,18 +74,6 @@ MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3);
#define RCAR_USB3_RX_POL_VAL BIT(21)
#define RCAR_USB3_TX_POL_VAL BIT(4)
-/* For soc_device_attribute */
-#define RCAR_XHCI_FIRMWARE_V2 BIT(0) /* FIRMWARE V2 */
-#define RCAR_XHCI_FIRMWARE_V3 BIT(1) /* FIRMWARE V3 */
-
-static const struct soc_device_attribute rcar_quirks_match[] = {
- {
- .soc_id = "r8a7795", .revision = "ES1.*",
- .data = (void *)RCAR_XHCI_FIRMWARE_V2,
- },
- { /* sentinel */ }
-};
-
static void xhci_rcar_start_gen2(struct usb_hcd *hcd)
{
/* LCLK Select */
@@ -135,9 +119,6 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd)
const struct firmware *fw;
int retval, index, j;
u32 data, val, temp;
- u32 quirks = 0;
- const struct soc_device_attribute *attr;
- const char *firmware_name;
/*
* According to the datasheet, "Upon the completion of FW Download,
@@ -146,19 +127,8 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd)
if (readl(regs + RCAR_USB3_DL_CTRL) & RCAR_USB3_DL_CTRL_FW_SUCCESS)
return 0;
- attr = soc_device_match(rcar_quirks_match);
- if (attr)
- quirks = (uintptr_t)attr->data;
-
- if (quirks & RCAR_XHCI_FIRMWARE_V2)
- firmware_name = XHCI_RCAR_FIRMWARE_NAME_V2;
- else if (quirks & RCAR_XHCI_FIRMWARE_V3)
- firmware_name = XHCI_RCAR_FIRMWARE_NAME_V3;
- else
- firmware_name = priv->firmware_name;
-
/* request R-Car USB3.0 firmware */
- retval = request_firmware(&fw, firmware_name, dev);
+ retval = request_firmware(&fw, priv->firmware_name, dev);
if (retval)
return retval;
@@ -312,7 +282,7 @@ static struct platform_driver usb_xhci_renesas_driver = {
.driver = {
.name = "xhci-renesas-hcd",
.pm = &xhci_plat_pm_ops,
- .of_match_table = of_match_ptr(usb_xhci_of_match),
+ .of_match_table = usb_xhci_of_match,
},
};
module_platform_driver(usb_xhci_renesas_driver);
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index eb788c60c1c0..1ad12d5a4857 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -3106,6 +3106,7 @@ irqreturn_t xhci_msi_irq(int irq, void *hcd)
{
return xhci_irq(hcd);
}
+EXPORT_SYMBOL_GPL(xhci_msi_irq);
/**** Endpoint Ring Operations ****/
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
index a88c39e525c2..c75d93244143 100644
--- a/drivers/usb/host/xhci-tegra.c
+++ b/drivers/usb/host/xhci-tegra.c
@@ -1535,7 +1535,6 @@ static void tegra_xusb_deinit_usb_phy(struct tegra_xusb *tegra)
static int tegra_xusb_probe(struct platform_device *pdev)
{
- struct of_phandle_args args;
struct tegra_xusb *tegra;
struct device_node *np;
struct resource *regs;
@@ -1594,15 +1593,13 @@ static int tegra_xusb_probe(struct platform_device *pdev)
goto put_padctl;
}
- /* Older device-trees don't have padctrl interrupt */
- err = of_irq_parse_one(np, 0, &args);
- if (!err) {
- tegra->padctl_irq = of_irq_get(np, 0);
- if (tegra->padctl_irq <= 0) {
- err = (tegra->padctl_irq == 0) ? -ENODEV : tegra->padctl_irq;
- goto put_padctl;
- }
- } else {
+ tegra->padctl_irq = of_irq_get(np, 0);
+ if (tegra->padctl_irq == -EPROBE_DEFER) {
+ err = tegra->padctl_irq;
+ goto put_padctl;
+ } else if (tegra->padctl_irq <= 0) {
+ /* Older device-trees don't have padctrl interrupt */
+ tegra->padctl_irq = 0;
dev_dbg(&pdev->dev,
"%pOF is missing an interrupt, disabling PM support\n", np);
}
diff --git a/drivers/usb/host/xhci-trace.c b/drivers/usb/host/xhci-trace.c
index d0070814d1ea..062662d23241 100644
--- a/drivers/usb/host/xhci-trace.c
+++ b/drivers/usb/host/xhci-trace.c
@@ -12,3 +12,4 @@
#include "xhci-trace.h"
EXPORT_TRACEPOINT_SYMBOL_GPL(xhci_dbg_quirks);
+EXPORT_TRACEPOINT_SYMBOL_GPL(xhci_dbg_init);
diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h
index 61e93a3540a7..4286dba5b157 100644
--- a/drivers/usb/host/xhci-trace.h
+++ b/drivers/usb/host/xhci-trace.h
@@ -120,7 +120,6 @@ DECLARE_EVENT_CLASS(xhci_log_trb,
__field(u32, field1)
__field(u32, field2)
__field(u32, field3)
- __dynamic_array(char, str, XHCI_MSG_MAX)
),
TP_fast_assign(
__entry->type = ring->type;
@@ -130,8 +129,8 @@ DECLARE_EVENT_CLASS(xhci_log_trb,
__entry->field3 = le32_to_cpu(trb->field[3]);
),
TP_printk("%s: %s", xhci_ring_type_string(__entry->type),
- xhci_decode_trb(__get_str(str), XHCI_MSG_MAX, __entry->field0, __entry->field1,
- __entry->field2, __entry->field3)
+ xhci_decode_trb(__get_buf(XHCI_MSG_MAX), XHCI_MSG_MAX, __entry->field0,
+ __entry->field1, __entry->field2, __entry->field3)
)
);
@@ -322,7 +321,6 @@ DECLARE_EVENT_CLASS(xhci_log_ep_ctx,
__field(u32, info2)
__field(u64, deq)
__field(u32, tx_info)
- __dynamic_array(char, str, XHCI_MSG_MAX)
),
TP_fast_assign(
__entry->info = le32_to_cpu(ctx->ep_info);
@@ -330,7 +328,7 @@ DECLARE_EVENT_CLASS(xhci_log_ep_ctx,
__entry->deq = le64_to_cpu(ctx->deq);
__entry->tx_info = le32_to_cpu(ctx->tx_info);
),
- TP_printk("%s", xhci_decode_ep_context(__get_str(str),
+ TP_printk("%s", xhci_decode_ep_context(__get_buf(XHCI_MSG_MAX),
__entry->info, __entry->info2, __entry->deq, __entry->tx_info)
)
);
@@ -368,7 +366,6 @@ DECLARE_EVENT_CLASS(xhci_log_slot_ctx,
__field(u32, info2)
__field(u32, tt_info)
__field(u32, state)
- __dynamic_array(char, str, XHCI_MSG_MAX)
),
TP_fast_assign(
__entry->info = le32_to_cpu(ctx->dev_info);
@@ -376,7 +373,7 @@ DECLARE_EVENT_CLASS(xhci_log_slot_ctx,
__entry->tt_info = le64_to_cpu(ctx->tt_info);
__entry->state = le32_to_cpu(ctx->dev_state);
),
- TP_printk("%s", xhci_decode_slot_context(__get_str(str),
+ TP_printk("%s", xhci_decode_slot_context(__get_buf(XHCI_MSG_MAX),
__entry->info, __entry->info2,
__entry->tt_info, __entry->state)
)
@@ -433,13 +430,12 @@ DECLARE_EVENT_CLASS(xhci_log_ctrl_ctx,
TP_STRUCT__entry(
__field(u32, drop)
__field(u32, add)
- __dynamic_array(char, str, XHCI_MSG_MAX)
),
TP_fast_assign(
__entry->drop = le32_to_cpu(ctrl_ctx->drop_flags);
__entry->add = le32_to_cpu(ctrl_ctx->add_flags);
),
- TP_printk("%s", xhci_decode_ctrl_ctx(__get_str(str), __entry->drop, __entry->add)
+ TP_printk("%s", xhci_decode_ctrl_ctx(__get_buf(XHCI_MSG_MAX), __entry->drop, __entry->add)
)
);
@@ -525,7 +521,6 @@ DECLARE_EVENT_CLASS(xhci_log_portsc,
TP_STRUCT__entry(
__field(u32, portnum)
__field(u32, portsc)
- __dynamic_array(char, str, XHCI_MSG_MAX)
),
TP_fast_assign(
__entry->portnum = portnum;
@@ -533,7 +528,7 @@ DECLARE_EVENT_CLASS(xhci_log_portsc,
),
TP_printk("port-%d: %s",
__entry->portnum,
- xhci_decode_portsc(__get_str(str), __entry->portsc)
+ xhci_decode_portsc(__get_buf(XHCI_MSG_MAX), __entry->portsc)
)
);
@@ -558,14 +553,13 @@ DECLARE_EVENT_CLASS(xhci_log_doorbell,
TP_STRUCT__entry(
__field(u32, slot)
__field(u32, doorbell)
- __dynamic_array(char, str, XHCI_MSG_MAX)
),
TP_fast_assign(
__entry->slot = slot;
__entry->doorbell = doorbell;
),
TP_printk("Ring doorbell for %s",
- xhci_decode_doorbell(__get_str(str), __entry->slot, __entry->doorbell)
+ xhci_decode_doorbell(__get_buf(XHCI_MSG_MAX), __entry->slot, __entry->doorbell)
)
);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 6307bae9cddf..78790dc13c5f 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -322,192 +322,6 @@ static int xhci_disable_interrupter(struct xhci_interrupter *ir)
return 0;
}
-#ifdef CONFIG_USB_PCI
-/*
- * Set up MSI
- */
-static int xhci_setup_msi(struct xhci_hcd *xhci)
-{
- int ret;
- /*
- * TODO:Check with MSI Soc for sysdev
- */
- struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
-
- ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
- if (ret < 0) {
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "failed to allocate MSI entry");
- return ret;
- }
-
- ret = request_irq(pdev->irq, xhci_msi_irq,
- 0, "xhci_hcd", xhci_to_hcd(xhci));
- if (ret) {
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "disable MSI interrupt");
- pci_free_irq_vectors(pdev);
- }
-
- return ret;
-}
-
-/*
- * Set up MSI-X
- */
-static int xhci_setup_msix(struct xhci_hcd *xhci)
-{
- int i, ret;
- struct usb_hcd *hcd = xhci_to_hcd(xhci);
- struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
-
- /*
- * calculate number of msi-x vectors supported.
- * - HCS_MAX_INTRS: the max number of interrupts the host can handle,
- * with max number of interrupters based on the xhci HCSPARAMS1.
- * - num_online_cpus: maximum msi-x vectors per CPUs core.
- * Add additional 1 vector to ensure always available interrupt.
- */
- xhci->msix_count = min(num_online_cpus() + 1,
- HCS_MAX_INTRS(xhci->hcs_params1));
-
- ret = pci_alloc_irq_vectors(pdev, xhci->msix_count, xhci->msix_count,
- PCI_IRQ_MSIX);
- if (ret < 0) {
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "Failed to enable MSI-X");
- return ret;
- }
-
- for (i = 0; i < xhci->msix_count; i++) {
- ret = request_irq(pci_irq_vector(pdev, i), xhci_msi_irq, 0,
- "xhci_hcd", xhci_to_hcd(xhci));
- if (ret)
- goto disable_msix;
- }
-
- hcd->msix_enabled = 1;
- return ret;
-
-disable_msix:
- xhci_dbg_trace(xhci, trace_xhci_dbg_init, "disable MSI-X interrupt");
- while (--i >= 0)
- free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci));
- pci_free_irq_vectors(pdev);
- return ret;
-}
-
-/* Free any IRQs and disable MSI-X */
-static void xhci_cleanup_msix(struct xhci_hcd *xhci)
-{
- struct usb_hcd *hcd = xhci_to_hcd(xhci);
- struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
-
- if (xhci->quirks & XHCI_PLAT)
- return;
-
- /* return if using legacy interrupt */
- if (hcd->irq > 0)
- return;
-
- if (hcd->msix_enabled) {
- int i;
-
- for (i = 0; i < xhci->msix_count; i++)
- free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci));
- } else {
- free_irq(pci_irq_vector(pdev, 0), xhci_to_hcd(xhci));
- }
-
- pci_free_irq_vectors(pdev);
- hcd->msix_enabled = 0;
-}
-
-static void __maybe_unused xhci_msix_sync_irqs(struct xhci_hcd *xhci)
-{
- struct usb_hcd *hcd = xhci_to_hcd(xhci);
-
- if (hcd->msix_enabled) {
- struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
- int i;
-
- for (i = 0; i < xhci->msix_count; i++)
- synchronize_irq(pci_irq_vector(pdev, i));
- }
-}
-
-static int xhci_try_enable_msi(struct usb_hcd *hcd)
-{
- struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- struct pci_dev *pdev;
- int ret;
-
- /* The xhci platform device has set up IRQs through usb_add_hcd. */
- if (xhci->quirks & XHCI_PLAT)
- return 0;
-
- pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
- /*
- * Some Fresco Logic host controllers advertise MSI, but fail to
- * generate interrupts. Don't even try to enable MSI.
- */
- if (xhci->quirks & XHCI_BROKEN_MSI)
- goto legacy_irq;
-
- /* unregister the legacy interrupt */
- if (hcd->irq)
- free_irq(hcd->irq, hcd);
- hcd->irq = 0;
-
- ret = xhci_setup_msix(xhci);
- if (ret)
- /* fall back to msi*/
- ret = xhci_setup_msi(xhci);
-
- if (!ret) {
- hcd->msi_enabled = 1;
- return 0;
- }
-
- if (!pdev->irq) {
- xhci_err(xhci, "No msi-x/msi found and no IRQ in BIOS\n");
- return -EINVAL;
- }
-
- legacy_irq:
- if (!strlen(hcd->irq_descr))
- snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
- hcd->driver->description, hcd->self.busnum);
-
- /* fall back to legacy interrupt*/
- ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,
- hcd->irq_descr, hcd);
- if (ret) {
- xhci_err(xhci, "request interrupt %d failed\n",
- pdev->irq);
- return ret;
- }
- hcd->irq = pdev->irq;
- return 0;
-}
-
-#else
-
-static inline int xhci_try_enable_msi(struct usb_hcd *hcd)
-{
- return 0;
-}
-
-static inline void xhci_cleanup_msix(struct xhci_hcd *xhci)
-{
-}
-
-static inline void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
-{
-}
-
-#endif
-
static void compliance_mode_recovery(struct timer_list *t)
{
struct xhci_hcd *xhci;
@@ -705,10 +519,6 @@ int xhci_run(struct usb_hcd *hcd)
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_run");
- ret = xhci_try_enable_msi(hcd);
- if (ret)
- return ret;
-
temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
temp_64 &= ~ERST_PTR_MASK;
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
@@ -758,7 +568,7 @@ EXPORT_SYMBOL_GPL(xhci_run);
* Disable device contexts, disable IRQs, and quiesce the HC.
* Reset the HC, finish any completed transactions, and cleanup memory.
*/
-static void xhci_stop(struct usb_hcd *hcd)
+void xhci_stop(struct usb_hcd *hcd)
{
u32 temp;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
@@ -781,8 +591,6 @@ static void xhci_stop(struct usb_hcd *hcd)
xhci_reset(xhci, XHCI_RESET_SHORT_USEC);
spin_unlock_irq(&xhci->lock);
- xhci_cleanup_msix(xhci);
-
/* Deleting Compliance Mode Recovery Timer */
if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
(!(xhci_all_ports_seen_u0(xhci)))) {
@@ -809,6 +617,7 @@ static void xhci_stop(struct usb_hcd *hcd)
readl(&xhci->op_regs->status));
mutex_unlock(&xhci->mutex);
}
+EXPORT_SYMBOL_GPL(xhci_stop);
/*
* Shutdown HC (not bus-specific)
@@ -850,8 +659,6 @@ void xhci_shutdown(struct usb_hcd *hcd)
spin_unlock_irq(&xhci->lock);
- xhci_cleanup_msix(xhci);
-
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"xhci_shutdown completed - status = %x",
readl(&xhci->op_regs->status));
@@ -1143,10 +950,6 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
__func__);
}
- /* step 5: remove core well power */
- /* synchronize irq when using MSI-X */
- xhci_msix_sync_irqs(xhci);
-
return rc;
}
EXPORT_SYMBOL_GPL(xhci_suspend);
@@ -1250,7 +1053,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
spin_unlock_irq(&xhci->lock);
if (retval)
return retval;
- xhci_cleanup_msix(xhci);
xhci_dbg(xhci, "// Disabling event ring interrupts\n");
temp = readl(&xhci->op_regs->status);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 786002bb35db..08d721921b7b 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -2125,6 +2125,7 @@ int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us);
int xhci_run(struct usb_hcd *hcd);
int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks);
void xhci_shutdown(struct usb_hcd *hcd);
+void xhci_stop(struct usb_hcd *hcd);
void xhci_init_driver(struct hc_driver *drv,
const struct xhci_driver_overrides *over);
int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index a5f7652db7da..99b15b77dfd5 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -4,6 +4,35 @@
#
comment "USB Miscellaneous drivers"
+config USB_USS720
+ tristate "USS720 parport driver"
+ depends on PARPORT
+ select PARPORT_NOT_PC
+ help
+ This driver is for USB parallel port adapters that use the Lucent
+ Technologies USS-720 chip. These cables are plugged into your USB
+ port and provide USB compatibility to peripherals designed with
+ parallel port interfaces.
+
+ The chip has two modes: automatic mode and manual mode. In automatic
+ mode, it looks to the computer like a standard USB printer. Only
+ printers may be connected to the USS-720 in this mode. The generic
+ USB printer driver ("USB Printer support", above) may be used in
+ that mode, and you can say N here if you want to use the chip only
+ in this mode.
+
+ Manual mode is not limited to printers, any parallel port
+ device should work. This driver utilizes manual mode.
+ Note however that some operations are three orders of magnitude
+ slower than on a PCI/ISA Parallel Port, so timing critical
+ applications might not work.
+
+ Say Y here if you own an USS-720 USB->Parport cable and intend to
+ connect anything other than a printer to it.
+
+ To compile this driver as a module, choose M here: the
+ module will be called uss720.
+
config USB_EMI62
tristate "EMI 6|2m USB Audio interface support"
help
@@ -108,28 +137,6 @@ config USB_IDMOUSE
See also <https://www.fs.tum.de/~echtler/idmouse/>.
-config USB_FTDI_ELAN
- tristate "Elan PCMCIA CardBus Adapter USB Client"
- help
- ELAN's Uxxx series of adapters are USB to PCMCIA CardBus adapters.
- Currently only the U132 adapter is available.
-
- The U132 is specifically designed for CardBus PC cards that contain
- an OHCI host controller. Typical PC cards are the Orange Mobile 3G
- Option GlobeTrotter Fusion card. The U132 adapter will *NOT* work
- with PC cards that do not contain an OHCI controller. To use a U132
- adapter you will need this "ftdi-elan" module as well as the "u132-hcd"
- module which is a USB host controller driver that talks to the OHCI
- controller within CardBus card that are inserted in the U132 adapter.
-
- This driver has been tested with a CardBus OHCI USB adapter, and
- worked with a USB PEN Drive inserted into the first USB port of
- the PCCARD. A rather pointless thing to do, but useful for testing.
-
- See also the USB_U132_HCD entry "Elan U132 Adapter Host Controller"
-
- It is safe to say M here.
-
config USB_APPLEDISPLAY
tristate "Apple Cinema Display support"
select BACKLIGHT_CLASS_DEVICE
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 93581baec3a8..1992cc284d8a 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -10,7 +10,6 @@ obj-$(CONFIG_USB_CYTHERM) += cytherm.o
obj-$(CONFIG_USB_EMI26) += emi26.o
obj-$(CONFIG_USB_EMI62) += emi62.o
obj-$(CONFIG_USB_EZUSB_FX2) += ezusb.o
-obj-$(CONFIG_USB_FTDI_ELAN) += ftdi-elan.o
obj-$(CONFIG_APPLE_MFI_FASTCHARGE) += apple-mfi-fastcharge.o
obj-$(CONFIG_USB_IDMOUSE) += idmouse.o
obj-$(CONFIG_USB_IOWARRIOR) += iowarrior.o
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
deleted file mode 100644
index 8ce191e3a4c0..000000000000
--- a/drivers/usb/misc/ftdi-elan.c
+++ /dev/null
@@ -1,2780 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * USB FTDI client driver for Elan Digital Systems's Uxxx adapters
- *
- * Copyright(C) 2006 Elan Digital Systems Limited
- * http://www.elandigitalsystems.com
- *
- * Author and Maintainer - Tony Olech - Elan Digital Systems
- * tony.olech@elandigitalsystems.com
- *
- * This driver was written by Tony Olech(tony.olech@elandigitalsystems.com)
- * based on various USB client drivers in the 2.6.15 linux kernel
- * with constant reference to the 3rd Edition of Linux Device Drivers
- * published by O'Reilly
- *
- * The U132 adapter is a USB to CardBus adapter specifically designed
- * for PC cards that contain an OHCI host controller. Typical PC cards
- * are the Orange Mobile 3G Option GlobeTrotter Fusion card.
- *
- * The U132 adapter will *NOT *work with PC cards that do not contain
- * an OHCI controller. A simple way to test whether a PC card has an
- * OHCI controller as an interface is to insert the PC card directly
- * into a laptop(or desktop) with a CardBus slot and if "lspci" shows
- * a new USB controller and "lsusb -v" shows a new OHCI Host Controller
- * then there is a good chance that the U132 adapter will support the
- * PC card.(you also need the specific client driver for the PC card)
- *
- * Please inform the Author and Maintainer about any PC cards that
- * contain OHCI Host Controller and work when directly connected to
- * an embedded CardBus slot but do not work when they are connected
- * via an ELAN U132 adapter.
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/ioctl.h>
-#include <linux/pci_ids.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/kref.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <linux/usb.h>
-#include <linux/workqueue.h>
-#include <linux/platform_device.h>
-MODULE_AUTHOR("Tony Olech");
-MODULE_DESCRIPTION("FTDI ELAN driver");
-MODULE_LICENSE("GPL");
-#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444)
-static bool distrust_firmware = 1;
-module_param(distrust_firmware, bool, 0);
-MODULE_PARM_DESC(distrust_firmware,
- "true to distrust firmware power/overcurrent setup");
-extern struct platform_driver u132_platform_driver;
-/*
- * ftdi_module_lock exists to protect access to global variables
- *
- */
-static struct mutex ftdi_module_lock;
-static int ftdi_instances = 0;
-static struct list_head ftdi_static_list;
-/*
- * end of the global variables protected by ftdi_module_lock
- */
-#include "usb_u132.h"
-#include <asm/io.h>
-#include <linux/usb/hcd.h>
-
-/* FIXME ohci.h is ONLY for internal use by the OHCI driver.
- * If you're going to try stuff like this, you need to split
- * out shareable stuff (register declarations?) into its own
- * file, maybe name <linux/usb/ohci.h>
- */
-
-#include "../host/ohci.h"
-/* Define these values to match your devices*/
-#define USB_FTDI_ELAN_VENDOR_ID 0x0403
-#define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea
-/* table of devices that work with this driver*/
-static const struct usb_device_id ftdi_elan_table[] = {
- {USB_DEVICE(USB_FTDI_ELAN_VENDOR_ID, USB_FTDI_ELAN_PRODUCT_ID)},
- { /* Terminating entry */ }
-};
-
-MODULE_DEVICE_TABLE(usb, ftdi_elan_table);
-/* only the jtag(firmware upgrade device) interface requires
- * a device file and corresponding minor number, but the
- * interface is created unconditionally - I suppose it could
- * be configured or not according to a module parameter.
- * But since we(now) require one interface per device,
- * and since it unlikely that a normal installation would
- * require more than a couple of elan-ftdi devices, 8 seems
- * like a reasonable limit to have here, and if someone
- * really requires more than 8 devices, then they can frig the
- * code and recompile
- */
-#define USB_FTDI_ELAN_MINOR_BASE 192
-#define COMMAND_BITS 5
-#define COMMAND_SIZE (1<<COMMAND_BITS)
-#define COMMAND_MASK (COMMAND_SIZE-1)
-struct u132_command {
- u8 header;
- u16 length;
- u8 address;
- u8 width;
- u32 value;
- int follows;
- void *buffer;
-};
-#define RESPOND_BITS 5
-#define RESPOND_SIZE (1<<RESPOND_BITS)
-#define RESPOND_MASK (RESPOND_SIZE-1)
-struct u132_respond {
- u8 header;
- u8 address;
- u32 *value;
- int *result;
- struct completion wait_completion;
-};
-struct u132_target {
- void *endp;
- struct urb *urb;
- int toggle_bits;
- int error_count;
- int condition_code;
- int repeat_number;
- int halted;
- int skipped;
- int actual;
- int non_null;
- int active;
- int abandoning;
- void (*callback)(void *endp, struct urb *urb, u8 *buf, int len,
- int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual,
- int non_null);
-};
-/* Structure to hold all of our device specific stuff*/
-struct usb_ftdi {
- struct list_head ftdi_list;
- struct mutex u132_lock;
- int command_next;
- int command_head;
- struct u132_command command[COMMAND_SIZE];
- int respond_next;
- int respond_head;
- struct u132_respond respond[RESPOND_SIZE];
- struct u132_target target[4];
- char device_name[16];
- unsigned synchronized:1;
- unsigned enumerated:1;
- unsigned registered:1;
- unsigned initialized:1;
- unsigned card_ejected:1;
- int function;
- int sequence_num;
- int disconnected;
- int gone_away;
- int stuck_status;
- int status_queue_delay;
- struct semaphore sw_lock;
- struct usb_device *udev;
- struct usb_interface *interface;
- struct usb_class_driver *class;
- struct delayed_work status_work;
- struct delayed_work command_work;
- struct delayed_work respond_work;
- struct u132_platform_data platform_data;
- struct resource resources[0];
- struct platform_device platform_dev;
- unsigned char *bulk_in_buffer;
- size_t bulk_in_size;
- size_t bulk_in_last;
- size_t bulk_in_left;
- __u8 bulk_in_endpointAddr;
- __u8 bulk_out_endpointAddr;
- struct kref kref;
- u32 controlreg;
- u8 response[4 + 1024];
- int expected;
- int received;
- int ed_found;
-};
-#define kref_to_usb_ftdi(d) container_of(d, struct usb_ftdi, kref)
-#define platform_device_to_usb_ftdi(d) container_of(d, struct usb_ftdi, \
- platform_dev)
-static struct usb_driver ftdi_elan_driver;
-static void ftdi_elan_delete(struct kref *kref)
-{
- struct usb_ftdi *ftdi = kref_to_usb_ftdi(kref);
- dev_warn(&ftdi->udev->dev, "FREEING ftdi=%p\n", ftdi);
- usb_put_dev(ftdi->udev);
- ftdi->disconnected += 1;
- mutex_lock(&ftdi_module_lock);
- list_del_init(&ftdi->ftdi_list);
- ftdi_instances -= 1;
- mutex_unlock(&ftdi_module_lock);
- kfree(ftdi->bulk_in_buffer);
- ftdi->bulk_in_buffer = NULL;
- kfree(ftdi);
-}
-
-static void ftdi_elan_put_kref(struct usb_ftdi *ftdi)
-{
- kref_put(&ftdi->kref, ftdi_elan_delete);
-}
-
-static void ftdi_elan_get_kref(struct usb_ftdi *ftdi)
-{
- kref_get(&ftdi->kref);
-}
-
-static void ftdi_elan_init_kref(struct usb_ftdi *ftdi)
-{
- kref_init(&ftdi->kref);
-}
-
-static void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta)
-{
- if (!schedule_delayed_work(&ftdi->status_work, delta))
- kref_put(&ftdi->kref, ftdi_elan_delete);
-}
-
-static void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta)
-{
- if (schedule_delayed_work(&ftdi->status_work, delta))
- kref_get(&ftdi->kref);
-}
-
-static void ftdi_status_cancel_work(struct usb_ftdi *ftdi)
-{
- if (cancel_delayed_work_sync(&ftdi->status_work))
- kref_put(&ftdi->kref, ftdi_elan_delete);
-}
-
-static void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta)
-{
- if (!schedule_delayed_work(&ftdi->command_work, delta))
- kref_put(&ftdi->kref, ftdi_elan_delete);
-}
-
-static void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta)
-{
- if (schedule_delayed_work(&ftdi->command_work, delta))
- kref_get(&ftdi->kref);
-}
-
-static void ftdi_command_cancel_work(struct usb_ftdi *ftdi)
-{
- if (cancel_delayed_work_sync(&ftdi->command_work))
- kref_put(&ftdi->kref, ftdi_elan_delete);
-}
-
-static void ftdi_response_requeue_work(struct usb_ftdi *ftdi,
- unsigned int delta)
-{
- if (!schedule_delayed_work(&ftdi->respond_work, delta))
- kref_put(&ftdi->kref, ftdi_elan_delete);
-}
-
-static void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta)
-{
- if (schedule_delayed_work(&ftdi->respond_work, delta))
- kref_get(&ftdi->kref);
-}
-
-static void ftdi_response_cancel_work(struct usb_ftdi *ftdi)
-{
- if (cancel_delayed_work_sync(&ftdi->respond_work))
- kref_put(&ftdi->kref, ftdi_elan_delete);
-}
-
-void ftdi_elan_gone_away(struct platform_device *pdev)
-{
- struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
- ftdi->gone_away += 1;
- ftdi_elan_put_kref(ftdi);
-}
-
-
-EXPORT_SYMBOL_GPL(ftdi_elan_gone_away);
-static void ftdi_release_platform_dev(struct device *dev)
-{
- dev->parent = NULL;
-}
-
-static void ftdi_elan_do_callback(struct usb_ftdi *ftdi,
- struct u132_target *target, u8 *buffer, int length);
-static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi);
-static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi);
-static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi);
-static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi);
-static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi);
-static int ftdi_elan_synchronize(struct usb_ftdi *ftdi);
-static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi);
-static int ftdi_elan_command_engine(struct usb_ftdi *ftdi);
-static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi);
-static int ftdi_elan_hcd_init(struct usb_ftdi *ftdi)
-{
- if (ftdi->platform_dev.dev.parent)
- return -EBUSY;
-
- ftdi_elan_get_kref(ftdi);
- ftdi->platform_data.potpg = 100;
- ftdi->platform_data.reset = NULL;
- ftdi->platform_dev.id = ftdi->sequence_num;
- ftdi->platform_dev.resource = ftdi->resources;
- ftdi->platform_dev.num_resources = ARRAY_SIZE(ftdi->resources);
- ftdi->platform_dev.dev.platform_data = &ftdi->platform_data;
- ftdi->platform_dev.dev.parent = NULL;
- ftdi->platform_dev.dev.release = ftdi_release_platform_dev;
- ftdi->platform_dev.dev.dma_mask = NULL;
- snprintf(ftdi->device_name, sizeof(ftdi->device_name), "u132_hcd");
- ftdi->platform_dev.name = ftdi->device_name;
- dev_info(&ftdi->udev->dev, "requesting module '%s'\n", "u132_hcd");
- request_module("u132_hcd");
- dev_info(&ftdi->udev->dev, "registering '%s'\n",
- ftdi->platform_dev.name);
-
- return platform_device_register(&ftdi->platform_dev);
-}
-
-static void ftdi_elan_abandon_completions(struct usb_ftdi *ftdi)
-{
- mutex_lock(&ftdi->u132_lock);
- while (ftdi->respond_next > ftdi->respond_head) {
- struct u132_respond *respond = &ftdi->respond[RESPOND_MASK &
- ftdi->respond_head++];
- *respond->result = -ESHUTDOWN;
- *respond->value = 0;
- complete(&respond->wait_completion);
- }
- mutex_unlock(&ftdi->u132_lock);
-}
-
-static void ftdi_elan_abandon_targets(struct usb_ftdi *ftdi)
-{
- int ed_number = 4;
- mutex_lock(&ftdi->u132_lock);
- while (ed_number-- > 0) {
- struct u132_target *target = &ftdi->target[ed_number];
- if (target->active == 1) {
- target->condition_code = TD_DEVNOTRESP;
- mutex_unlock(&ftdi->u132_lock);
- ftdi_elan_do_callback(ftdi, target, NULL, 0);
- mutex_lock(&ftdi->u132_lock);
- }
- }
- ftdi->received = 0;
- ftdi->expected = 4;
- ftdi->ed_found = 0;
- mutex_unlock(&ftdi->u132_lock);
-}
-
-static void ftdi_elan_flush_targets(struct usb_ftdi *ftdi)
-{
- int ed_number = 4;
- mutex_lock(&ftdi->u132_lock);
- while (ed_number-- > 0) {
- struct u132_target *target = &ftdi->target[ed_number];
- target->abandoning = 1;
- wait_1:if (target->active == 1) {
- int command_size = ftdi->command_next -
- ftdi->command_head;
- if (command_size < COMMAND_SIZE) {
- struct u132_command *command = &ftdi->command[
- COMMAND_MASK & ftdi->command_next];
- command->header = 0x80 | (ed_number << 5) | 0x4;
- command->length = 0x00;
- command->address = 0x00;
- command->width = 0x00;
- command->follows = 0;
- command->value = 0;
- command->buffer = &command->value;
- ftdi->command_next += 1;
- ftdi_elan_kick_command_queue(ftdi);
- } else {
- mutex_unlock(&ftdi->u132_lock);
- msleep(100);
- mutex_lock(&ftdi->u132_lock);
- goto wait_1;
- }
- }
- wait_2:if (target->active == 1) {
- int command_size = ftdi->command_next -
- ftdi->command_head;
- if (command_size < COMMAND_SIZE) {
- struct u132_command *command = &ftdi->command[
- COMMAND_MASK & ftdi->command_next];
- command->header = 0x90 | (ed_number << 5);
- command->length = 0x00;
- command->address = 0x00;
- command->width = 0x00;
- command->follows = 0;
- command->value = 0;
- command->buffer = &command->value;
- ftdi->command_next += 1;
- ftdi_elan_kick_command_queue(ftdi);
- } else {
- mutex_unlock(&ftdi->u132_lock);
- msleep(100);
- mutex_lock(&ftdi->u132_lock);
- goto wait_2;
- }
- }
- }
- ftdi->received = 0;
- ftdi->expected = 4;
- ftdi->ed_found = 0;
- mutex_unlock(&ftdi->u132_lock);
-}
-
-static void ftdi_elan_cancel_targets(struct usb_ftdi *ftdi)
-{
- int ed_number = 4;
- mutex_lock(&ftdi->u132_lock);
- while (ed_number-- > 0) {
- struct u132_target *target = &ftdi->target[ed_number];
- target->abandoning = 1;
- wait:if (target->active == 1) {
- int command_size = ftdi->command_next -
- ftdi->command_head;
- if (command_size < COMMAND_SIZE) {
- struct u132_command *command = &ftdi->command[
- COMMAND_MASK & ftdi->command_next];
- command->header = 0x80 | (ed_number << 5) | 0x4;
- command->length = 0x00;
- command->address = 0x00;
- command->width = 0x00;
- command->follows = 0;
- command->value = 0;
- command->buffer = &command->value;
- ftdi->command_next += 1;
- ftdi_elan_kick_command_queue(ftdi);
- } else {
- mutex_unlock(&ftdi->u132_lock);
- msleep(100);
- mutex_lock(&ftdi->u132_lock);
- goto wait;
- }
- }
- }
- ftdi->received = 0;
- ftdi->expected = 4;
- ftdi->ed_found = 0;
- mutex_unlock(&ftdi->u132_lock);
-}
-
-static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi)
-{
- ftdi_command_queue_work(ftdi, 0);
-}
-
-static void ftdi_elan_command_work(struct work_struct *work)
-{
- struct usb_ftdi *ftdi =
- container_of(work, struct usb_ftdi, command_work.work);
-
- if (ftdi->disconnected > 0) {
- ftdi_elan_put_kref(ftdi);
- return;
- } else {
- int retval = ftdi_elan_command_engine(ftdi);
- if (retval == -ESHUTDOWN) {
- ftdi->disconnected += 1;
- } else if (retval == -ENODEV) {
- ftdi->disconnected += 1;
- } else if (retval)
- dev_err(&ftdi->udev->dev, "command error %d\n", retval);
- ftdi_command_requeue_work(ftdi, msecs_to_jiffies(10));
- return;
- }
-}
-
-static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi)
-{
- ftdi_respond_queue_work(ftdi, 0);
-}
-
-static void ftdi_elan_respond_work(struct work_struct *work)
-{
- struct usb_ftdi *ftdi =
- container_of(work, struct usb_ftdi, respond_work.work);
- if (ftdi->disconnected > 0) {
- ftdi_elan_put_kref(ftdi);
- return;
- } else {
- int retval = ftdi_elan_respond_engine(ftdi);
- if (retval == 0) {
- } else if (retval == -ESHUTDOWN) {
- ftdi->disconnected += 1;
- } else if (retval == -ENODEV) {
- ftdi->disconnected += 1;
- } else if (retval == -EILSEQ) {
- ftdi->disconnected += 1;
- } else {
- ftdi->disconnected += 1;
- dev_err(&ftdi->udev->dev, "respond error %d\n", retval);
- }
- if (ftdi->disconnected > 0) {
- ftdi_elan_abandon_completions(ftdi);
- ftdi_elan_abandon_targets(ftdi);
- }
- ftdi_response_requeue_work(ftdi, msecs_to_jiffies(10));
- return;
- }
-}
-
-
-/*
- * the sw_lock is initially held and will be freed
- * after the FTDI has been synchronized
- *
- */
-static void ftdi_elan_status_work(struct work_struct *work)
-{
- struct usb_ftdi *ftdi =
- container_of(work, struct usb_ftdi, status_work.work);
- int work_delay_in_msec = 0;
- if (ftdi->disconnected > 0) {
- ftdi_elan_put_kref(ftdi);
- return;
- } else if (ftdi->synchronized == 0) {
- down(&ftdi->sw_lock);
- if (ftdi_elan_synchronize(ftdi) == 0) {
- ftdi->synchronized = 1;
- ftdi_command_queue_work(ftdi, 1);
- ftdi_respond_queue_work(ftdi, 1);
- up(&ftdi->sw_lock);
- work_delay_in_msec = 100;
- } else {
- dev_err(&ftdi->udev->dev, "synchronize failed\n");
- up(&ftdi->sw_lock);
- work_delay_in_msec = 10 *1000;
- }
- } else if (ftdi->stuck_status > 0) {
- if (ftdi_elan_stuck_waiting(ftdi) == 0) {
- ftdi->stuck_status = 0;
- ftdi->synchronized = 0;
- } else if ((ftdi->stuck_status++ % 60) == 1) {
- dev_err(&ftdi->udev->dev, "WRONG type of card inserted - please remove\n");
- } else
- dev_err(&ftdi->udev->dev, "WRONG type of card inserted - checked %d times\n",
- ftdi->stuck_status);
- work_delay_in_msec = 100;
- } else if (ftdi->enumerated == 0) {
- if (ftdi_elan_enumeratePCI(ftdi) == 0) {
- ftdi->enumerated = 1;
- work_delay_in_msec = 250;
- } else
- work_delay_in_msec = 1000;
- } else if (ftdi->initialized == 0) {
- if (ftdi_elan_setupOHCI(ftdi) == 0) {
- ftdi->initialized = 1;
- work_delay_in_msec = 500;
- } else {
- dev_err(&ftdi->udev->dev, "initialized failed - trying again in 10 seconds\n");
- work_delay_in_msec = 1 *1000;
- }
- } else if (ftdi->registered == 0) {
- work_delay_in_msec = 10;
- if (ftdi_elan_hcd_init(ftdi) == 0) {
- ftdi->registered = 1;
- } else
- dev_err(&ftdi->udev->dev, "register failed\n");
- work_delay_in_msec = 250;
- } else {
- if (ftdi_elan_checkingPCI(ftdi) == 0) {
- work_delay_in_msec = 250;
- } else if (ftdi->controlreg & 0x00400000) {
- if (ftdi->gone_away > 0) {
- dev_err(&ftdi->udev->dev, "PCI device eject confirmed platform_dev.dev.parent=%p platform_dev.dev=%p\n",
- ftdi->platform_dev.dev.parent,
- &ftdi->platform_dev.dev);
- platform_device_unregister(&ftdi->platform_dev);
- ftdi->platform_dev.dev.parent = NULL;
- ftdi->registered = 0;
- ftdi->enumerated = 0;
- ftdi->card_ejected = 0;
- ftdi->initialized = 0;
- ftdi->gone_away = 0;
- } else
- ftdi_elan_flush_targets(ftdi);
- work_delay_in_msec = 250;
- } else {
- dev_err(&ftdi->udev->dev, "PCI device has disappeared\n");
- ftdi_elan_cancel_targets(ftdi);
- work_delay_in_msec = 500;
- ftdi->enumerated = 0;
- ftdi->initialized = 0;
- }
- }
- if (ftdi->disconnected > 0) {
- ftdi_elan_put_kref(ftdi);
- return;
- } else {
- ftdi_status_requeue_work(ftdi,
- msecs_to_jiffies(work_delay_in_msec));
- return;
- }
-}
-
-
-/*
- * file_operations for the jtag interface
- *
- * the usage count for the device is incremented on open()
- * and decremented on release()
- */
-static int ftdi_elan_open(struct inode *inode, struct file *file)
-{
- int subminor;
- struct usb_interface *interface;
-
- subminor = iminor(inode);
- interface = usb_find_interface(&ftdi_elan_driver, subminor);
-
- if (!interface) {
- pr_err("can't find device for minor %d\n", subminor);
- return -ENODEV;
- } else {
- struct usb_ftdi *ftdi = usb_get_intfdata(interface);
- if (!ftdi) {
- return -ENODEV;
- } else {
- if (down_interruptible(&ftdi->sw_lock)) {
- return -EINTR;
- } else {
- ftdi_elan_get_kref(ftdi);
- file->private_data = ftdi;
- return 0;
- }
- }
- }
-}
-
-static int ftdi_elan_release(struct inode *inode, struct file *file)
-{
- struct usb_ftdi *ftdi = file->private_data;
- if (ftdi == NULL)
- return -ENODEV;
- up(&ftdi->sw_lock); /* decrement the count on our device */
- ftdi_elan_put_kref(ftdi);
- return 0;
-}
-
-
-/*
- *
- * blocking bulk reads are used to get data from the device
- *
- */
-static ssize_t ftdi_elan_read(struct file *file, char __user *buffer,
- size_t count, loff_t *ppos)
-{
- char data[30 *3 + 4];
- char *d = data;
- int m = (sizeof(data) - 1) / 3 - 1;
- int bytes_read = 0;
- int retry_on_empty = 10;
- int retry_on_timeout = 5;
- struct usb_ftdi *ftdi = file->private_data;
- if (ftdi->disconnected > 0) {
- return -ENODEV;
- }
- data[0] = 0;
-have:if (ftdi->bulk_in_left > 0) {
- if (count-- > 0) {
- char *p = ++ftdi->bulk_in_last + ftdi->bulk_in_buffer;
- ftdi->bulk_in_left -= 1;
- if (bytes_read < m) {
- d += sprintf(d, " %02X", 0x000000FF & *p);
- } else if (bytes_read > m) {
- } else
- d += sprintf(d, " ..");
- if (copy_to_user(buffer++, p, 1)) {
- return -EFAULT;
- } else {
- bytes_read += 1;
- goto have;
- }
- } else
- return bytes_read;
- }
-more:if (count > 0) {
- int packet_bytes = 0;
- int retval = usb_bulk_msg(ftdi->udev,
- usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
- ftdi->bulk_in_buffer, ftdi->bulk_in_size,
- &packet_bytes, 50);
- if (packet_bytes > 2) {
- ftdi->bulk_in_left = packet_bytes - 2;
- ftdi->bulk_in_last = 1;
- goto have;
- } else if (retval == -ETIMEDOUT) {
- if (retry_on_timeout-- > 0) {
- goto more;
- } else if (bytes_read > 0) {
- return bytes_read;
- } else
- return retval;
- } else if (retval == 0) {
- if (retry_on_empty-- > 0) {
- goto more;
- } else
- return bytes_read;
- } else
- return retval;
- } else
- return bytes_read;
-}
-
-static void ftdi_elan_write_bulk_callback(struct urb *urb)
-{
- struct usb_ftdi *ftdi = urb->context;
- int status = urb->status;
-
- if (status && !(status == -ENOENT || status == -ECONNRESET ||
- status == -ESHUTDOWN)) {
- dev_err(&ftdi->udev->dev,
- "urb=%p write bulk status received: %d\n", urb, status);
- }
- usb_free_coherent(urb->dev, urb->transfer_buffer_length,
- urb->transfer_buffer, urb->transfer_dma);
-}
-
-static int fill_buffer_with_all_queued_commands(struct usb_ftdi *ftdi,
- char *buf, int command_size, int total_size)
-{
- int ed_commands = 0;
- int b = 0;
- int I = command_size;
- int i = ftdi->command_head;
- while (I-- > 0) {
- struct u132_command *command = &ftdi->command[COMMAND_MASK &
- i++];
- int F = command->follows;
- u8 *f = command->buffer;
- if (command->header & 0x80) {
- ed_commands |= 1 << (0x3 & (command->header >> 5));
- }
- buf[b++] = command->header;
- buf[b++] = (command->length >> 0) & 0x00FF;
- buf[b++] = (command->length >> 8) & 0x00FF;
- buf[b++] = command->address;
- buf[b++] = command->width;
- while (F-- > 0) {
- buf[b++] = *f++;
- }
- }
- return ed_commands;
-}
-
-static int ftdi_elan_total_command_size(struct usb_ftdi *ftdi, int command_size)
-{
- int total_size = 0;
- int I = command_size;
- int i = ftdi->command_head;
- while (I-- > 0) {
- struct u132_command *command = &ftdi->command[COMMAND_MASK &
- i++];
- total_size += 5 + command->follows;
- }
- return total_size;
-}
-
-static int ftdi_elan_command_engine(struct usb_ftdi *ftdi)
-{
- int retval;
- char *buf;
- int ed_commands;
- int total_size;
- struct urb *urb;
- int command_size = ftdi->command_next - ftdi->command_head;
- if (command_size == 0)
- return 0;
- total_size = ftdi_elan_total_command_size(ftdi, command_size);
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb)
- return -ENOMEM;
- buf = usb_alloc_coherent(ftdi->udev, total_size, GFP_KERNEL,
- &urb->transfer_dma);
- if (!buf) {
- dev_err(&ftdi->udev->dev, "could not get a buffer to write %d commands totaling %d bytes to the Uxxx\n",
- command_size, total_size);
- usb_free_urb(urb);
- return -ENOMEM;
- }
- ed_commands = fill_buffer_with_all_queued_commands(ftdi, buf,
- command_size, total_size);
- usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
- ftdi->bulk_out_endpointAddr), buf, total_size,
- ftdi_elan_write_bulk_callback, ftdi);
- urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- if (ed_commands) {
- char diag[40 *3 + 4];
- char *d = diag;
- int m = total_size;
- u8 *c = buf;
- int s = (sizeof(diag) - 1) / 3;
- diag[0] = 0;
- while (s-- > 0 && m-- > 0) {
- if (s > 0 || m == 0) {
- d += sprintf(d, " %02X", *c++);
- } else
- d += sprintf(d, " ..");
- }
- }
- retval = usb_submit_urb(urb, GFP_KERNEL);
- if (retval) {
- dev_err(&ftdi->udev->dev, "failed %d to submit urb %p to write %d commands totaling %d bytes to the Uxxx\n",
- retval, urb, command_size, total_size);
- usb_free_coherent(ftdi->udev, total_size, buf, urb->transfer_dma);
- usb_free_urb(urb);
- return retval;
- }
- usb_free_urb(urb); /* release our reference to this urb,
- the USB core will eventually free it entirely */
- ftdi->command_head += command_size;
- ftdi_elan_kick_respond_queue(ftdi);
- return 0;
-}
-
-static void ftdi_elan_do_callback(struct usb_ftdi *ftdi,
- struct u132_target *target, u8 *buffer, int length)
-{
- struct urb *urb = target->urb;
- int halted = target->halted;
- int skipped = target->skipped;
- int actual = target->actual;
- int non_null = target->non_null;
- int toggle_bits = target->toggle_bits;
- int error_count = target->error_count;
- int condition_code = target->condition_code;
- int repeat_number = target->repeat_number;
- void (*callback) (void *, struct urb *, u8 *, int, int, int, int, int,
- int, int, int, int) = target->callback;
- target->active -= 1;
- target->callback = NULL;
- (*callback) (target->endp, urb, buffer, length, toggle_bits,
- error_count, condition_code, repeat_number, halted, skipped,
- actual, non_null);
-}
-
-static char *have_ed_set_response(struct usb_ftdi *ftdi,
- struct u132_target *target, u16 ed_length, int ed_number, int ed_type,
- char *b)
-{
- int payload = (ed_length >> 0) & 0x07FF;
- mutex_lock(&ftdi->u132_lock);
- target->actual = 0;
- target->non_null = (ed_length >> 15) & 0x0001;
- target->repeat_number = (ed_length >> 11) & 0x000F;
- if (ed_type == 0x02 || ed_type == 0x03) {
- if (payload == 0 || target->abandoning > 0) {
- target->abandoning = 0;
- mutex_unlock(&ftdi->u132_lock);
- ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
- payload);
- ftdi->received = 0;
- ftdi->expected = 4;
- ftdi->ed_found = 0;
- return ftdi->response;
- } else {
- ftdi->expected = 4 + payload;
- ftdi->ed_found = 1;
- mutex_unlock(&ftdi->u132_lock);
- return b;
- }
- } else {
- target->abandoning = 0;
- mutex_unlock(&ftdi->u132_lock);
- ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
- payload);
- ftdi->received = 0;
- ftdi->expected = 4;
- ftdi->ed_found = 0;
- return ftdi->response;
- }
-}
-
-static char *have_ed_get_response(struct usb_ftdi *ftdi,
- struct u132_target *target, u16 ed_length, int ed_number, int ed_type,
- char *b)
-{
- mutex_lock(&ftdi->u132_lock);
- target->condition_code = TD_DEVNOTRESP;
- target->actual = (ed_length >> 0) & 0x01FF;
- target->non_null = (ed_length >> 15) & 0x0001;
- target->repeat_number = (ed_length >> 11) & 0x000F;
- mutex_unlock(&ftdi->u132_lock);
- if (target->active)
- ftdi_elan_do_callback(ftdi, target, NULL, 0);
- target->abandoning = 0;
- ftdi->received = 0;
- ftdi->expected = 4;
- ftdi->ed_found = 0;
- return ftdi->response;
-}
-
-
-/*
- * The engine tries to empty the FTDI fifo
- *
- * all responses found in the fifo data are dispatched thus
- * the response buffer can only ever hold a maximum sized
- * response from the Uxxx.
- *
- */
-static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi)
-{
- u8 *b = ftdi->response + ftdi->received;
- int bytes_read = 0;
- int retry_on_empty = 1;
- int retry_on_timeout = 3;
-read:{
- int packet_bytes = 0;
- int retval = usb_bulk_msg(ftdi->udev,
- usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
- ftdi->bulk_in_buffer, ftdi->bulk_in_size,
- &packet_bytes, 500);
- char diag[30 *3 + 4];
- char *d = diag;
- int m = packet_bytes;
- u8 *c = ftdi->bulk_in_buffer;
- int s = (sizeof(diag) - 1) / 3;
- diag[0] = 0;
- while (s-- > 0 && m-- > 0) {
- if (s > 0 || m == 0) {
- d += sprintf(d, " %02X", *c++);
- } else
- d += sprintf(d, " ..");
- }
- if (packet_bytes > 2) {
- ftdi->bulk_in_left = packet_bytes - 2;
- ftdi->bulk_in_last = 1;
- goto have;
- } else if (retval == -ETIMEDOUT) {
- if (retry_on_timeout-- > 0) {
- dev_err(&ftdi->udev->dev, "TIMED OUT with packet_bytes = %d with total %d bytes%s\n",
- packet_bytes, bytes_read, diag);
- goto more;
- } else if (bytes_read > 0) {
- dev_err(&ftdi->udev->dev, "ONLY %d bytes%s\n",
- bytes_read, diag);
- return -ENOMEM;
- } else {
- dev_err(&ftdi->udev->dev, "TIMED OUT with packet_bytes = %d with total %d bytes%s\n",
- packet_bytes, bytes_read, diag);
- return -ENOMEM;
- }
- } else if (retval == -EILSEQ) {
- dev_err(&ftdi->udev->dev, "error = %d with packet_bytes = %d with total %d bytes%s\n",
- retval, packet_bytes, bytes_read, diag);
- return retval;
- } else if (retval) {
- dev_err(&ftdi->udev->dev, "error = %d with packet_bytes = %d with total %d bytes%s\n",
- retval, packet_bytes, bytes_read, diag);
- return retval;
- } else {
- if (retry_on_empty-- > 0) {
- goto more;
- } else
- return 0;
- }
- }
-more:{
- goto read;
- }
-have:if (ftdi->bulk_in_left > 0) {
- u8 c = ftdi->bulk_in_buffer[++ftdi->bulk_in_last];
- bytes_read += 1;
- ftdi->bulk_in_left -= 1;
- if (ftdi->received == 0 && c == 0xFF) {
- goto have;
- } else
- *b++ = c;
- if (++ftdi->received < ftdi->expected) {
- goto have;
- } else if (ftdi->ed_found) {
- int ed_number = (ftdi->response[0] >> 5) & 0x03;
- u16 ed_length = (ftdi->response[2] << 8) |
- ftdi->response[1];
- struct u132_target *target = &ftdi->target[ed_number];
- int payload = (ed_length >> 0) & 0x07FF;
- char diag[30 *3 + 4];
- char *d = diag;
- int m = payload;
- u8 *c = 4 + ftdi->response;
- int s = (sizeof(diag) - 1) / 3;
- diag[0] = 0;
- while (s-- > 0 && m-- > 0) {
- if (s > 0 || m == 0) {
- d += sprintf(d, " %02X", *c++);
- } else
- d += sprintf(d, " ..");
- }
- ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
- payload);
- ftdi->received = 0;
- ftdi->expected = 4;
- ftdi->ed_found = 0;
- b = ftdi->response;
- goto have;
- } else if (ftdi->expected == 8) {
- u8 buscmd;
- int respond_head = ftdi->respond_head++;
- struct u132_respond *respond = &ftdi->respond[
- RESPOND_MASK & respond_head];
- u32 data = ftdi->response[7];
- data <<= 8;
- data |= ftdi->response[6];
- data <<= 8;
- data |= ftdi->response[5];
- data <<= 8;
- data |= ftdi->response[4];
- *respond->value = data;
- *respond->result = 0;
- complete(&respond->wait_completion);
- ftdi->received = 0;
- ftdi->expected = 4;
- ftdi->ed_found = 0;
- b = ftdi->response;
- buscmd = (ftdi->response[0] >> 0) & 0x0F;
- if (buscmd == 0x00) {
- } else if (buscmd == 0x02) {
- } else if (buscmd == 0x06) {
- } else if (buscmd == 0x0A) {
- } else
- dev_err(&ftdi->udev->dev, "Uxxx unknown(%0X) value = %08X\n",
- buscmd, data);
- goto have;
- } else {
- if ((ftdi->response[0] & 0x80) == 0x00) {
- ftdi->expected = 8;
- goto have;
- } else {
- int ed_number = (ftdi->response[0] >> 5) & 0x03;
- int ed_type = (ftdi->response[0] >> 0) & 0x03;
- u16 ed_length = (ftdi->response[2] << 8) |
- ftdi->response[1];
- struct u132_target *target = &ftdi->target[
- ed_number];
- target->halted = (ftdi->response[0] >> 3) &
- 0x01;
- target->skipped = (ftdi->response[0] >> 2) &
- 0x01;
- target->toggle_bits = (ftdi->response[3] >> 6)
- & 0x03;
- target->error_count = (ftdi->response[3] >> 4)
- & 0x03;
- target->condition_code = (ftdi->response[
- 3] >> 0) & 0x0F;
- if ((ftdi->response[0] & 0x10) == 0x00) {
- b = have_ed_set_response(ftdi, target,
- ed_length, ed_number, ed_type,
- b);
- goto have;
- } else {
- b = have_ed_get_response(ftdi, target,
- ed_length, ed_number, ed_type,
- b);
- goto have;
- }
- }
- }
- } else
- goto more;
-}
-
-
-/*
- * create a urb, and a buffer for it, and copy the data to the urb
- *
- */
-static ssize_t ftdi_elan_write(struct file *file,
- const char __user *user_buffer, size_t count,
- loff_t *ppos)
-{
- int retval = 0;
- struct urb *urb;
- char *buf;
- struct usb_ftdi *ftdi = file->private_data;
-
- if (ftdi->disconnected > 0) {
- return -ENODEV;
- }
- if (count == 0) {
- goto exit;
- }
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- retval = -ENOMEM;
- goto error_1;
- }
- buf = usb_alloc_coherent(ftdi->udev, count, GFP_KERNEL,
- &urb->transfer_dma);
- if (!buf) {
- retval = -ENOMEM;
- goto error_2;
- }
- if (copy_from_user(buf, user_buffer, count)) {
- retval = -EFAULT;
- goto error_3;
- }
- usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
- ftdi->bulk_out_endpointAddr), buf, count,
- ftdi_elan_write_bulk_callback, ftdi);
- urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- retval = usb_submit_urb(urb, GFP_KERNEL);
- if (retval) {
- dev_err(&ftdi->udev->dev,
- "failed submitting write urb, error %d\n", retval);
- goto error_3;
- }
- usb_free_urb(urb);
-
-exit:
- return count;
-error_3:
- usb_free_coherent(ftdi->udev, count, buf, urb->transfer_dma);
-error_2:
- usb_free_urb(urb);
-error_1:
- return retval;
-}
-
-static const struct file_operations ftdi_elan_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = ftdi_elan_read,
- .write = ftdi_elan_write,
- .open = ftdi_elan_open,
- .release = ftdi_elan_release,
-};
-
-/*
- * usb class driver info in order to get a minor number from the usb core,
- * and to have the device registered with the driver core
- */
-static struct usb_class_driver ftdi_elan_jtag_class = {
- .name = "ftdi-%d-jtag",
- .fops = &ftdi_elan_fops,
- .minor_base = USB_FTDI_ELAN_MINOR_BASE,
-};
-
-/*
- * the following definitions are for the
- * ELAN FPGA state machgine processor that
- * lies on the other side of the FTDI chip
- */
-#define cPCIu132rd 0x0
-#define cPCIu132wr 0x1
-#define cPCIiord 0x2
-#define cPCIiowr 0x3
-#define cPCImemrd 0x6
-#define cPCImemwr 0x7
-#define cPCIcfgrd 0xA
-#define cPCIcfgwr 0xB
-#define cPCInull 0xF
-#define cU132cmd_status 0x0
-#define cU132flash 0x1
-#define cPIDsetup 0x0
-#define cPIDout 0x1
-#define cPIDin 0x2
-#define cPIDinonce 0x3
-#define cCCnoerror 0x0
-#define cCCcrc 0x1
-#define cCCbitstuff 0x2
-#define cCCtoggle 0x3
-#define cCCstall 0x4
-#define cCCnoresp 0x5
-#define cCCbadpid1 0x6
-#define cCCbadpid2 0x7
-#define cCCdataoverrun 0x8
-#define cCCdataunderrun 0x9
-#define cCCbuffoverrun 0xC
-#define cCCbuffunderrun 0xD
-#define cCCnotaccessed 0xF
-static int ftdi_elan_write_reg(struct usb_ftdi *ftdi, u32 data)
-{
-wait:if (ftdi->disconnected > 0) {
- return -ENODEV;
- } else {
- int command_size;
- mutex_lock(&ftdi->u132_lock);
- command_size = ftdi->command_next - ftdi->command_head;
- if (command_size < COMMAND_SIZE) {
- struct u132_command *command = &ftdi->command[
- COMMAND_MASK & ftdi->command_next];
- command->header = 0x00 | cPCIu132wr;
- command->length = 0x04;
- command->address = 0x00;
- command->width = 0x00;
- command->follows = 4;
- command->value = data;
- command->buffer = &command->value;
- ftdi->command_next += 1;
- ftdi_elan_kick_command_queue(ftdi);
- mutex_unlock(&ftdi->u132_lock);
- return 0;
- } else {
- mutex_unlock(&ftdi->u132_lock);
- msleep(100);
- goto wait;
- }
- }
-}
-
-static int ftdi_elan_write_config(struct usb_ftdi *ftdi, int config_offset,
- u8 width, u32 data)
-{
- u8 addressofs = config_offset / 4;
-wait:if (ftdi->disconnected > 0) {
- return -ENODEV;
- } else {
- int command_size;
- mutex_lock(&ftdi->u132_lock);
- command_size = ftdi->command_next - ftdi->command_head;
- if (command_size < COMMAND_SIZE) {
- struct u132_command *command = &ftdi->command[
- COMMAND_MASK & ftdi->command_next];
- command->header = 0x00 | (cPCIcfgwr & 0x0F);
- command->length = 0x04;
- command->address = addressofs;
- command->width = 0x00 | (width & 0x0F);
- command->follows = 4;
- command->value = data;
- command->buffer = &command->value;
- ftdi->command_next += 1;
- ftdi_elan_kick_command_queue(ftdi);
- mutex_unlock(&ftdi->u132_lock);
- return 0;
- } else {
- mutex_unlock(&ftdi->u132_lock);
- msleep(100);
- goto wait;
- }
- }
-}
-
-static int ftdi_elan_write_pcimem(struct usb_ftdi *ftdi, int mem_offset,
- u8 width, u32 data)
-{
- u8 addressofs = mem_offset / 4;
-wait:if (ftdi->disconnected > 0) {
- return -ENODEV;
- } else {
- int command_size;
- mutex_lock(&ftdi->u132_lock);
- command_size = ftdi->command_next - ftdi->command_head;
- if (command_size < COMMAND_SIZE) {
- struct u132_command *command = &ftdi->command[
- COMMAND_MASK & ftdi->command_next];
- command->header = 0x00 | (cPCImemwr & 0x0F);
- command->length = 0x04;
- command->address = addressofs;
- command->width = 0x00 | (width & 0x0F);
- command->follows = 4;
- command->value = data;
- command->buffer = &command->value;
- ftdi->command_next += 1;
- ftdi_elan_kick_command_queue(ftdi);
- mutex_unlock(&ftdi->u132_lock);
- return 0;
- } else {
- mutex_unlock(&ftdi->u132_lock);
- msleep(100);
- goto wait;
- }
- }
-}
-
-int usb_ftdi_elan_write_pcimem(struct platform_device *pdev, int mem_offset,
- u8 width, u32 data)
-{
- struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
- return ftdi_elan_write_pcimem(ftdi, mem_offset, width, data);
-}
-
-
-EXPORT_SYMBOL_GPL(usb_ftdi_elan_write_pcimem);
-static int ftdi_elan_read_reg(struct usb_ftdi *ftdi, u32 *data)
-{
-wait:if (ftdi->disconnected > 0) {
- return -ENODEV;
- } else {
- int command_size;
- int respond_size;
- mutex_lock(&ftdi->u132_lock);
- command_size = ftdi->command_next - ftdi->command_head;
- respond_size = ftdi->respond_next - ftdi->respond_head;
- if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE)
- {
- struct u132_command *command = &ftdi->command[
- COMMAND_MASK & ftdi->command_next];
- struct u132_respond *respond = &ftdi->respond[
- RESPOND_MASK & ftdi->respond_next];
- int result = -ENODEV;
- respond->result = &result;
- respond->header = command->header = 0x00 | cPCIu132rd;
- command->length = 0x04;
- respond->address = command->address = cU132cmd_status;
- command->width = 0x00;
- command->follows = 0;
- command->value = 0;
- command->buffer = NULL;
- respond->value = data;
- init_completion(&respond->wait_completion);
- ftdi->command_next += 1;
- ftdi->respond_next += 1;
- ftdi_elan_kick_command_queue(ftdi);
- mutex_unlock(&ftdi->u132_lock);
- wait_for_completion(&respond->wait_completion);
- return result;
- } else {
- mutex_unlock(&ftdi->u132_lock);
- msleep(100);
- goto wait;
- }
- }
-}
-
-static int ftdi_elan_read_config(struct usb_ftdi *ftdi, int config_offset,
- u8 width, u32 *data)
-{
- u8 addressofs = config_offset / 4;
-wait:if (ftdi->disconnected > 0) {
- return -ENODEV;
- } else {
- int command_size;
- int respond_size;
- mutex_lock(&ftdi->u132_lock);
- command_size = ftdi->command_next - ftdi->command_head;
- respond_size = ftdi->respond_next - ftdi->respond_head;
- if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE)
- {
- struct u132_command *command = &ftdi->command[
- COMMAND_MASK & ftdi->command_next];
- struct u132_respond *respond = &ftdi->respond[
- RESPOND_MASK & ftdi->respond_next];
- int result = -ENODEV;
- respond->result = &result;
- respond->header = command->header = 0x00 | (cPCIcfgrd &
- 0x0F);
- command->length = 0x04;
- respond->address = command->address = addressofs;
- command->width = 0x00 | (width & 0x0F);
- command->follows = 0;
- command->value = 0;
- command->buffer = NULL;
- respond->value = data;
- init_completion(&respond->wait_completion);
- ftdi->command_next += 1;
- ftdi->respond_next += 1;
- ftdi_elan_kick_command_queue(ftdi);
- mutex_unlock(&ftdi->u132_lock);
- wait_for_completion(&respond->wait_completion);
- return result;
- } else {
- mutex_unlock(&ftdi->u132_lock);
- msleep(100);
- goto wait;
- }
- }
-}
-
-static int ftdi_elan_read_pcimem(struct usb_ftdi *ftdi, int mem_offset,
- u8 width, u32 *data)
-{
- u8 addressofs = mem_offset / 4;
-wait:if (ftdi->disconnected > 0) {
- return -ENODEV;
- } else {
- int command_size;
- int respond_size;
- mutex_lock(&ftdi->u132_lock);
- command_size = ftdi->command_next - ftdi->command_head;
- respond_size = ftdi->respond_next - ftdi->respond_head;
- if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE)
- {
- struct u132_command *command = &ftdi->command[
- COMMAND_MASK & ftdi->command_next];
- struct u132_respond *respond = &ftdi->respond[
- RESPOND_MASK & ftdi->respond_next];
- int result = -ENODEV;
- respond->result = &result;
- respond->header = command->header = 0x00 | (cPCImemrd &
- 0x0F);
- command->length = 0x04;
- respond->address = command->address = addressofs;
- command->width = 0x00 | (width & 0x0F);
- command->follows = 0;
- command->value = 0;
- command->buffer = NULL;
- respond->value = data;
- init_completion(&respond->wait_completion);
- ftdi->command_next += 1;
- ftdi->respond_next += 1;
- ftdi_elan_kick_command_queue(ftdi);
- mutex_unlock(&ftdi->u132_lock);
- wait_for_completion(&respond->wait_completion);
- return result;
- } else {
- mutex_unlock(&ftdi->u132_lock);
- msleep(100);
- goto wait;
- }
- }
-}
-
-int usb_ftdi_elan_read_pcimem(struct platform_device *pdev, int mem_offset,
- u8 width, u32 *data)
-{
- struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
- if (ftdi->initialized == 0) {
- return -ENODEV;
- } else
- return ftdi_elan_read_pcimem(ftdi, mem_offset, width, data);
-}
-
-
-EXPORT_SYMBOL_GPL(usb_ftdi_elan_read_pcimem);
-static int ftdi_elan_edset_setup(struct usb_ftdi *ftdi, u8 ed_number,
- void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
- void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
- int toggle_bits, int error_count, int condition_code, int repeat_number,
- int halted, int skipped, int actual, int non_null))
-{
- u8 ed = ed_number - 1;
-wait:if (ftdi->disconnected > 0) {
- return -ENODEV;
- } else if (ftdi->initialized == 0) {
- return -ENODEV;
- } else {
- int command_size;
- mutex_lock(&ftdi->u132_lock);
- command_size = ftdi->command_next - ftdi->command_head;
- if (command_size < COMMAND_SIZE) {
- struct u132_target *target = &ftdi->target[ed];
- struct u132_command *command = &ftdi->command[
- COMMAND_MASK & ftdi->command_next];
- command->header = 0x80 | (ed << 5);
- command->length = 0x8007;
- command->address = (toggle_bits << 6) | (ep_number << 2)
- | (address << 0);
- command->width = usb_maxpacket(urb->dev, urb->pipe);
- command->follows = 8;
- command->value = 0;
- command->buffer = urb->setup_packet;
- target->callback = callback;
- target->endp = endp;
- target->urb = urb;
- target->active = 1;
- ftdi->command_next += 1;
- ftdi_elan_kick_command_queue(ftdi);
- mutex_unlock(&ftdi->u132_lock);
- return 0;
- } else {
- mutex_unlock(&ftdi->u132_lock);
- msleep(100);
- goto wait;
- }
- }
-}
-
-int usb_ftdi_elan_edset_setup(struct platform_device *pdev, u8 ed_number,
- void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
- void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
- int toggle_bits, int error_count, int condition_code, int repeat_number,
- int halted, int skipped, int actual, int non_null))
-{
- struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
- return ftdi_elan_edset_setup(ftdi, ed_number, endp, urb, address,
- ep_number, toggle_bits, callback);
-}
-
-
-EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_setup);
-static int ftdi_elan_edset_input(struct usb_ftdi *ftdi, u8 ed_number,
- void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
- void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
- int toggle_bits, int error_count, int condition_code, int repeat_number,
- int halted, int skipped, int actual, int non_null))
-{
- u8 ed = ed_number - 1;
-wait:if (ftdi->disconnected > 0) {
- return -ENODEV;
- } else if (ftdi->initialized == 0) {
- return -ENODEV;
- } else {
- int command_size;
- mutex_lock(&ftdi->u132_lock);
- command_size = ftdi->command_next - ftdi->command_head;
- if (command_size < COMMAND_SIZE) {
- struct u132_target *target = &ftdi->target[ed];
- struct u132_command *command = &ftdi->command[
- COMMAND_MASK & ftdi->command_next];
- u32 remaining_length = urb->transfer_buffer_length -
- urb->actual_length;
- command->header = 0x82 | (ed << 5);
- if (remaining_length == 0) {
- command->length = 0x0000;
- } else if (remaining_length > 1024) {
- command->length = 0x8000 | 1023;
- } else
- command->length = 0x8000 | (remaining_length -
- 1);
- command->address = (toggle_bits << 6) | (ep_number << 2)
- | (address << 0);
- command->width = usb_maxpacket(urb->dev, urb->pipe);
- command->follows = 0;
- command->value = 0;
- command->buffer = NULL;
- target->callback = callback;
- target->endp = endp;
- target->urb = urb;
- target->active = 1;
- ftdi->command_next += 1;
- ftdi_elan_kick_command_queue(ftdi);
- mutex_unlock(&ftdi->u132_lock);
- return 0;
- } else {
- mutex_unlock(&ftdi->u132_lock);
- msleep(100);
- goto wait;
- }
- }
-}
-
-int usb_ftdi_elan_edset_input(struct platform_device *pdev, u8 ed_number,
- void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
- void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
- int toggle_bits, int error_count, int condition_code, int repeat_number,
- int halted, int skipped, int actual, int non_null))
-{
- struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
- return ftdi_elan_edset_input(ftdi, ed_number, endp, urb, address,
- ep_number, toggle_bits, callback);
-}
-
-
-EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_input);
-static int ftdi_elan_edset_empty(struct usb_ftdi *ftdi, u8 ed_number,
- void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
- void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
- int toggle_bits, int error_count, int condition_code, int repeat_number,
- int halted, int skipped, int actual, int non_null))
-{
- u8 ed = ed_number - 1;
-wait:if (ftdi->disconnected > 0) {
- return -ENODEV;
- } else if (ftdi->initialized == 0) {
- return -ENODEV;
- } else {
- int command_size;
- mutex_lock(&ftdi->u132_lock);
- command_size = ftdi->command_next - ftdi->command_head;
- if (command_size < COMMAND_SIZE) {
- struct u132_target *target = &ftdi->target[ed];
- struct u132_command *command = &ftdi->command[
- COMMAND_MASK & ftdi->command_next];
- command->header = 0x81 | (ed << 5);
- command->length = 0x0000;
- command->address = (toggle_bits << 6) | (ep_number << 2)
- | (address << 0);
- command->width = usb_maxpacket(urb->dev, urb->pipe);
- command->follows = 0;
- command->value = 0;
- command->buffer = NULL;
- target->callback = callback;
- target->endp = endp;
- target->urb = urb;
- target->active = 1;
- ftdi->command_next += 1;
- ftdi_elan_kick_command_queue(ftdi);
- mutex_unlock(&ftdi->u132_lock);
- return 0;
- } else {
- mutex_unlock(&ftdi->u132_lock);
- msleep(100);
- goto wait;
- }
- }
-}
-
-int usb_ftdi_elan_edset_empty(struct platform_device *pdev, u8 ed_number,
- void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
- void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
- int toggle_bits, int error_count, int condition_code, int repeat_number,
- int halted, int skipped, int actual, int non_null))
-{
- struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
- return ftdi_elan_edset_empty(ftdi, ed_number, endp, urb, address,
- ep_number, toggle_bits, callback);
-}
-
-
-EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_empty);
-static int ftdi_elan_edset_output(struct usb_ftdi *ftdi, u8 ed_number,
- void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
- void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
- int toggle_bits, int error_count, int condition_code, int repeat_number,
- int halted, int skipped, int actual, int non_null))
-{
- u8 ed = ed_number - 1;
-wait:if (ftdi->disconnected > 0) {
- return -ENODEV;
- } else if (ftdi->initialized == 0) {
- return -ENODEV;
- } else {
- int command_size;
- mutex_lock(&ftdi->u132_lock);
- command_size = ftdi->command_next - ftdi->command_head;
- if (command_size < COMMAND_SIZE) {
- u8 *b;
- u16 urb_size;
- int i = 0;
- char data[30 *3 + 4];
- char *d = data;
- int m = (sizeof(data) - 1) / 3 - 1;
- struct u132_target *target = &ftdi->target[ed];
- struct u132_command *command = &ftdi->command[
- COMMAND_MASK & ftdi->command_next];
- command->header = 0x81 | (ed << 5);
- command->address = (toggle_bits << 6) | (ep_number << 2)
- | (address << 0);
- command->width = usb_maxpacket(urb->dev, urb->pipe);
- command->follows = min_t(u32, 1024,
- urb->transfer_buffer_length -
- urb->actual_length);
- command->value = 0;
- command->buffer = urb->transfer_buffer +
- urb->actual_length;
- command->length = 0x8000 | (command->follows - 1);
- b = command->buffer;
- urb_size = command->follows;
- data[0] = 0;
- while (urb_size-- > 0) {
- if (i > m) {
- } else if (i++ < m) {
- int w = sprintf(d, " %02X", *b++);
- d += w;
- } else
- d += sprintf(d, " ..");
- }
- target->callback = callback;
- target->endp = endp;
- target->urb = urb;
- target->active = 1;
- ftdi->command_next += 1;
- ftdi_elan_kick_command_queue(ftdi);
- mutex_unlock(&ftdi->u132_lock);
- return 0;
- } else {
- mutex_unlock(&ftdi->u132_lock);
- msleep(100);
- goto wait;
- }
- }
-}
-
-int usb_ftdi_elan_edset_output(struct platform_device *pdev, u8 ed_number,
- void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
- void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
- int toggle_bits, int error_count, int condition_code, int repeat_number,
- int halted, int skipped, int actual, int non_null))
-{
- struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
- return ftdi_elan_edset_output(ftdi, ed_number, endp, urb, address,
- ep_number, toggle_bits, callback);
-}
-
-
-EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_output);
-static int ftdi_elan_edset_single(struct usb_ftdi *ftdi, u8 ed_number,
- void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
- void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
- int toggle_bits, int error_count, int condition_code, int repeat_number,
- int halted, int skipped, int actual, int non_null))
-{
- u8 ed = ed_number - 1;
-wait:if (ftdi->disconnected > 0) {
- return -ENODEV;
- } else if (ftdi->initialized == 0) {
- return -ENODEV;
- } else {
- int command_size;
- mutex_lock(&ftdi->u132_lock);
- command_size = ftdi->command_next - ftdi->command_head;
- if (command_size < COMMAND_SIZE) {
- u32 remaining_length = urb->transfer_buffer_length -
- urb->actual_length;
- struct u132_target *target = &ftdi->target[ed];
- struct u132_command *command = &ftdi->command[
- COMMAND_MASK & ftdi->command_next];
- command->header = 0x83 | (ed << 5);
- if (remaining_length == 0) {
- command->length = 0x0000;
- } else if (remaining_length > 1024) {
- command->length = 0x8000 | 1023;
- } else
- command->length = 0x8000 | (remaining_length -
- 1);
- command->address = (toggle_bits << 6) | (ep_number << 2)
- | (address << 0);
- command->width = usb_maxpacket(urb->dev, urb->pipe);
- command->follows = 0;
- command->value = 0;
- command->buffer = NULL;
- target->callback = callback;
- target->endp = endp;
- target->urb = urb;
- target->active = 1;
- ftdi->command_next += 1;
- ftdi_elan_kick_command_queue(ftdi);
- mutex_unlock(&ftdi->u132_lock);
- return 0;
- } else {
- mutex_unlock(&ftdi->u132_lock);
- msleep(100);
- goto wait;
- }
- }
-}
-
-int usb_ftdi_elan_edset_single(struct platform_device *pdev, u8 ed_number,
- void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
- void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
- int toggle_bits, int error_count, int condition_code, int repeat_number,
- int halted, int skipped, int actual, int non_null))
-{
- struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
- return ftdi_elan_edset_single(ftdi, ed_number, endp, urb, address,
- ep_number, toggle_bits, callback);
-}
-
-
-EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_single);
-static int ftdi_elan_edset_flush(struct usb_ftdi *ftdi, u8 ed_number,
- void *endp)
-{
- u8 ed = ed_number - 1;
- if (ftdi->disconnected > 0) {
- return -ENODEV;
- } else if (ftdi->initialized == 0) {
- return -ENODEV;
- } else {
- struct u132_target *target = &ftdi->target[ed];
- mutex_lock(&ftdi->u132_lock);
- if (target->abandoning > 0) {
- mutex_unlock(&ftdi->u132_lock);
- return 0;
- } else {
- target->abandoning = 1;
- wait_1:if (target->active == 1) {
- int command_size = ftdi->command_next -
- ftdi->command_head;
- if (command_size < COMMAND_SIZE) {
- struct u132_command *command =
- &ftdi->command[COMMAND_MASK &
- ftdi->command_next];
- command->header = 0x80 | (ed << 5) |
- 0x4;
- command->length = 0x00;
- command->address = 0x00;
- command->width = 0x00;
- command->follows = 0;
- command->value = 0;
- command->buffer = &command->value;
- ftdi->command_next += 1;
- ftdi_elan_kick_command_queue(ftdi);
- } else {
- mutex_unlock(&ftdi->u132_lock);
- msleep(100);
- mutex_lock(&ftdi->u132_lock);
- goto wait_1;
- }
- }
- mutex_unlock(&ftdi->u132_lock);
- return 0;
- }
- }
-}
-
-int usb_ftdi_elan_edset_flush(struct platform_device *pdev, u8 ed_number,
- void *endp)
-{
- struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
- return ftdi_elan_edset_flush(ftdi, ed_number, endp);
-}
-
-
-EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_flush);
-static int ftdi_elan_flush_input_fifo(struct usb_ftdi *ftdi)
-{
- int retry_on_empty = 10;
- int retry_on_timeout = 5;
- int retry_on_status = 20;
-more:{
- int packet_bytes = 0;
- int retval = usb_bulk_msg(ftdi->udev,
- usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
- ftdi->bulk_in_buffer, ftdi->bulk_in_size,
- &packet_bytes, 100);
- if (packet_bytes > 2) {
- char diag[30 *3 + 4];
- char *d = diag;
- int m = (sizeof(diag) - 1) / 3 - 1;
- char *b = ftdi->bulk_in_buffer;
- int bytes_read = 0;
- diag[0] = 0;
- while (packet_bytes-- > 0) {
- char c = *b++;
- if (bytes_read < m) {
- d += sprintf(d, " %02X",
- 0x000000FF & c);
- } else if (bytes_read > m) {
- } else
- d += sprintf(d, " ..");
- bytes_read += 1;
- continue;
- }
- goto more;
- } else if (packet_bytes > 1) {
- char s1 = ftdi->bulk_in_buffer[0];
- char s2 = ftdi->bulk_in_buffer[1];
- if (s1 == 0x31 && s2 == 0x60) {
- return 0;
- } else if (retry_on_status-- > 0) {
- goto more;
- } else {
- dev_err(&ftdi->udev->dev, "STATUS ERROR retry limit reached\n");
- return -EFAULT;
- }
- } else if (packet_bytes > 0) {
- char b1 = ftdi->bulk_in_buffer[0];
- dev_err(&ftdi->udev->dev, "only one byte flushed from FTDI = %02X\n",
- b1);
- if (retry_on_status-- > 0) {
- goto more;
- } else {
- dev_err(&ftdi->udev->dev, "STATUS ERROR retry limit reached\n");
- return -EFAULT;
- }
- } else if (retval == -ETIMEDOUT) {
- if (retry_on_timeout-- > 0) {
- goto more;
- } else {
- dev_err(&ftdi->udev->dev, "TIMED OUT retry limit reached\n");
- return -ENOMEM;
- }
- } else if (retval == 0) {
- if (retry_on_empty-- > 0) {
- goto more;
- } else {
- dev_err(&ftdi->udev->dev, "empty packet retry limit reached\n");
- return -ENOMEM;
- }
- } else {
- dev_err(&ftdi->udev->dev, "error = %d\n", retval);
- return retval;
- }
- }
- return -1;
-}
-
-
-/*
- * send the long flush sequence
- *
- */
-static int ftdi_elan_synchronize_flush(struct usb_ftdi *ftdi)
-{
- int retval;
- struct urb *urb;
- char *buf;
- int I = 257;
- int i = 0;
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb)
- return -ENOMEM;
- buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma);
- if (!buf) {
- dev_err(&ftdi->udev->dev, "could not get a buffer for flush sequence\n");
- usb_free_urb(urb);
- return -ENOMEM;
- }
- while (I-- > 0)
- buf[i++] = 0x55;
- usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
- ftdi->bulk_out_endpointAddr), buf, i,
- ftdi_elan_write_bulk_callback, ftdi);
- urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- retval = usb_submit_urb(urb, GFP_KERNEL);
- if (retval) {
- dev_err(&ftdi->udev->dev, "failed to submit urb containing the flush sequence\n");
- usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma);
- usb_free_urb(urb);
- return -ENOMEM;
- }
- usb_free_urb(urb);
- return 0;
-}
-
-
-/*
- * send the reset sequence
- *
- */
-static int ftdi_elan_synchronize_reset(struct usb_ftdi *ftdi)
-{
- int retval;
- struct urb *urb;
- char *buf;
- int I = 4;
- int i = 0;
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb)
- return -ENOMEM;
- buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma);
- if (!buf) {
- dev_err(&ftdi->udev->dev, "could not get a buffer for the reset sequence\n");
- usb_free_urb(urb);
- return -ENOMEM;
- }
- buf[i++] = 0x55;
- buf[i++] = 0xAA;
- buf[i++] = 0x5A;
- buf[i++] = 0xA5;
- usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
- ftdi->bulk_out_endpointAddr), buf, i,
- ftdi_elan_write_bulk_callback, ftdi);
- urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- retval = usb_submit_urb(urb, GFP_KERNEL);
- if (retval) {
- dev_err(&ftdi->udev->dev, "failed to submit urb containing the reset sequence\n");
- usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma);
- usb_free_urb(urb);
- return -ENOMEM;
- }
- usb_free_urb(urb);
- return 0;
-}
-
-static int ftdi_elan_synchronize(struct usb_ftdi *ftdi)
-{
- int retval;
- int long_stop = 10;
- int retry_on_timeout = 5;
- int retry_on_empty = 10;
- retval = ftdi_elan_flush_input_fifo(ftdi);
- if (retval)
- return retval;
- ftdi->bulk_in_left = 0;
- ftdi->bulk_in_last = -1;
- while (long_stop-- > 0) {
- int read_stop;
- int read_stuck;
- retval = ftdi_elan_synchronize_flush(ftdi);
- if (retval)
- return retval;
- retval = ftdi_elan_flush_input_fifo(ftdi);
- if (retval)
- return retval;
- reset:retval = ftdi_elan_synchronize_reset(ftdi);
- if (retval)
- return retval;
- read_stop = 100;
- read_stuck = 10;
- read:{
- int packet_bytes = 0;
- retval = usb_bulk_msg(ftdi->udev,
- usb_rcvbulkpipe(ftdi->udev,
- ftdi->bulk_in_endpointAddr),
- ftdi->bulk_in_buffer, ftdi->bulk_in_size,
- &packet_bytes, 500);
- if (packet_bytes > 2) {
- char diag[30 *3 + 4];
- char *d = diag;
- int m = (sizeof(diag) - 1) / 3 - 1;
- char *b = ftdi->bulk_in_buffer;
- int bytes_read = 0;
- unsigned char c = 0;
- diag[0] = 0;
- while (packet_bytes-- > 0) {
- c = *b++;
- if (bytes_read < m) {
- d += sprintf(d, " %02X", c);
- } else if (bytes_read > m) {
- } else
- d += sprintf(d, " ..");
- bytes_read += 1;
- continue;
- }
- if (c == 0x7E) {
- return 0;
- } else {
- if (c == 0x55) {
- goto read;
- } else if (read_stop-- > 0) {
- goto read;
- } else {
- dev_err(&ftdi->udev->dev, "retry limit reached\n");
- continue;
- }
- }
- } else if (packet_bytes > 1) {
- unsigned char s1 = ftdi->bulk_in_buffer[0];
- unsigned char s2 = ftdi->bulk_in_buffer[1];
- if (s1 == 0x31 && s2 == 0x00) {
- if (read_stuck-- > 0) {
- goto read;
- } else
- goto reset;
- } else {
- if (read_stop-- > 0) {
- goto read;
- } else {
- dev_err(&ftdi->udev->dev, "retry limit reached\n");
- continue;
- }
- }
- } else if (packet_bytes > 0) {
- if (read_stop-- > 0) {
- goto read;
- } else {
- dev_err(&ftdi->udev->dev, "retry limit reached\n");
- continue;
- }
- } else if (retval == -ETIMEDOUT) {
- if (retry_on_timeout-- > 0) {
- goto read;
- } else {
- dev_err(&ftdi->udev->dev, "TIMED OUT retry limit reached\n");
- continue;
- }
- } else if (retval == 0) {
- if (retry_on_empty-- > 0) {
- goto read;
- } else {
- dev_err(&ftdi->udev->dev, "empty packet retry limit reached\n");
- continue;
- }
- } else {
- dev_err(&ftdi->udev->dev, "error = %d\n",
- retval);
- if (read_stop-- > 0) {
- goto read;
- } else {
- dev_err(&ftdi->udev->dev, "retry limit reached\n");
- continue;
- }
- }
- }
- }
- dev_err(&ftdi->udev->dev, "failed to synchronize\n");
- return -EFAULT;
-}
-
-static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi)
-{
- int retry_on_empty = 10;
- int retry_on_timeout = 5;
- int retry_on_status = 50;
-more:{
- int packet_bytes = 0;
- int retval = usb_bulk_msg(ftdi->udev,
- usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
- ftdi->bulk_in_buffer, ftdi->bulk_in_size,
- &packet_bytes, 1000);
- if (packet_bytes > 2) {
- char diag[30 *3 + 4];
- char *d = diag;
- int m = (sizeof(diag) - 1) / 3 - 1;
- char *b = ftdi->bulk_in_buffer;
- int bytes_read = 0;
- diag[0] = 0;
- while (packet_bytes-- > 0) {
- char c = *b++;
- if (bytes_read < m) {
- d += sprintf(d, " %02X",
- 0x000000FF & c);
- } else if (bytes_read > m) {
- } else
- d += sprintf(d, " ..");
- bytes_read += 1;
- }
- goto more;
- } else if (packet_bytes > 1) {
- char s1 = ftdi->bulk_in_buffer[0];
- char s2 = ftdi->bulk_in_buffer[1];
- if (s1 == 0x31 && s2 == 0x60) {
- return 0;
- } else if (retry_on_status-- > 0) {
- msleep(5);
- goto more;
- } else
- return -EFAULT;
- } else if (packet_bytes > 0) {
- char b1 = ftdi->bulk_in_buffer[0];
- dev_err(&ftdi->udev->dev, "only one byte flushed from FTDI = %02X\n", b1);
- if (retry_on_status-- > 0) {
- msleep(5);
- goto more;
- } else {
- dev_err(&ftdi->udev->dev, "STATUS ERROR retry limit reached\n");
- return -EFAULT;
- }
- } else if (retval == -ETIMEDOUT) {
- if (retry_on_timeout-- > 0) {
- goto more;
- } else {
- dev_err(&ftdi->udev->dev, "TIMED OUT retry limit reached\n");
- return -ENOMEM;
- }
- } else if (retval == 0) {
- if (retry_on_empty-- > 0) {
- goto more;
- } else {
- dev_err(&ftdi->udev->dev, "empty packet retry limit reached\n");
- return -ENOMEM;
- }
- } else {
- dev_err(&ftdi->udev->dev, "error = %d\n", retval);
- return -ENOMEM;
- }
- }
- return -1;
-}
-
-static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi)
-{
- int UxxxStatus = ftdi_elan_read_reg(ftdi, &ftdi->controlreg);
- if (UxxxStatus)
- return UxxxStatus;
- if (ftdi->controlreg & 0x00400000) {
- if (ftdi->card_ejected) {
- } else {
- ftdi->card_ejected = 1;
- dev_err(&ftdi->udev->dev, "CARD EJECTED - controlreg = %08X\n",
- ftdi->controlreg);
- }
- return -ENODEV;
- } else {
- u8 fn = ftdi->function - 1;
- int activePCIfn = fn << 8;
- u32 pcidata;
- u32 pciVID;
- u32 pciPID;
- int reg = 0;
- UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
- &pcidata);
- if (UxxxStatus)
- return UxxxStatus;
- pciVID = pcidata & 0xFFFF;
- pciPID = (pcidata >> 16) & 0xFFFF;
- if (pciVID == ftdi->platform_data.vendor && pciPID ==
- ftdi->platform_data.device) {
- return 0;
- } else {
- dev_err(&ftdi->udev->dev, "vendor=%04X pciVID=%04X device=%04X pciPID=%04X\n",
- ftdi->platform_data.vendor, pciVID,
- ftdi->platform_data.device, pciPID);
- return -ENODEV;
- }
- }
-}
-
-
-#define ftdi_read_pcimem(ftdi, member, data) ftdi_elan_read_pcimem(ftdi, \
- offsetof(struct ohci_regs, member), 0, data);
-#define ftdi_write_pcimem(ftdi, member, data) ftdi_elan_write_pcimem(ftdi, \
- offsetof(struct ohci_regs, member), 0, data);
-
-#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
-#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \
- OHCI_INTR_WDH)
-static int ftdi_elan_check_controller(struct usb_ftdi *ftdi, int quirk)
-{
- int devices = 0;
- int retval;
- u32 hc_control;
- int num_ports;
- u32 control;
- u32 rh_a = -1;
- u32 status;
- u32 fminterval;
- u32 hc_fminterval;
- u32 periodicstart;
- u32 cmdstatus;
- u32 roothub_a;
- int mask = OHCI_INTR_INIT;
- int sleep_time = 0;
- int reset_timeout = 30; /* ... allow extra time */
- int temp;
- retval = ftdi_write_pcimem(ftdi, intrdisable, OHCI_INTR_MIE);
- if (retval)
- return retval;
- retval = ftdi_read_pcimem(ftdi, control, &control);
- if (retval)
- return retval;
- retval = ftdi_read_pcimem(ftdi, roothub.a, &rh_a);
- if (retval)
- return retval;
- num_ports = rh_a & RH_A_NDP;
- retval = ftdi_read_pcimem(ftdi, fminterval, &hc_fminterval);
- if (retval)
- return retval;
- hc_fminterval &= 0x3fff;
- if (hc_fminterval != FI) {
- }
- hc_fminterval |= FSMP(hc_fminterval) << 16;
- retval = ftdi_read_pcimem(ftdi, control, &hc_control);
- if (retval)
- return retval;
- switch (hc_control & OHCI_CTRL_HCFS) {
- case OHCI_USB_OPER:
- sleep_time = 0;
- break;
- case OHCI_USB_SUSPEND:
- case OHCI_USB_RESUME:
- hc_control &= OHCI_CTRL_RWC;
- hc_control |= OHCI_USB_RESUME;
- sleep_time = 10;
- break;
- default:
- hc_control &= OHCI_CTRL_RWC;
- hc_control |= OHCI_USB_RESET;
- sleep_time = 50;
- break;
- }
- retval = ftdi_write_pcimem(ftdi, control, hc_control);
- if (retval)
- return retval;
- retval = ftdi_read_pcimem(ftdi, control, &control);
- if (retval)
- return retval;
- msleep(sleep_time);
- retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a);
- if (retval)
- return retval;
- if (!(roothub_a & RH_A_NPS)) { /* power down each port */
- for (temp = 0; temp < num_ports; temp++) {
- retval = ftdi_write_pcimem(ftdi,
- roothub.portstatus[temp], RH_PS_LSDA);
- if (retval)
- return retval;
- }
- }
- retval = ftdi_read_pcimem(ftdi, control, &control);
- if (retval)
- return retval;
-retry:retval = ftdi_read_pcimem(ftdi, cmdstatus, &status);
- if (retval)
- return retval;
- retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_HCR);
- if (retval)
- return retval;
-extra:{
- retval = ftdi_read_pcimem(ftdi, cmdstatus, &status);
- if (retval)
- return retval;
- if (0 != (status & OHCI_HCR)) {
- if (--reset_timeout == 0) {
- dev_err(&ftdi->udev->dev, "USB HC reset timed out!\n");
- return -ENODEV;
- } else {
- msleep(5);
- goto extra;
- }
- }
- }
- if (quirk & OHCI_QUIRK_INITRESET) {
- retval = ftdi_write_pcimem(ftdi, control, hc_control);
- if (retval)
- return retval;
- retval = ftdi_read_pcimem(ftdi, control, &control);
- if (retval)
- return retval;
- }
- retval = ftdi_write_pcimem(ftdi, ed_controlhead, 0x00000000);
- if (retval)
- return retval;
- retval = ftdi_write_pcimem(ftdi, ed_bulkhead, 0x11000000);
- if (retval)
- return retval;
- retval = ftdi_write_pcimem(ftdi, hcca, 0x00000000);
- if (retval)
- return retval;
- retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval);
- if (retval)
- return retval;
- retval = ftdi_write_pcimem(ftdi, fminterval,
- ((fminterval & FIT) ^ FIT) | hc_fminterval);
- if (retval)
- return retval;
- retval = ftdi_write_pcimem(ftdi, periodicstart,
- ((9 *hc_fminterval) / 10) & 0x3fff);
- if (retval)
- return retval;
- retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval);
- if (retval)
- return retval;
- retval = ftdi_read_pcimem(ftdi, periodicstart, &periodicstart);
- if (retval)
- return retval;
- if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) {
- if (!(quirk & OHCI_QUIRK_INITRESET)) {
- quirk |= OHCI_QUIRK_INITRESET;
- goto retry;
- } else
- dev_err(&ftdi->udev->dev, "init err(%08x %04x)\n",
- fminterval, periodicstart);
- } /* start controller operations */
- hc_control &= OHCI_CTRL_RWC;
- hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER;
- retval = ftdi_write_pcimem(ftdi, control, hc_control);
- if (retval)
- return retval;
- retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_BLF);
- if (retval)
- return retval;
- retval = ftdi_read_pcimem(ftdi, cmdstatus, &cmdstatus);
- if (retval)
- return retval;
- retval = ftdi_read_pcimem(ftdi, control, &control);
- if (retval)
- return retval;
- retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_DRWE);
- if (retval)
- return retval;
- retval = ftdi_write_pcimem(ftdi, intrstatus, mask);
- if (retval)
- return retval;
- retval = ftdi_write_pcimem(ftdi, intrdisable,
- OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO |
- OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH |
- OHCI_INTR_SO);
- if (retval)
- return retval; /* handle root hub init quirks ... */
- retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a);
- if (retval)
- return retval;
- roothub_a &= ~(RH_A_PSM | RH_A_OCPM);
- if (quirk & OHCI_QUIRK_SUPERIO) {
- roothub_a |= RH_A_NOCP;
- roothub_a &= ~(RH_A_POTPGT | RH_A_NPS);
- retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a);
- if (retval)
- return retval;
- } else if ((quirk & OHCI_QUIRK_AMD756) || distrust_firmware) {
- roothub_a |= RH_A_NPS;
- retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a);
- if (retval)
- return retval;
- }
- retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_LPSC);
- if (retval)
- return retval;
- retval = ftdi_write_pcimem(ftdi, roothub.b,
- (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM);
- if (retval)
- return retval;
- retval = ftdi_read_pcimem(ftdi, control, &control);
- if (retval)
- return retval;
- mdelay((roothub_a >> 23) & 0x1fe);
- for (temp = 0; temp < num_ports; temp++) {
- u32 portstatus;
- retval = ftdi_read_pcimem(ftdi, roothub.portstatus[temp],
- &portstatus);
- if (retval)
- return retval;
- if (1 & portstatus)
- devices += 1;
- }
- return devices;
-}
-
-static int ftdi_elan_setup_controller(struct usb_ftdi *ftdi, int fn)
-{
- u32 latence_timer;
- int UxxxStatus;
- u32 pcidata;
- int reg = 0;
- int activePCIfn = fn << 8;
- UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800);
- if (UxxxStatus)
- return UxxxStatus;
- reg = 16;
- UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0,
- 0xFFFFFFFF);
- if (UxxxStatus)
- return UxxxStatus;
- UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
- &pcidata);
- if (UxxxStatus)
- return UxxxStatus;
- UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0,
- 0xF0000000);
- if (UxxxStatus)
- return UxxxStatus;
- UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
- &pcidata);
- if (UxxxStatus)
- return UxxxStatus;
- reg = 12;
- UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
- &latence_timer);
- if (UxxxStatus)
- return UxxxStatus;
- latence_timer &= 0xFFFF00FF;
- latence_timer |= 0x00001600;
- UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00,
- latence_timer);
- if (UxxxStatus)
- return UxxxStatus;
- UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
- &pcidata);
- if (UxxxStatus)
- return UxxxStatus;
- reg = 4;
- UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00,
- 0x06);
- if (UxxxStatus)
- return UxxxStatus;
- UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
- &pcidata);
- if (UxxxStatus)
- return UxxxStatus;
- for (reg = 0; reg <= 0x54; reg += 4) {
- UxxxStatus = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
- if (UxxxStatus)
- return UxxxStatus;
- }
- return 0;
-}
-
-static int ftdi_elan_close_controller(struct usb_ftdi *ftdi, int fn)
-{
- u32 latence_timer;
- int UxxxStatus;
- u32 pcidata;
- int reg = 0;
- int activePCIfn = fn << 8;
- UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800);
- if (UxxxStatus)
- return UxxxStatus;
- reg = 16;
- UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0,
- 0xFFFFFFFF);
- if (UxxxStatus)
- return UxxxStatus;
- UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
- &pcidata);
- if (UxxxStatus)
- return UxxxStatus;
- UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0,
- 0x00000000);
- if (UxxxStatus)
- return UxxxStatus;
- UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
- &pcidata);
- if (UxxxStatus)
- return UxxxStatus;
- reg = 12;
- UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
- &latence_timer);
- if (UxxxStatus)
- return UxxxStatus;
- latence_timer &= 0xFFFF00FF;
- latence_timer |= 0x00001600;
- UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00,
- latence_timer);
- if (UxxxStatus)
- return UxxxStatus;
- UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
- &pcidata);
- if (UxxxStatus)
- return UxxxStatus;
- reg = 4;
- UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00,
- 0x00);
- if (UxxxStatus)
- return UxxxStatus;
- return ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, &pcidata);
-}
-
-static int ftdi_elan_found_controller(struct usb_ftdi *ftdi, int fn, int quirk)
-{
- int result;
- int UxxxStatus;
- UxxxStatus = ftdi_elan_setup_controller(ftdi, fn);
- if (UxxxStatus)
- return UxxxStatus;
- result = ftdi_elan_check_controller(ftdi, quirk);
- UxxxStatus = ftdi_elan_close_controller(ftdi, fn);
- if (UxxxStatus)
- return UxxxStatus;
- return result;
-}
-
-static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi)
-{
- u32 controlreg;
- u8 sensebits;
- int UxxxStatus;
- UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
- if (UxxxStatus)
- return UxxxStatus;
- UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L);
- if (UxxxStatus)
- return UxxxStatus;
- msleep(750);
- UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100);
- if (UxxxStatus)
- return UxxxStatus;
- UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500);
- if (UxxxStatus)
- return UxxxStatus;
- UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
- if (UxxxStatus)
- return UxxxStatus;
- UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000);
- if (UxxxStatus)
- return UxxxStatus;
- UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000);
- if (UxxxStatus)
- return UxxxStatus;
- msleep(250);
- UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000);
- if (UxxxStatus)
- return UxxxStatus;
- UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
- if (UxxxStatus)
- return UxxxStatus;
- UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800);
- if (UxxxStatus)
- return UxxxStatus;
- UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
- if (UxxxStatus)
- return UxxxStatus;
- UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
- if (UxxxStatus)
- return UxxxStatus;
- msleep(1000);
- sensebits = (controlreg >> 16) & 0x000F;
- if (0x0D == sensebits)
- return 0;
- else
- return - ENXIO;
-}
-
-static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi)
-{
- int UxxxStatus;
- u32 pcidata;
- int reg = 0;
- u8 fn;
- int activePCIfn = 0;
- int max_devices = 0;
- int controllers = 0;
- int unrecognized = 0;
- ftdi->function = 0;
- for (fn = 0; (fn < 4); fn++) {
- u32 pciVID = 0;
- u32 pciPID = 0;
- int devices = 0;
- activePCIfn = fn << 8;
- UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
- &pcidata);
- if (UxxxStatus)
- return UxxxStatus;
- pciVID = pcidata & 0xFFFF;
- pciPID = (pcidata >> 16) & 0xFFFF;
- if ((pciVID == PCI_VENDOR_ID_OPTI) && (pciPID == 0xc861)) {
- devices = ftdi_elan_found_controller(ftdi, fn, 0);
- controllers += 1;
- } else if ((pciVID == PCI_VENDOR_ID_NEC) && (pciPID == 0x0035))
- {
- devices = ftdi_elan_found_controller(ftdi, fn, 0);
- controllers += 1;
- } else if ((pciVID == PCI_VENDOR_ID_AL) && (pciPID == 0x5237)) {
- devices = ftdi_elan_found_controller(ftdi, fn, 0);
- controllers += 1;
- } else if ((pciVID == PCI_VENDOR_ID_ATT) && (pciPID == 0x5802))
- {
- devices = ftdi_elan_found_controller(ftdi, fn, 0);
- controllers += 1;
- } else if (pciVID == PCI_VENDOR_ID_AMD && pciPID == 0x740c) {
- devices = ftdi_elan_found_controller(ftdi, fn,
- OHCI_QUIRK_AMD756);
- controllers += 1;
- } else if (pciVID == PCI_VENDOR_ID_COMPAQ && pciPID == 0xa0f8) {
- devices = ftdi_elan_found_controller(ftdi, fn,
- OHCI_QUIRK_ZFMICRO);
- controllers += 1;
- } else if (0 == pcidata) {
- } else
- unrecognized += 1;
- if (devices > max_devices) {
- max_devices = devices;
- ftdi->function = fn + 1;
- ftdi->platform_data.vendor = pciVID;
- ftdi->platform_data.device = pciPID;
- }
- }
- if (ftdi->function > 0) {
- return ftdi_elan_setup_controller(ftdi, ftdi->function - 1);
- } else if (controllers > 0) {
- return -ENXIO;
- } else if (unrecognized > 0) {
- return -ENXIO;
- } else {
- ftdi->enumerated = 0;
- return -ENXIO;
- }
-}
-
-
-/*
- * we use only the first bulk-in and bulk-out endpoints
- */
-static int ftdi_elan_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- struct usb_host_interface *iface_desc;
- struct usb_endpoint_descriptor *bulk_in, *bulk_out;
- int retval;
- struct usb_ftdi *ftdi;
-
- ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
- if (!ftdi)
- return -ENOMEM;
-
- mutex_lock(&ftdi_module_lock);
- list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
- ftdi->sequence_num = ++ftdi_instances;
- mutex_unlock(&ftdi_module_lock);
- ftdi_elan_init_kref(ftdi);
- sema_init(&ftdi->sw_lock, 1);
- ftdi->udev = usb_get_dev(interface_to_usbdev(interface));
- ftdi->interface = interface;
- mutex_init(&ftdi->u132_lock);
- ftdi->expected = 4;
-
- iface_desc = interface->cur_altsetting;
- retval = usb_find_common_endpoints(iface_desc,
- &bulk_in, &bulk_out, NULL, NULL);
- if (retval) {
- dev_err(&ftdi->udev->dev, "Could not find both bulk-in and bulk-out endpoints\n");
- goto error;
- }
-
- ftdi->bulk_in_size = usb_endpoint_maxp(bulk_in);
- ftdi->bulk_in_endpointAddr = bulk_in->bEndpointAddress;
- ftdi->bulk_in_buffer = kmalloc(ftdi->bulk_in_size, GFP_KERNEL);
- if (!ftdi->bulk_in_buffer) {
- retval = -ENOMEM;
- goto error;
- }
-
- ftdi->bulk_out_endpointAddr = bulk_out->bEndpointAddress;
-
- dev_info(&ftdi->udev->dev, "interface %d has I=%02X O=%02X\n",
- iface_desc->desc.bInterfaceNumber, ftdi->bulk_in_endpointAddr,
- ftdi->bulk_out_endpointAddr);
- usb_set_intfdata(interface, ftdi);
- if (iface_desc->desc.bInterfaceNumber == 0 &&
- ftdi->bulk_in_endpointAddr == 0x81 &&
- ftdi->bulk_out_endpointAddr == 0x02) {
- retval = usb_register_dev(interface, &ftdi_elan_jtag_class);
- if (retval) {
- dev_err(&ftdi->udev->dev, "Not able to get a minor for this device\n");
- usb_set_intfdata(interface, NULL);
- retval = -ENOMEM;
- goto error;
- } else {
- ftdi->class = &ftdi_elan_jtag_class;
- dev_info(&ftdi->udev->dev, "USB FDTI=%p JTAG interface %d now attached to ftdi%d\n",
- ftdi, iface_desc->desc.bInterfaceNumber,
- interface->minor);
- return 0;
- }
- } else if (iface_desc->desc.bInterfaceNumber == 1 &&
- ftdi->bulk_in_endpointAddr == 0x83 &&
- ftdi->bulk_out_endpointAddr == 0x04) {
- ftdi->class = NULL;
- dev_info(&ftdi->udev->dev, "USB FDTI=%p ELAN interface %d now activated\n",
- ftdi, iface_desc->desc.bInterfaceNumber);
- INIT_DELAYED_WORK(&ftdi->status_work, ftdi_elan_status_work);
- INIT_DELAYED_WORK(&ftdi->command_work, ftdi_elan_command_work);
- INIT_DELAYED_WORK(&ftdi->respond_work, ftdi_elan_respond_work);
- ftdi_status_queue_work(ftdi, msecs_to_jiffies(3 *1000));
- return 0;
- } else {
- dev_err(&ftdi->udev->dev,
- "Could not find ELAN's U132 device\n");
- retval = -ENODEV;
- goto error;
- }
-error:if (ftdi) {
- ftdi_elan_put_kref(ftdi);
- }
- return retval;
-}
-
-static void ftdi_elan_disconnect(struct usb_interface *interface)
-{
- struct usb_ftdi *ftdi = usb_get_intfdata(interface);
- ftdi->disconnected += 1;
- if (ftdi->class) {
- int minor = interface->minor;
- struct usb_class_driver *class = ftdi->class;
- usb_set_intfdata(interface, NULL);
- usb_deregister_dev(interface, class);
- dev_info(&ftdi->udev->dev, "USB FTDI U132 jtag interface on minor %d now disconnected\n",
- minor);
- } else {
- ftdi_status_cancel_work(ftdi);
- ftdi_command_cancel_work(ftdi);
- ftdi_response_cancel_work(ftdi);
- ftdi_elan_abandon_completions(ftdi);
- ftdi_elan_abandon_targets(ftdi);
- if (ftdi->registered) {
- platform_device_unregister(&ftdi->platform_dev);
- ftdi->synchronized = 0;
- ftdi->enumerated = 0;
- ftdi->initialized = 0;
- ftdi->registered = 0;
- }
- ftdi->disconnected += 1;
- usb_set_intfdata(interface, NULL);
- dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller interface now disconnected\n");
- }
- ftdi_elan_put_kref(ftdi);
-}
-
-static struct usb_driver ftdi_elan_driver = {
- .name = "ftdi-elan",
- .probe = ftdi_elan_probe,
- .disconnect = ftdi_elan_disconnect,
- .id_table = ftdi_elan_table,
-};
-static int __init ftdi_elan_init(void)
-{
- int result;
- pr_info("driver %s\n", ftdi_elan_driver.name);
- mutex_init(&ftdi_module_lock);
- INIT_LIST_HEAD(&ftdi_static_list);
- result = usb_register(&ftdi_elan_driver);
- if (result) {
- pr_err("usb_register failed. Error number %d\n", result);
- }
- return result;
-
-}
-
-static void __exit ftdi_elan_exit(void)
-{
- struct usb_ftdi *ftdi;
- struct usb_ftdi *temp;
- usb_deregister(&ftdi_elan_driver);
- pr_info("ftdi_u132 driver deregistered\n");
- list_for_each_entry_safe(ftdi, temp, &ftdi_static_list, ftdi_list) {
- ftdi_status_cancel_work(ftdi);
- ftdi_command_cancel_work(ftdi);
- ftdi_response_cancel_work(ftdi);
- }
-}
-
-
-module_init(ftdi_elan_init);
-module_exit(ftdi_elan_exit);
diff --git a/drivers/usb/misc/sisusbvga/sisusbvga.c b/drivers/usb/misc/sisusbvga/sisusbvga.c
index 654a79fd3231..febf34f9f049 100644
--- a/drivers/usb/misc/sisusbvga/sisusbvga.c
+++ b/drivers/usb/misc/sisusbvga/sisusbvga.c
@@ -2778,6 +2778,20 @@ static int sisusb_probe(struct usb_interface *intf,
struct usb_device *dev = interface_to_usbdev(intf);
struct sisusb_usb_data *sisusb;
int retval = 0, i;
+ static const u8 ep_addresses[] = {
+ SISUSB_EP_GFX_IN | USB_DIR_IN,
+ SISUSB_EP_GFX_OUT | USB_DIR_OUT,
+ SISUSB_EP_GFX_BULK_OUT | USB_DIR_OUT,
+ SISUSB_EP_GFX_LBULK_OUT | USB_DIR_OUT,
+ SISUSB_EP_BRIDGE_IN | USB_DIR_IN,
+ SISUSB_EP_BRIDGE_OUT | USB_DIR_OUT,
+ 0};
+
+ /* Are the expected endpoints present? */
+ if (!usb_check_bulk_endpoints(intf, ep_addresses)) {
+ dev_err(&intf->dev, "Invalid USB2VGA device\n");
+ return -EINVAL;
+ }
dev_info(&dev->dev, "USB2VGA dongle found at address %d\n",
dev->devnum);
diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c
index e3abe67a155d..ce1da80d3365 100644
--- a/drivers/usb/misc/usb251xb.c
+++ b/drivers/usb/misc/usb251xb.c
@@ -377,7 +377,6 @@ out_err:
return err;
}
-#ifdef CONFIG_OF
static void usb251xb_get_ports_field(struct usb251xb *hub,
const char *prop_name, u8 port_cnt,
bool ds_only, u8 *fld)
@@ -410,10 +409,7 @@ static int usb251xb_get_ofdata(struct usb251xb *hub,
return -ENODEV;
}
- if (of_get_property(np, "skip-config", NULL))
- hub->skip_config = 1;
- else
- hub->skip_config = 0;
+ hub->skip_config = of_property_read_bool(np, "skip-config");
hub->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(hub->gpio_reset))
@@ -431,40 +427,40 @@ static int usb251xb_get_ofdata(struct usb251xb *hub,
hub->device_id = USB251XB_DEF_DEVICE_ID;
hub->conf_data1 = USB251XB_DEF_CONFIG_DATA_1;
- if (of_get_property(np, "self-powered", NULL)) {
+ if (of_property_read_bool(np, "self-powered")) {
hub->conf_data1 |= BIT(7);
/* Configure Over-Current sens when self-powered */
hub->conf_data1 &= ~BIT(2);
- if (of_get_property(np, "ganged-sensing", NULL))
+ if (of_property_read_bool(np, "ganged-sensing"))
hub->conf_data1 &= ~BIT(1);
- else if (of_get_property(np, "individual-sensing", NULL))
+ else if (of_property_read_bool(np, "individual-sensing"))
hub->conf_data1 |= BIT(1);
- } else if (of_get_property(np, "bus-powered", NULL)) {
+ } else if (of_property_read_bool(np, "bus-powered")) {
hub->conf_data1 &= ~BIT(7);
/* Disable Over-Current sense when bus-powered */
hub->conf_data1 |= BIT(2);
}
- if (of_get_property(np, "disable-hi-speed", NULL))
+ if (of_property_read_bool(np, "disable-hi-speed"))
hub->conf_data1 |= BIT(5);
- if (of_get_property(np, "multi-tt", NULL))
+ if (of_property_read_bool(np, "multi-tt"))
hub->conf_data1 |= BIT(4);
- else if (of_get_property(np, "single-tt", NULL))
+ else if (of_property_read_bool(np, "single-tt"))
hub->conf_data1 &= ~BIT(4);
- if (of_get_property(np, "disable-eop", NULL))
+ if (of_property_read_bool(np, "disable-eop"))
hub->conf_data1 |= BIT(3);
- if (of_get_property(np, "individual-port-switching", NULL))
+ if (of_property_read_bool(np, "individual-port-switching"))
hub->conf_data1 |= BIT(0);
- else if (of_get_property(np, "ganged-port-switching", NULL))
+ else if (of_property_read_bool(np, "ganged-port-switching"))
hub->conf_data1 &= ~BIT(0);
hub->conf_data2 = USB251XB_DEF_CONFIG_DATA_2;
- if (of_get_property(np, "dynamic-power-switching", NULL))
+ if (of_property_read_bool(np, "dynamic-power-switching"))
hub->conf_data2 |= BIT(7);
if (!of_property_read_u32(np, "oc-delay-us", &property_u32)) {
@@ -487,17 +483,17 @@ static int usb251xb_get_ofdata(struct usb251xb *hub,
}
}
- if (of_get_property(np, "compound-device", NULL))
+ if (of_property_read_bool(np, "compound-device"))
hub->conf_data2 |= BIT(3);
hub->conf_data3 = USB251XB_DEF_CONFIG_DATA_3;
- if (of_get_property(np, "port-mapping-mode", NULL))
+ if (of_property_read_bool(np, "port-mapping-mode"))
hub->conf_data3 |= BIT(3);
if (data->led_support && of_get_property(np, "led-usb-mode", NULL))
hub->conf_data3 &= ~BIT(1);
- if (of_get_property(np, "string-support", NULL))
+ if (of_property_read_bool(np, "string-support"))
hub->conf_data3 |= BIT(0);
hub->non_rem_dev = USB251XB_DEF_NON_REMOVABLE_DEVICES;
@@ -626,13 +622,6 @@ static const struct of_device_id usb251xb_of_match[] = {
}
};
MODULE_DEVICE_TABLE(of, usb251xb_of_match);
-#else /* CONFIG_OF */
-static int usb251xb_get_ofdata(struct usb251xb *hub,
- const struct usb251xb_data *data)
-{
- return 0;
-}
-#endif /* CONFIG_OF */
static void usb251xb_regulator_disable_action(void *data)
{
@@ -754,7 +743,7 @@ MODULE_DEVICE_TABLE(i2c, usb251xb_id);
static struct i2c_driver usb251xb_i2c_driver = {
.driver = {
.name = DRIVER_NAME,
- .of_match_table = of_match_ptr(usb251xb_of_match),
+ .of_match_table = usb251xb_of_match,
.pm = &usb251xb_pm_ops,
},
.probe_new = usb251xb_i2c_probe,
diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c
index bd47c4437ca4..c6cfd1edaf76 100644
--- a/drivers/usb/misc/usb3503.c
+++ b/drivers/usb/misc/usb3503.c
@@ -46,34 +46,18 @@ struct usb3503 {
struct device *dev;
struct clk *clk;
u8 port_off_mask;
+ struct gpio_desc *bypass;
struct gpio_desc *intn;
struct gpio_desc *reset;
struct gpio_desc *connect;
bool secondary_ref_clk;
};
-static int usb3503_reset(struct usb3503 *hub, int state)
-{
- if (!state && hub->connect)
- gpiod_set_value_cansleep(hub->connect, 0);
-
- if (hub->reset)
- gpiod_set_value_cansleep(hub->reset, !state);
-
- /* Wait T_HUBINIT == 4ms for hub logic to stabilize */
- if (state)
- usleep_range(4000, 10000);
-
- return 0;
-}
-
static int usb3503_connect(struct usb3503 *hub)
{
struct device *dev = hub->dev;
int err;
- usb3503_reset(hub, 1);
-
if (hub->regmap) {
/* SP_ILOCK: set connect_n, config_n for config */
err = regmap_write(hub->regmap, USB3503_SP_ILOCK,
@@ -126,25 +110,46 @@ static int usb3503_connect(struct usb3503 *hub)
static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode)
{
struct device *dev = hub->dev;
- int err = 0;
+ int rst, bypass, conn;
switch (mode) {
case USB3503_MODE_HUB:
- err = usb3503_connect(hub);
+ conn = 1;
+ rst = 0;
+ bypass = 0;
break;
-
case USB3503_MODE_STANDBY:
- usb3503_reset(hub, 0);
+ conn = 0;
+ rst = 1;
+ bypass = 1;
dev_info(dev, "switched to STANDBY mode\n");
break;
-
+ case USB3503_MODE_BYPASS:
+ conn = 0;
+ rst = 0;
+ bypass = 1;
+ break;
default:
dev_err(dev, "unknown mode is requested\n");
- err = -EINVAL;
- break;
+ return -EINVAL;
}
- return err;
+ if (!conn && hub->connect)
+ gpiod_set_value_cansleep(hub->connect, 0);
+
+ if (hub->reset)
+ gpiod_set_value_cansleep(hub->reset, rst);
+
+ if (hub->bypass)
+ gpiod_set_value_cansleep(hub->bypass, bypass);
+
+ if (conn) {
+ /* Wait T_HUBINIT == 4ms for hub logic to stabilize */
+ usleep_range(4000, 10000);
+ return usb3503_connect(hub);
+ }
+
+ return 0;
}
static const struct regmap_config usb3503_regmap_config = {
@@ -253,6 +258,14 @@ static int usb3503_probe(struct usb3503 *hub)
if (hub->connect)
gpiod_set_consumer_name(hub->connect, "usb3503 connect");
+ hub->bypass = devm_gpiod_get_optional(dev, "bypass", GPIOD_OUT_HIGH);
+ if (IS_ERR(hub->bypass)) {
+ err = PTR_ERR(hub->bypass);
+ goto err_clk;
+ }
+ if (hub->bypass)
+ gpiod_set_consumer_name(hub->bypass, "usb3503 bypass");
+
hub->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(hub->reset)) {
err = PTR_ERR(hub->reset);
@@ -388,6 +401,7 @@ MODULE_DEVICE_TABLE(i2c, usb3503_id);
static const struct of_device_id usb3503_of_match[] = {
{ .compatible = "smsc,usb3503", },
{ .compatible = "smsc,usb3503a", },
+ { .compatible = "smsc,usb3803", },
{},
};
MODULE_DEVICE_TABLE(of, usb3503_of_match);
diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
index 2d7b57e07eee..b4a7662dded5 100644
--- a/drivers/usb/mtu3/mtu3.h
+++ b/drivers/usb/mtu3/mtu3.h
@@ -90,7 +90,7 @@ struct mtu3_request;
*/
#define EP0_RESPONSE_BUF 6
-#define BULK_CLKS_CNT 4
+#define BULK_CLKS_CNT 6
/* device operated link and speed got from DEVICE_CONF register */
enum mtu3_speed {
diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c
index 9b8aded3d95e..8191b7ed3852 100644
--- a/drivers/usb/mtu3/mtu3_dr.c
+++ b/drivers/usb/mtu3/mtu3_dr.c
@@ -294,6 +294,7 @@ static int ssusb_role_sw_register(struct otg_switch_mtk *otg_sx)
role_sx_desc.get = ssusb_role_sw_get;
role_sx_desc.fwnode = dev_fwnode(dev);
role_sx_desc.driver_data = ssusb;
+ role_sx_desc.allow_userspace_control = true;
otg_sx->role_sw = usb_role_switch_register(dev, &role_sx_desc);
if (IS_ERR(otg_sx->role_sw))
return PTR_ERR(otg_sx->role_sw);
diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c
index c0264d5426bf..ad0eeac4332d 100644
--- a/drivers/usb/mtu3/mtu3_gadget.c
+++ b/drivers/usb/mtu3/mtu3_gadget.c
@@ -23,7 +23,6 @@ __acquires(mep->mtu->lock)
req->status = status;
trace_mtu3_req_complete(mreq);
- spin_unlock(&mtu->lock);
/* ep0 makes use of PIO, needn't unmap it */
if (mep->epnum)
@@ -32,6 +31,7 @@ __acquires(mep->mtu->lock)
dev_dbg(mtu->dev, "%s complete req: %p, sts %d, %d/%d\n",
mep->name, req, req->status, req->actual, req->length);
+ spin_unlock(&mtu->lock);
usb_gadget_giveback_request(&mep->ep, req);
spin_lock(&mtu->lock);
}
diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c
index f3903367a6a0..177d2caf887c 100644
--- a/drivers/usb/mtu3/mtu3_host.c
+++ b/drivers/usb/mtu3/mtu3_host.c
@@ -11,7 +11,7 @@
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
-#include <linux/of_device.h>
+#include <linux/of_platform.h>
#include <linux/regmap.h>
#include "mtu3.h"
diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c
index d78ae52b4e26..6f264b129243 100644
--- a/drivers/usb/mtu3/mtu3_plat.c
+++ b/drivers/usb/mtu3/mtu3_plat.c
@@ -234,6 +234,8 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
clks[1].id = "ref_ck";
clks[2].id = "mcu_ck";
clks[3].id = "dma_ck";
+ clks[4].id = "xhci_ck";
+ clks[5].id = "frmcnt_ck";
ret = devm_clk_bulk_get_optional(dev, BULK_CLKS_CNT, clks);
if (ret)
return ret;
diff --git a/drivers/usb/mtu3/mtu3_qmu.c b/drivers/usb/mtu3/mtu3_qmu.c
index a2fdab8b63b2..3d77408e3133 100644
--- a/drivers/usb/mtu3/mtu3_qmu.c
+++ b/drivers/usb/mtu3/mtu3_qmu.c
@@ -210,6 +210,7 @@ static struct qmu_gpd *advance_enq_gpd(struct mtu3_gpd_ring *ring)
return ring->enqueue;
}
+/* @dequeue may be NULL if ring is unallocated or freed */
static struct qmu_gpd *advance_deq_gpd(struct mtu3_gpd_ring *ring)
{
if (ring->dequeue < ring->end)
@@ -221,7 +222,7 @@ static struct qmu_gpd *advance_deq_gpd(struct mtu3_gpd_ring *ring)
}
/* check if a ring is emtpy */
-static int gpd_ring_empty(struct mtu3_gpd_ring *ring)
+static bool gpd_ring_empty(struct mtu3_gpd_ring *ring)
{
struct qmu_gpd *enq = ring->enqueue;
struct qmu_gpd *next;
@@ -467,6 +468,37 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum)
}
/*
+ * when rx error happens (except zlperr), QMU will stop, and RQCPR saves
+ * the GPD encountered error, Done irq will arise after resuming QMU again.
+ */
+static void qmu_error_rx(struct mtu3 *mtu, u8 epnum)
+{
+ struct mtu3_ep *mep = mtu->out_eps + epnum;
+ struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+ struct qmu_gpd *gpd_current = NULL;
+ struct mtu3_request *mreq;
+ dma_addr_t cur_gpd_dma;
+
+ cur_gpd_dma = read_rxq_cur_addr(mtu->mac_base, epnum);
+ gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma);
+
+ mreq = next_request(mep);
+ if (!mreq || mreq->gpd != gpd_current) {
+ dev_err(mtu->dev, "no correct RX req is found\n");
+ return;
+ }
+
+ mreq->request.status = -EAGAIN;
+
+ /* by pass the current GDP */
+ gpd_current->dw0_info |= cpu_to_le32(GPD_FLAGS_BPS | GPD_FLAGS_HWO);
+ mtu3_qmu_resume(mep);
+
+ dev_dbg(mtu->dev, "%s EP%d, current=%p, req=%p\n",
+ __func__, epnum, gpd_current, mreq);
+}
+
+/*
* NOTE: request list maybe is already empty as following case:
* queue_tx --> qmu_interrupt(clear interrupt pending, schedule tasklet)-->
* queue_tx --> process_tasklet(meanwhile, the second one is transferred,
@@ -491,7 +523,7 @@ static void qmu_done_tx(struct mtu3 *mtu, u8 epnum)
dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n",
__func__, epnum, gpd, gpd_current, ring->enqueue);
- while (gpd != gpd_current && !GET_GPD_HWO(gpd)) {
+ while (gpd && gpd != gpd_current && !GET_GPD_HWO(gpd)) {
mreq = next_request(mep);
@@ -530,7 +562,7 @@ static void qmu_done_rx(struct mtu3 *mtu, u8 epnum)
dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n",
__func__, epnum, gpd, gpd_current, ring->enqueue);
- while (gpd != gpd_current && !GET_GPD_HWO(gpd)) {
+ while (gpd && gpd != gpd_current && !GET_GPD_HWO(gpd)) {
mreq = next_request(mep);
@@ -571,14 +603,18 @@ static void qmu_exception_isr(struct mtu3 *mtu, u32 qmu_status)
if ((qmu_status & RXQ_CSERR_INT) || (qmu_status & RXQ_LENERR_INT)) {
errval = mtu3_readl(mbase, U3D_RQERRIR0);
+ mtu3_writel(mbase, U3D_RQERRIR0, errval);
+
for (i = 1; i < mtu->num_eps; i++) {
if (errval & QMU_RX_CS_ERR(i))
dev_err(mtu->dev, "Rx %d CS error!\n", i);
if (errval & QMU_RX_LEN_ERR(i))
dev_err(mtu->dev, "RX %d Length error\n", i);
+
+ if (errval & (QMU_RX_CS_ERR(i) | QMU_RX_LEN_ERR(i)))
+ qmu_error_rx(mtu, i);
}
- mtu3_writel(mbase, U3D_RQERRIR0, errval);
}
if (qmu_status & RXQ_ZLPERR_INT) {
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 3a1f4bcea80c..9a8cf3de0617 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -113,7 +113,7 @@ config USB_MUSB_MEDIATEK
config USB_MUSB_POLARFIRE_SOC
tristate "Microchip PolarFire SoC platforms"
- depends on SOC_MICROCHIP_POLARFIRE || COMPILE_TEST
+ depends on ARCH_MICROCHIP_POLARFIRE || COMPILE_TEST
depends on NOP_USB_XCEIV
select USB_MUSB_DUAL_ROLE
help
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index d47e5c94587b..912e32b78ac6 100644
--- a/drivers/usb/musb/da8xx.c
+++ b/drivers/usb/musb/da8xx.c
@@ -576,14 +576,12 @@ static int da8xx_probe(struct platform_device *pdev)
return ret;
}
-static int da8xx_remove(struct platform_device *pdev)
+static void da8xx_remove(struct platform_device *pdev)
{
struct da8xx_glue *glue = platform_get_drvdata(pdev);
platform_device_unregister(glue->musb);
usb_phy_generic_unregister(glue->usb_phy);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -626,7 +624,7 @@ MODULE_DEVICE_TABLE(of, da8xx_id_table);
static struct platform_driver da8xx_driver = {
.probe = da8xx_probe,
- .remove = da8xx_remove,
+ .remove_new = da8xx_remove,
.driver = {
.name = "musb-da8xx",
.pm = &da8xx_pm_ops,
diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c
index c7b1d2a394d9..5aabdd7e2511 100644
--- a/drivers/usb/musb/jz4740.c
+++ b/drivers/usb/musb/jz4740.c
@@ -308,14 +308,12 @@ err_platform_device_put:
return ret;
}
-static int jz4740_remove(struct platform_device *pdev)
+static void jz4740_remove(struct platform_device *pdev)
{
struct jz4740_glue *glue = platform_get_drvdata(pdev);
platform_device_unregister(glue->pdev);
clk_disable_unprepare(glue->clk);
-
- return 0;
}
static const struct of_device_id jz4740_musb_of_match[] = {
@@ -327,7 +325,7 @@ MODULE_DEVICE_TABLE(of, jz4740_musb_of_match);
static struct platform_driver jz4740_driver = {
.probe = jz4740_probe,
- .remove = jz4740_remove,
+ .remove_new = jz4740_remove,
.driver = {
.name = "musb-jz4740",
.of_match_table = jz4740_musb_of_match,
diff --git a/drivers/usb/musb/mediatek.c b/drivers/usb/musb/mediatek.c
index 27b9bd258340..598ee5c0bf34 100644
--- a/drivers/usb/musb/mediatek.c
+++ b/drivers/usb/musb/mediatek.c
@@ -508,15 +508,13 @@ err_unregister_usb_phy:
return ret;
}
-static int mtk_musb_remove(struct platform_device *pdev)
+static void mtk_musb_remove(struct platform_device *pdev)
{
struct mtk_glue *glue = platform_get_drvdata(pdev);
struct platform_device *usb_phy = glue->usb_phy;
platform_device_unregister(glue->musb_pdev);
usb_phy_generic_unregister(usb_phy);
-
- return 0;
}
#ifdef CONFIG_OF
@@ -529,7 +527,7 @@ MODULE_DEVICE_TABLE(of, mtk_musb_match);
static struct platform_driver mtk_musb_driver = {
.probe = mtk_musb_probe,
- .remove = mtk_musb_remove,
+ .remove_new = mtk_musb_remove,
.driver = {
.name = "musb-mtk",
.of_match_table = of_match_ptr(mtk_musb_match),
diff --git a/drivers/usb/musb/mpfs.c b/drivers/usb/musb/mpfs.c
index cea2e8108867..24b98716f7fc 100644
--- a/drivers/usb/musb/mpfs.c
+++ b/drivers/usb/musb/mpfs.c
@@ -235,15 +235,13 @@ err_phy_release:
return ret;
}
-static int mpfs_remove(struct platform_device *pdev)
+static void mpfs_remove(struct platform_device *pdev)
{
struct mpfs_glue *glue = platform_get_drvdata(pdev);
clk_disable_unprepare(glue->clk);
platform_device_unregister(glue->musb);
usb_phy_generic_unregister(pdev);
-
- return 0;
}
#ifdef CONFIG_OF
@@ -256,7 +254,7 @@ MODULE_DEVICE_TABLE(of, mpfs_id_table);
static struct platform_driver mpfs_musb_driver = {
.probe = mpfs_probe,
- .remove = mpfs_remove,
+ .remove_new = mpfs_remove,
.driver = {
.name = "mpfs-musb",
.of_match_table = of_match_ptr(mpfs_id_table)
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 648bb6021c5e..d162afbbe19f 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -2621,7 +2621,7 @@ static int musb_probe(struct platform_device *pdev)
return musb_init_controller(dev, irq, base);
}
-static int musb_remove(struct platform_device *pdev)
+static void musb_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct musb *musb = dev_to_musb(dev);
@@ -2657,7 +2657,6 @@ static int musb_remove(struct platform_device *pdev)
usb_phy_shutdown(musb->xceiv);
musb_free(musb);
device_init_wakeup(dev, 0);
- return 0;
}
#ifdef CONFIG_PM
@@ -2955,7 +2954,7 @@ static struct platform_driver musb_driver = {
.dev_groups = musb_groups,
},
.probe = musb_probe,
- .remove = musb_remove,
+ .remove_new = musb_remove,
};
module_platform_driver(musb_driver);
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index f75cde0f2b43..9119b1d51370 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -915,7 +915,7 @@ err:
return ret;
}
-static int dsps_remove(struct platform_device *pdev)
+static void dsps_remove(struct platform_device *pdev)
{
struct dsps_glue *glue = platform_get_drvdata(pdev);
@@ -923,8 +923,6 @@ static int dsps_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
iounmap(glue->usbss_base);
-
- return 0;
}
static const struct dsps_musb_wrapper am33xx_driver_data = {
@@ -1036,7 +1034,7 @@ static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume);
static struct platform_driver dsps_usbss_driver = {
.probe = dsps_probe,
- .remove = dsps_remove,
+ .remove_new = dsps_remove,
.driver = {
.name = "musb-dsps",
.pm = &dsps_pm_ops,
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 44a21ec865fb..b4a4c1df4e0d 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -334,7 +334,7 @@ static int omap2430_probe(struct platform_device *pdev)
* Legacy SoCs using omap_device get confused if node is moved
* because of interconnect properties mixed into the node.
*/
- if (of_get_property(np, "ti,hwmods", NULL)) {
+ if (of_property_present(np, "ti,hwmods")) {
dev_warn(&pdev->dev, "please update to probe with ti-sysc\n");
populate_irqs = true;
} else {
@@ -471,14 +471,12 @@ err0:
return ret;
}
-static int omap2430_remove(struct platform_device *pdev)
+static void omap2430_remove(struct platform_device *pdev)
{
struct omap2430_glue *glue = platform_get_drvdata(pdev);
platform_device_unregister(glue->musb);
pm_runtime_disable(glue->dev);
-
- return 0;
}
#ifdef CONFIG_PM
@@ -610,7 +608,7 @@ MODULE_DEVICE_TABLE(of, omap2430_id_table);
static struct platform_driver omap2430_driver = {
.probe = omap2430_probe,
- .remove = omap2430_remove,
+ .remove_new = omap2430_remove,
.driver = {
.name = "musb-omap2430",
.pm = DEV_PM_OPS,
diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c
index 9b622cd9b2bd..c5c6c4e09300 100644
--- a/drivers/usb/musb/sunxi.c
+++ b/drivers/usb/musb/sunxi.c
@@ -805,15 +805,13 @@ err_unregister_usb_phy:
return ret;
}
-static int sunxi_musb_remove(struct platform_device *pdev)
+static void sunxi_musb_remove(struct platform_device *pdev)
{
struct sunxi_glue *glue = platform_get_drvdata(pdev);
struct platform_device *usb_phy = glue->usb_phy;
platform_device_unregister(glue->musb_pdev);
usb_phy_generic_unregister(usb_phy);
-
- return 0;
}
static const struct sunxi_musb_cfg sun4i_a10_musb_cfg = {
@@ -862,7 +860,7 @@ MODULE_DEVICE_TABLE(of, sunxi_musb_match);
static struct platform_driver sunxi_musb_driver = {
.probe = sunxi_musb_probe,
- .remove = sunxi_musb_remove,
+ .remove_new = sunxi_musb_remove,
.driver = {
.name = "musb-sunxi",
.of_match_table = sunxi_musb_match,
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 5609b4e84d40..a1f29dbc62e6 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -1258,19 +1258,17 @@ static int tusb_probe(struct platform_device *pdev)
return 0;
}
-static int tusb_remove(struct platform_device *pdev)
+static void tusb_remove(struct platform_device *pdev)
{
struct tusb6010_glue *glue = platform_get_drvdata(pdev);
platform_device_unregister(glue->musb);
usb_phy_generic_unregister(glue->phy);
-
- return 0;
}
static struct platform_driver tusb_driver = {
.probe = tusb_probe,
- .remove = tusb_remove,
+ .remove_new = tusb_remove,
.driver = {
.name = "musb-tusb",
},
diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c
index 8ea62c344328..c8d9d2a1d2f0 100644
--- a/drivers/usb/musb/ux500.c
+++ b/drivers/usb/musb/ux500.c
@@ -303,14 +303,12 @@ err0:
return ret;
}
-static int ux500_remove(struct platform_device *pdev)
+static void ux500_remove(struct platform_device *pdev)
{
struct ux500_glue *glue = platform_get_drvdata(pdev);
platform_device_unregister(glue->musb);
clk_disable_unprepare(glue->clk);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -357,7 +355,7 @@ MODULE_DEVICE_TABLE(of, ux500_match);
static struct platform_driver ux500_driver = {
.probe = ux500_probe,
- .remove = ux500_remove,
+ .remove_new = ux500_remove,
.driver = {
.name = "musb-ux500",
.pm = &ux500_pm_ops,
diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c
index 4c52ba96f17e..408f47e39025 100644
--- a/drivers/usb/phy/phy-ab8500-usb.c
+++ b/drivers/usb/phy/phy-ab8500-usb.c
@@ -965,7 +965,7 @@ static int ab8500_usb_probe(struct platform_device *pdev)
return 0;
}
-static int ab8500_usb_remove(struct platform_device *pdev)
+static void ab8500_usb_remove(struct platform_device *pdev)
{
struct ab8500_usb *ab = platform_get_drvdata(pdev);
@@ -977,8 +977,6 @@ static int ab8500_usb_remove(struct platform_device *pdev)
ab8500_usb_host_phy_dis(ab);
else if (ab->mode == USB_PERIPHERAL)
ab8500_usb_peri_phy_dis(ab);
-
- return 0;
}
static const struct platform_device_id ab8500_usb_devtype[] = {
@@ -989,7 +987,7 @@ MODULE_DEVICE_TABLE(platform, ab8500_usb_devtype);
static struct platform_driver ab8500_usb_driver = {
.probe = ab8500_usb_probe,
- .remove = ab8500_usb_remove,
+ .remove_new = ab8500_usb_remove,
.id_table = ab8500_usb_devtype,
.driver = {
.name = "abx5x0-usb",
diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c
index 8524475d942d..e39665cf4b4a 100644
--- a/drivers/usb/phy/phy-am335x.c
+++ b/drivers/usb/phy/phy-am335x.c
@@ -82,12 +82,11 @@ static int am335x_phy_probe(struct platform_device *pdev)
return usb_add_phy_dev(&am_phy->usb_phy_gen.phy);
}
-static int am335x_phy_remove(struct platform_device *pdev)
+static void am335x_phy_remove(struct platform_device *pdev)
{
struct am335x_phy *am_phy = platform_get_drvdata(pdev);
usb_remove_phy(&am_phy->usb_phy_gen.phy);
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -134,7 +133,7 @@ MODULE_DEVICE_TABLE(of, am335x_phy_ids);
static struct platform_driver am335x_phy_driver = {
.probe = am335x_phy_probe,
- .remove = am335x_phy_remove,
+ .remove_new = am335x_phy_remove,
.driver = {
.name = "am335x-phy-driver",
.pm = &am335x_pm_ops,
diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
index 972704262b02..79617bb0a70e 100644
--- a/drivers/usb/phy/phy-fsl-usb.c
+++ b/drivers/usb/phy/phy-fsl-usb.c
@@ -983,7 +983,7 @@ static int fsl_otg_probe(struct platform_device *pdev)
return ret;
}
-static int fsl_otg_remove(struct platform_device *pdev)
+static void fsl_otg_remove(struct platform_device *pdev)
{
struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
@@ -998,13 +998,11 @@ static int fsl_otg_remove(struct platform_device *pdev)
if (pdata->exit)
pdata->exit(pdev);
-
- return 0;
}
struct platform_driver fsl_otg_driver = {
.probe = fsl_otg_probe,
- .remove = fsl_otg_remove,
+ .remove_new = fsl_otg_remove,
.driver = {
.name = driver_name,
.owner = THIS_MODULE,
diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
index c1309ea24a52..770081b828a4 100644
--- a/drivers/usb/phy/phy-generic.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -330,13 +330,11 @@ static int usb_phy_generic_probe(struct platform_device *pdev)
return 0;
}
-static int usb_phy_generic_remove(struct platform_device *pdev)
+static void usb_phy_generic_remove(struct platform_device *pdev)
{
struct usb_phy_generic *nop = platform_get_drvdata(pdev);
usb_remove_phy(&nop->phy);
-
- return 0;
}
static const struct of_device_id nop_xceiv_dt_ids[] = {
@@ -348,7 +346,7 @@ MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids);
static struct platform_driver usb_phy_generic_driver = {
.probe = usb_phy_generic_probe,
- .remove = usb_phy_generic_remove,
+ .remove_new = usb_phy_generic_remove,
.driver = {
.name = "usb_phy_generic",
.of_match_table = nop_xceiv_dt_ids,
diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c
index 12dfeff7de3d..817c242a76ca 100644
--- a/drivers/usb/phy/phy-gpio-vbus-usb.c
+++ b/drivers/usb/phy/phy-gpio-vbus-usb.c
@@ -325,7 +325,7 @@ static int gpio_vbus_probe(struct platform_device *pdev)
return 0;
}
-static int gpio_vbus_remove(struct platform_device *pdev)
+static void gpio_vbus_remove(struct platform_device *pdev)
{
struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
@@ -333,8 +333,6 @@ static int gpio_vbus_remove(struct platform_device *pdev)
cancel_delayed_work_sync(&gpio_vbus->work);
usb_remove_phy(&gpio_vbus->phy);
-
- return 0;
}
#ifdef CONFIG_PM
@@ -386,7 +384,7 @@ static struct platform_driver gpio_vbus_driver = {
.of_match_table = gpio_vbus_of_match,
},
.probe = gpio_vbus_probe,
- .remove = gpio_vbus_remove,
+ .remove_new = gpio_vbus_remove,
};
module_platform_driver(gpio_vbus_driver);
diff --git a/drivers/usb/phy/phy-keystone.c b/drivers/usb/phy/phy-keystone.c
index f75912279b39..bd9a98ad1b30 100644
--- a/drivers/usb/phy/phy-keystone.c
+++ b/drivers/usb/phy/phy-keystone.c
@@ -88,13 +88,11 @@ static int keystone_usbphy_probe(struct platform_device *pdev)
return usb_add_phy_dev(&k_phy->usb_phy_gen.phy);
}
-static int keystone_usbphy_remove(struct platform_device *pdev)
+static void keystone_usbphy_remove(struct platform_device *pdev)
{
struct keystone_usbphy *k_phy = platform_get_drvdata(pdev);
usb_remove_phy(&k_phy->usb_phy_gen.phy);
-
- return 0;
}
static const struct of_device_id keystone_usbphy_ids[] = {
@@ -105,7 +103,7 @@ MODULE_DEVICE_TABLE(of, keystone_usbphy_ids);
static struct platform_driver keystone_usbphy_driver = {
.probe = keystone_usbphy_probe,
- .remove = keystone_usbphy_remove,
+ .remove_new = keystone_usbphy_remove,
.driver = {
.name = "keystone-usbphy",
.of_match_table = keystone_usbphy_ids,
diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c
index 86503b7d695c..df7c27474a75 100644
--- a/drivers/usb/phy/phy-mv-usb.c
+++ b/drivers/usb/phy/phy-mv-usb.c
@@ -644,7 +644,7 @@ static const struct attribute_group *mv_otg_groups[] = {
NULL,
};
-static int mv_otg_remove(struct platform_device *pdev)
+static void mv_otg_remove(struct platform_device *pdev)
{
struct mv_otg *mvotg = platform_get_drvdata(pdev);
@@ -654,8 +654,6 @@ static int mv_otg_remove(struct platform_device *pdev)
mv_otg_disable(mvotg);
usb_remove_phy(&mvotg->phy);
-
- return 0;
}
static int mv_otg_probe(struct platform_device *pdev)
@@ -869,7 +867,7 @@ static int mv_otg_resume(struct platform_device *pdev)
static struct platform_driver mv_otg_driver = {
.probe = mv_otg_probe,
- .remove = mv_otg_remove,
+ .remove_new = mv_otg_remove,
.driver = {
.name = driver_name,
.dev_groups = mv_otg_groups,
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index d2836ef5d15c..e1a2b2ea098b 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -733,7 +733,7 @@ static int mxs_phy_probe(struct platform_device *pdev)
return -ENOMEM;
/* Some SoCs don't have anatop registers */
- if (of_get_property(np, "fsl,anatop", NULL)) {
+ if (of_property_present(np, "fsl,anatop")) {
mxs_phy->regmap_anatop = syscon_regmap_lookup_by_phandle
(np, "fsl,anatop");
if (IS_ERR(mxs_phy->regmap_anatop)) {
@@ -801,13 +801,11 @@ static int mxs_phy_probe(struct platform_device *pdev)
return usb_add_phy_dev(&mxs_phy->phy);
}
-static int mxs_phy_remove(struct platform_device *pdev)
+static void mxs_phy_remove(struct platform_device *pdev)
{
struct mxs_phy *mxs_phy = platform_get_drvdata(pdev);
usb_remove_phy(&mxs_phy->phy);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -853,7 +851,7 @@ static SIMPLE_DEV_PM_OPS(mxs_phy_pm, mxs_phy_system_suspend,
static struct platform_driver mxs_phy_driver = {
.probe = mxs_phy_probe,
- .remove = mxs_phy_remove,
+ .remove_new = mxs_phy_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = mxs_phy_dt_ids,
diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c
index f2d2cc586c5b..47562d49dfc1 100644
--- a/drivers/usb/phy/phy-tahvo.c
+++ b/drivers/usb/phy/phy-tahvo.c
@@ -412,7 +412,7 @@ err_disable_clk:
return ret;
}
-static int tahvo_usb_remove(struct platform_device *pdev)
+static void tahvo_usb_remove(struct platform_device *pdev)
{
struct tahvo_usb *tu = platform_get_drvdata(pdev);
@@ -420,13 +420,11 @@ static int tahvo_usb_remove(struct platform_device *pdev)
usb_remove_phy(&tu->phy);
if (!IS_ERR(tu->ick))
clk_disable(tu->ick);
-
- return 0;
}
static struct platform_driver tahvo_usb_driver = {
.probe = tahvo_usb_probe,
- .remove = tahvo_usb_remove,
+ .remove_new = tahvo_usb_remove,
.driver = {
.name = "tahvo-usb",
.dev_groups = tahvo_groups,
diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c
index f0240107edb1..8b2ff3a8882d 100644
--- a/drivers/usb/phy/phy-tegra-usb.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
@@ -1375,7 +1375,7 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
tegra_phy->is_legacy_phy =
of_property_read_bool(np, "nvidia,has-legacy-mode");
- if (of_find_property(np, "dr_mode", NULL))
+ if (of_property_present(np, "dr_mode"))
tegra_phy->mode = usb_get_dr_mode(&pdev->dev);
else
tegra_phy->mode = USB_DR_MODE_HOST;
@@ -1486,18 +1486,16 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
return usb_add_phy_dev(&tegra_phy->u_phy);
}
-static int tegra_usb_phy_remove(struct platform_device *pdev)
+static void tegra_usb_phy_remove(struct platform_device *pdev)
{
struct tegra_usb_phy *tegra_phy = platform_get_drvdata(pdev);
usb_remove_phy(&tegra_phy->u_phy);
-
- return 0;
}
static struct platform_driver tegra_usb_phy_driver = {
.probe = tegra_usb_phy_probe,
- .remove = tegra_usb_phy_remove,
+ .remove_new = tegra_usb_phy_remove,
.driver = {
.name = "tegra-phy",
.of_match_table = tegra_usb_phy_id_table,
diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c
index ab3c38a7d8ac..c3ce6b1054f1 100644
--- a/drivers/usb/phy/phy-twl6030-usb.c
+++ b/drivers/usb/phy/phy-twl6030-usb.c
@@ -409,7 +409,7 @@ err_put_regulator:
return status;
}
-static int twl6030_usb_remove(struct platform_device *pdev)
+static void twl6030_usb_remove(struct platform_device *pdev)
{
struct twl6030_usb *twl = platform_get_drvdata(pdev);
@@ -422,8 +422,6 @@ static int twl6030_usb_remove(struct platform_device *pdev)
free_irq(twl->irq2, twl);
regulator_put(twl->usb3v3);
cancel_work_sync(&twl->set_vbus_work);
-
- return 0;
}
static const struct of_device_id twl6030_usb_id_table[] = {
@@ -434,7 +432,7 @@ MODULE_DEVICE_TABLE(of, twl6030_usb_id_table);
static struct platform_driver twl6030_usb_driver = {
.probe = twl6030_usb_probe,
- .remove = twl6030_usb_remove,
+ .remove_new = twl6030_usb_remove,
.driver = {
.name = "twl6030_usb",
.of_match_table = of_match_ptr(twl6030_usb_id_table),
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index 96f3939a65e2..fa34efabcccf 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -823,7 +823,7 @@ static struct platform_driver renesas_usbhs_driver = {
.driver = {
.name = "renesas_usbhs",
.pm = &usbhsc_pm_ops,
- .of_match_table = of_match_ptr(usbhs_of_match),
+ .of_match_table = usbhs_of_match,
},
.probe = usbhs_probe,
.remove = usbhs_remove,
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index f31cc3c76329..644a55447fd7 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -595,6 +595,11 @@ static void option_instat_callback(struct urb *urb);
#define SIERRA_VENDOR_ID 0x1199
#define SIERRA_PRODUCT_EM9191 0x90d3
+/* UNISOC (Spreadtrum) products */
+#define UNISOC_VENDOR_ID 0x1782
+/* TOZED LT70-C based on UNISOC SL8563 uses UNISOC's vendor ID */
+#define TOZED_PRODUCT_LT70C 0x4055
+
/* Device flags */
/* Highest interface number which can be used with NCTRL() and RSVD() */
@@ -2225,6 +2230,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(OPPO_VENDOR_ID, OPPO_PRODUCT_R11, 0xff, 0xff, 0x30) },
{ USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0xff, 0x30) },
{ USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0, 0) },
+ { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, TOZED_PRODUCT_LT70C, 0xff, 0, 0) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
index 6fca40ace83a..fee581409bf6 100644
--- a/drivers/usb/serial/quatech2.c
+++ b/drivers/usb/serial/quatech2.c
@@ -176,14 +176,6 @@ static inline int qt2_control_msg(struct usb_device *dev,
NULL, 0, QT2_USB_TIMEOUT);
}
-static inline int qt2_setdevice(struct usb_device *dev, u8 *data)
-{
- u16 x = ((u16) (data[1] << 8) | (u16) (data[0]));
-
- return qt2_control_msg(dev, QT_SET_GET_DEVICE, x, 0);
-}
-
-
static inline int qt2_getregister(struct usb_device *dev,
u8 uart,
u8 reg,
diff --git a/drivers/usb/typec/hd3ss3220.c b/drivers/usb/typec/hd3ss3220.c
index 746ef3a75b76..8bbeb9b1e439 100644
--- a/drivers/usb/typec/hd3ss3220.c
+++ b/drivers/usb/typec/hd3ss3220.c
@@ -290,7 +290,7 @@ MODULE_DEVICE_TABLE(of, dev_ids);
static struct i2c_driver hd3ss3220_driver = {
.driver = {
.name = "hd3ss3220",
- .of_match_table = of_match_ptr(dev_ids),
+ .of_match_table = dev_ids,
},
.probe_new = hd3ss3220_probe,
.remove = hd3ss3220_remove,
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 1ffce00d94b4..62ba53357612 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -190,7 +190,7 @@ static void fusb302_log(struct fusb302_chip *chip, const char *fmt, ...)
static int fusb302_debug_show(struct seq_file *s, void *v)
{
- struct fusb302_chip *chip = (struct fusb302_chip *)s->private;
+ struct fusb302_chip *chip = s->private;
int tail;
mutex_lock(&chip->logbuffer_lock);
@@ -1813,7 +1813,7 @@ static int fusb302_pm_resume(struct device *dev)
return 0;
}
-static const struct of_device_id fusb302_dt_match[] = {
+static const struct of_device_id fusb302_dt_match[] __maybe_unused = {
{.compatible = "fcs,fusb302"},
{},
};
diff --git a/drivers/usb/typec/tcpm/tcpci_mt6360.c b/drivers/usb/typec/tcpm/tcpci_mt6360.c
index 1b7c31278ebb..6fa8fd5c8041 100644
--- a/drivers/usb/typec/tcpm/tcpci_mt6360.c
+++ b/drivers/usb/typec/tcpm/tcpci_mt6360.c
@@ -43,12 +43,6 @@ struct mt6360_tcpc_info {
int irq;
};
-static inline int mt6360_tcpc_read16(struct regmap *regmap,
- unsigned int reg, u16 *val)
-{
- return regmap_raw_read(regmap, reg, val, sizeof(u16));
-}
-
static inline int mt6360_tcpc_write16(struct regmap *regmap,
unsigned int reg, u16 val)
{
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 1ee774c263f0..3c6b0c8e2d3a 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -737,7 +737,7 @@ static void tcpm_log_source_caps(struct tcpm_port *port)
static int tcpm_debug_show(struct seq_file *s, void *v)
{
- struct tcpm_port *port = (struct tcpm_port *)s->private;
+ struct tcpm_port *port = s->private;
int tail;
mutex_lock(&port->logbuffer_lock);
@@ -1523,7 +1523,21 @@ static bool svdm_consume_svids(struct tcpm_port *port, const u32 *p, int cnt)
pmdata->svids[pmdata->nsvids++] = svid;
tcpm_log(port, "SVID %d: 0x%x", pmdata->nsvids, svid);
}
- return true;
+
+ /*
+ * PD3.0 Spec 6.4.4.3.2: The SVIDs are returned 2 per VDO (see Table
+ * 6-43), and can be returned maximum 6 VDOs per response (see Figure
+ * 6-19). If the Respondersupports 12 or more SVID then the Discover
+ * SVIDs Command Shall be executed multiple times until a Discover
+ * SVIDs VDO is returned ending either with a SVID value of 0x0000 in
+ * the last part of the last VDO or with a VDO containing two SVIDs
+ * with values of 0x0000.
+ *
+ * However, some odd dockers support SVIDs less than 12 but without
+ * 0x0000 in the last VDO, so we need to break the Discover SVIDs
+ * request and return false here.
+ */
+ return cnt == 7;
abort:
tcpm_log(port, "SVID_DISCOVERY_MAX(%d) too low!", SVID_DISCOVERY_MAX);
return false;
@@ -6577,6 +6591,8 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
port->port_type = port->typec_caps.type;
port->role_sw = usb_role_switch_get(port->dev);
+ if (!port->role_sw)
+ port->role_sw = fwnode_usb_role_switch_get(tcpc->fwnode);
if (IS_ERR(port->role_sw)) {
err = PTR_ERR(port->role_sw);
goto out_destroy_wq;
diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c
index 485b90c13078..8b075ca82ef6 100644
--- a/drivers/usb/typec/tipd/core.c
+++ b/drivers/usb/typec/tipd/core.c
@@ -16,6 +16,7 @@
#include <linux/usb/typec.h>
#include <linux/usb/typec_altmode.h>
#include <linux/usb/role.h>
+#include <linux/workqueue.h>
#include "tps6598x.h"
#include "trace.h"
@@ -97,6 +98,8 @@ struct tps6598x {
int wakeup;
u16 pwr_status;
+ struct delayed_work wq_poll;
+ irq_handler_t irq_handler;
};
static enum power_supply_property tps6598x_psy_props[] = {
@@ -177,16 +180,6 @@ static inline int tps6598x_read64(struct tps6598x *tps, u8 reg, u64 *val)
return tps6598x_block_read(tps, reg, val, sizeof(u64));
}
-static inline int tps6598x_write16(struct tps6598x *tps, u8 reg, u16 val)
-{
- return tps6598x_block_write(tps, reg, &val, sizeof(u16));
-}
-
-static inline int tps6598x_write32(struct tps6598x *tps, u8 reg, u32 val)
-{
- return tps6598x_block_write(tps, reg, &val, sizeof(u32));
-}
-
static inline int tps6598x_write64(struct tps6598x *tps, u8 reg, u64 val)
{
return tps6598x_block_write(tps, reg, &val, sizeof(u64));
@@ -568,6 +561,18 @@ err_unlock:
return IRQ_NONE;
}
+/* Time interval for Polling */
+#define POLL_INTERVAL 500 /* msecs */
+static void tps6598x_poll_work(struct work_struct *work)
+{
+ struct tps6598x *tps = container_of(to_delayed_work(work),
+ struct tps6598x, wq_poll);
+
+ tps->irq_handler(0, tps);
+ queue_delayed_work(system_power_efficient_wq,
+ &tps->wq_poll, msecs_to_jiffies(POLL_INTERVAL));
+}
+
static int tps6598x_check_mode(struct tps6598x *tps)
{
char mode[5] = { };
@@ -746,6 +751,7 @@ static int tps6598x_probe(struct i2c_client *client)
TPS_REG_INT_PLUG_EVENT;
}
+ tps->irq_handler = irq_handler;
/* Make sure the controller has application firmware running */
ret = tps6598x_check_mode(tps);
if (ret)
@@ -837,10 +843,18 @@ static int tps6598x_probe(struct i2c_client *client)
dev_err(&client->dev, "failed to register partner\n");
}
- ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
- irq_handler,
- IRQF_SHARED | IRQF_ONESHOT,
- dev_name(&client->dev), tps);
+ if (client->irq) {
+ ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+ irq_handler,
+ IRQF_SHARED | IRQF_ONESHOT,
+ dev_name(&client->dev), tps);
+ } else {
+ dev_warn(tps->dev, "Unable to find the interrupt, switching to polling\n");
+ INIT_DELAYED_WORK(&tps->wq_poll, tps6598x_poll_work);
+ queue_delayed_work(system_power_efficient_wq, &tps->wq_poll,
+ msecs_to_jiffies(POLL_INTERVAL));
+ }
+
if (ret)
goto err_disconnect;
@@ -848,7 +862,7 @@ static int tps6598x_probe(struct i2c_client *client)
fwnode_handle_put(fwnode);
tps->wakeup = device_property_read_bool(tps->dev, "wakeup-source");
- if (tps->wakeup) {
+ if (tps->wakeup && client->irq) {
device_init_wakeup(&client->dev, true);
enable_irq_wake(client->irq);
}
@@ -887,6 +901,9 @@ static int __maybe_unused tps6598x_suspend(struct device *dev)
enable_irq_wake(client->irq);
}
+ if (!client->irq)
+ cancel_delayed_work_sync(&tps->wq_poll);
+
return 0;
}
@@ -900,6 +917,10 @@ static int __maybe_unused tps6598x_resume(struct device *dev)
enable_irq(client->irq);
}
+ if (client->irq)
+ queue_delayed_work(system_power_efficient_wq, &tps->wq_poll,
+ msecs_to_jiffies(POLL_INTERVAL));
+
return 0;
}
diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig
index 8f9c4b9f31f7..b3bb0191987e 100644
--- a/drivers/usb/typec/ucsi/Kconfig
+++ b/drivers/usb/typec/ucsi/Kconfig
@@ -58,4 +58,14 @@ config UCSI_STM32G0
To compile the driver as a module, choose M here: the module will be
called ucsi_stm32g0.
+config UCSI_PMIC_GLINK
+ tristate "UCSI Qualcomm PMIC GLINK Interface Driver"
+ depends on QCOM_PMIC_GLINK
+ help
+ This driver enables UCSI support on platforms that expose UCSI
+ interface as PMIC GLINK device.
+
+ To compile the driver as a module, choose M here: the module will be
+ called ucsi_glink.
+
endif
diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile
index 480d533d762f..77f09e136956 100644
--- a/drivers/usb/typec/ucsi/Makefile
+++ b/drivers/usb/typec/ucsi/Makefile
@@ -18,3 +18,4 @@ endif
obj-$(CONFIG_UCSI_ACPI) += ucsi_acpi.o
obj-$(CONFIG_UCSI_CCG) += ucsi_ccg.o
obj-$(CONFIG_UCSI_STM32G0) += ucsi_stm32g0.o
+obj-$(CONFIG_UCSI_PMIC_GLINK) += ucsi_glink.o
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index 8d1baf28df55..2b472ec01dc4 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -1444,11 +1444,13 @@ static void ucsi_init_work(struct work_struct *work)
ret = ucsi_init(ucsi);
if (ret)
- dev_err(ucsi->dev, "PPM init failed (%d)\n", ret);
+ dev_err_probe(ucsi->dev, ret, "PPM init failed\n");
if (ret == -EPROBE_DEFER) {
- if (ucsi->work_count++ > UCSI_ROLE_SWITCH_WAIT_COUNT)
+ if (ucsi->work_count++ > UCSI_ROLE_SWITCH_WAIT_COUNT) {
+ dev_err(ucsi->dev, "PPM init failed, stop trying\n");
return;
+ }
queue_delayed_work(system_long_wq, &ucsi->work,
UCSI_ROLE_SWITCH_INTERVAL);
diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c
index 62206a6b8ea7..217355f1f9b9 100644
--- a/drivers/usb/typec/ucsi/ucsi_acpi.c
+++ b/drivers/usb/typec/ucsi/ucsi_acpi.c
@@ -9,6 +9,7 @@
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/acpi.h>
+#include <linux/dmi.h>
#include "ucsi.h"
@@ -23,6 +24,7 @@ struct ucsi_acpi {
struct completion complete;
unsigned long flags;
guid_t guid;
+ u64 cmd;
};
static int ucsi_acpi_dsm(struct ucsi_acpi *ua, int func)
@@ -62,6 +64,7 @@ static int ucsi_acpi_async_write(struct ucsi *ucsi, unsigned int offset,
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
memcpy(ua->base + offset, val, val_len);
+ ua->cmd = *(u64 *)val;
return ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_WRITE);
}
@@ -93,13 +96,46 @@ static const struct ucsi_operations ucsi_acpi_ops = {
.async_write = ucsi_acpi_async_write
};
+static int
+ucsi_zenbook_read(struct ucsi *ucsi, unsigned int offset, void *val, size_t val_len)
+{
+ struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
+ int ret;
+
+ if (offset == UCSI_VERSION || UCSI_COMMAND(ua->cmd) == UCSI_PPM_RESET) {
+ ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ);
+ if (ret)
+ return ret;
+ }
+
+ memcpy(val, ua->base + offset, val_len);
+
+ return 0;
+}
+
+static const struct ucsi_operations ucsi_zenbook_ops = {
+ .read = ucsi_zenbook_read,
+ .sync_write = ucsi_acpi_sync_write,
+ .async_write = ucsi_acpi_async_write
+};
+
+static const struct dmi_system_id zenbook_dmi_id[] = {
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UA_UM325UA"),
+ },
+ },
+ { }
+};
+
static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data)
{
struct ucsi_acpi *ua = data;
u32 cci;
int ret;
- ret = ucsi_acpi_read(ua->ucsi, UCSI_CCI, &cci, sizeof(cci));
+ ret = ua->ucsi->ops->read(ua->ucsi, UCSI_CCI, &cci, sizeof(cci));
if (ret)
return;
@@ -114,6 +150,7 @@ static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data)
static int ucsi_acpi_probe(struct platform_device *pdev)
{
struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
+ const struct ucsi_operations *ops = &ucsi_acpi_ops;
struct ucsi_acpi *ua;
struct resource *res;
acpi_status status;
@@ -143,7 +180,10 @@ static int ucsi_acpi_probe(struct platform_device *pdev)
init_completion(&ua->complete);
ua->dev = &pdev->dev;
- ua->ucsi = ucsi_create(&pdev->dev, &ucsi_acpi_ops);
+ if (dmi_check_system(zenbook_dmi_id))
+ ops = &ucsi_zenbook_ops;
+
+ ua->ucsi = ucsi_create(&pdev->dev, ops);
if (IS_ERR(ua->ucsi))
return PTR_ERR(ua->ucsi);
diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c
new file mode 100644
index 000000000000..b454a5159896
--- /dev/null
+++ b/drivers/usb/typec/ucsi/ucsi_glink.c
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023, Linaro Ltd
+ */
+#include <linux/auxiliary_bus.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/mutex.h>
+#include <linux/property.h>
+#include <linux/soc/qcom/pdr.h>
+#include <linux/soc/qcom/pmic_glink.h>
+#include "ucsi.h"
+
+#define UCSI_BUF_SIZE 48
+
+#define MSG_TYPE_REQ_RESP 1
+#define UCSI_BUF_SIZE 48
+
+#define UC_NOTIFY_RECEIVER_UCSI 0x0
+#define UC_UCSI_READ_BUF_REQ 0x11
+#define UC_UCSI_WRITE_BUF_REQ 0x12
+#define UC_UCSI_USBC_NOTIFY_IND 0x13
+
+struct ucsi_read_buf_req_msg {
+ struct pmic_glink_hdr hdr;
+};
+
+struct ucsi_read_buf_resp_msg {
+ struct pmic_glink_hdr hdr;
+ u8 buf[UCSI_BUF_SIZE];
+ u32 ret_code;
+};
+
+struct ucsi_write_buf_req_msg {
+ struct pmic_glink_hdr hdr;
+ u8 buf[UCSI_BUF_SIZE];
+ u32 reserved;
+};
+
+struct ucsi_write_buf_resp_msg {
+ struct pmic_glink_hdr hdr;
+ u32 ret_code;
+};
+
+struct ucsi_notify_ind_msg {
+ struct pmic_glink_hdr hdr;
+ u32 notification;
+ u32 receiver;
+ u32 reserved;
+};
+
+struct pmic_glink_ucsi {
+ struct device *dev;
+
+ struct pmic_glink_client *client;
+
+ struct ucsi *ucsi;
+ struct completion read_ack;
+ struct completion write_ack;
+ struct completion sync_ack;
+ bool sync_pending;
+ struct mutex lock; /* protects concurrent access to PMIC Glink interface */
+
+ int sync_val;
+
+ struct work_struct notify_work;
+ struct work_struct register_work;
+
+ u8 read_buf[UCSI_BUF_SIZE];
+};
+
+static int pmic_glink_ucsi_read(struct ucsi *__ucsi, unsigned int offset,
+ void *val, size_t val_len)
+{
+ struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi);
+ struct ucsi_read_buf_req_msg req = {};
+ unsigned long left;
+ int ret;
+
+ req.hdr.owner = PMIC_GLINK_OWNER_USBC;
+ req.hdr.type = MSG_TYPE_REQ_RESP;
+ req.hdr.opcode = UC_UCSI_READ_BUF_REQ;
+
+ mutex_lock(&ucsi->lock);
+ memset(ucsi->read_buf, 0, sizeof(ucsi->read_buf));
+ reinit_completion(&ucsi->read_ack);
+
+ ret = pmic_glink_send(ucsi->client, &req, sizeof(req));
+ if (ret < 0) {
+ dev_err(ucsi->dev, "failed to send UCSI read request: %d\n", ret);
+ goto out_unlock;
+ }
+
+ left = wait_for_completion_timeout(&ucsi->read_ack, 5 * HZ);
+ if (!left) {
+ dev_err(ucsi->dev, "timeout waiting for UCSI read response\n");
+ ret = -ETIMEDOUT;
+ goto out_unlock;
+ }
+
+ memcpy(val, &ucsi->read_buf[offset], val_len);
+ ret = 0;
+
+out_unlock:
+ mutex_unlock(&ucsi->lock);
+
+ return ret;
+}
+
+static int pmic_glink_ucsi_locked_write(struct pmic_glink_ucsi *ucsi, unsigned int offset,
+ const void *val, size_t val_len)
+{
+ struct ucsi_write_buf_req_msg req = {};
+ unsigned long left;
+ int ret;
+
+ req.hdr.owner = PMIC_GLINK_OWNER_USBC;
+ req.hdr.type = MSG_TYPE_REQ_RESP;
+ req.hdr.opcode = UC_UCSI_WRITE_BUF_REQ;
+ memcpy(&req.buf[offset], val, val_len);
+
+ reinit_completion(&ucsi->write_ack);
+
+ ret = pmic_glink_send(ucsi->client, &req, sizeof(req));
+ if (ret < 0) {
+ dev_err(ucsi->dev, "failed to send UCSI write request: %d\n", ret);
+ return ret;
+ }
+
+ left = wait_for_completion_timeout(&ucsi->write_ack, 5 * HZ);
+ if (!left) {
+ dev_err(ucsi->dev, "timeout waiting for UCSI write response\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int pmic_glink_ucsi_async_write(struct ucsi *__ucsi, unsigned int offset,
+ const void *val, size_t val_len)
+{
+ struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi);
+ int ret;
+
+ mutex_lock(&ucsi->lock);
+ ret = pmic_glink_ucsi_locked_write(ucsi, offset, val, val_len);
+ mutex_unlock(&ucsi->lock);
+
+ return ret;
+}
+
+static int pmic_glink_ucsi_sync_write(struct ucsi *__ucsi, unsigned int offset,
+ const void *val, size_t val_len)
+{
+ struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi);
+ unsigned long left;
+ int ret;
+
+ /* TOFIX: Downstream forces recipient to CON when UCSI_GET_ALTERNATE_MODES command */
+
+ mutex_lock(&ucsi->lock);
+ ucsi->sync_val = 0;
+ reinit_completion(&ucsi->sync_ack);
+ ucsi->sync_pending = true;
+ ret = pmic_glink_ucsi_locked_write(ucsi, offset, val, val_len);
+ mutex_unlock(&ucsi->lock);
+
+ left = wait_for_completion_timeout(&ucsi->sync_ack, 5 * HZ);
+ if (!left) {
+ dev_err(ucsi->dev, "timeout waiting for UCSI sync write response\n");
+ ret = -ETIMEDOUT;
+ } else if (ucsi->sync_val) {
+ dev_err(ucsi->dev, "sync write returned: %d\n", ucsi->sync_val);
+ }
+
+ ucsi->sync_pending = false;
+
+ return ret;
+}
+
+static const struct ucsi_operations pmic_glink_ucsi_ops = {
+ .read = pmic_glink_ucsi_read,
+ .sync_write = pmic_glink_ucsi_sync_write,
+ .async_write = pmic_glink_ucsi_async_write
+};
+
+static void pmic_glink_ucsi_read_ack(struct pmic_glink_ucsi *ucsi, const void *data, int len)
+{
+ const struct ucsi_read_buf_resp_msg *resp = data;
+
+ if (resp->ret_code)
+ return;
+
+ memcpy(ucsi->read_buf, resp->buf, UCSI_BUF_SIZE);
+ complete(&ucsi->read_ack);
+}
+
+static void pmic_glink_ucsi_write_ack(struct pmic_glink_ucsi *ucsi, const void *data, int len)
+{
+ const struct ucsi_write_buf_resp_msg *resp = data;
+
+ if (resp->ret_code)
+ return;
+
+ ucsi->sync_val = resp->ret_code;
+ complete(&ucsi->write_ack);
+}
+
+static void pmic_glink_ucsi_notify(struct work_struct *work)
+{
+ struct pmic_glink_ucsi *ucsi = container_of(work, struct pmic_glink_ucsi, notify_work);
+ unsigned int con_num;
+ u32 cci;
+ int ret;
+
+ ret = pmic_glink_ucsi_read(ucsi->ucsi, UCSI_CCI, &cci, sizeof(cci));
+ if (ret) {
+ dev_err(ucsi->dev, "failed to read CCI on notification\n");
+ return;
+ }
+
+ con_num = UCSI_CCI_CONNECTOR(cci);
+ if (con_num)
+ ucsi_connector_change(ucsi->ucsi, con_num);
+
+ if (ucsi->sync_pending && cci & UCSI_CCI_BUSY) {
+ ucsi->sync_val = -EBUSY;
+ complete(&ucsi->sync_ack);
+ } else if (ucsi->sync_pending &&
+ (cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE))) {
+ complete(&ucsi->sync_ack);
+ }
+}
+
+static void pmic_glink_ucsi_register(struct work_struct *work)
+{
+ struct pmic_glink_ucsi *ucsi = container_of(work, struct pmic_glink_ucsi, register_work);
+
+ ucsi_register(ucsi->ucsi);
+}
+
+static void pmic_glink_ucsi_callback(const void *data, size_t len, void *priv)
+{
+ struct pmic_glink_ucsi *ucsi = priv;
+ const struct pmic_glink_hdr *hdr = data;
+
+ switch (hdr->opcode) {
+ case UC_UCSI_READ_BUF_REQ:
+ pmic_glink_ucsi_read_ack(ucsi, data, len);
+ break;
+ case UC_UCSI_WRITE_BUF_REQ:
+ pmic_glink_ucsi_write_ack(ucsi, data, len);
+ break;
+ case UC_UCSI_USBC_NOTIFY_IND:
+ schedule_work(&ucsi->notify_work);
+ break;
+ };
+}
+
+static void pmic_glink_ucsi_pdr_notify(void *priv, int state)
+{
+ struct pmic_glink_ucsi *ucsi = priv;
+
+ if (state == SERVREG_SERVICE_STATE_UP)
+ schedule_work(&ucsi->register_work);
+ else if (state == SERVREG_SERVICE_STATE_DOWN)
+ ucsi_unregister(ucsi->ucsi);
+}
+
+static void pmic_glink_ucsi_destroy(void *data)
+{
+ struct pmic_glink_ucsi *ucsi = data;
+
+ /* Protect to make sure we're not in a middle of a transaction from a glink callback */
+ mutex_lock(&ucsi->lock);
+ ucsi_destroy(ucsi->ucsi);
+ mutex_unlock(&ucsi->lock);
+}
+
+static int pmic_glink_ucsi_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
+{
+ struct pmic_glink_ucsi *ucsi;
+ struct device *dev = &adev->dev;
+ int ret;
+
+ ucsi = devm_kzalloc(dev, sizeof(*ucsi), GFP_KERNEL);
+ if (!ucsi)
+ return -ENOMEM;
+
+ ucsi->dev = dev;
+ dev_set_drvdata(dev, ucsi);
+
+ INIT_WORK(&ucsi->notify_work, pmic_glink_ucsi_notify);
+ INIT_WORK(&ucsi->register_work, pmic_glink_ucsi_register);
+ init_completion(&ucsi->read_ack);
+ init_completion(&ucsi->write_ack);
+ init_completion(&ucsi->sync_ack);
+ mutex_init(&ucsi->lock);
+
+ ucsi->ucsi = ucsi_create(dev, &pmic_glink_ucsi_ops);
+ if (IS_ERR(ucsi->ucsi))
+ return PTR_ERR(ucsi->ucsi);
+
+ /* Make sure we destroy *after* pmic_glink unregister */
+ ret = devm_add_action_or_reset(dev, pmic_glink_ucsi_destroy, ucsi);
+ if (ret)
+ return ret;
+
+ ucsi_set_drvdata(ucsi->ucsi, ucsi);
+
+ ucsi->client = devm_pmic_glink_register_client(dev,
+ PMIC_GLINK_OWNER_USBC,
+ pmic_glink_ucsi_callback,
+ pmic_glink_ucsi_pdr_notify,
+ ucsi);
+ return PTR_ERR_OR_ZERO(ucsi->client);
+}
+
+static void pmic_glink_ucsi_remove(struct auxiliary_device *adev)
+{
+ struct pmic_glink_ucsi *ucsi = dev_get_drvdata(&adev->dev);
+
+ /* Unregister first to stop having read & writes */
+ ucsi_unregister(ucsi->ucsi);
+}
+
+static const struct auxiliary_device_id pmic_glink_ucsi_id_table[] = {
+ { .name = "pmic_glink.ucsi", },
+ {},
+};
+MODULE_DEVICE_TABLE(auxiliary, pmic_glink_ucsi_id_table);
+
+static struct auxiliary_driver pmic_glink_ucsi_driver = {
+ .name = "pmic_glink_ucsi",
+ .probe = pmic_glink_ucsi_probe,
+ .remove = pmic_glink_ucsi_remove,
+ .id_table = pmic_glink_ucsi_id_table,
+};
+
+module_auxiliary_driver(pmic_glink_ucsi_driver);
+
+MODULE_DESCRIPTION("Qualcomm PMIC GLINK UCSI driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/platform_data/usb3503.h b/include/linux/platform_data/usb3503.h
index d01ef97ddf36..f3c942f396f8 100644
--- a/include/linux/platform_data/usb3503.h
+++ b/include/linux/platform_data/usb3503.h
@@ -12,6 +12,7 @@ enum usb3503_mode {
USB3503_MODE_UNKNOWN,
USB3503_MODE_HUB,
USB3503_MODE_STANDBY,
+ USB3503_MODE_BYPASS,
};
struct usb3503_platform_data {
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 0a81e0f5beb4..25f8e62a30ec 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -303,6 +303,11 @@ void usb_put_intf(struct usb_interface *intf);
#define USB_MAXINTERFACES 32
#define USB_MAXIADS (USB_MAXINTERFACES/2)
+bool usb_check_bulk_endpoints(
+ const struct usb_interface *intf, const u8 *ep_addrs);
+bool usb_check_int_endpoints(
+ const struct usb_interface *intf, const u8 *ep_addrs);
+
/*
* USB Resume Timer: Every Host controller driver should drive the resume
* signalling on the bus for the amount of time defined by this macro.
@@ -716,13 +721,12 @@ struct usb_device {
unsigned long active_duration;
-#ifdef CONFIG_PM
unsigned long connect_time;
unsigned do_remote_wakeup:1;
unsigned reset_resume:1;
unsigned port_is_suspended:1;
-#endif
+
struct wusb_dev *wusb_dev;
int slot_id;
struct usb2_lpm_parameters l1_params;
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 608dc962748b..a2448e98854f 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -150,6 +150,9 @@ struct usb_os_desc_table {
* GetStatus() request when the recipient is Interface.
* @func_suspend: callback to be called when
* SetFeature(FUNCTION_SUSPEND) is reseived
+ * @func_suspended: Indicates whether the function is in function suspend state.
+ * @func_wakeup_armed: Indicates whether the function is armed by the host for
+ * wakeup signaling.
*
* A single USB function uses one or more interfaces, and should in most
* cases support operation at both full and high speeds. Each function is
@@ -220,6 +223,8 @@ struct usb_function {
int (*get_status)(struct usb_function *);
int (*func_suspend)(struct usb_function *,
u8 suspend_opt);
+ bool func_suspended;
+ bool func_wakeup_armed;
/* private: */
/* internals */
struct list_head list;
@@ -241,6 +246,7 @@ int config_ep_by_speed_and_alt(struct usb_gadget *g, struct usb_function *f,
int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f,
struct usb_ep *_ep);
+int usb_func_wakeup(struct usb_function *func);
#define MAX_CONFIG_INTERFACES 16 /* arbitrary; max 255 */
@@ -413,6 +419,8 @@ extern int composite_dev_prepare(struct usb_composite_driver *composite,
extern int composite_os_desc_req_prepare(struct usb_composite_dev *cdev,
struct usb_ep *ep0);
void composite_dev_cleanup(struct usb_composite_dev *cdev);
+void check_remote_wakeup_config(struct usb_gadget *g,
+ struct usb_configuration *c);
static inline struct usb_composite_driver *to_cdriver(
struct usb_gadget_driver *gdrv)
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 00750f7020f3..75bda0783395 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -310,6 +310,8 @@ struct usb_udc;
struct usb_gadget_ops {
int (*get_frame)(struct usb_gadget *);
int (*wakeup)(struct usb_gadget *);
+ int (*func_wakeup)(struct usb_gadget *gadget, int intf_id);
+ int (*set_remote_wakeup)(struct usb_gadget *, int set);
int (*set_selfpowered) (struct usb_gadget *, int is_selfpowered);
int (*vbus_session) (struct usb_gadget *, int is_active);
int (*vbus_draw) (struct usb_gadget *, unsigned mA);
@@ -384,6 +386,8 @@ struct usb_gadget_ops {
* @connected: True if gadget is connected.
* @lpm_capable: If the gadget max_speed is FULL or HIGH, this flag
* indicates that it supports LPM as per the LPM ECN & errata.
+ * @wakeup_capable: True if gadget is capable of sending remote wakeup.
+ * @wakeup_armed: True if gadget is armed by the host for remote wakeup.
* @irq: the interrupt number for device controller.
* @id_number: a unique ID number for ensuring that gadget names are distinct
*
@@ -445,6 +449,8 @@ struct usb_gadget {
unsigned deactivated:1;
unsigned connected:1;
unsigned lpm_capable:1;
+ unsigned wakeup_capable:1;
+ unsigned wakeup_armed:1;
int irq;
int id_number;
};
@@ -601,6 +607,7 @@ static inline int gadget_is_otg(struct usb_gadget *g)
#if IS_ENABLED(CONFIG_USB_GADGET)
int usb_gadget_frame_number(struct usb_gadget *gadget);
int usb_gadget_wakeup(struct usb_gadget *gadget);
+int usb_gadget_set_remote_wakeup(struct usb_gadget *gadget, int set);
int usb_gadget_set_selfpowered(struct usb_gadget *gadget);
int usb_gadget_clear_selfpowered(struct usb_gadget *gadget);
int usb_gadget_vbus_connect(struct usb_gadget *gadget);
@@ -616,6 +623,8 @@ static inline int usb_gadget_frame_number(struct usb_gadget *gadget)
{ return 0; }
static inline int usb_gadget_wakeup(struct usb_gadget *gadget)
{ return 0; }
+static inline int usb_gadget_set_remote_wakeup(struct usb_gadget *gadget, int set)
+{ return 0; }
static inline int usb_gadget_set_selfpowered(struct usb_gadget *gadget)
{ return 0; }
static inline int usb_gadget_clear_selfpowered(struct usb_gadget *gadget)
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index b51c07111729..094c77eaf455 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -488,9 +488,7 @@ extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
extern int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev);
-#ifdef CONFIG_PM
extern const struct dev_pm_ops usb_hcd_pci_pm_ops;
-#endif
#endif /* CONFIG_USB_PCI */
/* pci-ish (pdev null is ok) buffer alloc/mapping support */