mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-06 13:16:22 +00:00
USB/Thunderbolt driver changes for 6.2-rc1
Here is the large set of USB and Thunderbolt driver changes for 6.2-rc1. Overall, thanks to the removal of a driver, more lines were removed than added, a nice change. Highlights include: - removal of the sisusbvga driver that was not used by anyone anymore - minor thunderbolt driver changes and tweaks - chipidea driver updates - usual set of typec driver features and hardware support added - musb minor driver fixes - fotg210 driver fixes, bringing that hardware back from the "dead" - minor dwc3 driver updates - addition, and then removal, of a list.h helper function for many USB and other subsystem drivers, that ended up breaking the build. That will come back for 6.3-rc1, it missed this merge window. - usual xhci updates and enhancements - usb-serial driver updates and support for new devices - other minor USB driver updates All of these have been in linux-next for a while with no reported problems. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCY5wvYg8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yl5DACgssl/ag4zDePHpfoiG5zEGEzH8XsAoMFrzvzu d43hsH3qsfDGSZRkJJMu =ORDd -----END PGP SIGNATURE----- Merge tag 'usb-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB and Thunderbolt driver updates from Greg KH: "Here is the large set of USB and Thunderbolt driver changes for 6.2-rc1. Overall, thanks to the removal of a driver, more lines were removed than added, a nice change. Highlights include: - removal of the sisusbvga driver that was not used by anyone anymore - minor thunderbolt driver changes and tweaks - chipidea driver updates - usual set of typec driver features and hardware support added - musb minor driver fixes - fotg210 driver fixes, bringing that hardware back from the "dead" - minor dwc3 driver updates - addition, and then removal, of a list.h helper function for many USB and other subsystem drivers, that ended up breaking the build. That will come back for 6.3-rc1, it missed this merge window. - usual xhci updates and enhancements - usb-serial driver updates and support for new devices - other minor USB driver updates All of these have been in linux-next for a while with no reported problems" * tag 'usb-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (153 commits) usb: gadget: uvc: Rename bmInterfaceFlags -> bmInterlaceFlags usb: dwc2: power on/off phy for peripheral mode in dual-role mode usb: dwc2: disable lpm feature on Rockchip SoCs dt-bindings: usb: mtk-xhci: add support for mt7986 usb: dwc3: core: defer probe on ulpi_read_id timeout usb: ulpi: defer ulpi_register on ulpi_read_id timeout usb: misc: onboard_usb_hub: add Genesys Logic GL850G hub support dt-bindings: usb: Add binding for Genesys Logic GL850G hub controller dt-bindings: vendor-prefixes: add Genesys Logic usb: fotg210-udc: fix potential memory leak in fotg210_udc_probe() usb: typec: tipd: Set mode of operation for USB Type-C connector usb: gadget: udc: drop obsolete dependencies on COMPILE_TEST usb: musb: remove extra check in musb_gadget_vbus_draw usb: gadget: uvc: Prevent buffer overflow in setup handler usb: dwc3: qcom: Fix memory leak in dwc3_qcom_interconnect_init usb: typec: wusb3801: fix fwnode refcount leak in wusb3801_probe() usb: storage: Add check for kcalloc USB: sisusbvga: use module_usb_driver() USB: sisusbvga: rename sisusb.c to sisusbvga.c USB: sisusbvga: remove console support ...
This commit is contained in:
commit
58bcac11fd
@ -197,7 +197,7 @@ Description: Specific MJPEG format descriptors
|
||||
read-only
|
||||
bmaControls this format's data for bmaControls in
|
||||
the streaming header
|
||||
bmInterfaceFlags specifies interlace information,
|
||||
bmInterlaceFlags specifies interlace information,
|
||||
read-only
|
||||
bAspectRatioY the X dimension of the picture aspect
|
||||
ratio, read-only
|
||||
@ -253,7 +253,7 @@ Description: Specific uncompressed format descriptors
|
||||
read-only
|
||||
bmaControls this format's data for bmaControls in
|
||||
the streaming header
|
||||
bmInterfaceFlags specifies interlace information,
|
||||
bmInterlaceFlags specifies interlace information,
|
||||
read-only
|
||||
bAspectRatioY the X dimension of the picture aspect
|
||||
ratio, read-only
|
||||
|
@ -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>
|
||||
|
@ -28,6 +28,9 @@ properties:
|
||||
items:
|
||||
- const: phy
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
vbus-supply:
|
||||
description:
|
||||
A phandle to the regulator for USB VBUS.
|
||||
|
@ -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
|
||||
|
48
Documentation/devicetree/bindings/usb/genesys,gl850g.yaml
Normal file
48
Documentation/devicetree/bindings/usb/genesys,gl850g.yaml
Normal file
@ -0,0 +1,48 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/usb/genesys,gl850g.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Genesys Logic GL850G USB 2.0 hub controller
|
||||
|
||||
maintainers:
|
||||
- Icenowy Zheng <uwu@icenowy.me>
|
||||
|
||||
allOf:
|
||||
- $ref: usb-device.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- usb5e3,608
|
||||
|
||||
reg: true
|
||||
|
||||
reset-gpios:
|
||||
description: GPIO controlling the RESET# pin.
|
||||
|
||||
vdd-supply:
|
||||
description:
|
||||
the regulator that provides 3.3V core power to the hub.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
usb {
|
||||
dr_mode = "host";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
hub: hub@1 {
|
||||
compatible = "usb5e3,608";
|
||||
reg = <1>;
|
||||
reset-gpios = <&pio 7 2 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
@ -28,6 +28,7 @@ properties:
|
||||
- mediatek,mt7622-xhci
|
||||
- mediatek,mt7623-xhci
|
||||
- mediatek,mt7629-xhci
|
||||
- mediatek,mt7986-xhci
|
||||
- mediatek,mt8173-xhci
|
||||
- mediatek,mt8183-xhci
|
||||
- mediatek,mt8186-xhci
|
||||
|
@ -24,6 +24,7 @@ properties:
|
||||
- mediatek,mt2712-mtu3
|
||||
- mediatek,mt8173-mtu3
|
||||
- mediatek,mt8183-mtu3
|
||||
- mediatek,mt8186-mtu3
|
||||
- mediatek,mt8188-mtu3
|
||||
- mediatek,mt8192-mtu3
|
||||
- mediatek,mt8195-mtu3
|
||||
|
@ -39,6 +39,7 @@ properties:
|
||||
- qcom,sm8250-dwc3
|
||||
- qcom,sm8350-dwc3
|
||||
- qcom,sm8450-dwc3
|
||||
- qcom,sm8550-dwc3
|
||||
- const: qcom,dwc3
|
||||
|
||||
reg:
|
||||
@ -301,6 +302,7 @@ allOf:
|
||||
- qcom,sm8150-dwc3
|
||||
- qcom,sm8250-dwc3
|
||||
- qcom,sm8450-dwc3
|
||||
- qcom,sm8550-dwc3
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
@ -358,6 +360,7 @@ allOf:
|
||||
- qcom,sm8250-dwc3
|
||||
- qcom,sm8350-dwc3
|
||||
- qcom,sm8450-dwc3
|
||||
- qcom,sm8550-dwc3
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
|
@ -27,6 +27,7 @@ properties:
|
||||
should default to OTG.
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
enum: [host, peripheral, otg]
|
||||
default: otg
|
||||
|
||||
hnp-disable:
|
||||
description:
|
||||
|
@ -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'
|
||||
|
@ -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>;
|
||||
};
|
271
Documentation/devicetree/bindings/usb/usb251xb.yaml
Normal file
271
Documentation/devicetree/bindings/usb/usb251xb.yaml
Normal file
@ -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>;
|
||||
};
|
||||
};
|
@ -494,6 +494,8 @@ patternProperties:
|
||||
description: GE Fanuc Intelligent Platforms Embedded Systems, Inc.
|
||||
"^gemei,.*":
|
||||
description: Gemei Digital Technology Co., Ltd.
|
||||
"^genesys,.*":
|
||||
description: Genesys Logic, Inc.
|
||||
"^geniatech,.*":
|
||||
description: Geniatech, Inc.
|
||||
"^giantec,.*":
|
||||
|
@ -395,6 +395,8 @@ PCI
|
||||
|
||||
PHY
|
||||
devm_usb_get_phy()
|
||||
devm_usb_get_phy_by_node()
|
||||
devm_usb_get_phy_by_phandle()
|
||||
devm_usb_put_phy()
|
||||
|
||||
PINCTRL
|
||||
|
@ -7935,6 +7935,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
|
||||
@ -13795,7 +13801,7 @@ MICROCHIP USB251XB DRIVER
|
||||
M: Richard Leitner <richard.leitner@skidata.com>
|
||||
L: linux-usb@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/usb/usb251xb.txt
|
||||
F: Documentation/devicetree/bindings/usb/usb251xb.yaml
|
||||
F: drivers/usb/misc/usb251xb.c
|
||||
|
||||
MICROCHIP USBA UDC DRIVER
|
||||
|
@ -911,7 +911,6 @@ CONFIG_USB_IDMOUSE=m
|
||||
CONFIG_USB_FTDI_ELAN=m
|
||||
CONFIG_USB_APPLEDISPLAY=m
|
||||
CONFIG_USB_SISUSBVGA=m
|
||||
CONFIG_USB_SISUSBVGA_CON=y
|
||||
CONFIG_USB_LD=m
|
||||
CONFIG_USB_TRANCEVIBRATOR=m
|
||||
CONFIG_USB_IOWARRIOR=m
|
||||
|
@ -92,7 +92,6 @@ CONFIG_USB_SERIAL_PL2303=m
|
||||
CONFIG_USB_EMI62=m
|
||||
CONFIG_USB_EMI26=m
|
||||
CONFIG_USB_SISUSBVGA=m
|
||||
CONFIG_USB_SISUSBVGA_CON=y
|
||||
CONFIG_EXT2_FS=y
|
||||
CONFIG_EXT3_FS=y
|
||||
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
|
||||
|
@ -313,9 +313,9 @@ static void tusb320_typec_irq_handler(struct tusb320_priv *priv, u8 reg9)
|
||||
typec_set_pwr_opmode(port, TYPEC_PWR_MODE_USB);
|
||||
}
|
||||
|
||||
static irqreturn_t tusb320_irq_handler(int irq, void *dev_id)
|
||||
static irqreturn_t tusb320_state_update_handler(struct tusb320_priv *priv,
|
||||
bool force_update)
|
||||
{
|
||||
struct tusb320_priv *priv = dev_id;
|
||||
unsigned int reg;
|
||||
|
||||
if (regmap_read(priv->regmap, TUSB320_REG9, ®)) {
|
||||
@ -323,7 +323,7 @@ static irqreturn_t tusb320_irq_handler(int irq, void *dev_id)
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (!(reg & TUSB320_REG9_INTERRUPT_STATUS))
|
||||
if (!force_update && !(reg & TUSB320_REG9_INTERRUPT_STATUS))
|
||||
return IRQ_NONE;
|
||||
|
||||
tusb320_extcon_irq_handler(priv, reg);
|
||||
@ -340,6 +340,13 @@ static irqreturn_t tusb320_irq_handler(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t tusb320_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct tusb320_priv *priv = dev_id;
|
||||
|
||||
return tusb320_state_update_handler(priv, false);
|
||||
}
|
||||
|
||||
static const struct regmap_config tusb320_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
@ -466,7 +473,7 @@ static int tusb320_probe(struct i2c_client *client,
|
||||
return ret;
|
||||
|
||||
/* update initial state */
|
||||
tusb320_irq_handler(client->irq, priv);
|
||||
tusb320_state_update_handler(priv, true);
|
||||
|
||||
/* Reset chip to its default state */
|
||||
ret = tusb320_reset(priv);
|
||||
@ -477,7 +484,7 @@ static int tusb320_probe(struct i2c_client *client,
|
||||
* State and polarity might change after a reset, so update
|
||||
* them again and make sure the interrupt status bit is cleared.
|
||||
*/
|
||||
tusb320_irq_handler(client->irq, priv);
|
||||
tusb320_state_update_handler(priv, true);
|
||||
|
||||
ret = devm_request_threaded_irq(priv->dev, client->irq, NULL,
|
||||
tusb320_irq_handler,
|
||||
|
@ -971,7 +971,7 @@ static void cros_typec_register_partner_pdos(struct cros_typec_data *typec,
|
||||
if (!resp->source_cap_count && !resp->sink_cap_count)
|
||||
return;
|
||||
|
||||
port->partner_pd = usb_power_delivery_register(NULL, &desc);
|
||||
port->partner_pd = typec_partner_usb_power_delivery_register(port->partner, &desc);
|
||||
if (IS_ERR(port->partner_pd)) {
|
||||
dev_warn(typec->dev, "Failed to register partner PD device, port: %d\n", port_num);
|
||||
return;
|
||||
|
@ -15,24 +15,20 @@ static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
|
||||
void **return_value)
|
||||
{
|
||||
struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
|
||||
struct fwnode_reference_args args;
|
||||
struct fwnode_handle *fwnode;
|
||||
struct tb_nhi *nhi = data;
|
||||
struct pci_dev *pdev;
|
||||
struct device *dev;
|
||||
int ret;
|
||||
|
||||
if (!adev)
|
||||
return AE_OK;
|
||||
|
||||
fwnode = acpi_fwnode_handle(adev);
|
||||
ret = fwnode_property_get_reference_args(fwnode, "usb4-host-interface",
|
||||
NULL, 0, 0, &args);
|
||||
if (ret)
|
||||
fwnode = fwnode_find_reference(acpi_fwnode_handle(adev), "usb4-host-interface", 0);
|
||||
if (IS_ERR(fwnode))
|
||||
return AE_OK;
|
||||
|
||||
/* It needs to reference this NHI */
|
||||
if (dev_fwnode(&nhi->pdev->dev) != args.fwnode)
|
||||
if (dev_fwnode(&nhi->pdev->dev) != fwnode)
|
||||
goto out_put;
|
||||
|
||||
/*
|
||||
@ -100,7 +96,7 @@ static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
|
||||
}
|
||||
|
||||
out_put:
|
||||
fwnode_handle_put(args.fwnode);
|
||||
fwnode_handle_put(fwnode);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
|
@ -8,12 +8,13 @@
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nvmem-provider.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string_helpers.h>
|
||||
|
||||
#include "tb.h"
|
||||
|
||||
@ -644,7 +645,7 @@ static int __tb_port_enable(struct tb_port *port, bool enable)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tb_port_dbg(port, "lane %sabled\n", enable ? "en" : "dis");
|
||||
tb_port_dbg(port, "lane %s\n", str_enabled_disabled(enable));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -361,6 +361,8 @@ struct tb_regs_port_header {
|
||||
#define PORT_CS_18_BE BIT(8)
|
||||
#define PORT_CS_18_TCM BIT(9)
|
||||
#define PORT_CS_18_CPS BIT(10)
|
||||
#define PORT_CS_18_WOCS BIT(16)
|
||||
#define PORT_CS_18_WODS BIT(17)
|
||||
#define PORT_CS_18_WOU4S BIT(18)
|
||||
#define PORT_CS_19 0x13
|
||||
#define PORT_CS_19_PC BIT(3)
|
||||
|
@ -155,6 +155,8 @@ static inline int usb4_switch_op_data(struct tb_switch *sw, u16 opcode,
|
||||
|
||||
static void usb4_switch_check_wakes(struct tb_switch *sw)
|
||||
{
|
||||
bool wakeup_usb4 = false;
|
||||
struct usb4_port *usb4;
|
||||
struct tb_port *port;
|
||||
bool wakeup = false;
|
||||
u32 val;
|
||||
@ -173,20 +175,31 @@ static void usb4_switch_check_wakes(struct tb_switch *sw)
|
||||
wakeup = val & (ROUTER_CS_6_WOPS | ROUTER_CS_6_WOUS);
|
||||
}
|
||||
|
||||
/* Check for any connected downstream ports for USB4 wake */
|
||||
/*
|
||||
* Check for any downstream ports for USB4 wake,
|
||||
* connection wake and disconnection wake.
|
||||
*/
|
||||
tb_switch_for_each_port(sw, port) {
|
||||
if (!tb_port_has_remote(port))
|
||||
if (!port->cap_usb4)
|
||||
continue;
|
||||
|
||||
if (tb_port_read(port, &val, TB_CFG_PORT,
|
||||
port->cap_usb4 + PORT_CS_18, 1))
|
||||
break;
|
||||
|
||||
tb_port_dbg(port, "USB4 wake: %s\n",
|
||||
(val & PORT_CS_18_WOU4S) ? "yes" : "no");
|
||||
tb_port_dbg(port, "USB4 wake: %s, connection wake: %s, disconnection wake: %s\n",
|
||||
(val & PORT_CS_18_WOU4S) ? "yes" : "no",
|
||||
(val & PORT_CS_18_WOCS) ? "yes" : "no",
|
||||
(val & PORT_CS_18_WODS) ? "yes" : "no");
|
||||
|
||||
if (val & PORT_CS_18_WOU4S)
|
||||
wakeup = true;
|
||||
wakeup_usb4 = val & (PORT_CS_18_WOU4S | PORT_CS_18_WOCS |
|
||||
PORT_CS_18_WODS);
|
||||
|
||||
usb4 = port->usb4;
|
||||
if (device_may_wakeup(&usb4->dev) && wakeup_usb4)
|
||||
pm_wakeup_event(&usb4->dev, 0);
|
||||
|
||||
wakeup |= wakeup_usb4;
|
||||
}
|
||||
|
||||
if (wakeup)
|
||||
@ -366,6 +379,7 @@ bool usb4_switch_lane_bonding_possible(struct tb_switch *sw)
|
||||
*/
|
||||
int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags)
|
||||
{
|
||||
struct usb4_port *usb4;
|
||||
struct tb_port *port;
|
||||
u64 route = tb_route(sw);
|
||||
u32 val;
|
||||
@ -395,10 +409,13 @@ int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags)
|
||||
val |= PORT_CS_19_WOU4;
|
||||
} else {
|
||||
bool configured = val & PORT_CS_19_PC;
|
||||
usb4 = port->usb4;
|
||||
|
||||
if ((flags & TB_WAKE_ON_CONNECT) && !configured)
|
||||
if (((flags & TB_WAKE_ON_CONNECT) |
|
||||
device_may_wakeup(&usb4->dev)) && !configured)
|
||||
val |= PORT_CS_19_WOC;
|
||||
if ((flags & TB_WAKE_ON_DISCONNECT) && configured)
|
||||
if (((flags & TB_WAKE_ON_DISCONNECT) |
|
||||
device_may_wakeup(&usb4->dev)) && configured)
|
||||
val |= PORT_CS_19_WOD;
|
||||
if ((flags & TB_WAKE_ON_USB4) && configured)
|
||||
val |= PORT_CS_19_WOU4;
|
||||
|
@ -284,6 +284,9 @@ struct usb4_port *usb4_port_device_add(struct tb_port *port)
|
||||
}
|
||||
}
|
||||
|
||||
if (!tb_is_upstream_port(port))
|
||||
device_set_wakeup_capable(&usb4->dev, true);
|
||||
|
||||
pm_runtime_no_callbacks(&usb4->dev);
|
||||
pm_runtime_set_active(&usb4->dev);
|
||||
pm_runtime_enable(&usb4->dev);
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/prandom.h>
|
||||
#include <linux/string_helpers.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/workqueue.h>
|
||||
@ -341,7 +342,6 @@ static int tb_xdp_properties_request(struct tb_ctl *ctl, u64 route,
|
||||
memcpy(&req.src_uuid, src_uuid, sizeof(*src_uuid));
|
||||
memcpy(&req.dst_uuid, dst_uuid, sizeof(*dst_uuid));
|
||||
|
||||
len = 0;
|
||||
data_len = 0;
|
||||
|
||||
do {
|
||||
@ -1344,7 +1344,7 @@ static int tb_xdomain_bond_lanes_uuid_high(struct tb_xdomain *xd)
|
||||
tb_port_update_credits(port);
|
||||
tb_xdomain_update_link_attributes(xd);
|
||||
|
||||
dev_dbg(&xd->dev, "lane bonding %sabled\n", width == 2 ? "en" : "dis");
|
||||
dev_dbg(&xd->dev, "lane bonding %s\n", str_enabled_disabled(width == 2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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/
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -2006,10 +2006,11 @@ int cdnsp_queue_bulk_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
|
||||
|
||||
int cdnsp_queue_ctrl_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
|
||||
{
|
||||
u32 field, length_field, remainder;
|
||||
u32 field, length_field, zlp = 0;
|
||||
struct cdnsp_ep *pep = preq->pep;
|
||||
struct cdnsp_ring *ep_ring;
|
||||
int num_trbs;
|
||||
u32 maxp;
|
||||
int ret;
|
||||
|
||||
ep_ring = cdnsp_request_to_transfer_ring(pdev, preq);
|
||||
@ -2019,26 +2020,33 @@ int cdnsp_queue_ctrl_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
|
||||
/* 1 TRB for data, 1 for status */
|
||||
num_trbs = (pdev->three_stage_setup) ? 2 : 1;
|
||||
|
||||
maxp = usb_endpoint_maxp(pep->endpoint.desc);
|
||||
|
||||
if (preq->request.zero && preq->request.length &&
|
||||
(preq->request.length % maxp == 0)) {
|
||||
num_trbs++;
|
||||
zlp = 1;
|
||||
}
|
||||
|
||||
ret = cdnsp_prepare_transfer(pdev, preq, num_trbs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* If there's data, queue data TRBs */
|
||||
if (pdev->ep0_expect_in)
|
||||
field = TRB_TYPE(TRB_DATA) | TRB_IOC;
|
||||
else
|
||||
field = TRB_ISP | TRB_TYPE(TRB_DATA) | TRB_IOC;
|
||||
|
||||
if (preq->request.length > 0) {
|
||||
remainder = cdnsp_td_remainder(pdev, 0, preq->request.length,
|
||||
preq->request.length, preq, 1, 0);
|
||||
field = TRB_TYPE(TRB_DATA);
|
||||
|
||||
length_field = TRB_LEN(preq->request.length) |
|
||||
TRB_TD_SIZE(remainder) | TRB_INTR_TARGET(0);
|
||||
if (zlp)
|
||||
field |= TRB_CHAIN;
|
||||
else
|
||||
field |= TRB_IOC | (pdev->ep0_expect_in ? 0 : TRB_ISP);
|
||||
|
||||
if (pdev->ep0_expect_in)
|
||||
field |= TRB_DIR_IN;
|
||||
|
||||
length_field = TRB_LEN(preq->request.length) |
|
||||
TRB_TD_SIZE(zlp) | TRB_INTR_TARGET(0);
|
||||
|
||||
cdnsp_queue_trb(pdev, ep_ring, true,
|
||||
lower_32_bits(preq->request.dma),
|
||||
upper_32_bits(preq->request.dma), length_field,
|
||||
@ -2046,6 +2054,20 @@ int cdnsp_queue_ctrl_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
|
||||
TRB_SETUPID(pdev->setup_id) |
|
||||
pdev->setup_speed);
|
||||
|
||||
if (zlp) {
|
||||
field = TRB_TYPE(TRB_NORMAL) | TRB_IOC;
|
||||
|
||||
if (!pdev->ep0_expect_in)
|
||||
field = TRB_ISP;
|
||||
|
||||
cdnsp_queue_trb(pdev, ep_ring, true,
|
||||
lower_32_bits(preq->request.dma),
|
||||
upper_32_bits(preq->request.dma), 0,
|
||||
field | ep_ring->cycle_state |
|
||||
TRB_SETUPID(pdev->setup_id) |
|
||||
pdev->setup_speed);
|
||||
}
|
||||
|
||||
pdev->ep0_stage = CDNSP_DATA_STAGE;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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 = {
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
struct ci_hdrc_cable *cable;
|
||||
|
||||
if ((ci_role != CI_ROLE_END && !ci->roles[ci_role]) ||
|
||||
(current_role == role))
|
||||
return 0;
|
||||
|
||||
pm_runtime_get_sync(ci->dev);
|
||||
/* Stop current role */
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
if (current_role == USB_ROLE_DEVICE)
|
||||
cable = &ci->platdata->vbus_extcon;
|
||||
else if (current_role == USB_ROLE_HOST)
|
||||
if (role == USB_ROLE_HOST) {
|
||||
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);
|
||||
cable = &ci->platdata->vbus_extcon;
|
||||
cable->changed = true;
|
||||
cable->connected = false;
|
||||
} else if (role == USB_ROLE_DEVICE) {
|
||||
cable = &ci->platdata->id_extcon;
|
||||
cable->changed = true;
|
||||
cable->connected = false;
|
||||
cable = &ci->platdata->vbus_extcon;
|
||||
cable->changed = true;
|
||||
cable->connected = true;
|
||||
} 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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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";
|
||||
|
||||
|
@ -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,31 +1052,30 @@ 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);
|
||||
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 (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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(imx_usbmisc_init_post);
|
||||
|
||||
int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *data, bool enabled)
|
||||
{
|
||||
struct imx_usbmisc *usbmisc;
|
||||
|
||||
if (!data)
|
||||
return 0;
|
||||
|
||||
usbmisc = dev_get_drvdata(data->dev);
|
||||
if (!usbmisc->ops->set_wakeup)
|
||||
return 0;
|
||||
return usbmisc->ops->set_wakeup(data, enabled);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(imx_usbmisc_set_wakeup);
|
||||
|
||||
int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data)
|
||||
{
|
||||
struct imx_usbmisc *usbmisc;
|
||||
@ -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",
|
||||
|
@ -207,7 +207,7 @@ static int ulpi_read_id(struct ulpi *ulpi)
|
||||
/* Test the interface */
|
||||
ret = ulpi_write(ulpi, ULPI_SCRATCH, 0xaa);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
ret = ulpi_read(ulpi, ULPI_SCRATCH);
|
||||
if (ret < 0)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -558,6 +558,17 @@ static int hcd_pci_suspend_noirq(struct device *dev)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int hcd_pci_poweroff_late(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
|
||||
|
||||
if (hcd->driver->pci_poweroff_late && !HCD_DEAD(hcd))
|
||||
return hcd->driver->pci_poweroff_late(hcd, device_may_wakeup(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hcd_pci_resume_noirq(struct device *dev)
|
||||
{
|
||||
powermac_set_asic(to_pci_dev(dev), 1);
|
||||
@ -578,6 +589,7 @@ static int hcd_pci_restore(struct device *dev)
|
||||
|
||||
#define hcd_pci_suspend NULL
|
||||
#define hcd_pci_suspend_noirq NULL
|
||||
#define hcd_pci_poweroff_late NULL
|
||||
#define hcd_pci_resume_noirq NULL
|
||||
#define hcd_pci_resume NULL
|
||||
#define hcd_pci_restore NULL
|
||||
@ -615,6 +627,7 @@ const struct dev_pm_ops usb_hcd_pci_pm_ops = {
|
||||
.thaw_noirq = NULL,
|
||||
.thaw = hcd_pci_resume,
|
||||
.poweroff = hcd_pci_suspend,
|
||||
.poweroff_late = hcd_pci_poweroff_late,
|
||||
.poweroff_noirq = hcd_pci_suspend_noirq,
|
||||
.restore_noirq = hcd_pci_resume_noirq,
|
||||
.restore = hcd_pci_restore,
|
||||
|
@ -3133,8 +3133,12 @@ int usb_hcd_setup_local_mem(struct usb_hcd *hcd, phys_addr_t phys_addr,
|
||||
GFP_KERNEL,
|
||||
DMA_ATTR_WRITE_COMBINE);
|
||||
|
||||
if (IS_ERR(local_mem))
|
||||
if (IS_ERR_OR_NULL(local_mem)) {
|
||||
if (!local_mem)
|
||||
return -ENOMEM;
|
||||
|
||||
return PTR_ERR(local_mem);
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we pass a dma_addr_t but the arg type is a phys_addr_t.
|
||||
|
@ -3081,6 +3081,48 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
|
||||
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. */
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
|
@ -4549,7 +4549,8 @@ static int dwc2_hsotg_udc_start(struct usb_gadget *gadget,
|
||||
hsotg->gadget.dev.of_node = hsotg->dev->of_node;
|
||||
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
|
||||
if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) {
|
||||
if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL ||
|
||||
(hsotg->dr_mode == USB_DR_MODE_OTG && dwc2_is_device_mode(hsotg))) {
|
||||
ret = dwc2_lowlevel_hw_enable(hsotg);
|
||||
if (ret)
|
||||
goto err;
|
||||
@ -4611,7 +4612,8 @@ static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget)
|
||||
if (!IS_ERR_OR_NULL(hsotg->uphy))
|
||||
otg_set_peripheral(hsotg->uphy->otg, NULL);
|
||||
|
||||
if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
|
||||
if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL ||
|
||||
(hsotg->dr_mode == USB_DR_MODE_OTG && dwc2_is_device_mode(hsotg)))
|
||||
dwc2_lowlevel_hw_disable(hsotg);
|
||||
|
||||
return 0;
|
||||
|
@ -113,6 +113,10 @@ static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg)
|
||||
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
|
||||
GAHBCFG_HBSTLEN_SHIFT;
|
||||
p->power_down = DWC2_POWER_DOWN_PARAM_NONE;
|
||||
p->lpm = false;
|
||||
p->lpm_clock_gating = false;
|
||||
p->besl = false;
|
||||
p->hird_threshold_en = false;
|
||||
}
|
||||
|
||||
static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -576,7 +576,8 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
||||
dwc2_debugfs_init(hsotg);
|
||||
|
||||
/* Gadget code manages lowlevel hw on its own */
|
||||
if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
|
||||
if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL ||
|
||||
(hsotg->dr_mode == USB_DR_MODE_OTG && dwc2_is_device_mode(hsotg)))
|
||||
dwc2_lowlevel_hw_disable(hsotg);
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \
|
||||
|
@ -152,11 +152,11 @@ config USB_DWC3_IMX8MP
|
||||
|
||||
config USB_DWC3_XILINX
|
||||
tristate "Xilinx Platforms"
|
||||
depends on (ARCH_ZYNQMP || ARCH_VERSAL) && OF
|
||||
depends on (ARCH_ZYNQMP || COMPILE_TEST) && OF
|
||||
default USB_DWC3
|
||||
help
|
||||
Support Xilinx SoCs with DesignWare Core USB3 IP.
|
||||
This driver handles both ZynqMP and Versal SoC operations.
|
||||
This driver handles ZynqMP SoC operations.
|
||||
Say 'Y' or 'M' if you have one such device.
|
||||
|
||||
config USB_DWC3_AM62
|
||||
|
@ -122,21 +122,25 @@ static void __dwc3_set_mode(struct work_struct *work)
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
u32 reg;
|
||||
u32 desired_dr_role;
|
||||
|
||||
mutex_lock(&dwc->mutex);
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
desired_dr_role = dwc->desired_dr_role;
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
pm_runtime_get_sync(dwc->dev);
|
||||
|
||||
if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG)
|
||||
dwc3_otg_update(dwc, 0);
|
||||
|
||||
if (!dwc->desired_dr_role)
|
||||
if (!desired_dr_role)
|
||||
goto out;
|
||||
|
||||
if (dwc->desired_dr_role == dwc->current_dr_role)
|
||||
if (desired_dr_role == dwc->current_dr_role)
|
||||
goto out;
|
||||
|
||||
if (dwc->desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev)
|
||||
if (desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev)
|
||||
goto out;
|
||||
|
||||
switch (dwc->current_dr_role) {
|
||||
@ -164,7 +168,7 @@ static void __dwc3_set_mode(struct work_struct *work)
|
||||
*/
|
||||
if (dwc->current_dr_role && ((DWC3_IP_IS(DWC3) ||
|
||||
DWC3_VER_IS_PRIOR(DWC31, 190A)) &&
|
||||
dwc->desired_dr_role != DWC3_GCTL_PRTCAP_OTG)) {
|
||||
desired_dr_role != DWC3_GCTL_PRTCAP_OTG)) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
reg |= DWC3_GCTL_CORESOFTRESET;
|
||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
@ -184,11 +188,11 @@ static void __dwc3_set_mode(struct work_struct *work)
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
||||
dwc3_set_prtcap(dwc, dwc->desired_dr_role);
|
||||
dwc3_set_prtcap(dwc, desired_dr_role);
|
||||
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
switch (dwc->desired_dr_role) {
|
||||
switch (desired_dr_role) {
|
||||
case DWC3_GCTL_PRTCAP_HOST:
|
||||
ret = dwc3_host_init(dwc);
|
||||
if (ret) {
|
||||
@ -1096,8 +1100,13 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
||||
|
||||
if (!dwc->ulpi_ready) {
|
||||
ret = dwc3_core_ulpi_init(dwc);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
if (ret == -ETIMEDOUT) {
|
||||
dwc3_core_soft_reset(dwc);
|
||||
ret = -EPROBE_DEFER;
|
||||
}
|
||||
goto err0;
|
||||
}
|
||||
dwc->ulpi_ready = true;
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@
|
||||
#define PCI_DEVICE_ID_INTEL_ADLN 0x465e
|
||||
#define PCI_DEVICE_ID_INTEL_ADLN_PCH 0x54ee
|
||||
#define PCI_DEVICE_ID_INTEL_ADLS 0x7ae1
|
||||
#define PCI_DEVICE_ID_INTEL_RPL 0x460e
|
||||
#define PCI_DEVICE_ID_INTEL_RPL 0xa70e
|
||||
#define PCI_DEVICE_ID_INTEL_RPLS 0x7a61
|
||||
#define PCI_DEVICE_ID_INTEL_MTLP 0x7ec1
|
||||
#define PCI_DEVICE_ID_INTEL_MTL 0x7e7e
|
||||
|
@ -261,7 +261,8 @@ static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
|
||||
if (IS_ERR(qcom->icc_path_apps)) {
|
||||
dev_err(dev, "failed to get apps-usb path: %ld\n",
|
||||
PTR_ERR(qcom->icc_path_apps));
|
||||
return PTR_ERR(qcom->icc_path_apps);
|
||||
ret = PTR_ERR(qcom->icc_path_apps);
|
||||
goto put_path_ddr;
|
||||
}
|
||||
|
||||
max_speed = usb_get_maximum_speed(&qcom->dwc3->dev);
|
||||
@ -274,16 +275,22 @@ static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
|
||||
}
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to set bandwidth for usb-ddr path: %d\n", ret);
|
||||
return ret;
|
||||
goto put_path_apps;
|
||||
}
|
||||
|
||||
ret = icc_set_bw(qcom->icc_path_apps, APPS_USB_AVG_BW, APPS_USB_PEAK_BW);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to set bandwidth for apps-usb path: %d\n", ret);
|
||||
return ret;
|
||||
goto put_path_apps;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
put_path_apps:
|
||||
icc_put(qcom->icc_path_apps);
|
||||
put_path_ddr:
|
||||
icc_put(qcom->icc_path_ddr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1464,8 +1464,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);
|
||||
|
38
drivers/usb/fotg210/Kconfig
Normal file
38
drivers/usb/fotg210/Kconfig
Normal file
@ -0,0 +1,38 @@
|
||||
# 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
|
||||
depends on ARCH_GEMINI || COMPILE_TEST
|
||||
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=y || USB=USB_FOTG210
|
||||
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=y || USB_GADGET=USB_FOTG210
|
||||
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
|
10
drivers/usb/fotg210/Makefile
Normal file
10
drivers/usb/fotg210/Makefile
Normal file
@ -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
|
166
drivers/usb/fotg210/fotg210-core.c
Normal file
166
drivers/usb/fotg210/fotg210-core.c
Normal file
@ -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");
|
@ -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 @@ static int fotg210_hcd_probe(struct platform_device *pdev)
|
||||
* @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);
|
@ -15,8 +15,12 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/usb/phy.h>
|
||||
|
||||
#include "fotg210.h"
|
||||
#include "fotg210-udc.h"
|
||||
|
||||
#define DRIVER_DESC "FOTG210 USB Device Controller Driver"
|
||||
#define DRIVER_VERSION "30-April-2013"
|
||||
@ -629,10 +633,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 +717,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;
|
||||
@ -1007,11 +1011,19 @@ static int fotg210_udc_start(struct usb_gadget *g,
|
||||
{
|
||||
struct fotg210_udc *fotg210 = gadget_to_fotg210(g);
|
||||
u32 value;
|
||||
int ret;
|
||||
|
||||
/* hook up the driver */
|
||||
driver->driver.bus = NULL;
|
||||
fotg210->driver = driver;
|
||||
|
||||
if (!IS_ERR_OR_NULL(fotg210->phy)) {
|
||||
ret = otg_set_peripheral(fotg210->phy->otg,
|
||||
&fotg210->gadget);
|
||||
if (ret)
|
||||
dev_err(fotg210->dev, "can't bind to phy\n");
|
||||
}
|
||||
|
||||
/* enable device global interrupt */
|
||||
value = ioread32(fotg210->reg + FOTG210_DMCR);
|
||||
value |= DMCR_GLINT_EN;
|
||||
@ -1053,6 +1065,9 @@ static int fotg210_udc_stop(struct usb_gadget *g)
|
||||
struct fotg210_udc *fotg210 = gadget_to_fotg210(g);
|
||||
unsigned long flags;
|
||||
|
||||
if (!IS_ERR_OR_NULL(fotg210->phy))
|
||||
return otg_set_peripheral(fotg210->phy->otg, NULL);
|
||||
|
||||
spin_lock_irqsave(&fotg210->lock, flags);
|
||||
|
||||
fotg210_init(fotg210);
|
||||
@ -1068,28 +1083,71 @@ static const struct usb_gadget_ops fotg210_gadget_ops = {
|
||||
.udc_stop = fotg210_udc_stop,
|
||||
};
|
||||
|
||||
static int fotg210_udc_remove(struct platform_device *pdev)
|
||||
/**
|
||||
* fotg210_phy_event - Called by phy upon VBus event
|
||||
* @nb: notifier block
|
||||
* @action: phy action, is vbus connect or disconnect
|
||||
* @data: the usb_gadget structure in fotg210
|
||||
*
|
||||
* Called by the USB Phy when a cable connect or disconnect is sensed.
|
||||
*
|
||||
* Returns NOTIFY_OK or NOTIFY_DONE
|
||||
*/
|
||||
static int fotg210_phy_event(struct notifier_block *nb, unsigned long action,
|
||||
void *data)
|
||||
{
|
||||
struct usb_gadget *gadget = data;
|
||||
|
||||
if (!gadget)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
switch (action) {
|
||||
case USB_EVENT_VBUS:
|
||||
usb_gadget_vbus_connect(gadget);
|
||||
return NOTIFY_OK;
|
||||
case USB_EVENT_NONE:
|
||||
usb_gadget_vbus_disconnect(gadget);
|
||||
return NOTIFY_OK;
|
||||
default:
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
static struct notifier_block fotg210_phy_notifier = {
|
||||
.notifier_call = fotg210_phy_event,
|
||||
};
|
||||
|
||||
int fotg210_udc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct fotg210_udc *fotg210 = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
usb_del_gadget_udc(&fotg210->gadget);
|
||||
if (!IS_ERR_OR_NULL(fotg210->phy)) {
|
||||
usb_unregister_notifier(fotg210->phy, &fotg210_phy_notifier);
|
||||
usb_put_phy(fotg210->phy);
|
||||
}
|
||||
iounmap(fotg210->reg);
|
||||
free_irq(platform_get_irq(pdev, 0), fotg210);
|
||||
|
||||
fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req);
|
||||
for (i = 0; i < FOTG210_MAX_NUM_EP; i++)
|
||||
kfree(fotg210->ep[i]);
|
||||
|
||||
if (!IS_ERR(fotg210->pclk))
|
||||
clk_disable_unprepare(fotg210->pclk);
|
||||
|
||||
kfree(fotg210);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fotg210_udc_probe(struct platform_device *pdev)
|
||||
int fotg210_udc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res, *ires;
|
||||
struct resource *res;
|
||||
struct fotg210_udc *fotg210 = NULL;
|
||||
struct fotg210_ep *_ep[FOTG210_MAX_NUM_EP];
|
||||
struct device *dev = &pdev->dev;
|
||||
int irq;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
@ -1099,29 +1157,59 @@ static int fotg210_udc_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!ires) {
|
||||
pr_err("platform_get_resource IORESOURCE_IRQ error.\n");
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
pr_err("could not get irq\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = -ENOMEM;
|
||||
|
||||
/* initialize udc */
|
||||
fotg210 = kzalloc(sizeof(struct fotg210_udc), GFP_KERNEL);
|
||||
if (fotg210 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
fotg210->dev = dev;
|
||||
|
||||
/* It's OK not to supply this clock */
|
||||
fotg210->pclk = devm_clk_get(dev, "PCLK");
|
||||
if (!IS_ERR(fotg210->pclk)) {
|
||||
ret = clk_prepare_enable(fotg210->pclk);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable PCLK\n");
|
||||
goto err;
|
||||
}
|
||||
} else if (PTR_ERR(fotg210->pclk) == -EPROBE_DEFER) {
|
||||
/*
|
||||
* Percolate deferrals, for anything else,
|
||||
* just live without the clocking.
|
||||
*/
|
||||
ret = -EPROBE_DEFER;
|
||||
goto err;
|
||||
}
|
||||
|
||||
fotg210->phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
|
||||
if (IS_ERR(fotg210->phy)) {
|
||||
ret = PTR_ERR(fotg210->phy);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
goto err_pclk;
|
||||
dev_info(dev, "no PHY found\n");
|
||||
fotg210->phy = NULL;
|
||||
} else {
|
||||
ret = usb_phy_init(fotg210->phy);
|
||||
if (ret)
|
||||
goto err_pclk;
|
||||
dev_info(dev, "found and initialized PHY\n");
|
||||
}
|
||||
|
||||
for (i = 0; i < FOTG210_MAX_NUM_EP; i++) {
|
||||
_ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL);
|
||||
if (_ep[i] == NULL)
|
||||
fotg210->ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL);
|
||||
if (!fotg210->ep[i])
|
||||
goto err_alloc;
|
||||
fotg210->ep[i] = _ep[i];
|
||||
}
|
||||
|
||||
fotg210->reg = ioremap(res->start, resource_size(res));
|
||||
if (fotg210->reg == NULL) {
|
||||
pr_err("ioremap error.\n");
|
||||
dev_err(dev, "ioremap error\n");
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
@ -1132,8 +1220,8 @@ static int fotg210_udc_probe(struct platform_device *pdev)
|
||||
fotg210->gadget.ops = &fotg210_gadget_ops;
|
||||
|
||||
fotg210->gadget.max_speed = USB_SPEED_HIGH;
|
||||
fotg210->gadget.dev.parent = &pdev->dev;
|
||||
fotg210->gadget.dev.dma_mask = pdev->dev.dma_mask;
|
||||
fotg210->gadget.dev.parent = dev;
|
||||
fotg210->gadget.dev.dma_mask = dev->dma_mask;
|
||||
fotg210->gadget.name = udc_name;
|
||||
|
||||
INIT_LIST_HEAD(&fotg210->gadget.ep_list);
|
||||
@ -1176,23 +1264,28 @@ static int fotg210_udc_probe(struct platform_device *pdev)
|
||||
|
||||
fotg210_disable_unplug(fotg210);
|
||||
|
||||
ret = request_irq(ires->start, fotg210_irq, IRQF_SHARED,
|
||||
ret = request_irq(irq, fotg210_irq, IRQF_SHARED,
|
||||
udc_name, fotg210);
|
||||
if (ret < 0) {
|
||||
pr_err("request_irq error (%d)\n", ret);
|
||||
dev_err(dev, "request_irq error (%d)\n", ret);
|
||||
goto err_req;
|
||||
}
|
||||
|
||||
ret = usb_add_gadget_udc(&pdev->dev, &fotg210->gadget);
|
||||
if (!IS_ERR_OR_NULL(fotg210->phy))
|
||||
usb_register_notifier(fotg210->phy, &fotg210_phy_notifier);
|
||||
|
||||
ret = usb_add_gadget_udc(dev, &fotg210->gadget);
|
||||
if (ret)
|
||||
goto err_add_udc;
|
||||
|
||||
dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
|
||||
dev_info(dev, "version %s\n", DRIVER_VERSION);
|
||||
|
||||
return 0;
|
||||
|
||||
err_add_udc:
|
||||
free_irq(ires->start, fotg210);
|
||||
if (!IS_ERR_OR_NULL(fotg210->phy))
|
||||
usb_unregister_notifier(fotg210->phy, &fotg210_phy_notifier);
|
||||
free_irq(irq, fotg210);
|
||||
|
||||
err_req:
|
||||
fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req);
|
||||
@ -1203,22 +1296,11 @@ static int fotg210_udc_probe(struct platform_device *pdev)
|
||||
err_alloc:
|
||||
for (i = 0; i < FOTG210_MAX_NUM_EP; i++)
|
||||
kfree(fotg210->ep[i]);
|
||||
kfree(fotg210);
|
||||
err_pclk:
|
||||
if (!IS_ERR(fotg210->pclk))
|
||||
clk_disable_unprepare(fotg210->pclk);
|
||||
|
||||
err:
|
||||
kfree(fotg210);
|
||||
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);
|
@ -231,9 +231,12 @@ struct fotg210_ep {
|
||||
struct fotg210_udc {
|
||||
spinlock_t lock; /* protect the struct */
|
||||
void __iomem *reg;
|
||||
struct clk *pclk;
|
||||
|
||||
unsigned long irq_trigger;
|
||||
|
||||
struct device *dev;
|
||||
struct usb_phy *phy;
|
||||
struct usb_gadget gadget;
|
||||
struct usb_gadget_driver *driver;
|
||||
|
42
drivers/usb/fotg210/fotg210.h
Normal file
42
drivers/usb/fotg210/fotg210.h
Normal file
@ -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 */
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -71,7 +71,7 @@ struct f_hidg {
|
||||
wait_queue_head_t write_queue;
|
||||
struct usb_request *req;
|
||||
|
||||
int minor;
|
||||
struct device dev;
|
||||
struct cdev cdev;
|
||||
struct usb_function func;
|
||||
|
||||
@ -84,6 +84,14 @@ static inline struct f_hidg *func_to_hidg(struct usb_function *f)
|
||||
return container_of(f, struct f_hidg, func);
|
||||
}
|
||||
|
||||
static void hidg_release(struct device *dev)
|
||||
{
|
||||
struct f_hidg *hidg = container_of(dev, struct f_hidg, dev);
|
||||
|
||||
kfree(hidg->set_report_buf);
|
||||
kfree(hidg);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* Static descriptors */
|
||||
|
||||
@ -904,9 +912,7 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
struct usb_ep *ep;
|
||||
struct f_hidg *hidg = func_to_hidg(f);
|
||||
struct usb_string *us;
|
||||
struct device *device;
|
||||
int status;
|
||||
dev_t dev;
|
||||
|
||||
/* maybe allocate device-global string IDs, and patch descriptors */
|
||||
us = usb_gstrings_attach(c->cdev, ct_func_strings,
|
||||
@ -999,21 +1005,11 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
|
||||
/* create char device */
|
||||
cdev_init(&hidg->cdev, &f_hidg_fops);
|
||||
dev = MKDEV(major, hidg->minor);
|
||||
status = cdev_add(&hidg->cdev, dev, 1);
|
||||
status = cdev_device_add(&hidg->cdev, &hidg->dev);
|
||||
if (status)
|
||||
goto fail_free_descs;
|
||||
|
||||
device = device_create(hidg_class, NULL, dev, NULL,
|
||||
"%s%d", "hidg", hidg->minor);
|
||||
if (IS_ERR(device)) {
|
||||
status = PTR_ERR(device);
|
||||
goto del;
|
||||
}
|
||||
|
||||
return 0;
|
||||
del:
|
||||
cdev_del(&hidg->cdev);
|
||||
fail_free_descs:
|
||||
usb_free_all_descriptors(f);
|
||||
fail:
|
||||
@ -1244,9 +1240,7 @@ static void hidg_free(struct usb_function *f)
|
||||
|
||||
hidg = func_to_hidg(f);
|
||||
opts = container_of(f->fi, struct f_hid_opts, func_inst);
|
||||
kfree(hidg->report_desc);
|
||||
kfree(hidg->set_report_buf);
|
||||
kfree(hidg);
|
||||
put_device(&hidg->dev);
|
||||
mutex_lock(&opts->lock);
|
||||
--opts->refcnt;
|
||||
mutex_unlock(&opts->lock);
|
||||
@ -1256,8 +1250,7 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct f_hidg *hidg = func_to_hidg(f);
|
||||
|
||||
device_destroy(hidg_class, MKDEV(major, hidg->minor));
|
||||
cdev_del(&hidg->cdev);
|
||||
cdev_device_del(&hidg->cdev, &hidg->dev);
|
||||
|
||||
usb_free_all_descriptors(f);
|
||||
}
|
||||
@ -1266,6 +1259,7 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi)
|
||||
{
|
||||
struct f_hidg *hidg;
|
||||
struct f_hid_opts *opts;
|
||||
int ret;
|
||||
|
||||
/* allocate and initialize one new instance */
|
||||
hidg = kzalloc(sizeof(*hidg), GFP_KERNEL);
|
||||
@ -1275,25 +1269,31 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi)
|
||||
opts = container_of(fi, struct f_hid_opts, func_inst);
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
++opts->refcnt;
|
||||
|
||||
hidg->minor = opts->minor;
|
||||
device_initialize(&hidg->dev);
|
||||
hidg->dev.release = hidg_release;
|
||||
hidg->dev.class = hidg_class;
|
||||
hidg->dev.devt = MKDEV(major, opts->minor);
|
||||
ret = dev_set_name(&hidg->dev, "hidg%d", opts->minor);
|
||||
if (ret)
|
||||
goto err_unlock;
|
||||
|
||||
hidg->bInterfaceSubClass = opts->subclass;
|
||||
hidg->bInterfaceProtocol = opts->protocol;
|
||||
hidg->report_length = opts->report_length;
|
||||
hidg->report_desc_length = opts->report_desc_length;
|
||||
if (opts->report_desc) {
|
||||
hidg->report_desc = kmemdup(opts->report_desc,
|
||||
opts->report_desc_length,
|
||||
GFP_KERNEL);
|
||||
hidg->report_desc = devm_kmemdup(&hidg->dev, opts->report_desc,
|
||||
opts->report_desc_length,
|
||||
GFP_KERNEL);
|
||||
if (!hidg->report_desc) {
|
||||
kfree(hidg);
|
||||
mutex_unlock(&opts->lock);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
ret = -ENOMEM;
|
||||
goto err_put_device;
|
||||
}
|
||||
}
|
||||
hidg->use_out_ep = !opts->no_out_endpoint;
|
||||
|
||||
++opts->refcnt;
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
hidg->func.name = "hid";
|
||||
@ -1308,6 +1308,12 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi)
|
||||
hidg->qlen = 4;
|
||||
|
||||
return &hidg->func;
|
||||
|
||||
err_put_device:
|
||||
put_device(&hidg->dev);
|
||||
err_unlock:
|
||||
mutex_unlock(&opts->lock);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(hid, hidg_alloc_inst, hidg_alloc);
|
||||
|
@ -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;
|
||||
|
@ -364,7 +364,7 @@ printer_open(struct inode *inode, struct file *fd)
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
kref_get(&dev->kref);
|
||||
DBG(dev, "printer_open returned %x\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -382,7 +382,6 @@ printer_close(struct inode *inode, struct file *fd)
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
kref_put(&dev->kref, printer_dev_free);
|
||||
DBG(dev, "printer_close\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -848,8 +847,6 @@ static void printer_reset_interface(struct printer_dev *dev)
|
||||
if (dev->interface < 0)
|
||||
return;
|
||||
|
||||
DBG(dev, "%s\n", __func__);
|
||||
|
||||
if (dev->in_ep->desc)
|
||||
usb_ep_disable(dev->in_ep);
|
||||
|
||||
@ -887,8 +884,6 @@ static void printer_soft_reset(struct printer_dev *dev)
|
||||
{
|
||||
struct usb_request *req;
|
||||
|
||||
INFO(dev, "Received Printer Reset Request\n");
|
||||
|
||||
if (usb_ep_disable(dev->in_ep))
|
||||
DBG(dev, "Failed to disable USB in_ep\n");
|
||||
if (usb_ep_disable(dev->out_ep))
|
||||
@ -1185,8 +1180,6 @@ static void printer_func_disable(struct usb_function *f)
|
||||
{
|
||||
struct printer_dev *dev = func_to_printer(f);
|
||||
|
||||
DBG(dev, "%s\n", __func__);
|
||||
|
||||
printer_reset_interface(dev);
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
@ -216,8 +213,9 @@ uvc_function_ep0_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
|
||||
memset(&v4l2_event, 0, sizeof(v4l2_event));
|
||||
v4l2_event.type = UVC_EVENT_DATA;
|
||||
uvc_event->data.length = req->actual;
|
||||
memcpy(&uvc_event->data.data, req->buf, req->actual);
|
||||
uvc_event->data.length = min_t(unsigned int, req->actual,
|
||||
sizeof(uvc_event->data.data));
|
||||
memcpy(&uvc_event->data.data, req->buf, uvc_event->data.length);
|
||||
v4l2_event_queue(&uvc->vdev, &v4l2_event);
|
||||
}
|
||||
}
|
||||
@ -228,6 +226,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 +248,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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -1512,7 +1512,7 @@ UVCG_UNCOMPRESSED_ATTR(b_bits_per_pixel, bBitsPerPixel, 8);
|
||||
UVCG_UNCOMPRESSED_ATTR(b_default_frame_index, bDefaultFrameIndex, 8);
|
||||
UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, 8);
|
||||
UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, 8);
|
||||
UVCG_UNCOMPRESSED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, 8);
|
||||
UVCG_UNCOMPRESSED_ATTR_RO(bm_interlace_flags, bmInterlaceFlags, 8);
|
||||
|
||||
#undef UVCG_UNCOMPRESSED_ATTR
|
||||
#undef UVCG_UNCOMPRESSED_ATTR_RO
|
||||
@ -1541,7 +1541,7 @@ static struct configfs_attribute *uvcg_uncompressed_attrs[] = {
|
||||
&uvcg_uncompressed_attr_b_default_frame_index,
|
||||
&uvcg_uncompressed_attr_b_aspect_ratio_x,
|
||||
&uvcg_uncompressed_attr_b_aspect_ratio_y,
|
||||
&uvcg_uncompressed_attr_bm_interface_flags,
|
||||
&uvcg_uncompressed_attr_bm_interlace_flags,
|
||||
&uvcg_uncompressed_attr_bma_controls,
|
||||
NULL,
|
||||
};
|
||||
@ -1574,7 +1574,7 @@ static struct config_group *uvcg_uncompressed_make(struct config_group *group,
|
||||
h->desc.bDefaultFrameIndex = 1;
|
||||
h->desc.bAspectRatioX = 0;
|
||||
h->desc.bAspectRatioY = 0;
|
||||
h->desc.bmInterfaceFlags = 0;
|
||||
h->desc.bmInterlaceFlags = 0;
|
||||
h->desc.bCopyProtect = 0;
|
||||
|
||||
INIT_LIST_HEAD(&h->fmt.frames);
|
||||
@ -1700,7 +1700,7 @@ UVCG_MJPEG_ATTR(b_default_frame_index, bDefaultFrameIndex, 8);
|
||||
UVCG_MJPEG_ATTR_RO(bm_flags, bmFlags, 8);
|
||||
UVCG_MJPEG_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, 8);
|
||||
UVCG_MJPEG_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, 8);
|
||||
UVCG_MJPEG_ATTR_RO(bm_interface_flags, bmInterfaceFlags, 8);
|
||||
UVCG_MJPEG_ATTR_RO(bm_interlace_flags, bmInterlaceFlags, 8);
|
||||
|
||||
#undef UVCG_MJPEG_ATTR
|
||||
#undef UVCG_MJPEG_ATTR_RO
|
||||
@ -1728,7 +1728,7 @@ static struct configfs_attribute *uvcg_mjpeg_attrs[] = {
|
||||
&uvcg_mjpeg_attr_bm_flags,
|
||||
&uvcg_mjpeg_attr_b_aspect_ratio_x,
|
||||
&uvcg_mjpeg_attr_b_aspect_ratio_y,
|
||||
&uvcg_mjpeg_attr_bm_interface_flags,
|
||||
&uvcg_mjpeg_attr_bm_interlace_flags,
|
||||
&uvcg_mjpeg_attr_bma_controls,
|
||||
NULL,
|
||||
};
|
||||
@ -1755,7 +1755,7 @@ static struct config_group *uvcg_mjpeg_make(struct config_group *group,
|
||||
h->desc.bDefaultFrameIndex = 1;
|
||||
h->desc.bAspectRatioX = 0;
|
||||
h->desc.bAspectRatioY = 0;
|
||||
h->desc.bmInterfaceFlags = 0;
|
||||
h->desc.bmInterlaceFlags = 0;
|
||||
h->desc.bCopyProtect = 0;
|
||||
|
||||
INIT_LIST_HEAD(&h->fmt.frames);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -171,7 +171,7 @@ static const struct uvc_format_uncompressed uvc_format_yuv = {
|
||||
.bDefaultFrameIndex = 1,
|
||||
.bAspectRatioX = 0,
|
||||
.bAspectRatioY = 0,
|
||||
.bmInterfaceFlags = 0,
|
||||
.bmInterlaceFlags = 0,
|
||||
.bCopyProtect = 0,
|
||||
};
|
||||
|
||||
@ -222,7 +222,7 @@ static const struct uvc_format_mjpeg uvc_format_mjpg = {
|
||||
.bDefaultFrameIndex = 1,
|
||||
.bAspectRatioX = 0,
|
||||
.bAspectRatioY = 0,
|
||||
.bmInterfaceFlags = 0,
|
||||
.bmInterlaceFlags = 0,
|
||||
.bCopyProtect = 0,
|
||||
};
|
||||
|
||||
|
@ -33,7 +33,7 @@ menu "USB Peripheral Controller"
|
||||
config USB_AT91
|
||||
tristate "Atmel AT91 USB Device Port"
|
||||
depends on ARCH_AT91
|
||||
depends on OF || COMPILE_TEST
|
||||
depends on OF
|
||||
help
|
||||
Many Atmel AT91 processors (such as the AT91RM2000) have a
|
||||
full speed USB Device Port with support for five configurable
|
||||
@ -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
|
||||
@ -430,7 +419,7 @@ config USB_EG20T
|
||||
config USB_GADGET_XILINX
|
||||
tristate "Xilinx USB Driver"
|
||||
depends on HAS_DMA
|
||||
depends on OF || COMPILE_TEST
|
||||
depends on OF
|
||||
help
|
||||
USB peripheral controller driver for Xilinx USB2 device.
|
||||
Xilinx USB2 device is a soft IP which supports both full
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 = {
|
||||
|
@ -734,13 +734,13 @@ int usb_gadget_disconnect(struct usb_gadget *gadget)
|
||||
}
|
||||
|
||||
ret = gadget->ops->pullup(gadget, 0);
|
||||
if (!ret) {
|
||||
if (!ret)
|
||||
gadget->connected = 0;
|
||||
mutex_lock(&udc_lock);
|
||||
if (gadget->udc->driver)
|
||||
gadget->udc->driver->disconnect(gadget);
|
||||
mutex_unlock(&udc_lock);
|
||||
}
|
||||
|
||||
mutex_lock(&udc_lock);
|
||||
if (gadget->udc->driver)
|
||||
gadget->udc->driver->disconnect(gadget);
|
||||
mutex_unlock(&udc_lock);
|
||||
|
||||
out:
|
||||
trace_usb_gadget_disconnect(gadget, ret);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -471,7 +471,7 @@ struct ehci_iso_sched {
|
||||
* acts like a qh would, if EHCI had them for ISO.
|
||||
*/
|
||||
struct ehci_iso_stream {
|
||||
/* first field matches ehci_hq, but is NULL */
|
||||
/* first field matches ehci_qh, but is NULL */
|
||||
struct ehci_qh_hw *hw;
|
||||
|
||||
u8 bEndpointAddress;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -426,24 +426,37 @@ static unsigned int xhci_port_speed(unsigned int port_status)
|
||||
*/
|
||||
#define XHCI_PORT_RZ ((1<<2) | (1<<24) | (0xf<<28))
|
||||
|
||||
/*
|
||||
/**
|
||||
* xhci_port_state_to_neutral() - Clean up read portsc value back into writeable
|
||||
* @state: u32 port value read from portsc register to be cleanup up
|
||||
*
|
||||
* Given a port state, this function returns a value that would result in the
|
||||
* port being in the same state, if the value was written to the port status
|
||||
* control register.
|
||||
* Save Read Only (RO) bits and save read/write bits where
|
||||
* writing a 0 clears the bit and writing a 1 sets the bit (RWS).
|
||||
* For all other types (RW1S, RW1CS, RW, and RZ), writing a '0' has no effect.
|
||||
*
|
||||
* Return: u32 value that can be written back to portsc register without
|
||||
* changing port state.
|
||||
*/
|
||||
|
||||
u32 xhci_port_state_to_neutral(u32 state)
|
||||
{
|
||||
/* Save read-only status and port state */
|
||||
return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xhci_port_state_to_neutral);
|
||||
|
||||
/*
|
||||
* find slot id based on port number.
|
||||
* @port: The one-based port number from one of the two split roothubs.
|
||||
/**
|
||||
* xhci_find_slot_id_by_port() - Find slot id of a usb device on a roothub port
|
||||
* @hcd: pointer to hcd of the roothub
|
||||
* @xhci: pointer to xhci structure
|
||||
* @port: one-based port number of the port in this roothub.
|
||||
*
|
||||
* Return: Slot id of the usb device connected to the root port, 0 if not found
|
||||
*/
|
||||
|
||||
int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
|
||||
u16 port)
|
||||
{
|
||||
@ -465,6 +478,7 @@ int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
|
||||
|
||||
return slot_id;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xhci_find_slot_id_by_port);
|
||||
|
||||
/*
|
||||
* Stop device
|
||||
|
@ -485,6 +485,7 @@ static int xhci_mtk_probe(struct platform_device *pdev)
|
||||
const struct hc_driver *driver;
|
||||
struct xhci_hcd *xhci;
|
||||
struct resource *res;
|
||||
struct usb_hcd *usb3_hcd;
|
||||
struct usb_hcd *hcd;
|
||||
int ret = -ENODEV;
|
||||
int wakeup_irq;
|
||||
@ -593,6 +594,7 @@ static int xhci_mtk_probe(struct platform_device *pdev)
|
||||
|
||||
xhci = hcd_to_xhci(hcd);
|
||||
xhci->main_hcd = hcd;
|
||||
xhci->allow_single_roothub = 1;
|
||||
|
||||
/*
|
||||
* imod_interval is the interrupt moderation value in nanoseconds.
|
||||
@ -602,24 +604,29 @@ static int xhci_mtk_probe(struct platform_device *pdev)
|
||||
xhci->imod_interval = 5000;
|
||||
device_property_read_u32(dev, "imod-interval-ns", &xhci->imod_interval);
|
||||
|
||||
xhci->shared_hcd = usb_create_shared_hcd(driver, dev,
|
||||
dev_name(dev), hcd);
|
||||
if (!xhci->shared_hcd) {
|
||||
ret = -ENOMEM;
|
||||
goto disable_device_wakeup;
|
||||
}
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (ret)
|
||||
goto put_usb3_hcd;
|
||||
goto disable_device_wakeup;
|
||||
|
||||
if (HCC_MAX_PSA(xhci->hcc_params) >= 4 &&
|
||||
if (!xhci_has_one_roothub(xhci)) {
|
||||
xhci->shared_hcd = usb_create_shared_hcd(driver, dev,
|
||||
dev_name(dev), hcd);
|
||||
if (!xhci->shared_hcd) {
|
||||
ret = -ENOMEM;
|
||||
goto dealloc_usb2_hcd;
|
||||
}
|
||||
}
|
||||
|
||||
usb3_hcd = xhci_get_usb3_hcd(xhci);
|
||||
if (usb3_hcd && HCC_MAX_PSA(xhci->hcc_params) >= 4 &&
|
||||
!(xhci->quirks & XHCI_BROKEN_STREAMS))
|
||||
xhci->shared_hcd->can_do_streams = 1;
|
||||
usb3_hcd->can_do_streams = 1;
|
||||
|
||||
ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
|
||||
if (ret)
|
||||
goto dealloc_usb2_hcd;
|
||||
if (xhci->shared_hcd) {
|
||||
ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
|
||||
if (ret)
|
||||
goto put_usb3_hcd;
|
||||
}
|
||||
|
||||
if (wakeup_irq > 0) {
|
||||
ret = dev_pm_set_dedicated_wake_irq_reverse(dev, wakeup_irq);
|
||||
@ -639,15 +646,14 @@ static int xhci_mtk_probe(struct platform_device *pdev)
|
||||
|
||||
dealloc_usb3_hcd:
|
||||
usb_remove_hcd(xhci->shared_hcd);
|
||||
xhci->shared_hcd = NULL;
|
||||
|
||||
dealloc_usb2_hcd:
|
||||
usb_remove_hcd(hcd);
|
||||
|
||||
put_usb3_hcd:
|
||||
xhci_mtk_sch_exit(mtk);
|
||||
usb_put_hcd(xhci->shared_hcd);
|
||||
|
||||
dealloc_usb2_hcd:
|
||||
xhci_mtk_sch_exit(mtk);
|
||||
usb_remove_hcd(hcd);
|
||||
|
||||
disable_device_wakeup:
|
||||
device_init_wakeup(dev, false);
|
||||
|
||||
@ -679,10 +685,15 @@ static int xhci_mtk_remove(struct platform_device *pdev)
|
||||
dev_pm_clear_wake_irq(dev);
|
||||
device_init_wakeup(dev, false);
|
||||
|
||||
usb_remove_hcd(shared_hcd);
|
||||
xhci->shared_hcd = NULL;
|
||||
if (shared_hcd) {
|
||||
usb_remove_hcd(shared_hcd);
|
||||
xhci->shared_hcd = NULL;
|
||||
}
|
||||
usb_remove_hcd(hcd);
|
||||
usb_put_hcd(shared_hcd);
|
||||
|
||||
if (shared_hcd)
|
||||
usb_put_hcd(shared_hcd);
|
||||
|
||||
usb_put_hcd(hcd);
|
||||
xhci_mtk_sch_exit(mtk);
|
||||
clk_bulk_disable_unprepare(BULK_CLKS_NUM, mtk->clks);
|
||||
@ -700,13 +711,16 @@ static int __maybe_unused xhci_mtk_suspend(struct device *dev)
|
||||
struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
|
||||
struct usb_hcd *hcd = mtk->hcd;
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
struct usb_hcd *shared_hcd = xhci->shared_hcd;
|
||||
int ret;
|
||||
|
||||
xhci_dbg(xhci, "%s: stop port polling\n", __func__);
|
||||
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
|
||||
del_timer_sync(&hcd->rh_timer);
|
||||
clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
|
||||
del_timer_sync(&xhci->shared_hcd->rh_timer);
|
||||
if (shared_hcd) {
|
||||
clear_bit(HCD_FLAG_POLL_RH, &shared_hcd->flags);
|
||||
del_timer_sync(&shared_hcd->rh_timer);
|
||||
}
|
||||
|
||||
ret = xhci_mtk_host_disable(mtk);
|
||||
if (ret)
|
||||
@ -718,8 +732,10 @@ static int __maybe_unused xhci_mtk_suspend(struct device *dev)
|
||||
|
||||
restart_poll_rh:
|
||||
xhci_dbg(xhci, "%s: restart port polling\n", __func__);
|
||||
set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
|
||||
usb_hcd_poll_rh_status(xhci->shared_hcd);
|
||||
if (shared_hcd) {
|
||||
set_bit(HCD_FLAG_POLL_RH, &shared_hcd->flags);
|
||||
usb_hcd_poll_rh_status(shared_hcd);
|
||||
}
|
||||
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
|
||||
usb_hcd_poll_rh_status(hcd);
|
||||
return ret;
|
||||
@ -730,6 +746,7 @@ static int __maybe_unused xhci_mtk_resume(struct device *dev)
|
||||
struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
|
||||
struct usb_hcd *hcd = mtk->hcd;
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
struct usb_hcd *shared_hcd = xhci->shared_hcd;
|
||||
int ret;
|
||||
|
||||
usb_wakeup_set(mtk, false);
|
||||
@ -742,8 +759,10 @@ static int __maybe_unused xhci_mtk_resume(struct device *dev)
|
||||
goto disable_clks;
|
||||
|
||||
xhci_dbg(xhci, "%s: restart port polling\n", __func__);
|
||||
set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
|
||||
usb_hcd_poll_rh_status(xhci->shared_hcd);
|
||||
if (shared_hcd) {
|
||||
set_bit(HCD_FLAG_POLL_RH, &shared_hcd->flags);
|
||||
usb_hcd_poll_rh_status(shared_hcd);
|
||||
}
|
||||
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
|
||||
usb_hcd_poll_rh_status(hcd);
|
||||
return 0;
|
||||
|
@ -59,6 +59,7 @@
|
||||
#define PCI_DEVICE_ID_INTEL_TIGER_LAKE_XHCI 0x9a13
|
||||
#define PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_XHCI 0x1138
|
||||
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI 0x51ed
|
||||
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_N_PCH_XHCI 0x54ed
|
||||
|
||||
#define PCI_DEVICE_ID_AMD_RENOIR_XHCI 0x1639
|
||||
#define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9
|
||||
@ -246,7 +247,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
||||
xhci->quirks |= XHCI_MISSING_CAS;
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
|
||||
pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI)
|
||||
(pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI ||
|
||||
pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_N_PCH_XHCI))
|
||||
xhci->quirks |= XHCI_RESET_TO_DEFAULT;
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
|
||||
@ -620,6 +622,57 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int xhci_pci_poweroff_late(struct usb_hcd *hcd, bool do_wakeup)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
struct xhci_port *port;
|
||||
struct usb_device *udev;
|
||||
unsigned int slot_id;
|
||||
u32 portsc;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Systems with XHCI_RESET_TO_DEFAULT quirk have boot firmware that
|
||||
* cause significant boot delay if usb ports are in suspended U3 state
|
||||
* during boot. Some USB devices survive in U3 state over S4 hibernate
|
||||
*
|
||||
* Disable ports that are in U3 if remote wake is not enabled for either
|
||||
* host controller or connected device
|
||||
*/
|
||||
|
||||
if (!(xhci->quirks & XHCI_RESET_TO_DEFAULT))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < HCS_MAX_PORTS(xhci->hcs_params1); i++) {
|
||||
port = &xhci->hw_ports[i];
|
||||
portsc = readl(port->addr);
|
||||
|
||||
if ((portsc & PORT_PLS_MASK) != XDEV_U3)
|
||||
continue;
|
||||
|
||||
slot_id = xhci_find_slot_id_by_port(port->rhub->hcd, xhci,
|
||||
port->hcd_portnum + 1);
|
||||
if (!slot_id || !xhci->devs[slot_id]) {
|
||||
xhci_err(xhci, "No dev for slot_id %d for port %d-%d in U3\n",
|
||||
slot_id, port->rhub->hcd->self.busnum, port->hcd_portnum + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
udev = xhci->devs[slot_id]->udev;
|
||||
|
||||
/* if wakeup is enabled then don't disable the port */
|
||||
if (udev->do_remote_wakeup && do_wakeup)
|
||||
continue;
|
||||
|
||||
xhci_dbg(xhci, "port %d-%d in U3 without wakeup, disable it\n",
|
||||
port->rhub->hcd->self.busnum, port->hcd_portnum + 1);
|
||||
portsc = xhci_port_state_to_neutral(portsc);
|
||||
writel(portsc | PORT_PE, port->addr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xhci_pci_shutdown(struct usb_hcd *hcd)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
@ -673,11 +726,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)
|
||||
@ -686,6 +740,7 @@ static int __init xhci_pci_init(void)
|
||||
#ifdef CONFIG_PM
|
||||
xhci_pci_hc_driver.pci_suspend = xhci_pci_suspend;
|
||||
xhci_pci_hc_driver.pci_resume = xhci_pci_resume;
|
||||
xhci_pci_hc_driver.pci_poweroff_late = xhci_pci_poweroff_late;
|
||||
xhci_pci_hc_driver.shutdown = xhci_pci_shutdown;
|
||||
#endif
|
||||
return pci_register_driver(&xhci_pci_driver);
|
||||
|
@ -896,7 +896,7 @@ static int xhci_reset_halted_ep(struct xhci_hcd *xhci, unsigned int slot_id,
|
||||
}
|
||||
|
||||
static int xhci_handle_halted_endpoint(struct xhci_hcd *xhci,
|
||||
struct xhci_virt_ep *ep, unsigned int stream_id,
|
||||
struct xhci_virt_ep *ep,
|
||||
struct xhci_td *td,
|
||||
enum xhci_ep_reset_type reset_type)
|
||||
{
|
||||
@ -1110,8 +1110,7 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
|
||||
td->status = -EPROTO;
|
||||
}
|
||||
/* reset ep, reset handler cleans up cancelled tds */
|
||||
err = xhci_handle_halted_endpoint(xhci, ep, 0, td,
|
||||
reset_type);
|
||||
err = xhci_handle_halted_endpoint(xhci, ep, td, reset_type);
|
||||
if (err)
|
||||
break;
|
||||
ep->ep_state &= ~EP_STOP_CMD_PENDING;
|
||||
@ -2183,8 +2182,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
|
||||
}
|
||||
/* Almost same procedure as for STALL_ERROR below */
|
||||
xhci_clear_hub_tt_buffer(xhci, td, ep);
|
||||
xhci_handle_halted_endpoint(xhci, ep, ep_ring->stream_id, td,
|
||||
EP_HARD_RESET);
|
||||
xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET);
|
||||
return 0;
|
||||
case COMP_STALL_ERROR:
|
||||
/*
|
||||
@ -2200,8 +2198,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
|
||||
if (ep->ep_index != 0)
|
||||
xhci_clear_hub_tt_buffer(xhci, td, ep);
|
||||
|
||||
xhci_handle_halted_endpoint(xhci, ep, ep_ring->stream_id, td,
|
||||
EP_HARD_RESET);
|
||||
xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET);
|
||||
|
||||
return 0; /* xhci_handle_halted_endpoint marked td cancelled */
|
||||
default:
|
||||
@ -2458,7 +2455,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
|
||||
|
||||
switch (trb_comp_code) {
|
||||
case COMP_SUCCESS:
|
||||
ep_ring->err_count = 0;
|
||||
ep->err_count = 0;
|
||||
/* handle success with untransferred data as short packet */
|
||||
if (ep_trb != td->last_trb || remaining) {
|
||||
xhci_warn(xhci, "WARN Successful completion on short TX\n");
|
||||
@ -2484,14 +2481,13 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
|
||||
break;
|
||||
case COMP_USB_TRANSACTION_ERROR:
|
||||
if (xhci->quirks & XHCI_NO_SOFT_RETRY ||
|
||||
(ep_ring->err_count++ > MAX_SOFT_RETRY) ||
|
||||
(ep->err_count++ > MAX_SOFT_RETRY) ||
|
||||
le32_to_cpu(slot_ctx->tt_info) & TT_SLOT)
|
||||
break;
|
||||
|
||||
td->status = 0;
|
||||
|
||||
xhci_handle_halted_endpoint(xhci, ep, ep_ring->stream_id, td,
|
||||
EP_SOFT_RESET);
|
||||
xhci_handle_halted_endpoint(xhci, ep, td, EP_SOFT_RESET);
|
||||
return 0;
|
||||
default:
|
||||
/* do nothing */
|
||||
@ -2565,8 +2561,14 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||
case COMP_USB_TRANSACTION_ERROR:
|
||||
case COMP_INVALID_STREAM_TYPE_ERROR:
|
||||
case COMP_INVALID_STREAM_ID_ERROR:
|
||||
xhci_handle_halted_endpoint(xhci, ep, 0, NULL,
|
||||
EP_SOFT_RESET);
|
||||
xhci_dbg(xhci, "Stream transaction error ep %u no id\n",
|
||||
ep_index);
|
||||
if (ep->err_count++ > MAX_SOFT_RETRY)
|
||||
xhci_handle_halted_endpoint(xhci, ep, NULL,
|
||||
EP_HARD_RESET);
|
||||
else
|
||||
xhci_handle_halted_endpoint(xhci, ep, NULL,
|
||||
EP_SOFT_RESET);
|
||||
goto cleanup;
|
||||
case COMP_RING_UNDERRUN:
|
||||
case COMP_RING_OVERRUN:
|
||||
@ -2749,9 +2751,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||
if (trb_comp_code == COMP_STALL_ERROR ||
|
||||
xhci_requires_manual_halt_cleanup(xhci, ep_ctx,
|
||||
trb_comp_code)) {
|
||||
xhci_handle_halted_endpoint(xhci, ep,
|
||||
ep_ring->stream_id,
|
||||
NULL,
|
||||
xhci_handle_halted_endpoint(xhci, ep, NULL,
|
||||
EP_HARD_RESET);
|
||||
}
|
||||
goto cleanup;
|
||||
@ -2844,9 +2844,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||
if (trb_comp_code == COMP_STALL_ERROR ||
|
||||
xhci_requires_manual_halt_cleanup(xhci, ep_ctx,
|
||||
trb_comp_code))
|
||||
xhci_handle_halted_endpoint(xhci, ep,
|
||||
ep_ring->stream_id,
|
||||
td, EP_HARD_RESET);
|
||||
xhci_handle_halted_endpoint(xhci, ep, td,
|
||||
EP_HARD_RESET);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@ -3031,6 +3030,11 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
|
||||
if (!(status & STS_EINT))
|
||||
goto out;
|
||||
|
||||
if (status & STS_HCE) {
|
||||
xhci_warn(xhci, "WARNING: Host Controller Error\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (status & STS_FATAL) {
|
||||
xhci_warn(xhci, "WARNING: Host System Error\n");
|
||||
xhci_halt(xhci);
|
||||
|
@ -933,6 +933,7 @@ struct xhci_virt_ep {
|
||||
* have to restore the device state to the previous state
|
||||
*/
|
||||
struct xhci_ring *new_ring;
|
||||
unsigned int err_count;
|
||||
unsigned int ep_state;
|
||||
#define SET_DEQ_PENDING (1 << 0)
|
||||
#define EP_HALTED (1 << 1) /* For stall handling */
|
||||
@ -1627,7 +1628,6 @@ struct xhci_ring {
|
||||
* if we own the TRB (if we are the consumer). See section 4.9.1.
|
||||
*/
|
||||
u32 cycle_state;
|
||||
unsigned int err_count;
|
||||
unsigned int stream_id;
|
||||
unsigned int num_segs;
|
||||
unsigned int num_trbs_free;
|
||||
|
@ -298,7 +298,7 @@ config BRCM_USB_PINMAP
|
||||
|
||||
config USB_ONBOARD_HUB
|
||||
tristate "Onboard USB hub support"
|
||||
depends on OF || COMPILE_TEST
|
||||
depends on OF
|
||||
help
|
||||
Say Y here if you want to support discrete onboard USB hubs that
|
||||
don't require an additional control bus for initialization, but
|
||||
|
@ -1624,7 +1624,6 @@ wait:if (ftdi->disconnected > 0) {
|
||||
char data[30 *3 + 4];
|
||||
char *d = data;
|
||||
int m = (sizeof(data) - 1) / 3 - 1;
|
||||
int l = 0;
|
||||
struct u132_target *target = &ftdi->target[ed];
|
||||
struct u132_command *command = &ftdi->command[
|
||||
COMMAND_MASK & ftdi->command_next];
|
||||
@ -1647,7 +1646,6 @@ wait:if (ftdi->disconnected > 0) {
|
||||
} else if (i++ < m) {
|
||||
int w = sprintf(d, " %02X", *b++);
|
||||
d += w;
|
||||
l += w;
|
||||
} else
|
||||
d += sprintf(d, " ..");
|
||||
}
|
||||
@ -1956,7 +1954,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 +2048,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) {
|
||||
|
@ -331,6 +331,7 @@ static struct platform_driver onboard_hub_driver = {
|
||||
|
||||
/************************** USB driver **************************/
|
||||
|
||||
#define VENDOR_ID_GENESYS 0x05e3
|
||||
#define VENDOR_ID_MICROCHIP 0x0424
|
||||
#define VENDOR_ID_REALTEK 0x0bda
|
||||
#define VENDOR_ID_TI 0x0451
|
||||
@ -407,6 +408,7 @@ static void onboard_hub_usbdev_disconnect(struct usb_device *udev)
|
||||
}
|
||||
|
||||
static const struct usb_device_id onboard_hub_id_table[] = {
|
||||
{ USB_DEVICE(VENDOR_ID_GENESYS, 0x0608) }, /* Genesys Logic GL850G USB 2.0 */
|
||||
{ USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2514) }, /* USB2514B USB 2.0 */
|
||||
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x0411) }, /* RTS5411 USB 3.1 */
|
||||
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x5411) }, /* RTS5411 USB 2.1 */
|
||||
|
@ -22,10 +22,15 @@ static const struct onboard_hub_pdata ti_tusb8041_data = {
|
||||
.reset_us = 3000,
|
||||
};
|
||||
|
||||
static const struct onboard_hub_pdata genesys_gl850g_data = {
|
||||
.reset_us = 3,
|
||||
};
|
||||
|
||||
static const struct of_device_id onboard_hub_match[] = {
|
||||
{ .compatible = "usb424,2514", .data = µchip_usb424_data, },
|
||||
{ .compatible = "usb451,8140", .data = &ti_tusb8041_data, },
|
||||
{ .compatible = "usb451,8142", .data = &ti_tusb8041_data, },
|
||||
{ .compatible = "usb5e3,608", .data = &genesys_gl850g_data, },
|
||||
{ .compatible = "usbbda,411", .data = &realtek_rts5411_data, },
|
||||
{ .compatible = "usbbda,5411", .data = &realtek_rts5411_data, },
|
||||
{ .compatible = "usbbda,414", .data = &realtek_rts5411_data, },
|
||||
|
@ -3,7 +3,6 @@
|
||||
config USB_SISUSBVGA
|
||||
tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)"
|
||||
depends on (USB_MUSB_HDRC || USB_EHCI_HCD)
|
||||
select FONT_SUPPORT if USB_SISUSBVGA_CON
|
||||
help
|
||||
Say Y here if you intend to attach a USB2VGA dongle based on a
|
||||
Net2280 and a SiS315 chip.
|
||||
@ -13,36 +12,3 @@ config USB_SISUSBVGA
|
||||
|
||||
To compile this driver as a module, choose M here; the module will be
|
||||
called sisusbvga. If unsure, say N.
|
||||
|
||||
config USB_SISUSBVGA_CON
|
||||
bool "Text console and mode switching support" if USB_SISUSBVGA
|
||||
depends on VT && BROKEN
|
||||
select FONT_8x16
|
||||
help
|
||||
Say Y here if you want a VGA text console via the USB dongle or
|
||||
want to support userland applications that utilize the driver's
|
||||
display mode switching capabilities.
|
||||
|
||||
Note that this console supports VGA/EGA text mode only.
|
||||
|
||||
By default, the console part of the driver will not kick in when
|
||||
the driver is initialized. If you want the driver to take over
|
||||
one or more of the consoles, you need to specify the number of
|
||||
the first and last consoles (starting at 1) as driver parameters.
|
||||
|
||||
For example, if the driver is compiled as a module:
|
||||
|
||||
modprobe sisusbvga first=1 last=5
|
||||
|
||||
If you use hotplug, add this to your modutils config files with
|
||||
the "options" keyword, such as eg.
|
||||
|
||||
options sisusbvga first=1 last=5
|
||||
|
||||
If the driver is compiled into the kernel image, the parameters
|
||||
must be given in the kernel command like, such as
|
||||
|
||||
sisusbvga.first=1 sisusbvga.last=5
|
||||
|
||||
|
||||
|
||||
|
@ -4,6 +4,3 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga.o
|
||||
|
||||
sisusbvga-y := sisusb.o
|
||||
sisusbvga-$(CONFIG_USB_SISUSBVGA_CON) += sisusb_con.o sisusb_init.o
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user