summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-bus-usb11
-rw-r--r--Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml3
-rw-r--r--Documentation/devicetree/bindings/usb/dwc2.yaml3
-rw-r--r--Documentation/devicetree/bindings/usb/usb-drd.yaml1
-rw-r--r--Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml5
-rw-r--r--Documentation/devicetree/bindings/usb/usb251xb.txt89
-rw-r--r--Documentation/devicetree/bindings/usb/usb251xb.yaml271
-rw-r--r--Documentation/driver-api/driver-model/devres.rst2
-rw-r--r--MAINTAINERS6
-rw-r--r--drivers/usb/Kconfig4
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/cdns3/cdnsp-pci.c8
-rw-r--r--drivers/usb/chipidea/ci.h4
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c51
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.h4
-rw-r--r--drivers/usb/chipidea/core.c143
-rw-r--r--drivers/usb/chipidea/host.c16
-rw-r--r--drivers/usb/chipidea/otg.c2
-rw-r--r--drivers/usb/chipidea/otg.h1
-rw-r--r--drivers/usb/chipidea/udc.c32
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c160
-rw-r--r--drivers/usb/core/config.c82
-rw-r--r--drivers/usb/core/hub.c60
-rw-r--r--drivers/usb/core/hub.h4
-rw-r--r--drivers/usb/core/port.c30
-rw-r--r--drivers/usb/core/sysfs.c7
-rw-r--r--drivers/usb/dwc2/platform.c2
-rw-r--r--drivers/usb/dwc3/gadget.c14
-rw-r--r--drivers/usb/fotg210/Kconfig37
-rw-r--r--drivers/usb/fotg210/Makefile10
-rw-r--r--drivers/usb/fotg210/fotg210-core.c166
-rw-r--r--drivers/usb/fotg210/fotg210-hcd.c (renamed from drivers/usb/host/fotg210-hcd.c)51
-rw-r--r--drivers/usb/fotg210/fotg210-hcd.h (renamed from drivers/usb/host/fotg210.h)0
-rw-r--r--drivers/usb/fotg210/fotg210-udc.c (renamed from drivers/usb/gadget/udc/fotg210-udc.c)31
-rw-r--r--drivers/usb/fotg210/fotg210-udc.h (renamed from drivers/usb/gadget/udc/fotg210.h)0
-rw-r--r--drivers/usb/fotg210/fotg210.h42
-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_mass_storage.c3
-rw-r--r--drivers/usb/gadget/function/f_uvc.c15
-rw-r--r--drivers/usb/gadget/function/storage_common.c9
-rw-r--r--drivers/usb/gadget/function/u_ether.c4
-rw-r--r--drivers/usb/gadget/function/u_serial.c3
-rw-r--r--drivers/usb/gadget/legacy/serial.c3
-rw-r--r--drivers/usb/gadget/udc/Kconfig11
-rw-r--r--drivers/usb/gadget/udc/Makefile1
-rw-r--r--drivers/usb/gadget/udc/aspeed-vhub/core.c2
-rw-r--r--drivers/usb/gadget/udc/aspeed-vhub/epn.c16
-rw-r--r--drivers/usb/gadget/udc/at91_udc.c5
-rw-r--r--drivers/usb/host/Kconfig13
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-grlib.c2
-rw-r--r--drivers/usb/host/ehci-pci.c7
-rw-r--r--drivers/usb/host/ehci-ppc-of.c2
-rw-r--r--drivers/usb/host/fhci-hcd.c2
-rw-r--r--drivers/usb/host/ohci-ppc-of.c2
-rw-r--r--drivers/usb/host/uhci-grlib.c2
-rw-r--r--drivers/usb/host/xhci-pci.c7
-rw-r--r--drivers/usb/misc/ftdi-elan.c2
-rw-r--r--drivers/usb/musb/Kconfig13
-rw-r--r--drivers/usb/musb/Makefile2
-rw-r--r--drivers/usb/musb/cppi_dma.c1547
-rw-r--r--drivers/usb/musb/davinci.c606
-rw-r--r--drivers/usb/musb/davinci.h103
-rw-r--r--drivers/usb/musb/jz4740.c62
-rw-r--r--drivers/usb/musb/musb_core.c107
-rw-r--r--drivers/usb/musb/musb_core.h24
-rw-r--r--drivers/usb/musb/musb_debugfs.c6
-rw-r--r--drivers/usb/musb/musb_dma.h13
-rw-r--r--drivers/usb/musb/musb_gadget.c61
-rw-r--r--drivers/usb/musb/musb_host.c18
-rw-r--r--drivers/usb/musb/musb_virthub.c33
-rw-r--r--drivers/usb/phy/Kconfig14
-rw-r--r--drivers/usb/phy/Makefile1
-rw-r--r--drivers/usb/phy/phy-generic.c18
-rw-r--r--drivers/usb/phy/phy-gpio-vbus-usb.c12
-rw-r--r--drivers/usb/phy/phy-jz4770.c353
-rw-r--r--drivers/usb/typec/retimer.c16
-rw-r--r--drivers/usb/typec/retimer.h4
-rw-r--r--drivers/usb/usbip/stub_dev.c4
-rw-r--r--drivers/usb/usbip/vudc_rx.c4
-rw-r--r--drivers/usb/usbip/vudc_sysfs.c2
-rw-r--r--include/uapi/linux/usb/g_uvc.h3
-rw-r--r--tools/usb/ffs-aio-example/simple/device_app/aio_simple.c44
84 files changed, 1358 insertions, 3203 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb
index 568103d3376e..545c2dd97ed0 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -264,6 +264,17 @@ Description:
attached to the port will not be detected, initialized,
or enumerated.
+What: /sys/bus/usb/devices/.../<hub_interface>/port<X>/early_stop
+Date: Sep 2022
+Contact: Ray Chi <raychi@google.com>
+Description:
+ Some USB hosts have some watchdog mechanisms so that the device
+ may enter ramdump if it takes a long time during port initialization.
+ This attribute allows each port just has two attempts so that the
+ port initialization will be failed quickly. In addition, if a port
+ which is marked with early_stop has failed to initialize, it will ignore
+ all future connections until this attribute is clear.
+
What: /sys/bus/usb/devices/.../power/usb2_lpm_l1_timeout
Date: May 2013
Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
diff --git a/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml b/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml
index 2936f3510a6a..5ba9570ad7bf 100644
--- a/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml
@@ -28,6 +28,9 @@ properties:
items:
- const: phy
+ power-domains:
+ maxItems: 1
+
vbus-supply:
description:
A phandle to the regulator for USB VBUS.
diff --git a/Documentation/devicetree/bindings/usb/dwc2.yaml b/Documentation/devicetree/bindings/usb/dwc2.yaml
index dc4988c0009c..1ab85489a3f8 100644
--- a/Documentation/devicetree/bindings/usb/dwc2.yaml
+++ b/Documentation/devicetree/bindings/usb/dwc2.yaml
@@ -43,7 +43,10 @@ properties:
- const: rockchip,rk3066-usb
- const: snps,dwc2
- const: lantiq,arx100-usb
+ - const: lantiq,ase-usb
+ - const: lantiq,danube-usb
- const: lantiq,xrx200-usb
+ - const: lantiq,xrx300-usb
- items:
- enum:
- amlogic,meson8-usb
diff --git a/Documentation/devicetree/bindings/usb/usb-drd.yaml b/Documentation/devicetree/bindings/usb/usb-drd.yaml
index 1567549b05ce..114fb5dc0498 100644
--- a/Documentation/devicetree/bindings/usb/usb-drd.yaml
+++ b/Documentation/devicetree/bindings/usb/usb-drd.yaml
@@ -27,6 +27,7 @@ properties:
should default to OTG.
$ref: /schemas/types.yaml#/definitions/string
enum: [host, peripheral, otg]
+ default: otg
hnp-disable:
description:
diff --git a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml
index 2824c17285ee..326131dcf14d 100644
--- a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml
+++ b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml
@@ -39,6 +39,11 @@ properties:
the VBus line.
$ref: /schemas/types.yaml#/definitions/phandle
+ wakeup-source:
+ description:
+ Specify if the USB phy can detect the remote wakeup signal
+ while the system sleep.
+
required:
- compatible
- '#phy-cells'
diff --git a/Documentation/devicetree/bindings/usb/usb251xb.txt b/Documentation/devicetree/bindings/usb/usb251xb.txt
deleted file mode 100644
index 1a934eab175e..000000000000
--- a/Documentation/devicetree/bindings/usb/usb251xb.txt
+++ /dev/null
@@ -1,89 +0,0 @@
-Microchip USB 2.0 Hi-Speed Hub Controller
-
-The device node for the configuration of a Microchip USB251x/xBi USB 2.0
-Hi-Speed Controller.
-
-Required properties :
- - compatible : Should be "microchip,usb251xb" or one of the specific types:
- "microchip,usb2512b", "microchip,usb2512bi", "microchip,usb2513b",
- "microchip,usb2513bi", "microchip,usb2514b", "microchip,usb2514bi",
- "microchip,usb2517", "microchip,usb2517i", "microchip,usb2422"
- - reg : I2C address on the selected bus (default is <0x2C>)
-
-Optional properties :
- - reset-gpios : Should specify the gpio for hub reset
- - vdd-supply : Should specify the phandle to the regulator supplying vdd
- - skip-config : Skip Hub configuration, but only send the USB-Attach command
- - vendor-id : Set USB Vendor ID of the hub (16 bit, default is 0x0424)
- - product-id : Set USB Product ID of the hub (16 bit, default depends on type)
- - device-id : Set USB Device ID of the hub (16 bit, default is 0x0bb3)
- - language-id : Set USB Language ID (16 bit, default is 0x0000)
- - manufacturer : Set USB Manufacturer string (max 31 characters long)
- - product : Set USB Product string (max 31 characters long)
- - serial : Set USB Serial string (max 31 characters long)
- - {bus,self}-powered : selects between self- and bus-powered operation
- (boolean, default is self-powered)
- - disable-hi-speed : disable USB Hi-Speed support (boolean)
- - {multi,single}-tt : selects between multi- and single-transaction-translator
- (boolean, default is multi-tt)
- - disable-eop : disable End of Packet generation in full-speed mode (boolean)
- - {ganged,individual}-sensing : select over-current sense type in self-powered
- mode (boolean, default is individual)
- - {ganged,individual}-port-switching : select port power switching mode
- (boolean, default is individual)
- - dynamic-power-switching : enable auto-switching from self- to bus-powered
- operation if the local power source is removed or unavailable (boolean)
- - oc-delay-us : Delay time (in microseconds) for filtering the over-current
- sense inputs. Valid values are 100, 4000, 8000 (default) and 16000. If
- an invalid value is given, the default is used instead.
- - compound-device : indicate the hub is part of a compound device (boolean)
- - port-mapping-mode : enable port mapping mode (boolean)
- - led-{usb,speed}-mode : led usb/speed indication mode selection
- (boolean, default is speed mode)
- - string-support : enable string descriptor support (required for manufacturer,
- product and serial string configuration)
- - non-removable-ports : Should specify the ports which have a non-removable
- device connected.
- - sp-disabled-ports : Specifies the ports which will be self-power disabled
- - bp-disabled-ports : Specifies the ports which will be bus-power disabled
- - sp-max-total-current-microamp: Specifies max current consumed by the hub
- from VBUS when operating in self-powered hub. It includes the hub
- silicon along with all associated circuitry including a permanently
- attached peripheral (range: 0 - 100000 uA, default 1000 uA)
- - bp-max-total-current-microamp: Specifies max current consumed by the hub
- from VBUS when operating in self-powered hub. It includes the hub
- silicon along with all associated circuitry including a permanently
- attached peripheral (range: 0 - 510000 uA, default 100000 uA)
- - sp-max-removable-current-microamp: Specifies max current consumed by the hub
- from VBUS when operating in self-powered hub. It includes the hub
- silicon along with all associated circuitry excluding a permanently
- attached peripheral (range: 0 - 100000 uA, default 1000 uA)
- - bp-max-removable-current-microamp: Specifies max current consumed by the hub
- from VBUS when operating in self-powered hub. It includes the hub
- silicon along with all associated circuitry excluding a permanently
- attached peripheral (range: 0 - 510000 uA, default 100000 uA)
- - power-on-time-ms : Specifies the time it takes from the time the host
- initiates the power-on sequence to a port until the port has adequate
- power. The value is given in ms in a 0 - 510 range (default is 100ms).
- - swap-dx-lanes : Specifies the ports which will swap the differential-pair
- (D+/D-), default is not-swapped.
-
-Examples:
- usb2512b@2c {
- compatible = "microchip,usb2512b";
- reg = <0x2c>;
- reset-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
- };
-
- usb2514b@2c {
- compatible = "microchip,usb2514b";
- reg = <0x2c>;
- vendor-id = /bits/ 16 <0x0000>;
- product-id = /bits/ 16 <0x0000>;
- string-support;
- manufacturer = "Foo";
- product = "Foo-Bar";
- serial = "1234567890A";
- /* correct misplaced usb connectors on port 1,2 */
- swap-dx-lanes = <1 2>;
- };
diff --git a/Documentation/devicetree/bindings/usb/usb251xb.yaml b/Documentation/devicetree/bindings/usb/usb251xb.yaml
new file mode 100644
index 000000000000..4d1530816817
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/usb251xb.yaml
@@ -0,0 +1,271 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/usb251xb.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip USB 2.0 Hi-Speed Hub Controller
+
+maintainers:
+ - Richard Leitner <richard.leitner@skidata.com>
+
+properties:
+ compatible:
+ enum:
+ - microchip,usb2422
+ - microchip,usb2512b
+ - microchip,usb2512bi
+ - microchip,usb2513b
+ - microchip,usb2513bi
+ - microchip,usb2514b
+ - microchip,usb2514bi
+ - microchip,usb2517
+ - microchip,usb2517i
+ - microchip,usb251xb
+
+ reg:
+ maxItems: 1
+
+ reset-gpios:
+ description: |
+ Should specify the gpio for hub reset
+
+ vdd-supply:
+ description: |
+ Should specify the phandle to the regulator supplying vdd
+
+ skip-config:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ Skip Hub configuration, but only send the USB-Attach command
+
+ vendor-id:
+ $ref: /schemas/types.yaml#/definitions/uint16
+ default: 0x0424
+ description: |
+ Set USB Vendor ID of the hub
+
+ product-id:
+ $ref: /schemas/types.yaml#/definitions/uint16
+ description: |
+ Set USB Product ID of the hub
+
+ device-id:
+ $ref: /schemas/types.yaml#/definitions/uint16
+ default: 0x0bb3
+ description: |
+ Set USB Device ID of the hub
+
+ language-id:
+ $ref: /schemas/types.yaml#/definitions/uint16
+ default: 0x0000
+ description: |
+ Set USB Language ID
+
+ manufacturer:
+ $ref: /schemas/types.yaml#/definitions/string
+ description: |
+ Set USB Manufacturer string (max 31 characters long)
+
+ product:
+ $ref: /schemas/types.yaml#/definitions/string
+ description: |
+ Set USB Product string (max 31 characters long)
+
+ serial:
+ $ref: /schemas/types.yaml#/definitions/string
+ description: |
+ Set USB Serial string (max 31 characters long)
+
+ bus-powered:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ selects between self- and bus-powered operation
+ (boolean, default is self-powered)
+
+ self-powered:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ selects between self- and bus-powered operation
+ (boolean, default is self-powered)
+
+ disable-hi-speed:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ disable USB Hi-Speed support (boolean)
+
+ multi-tt:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ selects between multi- and single-transaction-translator
+ (boolean, default is multi-tt)
+
+ single-tt:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ selects between multi- and single-transaction-translator
+ (boolean, default is multi-tt)
+
+ disable-eop:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ disable End of Packet generation in full-speed mode (boolean)
+
+ ganged-sensing:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ select over-current sense type in self-powered mode
+ (boolean, default is individual)
+
+ individual-sensing:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ select over-current sense type in self-powered mode
+ (boolean, default is individual)
+
+ ganged-port-switching:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ select port power switching mode (boolean, default is individual)
+
+ individual-port-switching:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ select port power switching mode (boolean, default is individual)
+
+ dynamic-power-switching:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ enable auto-switching from self- to bus-powered operation if the
+ local power source is removed or unavailable (boolean)
+
+ oc-delay-us:
+ enum: [100, 4000, 8000, 16000]
+ default: 8000
+ description: |
+ Delay time (in microseconds) for filtering the over-current sense
+ inputs. If an invalid value is given, the default is used instead.
+
+ compound-device:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ indicate the hub is part of a compound device (boolean)
+
+ port-mapping-mode:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ enable port mapping mode (boolean)
+
+ led-usb-mode:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ led usb/speed indication mode selection (boolean, default is speed mode)
+
+ led-speed-mode:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ led usb/speed indication mode selection (boolean, default is speed mode)
+
+ string-support:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ enable string descriptor support (required for manufacturer, product
+ and serial string configuration)
+
+ non-removable-ports:
+ $ref: /schemas/types.yaml#/definitions/uint8-array
+ description: |
+ Should specify the ports which have a non-removable device connected.
+
+ sp-disabled-ports:
+ $ref: /schemas/types.yaml#/definitions/uint8-array
+ description: |
+ Specifies the ports which will be self-power disabled
+
+ bp-disabled-ports:
+ $ref: /schemas/types.yaml#/definitions/uint8-array
+ description: |
+ Specifies the ports which will be bus-power disabled
+
+ sp-max-total-current-microamp:
+ maximum: 100000
+ default: 1000
+ description: |
+ Specifies max current consumed by the hub from VBUS when
+ operating in self-powered hub. It includes the hub silicon
+ along with all associated circuitry including a permanently
+ attached peripheral.
+
+ bp-max-total-current-microamp:
+ maximum: 510000
+ default: 100000
+ description: |
+ Specifies max current consumed by the hub from VBUS when
+ operating in self-powered hub. It includes the hub silicon
+ along with all associated circuitry including a permanently
+ attached peripheral.
+
+ sp-max-removable-current-microamp:
+ maximum: 100000
+ default: 1000
+ description: |
+ Specifies max current consumed by the hub from VBUS when
+ operating in self-powered hub. It includes the hub silicon
+ along with all associated circuitry excluding a permanently
+ attached peripheral.
+
+ bp-max-removable-current-microamp:
+ maximum: 510000
+ default: 100000
+ description: |
+ Specifies max current consumed by the hub from VBUS when
+ operating in self-powered hub. It includes the hub silicon
+ along with all associated circuitry excluding a permanently
+ attached peripheral.
+
+ power-on-time-ms:
+ maximum: 510
+ default: 100
+ description: |
+ Specifies the time it takes from the time the host initiates the
+ power-on sequence to a port until the port has adequate power.
+
+ swap-dx-lanes:
+ $ref: /schemas/types.yaml#/definitions/uint8-array
+ description: |
+ Specifies the ports which will swap the differential-pair (D+/D-),
+ default is not-swapped.
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ usb-hub@2c {
+ compatible = "microchip,usb2512b";
+ reg = <0x2c>;
+ reset-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+ };
+
+ usb-hub@2d {
+ compatible = "microchip,usb2514b";
+ reg = <0x2d>;
+ vendor-id = /bits/ 16 <0x0000>;
+ product-id = /bits/ 16 <0x0000>;
+ string-support;
+ manufacturer = "Foo";
+ product = "Foo-Bar";
+ serial = "1234567890A";
+ /* correct misplaced usb connectors on port 1,2 */
+ swap-dx-lanes = <1 2>;
+ };
+ };
diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst
index 56082265e8e5..060db79a740e 100644
--- a/Documentation/driver-api/driver-model/devres.rst
+++ b/Documentation/driver-api/driver-model/devres.rst
@@ -388,6 +388,8 @@ PCI
PHY
devm_usb_get_phy()
+ devm_usb_get_phy_by_node()
+ devm_usb_get_phy_by_phandle()
devm_usb_put_phy()
PINCTRL
diff --git a/MAINTAINERS b/MAINTAINERS
index 2585e7edc335..2a8c456c184e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7873,6 +7873,12 @@ F: fs/notify/fanotify/
F: include/linux/fanotify.h
F: include/uapi/linux/fanotify.h
+FARADAY FOTG210 USB2 DUAL-ROLE CONTROLLER
+M: Linus Walleij <linus.walleij@linaro.org>
+L: linux-usb@vger.kernel.org
+S: Maintained
+F: drivers/usb/fotg210/
+
FARSYNC SYNCHRONOUS DRIVER
M: Kevin Curtis <kevin.curtis@farsite.co.uk>
S: Supported
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 578a439e71b5..a871a988829d 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -111,8 +111,12 @@ source "drivers/usb/usbip/Kconfig"
endif
+comment "USB dual-mode controller drivers"
+
source "drivers/usb/cdns3/Kconfig"
+source "drivers/usb/fotg210/Kconfig"
+
source "drivers/usb/mtu3/Kconfig"
source "drivers/usb/musb/Kconfig"
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 643edf5fe18c..a81e6ef293af 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -17,6 +17,8 @@ obj-$(CONFIG_USB_CDNS_SUPPORT) += cdns3/
obj-$(CONFIG_USB_CDNS3) += cdns3/
obj-$(CONFIG_USB_CDNSP_PCI) += cdns3/
+obj-$(CONFIG_USB_FOTG210) += fotg210/
+
obj-$(CONFIG_USB_MON) += mon/
obj-$(CONFIG_USB_MTU3) += mtu3/
diff --git a/drivers/usb/cdns3/cdnsp-pci.c b/drivers/usb/cdns3/cdnsp-pci.c
index fe8a114c586c..efd54ed918b9 100644
--- a/drivers/usb/cdns3/cdnsp-pci.c
+++ b/drivers/usb/cdns3/cdnsp-pci.c
@@ -192,14 +192,12 @@ static void cdnsp_pci_remove(struct pci_dev *pdev)
if (pci_dev_run_wake(pdev))
pm_runtime_get_noresume(&pdev->dev);
- if (!pci_is_enabled(func)) {
+ if (pci_is_enabled(func)) {
+ cdns_remove(cdnsp);
+ } else {
kfree(cdnsp);
- goto pci_put;
}
- cdns_remove(cdnsp);
-
-pci_put:
pci_dev_put(func);
}
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index a4a3be049910..005c67cb3afb 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -127,12 +127,16 @@ enum ci_revision {
* struct ci_role_driver - host/gadget role driver
* @start: start this role
* @stop: stop this role
+ * @suspend: system suspend handler for this role
+ * @resume: system resume handler for this role
* @irq: irq handler for this role
* @name: role name string (host/gadget)
*/
struct ci_role_driver {
int (*start)(struct ci_hdrc *);
void (*stop)(struct ci_hdrc *);
+ void (*suspend)(struct ci_hdrc *ci);
+ void (*resume)(struct ci_hdrc *ci, bool power_lost);
irqreturn_t (*irq)(struct ci_hdrc *);
const char *name;
};
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index 9ffcecd3058c..0dc482542d85 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -355,7 +355,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
data->hsic_pad_regulator =
devm_regulator_get_optional(dev, "hsic");
if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) {
- /* no pad regualator is needed */
+ /* no pad regulator is needed */
data->hsic_pad_regulator = NULL;
} else if (IS_ERR(data->hsic_pad_regulator))
return dev_err_probe(dev, PTR_ERR(data->hsic_pad_regulator),
@@ -527,16 +527,19 @@ static void ci_hdrc_imx_shutdown(struct platform_device *pdev)
ci_hdrc_imx_remove(pdev);
}
-static int __maybe_unused imx_controller_suspend(struct device *dev)
+static int __maybe_unused imx_controller_suspend(struct device *dev,
+ pm_message_t msg)
{
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
int ret = 0;
dev_dbg(dev, "at %s\n", __func__);
- ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, false);
+ ret = imx_usbmisc_suspend(data->usbmisc_data,
+ PMSG_IS_AUTO(msg) || device_may_wakeup(dev));
if (ret) {
- dev_err(dev, "usbmisc hsic_set_clk failed, ret=%d\n", ret);
+ dev_err(dev,
+ "usbmisc suspend failed, ret=%d\n", ret);
return ret;
}
@@ -549,7 +552,8 @@ static int __maybe_unused imx_controller_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused imx_controller_resume(struct device *dev)
+static int __maybe_unused imx_controller_resume(struct device *dev,
+ pm_message_t msg)
{
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
int ret = 0;
@@ -570,22 +574,15 @@ static int __maybe_unused imx_controller_resume(struct device *dev)
data->in_lpm = false;
- ret = imx_usbmisc_set_wakeup(data->usbmisc_data, false);
+ ret = imx_usbmisc_resume(data->usbmisc_data,
+ PMSG_IS_AUTO(msg) || device_may_wakeup(dev));
if (ret) {
- dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret);
+ dev_err(dev, "usbmisc resume failed, ret=%d\n", ret);
goto clk_disable;
}
- ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, true);
- if (ret) {
- dev_err(dev, "usbmisc hsic_set_clk failed, ret=%d\n", ret);
- goto hsic_set_clk_fail;
- }
-
return 0;
-hsic_set_clk_fail:
- imx_usbmisc_set_wakeup(data->usbmisc_data, true);
clk_disable:
imx_disable_unprepare_clks(dev);
return ret;
@@ -601,16 +598,7 @@ static int __maybe_unused ci_hdrc_imx_suspend(struct device *dev)
/* The core's suspend doesn't run */
return 0;
- if (device_may_wakeup(dev)) {
- ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true);
- if (ret) {
- dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n",
- ret);
- return ret;
- }
- }
-
- ret = imx_controller_suspend(dev);
+ ret = imx_controller_suspend(dev, PMSG_SUSPEND);
if (ret)
return ret;
@@ -624,7 +612,7 @@ static int __maybe_unused ci_hdrc_imx_resume(struct device *dev)
int ret;
pinctrl_pm_select_default_state(dev);
- ret = imx_controller_resume(dev);
+ ret = imx_controller_resume(dev, PMSG_RESUME);
if (!ret && data->supports_runtime_pm) {
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
@@ -637,25 +625,18 @@ static int __maybe_unused ci_hdrc_imx_resume(struct device *dev)
static int __maybe_unused ci_hdrc_imx_runtime_suspend(struct device *dev)
{
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
- int ret;
if (data->in_lpm) {
WARN_ON(1);
return 0;
}
- ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true);
- if (ret) {
- dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret);
- return ret;
- }
-
- return imx_controller_suspend(dev);
+ return imx_controller_suspend(dev, PMSG_AUTO_SUSPEND);
}
static int __maybe_unused ci_hdrc_imx_runtime_resume(struct device *dev)
{
- return imx_controller_resume(dev);
+ return imx_controller_resume(dev, PMSG_AUTO_RESUME);
}
static const struct dev_pm_ops ci_hdrc_imx_pm_ops = {
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.h b/drivers/usb/chipidea/ci_hdrc_imx.h
index 7daccb9c5006..7135b9a5d913 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.h
+++ b/drivers/usb/chipidea/ci_hdrc_imx.h
@@ -32,9 +32,9 @@ struct imx_usbmisc_data {
int imx_usbmisc_init(struct imx_usbmisc_data *data);
int imx_usbmisc_init_post(struct imx_usbmisc_data *data);
-int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *data, bool enabled);
int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data);
-int imx_usbmisc_hsic_set_clk(struct imx_usbmisc_data *data, bool on);
int imx_usbmisc_charger_detection(struct imx_usbmisc_data *data, bool connect);
+int imx_usbmisc_suspend(struct imx_usbmisc_data *data, bool wakeup);
+int imx_usbmisc_resume(struct imx_usbmisc_data *data, bool wakeup);
#endif /* __DRIVER_USB_CHIPIDEA_CI_HDRC_IMX_H */
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 6330fa911792..484b1cd23431 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -608,52 +608,59 @@ static int ci_usb_role_switch_set(struct usb_role_switch *sw,
enum usb_role role)
{
struct ci_hdrc *ci = usb_role_switch_get_drvdata(sw);
- struct ci_hdrc_cable *cable = NULL;
- enum usb_role current_role = ci_role_to_usb_role(ci);
- enum ci_role ci_role = usb_role_to_ci_role(role);
- unsigned long flags;
-
- if ((ci_role != CI_ROLE_END && !ci->roles[ci_role]) ||
- (current_role == role))
- return 0;
+ struct ci_hdrc_cable *cable;
- pm_runtime_get_sync(ci->dev);
- /* Stop current role */
- spin_lock_irqsave(&ci->lock, flags);
- if (current_role == USB_ROLE_DEVICE)
+ if (role == USB_ROLE_HOST) {
+ cable = &ci->platdata->id_extcon;
+ cable->changed = true;
+ cable->connected = true;
cable = &ci->platdata->vbus_extcon;
- else if (current_role == USB_ROLE_HOST)
+ cable->changed = true;
+ cable->connected = false;
+ } else if (role == USB_ROLE_DEVICE) {
cable = &ci->platdata->id_extcon;
-
- if (cable) {
cable->changed = true;
cable->connected = false;
- ci_irq(ci);
- spin_unlock_irqrestore(&ci->lock, flags);
- if (ci->wq && role != USB_ROLE_NONE)
- flush_workqueue(ci->wq);
- spin_lock_irqsave(&ci->lock, flags);
- }
-
- cable = NULL;
-
- /* Start target role */
- if (role == USB_ROLE_DEVICE)
cable = &ci->platdata->vbus_extcon;
- else if (role == USB_ROLE_HOST)
- cable = &ci->platdata->id_extcon;
-
- if (cable) {
cable->changed = true;
cable->connected = true;
- ci_irq(ci);
+ } else {
+ cable = &ci->platdata->id_extcon;
+ cable->changed = true;
+ cable->connected = false;
+ cable = &ci->platdata->vbus_extcon;
+ cable->changed = true;
+ cable->connected = false;
}
- spin_unlock_irqrestore(&ci->lock, flags);
- pm_runtime_put_sync(ci->dev);
+ ci_irq(ci);
return 0;
}
+static enum ci_role ci_get_role(struct ci_hdrc *ci)
+{
+ enum ci_role role;
+
+ if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) {
+ if (ci->is_otg) {
+ role = ci_otg_role(ci);
+ hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE);
+ } else {
+ /*
+ * If the controller is not OTG capable, but support
+ * role switch, the defalt role is gadget, and the
+ * user can switch it through debugfs.
+ */
+ role = CI_ROLE_GADGET;
+ }
+ } else {
+ role = ci->roles[CI_ROLE_HOST] ? CI_ROLE_HOST
+ : CI_ROLE_GADGET;
+ }
+
+ return role;
+}
+
static struct usb_role_switch_desc ci_role_switch = {
.set = ci_usb_role_switch_set,
.get = ci_usb_role_switch_get,
@@ -1151,25 +1158,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
}
}
- if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) {
- if (ci->is_otg) {
- ci->role = ci_otg_role(ci);
- /* Enable ID change irq */
- hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE);
- } else {
- /*
- * If the controller is not OTG capable, but support
- * role switch, the defalt role is gadget, and the
- * user can switch it through debugfs.
- */
- ci->role = CI_ROLE_GADGET;
- }
- } else {
- ci->role = ci->roles[CI_ROLE_HOST]
- ? CI_ROLE_HOST
- : CI_ROLE_GADGET;
- }
-
+ ci->role = ci_get_role(ci);
if (!ci_otg_is_fsm_mode(ci)) {
/* only update vbus status for peripheral */
if (ci->role == CI_ROLE_GADGET) {
@@ -1305,11 +1294,13 @@ static void ci_extcon_wakeup_int(struct ci_hdrc *ci)
cable_id = &ci->platdata->id_extcon;
cable_vbus = &ci->platdata->vbus_extcon;
- if (!IS_ERR(cable_id->edev) && ci->is_otg &&
+ if ((!IS_ERR(cable_id->edev) || !IS_ERR(ci->role_switch))
+ && ci->is_otg &&
(otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS))
ci_irq(ci);
- if (!IS_ERR(cable_vbus->edev) && ci->is_otg &&
+ if ((!IS_ERR(cable_vbus->edev) || !IS_ERR(ci->role_switch))
+ && ci->is_otg &&
(otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS))
ci_irq(ci);
}
@@ -1373,6 +1364,10 @@ static int ci_suspend(struct device *dev)
return 0;
}
+ /* Extra routine per role before system suspend */
+ if (ci->role != CI_ROLE_END && ci_role(ci)->suspend)
+ ci_role(ci)->suspend(ci);
+
if (device_may_wakeup(dev)) {
if (ci_otg_is_fsm_mode(ci))
ci_otg_fsm_suspend_for_srp(ci);
@@ -1386,11 +1381,38 @@ static int ci_suspend(struct device *dev)
return 0;
}
+static void ci_handle_power_lost(struct ci_hdrc *ci)
+{
+ enum ci_role role;
+
+ disable_irq_nosync(ci->irq);
+ if (!ci_otg_is_fsm_mode(ci)) {
+ role = ci_get_role(ci);
+
+ if (ci->role != role) {
+ ci_handle_id_switch(ci);
+ } else if (role == CI_ROLE_GADGET) {
+ if (ci->is_otg && hw_read_otgsc(ci, OTGSC_BSV))
+ usb_gadget_vbus_connect(&ci->gadget);
+ }
+ }
+
+ enable_irq(ci->irq);
+}
+
static int ci_resume(struct device *dev)
{
struct ci_hdrc *ci = dev_get_drvdata(dev);
+ bool power_lost;
int ret;
+ /* Since ASYNCLISTADDR (host mode) and ENDPTLISTADDR (device
+ * mode) share the same register address. We can check if
+ * controller resume from power lost based on this address
+ * due to this register will be reset after power lost.
+ */
+ power_lost = !hw_read(ci, OP_ENDPTLISTADDR, ~0);
+
if (device_may_wakeup(dev))
disable_irq_wake(ci->irq);
@@ -1398,6 +1420,19 @@ static int ci_resume(struct device *dev)
if (ret)
return ret;
+ if (power_lost) {
+ /* shutdown and re-init for phy */
+ ci_usb_phy_exit(ci);
+ ci_usb_phy_init(ci);
+ }
+
+ /* Extra routine per role after system resume */
+ if (ci->role != CI_ROLE_END && ci_role(ci)->resume)
+ ci_role(ci)->resume(ci, power_lost);
+
+ if (power_lost)
+ ci_handle_power_lost(ci);
+
if (ci->supports_runtime_pm) {
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
index bc3634a54c6b..ebe7400243b1 100644
--- a/drivers/usb/chipidea/host.c
+++ b/drivers/usb/chipidea/host.c
@@ -459,6 +459,18 @@ static void ci_hdrc_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
ci_hdrc_free_dma_aligned_buffer(urb);
}
+#ifdef CONFIG_PM_SLEEP
+static void ci_hdrc_host_suspend(struct ci_hdrc *ci)
+{
+ ehci_suspend(ci->hcd, device_may_wakeup(ci->dev));
+}
+
+static void ci_hdrc_host_resume(struct ci_hdrc *ci, bool power_lost)
+{
+ ehci_resume(ci->hcd, power_lost);
+}
+#endif
+
int ci_hdrc_host_init(struct ci_hdrc *ci)
{
struct ci_role_driver *rdrv;
@@ -472,6 +484,10 @@ int ci_hdrc_host_init(struct ci_hdrc *ci)
rdrv->start = host_start;
rdrv->stop = host_stop;
+#ifdef CONFIG_PM_SLEEP
+ rdrv->suspend = ci_hdrc_host_suspend;
+ rdrv->resume = ci_hdrc_host_resume;
+#endif
rdrv->irq = host_irq;
rdrv->name = "host";
ci->roles[CI_ROLE_HOST] = rdrv;
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
index 7b53274ef966..622c3b68aa1e 100644
--- a/drivers/usb/chipidea/otg.c
+++ b/drivers/usb/chipidea/otg.c
@@ -165,7 +165,7 @@ static int hw_wait_vbus_lower_bsv(struct ci_hdrc *ci)
return 0;
}
-static void ci_handle_id_switch(struct ci_hdrc *ci)
+void ci_handle_id_switch(struct ci_hdrc *ci)
{
enum ci_role role = ci_otg_role(ci);
diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h
index 5e7a6e571dd2..87629b81e03e 100644
--- a/drivers/usb/chipidea/otg.h
+++ b/drivers/usb/chipidea/otg.h
@@ -14,6 +14,7 @@ int ci_hdrc_otg_init(struct ci_hdrc *ci);
void ci_hdrc_otg_destroy(struct ci_hdrc *ci);
enum ci_role ci_otg_role(struct ci_hdrc *ci);
void ci_handle_vbus_change(struct ci_hdrc *ci);
+void ci_handle_id_switch(struct ci_hdrc *ci);
static inline void ci_otg_queue_work(struct ci_hdrc *ci)
{
disable_irq_nosync(ci->irq);
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 8c3e3a635ac2..54c09245ad05 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -2181,6 +2181,34 @@ static void udc_id_switch_for_host(struct ci_hdrc *ci)
ci->platdata->pins_default);
}
+#ifdef CONFIG_PM_SLEEP
+static void udc_suspend(struct ci_hdrc *ci)
+{
+ /*
+ * Set OP_ENDPTLISTADDR to be non-zero for
+ * checking if controller resume from power lost
+ * in non-host mode.
+ */
+ if (hw_read(ci, OP_ENDPTLISTADDR, ~0) == 0)
+ hw_write(ci, OP_ENDPTLISTADDR, ~0, ~0);
+}
+
+static void udc_resume(struct ci_hdrc *ci, bool power_lost)
+{
+ if (power_lost) {
+ if (ci->is_otg)
+ hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE,
+ OTGSC_BSVIS | OTGSC_BSVIE);
+ if (ci->vbus_active)
+ usb_gadget_vbus_disconnect(&ci->gadget);
+ }
+
+ /* Restore value 0 if it was set for power lost check */
+ if (hw_read(ci, OP_ENDPTLISTADDR, ~0) == 0xFFFFFFFF)
+ hw_write(ci, OP_ENDPTLISTADDR, ~0, 0);
+}
+#endif
+
/**
* ci_hdrc_gadget_init - initialize device related bits
* @ci: the controller
@@ -2201,6 +2229,10 @@ int ci_hdrc_gadget_init(struct ci_hdrc *ci)
rdrv->start = udc_id_switch_for_device;
rdrv->stop = udc_id_switch_for_host;
+#ifdef CONFIG_PM_SLEEP
+ rdrv->suspend = udc_suspend;
+ rdrv->resume = udc_resume;
+#endif
rdrv->irq = udc_irq;
rdrv->name = "gadget";
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index bac0f5458cab..acdb13316cd0 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -150,6 +150,8 @@ struct usbmisc_ops {
int (*hsic_set_clk)(struct imx_usbmisc_data *data, bool enabled);
/* usb charger detection */
int (*charger_detection)(struct imx_usbmisc_data *data);
+ /* It's called when system resume from usb power lost */
+ int (*power_lost_check)(struct imx_usbmisc_data *data);
};
struct imx_usbmisc {
@@ -937,6 +939,44 @@ static int usbmisc_imx7ulp_init(struct imx_usbmisc_data *data)
return 0;
}
+static int usbmisc_imx7d_power_lost_check(struct imx_usbmisc_data *data)
+{
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&usbmisc->lock, flags);
+ val = readl(usbmisc->base);
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+ /*
+ * Here use a power on reset value to judge
+ * if the controller experienced a power lost
+ */
+ if (val == 0x30001000)
+ return 1;
+ else
+ return 0;
+}
+
+static int usbmisc_imx6sx_power_lost_check(struct imx_usbmisc_data *data)
+{
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&usbmisc->lock, flags);
+ val = readl(usbmisc->base + data->index * 4);
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+ /*
+ * Here use a power on reset value to judge
+ * if the controller experienced a power lost
+ */
+ if (val == 0x30001000)
+ return 1;
+ else
+ return 0;
+}
+
static const struct usbmisc_ops imx25_usbmisc_ops = {
.init = usbmisc_imx25_init,
.post = usbmisc_imx25_post,
@@ -970,12 +1010,14 @@ static const struct usbmisc_ops imx6sx_usbmisc_ops = {
.init = usbmisc_imx6sx_init,
.hsic_set_connect = usbmisc_imx6_hsic_set_connect,
.hsic_set_clk = usbmisc_imx6_hsic_set_clk,
+ .power_lost_check = usbmisc_imx6sx_power_lost_check,
};
static const struct usbmisc_ops imx7d_usbmisc_ops = {
.init = usbmisc_imx7d_init,
.set_wakeup = usbmisc_imx7d_set_wakeup,
.charger_detection = imx7d_charger_detection,
+ .power_lost_check = usbmisc_imx7d_power_lost_check,
};
static const struct usbmisc_ops imx7ulp_usbmisc_ops = {
@@ -983,6 +1025,7 @@ static const struct usbmisc_ops imx7ulp_usbmisc_ops = {
.set_wakeup = usbmisc_imx7d_set_wakeup,
.hsic_set_connect = usbmisc_imx6_hsic_set_connect,
.hsic_set_clk = usbmisc_imx6_hsic_set_clk,
+ .power_lost_check = usbmisc_imx7d_power_lost_check,
};
static inline bool is_imx53_usbmisc(struct imx_usbmisc_data *data)
@@ -1009,30 +1052,29 @@ EXPORT_SYMBOL_GPL(imx_usbmisc_init);
int imx_usbmisc_init_post(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc;
+ int ret = 0;
if (!data)
return 0;
usbmisc = dev_get_drvdata(data->dev);
- if (!usbmisc->ops->post)
- return 0;
- return usbmisc->ops->post(data);
-}
-EXPORT_SYMBOL_GPL(imx_usbmisc_init_post);
-
-int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *data, bool enabled)
-{
- struct imx_usbmisc *usbmisc;
+ if (usbmisc->ops->post)
+ ret = usbmisc->ops->post(data);
+ if (ret) {
+ dev_err(data->dev, "post init failed, ret=%d\n", ret);
+ return ret;
+ }
- if (!data)
- return 0;
+ if (usbmisc->ops->set_wakeup)
+ ret = usbmisc->ops->set_wakeup(data, false);
+ if (ret) {
+ dev_err(data->dev, "set_wakeup failed, ret=%d\n", ret);
+ return ret;
+ }
- usbmisc = dev_get_drvdata(data->dev);
- if (!usbmisc->ops->set_wakeup)
- return 0;
- return usbmisc->ops->set_wakeup(data, enabled);
+ return 0;
}
-EXPORT_SYMBOL_GPL(imx_usbmisc_set_wakeup);
+EXPORT_SYMBOL_GPL(imx_usbmisc_init_post);
int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data)
{
@@ -1048,20 +1090,6 @@ int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data)
}
EXPORT_SYMBOL_GPL(imx_usbmisc_hsic_set_connect);
-int imx_usbmisc_hsic_set_clk(struct imx_usbmisc_data *data, bool on)
-{
- struct imx_usbmisc *usbmisc;
-
- if (!data)
- return 0;
-
- usbmisc = dev_get_drvdata(data->dev);
- if (!usbmisc->ops->hsic_set_clk || !data->hsic)
- return 0;
- return usbmisc->ops->hsic_set_clk(data, on);
-}
-EXPORT_SYMBOL_GPL(imx_usbmisc_hsic_set_clk);
-
int imx_usbmisc_charger_detection(struct imx_usbmisc_data *data, bool connect)
{
struct imx_usbmisc *usbmisc;
@@ -1094,6 +1122,78 @@ int imx_usbmisc_charger_detection(struct imx_usbmisc_data *data, bool connect)
}
EXPORT_SYMBOL_GPL(imx_usbmisc_charger_detection);
+int imx_usbmisc_suspend(struct imx_usbmisc_data *data, bool wakeup)
+{
+ struct imx_usbmisc *usbmisc;
+ int ret = 0;
+
+ if (!data)
+ return 0;
+
+ usbmisc = dev_get_drvdata(data->dev);
+
+ if (wakeup && usbmisc->ops->set_wakeup)
+ ret = usbmisc->ops->set_wakeup(data, true);
+ if (ret) {
+ dev_err(data->dev, "set_wakeup failed, ret=%d\n", ret);
+ return ret;
+ }
+
+ if (usbmisc->ops->hsic_set_clk && data->hsic)
+ ret = usbmisc->ops->hsic_set_clk(data, false);
+ if (ret) {
+ dev_err(data->dev, "set_wakeup failed, ret=%d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(imx_usbmisc_suspend);
+
+int imx_usbmisc_resume(struct imx_usbmisc_data *data, bool wakeup)
+{
+ struct imx_usbmisc *usbmisc;
+ int ret = 0;
+
+ if (!data)
+ return 0;
+
+ usbmisc = dev_get_drvdata(data->dev);
+
+ if (usbmisc->ops->power_lost_check)
+ ret = usbmisc->ops->power_lost_check(data);
+ if (ret > 0) {
+ /* re-init if resume from power lost */
+ ret = imx_usbmisc_init(data);
+ if (ret) {
+ dev_err(data->dev, "re-init failed, ret=%d\n", ret);
+ return ret;
+ }
+ }
+
+ if (wakeup && usbmisc->ops->set_wakeup)
+ ret = usbmisc->ops->set_wakeup(data, false);
+ if (ret) {
+ dev_err(data->dev, "set_wakeup failed, ret=%d\n", ret);
+ return ret;
+ }
+
+ if (usbmisc->ops->hsic_set_clk && data->hsic)
+ ret = usbmisc->ops->hsic_set_clk(data, true);
+ if (ret) {
+ dev_err(data->dev, "set_wakeup failed, ret=%d\n", ret);
+ goto hsic_set_clk_fail;
+ }
+
+ return 0;
+
+hsic_set_clk_fail:
+ if (wakeup && usbmisc->ops->set_wakeup)
+ usbmisc->ops->set_wakeup(data, true);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(imx_usbmisc_resume);
+
static const struct of_device_id usbmisc_imx_dt_ids[] = {
{
.compatible = "fsl,imx25-usbmisc",
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 48bc8a4814ac..725b8dbcfe5f 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -61,7 +61,7 @@ static void usb_parse_ssp_isoc_endpoint_companion(struct device *ddev,
desc = (struct usb_ssp_isoc_ep_comp_descriptor *) buffer;
if (desc->bDescriptorType != USB_DT_SSP_ISOC_ENDPOINT_COMP ||
size < USB_DT_SSP_ISOC_EP_COMP_SIZE) {
- dev_warn(ddev, "Invalid SuperSpeedPlus isoc endpoint companion"
+ dev_notice(ddev, "Invalid SuperSpeedPlus isoc endpoint companion"
"for config %d interface %d altsetting %d ep %d.\n",
cfgno, inum, asnum, ep->desc.bEndpointAddress);
return;
@@ -83,7 +83,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP ||
size < USB_DT_SS_EP_COMP_SIZE) {
- dev_warn(ddev, "No SuperSpeed endpoint companion for config %d "
+ dev_notice(ddev, "No SuperSpeed endpoint companion for config %d "
" interface %d altsetting %d ep %d: "
"using minimum values\n",
cfgno, inum, asnum, ep->desc.bEndpointAddress);
@@ -109,13 +109,13 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
/* Check the various values */
if (usb_endpoint_xfer_control(&ep->desc) && desc->bMaxBurst != 0) {
- dev_warn(ddev, "Control endpoint with bMaxBurst = %d in "
+ dev_notice(ddev, "Control endpoint with bMaxBurst = %d in "
"config %d interface %d altsetting %d ep %d: "
"setting to zero\n", desc->bMaxBurst,
cfgno, inum, asnum, ep->desc.bEndpointAddress);
ep->ss_ep_comp.bMaxBurst = 0;
} else if (desc->bMaxBurst > 15) {
- dev_warn(ddev, "Endpoint with bMaxBurst = %d in "
+ dev_notice(ddev, "Endpoint with bMaxBurst = %d in "
"config %d interface %d altsetting %d ep %d: "
"setting to 15\n", desc->bMaxBurst,
cfgno, inum, asnum, ep->desc.bEndpointAddress);
@@ -125,7 +125,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
if ((usb_endpoint_xfer_control(&ep->desc) ||
usb_endpoint_xfer_int(&ep->desc)) &&
desc->bmAttributes != 0) {
- dev_warn(ddev, "%s endpoint with bmAttributes = %d in "
+ dev_notice(ddev, "%s endpoint with bmAttributes = %d in "
"config %d interface %d altsetting %d ep %d: "
"setting to zero\n",
usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Bulk",
@@ -134,7 +134,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
ep->ss_ep_comp.bmAttributes = 0;
} else if (usb_endpoint_xfer_bulk(&ep->desc) &&
desc->bmAttributes > 16) {
- dev_warn(ddev, "Bulk endpoint with more than 65536 streams in "
+ dev_notice(ddev, "Bulk endpoint with more than 65536 streams in "
"config %d interface %d altsetting %d ep %d: "
"setting to max\n",
cfgno, inum, asnum, ep->desc.bEndpointAddress);
@@ -142,7 +142,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
} else if (usb_endpoint_xfer_isoc(&ep->desc) &&
!USB_SS_SSP_ISOC_COMP(desc->bmAttributes) &&
USB_SS_MULT(desc->bmAttributes) > 3) {
- dev_warn(ddev, "Isoc endpoint has Mult of %d in "
+ dev_notice(ddev, "Isoc endpoint has Mult of %d in "
"config %d interface %d altsetting %d ep %d: "
"setting to 3\n",
USB_SS_MULT(desc->bmAttributes),
@@ -160,7 +160,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
else
max_tx = 999999;
if (le16_to_cpu(desc->wBytesPerInterval) > max_tx) {
- dev_warn(ddev, "%s endpoint with wBytesPerInterval of %d in "
+ dev_notice(ddev, "%s endpoint with wBytesPerInterval of %d in "
"config %d interface %d altsetting %d ep %d: "
"setting to %d\n",
usb_endpoint_xfer_isoc(&ep->desc) ? "Isoc" : "Int",
@@ -273,7 +273,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
else if (d->bLength >= USB_DT_ENDPOINT_SIZE)
n = USB_DT_ENDPOINT_SIZE;
else {
- dev_warn(ddev, "config %d interface %d altsetting %d has an "
+ dev_notice(ddev, "config %d interface %d altsetting %d has an "
"invalid endpoint descriptor of length %d, skipping\n",
cfgno, inum, asnum, d->bLength);
goto skip_to_next_endpoint_or_interface_descriptor;
@@ -281,7 +281,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
i = d->bEndpointAddress & ~USB_ENDPOINT_DIR_MASK;
if (i >= 16 || i == 0) {
- dev_warn(ddev, "config %d interface %d altsetting %d has an "
+ dev_notice(ddev, "config %d interface %d altsetting %d has an "
"invalid endpoint with address 0x%X, skipping\n",
cfgno, inum, asnum, d->bEndpointAddress);
goto skip_to_next_endpoint_or_interface_descriptor;
@@ -293,7 +293,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
/* Check for duplicate endpoint addresses */
if (config_endpoint_is_duplicate(config, inum, asnum, d)) {
- dev_warn(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n",
+ dev_notice(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n",
cfgno, inum, asnum, d->bEndpointAddress);
goto skip_to_next_endpoint_or_interface_descriptor;
}
@@ -301,7 +301,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
/* Ignore some endpoints */
if (udev->quirks & USB_QUIRK_ENDPOINT_IGNORE) {
if (usb_endpoint_is_ignored(udev, ifp, d)) {
- dev_warn(ddev, "config %d interface %d altsetting %d has an ignored endpoint with address 0x%X, skipping\n",
+ dev_notice(ddev, "config %d interface %d altsetting %d has an ignored endpoint with address 0x%X, skipping\n",
cfgno, inum, asnum,
d->bEndpointAddress);
goto skip_to_next_endpoint_or_interface_descriptor;
@@ -378,7 +378,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
}
}
if (d->bInterval < i || d->bInterval > j) {
- dev_warn(ddev, "config %d interface %d altsetting %d "
+ dev_notice(ddev, "config %d interface %d altsetting %d "
"endpoint 0x%X has an invalid bInterval %d, "
"changing to %d\n",
cfgno, inum, asnum,
@@ -391,7 +391,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
* them usable, we will try treating them as Interrupt endpoints.
*/
if (udev->speed == USB_SPEED_LOW && usb_endpoint_xfer_bulk(d)) {
- dev_warn(ddev, "config %d interface %d altsetting %d "
+ dev_notice(ddev, "config %d interface %d altsetting %d "
"endpoint 0x%X is Bulk; changing to Interrupt\n",
cfgno, inum, asnum, d->bEndpointAddress);
endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT;
@@ -408,7 +408,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
*/
maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize);
if (maxp == 0 && !(usb_endpoint_xfer_isoc(d) && asnum == 0)) {
- dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid wMaxPacketSize 0\n",
+ dev_notice(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid wMaxPacketSize 0\n",
cfgno, inum, asnum, d->bEndpointAddress);
}
@@ -439,7 +439,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
j = maxpacket_maxes[usb_endpoint_type(&endpoint->desc)];
if (maxp > j) {
- dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid maxpacket %d, setting to %d\n",
+ dev_notice(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid maxpacket %d, setting to %d\n",
cfgno, inum, asnum, d->bEndpointAddress, maxp, j);
maxp = j;
endpoint->desc.wMaxPacketSize = cpu_to_le16(i | maxp);
@@ -452,7 +452,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
*/
if (udev->speed == USB_SPEED_HIGH && usb_endpoint_xfer_bulk(d)) {
if (maxp != 512)
- dev_warn(ddev, "config %d interface %d altsetting %d "
+ dev_notice(ddev, "config %d interface %d altsetting %d "
"bulk endpoint 0x%X has invalid maxpacket %d\n",
cfgno, inum, asnum, d->bEndpointAddress,
maxp);
@@ -533,7 +533,7 @@ static int usb_parse_interface(struct device *ddev, int cfgno,
i < intfc->num_altsetting;
(++i, ++alt)) {
if (alt->desc.bAlternateSetting == asnum) {
- dev_warn(ddev, "Duplicate descriptor for config %d "
+ dev_notice(ddev, "Duplicate descriptor for config %d "
"interface %d altsetting %d, skipping\n",
cfgno, inum, asnum);
goto skip_to_next_interface_descriptor;
@@ -559,7 +559,7 @@ static int usb_parse_interface(struct device *ddev, int cfgno,
num_ep = num_ep_orig = alt->desc.bNumEndpoints;
alt->desc.bNumEndpoints = 0; /* Use as a counter */
if (num_ep > USB_MAXENDPOINTS) {
- dev_warn(ddev, "too many endpoints for config %d interface %d "
+ dev_notice(ddev, "too many endpoints for config %d interface %d "
"altsetting %d: %d, using maximum allowed: %d\n",
cfgno, inum, asnum, num_ep, USB_MAXENDPOINTS);
num_ep = USB_MAXENDPOINTS;
@@ -590,7 +590,7 @@ static int usb_parse_interface(struct device *ddev, int cfgno,
}
if (n != num_ep_orig)
- dev_warn(ddev, "config %d interface %d altsetting %d has %d "
+ dev_notice(ddev, "config %d interface %d altsetting %d has %d "
"endpoint descriptor%s, different from the interface "
"descriptor's value: %d\n",
cfgno, inum, asnum, n, plural(n), num_ep_orig);
@@ -625,7 +625,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
if (config->desc.bDescriptorType != USB_DT_CONFIG ||
config->desc.bLength < USB_DT_CONFIG_SIZE ||
config->desc.bLength > size) {
- dev_err(ddev, "invalid descriptor for config index %d: "
+ dev_notice(ddev, "invalid descriptor for config index %d: "
"type = 0x%X, length = %d\n", cfgidx,
config->desc.bDescriptorType, config->desc.bLength);
return -EINVAL;
@@ -636,7 +636,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
size -= config->desc.bLength;
if (nintf > USB_MAXINTERFACES) {
- dev_warn(ddev, "config %d has too many interfaces: %d, "
+ dev_notice(ddev, "config %d has too many interfaces: %d, "
"using maximum allowed: %d\n",
cfgno, nintf, USB_MAXINTERFACES);
nintf = USB_MAXINTERFACES;
@@ -650,7 +650,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
(buffer2 += header->bLength, size2 -= header->bLength)) {
if (size2 < sizeof(struct usb_descriptor_header)) {
- dev_warn(ddev, "config %d descriptor has %d excess "
+ dev_notice(ddev, "config %d descriptor has %d excess "
"byte%s, ignoring\n",
cfgno, size2, plural(size2));
break;
@@ -658,7 +658,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
header = (struct usb_descriptor_header *) buffer2;
if ((header->bLength > size2) || (header->bLength < 2)) {
- dev_warn(ddev, "config %d has an invalid descriptor "
+ dev_notice(ddev, "config %d has an invalid descriptor "
"of length %d, skipping remainder of the config\n",
cfgno, header->bLength);
break;
@@ -670,7 +670,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
d = (struct usb_interface_descriptor *) header;
if (d->bLength < USB_DT_INTERFACE_SIZE) {
- dev_warn(ddev, "config %d has an invalid "
+ dev_notice(ddev, "config %d has an invalid "
"interface descriptor of length %d, "
"skipping\n", cfgno, d->bLength);
continue;
@@ -680,7 +680,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
if ((dev->quirks & USB_QUIRK_HONOR_BNUMINTERFACES) &&
n >= nintf_orig) {
- dev_warn(ddev, "config %d has more interface "
+ dev_notice(ddev, "config %d has more interface "
"descriptors, than it declares in "
"bNumInterfaces, ignoring interface "
"number: %d\n", cfgno, inum);
@@ -688,7 +688,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
}
if (inum >= nintf_orig)
- dev_warn(ddev, "config %d has an invalid "
+ dev_notice(ddev, "config %d has an invalid "
"interface number: %d but max is %d\n",
cfgno, inum, nintf_orig - 1);
@@ -713,14 +713,14 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
d = (struct usb_interface_assoc_descriptor *)header;
if (d->bLength < USB_DT_INTERFACE_ASSOCIATION_SIZE) {
- dev_warn(ddev,
+ dev_notice(ddev,
"config %d has an invalid interface association descriptor of length %d, skipping\n",
cfgno, d->bLength);
continue;
}
if (iad_num == USB_MAXIADS) {
- dev_warn(ddev, "found more Interface "
+ dev_notice(ddev, "found more Interface "
"Association Descriptors "
"than allocated for in "
"configuration %d\n", cfgno);
@@ -731,7 +731,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
} else if (header->bDescriptorType == USB_DT_DEVICE ||
header->bDescriptorType == USB_DT_CONFIG)
- dev_warn(ddev, "config %d contains an unexpected "
+ dev_notice(ddev, "config %d contains an unexpected "
"descriptor of type 0x%X, skipping\n",
cfgno, header->bDescriptorType);
@@ -740,11 +740,11 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
config->desc.wTotalLength = cpu_to_le16(buffer2 - buffer0);
if (n != nintf)
- dev_warn(ddev, "config %d has %d interface%s, different from "
+ dev_notice(ddev, "config %d has %d interface%s, different from "
"the descriptor's value: %d\n",
cfgno, n, plural(n), nintf_orig);
else if (n == 0)
- dev_warn(ddev, "config %d has no interfaces?\n", cfgno);
+ dev_notice(ddev, "config %d has no interfaces?\n", cfgno);
config->desc.bNumInterfaces = nintf = n;
/* Check for missing interface numbers */
@@ -754,7 +754,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
break;
}
if (j >= nintf)
- dev_warn(ddev, "config %d has no interface number "
+ dev_notice(ddev, "config %d has no interface number "
"%d\n", cfgno, i);
}
@@ -762,7 +762,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
for (i = 0; i < nintf; ++i) {
j = nalts[i];
if (j > USB_MAXALTSETTING) {
- dev_warn(ddev, "too many alternate settings for "
+ dev_notice(ddev, "too many alternate settings for "
"config %d interface %d: %d, "
"using maximum allowed: %d\n",
cfgno, inums[i], j, USB_MAXALTSETTING);
@@ -811,7 +811,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
break;
}
if (n >= intfc->num_altsetting)
- dev_warn(ddev, "config %d interface %d has no "
+ dev_notice(ddev, "config %d interface %d has no "
"altsetting %d\n", cfgno, inums[i], j);
}
}
@@ -868,7 +868,7 @@ int usb_get_configuration(struct usb_device *dev)
int result;
if (ncfg > USB_MAXCONFIG) {
- dev_warn(ddev, "too many configurations: %d, "
+ dev_notice(ddev, "too many configurations: %d, "
"using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG;
}
@@ -902,7 +902,7 @@ int usb_get_configuration(struct usb_device *dev)
"descriptor/%s: %d\n", cfgno, "start", result);
if (result != -EPIPE)
goto err;
- dev_err(ddev, "chopping to %d config(s)\n", cfgno);
+ dev_notice(ddev, "chopping to %d config(s)\n", cfgno);
dev->descriptor.bNumConfigurations = cfgno;
break;
} else if (result < 4) {
@@ -934,7 +934,7 @@ int usb_get_configuration(struct usb_device *dev)
goto err;
}
if (result < length) {
- dev_warn(ddev, "config index %d descriptor too short "
+ dev_notice(ddev, "config index %d descriptor too short "
"(expected %i, got %i)\n", cfgno, length, result);
length = result;
}
@@ -993,7 +993,7 @@ int usb_get_bos_descriptor(struct usb_device *dev)
/* Get BOS descriptor */
ret = usb_get_descriptor(dev, USB_DT_BOS, 0, bos, USB_DT_BOS_SIZE);
if (ret < USB_DT_BOS_SIZE || bos->bLength < USB_DT_BOS_SIZE) {
- dev_err(ddev, "unable to get BOS descriptor or descriptor too short\n");
+ dev_notice(ddev, "unable to get BOS descriptor or descriptor too short\n");
if (ret >= 0)
ret = -ENOMSG;
kfree(bos);
@@ -1021,7 +1021,7 @@ int usb_get_bos_descriptor(struct usb_device *dev)
ret = usb_get_descriptor(dev, USB_DT_BOS, 0, buffer, total_len);
if (ret < total_len) {
- dev_err(ddev, "unable to get BOS descriptor set\n");
+ dev_notice(ddev, "unable to get BOS descriptor set\n");
if (ret >= 0)
ret = -ENOMSG;
goto err;
@@ -1046,7 +1046,7 @@ int usb_get_bos_descriptor(struct usb_device *dev)
}
if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) {
- dev_warn(ddev, "descriptor type invalid, skip\n");
+ dev_notice(ddev, "descriptor type invalid, skip\n");
continue;
}
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index bbab424b0d55..77e73fc8d673 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -3081,6 +3081,48 @@ done:
return status;
}
+/*
+ * hub_port_stop_enumerate - stop USB enumeration or ignore port events
+ * @hub: target hub
+ * @port1: port num of the port
+ * @retries: port retries number of hub_port_init()
+ *
+ * Return:
+ * true: ignore port actions/events or give up connection attempts.
+ * false: keep original behavior.
+ *
+ * This function will be based on retries to check whether the port which is
+ * marked with early_stop attribute would stop enumeration or ignore events.
+ *
+ * Note:
+ * This function didn't change anything if early_stop is not set, and it will
+ * prevent all connection attempts when early_stop is set and the attempts of
+ * the port are more than 1.
+ */
+static bool hub_port_stop_enumerate(struct usb_hub *hub, int port1, int retries)
+{
+ struct usb_port *port_dev = hub->ports[port1 - 1];
+
+ if (port_dev->early_stop) {
+ if (port_dev->ignore_event)
+ return true;
+
+ /*
+ * We want unsuccessful attempts to fail quickly.
+ * Since some devices may need one failure during
+ * port initialization, we allow two tries but no
+ * more.
+ */
+ if (retries < 2)
+ return false;
+
+ port_dev->ignore_event = 1;
+ } else
+ port_dev->ignore_event = 0;
+
+ return port_dev->ignore_event;
+}
+
/* Check if a port is power on */
int usb_port_is_power_on(struct usb_hub *hub, unsigned int portstatus)
{
@@ -4796,6 +4838,11 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
do_new_scheme = use_new_scheme(udev, retry_counter, port_dev);
for (retries = 0; retries < GET_DESCRIPTOR_TRIES; (++retries, msleep(100))) {
+ if (hub_port_stop_enumerate(hub, port1, retries)) {
+ retval = -ENODEV;
+ break;
+ }
+
if (do_new_scheme) {
struct usb_device_descriptor *buf;
int r = 0;
@@ -5246,6 +5293,11 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
status = 0;
for (i = 0; i < PORT_INIT_TRIES; i++) {
+ if (hub_port_stop_enumerate(hub, port1, i)) {
+ status = -ENODEV;
+ break;
+ }
+
usb_lock_port(port_dev);
mutex_lock(hcd->address0_mutex);
retry_locked = true;
@@ -5614,6 +5666,10 @@ static void port_event(struct usb_hub *hub, int port1)
if (!pm_runtime_active(&port_dev->dev))
return;
+ /* skip port actions if ignore_event and early_stop are true */
+ if (port_dev->ignore_event && port_dev->early_stop)
+ return;
+
if (hub_handle_remote_wakeup(hub, port1, portstatus, portchange))
connect_change = 1;
@@ -5927,6 +5983,10 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
mutex_lock(hcd->address0_mutex);
for (i = 0; i < PORT_INIT_TRIES; ++i) {
+ if (hub_port_stop_enumerate(parent_hub, port1, i)) {
+ ret = -ENODEV;
+ break;
+ }
/* ep0 maxpacket size may change; let the HCD know about it.
* Other endpoints will be handled by re-enumeration. */
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index b2925856b4cb..e23833562e4f 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -90,6 +90,8 @@ struct usb_hub {
* @is_superspeed cache super-speed status
* @usb3_lpm_u1_permit: whether USB3 U1 LPM is permitted.
* @usb3_lpm_u2_permit: whether USB3 U2 LPM is permitted.
+ * @early_stop: whether port initialization will be stopped earlier.
+ * @ignore_event: whether events of the port are ignored.
*/
struct usb_port {
struct usb_device *child;
@@ -103,6 +105,8 @@ struct usb_port {
u32 over_current_count;
u8 portnum;
u32 quirks;
+ unsigned int early_stop:1;
+ unsigned int ignore_event:1;
unsigned int is_superspeed:1;
unsigned int usb3_lpm_u1_permit:1;
unsigned int usb3_lpm_u2_permit:1;
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index 38c1a4f4fdea..06a8f1f84f6f 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -7,6 +7,7 @@
* Author: Lan Tianyu <tianyu.lan@intel.com>
*/
+#include <linux/kstrtox.h>
#include <linux/slab.h>
#include <linux/pm_qos.h>
#include <linux/component.h>
@@ -17,6 +18,32 @@ static int usb_port_block_power_off;
static const struct attribute_group *port_dev_group[];
+static ssize_t early_stop_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_port *port_dev = to_usb_port(dev);
+
+ return sysfs_emit(buf, "%s\n", port_dev->early_stop ? "yes" : "no");
+}
+
+static ssize_t early_stop_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_port *port_dev = to_usb_port(dev);
+ bool value;
+
+ if (kstrtobool(buf, &value))
+ return -EINVAL;
+
+ if (value)
+ port_dev->early_stop = 1;
+ else
+ port_dev->early_stop = 0;
+
+ return count;
+}
+static DEVICE_ATTR_RW(early_stop);
+
static ssize_t disable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -63,7 +90,7 @@ static ssize_t disable_store(struct device *dev, struct device_attribute *attr,
bool disabled;
int rc;
- rc = strtobool(buf, &disabled);
+ rc = kstrtobool(buf, &disabled);
if (rc)
return rc;
@@ -236,6 +263,7 @@ static struct attribute *port_dev_attrs[] = {
&dev_attr_quirks.attr,
&dev_attr_over_current_count.attr,
&dev_attr_disable.attr,
+ &dev_attr_early_stop.attr,
NULL,
};
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 631574718d8a..8217032dfb85 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
+#include <linux/kstrtox.h>
#include <linux/string.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
@@ -505,7 +506,7 @@ static ssize_t usb2_hardware_lpm_store(struct device *dev,
if (ret < 0)
return -EINTR;
- ret = strtobool(buf, &value);
+ ret = kstrtobool(buf, &value);
if (!ret) {
udev->usb2_hw_lpm_allowed = value;
@@ -975,7 +976,7 @@ static ssize_t interface_authorized_default_store(struct device *dev,
int rc = count;
bool val;
- if (strtobool(buf, &val) != 0)
+ if (kstrtobool(buf, &val) != 0)
return -EINVAL;
if (val)
@@ -1176,7 +1177,7 @@ static ssize_t interface_authorized_store(struct device *dev,
struct usb_interface *intf = to_usb_interface(dev);
bool val;
- if (strtobool(buf, &val) != 0)
+ if (kstrtobool(buf, &val) != 0)
return -EINVAL;
if (val)
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index ec4ace0107f5..262c13b6362a 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -321,7 +321,7 @@ static int dwc2_driver_remove(struct platform_device *dev)
reset_control_assert(hsotg->reset);
reset_control_assert(hsotg->reset_ecc);
- return ret;
+ return 0;
}
/**
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 026d4029bda6..faf37c6a2666 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1463,8 +1463,18 @@ static int dwc3_prepare_trbs_sg(struct dwc3_ep *dep,
*/
if (num_trbs_left == 1 || (needs_extra_trb &&
num_trbs_left <= 2 &&
- sg_dma_len(sg_next(s)) >= length))
- must_interrupt = true;
+ sg_dma_len(sg_next(s)) >= length)) {
+ struct dwc3_request *r;
+
+ /* Check if previous requests already set IOC */
+ list_for_each_entry(r, &dep->started_list, list) {
+ if (r != req && !r->request.no_interrupt)
+ break;
+
+ if (r == req)
+ must_interrupt = true;
+ }
+ }
dwc3_prepare_one_trb(dep, req, trb_length, 1, i, false,
must_interrupt);
diff --git a/drivers/usb/fotg210/Kconfig b/drivers/usb/fotg210/Kconfig
new file mode 100644
index 000000000000..534206ee0d1d
--- /dev/null
+++ b/drivers/usb/fotg210/Kconfig
@@ -0,0 +1,37 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config USB_FOTG210
+ tristate "Faraday FOTG210 USB2 Dual Role controller"
+ depends on USB || USB_GADGET
+ depends on HAS_DMA && HAS_IOMEM
+ default ARCH_GEMINI
+ select MFD_SYSCON
+ help
+ Faraday FOTG210 is a dual-mode USB controller that can act
+ in both host controller and peripheral controller mode.
+
+if USB_FOTG210
+
+config USB_FOTG210_HCD
+ bool "Faraday FOTG210 USB Host Controller support"
+ depends on USB
+ help
+ Faraday FOTG210 is an OTG controller which can be configured as
+ an USB2.0 host. It is designed to meet USB2.0 EHCI specification
+ with minor modification.
+
+ To compile this driver as a module, choose M here: the
+ module will be called fotg210-hcd.
+
+config USB_FOTG210_UDC
+ depends on USB_GADGET
+ bool "Faraday FOTG210 USB Peripheral Controller support"
+ help
+ Faraday USB2.0 OTG controller which can be configured as
+ high speed or full speed USB device. This driver suppports
+ Bulk Transfer so far.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "fotg210-udc".
+
+endif
diff --git a/drivers/usb/fotg210/Makefile b/drivers/usb/fotg210/Makefile
new file mode 100644
index 000000000000..5aecff21f24b
--- /dev/null
+++ b/drivers/usb/fotg210/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# This setup links the different object files into one single
+# module so we don't have to EXPORT() a lot of internal symbols
+# or create unnecessary submodules.
+fotg210-objs-y += fotg210-core.o
+fotg210-objs-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o
+fotg210-objs-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o
+fotg210-objs := $(fotg210-objs-y)
+obj-$(CONFIG_USB_FOTG210) += fotg210.o
diff --git a/drivers/usb/fotg210/fotg210-core.c b/drivers/usb/fotg210/fotg210-core.c
new file mode 100644
index 000000000000..8a54edf921ac
--- /dev/null
+++ b/drivers/usb/fotg210/fotg210-core.c
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Central probing code for the FOTG210 dual role driver
+ * We register one driver for the hardware and then we decide
+ * whether to proceed with probing the host or the peripheral
+ * driver.
+ */
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/usb.h>
+#include <linux/usb/otg.h>
+
+#include "fotg210.h"
+
+/*
+ * Gemini-specific initialization function, only executed on the
+ * Gemini SoC using the global misc control register.
+ *
+ * The gemini USB blocks are connected to either Mini-A (host mode) or
+ * Mini-B (peripheral mode) plugs. There is no role switch support on the
+ * Gemini SoC, just either-or.
+ */
+#define GEMINI_GLOBAL_MISC_CTRL 0x30
+#define GEMINI_MISC_USB0_WAKEUP BIT(14)
+#define GEMINI_MISC_USB1_WAKEUP BIT(15)
+#define GEMINI_MISC_USB0_VBUS_ON BIT(22)
+#define GEMINI_MISC_USB1_VBUS_ON BIT(23)
+#define GEMINI_MISC_USB0_MINI_B BIT(29)
+#define GEMINI_MISC_USB1_MINI_B BIT(30)
+
+static int fotg210_gemini_init(struct device *dev, struct resource *res,
+ enum usb_dr_mode mode)
+{
+ struct device_node *np = dev->of_node;
+ struct regmap *map;
+ bool wakeup;
+ u32 mask, val;
+ int ret;
+
+ map = syscon_regmap_lookup_by_phandle(np, "syscon");
+ if (IS_ERR(map)) {
+ dev_err(dev, "no syscon\n");
+ return PTR_ERR(map);
+ }
+ wakeup = of_property_read_bool(np, "wakeup-source");
+
+ /*
+ * Figure out if this is USB0 or USB1 by simply checking the
+ * physical base address.
+ */
+ mask = 0;
+ if (res->start == 0x69000000) {
+ mask = GEMINI_MISC_USB1_VBUS_ON | GEMINI_MISC_USB1_MINI_B |
+ GEMINI_MISC_USB1_WAKEUP;
+ if (mode == USB_DR_MODE_HOST)
+ val = GEMINI_MISC_USB1_VBUS_ON;
+ else
+ val = GEMINI_MISC_USB1_MINI_B;
+ if (wakeup)
+ val |= GEMINI_MISC_USB1_WAKEUP;
+ } else {
+ mask = GEMINI_MISC_USB0_VBUS_ON | GEMINI_MISC_USB0_MINI_B |
+ GEMINI_MISC_USB0_WAKEUP;
+ if (mode == USB_DR_MODE_HOST)
+ val = GEMINI_MISC_USB0_VBUS_ON;
+ else
+ val = GEMINI_MISC_USB0_MINI_B;
+ if (wakeup)
+ val |= GEMINI_MISC_USB0_WAKEUP;
+ }
+
+ ret = regmap_update_bits(map, GEMINI_GLOBAL_MISC_CTRL, mask, val);
+ if (ret) {
+ dev_err(dev, "failed to initialize Gemini PHY\n");
+ return ret;
+ }
+
+ dev_info(dev, "initialized Gemini PHY in %s mode\n",
+ (mode == USB_DR_MODE_HOST) ? "host" : "gadget");
+ return 0;
+}
+
+static int fotg210_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ enum usb_dr_mode mode;
+ int ret;
+
+ mode = usb_get_dr_mode(dev);
+
+ if (of_device_is_compatible(dev->of_node, "cortina,gemini-usb")) {
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ret = fotg210_gemini_init(dev, res, mode);
+ if (ret)
+ return ret;
+ }
+
+ if (mode == USB_DR_MODE_PERIPHERAL)
+ ret = fotg210_udc_probe(pdev);
+ else
+ ret = fotg210_hcd_probe(pdev);
+
+ return ret;
+}
+
+static int fotg210_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ enum usb_dr_mode mode;
+
+ mode = usb_get_dr_mode(dev);
+
+ if (mode == USB_DR_MODE_PERIPHERAL)
+ fotg210_udc_remove(pdev);
+ else
+ fotg210_hcd_remove(pdev);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id fotg210_of_match[] = {
+ { .compatible = "faraday,fotg210" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, fotg210_of_match);
+#endif
+
+static struct platform_driver fotg210_driver = {
+ .driver = {
+ .name = "fotg210",
+ .of_match_table = of_match_ptr(fotg210_of_match),
+ },
+ .probe = fotg210_probe,
+ .remove = fotg210_remove,
+};
+
+static int __init fotg210_init(void)
+{
+ if (usb_disabled())
+ return -ENODEV;
+
+ if (IS_ENABLED(CONFIG_USB_FOTG210_HCD))
+ fotg210_hcd_init();
+ return platform_driver_register(&fotg210_driver);
+}
+module_init(fotg210_init);
+
+static void __exit fotg210_cleanup(void)
+{
+ platform_driver_unregister(&fotg210_driver);
+ if (IS_ENABLED(CONFIG_USB_FOTG210_HCD))
+ fotg210_hcd_cleanup();
+}
+module_exit(fotg210_cleanup);
+
+MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("FOTG210 Dual Role Controller Driver");
diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/fotg210/fotg210-hcd.c
index 3d1dbcf4c073..51ac93a2eb98 100644
--- a/drivers/usb/host/fotg210-hcd.c
+++ b/drivers/usb/fotg210/fotg210-hcd.c
@@ -39,8 +39,8 @@
#include <asm/irq.h>
#include <asm/unaligned.h>
-#define DRIVER_AUTHOR "Yuan-Hsin Chen"
-#define DRIVER_DESC "FOTG210 Host Controller (EHCI) Driver"
+#include "fotg210.h"
+
static const char hcd_name[] = "fotg210_hcd";
#undef FOTG210_URB_TRACE
@@ -77,7 +77,7 @@ MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us");
#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
-#include "fotg210.h"
+#include "fotg210-hcd.h"
#define fotg210_dbg(fotg210, fmt, args...) \
dev_dbg(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args)
@@ -5490,9 +5490,6 @@ static int fotg210_get_frame(struct usb_hcd *hcd)
* functions and in order to facilitate role switching we cannot
* give the fotg210 driver exclusive access to those.
*/
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_LICENSE("GPL");
static const struct hc_driver fotg210_fotg210_hc_driver = {
.description = hcd_name,
@@ -5560,7 +5557,7 @@ static void fotg210_init(struct fotg210_hcd *fotg210)
* then invokes the start() method for the HCD associated with it
* through the hotplug entry's driver_data.
*/
-static int fotg210_hcd_probe(struct platform_device *pdev)
+int fotg210_hcd_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct usb_hcd *hcd;
@@ -5652,7 +5649,7 @@ fail_create_hcd:
* @dev: USB Host Controller being removed
*
*/
-static int fotg210_hcd_remove(struct platform_device *pdev)
+int fotg210_hcd_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
@@ -5668,27 +5665,8 @@ static int fotg210_hcd_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_OF
-static const struct of_device_id fotg210_of_match[] = {
- { .compatible = "faraday,fotg210" },
- {},
-};
-MODULE_DEVICE_TABLE(of, fotg210_of_match);
-#endif
-
-static struct platform_driver fotg210_hcd_driver = {
- .driver = {
- .name = "fotg210-hcd",
- .of_match_table = of_match_ptr(fotg210_of_match),
- },
- .probe = fotg210_hcd_probe,
- .remove = fotg210_hcd_remove,
-};
-
-static int __init fotg210_hcd_init(void)
+int __init fotg210_hcd_init(void)
{
- int retval = 0;
-
if (usb_disabled())
return -ENODEV;
@@ -5704,24 +5682,11 @@ static int __init fotg210_hcd_init(void)
fotg210_debug_root = debugfs_create_dir("fotg210", usb_debug_root);
- retval = platform_driver_register(&fotg210_hcd_driver);
- if (retval < 0)
- goto clean;
- return retval;
-
-clean:
- debugfs_remove(fotg210_debug_root);
- fotg210_debug_root = NULL;
-
- clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
- return retval;
+ return 0;
}
-module_init(fotg210_hcd_init);
-static void __exit fotg210_hcd_cleanup(void)
+void __exit fotg210_hcd_cleanup(void)
{
- platform_driver_unregister(&fotg210_hcd_driver);
debugfs_remove(fotg210_debug_root);
clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
}
-module_exit(fotg210_hcd_cleanup);
diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/fotg210/fotg210-hcd.h
index 0781442b7a24..0781442b7a24 100644
--- a/drivers/usb/host/fotg210.h
+++ b/drivers/usb/fotg210/fotg210-hcd.h
diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/fotg210/fotg210-udc.c
index fdca28e72a3b..3c357ce42d3b 100644
--- a/drivers/usb/gadget/udc/fotg210-udc.c
+++ b/drivers/usb/fotg210/fotg210-udc.c
@@ -17,6 +17,7 @@
#include <linux/usb/gadget.h>
#include "fotg210.h"
+#include "fotg210-udc.h"
#define DRIVER_DESC "FOTG210 USB Device Controller Driver"
#define DRIVER_VERSION "30-April-2013"
@@ -629,10 +630,10 @@ static void fotg210_request_error(struct fotg210_udc *fotg210)
static void fotg210_set_address(struct fotg210_udc *fotg210,
struct usb_ctrlrequest *ctrl)
{
- if (ctrl->wValue >= 0x0100) {
+ if (le16_to_cpu(ctrl->wValue) >= 0x0100) {
fotg210_request_error(fotg210);
} else {
- fotg210_set_dev_addr(fotg210, ctrl->wValue);
+ fotg210_set_dev_addr(fotg210, le16_to_cpu(ctrl->wValue));
fotg210_set_cxdone(fotg210);
}
}
@@ -713,17 +714,17 @@ static void fotg210_get_status(struct fotg210_udc *fotg210,
switch (ctrl->bRequestType & USB_RECIP_MASK) {
case USB_RECIP_DEVICE:
- fotg210->ep0_data = 1 << USB_DEVICE_SELF_POWERED;
+ fotg210->ep0_data = cpu_to_le16(1 << USB_DEVICE_SELF_POWERED);
break;
case USB_RECIP_INTERFACE:
- fotg210->ep0_data = 0;
+ fotg210->ep0_data = cpu_to_le16(0);
break;
case USB_RECIP_ENDPOINT:
epnum = ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK;
if (epnum)
fotg210->ep0_data =
- fotg210_is_epnstall(fotg210->ep[epnum])
- << USB_ENDPOINT_HALT;
+ cpu_to_le16(fotg210_is_epnstall(fotg210->ep[epnum])
+ << USB_ENDPOINT_HALT);
else
fotg210_request_error(fotg210);
break;
@@ -1068,7 +1069,7 @@ static const struct usb_gadget_ops fotg210_gadget_ops = {
.udc_stop = fotg210_udc_stop,
};
-static int fotg210_udc_remove(struct platform_device *pdev)
+int fotg210_udc_remove(struct platform_device *pdev)
{
struct fotg210_udc *fotg210 = platform_get_drvdata(pdev);
int i;
@@ -1085,7 +1086,7 @@ static int fotg210_udc_remove(struct platform_device *pdev)
return 0;
}
-static int fotg210_udc_probe(struct platform_device *pdev)
+int fotg210_udc_probe(struct platform_device *pdev)
{
struct resource *res, *ires;
struct fotg210_udc *fotg210 = NULL;
@@ -1208,17 +1209,3 @@ err_alloc:
err:
return ret;
}
-
-static struct platform_driver fotg210_driver = {
- .driver = {
- .name = udc_name,
- },
- .probe = fotg210_udc_probe,
- .remove = fotg210_udc_remove,
-};
-
-module_platform_driver(fotg210_driver);
-
-MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang <john453@faraday-tech.com>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/gadget/udc/fotg210.h b/drivers/usb/fotg210/fotg210-udc.h
index 08c32957503b..08c32957503b 100644
--- a/drivers/usb/gadget/udc/fotg210.h
+++ b/drivers/usb/fotg210/fotg210-udc.h
diff --git a/drivers/usb/fotg210/fotg210.h b/drivers/usb/fotg210/fotg210.h
new file mode 100644
index 000000000000..ef79d8323d89
--- /dev/null
+++ b/drivers/usb/fotg210/fotg210.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __FOTG210_H
+#define __FOTG210_H
+
+#ifdef CONFIG_USB_FOTG210_HCD
+int fotg210_hcd_probe(struct platform_device *pdev);
+int fotg210_hcd_remove(struct platform_device *pdev);
+int fotg210_hcd_init(void);
+void fotg210_hcd_cleanup(void);
+#else
+static inline int fotg210_hcd_probe(struct platform_device *pdev)
+{
+ return 0;
+}
+static inline int fotg210_hcd_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+static inline int fotg210_hcd_init(void)
+{
+ return 0;
+}
+static inline void fotg210_hcd_cleanup(void)
+{
+}
+#endif
+
+#ifdef CONFIG_USB_FOTG210_UDC
+int fotg210_udc_probe(struct platform_device *pdev);
+int fotg210_udc_remove(struct platform_device *pdev);
+#else
+static inline int fotg210_udc_probe(struct platform_device *pdev)
+{
+ return 0;
+}
+static inline int fotg210_udc_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+#endif
+
+#endif /* __FOTG210_H */
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index 3a6b4926193e..96121d1c8df4 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -3,6 +3,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/device.h>
+#include <linux/kstrtox.h>
#include <linux/nls.h>
#include <linux/usb/composite.h>
#include <linux/usb/gadget_configfs.h>
@@ -800,7 +801,7 @@ static ssize_t os_desc_use_store(struct config_item *item, const char *page,
bool use;
mutex_lock(&gi->lock);
- ret = strtobool(page, &use);
+ ret = kstrtobool(page, &use);
if (!ret) {
gi->use_os_desc = use;
ret = len;
diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c
index ffe2486fce71..a7ab30e603e2 100644
--- a/drivers/usb/gadget/function/f_ecm.c
+++ b/drivers/usb/gadget/function/f_ecm.c
@@ -685,7 +685,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
struct usb_composite_dev *cdev = c->cdev;
struct f_ecm *ecm = func_to_ecm(f);
struct usb_string *us;
- int status;
+ int status = 0;
struct usb_ep *ep;
struct f_ecm_opts *ecm_opts;
@@ -695,23 +695,19 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
ecm_opts = container_of(f->fi, struct f_ecm_opts, func_inst);
- /*
- * in drivers/usb/gadget/configfs.c:configfs_composite_bind()
- * configurations are bound in sequence with list_for_each_entry,
- * in each configuration its functions are bound in sequence
- * with list_for_each_entry, so we assume no race condition
- * with regard to ecm_opts->bound access
- */
+ mutex_lock(&ecm_opts->lock);
+
+ gether_set_gadget(ecm_opts->net, cdev->gadget);
+
if (!ecm_opts->bound) {
- mutex_lock(&ecm_opts->lock);
- gether_set_gadget(ecm_opts->net, cdev->gadget);
status = gether_register_netdev(ecm_opts->net);
- mutex_unlock(&ecm_opts->lock);
- if (status)
- return status;
ecm_opts->bound = true;
}
+ mutex_unlock(&ecm_opts->lock);
+ if (status)
+ return status;
+
ecm_string_defs[1].s = ecm->ethaddr;
us = usb_gstrings_attach(cdev, ecm_strings,
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index 3abf7f586e2a..3a30feb47073 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -176,6 +176,7 @@
#include <linux/fcntl.h>
#include <linux/file.h>
#include <linux/fs.h>
+#include <linux/kstrtox.h>
#include <linux/kthread.h>
#include <linux/sched/signal.h>
#include <linux/limits.h>
@@ -3387,7 +3388,7 @@ static ssize_t fsg_opts_stall_store(struct config_item *item, const char *page,
return -EBUSY;
}
- ret = strtobool(page, &stall);
+ ret = kstrtobool(page, &stall);
if (!ret) {
opts->common->can_stall = stall;
ret = len;
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 6e196e06181e..6e131624011a 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -39,9 +39,6 @@ MODULE_PARM_DESC(trace, "Trace level bitmask");
/* string IDs are assigned dynamically */
-#define UVC_STRING_CONTROL_IDX 0
-#define UVC_STRING_STREAMING_IDX 1
-
static struct usb_string uvc_en_us_strings[] = {
/* [UVC_STRING_CONTROL_IDX].s = DYNAMIC, */
[UVC_STRING_STREAMING_IDX].s = "Video Streaming",
@@ -228,6 +225,8 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
struct uvc_device *uvc = to_uvc(f);
struct v4l2_event v4l2_event;
struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
+ unsigned int interface = le16_to_cpu(ctrl->wIndex) & 0xff;
+ struct usb_ctrlrequest *mctrl;
if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) {
uvcg_info(f, "invalid request type\n");
@@ -248,6 +247,16 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_SETUP;
memcpy(&uvc_event->req, ctrl, sizeof(uvc_event->req));
+
+ /* check for the interface number, fixup the interface number in
+ * the ctrl request so the userspace doesn't have to bother with
+ * offset and configfs parsing
+ */
+ mctrl = &uvc_event->req;
+ mctrl->wIndex &= ~cpu_to_le16(0xff);
+ if (interface == uvc->streaming_intf)
+ mctrl->wIndex = cpu_to_le16(UVC_STRING_STREAMING_IDX);
+
v4l2_event_queue(&uvc->vdev, &v4l2_event);
return 0;
diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c
index 208c6a92780a..2a4163b0f6fe 100644
--- a/drivers/usb/gadget/function/storage_common.c
+++ b/drivers/usb/gadget/function/storage_common.c
@@ -23,6 +23,7 @@
#include <linux/blkdev.h>
#include <linux/file.h>
#include <linux/fs.h>
+#include <linux/kstrtox.h>
#include <linux/usb/composite.h>
#include "storage_common.h"
@@ -396,7 +397,7 @@ ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem,
ssize_t rc;
bool ro;
- rc = strtobool(buf, &ro);
+ rc = kstrtobool(buf, &ro);
if (rc)
return rc;
@@ -419,7 +420,7 @@ ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count)
bool nofua;
int ret;
- ret = strtobool(buf, &nofua);
+ ret = kstrtobool(buf, &nofua);
if (ret)
return ret;
@@ -470,7 +471,7 @@ ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem,
bool cdrom;
int ret;
- ret = strtobool(buf, &cdrom);
+ ret = kstrtobool(buf, &cdrom);
if (ret)
return ret;
@@ -493,7 +494,7 @@ ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf,
bool removable;
int ret;
- ret = strtobool(buf, &removable);
+ ret = kstrtobool(buf, &removable);
if (ret)
return ret;
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index e06022873df1..8f12f3f8f6ee 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -798,7 +798,6 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g,
net->max_mtu = GETHER_MAX_MTU_SIZE;
dev->gadget = g;
- SET_NETDEV_DEV(net, &g->dev);
SET_NETDEV_DEVTYPE(net, &gadget_type);
status = register_netdev(net);
@@ -873,8 +872,6 @@ int gether_register_netdev(struct net_device *net)
struct usb_gadget *g;
int status;
- if (!net->dev.parent)
- return -EINVAL;
dev = netdev_priv(net);
g = dev->gadget;
@@ -905,7 +902,6 @@ void gether_set_gadget(struct net_device *net, struct usb_gadget *g)
dev = netdev_priv(net);
dev->gadget = g;
- SET_NETDEV_DEV(net, &g->dev);
}
EXPORT_SYMBOL_GPL(gether_set_gadget);
diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c
index 7538279f9817..840626e064e1 100644
--- a/drivers/usb/gadget/function/u_serial.c
+++ b/drivers/usb/gadget/function/u_serial.c
@@ -24,6 +24,7 @@
#include <linux/export.h>
#include <linux/module.h>
#include <linux/console.h>
+#include <linux/kstrtox.h>
#include <linux/kthread.h>
#include <linux/workqueue.h>
#include <linux/kfifo.h>
@@ -1070,7 +1071,7 @@ ssize_t gserial_set_console(unsigned char port_num, const char *page, size_t cou
bool enable;
int ret;
- ret = strtobool(page, &enable);
+ ret = kstrtobool(page, &enable);
if (ret)
return ret;
diff --git a/drivers/usb/gadget/legacy/serial.c b/drivers/usb/gadget/legacy/serial.c
index dcd3a6603d90..4974bee6049a 100644
--- a/drivers/usb/gadget/legacy/serial.c
+++ b/drivers/usb/gadget/legacy/serial.c
@@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <linux/device.h>
+#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
@@ -109,7 +110,7 @@ static int enable_set(const char *s, const struct kernel_param *kp)
if (!s) /* called for no-arg enable == default */
return 0;
- ret = strtobool(s, &do_enable);
+ ret = kstrtobool(s, &do_enable);
if (ret || enable == do_enable)
return ret;
diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
index 5756acb07b8d..16243964b1cd 100644
--- a/drivers/usb/gadget/udc/Kconfig
+++ b/drivers/usb/gadget/udc/Kconfig
@@ -108,17 +108,6 @@ config USB_FUSB300
help
Faraday usb device controller FUSB300 driver
-config USB_FOTG210_UDC
- depends on HAS_DMA
- tristate "Faraday FOTG210 USB Peripheral Controller"
- help
- Faraday USB2.0 OTG controller which can be configured as
- high speed or full speed USB device. This driver supppors
- Bulk Transfer so far.
-
- Say "y" to link the driver statically, or "m" to build a
- dynamically linked module called "fotg210_udc".
-
config USB_GR_UDC
tristate "Aeroflex Gaisler GRUSBDC USB Peripheral Controller Driver"
depends on HAS_DMA
diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile
index 12f9e4c9eb0c..39daf36a2baa 100644
--- a/drivers/usb/gadget/udc/Makefile
+++ b/drivers/usb/gadget/udc/Makefile
@@ -34,7 +34,6 @@ obj-$(CONFIG_USB_EG20T) += pch_udc.o
obj-$(CONFIG_USB_MV_UDC) += mv_udc.o
mv_udc-y := mv_udc_core.o
obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
-obj-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o
obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o
obj-$(CONFIG_USB_GR_UDC) += gr_udc.o
obj-$(CONFIG_USB_GADGET_XILINX) += udc-xilinx.o
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/aspeed-vhub/core.c
index 7a635c499777..ac3ca24f8b04 100644
--- a/drivers/usb/gadget/udc/aspeed-vhub/core.c
+++ b/drivers/usb/gadget/udc/aspeed-vhub/core.c
@@ -37,7 +37,7 @@ void ast_vhub_done(struct ast_vhub_ep *ep, struct ast_vhub_req *req,
list_del_init(&req->queue);
- if (req->req.status == -EINPROGRESS)
+ if ((req->req.status == -EINPROGRESS) || (status == -EOVERFLOW))
req->req.status = status;
if (req->req.dma) {
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/aspeed-vhub/epn.c
index b5252880b389..56e55472daa1 100644
--- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c
+++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c
@@ -84,6 +84,7 @@ static void ast_vhub_epn_handle_ack(struct ast_vhub_ep *ep)
{
struct ast_vhub_req *req;
unsigned int len;
+ int status = 0;
u32 stat;
/* Read EP status */
@@ -119,9 +120,15 @@ static void ast_vhub_epn_handle_ack(struct ast_vhub_ep *ep)
len = VHUB_EP_DMA_TX_SIZE(stat);
/* If not using DMA, copy data out if needed */
- if (!req->req.dma && !ep->epn.is_in && len)
- memcpy(req->req.buf + req->req.actual, ep->buf, len);
-
+ if (!req->req.dma && !ep->epn.is_in && len) {
+ if (req->req.actual + len > req->req.length) {
+ req->last_desc = 1;
+ status = -EOVERFLOW;
+ goto done;
+ } else {
+ memcpy(req->req.buf + req->req.actual, ep->buf, len);
+ }
+ }
/* Adjust size */
req->req.actual += len;
@@ -129,9 +136,10 @@ static void ast_vhub_epn_handle_ack(struct ast_vhub_ep *ep)
if (len < ep->ep.maxpacket)
req->last_desc = 1;
+done:
/* That's it ? complete the request and pick a new one */
if (req->last_desc >= 0) {
- ast_vhub_done(ep, req, 0);
+ ast_vhub_done(ep, req, status);
req = list_first_entry_or_null(&ep->queue, struct ast_vhub_req,
queue);
diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c
index a9a7b3fc60ec..922b4187004b 100644
--- a/drivers/usb/gadget/udc/at91_udc.c
+++ b/drivers/usb/gadget/udc/at91_udc.c
@@ -1628,10 +1628,7 @@ static int at91rm9200_udc_init(struct at91_udc *udc)
static void at91rm9200_udc_pullup(struct at91_udc *udc, int is_on)
{
- if (is_on)
- gpiod_set_value(udc->board.pullup_pin, 1);
- else
- gpiod_set_value(udc->board.pullup_pin, 0);
+ gpiod_set_value(udc->board.pullup_pin, is_on);
}
static const struct at91_udc_caps at91rm9200_udc_caps = {
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 247568bc17a2..8d799d23c476 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -47,7 +47,7 @@ config USB_XHCI_PCI_RENESAS
tristate "Support for additional Renesas xHCI controller with firmware"
help
Say 'Y' to enable the support for the Renesas xHCI controller with
- firmware. Make sure you have the firwmare for the device and
+ firmware. Make sure you have the firmware for the device and
installed on your system for this device to work.
If unsure, say 'N'.
@@ -389,17 +389,6 @@ config USB_ISP1362_HCD
To compile this driver as a module, choose M here: the
module will be called isp1362-hcd.
-config USB_FOTG210_HCD
- tristate "FOTG210 HCD support"
- depends on USB && HAS_DMA && HAS_IOMEM
- help
- Faraday FOTG210 is an OTG controller which can be configured as
- an USB2.0 host. It is designed to meet USB2.0 EHCI specification
- with minor modification.
-
- To compile this driver as a module, choose M here: the
- module will be called fotg210-hcd.
-
config USB_MAX3421_HCD
tristate "MAX3421 HCD (USB-over-SPI) support"
depends on USB && SPI
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 2c8a61be7e46..6d8ee264c9b2 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -84,6 +84,5 @@ obj-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
obj-$(CONFIG_USB_EHCI_MV) += ehci-mv.o
obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o
obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o
-obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o
obj-$(CONFIG_USB_MAX3421_HCD) += max3421-hcd.o
obj-$(CONFIG_USB_XEN_HCD) += xen-hcd.o
diff --git a/drivers/usb/host/ehci-grlib.c b/drivers/usb/host/ehci-grlib.c
index a2c3b4ec8a8b..0717f2ccf49d 100644
--- a/drivers/usb/host/ehci-grlib.c
+++ b/drivers/usb/host/ehci-grlib.c
@@ -99,7 +99,7 @@ static int ehci_hcd_grlib_probe(struct platform_device *op)
hcd->rsrc_len = resource_size(&res);
irq = irq_of_parse_and_map(dn, 0);
- if (irq == NO_IRQ) {
+ if (!irq) {
dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n",
__FILE__);
rv = -EBUSY;
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 17f8b6ea0c35..4b148fe5e43b 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -411,11 +411,12 @@ static struct pci_driver ehci_pci_driver = {
.remove = ehci_pci_remove,
.shutdown = usb_hcd_pci_shutdown,
-#ifdef CONFIG_PM
.driver = {
- .pm = &usb_hcd_pci_pm_ops
- },
+#ifdef CONFIG_PM
+ .pm = &usb_hcd_pci_pm_ops,
#endif
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
};
static int __init ehci_pci_init(void)
diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
index 28a19693c19f..62a0a193798c 100644
--- a/drivers/usb/host/ehci-ppc-of.c
+++ b/drivers/usb/host/ehci-ppc-of.c
@@ -119,7 +119,7 @@ static int ehci_hcd_ppc_of_probe(struct platform_device *op)
hcd->rsrc_len = resource_size(&res);
irq = irq_of_parse_and_map(dn, 0);
- if (irq == NO_IRQ) {
+ if (!irq) {
dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n",
__FILE__);
rv = -EBUSY;
diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c
index 95a44462bed0..64a64140c2fd 100644
--- a/drivers/usb/host/fhci-hcd.c
+++ b/drivers/usb/host/fhci-hcd.c
@@ -676,7 +676,7 @@ static int of_fhci_probe(struct platform_device *ofdev)
/* USB Host interrupt. */
usb_irq = irq_of_parse_and_map(node, 0);
- if (usb_irq == NO_IRQ) {
+ if (!usb_irq) {
dev_err(dev, "could not get usb irq\n");
ret = -EINVAL;
goto err_usb_irq;
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index 591f675cc930..f2f6c832ec98 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -120,7 +120,7 @@ static int ohci_hcd_ppc_of_probe(struct platform_device *op)
}
irq = irq_of_parse_and_map(dn, 0);
- if (irq == NO_IRQ) {
+ if (!irq) {
dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n",
__FILE__);
rv = -EBUSY;
diff --git a/drivers/usb/host/uhci-grlib.c b/drivers/usb/host/uhci-grlib.c
index 3ef6d52839e5..907d5f01edfd 100644
--- a/drivers/usb/host/uhci-grlib.c
+++ b/drivers/usb/host/uhci-grlib.c
@@ -116,7 +116,7 @@ static int uhci_hcd_grlib_probe(struct platform_device *op)
hcd->rsrc_len = resource_size(&res);
irq = irq_of_parse_and_map(dn, 0);
- if (irq == NO_IRQ) {
+ if (!irq) {
printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
rv = -EBUSY;
goto err_usb;
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 7bccbe50bab1..a29b681b562e 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -673,11 +673,12 @@ 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
- },
+#ifdef CONFIG_PM
+ .pm = &usb_hcd_pci_pm_ops,
#endif
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
};
static int __init xhci_pci_init(void)
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index b2f980409d0b..33b35788bd0b 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -1956,7 +1956,6 @@ static int ftdi_elan_synchronize(struct usb_ftdi *ftdi)
int long_stop = 10;
int retry_on_timeout = 5;
int retry_on_empty = 10;
- int err_count = 0;
retval = ftdi_elan_flush_input_fifo(ftdi);
if (retval)
return retval;
@@ -2051,7 +2050,6 @@ static int ftdi_elan_synchronize(struct usb_ftdi *ftdi)
continue;
}
} else {
- err_count += 1;
dev_err(&ftdi->udev->dev, "error = %d\n",
retval);
if (read_stop-- > 0) {
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 6c8f7763e75e..290df4d5d5ce 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -70,12 +70,6 @@ config USB_MUSB_SUNXI
select GENERIC_PHY
select SUNXI_SRAM
-config USB_MUSB_DAVINCI
- tristate "DaVinci"
- depends on ARCH_DAVINCI_DMx
- depends on NOP_USB_XCEIV
- depends on BROKEN
-
config USB_MUSB_DA8XX
tristate "DA8xx/OMAP-L1x"
depends on ARCH_DAVINCI_DA8XX
@@ -113,7 +107,6 @@ config USB_MUSB_JZ4740
depends on OF
depends on MIPS || COMPILE_TEST
depends on USB_MUSB_GADGET
- depends on USB=n || USB_OTG_DISABLE_EXTERNAL_HUB
select USB_ROLE_SWITCH
config USB_MUSB_MEDIATEK
@@ -161,12 +154,6 @@ config USB_INVENTRA_DMA
help
Enable DMA transfers using Mentor's engine.
-config USB_TI_CPPI_DMA
- bool 'TI CPPI (Davinci)'
- depends on USB_MUSB_DAVINCI
- help
- Enable DMA transfers when TI CPPI DMA is available.
-
config USB_TI_CPPI41_DMA
bool 'TI CPPI 4.1'
depends on (ARCH_OMAP || ARCH_DAVINCI_DA8XX) && DMADEVICES
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index 51dd54a8de49..44a9e27b2157 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -19,7 +19,6 @@ obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o
obj-$(CONFIG_USB_MUSB_AM35X) += am35x.o
obj-$(CONFIG_USB_MUSB_DSPS) += musb_dsps.o
obj-$(CONFIG_USB_MUSB_TUSB6010) += tusb6010.o
-obj-$(CONFIG_USB_MUSB_DAVINCI) += davinci.o
obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o
obj-$(CONFIG_USB_MUSB_UX500) += ux500.o
obj-$(CONFIG_USB_MUSB_JZ4740) += jz4740.o
@@ -33,7 +32,6 @@ obj-$(CONFIG_USB_MUSB_POLARFIRE_SOC) += mpfs.o
# though PIO is always there to back up DMA, and for ep0
musb_hdrc-$(CONFIG_USB_INVENTRA_DMA) += musbhsdma.o
-musb_hdrc-$(CONFIG_USB_TI_CPPI_DMA) += cppi_dma.o
musb_hdrc-$(CONFIG_USB_TUSB_OMAP_DMA) += tusb6010_omap.o
musb_hdrc-$(CONFIG_USB_UX500_DMA) += ux500_dma.o
musb_hdrc-$(CONFIG_USB_TI_CPPI41_DMA) += musb_cppi41.o
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
deleted file mode 100644
index edb5b63d7063..000000000000
--- a/drivers/usb/musb/cppi_dma.c
+++ /dev/null
@@ -1,1547 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2005-2006 by Texas Instruments
- *
- * This file implements a DMA interface using TI's CPPI DMA.
- * For now it's DaVinci-only, but CPPI isn't specific to DaVinci or USB.
- * The TUSB6020, using VLYNQ, has CPPI that looks much like DaVinci.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-
-#include "musb_core.h"
-#include "musb_debug.h"
-#include "cppi_dma.h"
-#include "davinci.h"
-
-
-/* CPPI DMA status 7-mar-2006:
- *
- * - See musb_{host,gadget}.c for more info
- *
- * - Correct RX DMA generally forces the engine into irq-per-packet mode,
- * which can easily saturate the CPU under non-mass-storage loads.
- *
- * NOTES 24-aug-2006 (2.6.18-rc4):
- *
- * - peripheral RXDMA wedged in a test with packets of length 512/512/1.
- * evidently after the 1 byte packet was received and acked, the queue
- * of BDs got garbaged so it wouldn't empty the fifo. (rxcsr 0x2003,
- * and RX DMA0: 4 left, 80000000 8feff880, 8feff860 8feff860; 8f321401
- * 004001ff 00000001 .. 8feff860) Host was just getting NAKed on tx
- * of its next (512 byte) packet. IRQ issues?
- *
- * REVISIT: the "transfer DMA" glue between CPPI and USB fifos will
- * evidently also directly update the RX and TX CSRs ... so audit all
- * host and peripheral side DMA code to avoid CSR access after DMA has
- * been started.
- */
-
-/* REVISIT now we can avoid preallocating these descriptors; or
- * more simply, switch to a global freelist not per-channel ones.
- * Note: at full speed, 64 descriptors == 4K bulk data.
- */
-#define NUM_TXCHAN_BD 64
-#define NUM_RXCHAN_BD 64
-
-static inline void cpu_drain_writebuffer(void)
-{
- wmb();
-#ifdef CONFIG_CPU_ARM926T
- /* REVISIT this "should not be needed",
- * but lack of it sure seemed to hurt ...
- */
- asm("mcr p15, 0, r0, c7, c10, 4 @ drain write buffer\n");
-#endif
-}
-
-static inline struct cppi_descriptor *cppi_bd_alloc(struct cppi_channel *c)
-{
- struct cppi_descriptor *bd = c->freelist;
-
- if (bd)
- c->freelist = bd->next;
- return bd;
-}
-
-static inline void
-cppi_bd_free(struct cppi_channel *c, struct cppi_descriptor *bd)
-{
- if (!bd)
- return;
- bd->next = c->freelist;
- c->freelist = bd;
-}
-
-/*
- * Start DMA controller
- *
- * Initialize the DMA controller as necessary.
- */
-
-/* zero out entire rx state RAM entry for the channel */
-static void cppi_reset_rx(struct cppi_rx_stateram __iomem *rx)
-{
- musb_writel(&rx->rx_skipbytes, 0, 0);
- musb_writel(&rx->rx_head, 0, 0);
- musb_writel(&rx->rx_sop, 0, 0);
- musb_writel(&rx->rx_current, 0, 0);
- musb_writel(&rx->rx_buf_current, 0, 0);
- musb_writel(&rx->rx_len_len, 0, 0);
- musb_writel(&rx->rx_cnt_cnt, 0, 0);
-}
-
-/* zero out entire tx state RAM entry for the channel */
-static void cppi_reset_tx(struct cppi_tx_stateram __iomem *tx, u32 ptr)
-{
- musb_writel(&tx->tx_head, 0, 0);
- musb_writel(&tx->tx_buf, 0, 0);
- musb_writel(&tx->tx_current, 0, 0);
- musb_writel(&tx->tx_buf_current, 0, 0);
- musb_writel(&tx->tx_info, 0, 0);
- musb_writel(&tx->tx_rem_len, 0, 0);
- /* musb_writel(&tx->tx_dummy, 0, 0); */
- musb_writel(&tx->tx_complete, 0, ptr);
-}
-
-static void cppi_pool_init(struct cppi *cppi, struct cppi_channel *c)
-{
- int j;
-
- /* initialize channel fields */
- c->head = NULL;
- c->tail = NULL;
- c->last_processed = NULL;
- c->channel.status = MUSB_DMA_STATUS_UNKNOWN;
- c->controller = cppi;
- c->is_rndis = 0;
- c->freelist = NULL;
-
- /* build the BD Free list for the channel */
- for (j = 0; j < NUM_TXCHAN_BD + 1; j++) {
- struct cppi_descriptor *bd;
- dma_addr_t dma;
-
- bd = dma_pool_alloc(cppi->pool, GFP_KERNEL, &dma);
- bd->dma = dma;
- cppi_bd_free(c, bd);
- }
-}
-
-static int cppi_channel_abort(struct dma_channel *);
-
-static void cppi_pool_free(struct cppi_channel *c)
-{
- struct cppi *cppi = c->controller;
- struct cppi_descriptor *bd;
-
- (void) cppi_channel_abort(&c->channel);
- c->channel.status = MUSB_DMA_STATUS_UNKNOWN;
- c->controller = NULL;
-
- /* free all its bds */
- bd = c->last_processed;
- do {
- if (bd)
- dma_pool_free(cppi->pool, bd, bd->dma);
- bd = cppi_bd_alloc(c);
- } while (bd);
- c->last_processed = NULL;
-}
-
-static void cppi_controller_start(struct cppi *controller)
-{
- void __iomem *tibase;
- int i;
-
- /* do whatever is necessary to start controller */
- for (i = 0; i < ARRAY_SIZE(controller->tx); i++) {
- controller->tx[i].transmit = true;
- controller->tx[i].index = i;
- }
- for (i = 0; i < ARRAY_SIZE(controller->rx); i++) {
- controller->rx[i].transmit = false;
- controller->rx[i].index = i;
- }
-
- /* setup BD list on a per channel basis */
- for (i = 0; i < ARRAY_SIZE(controller->tx); i++)
- cppi_pool_init(controller, controller->tx + i);
- for (i = 0; i < ARRAY_SIZE(controller->rx); i++)
- cppi_pool_init(controller, controller->rx + i);
-
- tibase = controller->tibase;
- INIT_LIST_HEAD(&controller->tx_complete);
-
- /* initialise tx/rx channel head pointers to zero */
- for (i = 0; i < ARRAY_SIZE(controller->tx); i++) {
- struct cppi_channel *tx_ch = controller->tx + i;
- struct cppi_tx_stateram __iomem *tx;
-
- INIT_LIST_HEAD(&tx_ch->tx_complete);
-
- tx = tibase + DAVINCI_TXCPPI_STATERAM_OFFSET(i);
- tx_ch->state_ram = tx;
- cppi_reset_tx(tx, 0);
- }
- for (i = 0; i < ARRAY_SIZE(controller->rx); i++) {
- struct cppi_channel *rx_ch = controller->rx + i;
- struct cppi_rx_stateram __iomem *rx;
-
- INIT_LIST_HEAD(&rx_ch->tx_complete);
-
- rx = tibase + DAVINCI_RXCPPI_STATERAM_OFFSET(i);
- rx_ch->state_ram = rx;
- cppi_reset_rx(rx);
- }
-
- /* enable individual cppi channels */
- musb_writel(tibase, DAVINCI_TXCPPI_INTENAB_REG,
- DAVINCI_DMA_ALL_CHANNELS_ENABLE);
- musb_writel(tibase, DAVINCI_RXCPPI_INTENAB_REG,
- DAVINCI_DMA_ALL_CHANNELS_ENABLE);
-
- /* enable tx/rx CPPI control */
- musb_writel(tibase, DAVINCI_TXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_ENABLE);
- musb_writel(tibase, DAVINCI_RXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_ENABLE);
-
- /* disable RNDIS mode, also host rx RNDIS autorequest */
- musb_writel(tibase, DAVINCI_RNDIS_REG, 0);
- musb_writel(tibase, DAVINCI_AUTOREQ_REG, 0);
-}
-
-/*
- * Stop DMA controller
- *
- * De-Init the DMA controller as necessary.
- */
-
-static void cppi_controller_stop(struct cppi *controller)
-{
- void __iomem *tibase;
- int i;
- struct musb *musb;
-
- musb = controller->controller.musb;
-
- tibase = controller->tibase;
- /* DISABLE INDIVIDUAL CHANNEL Interrupts */
- musb_writel(tibase, DAVINCI_TXCPPI_INTCLR_REG,
- DAVINCI_DMA_ALL_CHANNELS_ENABLE);
- musb_writel(tibase, DAVINCI_RXCPPI_INTCLR_REG,
- DAVINCI_DMA_ALL_CHANNELS_ENABLE);
-
- musb_dbg(musb, "Tearing down RX and TX Channels");
- for (i = 0; i < ARRAY_SIZE(controller->tx); i++) {
- /* FIXME restructure of txdma to use bds like rxdma */
- controller->tx[i].last_processed = NULL;
- cppi_pool_free(controller->tx + i);
- }
- for (i = 0; i < ARRAY_SIZE(controller->rx); i++)
- cppi_pool_free(controller->rx + i);
-
- /* in Tx Case proper teardown is supported. We resort to disabling
- * Tx/Rx CPPI after cleanup of Tx channels. Before TX teardown is
- * complete TX CPPI cannot be disabled.
- */
- /*disable tx/rx cppi */
- musb_writel(tibase, DAVINCI_TXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE);
- musb_writel(tibase, DAVINCI_RXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE);
-}
-
-/* While dma channel is allocated, we only want the core irqs active
- * for fault reports, otherwise we'd get irqs that we don't care about.
- * Except for TX irqs, where dma done != fifo empty and reusable ...
- *
- * NOTE: docs don't say either way, but irq masking **enables** irqs.
- *
- * REVISIT same issue applies to pure PIO usage too, and non-cppi dma...
- */
-static inline void core_rxirq_disable(void __iomem *tibase, unsigned epnum)
-{
- musb_writel(tibase, DAVINCI_USB_INT_MASK_CLR_REG, 1 << (epnum + 8));
-}
-
-static inline void core_rxirq_enable(void __iomem *tibase, unsigned epnum)
-{
- musb_writel(tibase, DAVINCI_USB_INT_MASK_SET_REG, 1 << (epnum + 8));
-}
-
-
-/*
- * Allocate a CPPI Channel for DMA. With CPPI, channels are bound to
- * each transfer direction of a non-control endpoint, so allocating
- * (and deallocating) is mostly a way to notice bad housekeeping on
- * the software side. We assume the irqs are always active.
- */
-static struct dma_channel *
-cppi_channel_allocate(struct dma_controller *c,
- struct musb_hw_ep *ep, u8 transmit)
-{
- struct cppi *controller;
- u8 index;
- struct cppi_channel *cppi_ch;
- void __iomem *tibase;
- struct musb *musb;
-
- controller = container_of(c, struct cppi, controller);
- tibase = controller->tibase;
- musb = c->musb;
-
- /* ep0 doesn't use DMA; remember cppi indices are 0..N-1 */
- index = ep->epnum - 1;
-
- /* return the corresponding CPPI Channel Handle, and
- * probably disable the non-CPPI irq until we need it.
- */
- if (transmit) {
- if (index >= ARRAY_SIZE(controller->tx)) {
- musb_dbg(musb, "no %cX%d CPPI channel", 'T', index);
- return NULL;
- }
- cppi_ch = controller->tx + index;
- } else {
- if (index >= ARRAY_SIZE(controller->rx)) {
- musb_dbg(musb, "no %cX%d CPPI channel", 'R', index);
- return NULL;
- }
- cppi_ch = controller->rx + index;
- core_rxirq_disable(tibase, ep->epnum);
- }
-
- /* REVISIT make this an error later once the same driver code works
- * with the other DMA engine too
- */
- if (cppi_ch->hw_ep)
- musb_dbg(musb, "re-allocating DMA%d %cX channel %p",
- index, transmit ? 'T' : 'R', cppi_ch);
- cppi_ch->hw_ep = ep;
- cppi_ch->channel.status = MUSB_DMA_STATUS_FREE;
- cppi_ch->channel.max_len = 0x7fffffff;
-
- musb_dbg(musb, "Allocate CPPI%d %cX", index, transmit ? 'T' : 'R');
- return &cppi_ch->channel;
-}
-
-/* Release a CPPI Channel. */
-static void cppi_channel_release(struct dma_channel *channel)
-{
- struct cppi_channel *c;
- void __iomem *tibase;
-
- /* REVISIT: for paranoia, check state and abort if needed... */
-
- c = container_of(channel, struct cppi_channel, channel);
- tibase = c->controller->tibase;
- if (!c->hw_ep)
- musb_dbg(c->controller->controller.musb,
- "releasing idle DMA channel %p", c);
- else if (!c->transmit)
- core_rxirq_enable(tibase, c->index + 1);
-
- /* for now, leave its cppi IRQ enabled (we won't trigger it) */
- c->hw_ep = NULL;
- channel->status = MUSB_DMA_STATUS_UNKNOWN;
-}
-
-/* Context: controller irqlocked */
-static void
-cppi_dump_rx(int level, struct cppi_channel *c, const char *tag)
-{
- void __iomem *base = c->controller->mregs;
- struct cppi_rx_stateram __iomem *rx = c->state_ram;
-
- musb_ep_select(base, c->index + 1);
-
- musb_dbg(c->controller->controller.musb,
- "RX DMA%d%s: %d left, csr %04x, "
- "%08x H%08x S%08x C%08x, "
- "B%08x L%08x %08x .. %08x",
- c->index, tag,
- musb_readl(c->controller->tibase,
- DAVINCI_RXCPPI_BUFCNT0_REG + 4 * c->index),
- musb_readw(c->hw_ep->regs, MUSB_RXCSR),
-
- musb_readl(&rx->rx_skipbytes, 0),
- musb_readl(&rx->rx_head, 0),
- musb_readl(&rx->rx_sop, 0),
- musb_readl(&rx->rx_current, 0),
-
- musb_readl(&rx->rx_buf_current, 0),
- musb_readl(&rx->rx_len_len, 0),
- musb_readl(&rx->rx_cnt_cnt, 0),
- musb_readl(&rx->rx_complete, 0)
- );
-}
-
-/* Context: controller irqlocked */
-static void
-cppi_dump_tx(int level, struct cppi_channel *c, const char *tag)
-{
- void __iomem *base = c->controller->mregs;
- struct cppi_tx_stateram __iomem *tx = c->state_ram;
-
- musb_ep_select(base, c->index + 1);
-
- musb_dbg(c->controller->controller.musb,
- "TX DMA%d%s: csr %04x, "
- "H%08x S%08x C%08x %08x, "
- "F%08x L%08x .. %08x",
- c->index, tag,
- musb_readw(c->hw_ep->regs, MUSB_TXCSR),
-
- musb_readl(&tx->tx_head, 0),
- musb_readl(&tx->tx_buf, 0),
- musb_readl(&tx->tx_current, 0),
- musb_readl(&tx->tx_buf_current, 0),
-
- musb_readl(&tx->tx_info, 0),
- musb_readl(&tx->tx_rem_len, 0),
- /* dummy/unused word 6 */
- musb_readl(&tx->tx_complete, 0)
- );
-}
-
-/* Context: controller irqlocked */
-static inline void
-cppi_rndis_update(struct cppi_channel *c, int is_rx,
- void __iomem *tibase, int is_rndis)
-{
- /* we may need to change the rndis flag for this cppi channel */
- if (c->is_rndis != is_rndis) {
- u32 value = musb_readl(tibase, DAVINCI_RNDIS_REG);
- u32 temp = 1 << (c->index);
-
- if (is_rx)
- temp <<= 16;
- if (is_rndis)
- value |= temp;
- else
- value &= ~temp;
- musb_writel(tibase, DAVINCI_RNDIS_REG, value);
- c->is_rndis = is_rndis;
- }
-}
-
-static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd)
-{
- pr_debug("RXBD/%s %08x: "
- "nxt %08x buf %08x off.blen %08x opt.plen %08x\n",
- tag, bd->dma,
- bd->hw_next, bd->hw_bufp, bd->hw_off_len,
- bd->hw_options);
-}
-
-static void cppi_dump_rxq(int level, const char *tag, struct cppi_channel *rx)
-{
- struct cppi_descriptor *bd;
-
- cppi_dump_rx(level, rx, tag);
- if (rx->last_processed)
- cppi_dump_rxbd("last", rx->last_processed);
- for (bd = rx->head; bd; bd = bd->next)
- cppi_dump_rxbd("active", bd);
-}
-
-
-/* NOTE: DaVinci autoreq is ignored except for host side "RNDIS" mode RX;
- * so we won't ever use it (see "CPPI RX Woes" below).
- */
-static inline int cppi_autoreq_update(struct cppi_channel *rx,
- void __iomem *tibase, int onepacket, unsigned n_bds)
-{
- u32 val;
-
-#ifdef RNDIS_RX_IS_USABLE
- u32 tmp;
- /* assert(is_host_active(musb)) */
-
- /* start from "AutoReq never" */
- tmp = musb_readl(tibase, DAVINCI_AUTOREQ_REG);
- val = tmp & ~((0x3) << (rx->index * 2));
-
- /* HCD arranged reqpkt for packet #1. we arrange int
- * for all but the last one, maybe in two segments.
- */
- if (!onepacket) {
-#if 0
- /* use two segments, autoreq "all" then the last "never" */
- val |= ((0x3) << (rx->index * 2));
- n_bds--;
-#else
- /* one segment, autoreq "all-but-last" */
- val |= ((0x1) << (rx->index * 2));
-#endif
- }
-
- if (val != tmp) {
- int n = 100;
-
- /* make sure that autoreq is updated before continuing */
- musb_writel(tibase, DAVINCI_AUTOREQ_REG, val);
- do {
- tmp = musb_readl(tibase, DAVINCI_AUTOREQ_REG);
- if (tmp == val)
- break;
- cpu_relax();
- } while (n-- > 0);
- }
-#endif
-
- /* REQPKT is turned off after each segment */
- if (n_bds && rx->channel.actual_len) {
- void __iomem *regs = rx->hw_ep->regs;
-
- val = musb_readw(regs, MUSB_RXCSR);
- if (!(val & MUSB_RXCSR_H_REQPKT)) {
- val |= MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_H_WZC_BITS;
- musb_writew(regs, MUSB_RXCSR, val);
- /* flush writebuffer */
- val = musb_readw(regs, MUSB_RXCSR);
- }
- }
- return n_bds;
-}
-
-
-/* Buffer enqueuing Logic:
- *
- * - RX builds new queues each time, to help handle routine "early
- * termination" cases (faults, including errors and short reads)
- * more correctly.
- *
- * - for now, TX reuses the same queue of BDs every time
- *
- * REVISIT long term, we want a normal dynamic model.
- * ... the goal will be to append to the
- * existing queue, processing completed "dma buffers" (segments) on the fly.
- *
- * Otherwise we force an IRQ latency between requests, which slows us a lot
- * (especially in "transparent" dma). Unfortunately that model seems to be
- * inherent in the DMA model from the Mentor code, except in the rare case
- * of transfers big enough (~128+ KB) that we could append "middle" segments
- * in the TX paths. (RX can't do this, see below.)
- *
- * That's true even in the CPPI- friendly iso case, where most urbs have
- * several small segments provided in a group and where the "packet at a time"
- * "transparent" DMA model is always correct, even on the RX side.
- */
-
-/*
- * CPPI TX:
- * ========
- * TX is a lot more reasonable than RX; it doesn't need to run in
- * irq-per-packet mode very often. RNDIS mode seems to behave too
- * (except how it handles the exactly-N-packets case). Building a
- * txdma queue with multiple requests (urb or usb_request) looks
- * like it would work ... but fault handling would need much testing.
- *
- * The main issue with TX mode RNDIS relates to transfer lengths that
- * are an exact multiple of the packet length. It appears that there's
- * a hiccup in that case (maybe the DMA completes before the ZLP gets
- * written?) boiling down to not being able to rely on CPPI writing any
- * terminating zero length packet before the next transfer is written.
- * So that's punted to PIO; better yet, gadget drivers can avoid it.
- *
- * Plus, there's allegedly an undocumented constraint that rndis transfer
- * length be a multiple of 64 bytes ... but the chip doesn't act that
- * way, and we really don't _want_ that behavior anyway.
- *
- * On TX, "transparent" mode works ... although experiments have shown
- * problems trying to use the SOP/EOP bits in different USB packets.
- *
- * REVISIT try to handle terminating zero length packets using CPPI
- * instead of doing it by PIO after an IRQ. (Meanwhile, make Ethernet
- * links avoid that issue by forcing them to avoid zlps.)
- */
-static void
-cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx)
-{
- unsigned maxpacket = tx->maxpacket;
- dma_addr_t addr = tx->buf_dma + tx->offset;
- size_t length = tx->buf_len - tx->offset;
- struct cppi_descriptor *bd;
- unsigned n_bds;
- unsigned i;
- struct cppi_tx_stateram __iomem *tx_ram = tx->state_ram;
- int rndis;
-
- /* TX can use the CPPI "rndis" mode, where we can probably fit this
- * transfer in one BD and one IRQ. The only time we would NOT want
- * to use it is when hardware constraints prevent it, or if we'd
- * trigger the "send a ZLP?" confusion.
- */
- rndis = (maxpacket & 0x3f) == 0
- && length > maxpacket
- && length < 0xffff
- && (length % maxpacket) != 0;
-
- if (rndis) {
- maxpacket = length;
- n_bds = 1;
- } else {
- if (length)
- n_bds = DIV_ROUND_UP(length, maxpacket);
- else
- n_bds = 1;
- n_bds = min(n_bds, (unsigned) NUM_TXCHAN_BD);
- length = min(n_bds * maxpacket, length);
- }
-
- musb_dbg(musb, "TX DMA%d, pktSz %d %s bds %d dma 0x%llx len %u",
- tx->index,
- maxpacket,
- rndis ? "rndis" : "transparent",
- n_bds,
- (unsigned long long)addr, length);
-
- cppi_rndis_update(tx, 0, musb->ctrl_base, rndis);
-
- /* assuming here that channel_program is called during
- * transfer initiation ... current code maintains state
- * for one outstanding request only (no queues, not even
- * the implicit ones of an iso urb).
- */
-
- bd = tx->freelist;
- tx->head = bd;
- tx->last_processed = NULL;
-
- /* FIXME use BD pool like RX side does, and just queue
- * the minimum number for this request.
- */
-
- /* Prepare queue of BDs first, then hand it to hardware.
- * All BDs except maybe the last should be of full packet
- * size; for RNDIS there _is_ only that last packet.
- */
- for (i = 0; i < n_bds; ) {
- if (++i < n_bds && bd->next)
- bd->hw_next = bd->next->dma;
- else
- bd->hw_next = 0;
-
- bd->hw_bufp = tx->buf_dma + tx->offset;
-
- /* FIXME set EOP only on the last packet,
- * SOP only on the first ... avoid IRQs
- */
- if ((tx->offset + maxpacket) <= tx->buf_len) {
- tx->offset += maxpacket;
- bd->hw_off_len = maxpacket;
- bd->hw_options = CPPI_SOP_SET | CPPI_EOP_SET
- | CPPI_OWN_SET | maxpacket;
- } else {
- /* only this one may be a partial USB Packet */
- u32 partial_len;
-
- partial_len = tx->buf_len - tx->offset;
- tx->offset = tx->buf_len;
- bd->hw_off_len = partial_len;
-
- bd->hw_options = CPPI_SOP_SET | CPPI_EOP_SET
- | CPPI_OWN_SET | partial_len;
- if (partial_len == 0)
- bd->hw_options |= CPPI_ZERO_SET;
- }
-
- musb_dbg(musb, "TXBD %p: nxt %08x buf %08x len %04x opt %08x",
- bd, bd->hw_next, bd->hw_bufp,
- bd->hw_off_len, bd->hw_options);
-
- /* update the last BD enqueued to the list */
- tx->tail = bd;
- bd = bd->next;
- }
-
- /* BDs live in DMA-coherent memory, but writes might be pending */
- cpu_drain_writebuffer();
-
- /* Write to the HeadPtr in state RAM to trigger */
- musb_writel(&tx_ram->tx_head, 0, (u32)tx->freelist->dma);
-
- cppi_dump_tx(5, tx, "/S");
-}
-
-/*
- * CPPI RX Woes:
- * =============
- * Consider a 1KB bulk RX buffer in two scenarios: (a) it's fed two 300 byte
- * packets back-to-back, and (b) it's fed two 512 byte packets back-to-back.
- * (Full speed transfers have similar scenarios.)
- *
- * The correct behavior for Linux is that (a) fills the buffer with 300 bytes,
- * and the next packet goes into a buffer that's queued later; while (b) fills
- * the buffer with 1024 bytes. How to do that with CPPI?
- *
- * - RX queues in "rndis" mode -- one single BD -- handle (a) correctly, but
- * (b) loses **BADLY** because nothing (!) happens when that second packet
- * fills the buffer, much less when a third one arrives. (Which makes this
- * not a "true" RNDIS mode. In the RNDIS protocol short-packet termination
- * is optional, and it's fine if peripherals -- not hosts! -- pad messages
- * out to end-of-buffer. Standard PCI host controller DMA descriptors
- * implement that mode by default ... which is no accident.)
- *
- * - RX queues in "transparent" mode -- two BDs with 512 bytes each -- have
- * converse problems: (b) is handled right, but (a) loses badly. CPPI RX
- * ignores SOP/EOP markings and processes both of those BDs; so both packets
- * are loaded into the buffer (with a 212 byte gap between them), and the next
- * buffer queued will NOT get its 300 bytes of data. (It seems like SOP/EOP
- * are intended as outputs for RX queues, not inputs...)
- *
- * - A variant of "transparent" mode -- one BD at a time -- is the only way to
- * reliably make both cases work, with software handling both cases correctly
- * and at the significant penalty of needing an IRQ per packet. (The lack of
- * I/O overlap can be slightly ameliorated by enabling double buffering.)
- *
- * So how to get rid of IRQ-per-packet? The transparent multi-BD case could
- * be used in special cases like mass storage, which sets URB_SHORT_NOT_OK
- * (or maybe its peripheral side counterpart) to flag (a) scenarios as errors
- * with guaranteed driver level fault recovery and scrubbing out what's left
- * of that garbaged datastream.
- *
- * But there seems to be no way to identify the cases where CPPI RNDIS mode
- * is appropriate -- which do NOT include RNDIS host drivers, but do include
- * the CDC Ethernet driver! -- and the documentation is incomplete/wrong.
- * So we can't _ever_ use RX RNDIS mode ... except by using a heuristic
- * that applies best on the peripheral side (and which could fail rudely).
- *
- * Leaving only "transparent" mode; we avoid multi-bd modes in almost all
- * cases other than mass storage class. Otherwise we're correct but slow,
- * since CPPI penalizes our need for a "true RNDIS" default mode.
- */
-
-
-/* Heuristic, intended to kick in for ethernet/rndis peripheral ONLY
- *
- * IFF
- * (a) peripheral mode ... since rndis peripherals could pad their
- * writes to hosts, causing i/o failure; or we'd have to cope with
- * a largely unknowable variety of host side protocol variants
- * (b) and short reads are NOT errors ... since full reads would
- * cause those same i/o failures
- * (c) and read length is
- * - less than 64KB (max per cppi descriptor)
- * - not a multiple of 4096 (g_zero default, full reads typical)
- * - N (>1) packets long, ditto (full reads not EXPECTED)
- * THEN
- * try rx rndis mode
- *
- * Cost of heuristic failing: RXDMA wedges at the end of transfers that
- * fill out the whole buffer. Buggy host side usb network drivers could
- * trigger that, but "in the field" such bugs seem to be all but unknown.
- *
- * So this module parameter lets the heuristic be disabled. When using
- * gadgetfs, the heuristic will probably need to be disabled.
- */
-static bool cppi_rx_rndis = 1;
-
-module_param(cppi_rx_rndis, bool, 0);
-MODULE_PARM_DESC(cppi_rx_rndis, "enable/disable RX RNDIS heuristic");
-
-
-/**
- * cppi_next_rx_segment - dma read for the next chunk of a buffer
- * @musb: the controller
- * @rx: dma channel
- * @onepacket: true unless caller treats short reads as errors, and
- * performs fault recovery above usbcore.
- * Context: controller irqlocked
- *
- * See above notes about why we can't use multi-BD RX queues except in
- * rare cases (mass storage class), and can never use the hardware "rndis"
- * mode (since it's not a "true" RNDIS mode) with complete safety..
- *
- * It's ESSENTIAL that callers specify "onepacket" mode unless they kick in
- * code to recover from corrupted datastreams after each short transfer.
- */
-static void
-cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
-{
- unsigned maxpacket = rx->maxpacket;
- dma_addr_t addr = rx->buf_dma + rx->offset;
- size_t length = rx->buf_len - rx->offset;
- struct cppi_descriptor *bd, *tail;
- unsigned n_bds;
- unsigned i;
- void __iomem *tibase = musb->ctrl_base;
- int is_rndis = 0;
- struct cppi_rx_stateram __iomem *rx_ram = rx->state_ram;
- struct cppi_descriptor *d;
-
- if (onepacket) {
- /* almost every USB driver, host or peripheral side */
- n_bds = 1;
-
- /* maybe apply the heuristic above */
- if (cppi_rx_rndis
- && is_peripheral_active(musb)
- && length > maxpacket
- && (length & ~0xffff) == 0
- && (length & 0x0fff) != 0
- && (length & (maxpacket - 1)) == 0) {
- maxpacket = length;
- is_rndis = 1;
- }
- } else {
- /* virtually nothing except mass storage class */
- if (length > 0xffff) {
- n_bds = 0xffff / maxpacket;
- length = n_bds * maxpacket;
- } else {
- n_bds = DIV_ROUND_UP(length, maxpacket);
- }
- if (n_bds == 1)
- onepacket = 1;
- else
- n_bds = min(n_bds, (unsigned) NUM_RXCHAN_BD);
- }
-
- /* In host mode, autorequest logic can generate some IN tokens; it's
- * tricky since we can't leave REQPKT set in RXCSR after the transfer
- * finishes. So: multipacket transfers involve two or more segments.
- * And always at least two IRQs ... RNDIS mode is not an option.
- */
- if (is_host_active(musb))
- n_bds = cppi_autoreq_update(rx, tibase, onepacket, n_bds);
-
- cppi_rndis_update(rx, 1, musb->ctrl_base, is_rndis);
-
- length = min(n_bds * maxpacket, length);
-
- musb_dbg(musb, "RX DMA%d seg, maxp %d %s bds %d (cnt %d) "
- "dma 0x%llx len %u %u/%u",
- rx->index, maxpacket,
- onepacket
- ? (is_rndis ? "rndis" : "onepacket")
- : "multipacket",
- n_bds,
- musb_readl(tibase,
- DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4))
- & 0xffff,
- (unsigned long long)addr, length,
- rx->channel.actual_len, rx->buf_len);
-
- /* only queue one segment at a time, since the hardware prevents
- * correct queue shutdown after unexpected short packets
- */
- bd = cppi_bd_alloc(rx);
- rx->head = bd;
-
- /* Build BDs for all packets in this segment */
- for (i = 0, tail = NULL; bd && i < n_bds; i++, tail = bd) {
- u32 bd_len;
-
- if (i) {
- bd = cppi_bd_alloc(rx);
- if (!bd)
- break;
- tail->next = bd;
- tail->hw_next = bd->dma;
- }
- bd->hw_next = 0;
-
- /* all but the last packet will be maxpacket size */
- if (maxpacket < length)
- bd_len = maxpacket;
- else
- bd_len = length;
-
- bd->hw_bufp = addr;
- addr += bd_len;
- rx->offset += bd_len;
-
- bd->hw_off_len = (0 /*offset*/ << 16) + bd_len;
- bd->buflen = bd_len;
-
- bd->hw_options = CPPI_OWN_SET | (i == 0 ? length : 0);
- length -= bd_len;
- }
-
- /* we always expect at least one reusable BD! */
- if (!tail) {
- WARNING("rx dma%d -- no BDs? need %d\n", rx->index, n_bds);
- return;
- } else if (i < n_bds)
- WARNING("rx dma%d -- only %d of %d BDs\n", rx->index, i, n_bds);
-
- tail->next = NULL;
- tail->hw_next = 0;
-
- bd = rx->head;
- rx->tail = tail;
-
- /* short reads and other faults should terminate this entire
- * dma segment. we want one "dma packet" per dma segment, not
- * one per USB packet, terminating the whole queue at once...
- * NOTE that current hardware seems to ignore SOP and EOP.
- */
- bd->hw_options |= CPPI_SOP_SET;
- tail->hw_options |= CPPI_EOP_SET;
-
- for (d = rx->head; d; d = d->next)
- cppi_dump_rxbd("S", d);
-
- /* in case the preceding transfer left some state... */
- tail = rx->last_processed;
- if (tail) {
- tail->next = bd;
- tail->hw_next = bd->dma;
- }
-
- core_rxirq_enable(tibase, rx->index + 1);
-
- /* BDs live in DMA-coherent memory, but writes might be pending */
- cpu_drain_writebuffer();
-
- /* REVISIT specs say to write this AFTER the BUFCNT register
- * below ... but that loses badly.
- */
- musb_writel(&rx_ram->rx_head, 0, bd->dma);
-
- /* bufferCount must be at least 3, and zeroes on completion
- * unless it underflows below zero, or stops at two, or keeps
- * growing ... grr.
- */
- i = musb_readl(tibase,
- DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4))
- & 0xffff;
-
- if (!i)
- musb_writel(tibase,
- DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4),
- n_bds + 2);
- else if (n_bds > (i - 3))
- musb_writel(tibase,
- DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4),
- n_bds - (i - 3));
-
- i = musb_readl(tibase,
- DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4))
- & 0xffff;
- if (i < (2 + n_bds)) {
- musb_dbg(musb, "bufcnt%d underrun - %d (for %d)",
- rx->index, i, n_bds);
- musb_writel(tibase,
- DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4),
- n_bds + 2);
- }
-
- cppi_dump_rx(4, rx, "/S");
-}
-
-/**
- * cppi_channel_program - program channel for data transfer
- * @ch: the channel
- * @maxpacket: max packet size
- * @mode: For RX, 1 unless the usb protocol driver promised to treat
- * all short reads as errors and kick in high level fault recovery.
- * For TX, ignored because of RNDIS mode races/glitches.
- * @dma_addr: dma address of buffer
- * @len: length of buffer
- * Context: controller irqlocked
- */
-static int cppi_channel_program(struct dma_channel *ch,
- u16 maxpacket, u8 mode,
- dma_addr_t dma_addr, u32 len)
-{
- struct cppi_channel *cppi_ch;
- struct cppi *controller;
- struct musb *musb;
-
- cppi_ch = container_of(ch, struct cppi_channel, channel);
- controller = cppi_ch->controller;
- musb = controller->controller.musb;
-
- switch (ch->status) {
- case MUSB_DMA_STATUS_BUS_ABORT:
- case MUSB_DMA_STATUS_CORE_ABORT:
- /* fault irq handler should have handled cleanup */
- WARNING("%cX DMA%d not cleaned up after abort!\n",
- cppi_ch->transmit ? 'T' : 'R',
- cppi_ch->index);
- /* WARN_ON(1); */
- break;
- case MUSB_DMA_STATUS_BUSY:
- WARNING("program active channel? %cX DMA%d\n",
- cppi_ch->transmit ? 'T' : 'R',
- cppi_ch->index);
- /* WARN_ON(1); */
- break;
- case MUSB_DMA_STATUS_UNKNOWN:
- musb_dbg(musb, "%cX DMA%d not allocated!",
- cppi_ch->transmit ? 'T' : 'R',
- cppi_ch->index);
- fallthrough;
- case MUSB_DMA_STATUS_FREE:
- break;
- }
-
- ch->status = MUSB_DMA_STATUS_BUSY;
-
- /* set transfer parameters, then queue up its first segment */
- cppi_ch->buf_dma = dma_addr;
- cppi_ch->offset = 0;
- cppi_ch->maxpacket = maxpacket;
- cppi_ch->buf_len = len;
- cppi_ch->channel.actual_len = 0;
-
- /* TX channel? or RX? */
- if (cppi_ch->transmit)
- cppi_next_tx_segment(musb, cppi_ch);
- else
- cppi_next_rx_segment(musb, cppi_ch, mode);
-
- return true;
-}
-
-static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
-{
- struct cppi_channel *rx = &cppi->rx[ch];
- struct cppi_rx_stateram __iomem *state = rx->state_ram;
- struct cppi_descriptor *bd;
- struct cppi_descriptor *last = rx->last_processed;
- bool completed = false;
- bool acked = false;
- int i;
- dma_addr_t safe2ack;
- void __iomem *regs = rx->hw_ep->regs;
- struct musb *musb = cppi->controller.musb;
-
- cppi_dump_rx(6, rx, "/K");
-
- bd = last ? last->next : rx->head;
- if (!bd)
- return false;
-
- /* run through all completed BDs */
- for (i = 0, safe2ack = musb_readl(&state->rx_complete, 0);
- (safe2ack || completed) && bd && i < NUM_RXCHAN_BD;
- i++, bd = bd->next) {
- u16 len;
-
- /* catch latest BD writes from CPPI */
- rmb();
- if (!completed && (bd->hw_options & CPPI_OWN_SET))
- break;
-
- musb_dbg(musb, "C/RXBD %llx: nxt %08x buf %08x "
- "off.len %08x opt.len %08x (%d)",
- (unsigned long long)bd->dma, bd->hw_next, bd->hw_bufp,
- bd->hw_off_len, bd->hw_options,
- rx->channel.actual_len);
-
- /* actual packet received length */
- if ((bd->hw_options & CPPI_SOP_SET) && !completed)
- len = bd->hw_off_len & CPPI_RECV_PKTLEN_MASK;
- else
- len = 0;
-
- if (bd->hw_options & CPPI_EOQ_MASK)
- completed = true;
-
- if (!completed && len < bd->buflen) {
- /* NOTE: when we get a short packet, RXCSR_H_REQPKT
- * must have been cleared, and no more DMA packets may
- * active be in the queue... TI docs didn't say, but
- * CPPI ignores those BDs even though OWN is still set.
- */
- completed = true;
- musb_dbg(musb, "rx short %d/%d (%d)",
- len, bd->buflen,
- rx->channel.actual_len);
- }
-
- /* If we got here, we expect to ack at least one BD; meanwhile
- * CPPI may completing other BDs while we scan this list...
- *
- * RACE: we can notice OWN cleared before CPPI raises the
- * matching irq by writing that BD as the completion pointer.
- * In such cases, stop scanning and wait for the irq, avoiding
- * lost acks and states where BD ownership is unclear.
- */
- if (bd->dma == safe2ack) {
- musb_writel(&state->rx_complete, 0, safe2ack);
- safe2ack = musb_readl(&state->rx_complete, 0);
- acked = true;
- if (bd->dma == safe2ack)
- safe2ack = 0;
- }
-
- rx->channel.actual_len += len;
-
- cppi_bd_free(rx, last);
- last = bd;
-
- /* stop scanning on end-of-segment */
- if (bd->hw_next == 0)
- completed = true;
- }
- rx->last_processed = last;
-
- /* dma abort, lost ack, or ... */
- if (!acked && last) {
- int csr;
-
- if (safe2ack == 0 || safe2ack == rx->last_processed->dma)
- musb_writel(&state->rx_complete, 0, safe2ack);
- if (safe2ack == 0) {
- cppi_bd_free(rx, last);
- rx->last_processed = NULL;
-
- /* if we land here on the host side, H_REQPKT will
- * be clear and we need to restart the queue...
- */
- WARN_ON(rx->head);
- }
- musb_ep_select(cppi->mregs, rx->index + 1);
- csr = musb_readw(regs, MUSB_RXCSR);
- if (csr & MUSB_RXCSR_DMAENAB) {
- musb_dbg(musb, "list%d %p/%p, last %llx%s, csr %04x",
- rx->index,
- rx->head, rx->tail,
- rx->last_processed
- ? (unsigned long long)
- rx->last_processed->dma
- : 0,
- completed ? ", completed" : "",
- csr);
- cppi_dump_rxq(4, "/what?", rx);
- }
- }
- if (!completed) {
- int csr;
-
- rx->head = bd;
-
- /* REVISIT seems like "autoreq all but EOP" doesn't...
- * setting it here "should" be racey, but seems to work
- */
- csr = musb_readw(rx->hw_ep->regs, MUSB_RXCSR);
- if (is_host_active(cppi->controller.musb)
- && bd
- && !(csr & MUSB_RXCSR_H_REQPKT)) {
- csr |= MUSB_RXCSR_H_REQPKT;
- musb_writew(regs, MUSB_RXCSR,
- MUSB_RXCSR_H_WZC_BITS | csr);
- csr = musb_readw(rx->hw_ep->regs, MUSB_RXCSR);
- }
- } else {
- rx->head = NULL;
- rx->tail = NULL;
- }
-
- cppi_dump_rx(6, rx, completed ? "/completed" : "/cleaned");
- return completed;
-}
-
-irqreturn_t cppi_interrupt(int irq, void *dev_id)
-{
- struct musb *musb = dev_id;
- struct cppi *cppi;
- void __iomem *tibase;
- struct musb_hw_ep *hw_ep = NULL;
- u32 rx, tx;
- int i, index;
- unsigned long flags;
-
- cppi = container_of(musb->dma_controller, struct cppi, controller);
- if (cppi->irq)
- spin_lock_irqsave(&musb->lock, flags);
-
- tibase = musb->ctrl_base;
-
- tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
- rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
-
- if (!tx && !rx) {
- if (cppi->irq)
- spin_unlock_irqrestore(&musb->lock, flags);
- return IRQ_NONE;
- }
-
- musb_dbg(musb, "CPPI IRQ Tx%x Rx%x", tx, rx);
-
- /* process TX channels */
- for (index = 0; tx; tx = tx >> 1, index++) {
- struct cppi_channel *tx_ch;
- struct cppi_tx_stateram __iomem *tx_ram;
- bool completed = false;
- struct cppi_descriptor *bd;
-
- if (!(tx & 1))
- continue;
-
- tx_ch = cppi->tx + index;
- tx_ram = tx_ch->state_ram;
-
- /* FIXME need a cppi_tx_scan() routine, which
- * can also be called from abort code
- */
-
- cppi_dump_tx(5, tx_ch, "/E");
-
- bd = tx_ch->head;
-
- /*
- * If Head is null then this could mean that a abort interrupt
- * that needs to be acknowledged.
- */
- if (NULL == bd) {
- musb_dbg(musb, "null BD");
- musb_writel(&tx_ram->tx_complete, 0, 0);
- continue;
- }
-
- /* run through all completed BDs */
- for (i = 0; !completed && bd && i < NUM_TXCHAN_BD;
- i++, bd = bd->next) {
- u16 len;
-
- /* catch latest BD writes from CPPI */
- rmb();
- if (bd->hw_options & CPPI_OWN_SET)
- break;
-
- musb_dbg(musb, "C/TXBD %p n %x b %x off %x opt %x",
- bd, bd->hw_next, bd->hw_bufp,
- bd->hw_off_len, bd->hw_options);
-
- len = bd->hw_off_len & CPPI_BUFFER_LEN_MASK;
- tx_ch->channel.actual_len += len;
-
- tx_ch->last_processed = bd;
-
- /* write completion register to acknowledge
- * processing of completed BDs, and possibly
- * release the IRQ; EOQ might not be set ...
- *
- * REVISIT use the same ack strategy as rx
- *
- * REVISIT have observed bit 18 set; huh??
- */
- /* if ((bd->hw_options & CPPI_EOQ_MASK)) */
- musb_writel(&tx_ram->tx_complete, 0, bd->dma);
-
- /* stop scanning on end-of-segment */
- if (bd->hw_next == 0)
- completed = true;
- }
-
- /* on end of segment, maybe go to next one */
- if (completed) {
- /* cppi_dump_tx(4, tx_ch, "/complete"); */
-
- /* transfer more, or report completion */
- if (tx_ch->offset >= tx_ch->buf_len) {
- tx_ch->head = NULL;
- tx_ch->tail = NULL;
- tx_ch->channel.status = MUSB_DMA_STATUS_FREE;
-
- hw_ep = tx_ch->hw_ep;
-
- musb_dma_completion(musb, index + 1, 1);
-
- } else {
- /* Bigger transfer than we could fit in
- * that first batch of descriptors...
- */
- cppi_next_tx_segment(musb, tx_ch);
- }
- } else
- tx_ch->head = bd;
- }
-
- /* Start processing the RX block */
- for (index = 0; rx; rx = rx >> 1, index++) {
-
- if (rx & 1) {
- struct cppi_channel *rx_ch;
-
- rx_ch = cppi->rx + index;
-
- /* let incomplete dma segments finish */
- if (!cppi_rx_scan(cppi, index))
- continue;
-
- /* start another dma segment if needed */
- if (rx_ch->channel.actual_len != rx_ch->buf_len
- && rx_ch->channel.actual_len
- == rx_ch->offset) {
- cppi_next_rx_segment(musb, rx_ch, 1);
- continue;
- }
-
- /* all segments completed! */
- rx_ch->channel.status = MUSB_DMA_STATUS_FREE;
-
- hw_ep = rx_ch->hw_ep;
-
- core_rxirq_disable(tibase, index + 1);
- musb_dma_completion(musb, index + 1, 0);
- }
- }
-
- /* write to CPPI EOI register to re-enable interrupts */
- musb_writel(tibase, DAVINCI_CPPI_EOI_REG, 0);
-
- if (cppi->irq)
- spin_unlock_irqrestore(&musb->lock, flags);
-
- return IRQ_HANDLED;
-}
-EXPORT_SYMBOL_GPL(cppi_interrupt);
-
-/* Instantiate a software object representing a DMA controller. */
-struct dma_controller *
-cppi_dma_controller_create(struct musb *musb, void __iomem *mregs)
-{
- struct cppi *controller;
- struct device *dev = musb->controller;
- struct platform_device *pdev = to_platform_device(dev);
- int irq = platform_get_irq_byname(pdev, "dma");
-
- controller = kzalloc(sizeof *controller, GFP_KERNEL);
- if (!controller)
- return NULL;
-
- controller->mregs = mregs;
- controller->tibase = mregs - DAVINCI_BASE_OFFSET;
-
- controller->controller.musb = musb;
- controller->controller.channel_alloc = cppi_channel_allocate;
- controller->controller.channel_release = cppi_channel_release;
- controller->controller.channel_program = cppi_channel_program;
- controller->controller.channel_abort = cppi_channel_abort;
-
- /* NOTE: allocating from on-chip SRAM would give the least
- * contention for memory access, if that ever matters here.
- */
-
- /* setup BufferPool */
- controller->pool = dma_pool_create("cppi",
- controller->controller.musb->controller,
- sizeof(struct cppi_descriptor),
- CPPI_DESCRIPTOR_ALIGN, 0);
- if (!controller->pool) {
- kfree(controller);
- return NULL;
- }
-
- if (irq > 0) {
- if (request_irq(irq, cppi_interrupt, 0, "cppi-dma", musb)) {
- dev_err(dev, "request_irq %d failed!\n", irq);
- musb_dma_controller_destroy(&controller->controller);
- return NULL;
- }
- controller->irq = irq;
- }
-
- cppi_controller_start(controller);
- return &controller->controller;
-}
-EXPORT_SYMBOL_GPL(cppi_dma_controller_create);
-
-/*
- * Destroy a previously-instantiated DMA controller.
- */
-void cppi_dma_controller_destroy(struct dma_controller *c)
-{
- struct cppi *cppi;
-
- cppi = container_of(c, struct cppi, controller);
-
- cppi_controller_stop(cppi);
-
- if (cppi->irq)
- free_irq(cppi->irq, cppi->controller.musb);
-
- /* assert: caller stopped the controller first */
- dma_pool_destroy(cppi->pool);
-
- kfree(cppi);
-}
-EXPORT_SYMBOL_GPL(cppi_dma_controller_destroy);
-
-/*
- * Context: controller irqlocked, endpoint selected
- */
-static int cppi_channel_abort(struct dma_channel *channel)
-{
- struct cppi_channel *cppi_ch;
- struct cppi *controller;
- void __iomem *mbase;
- void __iomem *tibase;
- void __iomem *regs;
- u32 value;
- struct cppi_descriptor *queue;
-
- cppi_ch = container_of(channel, struct cppi_channel, channel);
-
- controller = cppi_ch->controller;
-
- switch (channel->status) {
- case MUSB_DMA_STATUS_BUS_ABORT:
- case MUSB_DMA_STATUS_CORE_ABORT:
- /* from RX or TX fault irq handler */
- case MUSB_DMA_STATUS_BUSY:
- /* the hardware needs shutting down */
- regs = cppi_ch->hw_ep->regs;
- break;
- case MUSB_DMA_STATUS_UNKNOWN:
- case MUSB_DMA_STATUS_FREE:
- return 0;
- default:
- return -EINVAL;
- }
-
- if (!cppi_ch->transmit && cppi_ch->head)
- cppi_dump_rxq(3, "/abort", cppi_ch);
-
- mbase = controller->mregs;
- tibase = controller->tibase;
-
- queue = cppi_ch->head;
- cppi_ch->head = NULL;
- cppi_ch->tail = NULL;
-
- /* REVISIT should rely on caller having done this,
- * and caller should rely on us not changing it.
- * peripheral code is safe ... check host too.
- */
- musb_ep_select(mbase, cppi_ch->index + 1);
-
- if (cppi_ch->transmit) {
- struct cppi_tx_stateram __iomem *tx_ram;
- /* REVISIT put timeouts on these controller handshakes */
-
- cppi_dump_tx(6, cppi_ch, " (teardown)");
-
- /* teardown DMA engine then usb core */
- do {
- value = musb_readl(tibase, DAVINCI_TXCPPI_TEAR_REG);
- } while (!(value & CPPI_TEAR_READY));
- musb_writel(tibase, DAVINCI_TXCPPI_TEAR_REG, cppi_ch->index);
-
- tx_ram = cppi_ch->state_ram;
- do {
- value = musb_readl(&tx_ram->tx_complete, 0);
- } while (0xFFFFFFFC != value);
-
- /* FIXME clean up the transfer state ... here?
- * the completion routine should get called with
- * an appropriate status code.
- */
-
- value = musb_readw(regs, MUSB_TXCSR);
- value &= ~MUSB_TXCSR_DMAENAB;
- value |= MUSB_TXCSR_FLUSHFIFO;
- musb_writew(regs, MUSB_TXCSR, value);
- musb_writew(regs, MUSB_TXCSR, value);
-
- /*
- * 1. Write to completion Ptr value 0x1(bit 0 set)
- * (write back mode)
- * 2. Wait for abort interrupt and then put the channel in
- * compare mode by writing 1 to the tx_complete register.
- */
- cppi_reset_tx(tx_ram, 1);
- cppi_ch->head = NULL;
- musb_writel(&tx_ram->tx_complete, 0, 1);
- cppi_dump_tx(5, cppi_ch, " (done teardown)");
-
- /* REVISIT tx side _should_ clean up the same way
- * as the RX side ... this does no cleanup at all!
- */
-
- } else /* RX */ {
- u16 csr;
-
- /* NOTE: docs don't guarantee any of this works ... we
- * expect that if the usb core stops telling the cppi core
- * to pull more data from it, then it'll be safe to flush
- * current RX DMA state iff any pending fifo transfer is done.
- */
-
- core_rxirq_disable(tibase, cppi_ch->index + 1);
-
- /* for host, ensure ReqPkt is never set again */
- if (is_host_active(cppi_ch->controller->controller.musb)) {
- value = musb_readl(tibase, DAVINCI_AUTOREQ_REG);
- value &= ~((0x3) << (cppi_ch->index * 2));
- musb_writel(tibase, DAVINCI_AUTOREQ_REG, value);
- }
-
- csr = musb_readw(regs, MUSB_RXCSR);
-
- /* for host, clear (just) ReqPkt at end of current packet(s) */
- if (is_host_active(cppi_ch->controller->controller.musb)) {
- csr |= MUSB_RXCSR_H_WZC_BITS;
- csr &= ~MUSB_RXCSR_H_REQPKT;
- } else
- csr |= MUSB_RXCSR_P_WZC_BITS;
-
- /* clear dma enable */
- csr &= ~(MUSB_RXCSR_DMAENAB);
- musb_writew(regs, MUSB_RXCSR, csr);
- csr = musb_readw(regs, MUSB_RXCSR);
-
- /* Quiesce: wait for current dma to finish (if not cleanup).
- * We can't use bit zero of stateram->rx_sop, since that
- * refers to an entire "DMA packet" not just emptying the
- * current fifo. Most segments need multiple usb packets.
- */
- if (channel->status == MUSB_DMA_STATUS_BUSY)
- udelay(50);
-
- /* scan the current list, reporting any data that was
- * transferred and acking any IRQ
- */
- cppi_rx_scan(controller, cppi_ch->index);
-
- /* clobber the existing state once it's idle
- *
- * NOTE: arguably, we should also wait for all the other
- * RX channels to quiesce (how??) and then temporarily
- * disable RXCPPI_CTRL_REG ... but it seems that we can
- * rely on the controller restarting from state ram, with
- * only RXCPPI_BUFCNT state being bogus. BUFCNT will
- * correct itself after the next DMA transfer though.
- *
- * REVISIT does using rndis mode change that?
- */
- cppi_reset_rx(cppi_ch->state_ram);
-
- /* next DMA request _should_ load cppi head ptr */
-
- /* ... we don't "free" that list, only mutate it in place. */
- cppi_dump_rx(5, cppi_ch, " (done abort)");
-
- /* clean up previously pending bds */
- cppi_bd_free(cppi_ch, cppi_ch->last_processed);
- cppi_ch->last_processed = NULL;
-
- while (queue) {
- struct cppi_descriptor *tmp = queue->next;
-
- cppi_bd_free(cppi_ch, queue);
- queue = tmp;
- }
- }
-
- channel->status = MUSB_DMA_STATUS_FREE;
- cppi_ch->buf_dma = 0;
- cppi_ch->offset = 0;
- cppi_ch->buf_len = 0;
- cppi_ch->maxpacket = 0;
- return 0;
-}
-
-/* TBD Queries:
- *
- * Power Management ... probably turn off cppi during suspend, restart;
- * check state ram? Clocking is presumably shared with usb core.
- */
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
deleted file mode 100644
index 704435526394..000000000000
--- a/drivers/usb/musb/davinci.c
+++ /dev/null
@@ -1,606 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2005-2006 by Texas Instruments
- *
- * This file is part of the Inventra Controller Driver for Linux.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/gpio/consumer.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/usb/usb_phy_generic.h>
-
-#include <mach/cputype.h>
-#include <mach/hardware.h>
-
-#include <asm/mach-types.h>
-
-#include "musb_core.h"
-
-#include "davinci.h"
-#include "cppi_dma.h"
-
-
-#define USB_PHY_CTRL IO_ADDRESS(USBPHY_CTL_PADDR)
-#define DM355_DEEPSLEEP IO_ADDRESS(DM355_DEEPSLEEP_PADDR)
-
-struct davinci_glue {
- struct device *dev;
- struct platform_device *musb;
- struct clk *clk;
- bool vbus_state;
- struct gpio_desc *vbus;
- struct work_struct vbus_work;
-};
-
-/* REVISIT (PM) we should be able to keep the PHY in low power mode most
- * of the time (24 MHZ oscillator and PLL off, etc) by setting POWER.D0
- * and, when in host mode, autosuspending idle root ports... PHYPLLON
- * (overriding SUSPENDM?) then likely needs to stay off.
- */
-
-static inline void phy_on(void)
-{
- u32 phy_ctrl = __raw_readl(USB_PHY_CTRL);
-
- /* power everything up; start the on-chip PHY and its PLL */
- phy_ctrl &= ~(USBPHY_OSCPDWN | USBPHY_OTGPDWN | USBPHY_PHYPDWN);
- phy_ctrl |= USBPHY_SESNDEN | USBPHY_VBDTCTEN | USBPHY_PHYPLLON;
- __raw_writel(phy_ctrl, USB_PHY_CTRL);
-
- /* wait for PLL to lock before proceeding */
- while ((__raw_readl(USB_PHY_CTRL) & USBPHY_PHYCLKGD) == 0)
- cpu_relax();
-}
-
-static inline void phy_off(void)
-{
- u32 phy_ctrl = __raw_readl(USB_PHY_CTRL);
-
- /* powerdown the on-chip PHY, its PLL, and the OTG block */
- phy_ctrl &= ~(USBPHY_SESNDEN | USBPHY_VBDTCTEN | USBPHY_PHYPLLON);
- phy_ctrl |= USBPHY_OSCPDWN | USBPHY_OTGPDWN | USBPHY_PHYPDWN;
- __raw_writel(phy_ctrl, USB_PHY_CTRL);
-}
-
-static int dma_off = 1;
-
-static void davinci_musb_enable(struct musb *musb)
-{
- u32 tmp, old, val;
-
- /* workaround: setup irqs through both register sets */
- tmp = (musb->epmask & DAVINCI_USB_TX_ENDPTS_MASK)
- << DAVINCI_USB_TXINT_SHIFT;
- musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp);
- old = tmp;
- tmp = (musb->epmask & (0xfffe & DAVINCI_USB_RX_ENDPTS_MASK))
- << DAVINCI_USB_RXINT_SHIFT;
- musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp);
- tmp |= old;
-
- val = ~MUSB_INTR_SOF;
- tmp |= ((val & 0x01ff) << DAVINCI_USB_USBINT_SHIFT);
- musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp);
-
- if (is_dma_capable() && !dma_off)
- printk(KERN_WARNING "%s %s: dma not reactivated\n",
- __FILE__, __func__);
- else
- dma_off = 0;
-
- /* force a DRVVBUS irq so we can start polling for ID change */
- musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
- DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT);
-}
-
-/*
- * Disable the HDRC and flush interrupts
- */
-static void davinci_musb_disable(struct musb *musb)
-{
- /* because we don't set CTRLR.UINT, "important" to:
- * - not read/write INTRUSB/INTRUSBE
- * - (except during initial setup, as workaround)
- * - use INTSETR/INTCLRR instead
- */
- musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_CLR_REG,
- DAVINCI_USB_USBINT_MASK
- | DAVINCI_USB_TXINT_MASK
- | DAVINCI_USB_RXINT_MASK);
- musb_writel(musb->ctrl_base, DAVINCI_USB_EOI_REG, 0);
-
- if (is_dma_capable() && !dma_off)
- WARNING("dma still active\n");
-}
-
-
-#define portstate(stmt) stmt
-
-/*
- * VBUS SWITCHING IS BOARD-SPECIFIC ... at least for the DM6446 EVM,
- * which doesn't wire DRVVBUS to the FET that switches it. Unclear
- * if that's a problem with the DM6446 chip or just with that board.
- *
- * In either case, the DM355 EVM automates DRVVBUS the normal way,
- * when J10 is out, and TI documents it as handling OTG.
- */
-
-/* I2C operations are always synchronous, and require a task context.
- * With unloaded systems, using the shared workqueue seems to suffice
- * to satisfy the 100msec A_WAIT_VRISE timeout...
- */
-static void evm_deferred_drvvbus(struct work_struct *work)
-{
- struct davinci_glue *glue = container_of(work, struct davinci_glue,
- vbus_work);
-
- gpiod_set_value_cansleep(glue->vbus, glue->vbus_state);
- glue->vbus_state = !glue->vbus_state;
-}
-
-static void davinci_musb_source_power(struct musb *musb, int is_on,
- int immediate)
-{
- struct davinci_glue *glue = dev_get_drvdata(musb->controller->parent);
-
- /* This GPIO handling is entirely optional */
- if (!glue->vbus)
- return;
-
- if (is_on)
- is_on = 1;
-
- if (glue->vbus_state == is_on)
- return;
- /* 0/1 vs "-1 == unknown/init" */
- glue->vbus_state = !is_on;
-
- if (machine_is_davinci_evm()) {
- if (immediate)
- gpiod_set_value_cansleep(glue->vbus, glue->vbus_state);
- else
- schedule_work(&glue->vbus_work);
- }
- if (immediate)
- glue->vbus_state = is_on;
-}
-
-static void davinci_musb_set_vbus(struct musb *musb, int is_on)
-{
- WARN_ON(is_on && is_peripheral_active(musb));
- davinci_musb_source_power(musb, is_on, 0);
-}
-
-
-#define POLL_SECONDS 2
-
-static void otg_timer(struct timer_list *t)
-{
- struct musb *musb = from_timer(musb, t, dev_timer);
- void __iomem *mregs = musb->mregs;
- u8 devctl;
- unsigned long flags;
-
- /* We poll because DaVinci's won't expose several OTG-critical
- * status change events (from the transceiver) otherwise.
- */
- devctl = musb_readb(mregs, MUSB_DEVCTL);
- dev_dbg(musb->controller, "poll devctl %02x (%s)\n", devctl,
- usb_otg_state_string(musb->xceiv->otg->state));
-
- spin_lock_irqsave(&musb->lock, flags);
- switch (musb->xceiv->otg->state) {
- case OTG_STATE_A_WAIT_VFALL:
- /* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL
- * seems to mis-handle session "start" otherwise (or in our
- * case "recover"), in routine "VBUS was valid by the time
- * VBUSERR got reported during enumeration" cases.
- */
- if (devctl & MUSB_DEVCTL_VBUS) {
- mod_timer(&musb->dev_timer, jiffies + POLL_SECONDS * HZ);
- break;
- }
- musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
- musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
- MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT);
- break;
- case OTG_STATE_B_IDLE:
- /*
- * There's no ID-changed IRQ, so we have no good way to tell
- * when to switch to the A-Default state machine (by setting
- * the DEVCTL.SESSION flag).
- *
- * Workaround: whenever we're in B_IDLE, try setting the
- * session flag every few seconds. If it works, ID was
- * grounded and we're now in the A-Default state machine.
- *
- * NOTE setting the session flag is _supposed_ to trigger
- * SRP, but clearly it doesn't.
- */
- musb_writeb(mregs, MUSB_DEVCTL,
- devctl | MUSB_DEVCTL_SESSION);
- devctl = musb_readb(mregs, MUSB_DEVCTL);
- if (devctl & MUSB_DEVCTL_BDEVICE)
- mod_timer(&musb->dev_timer, jiffies + POLL_SECONDS * HZ);
- else
- musb->xceiv->otg->state = OTG_STATE_A_IDLE;
- break;
- default:
- break;
- }
- spin_unlock_irqrestore(&musb->lock, flags);
-}
-
-static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
-{
- unsigned long flags;
- irqreturn_t retval = IRQ_NONE;
- struct musb *musb = __hci;
- struct usb_otg *otg = musb->xceiv->otg;
- void __iomem *tibase = musb->ctrl_base;
- struct cppi *cppi;
- u32 tmp;
-
- spin_lock_irqsave(&musb->lock, flags);
-
- /* NOTE: DaVinci shadows the Mentor IRQs. Don't manage them through
- * the Mentor registers (except for setup), use the TI ones and EOI.
- *
- * Docs describe irq "vector" registers associated with the CPPI and
- * USB EOI registers. These hold a bitmask corresponding to the
- * current IRQ, not an irq handler address. Would using those bits
- * resolve some of the races observed in this dispatch code??
- */
-
- /* CPPI interrupts share the same IRQ line, but have their own
- * mask, state, "vector", and EOI registers.
- */
- cppi = container_of(musb->dma_controller, struct cppi, controller);
- if (is_cppi_enabled(musb) && musb->dma_controller && !cppi->irq)
- retval = cppi_interrupt(irq, __hci);
-
- /* ack and handle non-CPPI interrupts */
- tmp = musb_readl(tibase, DAVINCI_USB_INT_SRC_MASKED_REG);
- musb_writel(tibase, DAVINCI_USB_INT_SRC_CLR_REG, tmp);
- dev_dbg(musb->controller, "IRQ %08x\n", tmp);
-
- musb->int_rx = (tmp & DAVINCI_USB_RXINT_MASK)
- >> DAVINCI_USB_RXINT_SHIFT;
- musb->int_tx = (tmp & DAVINCI_USB_TXINT_MASK)
- >> DAVINCI_USB_TXINT_SHIFT;
- musb->int_usb = (tmp & DAVINCI_USB_USBINT_MASK)
- >> DAVINCI_USB_USBINT_SHIFT;
-
- /* DRVVBUS irqs are the only proxy we have (a very poor one!) for
- * DaVinci's missing ID change IRQ. We need an ID change IRQ to
- * switch appropriately between halves of the OTG state machine.
- * Managing DEVCTL.SESSION per Mentor docs requires we know its
- * value, but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
- * Also, DRVVBUS pulses for SRP (but not at 5V) ...
- */
- if (tmp & (DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT)) {
- int drvvbus = musb_readl(tibase, DAVINCI_USB_STAT_REG);
- void __iomem *mregs = musb->mregs;
- u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
- int err = musb->int_usb & MUSB_INTR_VBUSERROR;
-
- err = musb->int_usb & MUSB_INTR_VBUSERROR;
- if (err) {
- /* The Mentor core doesn't debounce VBUS as needed
- * to cope with device connect current spikes. This
- * means it's not uncommon for bus-powered devices
- * to get VBUS errors during enumeration.
- *
- * This is a workaround, but newer RTL from Mentor
- * seems to allow a better one: "re"starting sessions
- * without waiting (on EVM, a **long** time) for VBUS
- * to stop registering in devctl.
- */
- musb->int_usb &= ~MUSB_INTR_VBUSERROR;
- musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL;
- mod_timer(&musb->dev_timer, jiffies + POLL_SECONDS * HZ);
- WARNING("VBUS error workaround (delay coming)\n");
- } else if (drvvbus) {
- MUSB_HST_MODE(musb);
- musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
- portstate(musb->port1_status |= USB_PORT_STAT_POWER);
- del_timer(&musb->dev_timer);
- } else {
- musb->is_active = 0;
- MUSB_DEV_MODE(musb);
- musb->xceiv->otg->state = OTG_STATE_B_IDLE;
- portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
- }
-
- /* NOTE: this must complete poweron within 100 msec
- * (OTG_TIME_A_WAIT_VRISE) but we don't check for that.
- */
- davinci_musb_source_power(musb, drvvbus, 0);
- dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
- drvvbus ? "on" : "off",
- usb_otg_state_string(musb->xceiv->otg->state),
- err ? " ERROR" : "",
- devctl);
- retval = IRQ_HANDLED;
- }
-
- if (musb->int_tx || musb->int_rx || musb->int_usb)
- retval |= musb_interrupt(musb);
-
- /* irq stays asserted until EOI is written */
- musb_writel(tibase, DAVINCI_USB_EOI_REG, 0);
-
- /* poll for ID change */
- if (musb->xceiv->otg->state == OTG_STATE_B_IDLE)
- mod_timer(&musb->dev_timer, jiffies + POLL_SECONDS * HZ);
-
- spin_unlock_irqrestore(&musb->lock, flags);
-
- return retval;
-}
-
-static int davinci_musb_set_mode(struct musb *musb, u8 mode)
-{
- /* EVM can't do this (right?) */
- return -EIO;
-}
-
-static int davinci_musb_init(struct musb *musb)
-{
- void __iomem *tibase = musb->ctrl_base;
- u32 revision;
- int ret = -ENODEV;
-
- musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
- if (IS_ERR_OR_NULL(musb->xceiv)) {
- ret = -EPROBE_DEFER;
- goto unregister;
- }
-
- musb->mregs += DAVINCI_BASE_OFFSET;
-
- /* returns zero if e.g. not clocked */
- revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
- if (revision == 0)
- goto fail;
-
- timer_setup(&musb->dev_timer, otg_timer, 0);
-
- davinci_musb_source_power(musb, 0, 1);
-
- /* dm355 EVM swaps D+/D- for signal integrity, and
- * is clocked from the main 24 MHz crystal.
- */
- if (machine_is_davinci_dm355_evm()) {
- u32 phy_ctrl = __raw_readl(USB_PHY_CTRL);
-
- phy_ctrl &= ~(3 << 9);
- phy_ctrl |= USBPHY_DATAPOL;
- __raw_writel(phy_ctrl, USB_PHY_CTRL);
- }
-
- /* On dm355, the default-A state machine needs DRVVBUS control.
- * If we won't be a host, there's no need to turn it on.
- */
- if (cpu_is_davinci_dm355()) {
- u32 deepsleep = __raw_readl(DM355_DEEPSLEEP);
-
- deepsleep &= ~DRVVBUS_FORCE;
- __raw_writel(deepsleep, DM355_DEEPSLEEP);
- }
-
- /* reset the controller */
- musb_writel(tibase, DAVINCI_USB_CTRL_REG, 0x1);
-
- /* start the on-chip PHY and its PLL */
- phy_on();
-
- msleep(5);
-
- /* NOTE: irqs are in mixed mode, not bypass to pure-musb */
- pr_debug("DaVinci OTG revision %08x phy %03x control %02x\n",
- revision, __raw_readl(USB_PHY_CTRL),
- musb_readb(tibase, DAVINCI_USB_CTRL_REG));
-
- musb->isr = davinci_musb_interrupt;
- return 0;
-
-fail:
- usb_put_phy(musb->xceiv);
-unregister:
- usb_phy_generic_unregister();
- return ret;
-}
-
-static int davinci_musb_exit(struct musb *musb)
-{
- int maxdelay = 30;
- u8 devctl, warn = 0;
-
- del_timer_sync(&musb->dev_timer);
-
- /* force VBUS off */
- if (cpu_is_davinci_dm355()) {
- u32 deepsleep = __raw_readl(DM355_DEEPSLEEP);
-
- deepsleep &= ~DRVVBUS_FORCE;
- deepsleep |= DRVVBUS_OVERRIDE;
- __raw_writel(deepsleep, DM355_DEEPSLEEP);
- }
-
- davinci_musb_source_power(musb, 0 /*off*/, 1);
-
- /*
- * delay, to avoid problems with module reload.
- * if there's no peripheral connected, this can take a
- * long time to fall, especially on EVM with huge C133.
- */
- do {
- devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
- if (!(devctl & MUSB_DEVCTL_VBUS))
- break;
- if ((devctl & MUSB_DEVCTL_VBUS) != warn) {
- warn = devctl & MUSB_DEVCTL_VBUS;
- dev_dbg(musb->controller, "VBUS %d\n",
- warn >> MUSB_DEVCTL_VBUS_SHIFT);
- }
- msleep(1000);
- maxdelay--;
- } while (maxdelay > 0);
-
- /* in OTG mode, another host might be connected */
- if (devctl & MUSB_DEVCTL_VBUS)
- dev_dbg(musb->controller, "VBUS off timeout (devctl %02x)\n", devctl);
-
- phy_off();
-
- usb_put_phy(musb->xceiv);
-
- return 0;
-}
-
-static const struct musb_platform_ops davinci_ops = {
- .quirks = MUSB_DMA_CPPI,
- .init = davinci_musb_init,
- .exit = davinci_musb_exit,
-
-#ifdef CONFIG_USB_TI_CPPI_DMA
- .dma_init = cppi_dma_controller_create,
- .dma_exit = cppi_dma_controller_destroy,
-#endif
- .enable = davinci_musb_enable,
- .disable = davinci_musb_disable,
-
- .set_mode = davinci_musb_set_mode,
-
- .set_vbus = davinci_musb_set_vbus,
-};
-
-static const struct platform_device_info davinci_dev_info = {
- .name = "musb-hdrc",
- .id = PLATFORM_DEVID_AUTO,
- .dma_mask = DMA_BIT_MASK(32),
-};
-
-static int davinci_probe(struct platform_device *pdev)
-{
- struct resource musb_resources[3];
- struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev);
- struct platform_device *musb;
- struct davinci_glue *glue;
- struct platform_device_info pinfo;
- struct clk *clk;
-
- int ret = -ENOMEM;
-
- glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
- if (!glue)
- goto err0;
-
- clk = devm_clk_get(&pdev->dev, "usb");
- if (IS_ERR(clk)) {
- dev_err(&pdev->dev, "failed to get clock\n");
- ret = PTR_ERR(clk);
- goto err0;
- }
-
- ret = clk_enable(clk);
- if (ret) {
- dev_err(&pdev->dev, "failed to enable clock\n");
- goto err0;
- }
-
- glue->dev = &pdev->dev;
- glue->clk = clk;
-
- pdata->platform_ops = &davinci_ops;
-
- glue->vbus = devm_gpiod_get_optional(&pdev->dev, NULL, GPIOD_OUT_LOW);
- if (IS_ERR(glue->vbus)) {
- ret = PTR_ERR(glue->vbus);
- goto err0;
- } else {
- glue->vbus_state = -1;
- INIT_WORK(&glue->vbus_work, evm_deferred_drvvbus);
- }
-
- usb_phy_generic_register();
- platform_set_drvdata(pdev, glue);
-
- memset(musb_resources, 0x00, sizeof(*musb_resources) *
- ARRAY_SIZE(musb_resources));
-
- musb_resources[0].name = pdev->resource[0].name;
- musb_resources[0].start = pdev->resource[0].start;
- musb_resources[0].end = pdev->resource[0].end;
- musb_resources[0].flags = pdev->resource[0].flags;
-
- musb_resources[1].name = pdev->resource[1].name;
- musb_resources[1].start = pdev->resource[1].start;
- musb_resources[1].end = pdev->resource[1].end;
- musb_resources[1].flags = pdev->resource[1].flags;
-
- /*
- * For DM6467 3 resources are passed. A placeholder for the 3rd
- * resource is always there, so it's safe to always copy it...
- */
- musb_resources[2].name = pdev->resource[2].name;
- musb_resources[2].start = pdev->resource[2].start;
- musb_resources[2].end = pdev->resource[2].end;
- musb_resources[2].flags = pdev->resource[2].flags;
-
- pinfo = davinci_dev_info;
- pinfo.parent = &pdev->dev;
- pinfo.res = musb_resources;
- pinfo.num_res = ARRAY_SIZE(musb_resources);
- pinfo.data = pdata;
- pinfo.size_data = sizeof(*pdata);
-
- glue->musb = musb = platform_device_register_full(&pinfo);
- if (IS_ERR(musb)) {
- ret = PTR_ERR(musb);
- dev_err(&pdev->dev, "failed to register musb device: %d\n", ret);
- goto err1;
- }
-
- return 0;
-
-err1:
- clk_disable(clk);
-
-err0:
- return ret;
-}
-
-static int davinci_remove(struct platform_device *pdev)
-{
- struct davinci_glue *glue = platform_get_drvdata(pdev);
-
- platform_device_unregister(glue->musb);
- usb_phy_generic_unregister();
- clk_disable(glue->clk);
-
- return 0;
-}
-
-static struct platform_driver davinci_driver = {
- .probe = davinci_probe,
- .remove = davinci_remove,
- .driver = {
- .name = "musb-davinci",
- },
-};
-
-MODULE_DESCRIPTION("DaVinci MUSB Glue Layer");
-MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
-MODULE_LICENSE("GPL v2");
-module_platform_driver(davinci_driver);
diff --git a/drivers/usb/musb/davinci.h b/drivers/usb/musb/davinci.h
deleted file mode 100644
index c8e67d15b510..000000000000
--- a/drivers/usb/musb/davinci.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2005-2006 by Texas Instruments
- */
-
-#ifndef __MUSB_HDRDF_H__
-#define __MUSB_HDRDF_H__
-
-/*
- * DaVinci-specific definitions
- */
-
-/* Integrated highspeed/otg PHY */
-#define USBPHY_CTL_PADDR 0x01c40034
-#define USBPHY_DATAPOL BIT(11) /* (dm355) switch D+/D- */
-#define USBPHY_PHYCLKGD BIT(8)
-#define USBPHY_SESNDEN BIT(7) /* v(sess_end) comparator */
-#define USBPHY_VBDTCTEN BIT(6) /* v(bus) comparator */
-#define USBPHY_VBUSSENS BIT(5) /* (dm355,ro) is vbus > 0.5V */
-#define USBPHY_PHYPLLON BIT(4) /* override pll suspend */
-#define USBPHY_CLKO1SEL BIT(3)
-#define USBPHY_OSCPDWN BIT(2)
-#define USBPHY_OTGPDWN BIT(1)
-#define USBPHY_PHYPDWN BIT(0)
-
-#define DM355_DEEPSLEEP_PADDR 0x01c40048
-#define DRVVBUS_FORCE BIT(2)
-#define DRVVBUS_OVERRIDE BIT(1)
-
-/* For now include usb OTG module registers here */
-#define DAVINCI_USB_VERSION_REG 0x00
-#define DAVINCI_USB_CTRL_REG 0x04
-#define DAVINCI_USB_STAT_REG 0x08
-#define DAVINCI_RNDIS_REG 0x10
-#define DAVINCI_AUTOREQ_REG 0x14
-#define DAVINCI_USB_INT_SOURCE_REG 0x20
-#define DAVINCI_USB_INT_SET_REG 0x24
-#define DAVINCI_USB_INT_SRC_CLR_REG 0x28
-#define DAVINCI_USB_INT_MASK_REG 0x2c
-#define DAVINCI_USB_INT_MASK_SET_REG 0x30
-#define DAVINCI_USB_INT_MASK_CLR_REG 0x34
-#define DAVINCI_USB_INT_SRC_MASKED_REG 0x38
-#define DAVINCI_USB_EOI_REG 0x3c
-#define DAVINCI_USB_EOI_INTVEC 0x40
-
-/* BEGIN CPPI-generic (?) */
-
-/* CPPI related registers */
-#define DAVINCI_TXCPPI_CTRL_REG 0x80
-#define DAVINCI_TXCPPI_TEAR_REG 0x84
-#define DAVINCI_CPPI_EOI_REG 0x88
-#define DAVINCI_CPPI_INTVEC_REG 0x8c
-#define DAVINCI_TXCPPI_MASKED_REG 0x90
-#define DAVINCI_TXCPPI_RAW_REG 0x94
-#define DAVINCI_TXCPPI_INTENAB_REG 0x98
-#define DAVINCI_TXCPPI_INTCLR_REG 0x9c
-
-#define DAVINCI_RXCPPI_CTRL_REG 0xC0
-#define DAVINCI_RXCPPI_MASKED_REG 0xD0
-#define DAVINCI_RXCPPI_RAW_REG 0xD4
-#define DAVINCI_RXCPPI_INTENAB_REG 0xD8
-#define DAVINCI_RXCPPI_INTCLR_REG 0xDC
-
-#define DAVINCI_RXCPPI_BUFCNT0_REG 0xE0
-#define DAVINCI_RXCPPI_BUFCNT1_REG 0xE4
-#define DAVINCI_RXCPPI_BUFCNT2_REG 0xE8
-#define DAVINCI_RXCPPI_BUFCNT3_REG 0xEC
-
-/* CPPI state RAM entries */
-#define DAVINCI_CPPI_STATERAM_BASE_OFFSET 0x100
-
-#define DAVINCI_TXCPPI_STATERAM_OFFSET(chnum) \
- (DAVINCI_CPPI_STATERAM_BASE_OFFSET + ((chnum) * 0x40))
-#define DAVINCI_RXCPPI_STATERAM_OFFSET(chnum) \
- (DAVINCI_CPPI_STATERAM_BASE_OFFSET + 0x20 + ((chnum) * 0x40))
-
-/* CPPI masks */
-#define DAVINCI_DMA_CTRL_ENABLE 1
-#define DAVINCI_DMA_CTRL_DISABLE 0
-
-#define DAVINCI_DMA_ALL_CHANNELS_ENABLE 0xF
-#define DAVINCI_DMA_ALL_CHANNELS_DISABLE 0xF
-
-/* END CPPI-generic (?) */
-
-#define DAVINCI_USB_TX_ENDPTS_MASK 0x1f /* ep0 + 4 tx */
-#define DAVINCI_USB_RX_ENDPTS_MASK 0x1e /* 4 rx */
-
-#define DAVINCI_USB_USBINT_SHIFT 16
-#define DAVINCI_USB_TXINT_SHIFT 0
-#define DAVINCI_USB_RXINT_SHIFT 8
-
-#define DAVINCI_INTR_DRVVBUS 0x0100
-
-#define DAVINCI_USB_USBINT_MASK 0x01ff0000 /* 8 Mentor, DRVVBUS */
-#define DAVINCI_USB_TXINT_MASK \
- (DAVINCI_USB_TX_ENDPTS_MASK << DAVINCI_USB_TXINT_SHIFT)
-#define DAVINCI_USB_RXINT_MASK \
- (DAVINCI_USB_RX_ENDPTS_MASK << DAVINCI_USB_RXINT_SHIFT)
-
-#define DAVINCI_BASE_OFFSET 0x400
-
-#endif /* __MUSB_HDRDF_H__ */
diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c
index d1e4e0deb753..c7b1d2a394d9 100644
--- a/drivers/usb/musb/jz4740.c
+++ b/drivers/usb/musb/jz4740.c
@@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
+#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/usb/role.h>
#include <linux/usb/usb_phy_generic.h>
@@ -81,6 +82,9 @@ static int jz4740_musb_role_switch_set(struct usb_role_switch *sw,
struct jz4740_glue *glue = usb_role_switch_get_drvdata(sw);
struct usb_phy *phy = glue->musb->xceiv;
+ if (!phy)
+ return 0;
+
switch (role) {
case USB_ROLE_NONE:
atomic_notifier_call_chain(&phy->notifier, USB_EVENT_NONE, phy);
@@ -105,21 +109,51 @@ static int jz4740_musb_init(struct musb *musb)
.driver_data = glue,
.fwnode = dev_fwnode(dev),
};
+ int err;
glue->musb = musb;
- if (dev->of_node)
- musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0);
- else
- musb->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
- if (IS_ERR(musb->xceiv))
- return dev_err_probe(dev, PTR_ERR(musb->xceiv),
- "No transceiver configured\n");
+ if (IS_ENABLED(CONFIG_GENERIC_PHY)) {
+ musb->phy = devm_of_phy_get_by_index(dev, dev->of_node, 0);
+ if (IS_ERR(musb->phy)) {
+ err = PTR_ERR(musb->phy);
+ if (err != -ENODEV) {
+ dev_err(dev, "Unable to get PHY\n");
+ return err;
+ }
+
+ musb->phy = NULL;
+ }
+ }
+
+ if (musb->phy) {
+ err = phy_init(musb->phy);
+ if (err) {
+ dev_err(dev, "Failed to init PHY\n");
+ return err;
+ }
+
+ err = phy_power_on(musb->phy);
+ if (err) {
+ dev_err(dev, "Unable to power on PHY\n");
+ goto err_phy_shutdown;
+ }
+ } else {
+ if (dev->of_node)
+ musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0);
+ else
+ musb->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+ if (IS_ERR(musb->xceiv)) {
+ dev_err(dev, "No transceiver configured\n");
+ return PTR_ERR(musb->xceiv);
+ }
+ }
glue->role_sw = usb_role_switch_register(dev, &role_sw_desc);
if (IS_ERR(glue->role_sw)) {
dev_err(dev, "Failed to register USB role switch\n");
- return PTR_ERR(glue->role_sw);
+ err = PTR_ERR(glue->role_sw);
+ goto err_phy_power_down;
}
/*
@@ -131,6 +165,14 @@ static int jz4740_musb_init(struct musb *musb)
musb->isr = jz4740_musb_interrupt;
return 0;
+
+err_phy_power_down:
+ if (musb->phy)
+ phy_power_off(musb->phy);
+err_phy_shutdown:
+ if (musb->phy)
+ phy_exit(musb->phy);
+ return err;
}
static int jz4740_musb_exit(struct musb *musb)
@@ -138,6 +180,10 @@ static int jz4740_musb_exit(struct musb *musb)
struct jz4740_glue *glue = dev_get_drvdata(musb->controller->parent);
usb_role_switch_unregister(glue->role_sw);
+ if (musb->phy) {
+ phy_power_off(musb->phy);
+ phy_exit(musb->phy);
+ }
return 0;
}
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 03027c6fa3ab..648bb6021c5e 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -502,7 +502,7 @@ int musb_set_host(struct musb *musb)
init_data:
musb->is_active = 1;
- musb->xceiv->otg->state = OTG_STATE_A_IDLE;
+ musb_set_state(musb, OTG_STATE_A_IDLE);
MUSB_HST_MODE(musb);
return error;
@@ -549,7 +549,7 @@ int musb_set_peripheral(struct musb *musb)
init_data:
musb->is_active = 0;
- musb->xceiv->otg->state = OTG_STATE_B_IDLE;
+ musb_set_state(musb, OTG_STATE_B_IDLE);
MUSB_DEV_MODE(musb);
return error;
@@ -599,24 +599,24 @@ static void musb_otg_timer_func(struct timer_list *t)
unsigned long flags;
spin_lock_irqsave(&musb->lock, flags);
- switch (musb->xceiv->otg->state) {
+ switch (musb_get_state(musb)) {
case OTG_STATE_B_WAIT_ACON:
musb_dbg(musb,
"HNP: b_wait_acon timeout; back to b_peripheral");
musb_g_disconnect(musb);
- musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
+ musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
musb->is_active = 0;
break;
case OTG_STATE_A_SUSPEND:
case OTG_STATE_A_WAIT_BCON:
musb_dbg(musb, "HNP: %s timeout",
- usb_otg_state_string(musb->xceiv->otg->state));
+ musb_otg_state_string(musb));
musb_platform_set_vbus(musb, 0);
- musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL;
+ musb_set_state(musb, OTG_STATE_A_WAIT_VFALL);
break;
default:
musb_dbg(musb, "HNP: Unhandled mode %s",
- usb_otg_state_string(musb->xceiv->otg->state));
+ musb_otg_state_string(musb));
}
spin_unlock_irqrestore(&musb->lock, flags);
}
@@ -630,20 +630,18 @@ void musb_hnp_stop(struct musb *musb)
void __iomem *mbase = musb->mregs;
u8 reg;
- musb_dbg(musb, "HNP: stop from %s",
- usb_otg_state_string(musb->xceiv->otg->state));
+ musb_dbg(musb, "HNP: stop from %s", musb_otg_state_string(musb));
- switch (musb->xceiv->otg->state) {
+ switch (musb_get_state(musb)) {
case OTG_STATE_A_PERIPHERAL:
musb_g_disconnect(musb);
- musb_dbg(musb, "HNP: back to %s",
- usb_otg_state_string(musb->xceiv->otg->state));
+ musb_dbg(musb, "HNP: back to %s", musb_otg_state_string(musb));
break;
case OTG_STATE_B_HOST:
musb_dbg(musb, "HNP: Disabling HR");
if (hcd)
hcd->self.is_b_host = 0;
- musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
+ musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
MUSB_DEV_MODE(musb);
reg = musb_readb(mbase, MUSB_POWER);
reg |= MUSB_POWER_SUSPENDM;
@@ -652,7 +650,7 @@ void musb_hnp_stop(struct musb *musb)
break;
default:
musb_dbg(musb, "HNP: Stopping in unknown state %s",
- usb_otg_state_string(musb->xceiv->otg->state));
+ musb_otg_state_string(musb));
}
/*
@@ -667,11 +665,10 @@ static void musb_recover_from_babble(struct musb *musb);
static void musb_handle_intr_resume(struct musb *musb, u8 devctl)
{
- musb_dbg(musb, "RESUME (%s)",
- usb_otg_state_string(musb->xceiv->otg->state));
+ musb_dbg(musb, "RESUME (%s)", musb_otg_state_string(musb));
if (devctl & MUSB_DEVCTL_HM) {
- switch (musb->xceiv->otg->state) {
+ switch (musb_get_state(musb)) {
case OTG_STATE_A_SUSPEND:
/* remote wakeup? */
musb->port1_status |=
@@ -679,27 +676,27 @@ static void musb_handle_intr_resume(struct musb *musb, u8 devctl)
| MUSB_PORT_STAT_RESUME;
musb->rh_timer = jiffies
+ msecs_to_jiffies(USB_RESUME_TIMEOUT);
- musb->xceiv->otg->state = OTG_STATE_A_HOST;
+ musb_set_state(musb, OTG_STATE_A_HOST);
musb->is_active = 1;
musb_host_resume_root_hub(musb);
schedule_delayed_work(&musb->finish_resume_work,
msecs_to_jiffies(USB_RESUME_TIMEOUT));
break;
case OTG_STATE_B_WAIT_ACON:
- musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
+ musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
musb->is_active = 1;
MUSB_DEV_MODE(musb);
break;
default:
WARNING("bogus %s RESUME (%s)\n",
"host",
- usb_otg_state_string(musb->xceiv->otg->state));
+ musb_otg_state_string(musb));
}
} else {
- switch (musb->xceiv->otg->state) {
+ switch (musb_get_state(musb)) {
case OTG_STATE_A_SUSPEND:
/* possibly DISCONNECT is upcoming */
- musb->xceiv->otg->state = OTG_STATE_A_HOST;
+ musb_set_state(musb, OTG_STATE_A_HOST);
musb_host_resume_root_hub(musb);
break;
case OTG_STATE_B_WAIT_ACON:
@@ -722,7 +719,7 @@ static void musb_handle_intr_resume(struct musb *musb, u8 devctl)
default:
WARNING("bogus %s RESUME (%s)\n",
"peripheral",
- usb_otg_state_string(musb->xceiv->otg->state));
+ musb_otg_state_string(musb));
}
}
}
@@ -738,8 +735,7 @@ static irqreturn_t musb_handle_intr_sessreq(struct musb *musb, u8 devctl)
return IRQ_HANDLED;
}
- musb_dbg(musb, "SESSION_REQUEST (%s)",
- usb_otg_state_string(musb->xceiv->otg->state));
+ musb_dbg(musb, "SESSION_REQUEST (%s)", musb_otg_state_string(musb));
/* IRQ arrives from ID pin sense or (later, if VBUS power
* is removed) SRP. responses are time critical:
@@ -750,7 +746,7 @@ static irqreturn_t musb_handle_intr_sessreq(struct musb *musb, u8 devctl)
*/
musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
musb->ep0_stage = MUSB_EP0_START;
- musb->xceiv->otg->state = OTG_STATE_A_IDLE;
+ musb_set_state(musb, OTG_STATE_A_IDLE);
MUSB_HST_MODE(musb);
musb_platform_set_vbus(musb, 1);
@@ -777,7 +773,7 @@ static void musb_handle_intr_vbuserr(struct musb *musb, u8 devctl)
* REVISIT: do delays from lots of DEBUG_KERNEL checks
* make trouble here, keeping VBUS < 4.4V ?
*/
- switch (musb->xceiv->otg->state) {
+ switch (musb_get_state(musb)) {
case OTG_STATE_A_HOST:
/* recovery is dicey once we've gotten past the
* initial stages of enumeration, but if VBUS
@@ -806,7 +802,7 @@ static void musb_handle_intr_vbuserr(struct musb *musb, u8 devctl)
dev_printk(ignore ? KERN_DEBUG : KERN_ERR, musb->controller,
"VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n",
- usb_otg_state_string(musb->xceiv->otg->state),
+ musb_otg_state_string(musb),
devctl,
({ char *s;
switch (devctl & MUSB_DEVCTL_VBUS) {
@@ -831,9 +827,9 @@ static void musb_handle_intr_vbuserr(struct musb *musb, u8 devctl)
static void musb_handle_intr_suspend(struct musb *musb, u8 devctl)
{
musb_dbg(musb, "SUSPEND (%s) devctl %02x",
- usb_otg_state_string(musb->xceiv->otg->state), devctl);
+ musb_otg_state_string(musb), devctl);
- switch (musb->xceiv->otg->state) {
+ switch (musb_get_state(musb)) {
case OTG_STATE_A_PERIPHERAL:
/* We also come here if the cable is removed, since
* this silicon doesn't report ID-no-longer-grounded.
@@ -858,7 +854,7 @@ static void musb_handle_intr_suspend(struct musb *musb, u8 devctl)
musb_g_suspend(musb);
musb->is_active = musb->g.b_hnp_enable;
if (musb->is_active) {
- musb->xceiv->otg->state = OTG_STATE_B_WAIT_ACON;
+ musb_set_state(musb, OTG_STATE_B_WAIT_ACON);
musb_dbg(musb, "HNP: Setting timer for b_ase0_brst");
mod_timer(&musb->otg_timer, jiffies
+ msecs_to_jiffies(
@@ -871,7 +867,7 @@ static void musb_handle_intr_suspend(struct musb *musb, u8 devctl)
+ msecs_to_jiffies(musb->a_wait_bcon));
break;
case OTG_STATE_A_HOST:
- musb->xceiv->otg->state = OTG_STATE_A_SUSPEND;
+ musb_set_state(musb, OTG_STATE_A_SUSPEND);
musb->is_active = musb->hcd->self.b_hnp_enable;
break;
case OTG_STATE_B_HOST:
@@ -909,7 +905,7 @@ static void musb_handle_intr_connect(struct musb *musb, u8 devctl, u8 int_usb)
musb->port1_status |= USB_PORT_STAT_LOW_SPEED;
/* indicate new connection to OTG machine */
- switch (musb->xceiv->otg->state) {
+ switch (musb_get_state(musb)) {
case OTG_STATE_B_PERIPHERAL:
if (int_usb & MUSB_INTR_SUSPEND) {
musb_dbg(musb, "HNP: SUSPEND+CONNECT, now b_host");
@@ -921,7 +917,7 @@ static void musb_handle_intr_connect(struct musb *musb, u8 devctl, u8 int_usb)
case OTG_STATE_B_WAIT_ACON:
musb_dbg(musb, "HNP: CONNECT, now b_host");
b_host:
- musb->xceiv->otg->state = OTG_STATE_B_HOST;
+ musb_set_state(musb, OTG_STATE_B_HOST);
if (musb->hcd)
musb->hcd->self.is_b_host = 1;
del_timer(&musb->otg_timer);
@@ -929,7 +925,7 @@ b_host:
default:
if ((devctl & MUSB_DEVCTL_VBUS)
== (3 << MUSB_DEVCTL_VBUS_SHIFT)) {
- musb->xceiv->otg->state = OTG_STATE_A_HOST;
+ musb_set_state(musb, OTG_STATE_A_HOST);
if (hcd)
hcd->self.is_b_host = 0;
}
@@ -939,16 +935,16 @@ b_host:
musb_host_poke_root_hub(musb);
musb_dbg(musb, "CONNECT (%s) devctl %02x",
- usb_otg_state_string(musb->xceiv->otg->state), devctl);
+ musb_otg_state_string(musb), devctl);
}
static void musb_handle_intr_disconnect(struct musb *musb, u8 devctl)
{
musb_dbg(musb, "DISCONNECT (%s) as %s, devctl %02x",
- usb_otg_state_string(musb->xceiv->otg->state),
+ musb_otg_state_string(musb),
MUSB_MODE(musb), devctl);
- switch (musb->xceiv->otg->state) {
+ switch (musb_get_state(musb)) {
case OTG_STATE_A_HOST:
case OTG_STATE_A_SUSPEND:
musb_host_resume_root_hub(musb);
@@ -966,7 +962,7 @@ static void musb_handle_intr_disconnect(struct musb *musb, u8 devctl)
musb_root_disconnect(musb);
if (musb->hcd)
musb->hcd->self.is_b_host = 0;
- musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
+ musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
MUSB_DEV_MODE(musb);
musb_g_disconnect(musb);
break;
@@ -981,7 +977,7 @@ static void musb_handle_intr_disconnect(struct musb *musb, u8 devctl)
break;
default:
WARNING("unhandled DISCONNECT transition (%s)\n",
- usb_otg_state_string(musb->xceiv->otg->state));
+ musb_otg_state_string(musb));
break;
}
}
@@ -1004,16 +1000,15 @@ static void musb_handle_intr_reset(struct musb *musb)
dev_err(musb->controller, "Babble\n");
musb_recover_from_babble(musb);
} else {
- musb_dbg(musb, "BUS RESET as %s",
- usb_otg_state_string(musb->xceiv->otg->state));
- switch (musb->xceiv->otg->state) {
+ musb_dbg(musb, "BUS RESET as %s", musb_otg_state_string(musb));
+ switch (musb_get_state(musb)) {
case OTG_STATE_A_SUSPEND:
musb_g_reset(musb);
fallthrough;
case OTG_STATE_A_WAIT_BCON: /* OPT TD.4.7-900ms */
/* never use invalid T(a_wait_bcon) */
musb_dbg(musb, "HNP: in %s, %d msec timeout",
- usb_otg_state_string(musb->xceiv->otg->state),
+ musb_otg_state_string(musb),
TA_WAIT_BCON(musb));
mod_timer(&musb->otg_timer, jiffies
+ msecs_to_jiffies(TA_WAIT_BCON(musb)));
@@ -1024,19 +1019,19 @@ static void musb_handle_intr_reset(struct musb *musb)
break;
case OTG_STATE_B_WAIT_ACON:
musb_dbg(musb, "HNP: RESET (%s), to b_peripheral",
- usb_otg_state_string(musb->xceiv->otg->state));
- musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
+ musb_otg_state_string(musb));
+ musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
musb_g_reset(musb);
break;
case OTG_STATE_B_IDLE:
- musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
+ musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
fallthrough;
case OTG_STATE_B_PERIPHERAL:
musb_g_reset(musb);
break;
default:
musb_dbg(musb, "Unhandled BUS RESET as %s",
- usb_otg_state_string(musb->xceiv->otg->state));
+ musb_otg_state_string(musb));
}
}
}
@@ -1216,8 +1211,8 @@ void musb_start(struct musb *musb)
* (c) peripheral initiates, using SRP
*/
if (musb->port_mode != MUSB_HOST &&
- musb->xceiv->otg->state != OTG_STATE_A_WAIT_BCON &&
- (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) {
+ musb_get_state(musb) != OTG_STATE_A_WAIT_BCON &&
+ (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) {
musb->is_active = 1;
} else {
devctl |= MUSB_DEVCTL_SESSION;
@@ -1863,7 +1858,7 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf)
int ret;
spin_lock_irqsave(&musb->lock, flags);
- ret = sprintf(buf, "%s\n", usb_otg_state_string(musb->xceiv->otg->state));
+ ret = sprintf(buf, "%s\n", musb_otg_state_string(musb));
spin_unlock_irqrestore(&musb->lock, flags);
return ret;
@@ -1908,7 +1903,7 @@ vbus_store(struct device *dev, struct device_attribute *attr,
spin_lock_irqsave(&musb->lock, flags);
/* force T(a_wait_bcon) to be zero/unlimited *OR* valid */
musb->a_wait_bcon = val ? max_t(int, val, OTG_TIME_A_WAIT_BCON) : 0 ;
- if (musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON)
+ if (musb_get_state(musb) == OTG_STATE_A_WAIT_BCON)
musb->is_active = 0;
musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val));
spin_unlock_irqrestore(&musb->lock, flags);
@@ -2089,8 +2084,8 @@ static void musb_irq_work(struct work_struct *data)
musb_pm_runtime_check_session(musb);
- if (musb->xceiv->otg->state != musb->xceiv_old_state) {
- musb->xceiv_old_state = musb->xceiv->otg->state;
+ if (musb_get_state(musb) != musb->xceiv_old_state) {
+ musb->xceiv_old_state = musb_get_state(musb);
sysfs_notify(&musb->controller->kobj, NULL, "mode");
}
@@ -2453,7 +2448,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
else
musb->io.set_toggle = musb_default_set_toggle;
- if (!musb->xceiv->io_ops) {
+ if (IS_ENABLED(CONFIG_USB_PHY) && musb->xceiv && !musb->xceiv->io_ops) {
musb->xceiv->io_dev = musb->controller;
musb->xceiv->io_priv = musb->mregs;
musb->xceiv->io_ops = &musb_ulpi_access;
@@ -2532,7 +2527,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
}
MUSB_DEV_MODE(musb);
- musb->xceiv->otg->state = OTG_STATE_B_IDLE;
+ musb_set_state(musb, OTG_STATE_B_IDLE);
switch (musb->port_mode) {
case MUSB_HOST:
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index a8a65effe68b..b7588d11cfc5 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -339,6 +339,8 @@ struct musb {
struct usb_phy *xceiv;
struct phy *phy;
+ enum usb_otg_state otg_state;
+
int nIrq;
unsigned irq_wake:1;
@@ -592,6 +594,28 @@ static inline void musb_platform_clear_ep_rxintr(struct musb *musb, int epnum)
musb->ops->clear_ep_rxintr(musb, epnum);
}
+static inline void musb_set_state(struct musb *musb,
+ enum usb_otg_state otg_state)
+{
+ if (musb->xceiv)
+ musb->xceiv->otg->state = otg_state;
+ else
+ musb->otg_state = otg_state;
+}
+
+static inline enum usb_otg_state musb_get_state(struct musb *musb)
+{
+ if (musb->xceiv)
+ return musb->xceiv->otg->state;
+
+ return musb->otg_state;
+}
+
+static inline const char *musb_otg_state_string(struct musb *musb)
+{
+ return usb_otg_state_string(musb_get_state(musb));
+}
+
/*
* gets the "dr_mode" property from DT and converts it into musb_mode
* if the property is not found or not recognized returns MUSB_OTG
diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c
index 30a89aa8a3e7..78c726a71b17 100644
--- a/drivers/usb/musb/musb_debugfs.c
+++ b/drivers/usb/musb/musb_debugfs.c
@@ -235,7 +235,7 @@ static int musb_softconnect_show(struct seq_file *s, void *unused)
u8 reg;
int connect;
- switch (musb->xceiv->otg->state) {
+ switch (musb_get_state(musb)) {
case OTG_STATE_A_HOST:
case OTG_STATE_A_WAIT_BCON:
pm_runtime_get_sync(musb->controller);
@@ -275,7 +275,7 @@ static ssize_t musb_softconnect_write(struct file *file,
pm_runtime_get_sync(musb->controller);
if (!strncmp(buf, "0", 1)) {
- switch (musb->xceiv->otg->state) {
+ switch (musb_get_state(musb)) {
case OTG_STATE_A_HOST:
musb_root_disconnect(musb);
reg = musb_readb(musb->mregs, MUSB_DEVCTL);
@@ -286,7 +286,7 @@ static ssize_t musb_softconnect_write(struct file *file,
break;
}
} else if (!strncmp(buf, "1", 1)) {
- switch (musb->xceiv->otg->state) {
+ switch (musb_get_state(musb)) {
case OTG_STATE_A_WAIT_BCON:
/*
* musb_save_context() called in musb_runtime_suspend()
diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h
index 7d67b69df0a0..e2445ca3356d 100644
--- a/drivers/usb/musb/musb_dma.h
+++ b/drivers/usb/musb/musb_dma.h
@@ -61,12 +61,6 @@ struct musb_hw_ep;
#define musb_dma_cppi41(musb) 0
#endif
-#ifdef CONFIG_USB_TI_CPPI_DMA
-#define musb_dma_cppi(musb) (musb->ops->quirks & MUSB_DMA_CPPI)
-#else
-#define musb_dma_cppi(musb) 0
-#endif
-
#ifdef CONFIG_USB_TUSB_OMAP_DMA
#define tusb_dma_omap(musb) (musb->ops->quirks & MUSB_DMA_TUSB_OMAP)
#else
@@ -79,11 +73,10 @@ struct musb_hw_ep;
#define musb_dma_inventra(musb) 0
#endif
-#if defined(CONFIG_USB_TI_CPPI_DMA) || defined(CONFIG_USB_TI_CPPI41_DMA)
-#define is_cppi_enabled(musb) \
- (musb_dma_cppi(musb) || musb_dma_cppi41(musb))
+#if defined(CONFIG_USB_TI_CPPI41_DMA)
+#define is_cppi_enabled(musb) musb_dma_cppi41(musb)
#else
-#define is_cppi_enabled(musb) 0
+#define is_cppi_enabled(musb) 0
#endif
/*
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 6704a62a1665..6cb9514ef340 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -1523,7 +1523,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
spin_lock_irqsave(&musb->lock, flags);
- switch (musb->xceiv->otg->state) {
+ switch (musb_get_state(musb)) {
case OTG_STATE_B_PERIPHERAL:
/* NOTE: OTG state machine doesn't include B_SUSPENDED;
* that's part of the standard usb 1.1 state machine, and
@@ -1552,9 +1552,11 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
break;
}
- spin_unlock_irqrestore(&musb->lock, flags);
- otg_start_srp(musb->xceiv->otg);
- spin_lock_irqsave(&musb->lock, flags);
+ if (musb->xceiv) {
+ spin_unlock_irqrestore(&musb->lock, flags);
+ otg_start_srp(musb->xceiv->otg);
+ spin_lock_irqsave(&musb->lock, flags);
+ }
/* Block idling for at least 1s */
musb_platform_try_idle(musb,
@@ -1564,7 +1566,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
goto done;
default:
musb_dbg(musb, "Unhandled wake: %s",
- usb_otg_state_string(musb->xceiv->otg->state));
+ musb_otg_state_string(musb));
goto done;
}
@@ -1628,7 +1630,7 @@ static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
{
struct musb *musb = gadget_to_musb(gadget);
- if (!musb->xceiv->set_power)
+ if (!musb->xceiv || !musb->xceiv->set_power)
return -EOPNOTSUPP;
return usb_phy_set_power(musb->xceiv, mA);
}
@@ -1787,7 +1789,7 @@ int musb_gadget_setup(struct musb *musb)
musb->g.speed = USB_SPEED_UNKNOWN;
MUSB_DEV_MODE(musb);
- musb->xceiv->otg->state = OTG_STATE_B_IDLE;
+ musb_set_state(musb, OTG_STATE_B_IDLE);
/* this "gadget" abstracts/virtualizes the controller */
musb->g.name = musb_driver_name;
@@ -1834,7 +1836,6 @@ static int musb_gadget_start(struct usb_gadget *g,
struct usb_gadget_driver *driver)
{
struct musb *musb = gadget_to_musb(g);
- struct usb_otg *otg = musb->xceiv->otg;
unsigned long flags;
int retval = 0;
@@ -1851,8 +1852,12 @@ static int musb_gadget_start(struct usb_gadget *g,
spin_lock_irqsave(&musb->lock, flags);
musb->is_active = 1;
- otg_set_peripheral(otg, &musb->g);
- musb->xceiv->otg->state = OTG_STATE_B_IDLE;
+ if (musb->xceiv)
+ otg_set_peripheral(musb->xceiv->otg, &musb->g);
+ else
+ phy_set_mode(musb->phy, PHY_MODE_USB_DEVICE);
+
+ musb_set_state(musb, OTG_STATE_B_IDLE);
spin_unlock_irqrestore(&musb->lock, flags);
musb_start(musb);
@@ -1861,7 +1866,7 @@ static int musb_gadget_start(struct usb_gadget *g,
* handles power budgeting ... this way also
* ensures HdrcStart is indirectly called.
*/
- if (musb->xceiv->last_event == USB_EVENT_ID)
+ if (musb->xceiv && musb->xceiv->last_event == USB_EVENT_ID)
musb_platform_set_vbus(musb, 1);
pm_runtime_mark_last_busy(musb->controller);
@@ -1897,9 +1902,13 @@ static int musb_gadget_stop(struct usb_gadget *g)
(void) musb_gadget_vbus_draw(&musb->g, 0);
- musb->xceiv->otg->state = OTG_STATE_UNDEFINED;
+ musb_set_state(musb, OTG_STATE_UNDEFINED);
musb_stop(musb);
- otg_set_peripheral(musb->xceiv->otg, NULL);
+
+ if (musb->xceiv)
+ otg_set_peripheral(musb->xceiv->otg, NULL);
+ else
+ phy_set_mode(musb->phy, PHY_MODE_INVALID);
musb->is_active = 0;
musb->gadget_driver = NULL;
@@ -1926,7 +1935,7 @@ static int musb_gadget_stop(struct usb_gadget *g)
void musb_g_resume(struct musb *musb)
{
musb->is_suspended = 0;
- switch (musb->xceiv->otg->state) {
+ switch (musb_get_state(musb)) {
case OTG_STATE_B_IDLE:
break;
case OTG_STATE_B_WAIT_ACON:
@@ -1940,7 +1949,7 @@ void musb_g_resume(struct musb *musb)
break;
default:
WARNING("unhandled RESUME transition (%s)\n",
- usb_otg_state_string(musb->xceiv->otg->state));
+ musb_otg_state_string(musb));
}
}
@@ -1952,10 +1961,10 @@ void musb_g_suspend(struct musb *musb)
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
musb_dbg(musb, "musb_g_suspend: devctl %02x", devctl);
- switch (musb->xceiv->otg->state) {
+ switch (musb_get_state(musb)) {
case OTG_STATE_B_IDLE:
if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
- musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
+ musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
break;
case OTG_STATE_B_PERIPHERAL:
musb->is_suspended = 1;
@@ -1970,7 +1979,7 @@ void musb_g_suspend(struct musb *musb)
* A_PERIPHERAL may need care too
*/
WARNING("unhandled SUSPEND transition (%s)",
- usb_otg_state_string(musb->xceiv->otg->state));
+ musb_otg_state_string(musb));
}
}
@@ -2001,22 +2010,22 @@ void musb_g_disconnect(struct musb *musb)
spin_lock(&musb->lock);
}
- switch (musb->xceiv->otg->state) {
+ switch (musb_get_state(musb)) {
default:
musb_dbg(musb, "Unhandled disconnect %s, setting a_idle",
- usb_otg_state_string(musb->xceiv->otg->state));
- musb->xceiv->otg->state = OTG_STATE_A_IDLE;
+ musb_otg_state_string(musb));
+ musb_set_state(musb, OTG_STATE_A_IDLE);
MUSB_HST_MODE(musb);
break;
case OTG_STATE_A_PERIPHERAL:
- musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON;
+ musb_set_state(musb, OTG_STATE_A_WAIT_BCON);
MUSB_HST_MODE(musb);
break;
case OTG_STATE_B_WAIT_ACON:
case OTG_STATE_B_HOST:
case OTG_STATE_B_PERIPHERAL:
case OTG_STATE_B_IDLE:
- musb->xceiv->otg->state = OTG_STATE_B_IDLE;
+ musb_set_state(musb, OTG_STATE_B_IDLE);
break;
case OTG_STATE_B_SRP_INIT:
break;
@@ -2080,13 +2089,13 @@ __acquires(musb->lock)
* In that case, do not rely on devctl for setting
* peripheral mode.
*/
- musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
+ musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
musb->g.is_a_peripheral = 0;
} else if (devctl & MUSB_DEVCTL_BDEVICE) {
- musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
+ musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
musb->g.is_a_peripheral = 0;
} else {
- musb->xceiv->otg->state = OTG_STATE_A_PERIPHERAL;
+ musb_set_state(musb, OTG_STATE_A_PERIPHERAL);
musb->g.is_a_peripheral = 1;
}
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 9ff7d891b4b7..a02c29216955 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -2501,7 +2501,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd)
if (!is_host_active(musb))
return 0;
- switch (musb->xceiv->otg->state) {
+ switch (musb_get_state(musb)) {
case OTG_STATE_A_SUSPEND:
return 0;
case OTG_STATE_A_WAIT_VRISE:
@@ -2511,7 +2511,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd)
*/
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
- musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON;
+ musb_set_state(musb, OTG_STATE_A_WAIT_BCON);
break;
default:
break;
@@ -2519,7 +2519,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd)
if (musb->is_active) {
WARNING("trying to suspend as %s while active\n",
- usb_otg_state_string(musb->xceiv->otg->state));
+ musb_otg_state_string(musb));
return -EBUSY;
} else
return 0;
@@ -2720,12 +2720,18 @@ int musb_host_setup(struct musb *musb, int power_budget)
if (musb->port_mode == MUSB_HOST) {
MUSB_HST_MODE(musb);
- musb->xceiv->otg->state = OTG_STATE_A_IDLE;
+ musb_set_state(musb, OTG_STATE_A_IDLE);
}
- otg_set_host(musb->xceiv->otg, &hcd->self);
+
+ if (musb->xceiv) {
+ otg_set_host(musb->xceiv->otg, &hcd->self);
+ musb->xceiv->otg->host = &hcd->self;
+ } else {
+ phy_set_mode(musb->phy, PHY_MODE_USB_HOST);
+ }
+
/* don't support otg protocols */
hcd->self.otg_port = 0;
- musb->xceiv->otg->host = &hcd->self;
hcd->power_budget = 2 * (power_budget ? : 250);
hcd->skip_phy_initialization = 1;
diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
index cafc69536e1d..2b2164e028b3 100644
--- a/drivers/usb/musb/musb_virthub.c
+++ b/drivers/usb/musb/musb_virthub.c
@@ -43,14 +43,13 @@ void musb_host_finish_resume(struct work_struct *work)
musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
usb_hcd_poll_rh_status(musb->hcd);
/* NOTE: it might really be A_WAIT_BCON ... */
- musb->xceiv->otg->state = OTG_STATE_A_HOST;
+ musb_set_state(musb, OTG_STATE_A_HOST);
spin_unlock_irqrestore(&musb->lock, flags);
}
int musb_port_suspend(struct musb *musb, bool do_suspend)
{
- struct usb_otg *otg = musb->xceiv->otg;
u8 power;
void __iomem *mbase = musb->mregs;
@@ -85,10 +84,11 @@ int musb_port_suspend(struct musb *musb, bool do_suspend)
musb_dbg(musb, "Root port suspended, power %02x", power);
musb->port1_status |= USB_PORT_STAT_SUSPEND;
- switch (musb->xceiv->otg->state) {
+ switch (musb_get_state(musb)) {
case OTG_STATE_A_HOST:
- musb->xceiv->otg->state = OTG_STATE_A_SUSPEND;
- musb->is_active = otg->host->b_hnp_enable;
+ musb_set_state(musb, OTG_STATE_A_SUSPEND);
+ musb->is_active = musb->xceiv &&
+ musb->xceiv->otg->host->b_hnp_enable;
if (musb->is_active)
mod_timer(&musb->otg_timer, jiffies
+ msecs_to_jiffies(
@@ -96,13 +96,14 @@ int musb_port_suspend(struct musb *musb, bool do_suspend)
musb_platform_try_idle(musb, 0);
break;
case OTG_STATE_B_HOST:
- musb->xceiv->otg->state = OTG_STATE_B_WAIT_ACON;
- musb->is_active = otg->host->b_hnp_enable;
+ musb_set_state(musb, OTG_STATE_B_WAIT_ACON);
+ musb->is_active = musb->xceiv &&
+ musb->xceiv->otg->host->b_hnp_enable;
musb_platform_try_idle(musb, 0);
break;
default:
musb_dbg(musb, "bogus rh suspend? %s",
- usb_otg_state_string(musb->xceiv->otg->state));
+ musb_otg_state_string(musb));
}
} else if (power & MUSB_POWER_SUSPENDM) {
power &= ~MUSB_POWER_SUSPENDM;
@@ -123,7 +124,7 @@ void musb_port_reset(struct musb *musb, bool do_reset)
u8 power;
void __iomem *mbase = musb->mregs;
- if (musb->xceiv->otg->state == OTG_STATE_B_IDLE) {
+ if (musb_get_state(musb) == OTG_STATE_B_IDLE) {
musb_dbg(musb, "HNP: Returning from HNP; no hub reset from b_idle");
musb->port1_status &= ~USB_PORT_STAT_RESET;
return;
@@ -196,32 +197,30 @@ void musb_port_reset(struct musb *musb, bool do_reset)
void musb_root_disconnect(struct musb *musb)
{
- struct usb_otg *otg = musb->xceiv->otg;
-
musb->port1_status = USB_PORT_STAT_POWER
| (USB_PORT_STAT_C_CONNECTION << 16);
usb_hcd_poll_rh_status(musb->hcd);
musb->is_active = 0;
- switch (musb->xceiv->otg->state) {
+ switch (musb_get_state(musb)) {
case OTG_STATE_A_SUSPEND:
- if (otg->host->b_hnp_enable) {
- musb->xceiv->otg->state = OTG_STATE_A_PERIPHERAL;
+ if (musb->xceiv && musb->xceiv->otg->host->b_hnp_enable) {
+ musb_set_state(musb, OTG_STATE_A_PERIPHERAL);
musb->g.is_a_peripheral = 1;
break;
}
fallthrough;
case OTG_STATE_A_HOST:
- musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON;
+ musb_set_state(musb, OTG_STATE_A_WAIT_BCON);
musb->is_active = 0;
break;
case OTG_STATE_A_WAIT_VFALL:
- musb->xceiv->otg->state = OTG_STATE_B_IDLE;
+ musb_set_state(musb, OTG_STATE_B_IDLE);
break;
default:
musb_dbg(musb, "host disconnect (%s)",
- usb_otg_state_string(musb->xceiv->otg->state));
+ musb_otg_state_string(musb));
}
}
EXPORT_SYMBOL_GPL(musb_root_disconnect);
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 2acbe41fbf7e..915df5726a5c 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -93,12 +93,16 @@ config USB_GPIO_VBUS
tristate "GPIO based peripheral-only VBUS sensing 'transceiver'"
depends on GPIOLIB || COMPILE_TEST
depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
+ depends on !USB_CONN_GPIO
select USB_PHY
help
Provides simple GPIO VBUS sensing for controllers with an
internal transceiver via the usb_phy interface, and
optionally control of a D+ pullup GPIO as well as a VBUS
- current limit regulator.
+ current limit regulator. This driver is for devices that do
+ NOT support role switch. OTG devices that can do role switch
+ (master/peripheral) shall use the USB based connection
+ detection driver USB_CONN_GPIO.
config OMAP_OTG
tristate "OMAP USB OTG controller driver"
@@ -185,12 +189,4 @@ config USB_ULPI_VIEWPORT
Provides read/write operations to the ULPI phy register set for
controllers with a viewport register (e.g. Chipidea/ARC controllers).
-config JZ4770_PHY
- tristate "Ingenic SoCs Transceiver Driver"
- depends on MIPS || COMPILE_TEST
- select USB_PHY
- help
- This driver provides PHY support for the USB controller found
- on the JZ-series and X-series SoCs from Ingenic.
-
endmenu
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index b352bdbe8712..df1d99010079 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -24,4 +24,3 @@ obj-$(CONFIG_USB_MXS_PHY) += phy-mxs-usb.o
obj-$(CONFIG_USB_ULPI) += phy-ulpi.o
obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o
obj-$(CONFIG_KEYSTONE_USB_PHY) += phy-keystone.o
-obj-$(CONFIG_JZ4770_PHY) += phy-jz4770.o
diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
index 3dc5c04e7cbf..c1309ea24a52 100644
--- a/drivers/usb/phy/phy-generic.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -209,7 +209,7 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop)
int err = 0;
u32 clk_rate = 0;
- bool needs_vcc = false, needs_clk = false;
+ bool needs_clk = false;
if (dev->of_node) {
struct device_node *node = dev->of_node;
@@ -217,7 +217,6 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop)
if (of_property_read_u32(node, "clock-frequency", &clk_rate))
clk_rate = 0;
- needs_vcc = of_property_read_bool(node, "vcc-supply");
needs_clk = of_property_read_bool(node, "clocks");
}
nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
@@ -257,13 +256,10 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop)
}
}
- nop->vcc = devm_regulator_get(dev, "vcc");
- if (IS_ERR(nop->vcc)) {
- dev_dbg(dev, "Error getting vcc regulator: %ld\n",
- PTR_ERR(nop->vcc));
- if (needs_vcc)
- return -EPROBE_DEFER;
- }
+ nop->vcc = devm_regulator_get_optional(dev, "vcc");
+ if (IS_ERR(nop->vcc) && PTR_ERR(nop->vcc) != -ENODEV)
+ return dev_err_probe(dev, PTR_ERR(nop->vcc),
+ "could not get vcc regulator\n");
nop->vbus_draw = devm_regulator_get_exclusive(dev, "vbus");
if (PTR_ERR(nop->vbus_draw) == -ENODEV)
@@ -290,6 +286,7 @@ EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy);
static int usb_phy_generic_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct device_node *dn = dev->of_node;
struct usb_phy_generic *nop;
int err;
@@ -327,6 +324,9 @@ static int usb_phy_generic_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, nop);
+ device_set_wakeup_capable(&pdev->dev,
+ of_property_read_bool(dn, "wakeup-source"));
+
return 0;
}
diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c
index f13f5530746c..12dfeff7de3d 100644
--- a/drivers/usb/phy/phy-gpio-vbus-usb.c
+++ b/drivers/usb/phy/phy-gpio-vbus-usb.c
@@ -366,12 +366,24 @@ static const struct dev_pm_ops gpio_vbus_dev_pm_ops = {
MODULE_ALIAS("platform:gpio-vbus");
+/*
+ * NOTE: this driver matches against "gpio-usb-b-connector" for
+ * devices that do NOT support role switch.
+ */
+static const struct of_device_id gpio_vbus_of_match[] = {
+ {
+ .compatible = "gpio-usb-b-connector",
+ },
+ {},
+};
+
static struct platform_driver gpio_vbus_driver = {
.driver = {
.name = "gpio-vbus",
#ifdef CONFIG_PM
.pm = &gpio_vbus_dev_pm_ops,
#endif
+ .of_match_table = gpio_vbus_of_match,
},
.probe = gpio_vbus_probe,
.remove = gpio_vbus_remove,
diff --git a/drivers/usb/phy/phy-jz4770.c b/drivers/usb/phy/phy-jz4770.c
deleted file mode 100644
index f16adcacdce3..000000000000
--- a/drivers/usb/phy/phy-jz4770.c
+++ /dev/null
@@ -1,353 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Ingenic SoCs USB PHY driver
- * Copyright (c) Paul Cercueil <paul@crapouillou.net>
- * Copyright (c) 漆鹏振 (Qi Pengzhen) <aric.pzqi@ingenic.com>
- * Copyright (c) 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
- */
-
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/consumer.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/phy.h>
-
-/* OTGPHY register offsets */
-#define REG_USBPCR_OFFSET 0x00
-#define REG_USBRDT_OFFSET 0x04
-#define REG_USBVBFIL_OFFSET 0x08
-#define REG_USBPCR1_OFFSET 0x0c
-
-/* bits within the USBPCR register */
-#define USBPCR_USB_MODE BIT(31)
-#define USBPCR_AVLD_REG BIT(30)
-#define USBPCR_COMMONONN BIT(25)
-#define USBPCR_VBUSVLDEXT BIT(24)
-#define USBPCR_VBUSVLDEXTSEL BIT(23)
-#define USBPCR_POR BIT(22)
-#define USBPCR_SIDDQ BIT(21)
-#define USBPCR_OTG_DISABLE BIT(20)
-#define USBPCR_TXPREEMPHTUNE BIT(6)
-
-#define USBPCR_IDPULLUP_LSB 28
-#define USBPCR_IDPULLUP_MASK GENMASK(29, USBPCR_IDPULLUP_LSB)
-#define USBPCR_IDPULLUP_ALWAYS (0x2 << USBPCR_IDPULLUP_LSB)
-#define USBPCR_IDPULLUP_SUSPEND (0x1 << USBPCR_IDPULLUP_LSB)
-#define USBPCR_IDPULLUP_OTG (0x0 << USBPCR_IDPULLUP_LSB)
-
-#define USBPCR_COMPDISTUNE_LSB 17
-#define USBPCR_COMPDISTUNE_MASK GENMASK(19, USBPCR_COMPDISTUNE_LSB)
-#define USBPCR_COMPDISTUNE_DFT (0x4 << USBPCR_COMPDISTUNE_LSB)
-
-#define USBPCR_OTGTUNE_LSB 14
-#define USBPCR_OTGTUNE_MASK GENMASK(16, USBPCR_OTGTUNE_LSB)
-#define USBPCR_OTGTUNE_DFT (0x4 << USBPCR_OTGTUNE_LSB)
-
-#define USBPCR_SQRXTUNE_LSB 11
-#define USBPCR_SQRXTUNE_MASK GENMASK(13, USBPCR_SQRXTUNE_LSB)
-#define USBPCR_SQRXTUNE_DCR_20PCT (0x7 << USBPCR_SQRXTUNE_LSB)
-#define USBPCR_SQRXTUNE_DFT (0x3 << USBPCR_SQRXTUNE_LSB)
-
-#define USBPCR_TXFSLSTUNE_LSB 7
-#define USBPCR_TXFSLSTUNE_MASK GENMASK(10, USBPCR_TXFSLSTUNE_LSB)
-#define USBPCR_TXFSLSTUNE_DCR_50PPT (0xf << USBPCR_TXFSLSTUNE_LSB)
-#define USBPCR_TXFSLSTUNE_DCR_25PPT (0x7 << USBPCR_TXFSLSTUNE_LSB)
-#define USBPCR_TXFSLSTUNE_DFT (0x3 << USBPCR_TXFSLSTUNE_LSB)
-#define USBPCR_TXFSLSTUNE_INC_25PPT (0x1 << USBPCR_TXFSLSTUNE_LSB)
-#define USBPCR_TXFSLSTUNE_INC_50PPT (0x0 << USBPCR_TXFSLSTUNE_LSB)
-
-#define USBPCR_TXHSXVTUNE_LSB 4
-#define USBPCR_TXHSXVTUNE_MASK GENMASK(5, USBPCR_TXHSXVTUNE_LSB)
-#define USBPCR_TXHSXVTUNE_DFT (0x3 << USBPCR_TXHSXVTUNE_LSB)
-#define USBPCR_TXHSXVTUNE_DCR_15MV (0x1 << USBPCR_TXHSXVTUNE_LSB)
-
-#define USBPCR_TXRISETUNE_LSB 4
-#define USBPCR_TXRISETUNE_MASK GENMASK(5, USBPCR_TXRISETUNE_LSB)
-#define USBPCR_TXRISETUNE_DFT (0x3 << USBPCR_TXRISETUNE_LSB)
-
-#define USBPCR_TXVREFTUNE_LSB 0
-#define USBPCR_TXVREFTUNE_MASK GENMASK(3, USBPCR_TXVREFTUNE_LSB)
-#define USBPCR_TXVREFTUNE_INC_25PPT (0x7 << USBPCR_TXVREFTUNE_LSB)
-#define USBPCR_TXVREFTUNE_DFT (0x5 << USBPCR_TXVREFTUNE_LSB)
-
-/* bits within the USBRDTR register */
-#define USBRDT_UTMI_RST BIT(27)
-#define USBRDT_HB_MASK BIT(26)
-#define USBRDT_VBFIL_LD_EN BIT(25)
-#define USBRDT_IDDIG_EN BIT(24)
-#define USBRDT_IDDIG_REG BIT(23)
-#define USBRDT_VBFIL_EN BIT(2)
-
-/* bits within the USBPCR1 register */
-#define USBPCR1_BVLD_REG BIT(31)
-#define USBPCR1_DPPD BIT(29)
-#define USBPCR1_DMPD BIT(28)
-#define USBPCR1_USB_SEL BIT(28)
-#define USBPCR1_WORD_IF_16BIT BIT(19)
-
-enum ingenic_usb_phy_version {
- ID_JZ4770,
- ID_JZ4780,
- ID_X1000,
- ID_X1830,
-};
-
-struct ingenic_soc_info {
- enum ingenic_usb_phy_version version;
-
- void (*usb_phy_init)(struct usb_phy *phy);
-};
-
-struct jz4770_phy {
- const struct ingenic_soc_info *soc_info;
-
- struct usb_phy phy;
- struct usb_otg otg;
- struct device *dev;
- void __iomem *base;
- struct clk *clk;
- struct regulator *vcc_supply;
-};
-
-static inline struct jz4770_phy *otg_to_jz4770_phy(struct usb_otg *otg)
-{
- return container_of(otg, struct jz4770_phy, otg);
-}
-
-static inline struct jz4770_phy *phy_to_jz4770_phy(struct usb_phy *phy)
-{
- return container_of(phy, struct jz4770_phy, phy);
-}
-
-static int ingenic_usb_phy_set_peripheral(struct usb_otg *otg,
- struct usb_gadget *gadget)
-{
- struct jz4770_phy *priv = otg_to_jz4770_phy(otg);
- u32 reg;
-
- if (priv->soc_info->version >= ID_X1000) {
- reg = readl(priv->base + REG_USBPCR1_OFFSET);
- reg |= USBPCR1_BVLD_REG;
- writel(reg, priv->base + REG_USBPCR1_OFFSET);
- }
-
- reg = readl(priv->base + REG_USBPCR_OFFSET);
- reg &= ~USBPCR_USB_MODE;
- reg |= USBPCR_VBUSVLDEXT | USBPCR_VBUSVLDEXTSEL | USBPCR_OTG_DISABLE;
- writel(reg, priv->base + REG_USBPCR_OFFSET);
-
- return 0;
-}
-
-static int ingenic_usb_phy_set_host(struct usb_otg *otg, struct usb_bus *host)
-{
- struct jz4770_phy *priv = otg_to_jz4770_phy(otg);
- u32 reg;
-
- reg = readl(priv->base + REG_USBPCR_OFFSET);
- reg &= ~(USBPCR_VBUSVLDEXT | USBPCR_VBUSVLDEXTSEL | USBPCR_OTG_DISABLE);
- reg |= USBPCR_USB_MODE;
- writel(reg, priv->base + REG_USBPCR_OFFSET);
-
- return 0;
-}
-
-static int ingenic_usb_phy_init(struct usb_phy *phy)
-{
- struct jz4770_phy *priv = phy_to_jz4770_phy(phy);
- int err;
- u32 reg;
-
- err = regulator_enable(priv->vcc_supply);
- if (err) {
- dev_err(priv->dev, "Unable to enable VCC: %d\n", err);
- return err;
- }
-
- err = clk_prepare_enable(priv->clk);
- if (err) {
- dev_err(priv->dev, "Unable to start clock: %d\n", err);
- return err;
- }
-
- priv->soc_info->usb_phy_init(phy);
-
- /* Wait for PHY to reset */
- usleep_range(30, 300);
- reg = readl(priv->base + REG_USBPCR_OFFSET);
- writel(reg & ~USBPCR_POR, priv->base + REG_USBPCR_OFFSET);
- usleep_range(300, 1000);
-
- return 0;
-}
-
-static void ingenic_usb_phy_shutdown(struct usb_phy *phy)
-{
- struct jz4770_phy *priv = phy_to_jz4770_phy(phy);
-
- clk_disable_unprepare(priv->clk);
- regulator_disable(priv->vcc_supply);
-}
-
-static void ingenic_usb_phy_remove(void *phy)
-{
- usb_remove_phy(phy);
-}
-
-static void jz4770_usb_phy_init(struct usb_phy *phy)
-{
- struct jz4770_phy *priv = phy_to_jz4770_phy(phy);
- u32 reg;
-
- reg = USBPCR_AVLD_REG | USBPCR_COMMONONN | USBPCR_IDPULLUP_ALWAYS |
- USBPCR_COMPDISTUNE_DFT | USBPCR_OTGTUNE_DFT | USBPCR_SQRXTUNE_DFT |
- USBPCR_TXFSLSTUNE_DFT | USBPCR_TXRISETUNE_DFT | USBPCR_TXVREFTUNE_DFT |
- USBPCR_POR;
- writel(reg, priv->base + REG_USBPCR_OFFSET);
-}
-
-static void jz4780_usb_phy_init(struct usb_phy *phy)
-{
- struct jz4770_phy *priv = phy_to_jz4770_phy(phy);
- u32 reg;
-
- reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_USB_SEL |
- USBPCR1_WORD_IF_16BIT;
- writel(reg, priv->base + REG_USBPCR1_OFFSET);
-
- reg = USBPCR_TXPREEMPHTUNE | USBPCR_COMMONONN | USBPCR_POR;
- writel(reg, priv->base + REG_USBPCR_OFFSET);
-}
-
-static void x1000_usb_phy_init(struct usb_phy *phy)
-{
- struct jz4770_phy *priv = phy_to_jz4770_phy(phy);
- u32 reg;
-
- reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_WORD_IF_16BIT;
- writel(reg, priv->base + REG_USBPCR1_OFFSET);
-
- reg = USBPCR_SQRXTUNE_DCR_20PCT | USBPCR_TXPREEMPHTUNE |
- USBPCR_TXHSXVTUNE_DCR_15MV | USBPCR_TXVREFTUNE_INC_25PPT |
- USBPCR_COMMONONN | USBPCR_POR;
- writel(reg, priv->base + REG_USBPCR_OFFSET);
-}
-
-static void x1830_usb_phy_init(struct usb_phy *phy)
-{
- struct jz4770_phy *priv = phy_to_jz4770_phy(phy);
- u32 reg;
-
- /* rdt */
- writel(USBRDT_VBFIL_EN | USBRDT_UTMI_RST, priv->base + REG_USBRDT_OFFSET);
-
- reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_WORD_IF_16BIT |
- USBPCR1_DMPD | USBPCR1_DPPD;
- writel(reg, priv->base + REG_USBPCR1_OFFSET);
-
- reg = USBPCR_IDPULLUP_OTG | USBPCR_VBUSVLDEXT | USBPCR_TXPREEMPHTUNE |
- USBPCR_COMMONONN | USBPCR_POR;
- writel(reg, priv->base + REG_USBPCR_OFFSET);
-}
-
-static const struct ingenic_soc_info jz4770_soc_info = {
- .version = ID_JZ4770,
-
- .usb_phy_init = jz4770_usb_phy_init,
-};
-
-static const struct ingenic_soc_info jz4780_soc_info = {
- .version = ID_JZ4780,
-
- .usb_phy_init = jz4780_usb_phy_init,
-};
-
-static const struct ingenic_soc_info x1000_soc_info = {
- .version = ID_X1000,
-
- .usb_phy_init = x1000_usb_phy_init,
-};
-
-static const struct ingenic_soc_info x1830_soc_info = {
- .version = ID_X1830,
-
- .usb_phy_init = x1830_usb_phy_init,
-};
-
-static const struct of_device_id ingenic_usb_phy_of_matches[] = {
- { .compatible = "ingenic,jz4770-phy", .data = &jz4770_soc_info },
- { .compatible = "ingenic,jz4780-phy", .data = &jz4780_soc_info },
- { .compatible = "ingenic,x1000-phy", .data = &x1000_soc_info },
- { .compatible = "ingenic,x1830-phy", .data = &x1830_soc_info },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, ingenic_usb_phy_of_matches);
-
-static int jz4770_phy_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct jz4770_phy *priv;
- int err;
-
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- priv->soc_info = device_get_match_data(&pdev->dev);
- if (!priv->soc_info) {
- dev_err(&pdev->dev, "Error: No device match found\n");
- return -ENODEV;
- }
-
- platform_set_drvdata(pdev, priv);
- priv->dev = dev;
- priv->phy.dev = dev;
- priv->phy.otg = &priv->otg;
- priv->phy.label = "ingenic-usb-phy";
- priv->phy.init = ingenic_usb_phy_init;
- priv->phy.shutdown = ingenic_usb_phy_shutdown;
-
- priv->otg.state = OTG_STATE_UNDEFINED;
- priv->otg.usb_phy = &priv->phy;
- priv->otg.set_host = ingenic_usb_phy_set_host;
- priv->otg.set_peripheral = ingenic_usb_phy_set_peripheral;
-
- priv->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(priv->base)) {
- dev_err(dev, "Failed to map registers\n");
- return PTR_ERR(priv->base);
- }
-
- priv->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(priv->clk))
- return dev_err_probe(dev, PTR_ERR(priv->clk),
- "Failed to get clock\n");
-
- priv->vcc_supply = devm_regulator_get(dev, "vcc");
- if (IS_ERR(priv->vcc_supply))
- return dev_err_probe(dev, PTR_ERR(priv->vcc_supply),
- "Failed to get regulator\n");
-
- err = usb_add_phy(&priv->phy, USB_PHY_TYPE_USB2);
- if (err)
- return dev_err_probe(dev, err, "Unable to register PHY\n");
-
- return devm_add_action_or_reset(dev, ingenic_usb_phy_remove, &priv->phy);
-}
-
-static struct platform_driver ingenic_phy_driver = {
- .probe = jz4770_phy_probe,
- .driver = {
- .name = "jz4770-phy",
- .of_match_table = ingenic_usb_phy_of_matches,
- },
-};
-module_platform_driver(ingenic_phy_driver);
-
-MODULE_AUTHOR("周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>");
-MODULE_AUTHOR("漆鹏振 (Qi Pengzhen) <aric.pzqi@ingenic.com>");
-MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
-MODULE_DESCRIPTION("Ingenic SoCs USB PHY driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/typec/retimer.c b/drivers/usb/typec/retimer.c
index ee94dbbe4745..3a4146ea6e7c 100644
--- a/drivers/usb/typec/retimer.c
+++ b/drivers/usb/typec/retimer.c
@@ -17,21 +17,9 @@
#include "class.h"
#include "retimer.h"
-static bool dev_name_ends_with(struct device *dev, const char *suffix)
-{
- const char *name = dev_name(dev);
- const int name_len = strlen(name);
- const int suffix_len = strlen(suffix);
-
- if (suffix_len > name_len)
- return false;
-
- return strcmp(name + (name_len - suffix_len), suffix) == 0;
-}
-
static int retimer_fwnode_match(struct device *dev, const void *fwnode)
{
- return device_match_fwnode(dev, fwnode) && dev_name_ends_with(dev, "-retimer");
+ return is_typec_retimer(dev) && device_match_fwnode(dev, fwnode);
}
static void *typec_retimer_match(struct fwnode_handle *fwnode, const char *id, void *data)
@@ -97,7 +85,7 @@ static void typec_retimer_release(struct device *dev)
kfree(to_typec_retimer(dev));
}
-static const struct device_type typec_retimer_dev_type = {
+const struct device_type typec_retimer_dev_type = {
.name = "typec_retimer",
.release = typec_retimer_release,
};
diff --git a/drivers/usb/typec/retimer.h b/drivers/usb/typec/retimer.h
index fa15951d4846..e34bd23323be 100644
--- a/drivers/usb/typec/retimer.h
+++ b/drivers/usb/typec/retimer.h
@@ -12,4 +12,8 @@ struct typec_retimer {
#define to_typec_retimer(_dev_) container_of(_dev_, struct typec_retimer, dev)
+const struct device_type typec_retimer_dev_type;
+
+#define is_typec_retimer(dev) ((dev)->type == &typec_retimer_dev_type)
+
#endif /* __USB_TYPEC_RETIMER__ */
diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c
index 3c6d452e3bf4..9c6954aad6c8 100644
--- a/drivers/usb/usbip/stub_dev.c
+++ b/drivers/usb/usbip/stub_dev.c
@@ -30,7 +30,7 @@ static ssize_t usbip_status_show(struct device *dev,
status = sdev->ud.status;
spin_unlock_irq(&sdev->ud.lock);
- return snprintf(buf, PAGE_SIZE, "%d\n", status);
+ return sysfs_emit(buf, "%d\n", status);
}
static DEVICE_ATTR_RO(usbip_status);
@@ -118,6 +118,8 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
} else {
dev_info(dev, "stub down\n");
+ mutex_lock(&sdev->ud.sysfs_lock);
+
spin_lock_irq(&sdev->ud.lock);
if (sdev->ud.status != SDEV_ST_USED)
goto err;
diff --git a/drivers/usb/usbip/vudc_rx.c b/drivers/usb/usbip/vudc_rx.c
index d4a2f30a7580..51bb70837b90 100644
--- a/drivers/usb/usbip/vudc_rx.c
+++ b/drivers/usb/usbip/vudc_rx.c
@@ -149,7 +149,9 @@ static int v_recv_cmd_submit(struct vudc *udc,
urb_p->urb->status = -EINPROGRESS;
/* FIXME: more pipe setup to please usbip_common */
- urb_p->urb->pipe &= ~(3 << 30);
+ BUILD_BUG_ON_MSG(PIPE_BULK != 3, "PIPE_* doesn't range from 0 to 3");
+
+ urb_p->urb->pipe &= ~(PIPE_BULK << 30);
switch (urb_p->ep->type) {
case USB_ENDPOINT_XFER_BULK:
urb_p->urb->pipe |= (PIPE_BULK << 30);
diff --git a/drivers/usb/usbip/vudc_sysfs.c b/drivers/usb/usbip/vudc_sysfs.c
index c95e6b2bfd32..907a43a00896 100644
--- a/drivers/usb/usbip/vudc_sysfs.c
+++ b/drivers/usb/usbip/vudc_sysfs.c
@@ -242,7 +242,7 @@ static ssize_t usbip_status_show(struct device *dev,
status = udc->ud.status;
spin_unlock_irq(&udc->ud.lock);
- return snprintf(out, PAGE_SIZE, "%d\n", status);
+ return sysfs_emit(out, "%d\n", status);
}
static DEVICE_ATTR_RO(usbip_status);
diff --git a/include/uapi/linux/usb/g_uvc.h b/include/uapi/linux/usb/g_uvc.h
index 652f169a019e..8d7824dde1b2 100644
--- a/include/uapi/linux/usb/g_uvc.h
+++ b/include/uapi/linux/usb/g_uvc.h
@@ -21,6 +21,9 @@
#define UVC_EVENT_DATA (V4L2_EVENT_PRIVATE_START + 5)
#define UVC_EVENT_LAST (V4L2_EVENT_PRIVATE_START + 5)
+#define UVC_STRING_CONTROL_IDX 0
+#define UVC_STRING_STREAMING_IDX 1
+
struct uvc_request_data {
__s32 length;
__u8 data[60];
diff --git a/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c
index 1f44a29818bf..96616eb4600b 100644
--- a/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c
+++ b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c
@@ -25,7 +25,9 @@
* For more information, please refer to <http://unlicense.org/>
*/
-#define _BSD_SOURCE /* for endian.h */
+/* $(CROSS_COMPILE)cc -g -o aio_simple aio_simple.c -laio */
+
+#define _DEFAULT_SOURCE /* for endian.h */
#include <endian.h>
#include <errno.h>
@@ -49,6 +51,22 @@
#define BUF_LEN 8192
+/*
+ * cpu_to_le16/32 are used when initializing structures, a context where a
+ * function call is not allowed. To solve this, we code cpu_to_le16/32 in a way
+ * that allows them to be used when initializing structures.
+ */
+
+#if BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le16(x) (x)
+#define cpu_to_le32(x) (x)
+#else
+#define cpu_to_le16(x) ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8))
+#define cpu_to_le32(x) \
+ ((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >> 8) | \
+ (((x) & 0x0000ff00u) << 8) | (((x) & 0x000000ffu) << 24))
+#endif
+
/******************** Descriptors and Strings *******************************/
static const struct {
@@ -62,12 +80,12 @@ static const struct {
} __attribute__ ((__packed__)) fs_descs, hs_descs;
} __attribute__ ((__packed__)) descriptors = {
.header = {
- .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
- .flags = htole32(FUNCTIONFS_HAS_FS_DESC |
+ .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
+ .flags = cpu_to_le32(FUNCTIONFS_HAS_FS_DESC |
FUNCTIONFS_HAS_HS_DESC),
- .length = htole32(sizeof(descriptors)),
+ .length = cpu_to_le32(sizeof(descriptors)),
},
- .fs_count = htole32(3),
+ .fs_count = cpu_to_le32(3),
.fs_descs = {
.intf = {
.bLength = sizeof(descriptors.fs_descs.intf),
@@ -89,7 +107,7 @@ static const struct {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
},
},
- .hs_count = htole32(3),
+ .hs_count = cpu_to_le32(3),
.hs_descs = {
.intf = {
.bLength = sizeof(descriptors.hs_descs.intf),
@@ -103,14 +121,14 @@ static const struct {
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 1 | USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = htole16(512),
+ .wMaxPacketSize = cpu_to_le16(512),
},
.bulk_source = {
.bLength = sizeof(descriptors.hs_descs.bulk_source),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 2 | USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = htole16(512),
+ .wMaxPacketSize = cpu_to_le16(512),
},
},
};
@@ -125,13 +143,13 @@ static const struct {
} __attribute__ ((__packed__)) lang0;
} __attribute__ ((__packed__)) strings = {
.header = {
- .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
- .length = htole32(sizeof(strings)),
- .str_count = htole32(1),
- .lang_count = htole32(1),
+ .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
+ .length = cpu_to_le32(sizeof(strings)),
+ .str_count = cpu_to_le32(1),
+ .lang_count = cpu_to_le32(1),
},
.lang0 = {
- htole16(0x0409), /* en-us */
+ cpu_to_le16(0x0409), /* en-us */
STR_INTERFACE,
},
};