mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2025-01-26 15:54:18 +08:00
USB patches for 5.5-rc1
Here is the big set of USB patches for 5.5-rc1 Lots of little things in here: - typec updates and additions - usb-serial drivers cleanups and fixes - misc USB drivers cleanups and fixes - gadget drivers new features and controllers added - usual xhci additions - other minor changes All of these have been in linux-next with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXd5+Iw8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ylA4wCbB3P206oHeHLBe9Eika3D8gM9/fMAn2oWlmpB Xh7wr30FGC02zU/KBpJ1 =U5qC -----END PGP SIGNATURE----- Merge tag 'usb-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB updates from Greg KH: "Here is the big set of USB patches for 5.5-rc1 Lots of little things in here: - typec updates and additions - usb-serial drivers cleanups and fixes - misc USB drivers cleanups and fixes - gadget drivers new features and controllers added - usual xhci additions - other minor changes All of these have been in linux-next with no reported issues" * tag 'usb-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (223 commits) usb: gadget: udc: gr_udc: create debugfs directory under usb root usb: gadget: atmel: create debugfs directory under usb root usb: musb: create debugfs directory under usb root usb: serial: Fix Kconfig indentation usb: misc: Fix Kconfig indentation usb: gadget: Fix Kconfig indentation usb: host: Fix Kconfig indentation usb: dwc3: Fix Kconfig indentation usb: gadget: configfs: Fix missing spin_lock_init() usb-storage: Disable UAS on JMicron SATA enclosure USB: documentation: flags on usb-storage versus UAS USB: uas: heed CAPACITY_HEURISTICS USB: uas: honor flag to avoid CAPACITY16 usb: host: xhci-tegra: Correct phy enable sequence usb-serial: cp201x: support Mark-10 digital force gauge usb: chipidea: imx: pinctrl for HSIC is optional usb: chipidea: imx: refine the error handling for hsic usb: chipidea: imx: change hsic power regulator as optional usb: chipidea: imx: check data->usbmisc_data against NULL before access usb: chipidea: core: change vbus-regulator as optional ...
This commit is contained in:
commit
59274c7164
@ -5114,13 +5114,13 @@
|
||||
Flags is a set of characters, each corresponding
|
||||
to a common usb-storage quirk flag as follows:
|
||||
a = SANE_SENSE (collect more than 18 bytes
|
||||
of sense data);
|
||||
of sense data, not on uas);
|
||||
b = BAD_SENSE (don't collect more than 18
|
||||
bytes of sense data);
|
||||
bytes of sense data, not on uas);
|
||||
c = FIX_CAPACITY (decrease the reported
|
||||
device capacity by one sector);
|
||||
d = NO_READ_DISC_INFO (don't use
|
||||
READ_DISC_INFO command);
|
||||
READ_DISC_INFO command, not on uas);
|
||||
e = NO_READ_CAPACITY_16 (don't use
|
||||
READ_CAPACITY_16 command);
|
||||
f = NO_REPORT_OPCODES (don't use report opcodes
|
||||
@ -5135,17 +5135,18 @@
|
||||
j = NO_REPORT_LUNS (don't use report luns
|
||||
command, uas only);
|
||||
l = NOT_LOCKABLE (don't try to lock and
|
||||
unlock ejectable media);
|
||||
unlock ejectable media, not on uas);
|
||||
m = MAX_SECTORS_64 (don't transfer more
|
||||
than 64 sectors = 32 KB at a time);
|
||||
than 64 sectors = 32 KB at a time,
|
||||
not on uas);
|
||||
n = INITIAL_READ10 (force a retry of the
|
||||
initial READ(10) command);
|
||||
initial READ(10) command, not on uas);
|
||||
o = CAPACITY_OK (accept the capacity
|
||||
reported by the device);
|
||||
reported by the device, not on uas);
|
||||
p = WRITE_CACHE (the device cache is ON
|
||||
by default);
|
||||
by default, not on uas);
|
||||
r = IGNORE_RESIDUE (the device reports
|
||||
bogus residue values);
|
||||
bogus residue values, not on uas);
|
||||
s = SINGLE_LUN (the device has only one
|
||||
Logical Unit);
|
||||
t = NO_ATA_1X (don't allow ATA(12) and ATA(16)
|
||||
@ -5154,7 +5155,8 @@
|
||||
w = NO_WP_DETECT (don't test whether the
|
||||
medium is write-protected).
|
||||
y = ALWAYS_SYNC (issue a SYNCHRONIZE_CACHE
|
||||
even if the device claims no cache)
|
||||
even if the device claims no cache,
|
||||
not on uas)
|
||||
Example: quirks=0419:aaf5:rl,0421:0433:rc
|
||||
|
||||
user_debug= [KNL,ARM]
|
||||
|
@ -8,6 +8,7 @@ Required Properties:
|
||||
- "renesas,r8a7745-usb-dmac" (RZ/G1E)
|
||||
- "renesas,r8a77470-usb-dmac" (RZ/G1C)
|
||||
- "renesas,r8a774a1-usb-dmac" (RZ/G2M)
|
||||
- "renesas,r8a774b1-usb-dmac" (RZ/G2N)
|
||||
- "renesas,r8a774c0-usb-dmac" (RZ/G2E)
|
||||
- "renesas,r8a7790-usb-dmac" (R-Car H2)
|
||||
- "renesas,r8a7791-usb-dmac" (R-Car M2-W)
|
||||
|
@ -10,6 +10,8 @@ Required properties:
|
||||
SoC.
|
||||
"renesas,usb2-phy-r8a774a1" if the device is a part of an R8A774A1
|
||||
SoC.
|
||||
"renesas,usb2-phy-r8a774b1" if the device is a part of an R8A774B1
|
||||
SoC.
|
||||
"renesas,usb2-phy-r8a774c0" if the device is a part of an R8A774C0
|
||||
SoC.
|
||||
"renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795
|
||||
|
@ -8,6 +8,8 @@ need this driver.
|
||||
|
||||
Required properties:
|
||||
- compatible: "renesas,r8a774a1-usb3-phy" if the device is a part of an R8A774A1
|
||||
SoC.
|
||||
"renesas,r8a774b1-usb3-phy" if the device is a part of an R8A774B1
|
||||
SoC.
|
||||
"renesas,r8a7795-usb3-phy" if the device is a part of an R8A7795
|
||||
SoC.
|
||||
|
@ -1,41 +0,0 @@
|
||||
Renesas Electronics USB3.0 Peripheral driver
|
||||
|
||||
Required properties:
|
||||
- compatible: Must contain one of the following:
|
||||
- "renesas,r8a774a1-usb3-peri"
|
||||
- "renesas,r8a774c0-usb3-peri"
|
||||
- "renesas,r8a7795-usb3-peri"
|
||||
- "renesas,r8a7796-usb3-peri"
|
||||
- "renesas,r8a77965-usb3-peri"
|
||||
- "renesas,r8a77990-usb3-peri"
|
||||
- "renesas,rcar-gen3-usb3-peri" for a generic R-Car Gen3 or RZ/G2
|
||||
compatible device
|
||||
|
||||
When compatible with the generic version, nodes must list the
|
||||
SoC-specific version corresponding to the platform first
|
||||
followed by the generic version.
|
||||
|
||||
- reg: Base address and length of the register for the USB3.0 Peripheral
|
||||
- interrupts: Interrupt specifier for the USB3.0 Peripheral
|
||||
- clocks: clock phandle and specifier pair
|
||||
|
||||
Optional properties:
|
||||
- phys: phandle + phy specifier pair
|
||||
- phy-names: must be "usb"
|
||||
|
||||
Example of R-Car H3 ES1.x:
|
||||
usb3_peri0: usb@ee020000 {
|
||||
compatible = "renesas,r8a7795-usb3-peri",
|
||||
"renesas,rcar-gen3-usb3-peri";
|
||||
reg = <0 0xee020000 0 0x400>;
|
||||
interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 328>;
|
||||
};
|
||||
|
||||
usb3_peri1: usb@ee060000 {
|
||||
compatible = "renesas,r8a7795-usb3-peri",
|
||||
"renesas,rcar-gen3-usb3-peri";
|
||||
reg = <0 0xee060000 0 0x400>;
|
||||
interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 327>;
|
||||
};
|
86
Documentation/devicetree/bindings/usb/renesas,usb3-peri.yaml
Normal file
86
Documentation/devicetree/bindings/usb/renesas,usb3-peri.yaml
Normal file
@ -0,0 +1,86 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/usb/renesas,usb3-peri.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas USB 3.0 Peripheral controller
|
||||
|
||||
maintainers:
|
||||
- Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- renesas,r8a774a1-usb3-peri # RZ/G2M
|
||||
- renesas,r8a774b1-usb3-peri # RZ/G2N
|
||||
- renesas,r8a774c0-usb3-peri # RZ/G2E
|
||||
- renesas,r8a7795-usb3-peri # R-Car H3
|
||||
- renesas,r8a7796-usb3-peri # R-Car M3-W
|
||||
- renesas,r8a77965-usb3-peri # R-Car M3-N
|
||||
- renesas,r8a77990-usb3-peri # R-Car E3
|
||||
- const: renesas,rcar-gen3-usb3-peri
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
phys:
|
||||
maxItems: 1
|
||||
|
||||
phy-names:
|
||||
const: usb
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
usb-role-switch:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description: Support role switch.
|
||||
|
||||
companion:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: phandle of a companion.
|
||||
|
||||
port:
|
||||
description: |
|
||||
any connector to the data bus of this controller should be modelled
|
||||
using the OF graph bindings specified, if the "usb-role-switch"
|
||||
property is used.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- interrupts
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r8a774c0-cpg-mssr.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/power/r8a774c0-sysc.h>
|
||||
|
||||
usb3_peri0: usb@ee020000 {
|
||||
compatible = "renesas,r8a774c0-usb3-peri", "renesas,rcar-gen3-usb3-peri";
|
||||
reg = <0 0xee020000 0 0x400>;
|
||||
interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 328>;
|
||||
companion = <&xhci0>;
|
||||
usb-role-switch;
|
||||
|
||||
port {
|
||||
usb3_role_switch: endpoint {
|
||||
remote-endpoint = <&hd3ss3220_ep>;
|
||||
};
|
||||
};
|
||||
};
|
@ -1,57 +0,0 @@
|
||||
Renesas Electronics USBHS driver
|
||||
|
||||
Required properties:
|
||||
- compatible: Must contain one or more of the following:
|
||||
|
||||
- "renesas,usbhs-r8a7743" for r8a7743 (RZ/G1M) compatible device
|
||||
- "renesas,usbhs-r8a7744" for r8a7744 (RZ/G1N) compatible device
|
||||
- "renesas,usbhs-r8a7745" for r8a7745 (RZ/G1E) compatible device
|
||||
- "renesas,usbhs-r8a77470" for r8a77470 (RZ/G1C) compatible device
|
||||
- "renesas,usbhs-r8a774a1" for r8a774a1 (RZ/G2M) compatible device
|
||||
- "renesas,usbhs-r8a774c0" for r8a774c0 (RZ/G2E) compatible device
|
||||
- "renesas,usbhs-r8a7790" for r8a7790 (R-Car H2) compatible device
|
||||
- "renesas,usbhs-r8a7791" for r8a7791 (R-Car M2-W) compatible device
|
||||
- "renesas,usbhs-r8a7792" for r8a7792 (R-Car V2H) compatible device
|
||||
- "renesas,usbhs-r8a7793" for r8a7793 (R-Car M2-N) compatible device
|
||||
- "renesas,usbhs-r8a7794" for r8a7794 (R-Car E2) compatible device
|
||||
- "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device
|
||||
- "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) compatible device
|
||||
- "renesas,usbhs-r8a77965" for r8a77965 (R-Car M3-N) compatible device
|
||||
- "renesas,usbhs-r8a77990" for r8a77990 (R-Car E3) compatible device
|
||||
- "renesas,usbhs-r8a77995" for r8a77995 (R-Car D3) compatible device
|
||||
- "renesas,usbhs-r7s72100" for r7s72100 (RZ/A1) compatible device
|
||||
- "renesas,usbhs-r7s9210" for r7s9210 (RZ/A2) compatible device
|
||||
- "renesas,rcar-gen2-usbhs" for R-Car Gen2 or RZ/G1 compatible devices
|
||||
- "renesas,rcar-gen3-usbhs" for R-Car Gen3 or RZ/G2 compatible devices
|
||||
- "renesas,rza1-usbhs" for RZ/A1 compatible device
|
||||
- "renesas,rza2-usbhs" for RZ/A2 compatible device
|
||||
|
||||
When compatible with the generic version, nodes must list the
|
||||
SoC-specific version corresponding to the platform first followed
|
||||
by the generic version.
|
||||
|
||||
- reg: Base address and length of the register for the USBHS
|
||||
- interrupts: Interrupt specifier for the USBHS
|
||||
- clocks: A list of phandle + clock specifier pairs.
|
||||
- In case of "renesas,rcar-gen3-usbhs", two clocks are required.
|
||||
First clock should be peripheral and second one should be host.
|
||||
- In case of except above, one clock is required. First clock
|
||||
should be peripheral.
|
||||
|
||||
Optional properties:
|
||||
- renesas,buswait: Integer to use BUSWAIT register
|
||||
- renesas,enable-gpio: A gpio specifier to check GPIO determining if USB
|
||||
function should be enabled
|
||||
- phys: phandle + phy specifier pair
|
||||
- phy-names: must be "usb"
|
||||
- dmas: Must contain a list of references to DMA specifiers.
|
||||
- dma-names : named "ch%d", where %d is the channel number ranging from zero
|
||||
to the number of channels (DnFIFOs) minus one.
|
||||
|
||||
Example:
|
||||
usbhs: usb@e6590000 {
|
||||
compatible = "renesas,usbhs-r8a7790", "renesas,rcar-gen2-usbhs";
|
||||
reg = <0 0xe6590000 0 0x100>;
|
||||
interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&mstp7_clks R8A7790_CLK_HSUSB>;
|
||||
};
|
126
Documentation/devicetree/bindings/usb/renesas,usbhs.yaml
Normal file
126
Documentation/devicetree/bindings/usb/renesas,usbhs.yaml
Normal file
@ -0,0 +1,126 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/usb/renesas,usbhs.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas USBHS (HS-USB) controller
|
||||
|
||||
maintainers:
|
||||
- Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: renesas,usbhs-r7s72100 # RZ/A1
|
||||
- const: renesas,rza1-usbhs
|
||||
|
||||
- items:
|
||||
- const: renesas,usbhs-r7s9210 # RZ/A2
|
||||
- const: renesas,rza2-usbhs
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,usbhs-r8a7743 # RZ/G1M
|
||||
- renesas,usbhs-r8a7744 # RZ/G1N
|
||||
- renesas,usbhs-r8a7745 # RZ/G1E
|
||||
- renesas,usbhs-r8a77470 # RZ/G1C
|
||||
- renesas,usbhs-r8a7790 # R-Car H2
|
||||
- renesas,usbhs-r8a7791 # R-Car M2-W
|
||||
- renesas,usbhs-r8a7792 # R-Car V2H
|
||||
- renesas,usbhs-r8a7793 # R-Car M2-N
|
||||
- renesas,usbhs-r8a7794 # R-Car E2
|
||||
- const: renesas,rcar-gen2-usbhs
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,usbhs-r8a774a1 # RZ/G2M
|
||||
- renesas,usbhs-r8a774b1 # RZ/G2N
|
||||
- renesas,usbhs-r8a774c0 # RZ/G2E
|
||||
- renesas,usbhs-r8a7795 # R-Car H3
|
||||
- renesas,usbhs-r8a7796 # R-Car M3-W
|
||||
- renesas,usbhs-r8a77965 # R-Car M3-N
|
||||
- renesas,usbhs-r8a77990 # R-Car E3
|
||||
- renesas,usbhs-r8a77995 # R-Car D3
|
||||
- const: renesas,rcar-gen3-usbhs
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
items:
|
||||
- description: USB 2.0 host
|
||||
- description: USB 2.0 peripheral
|
||||
- description: USB 2.0 clock selector
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
renesas,buswait:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Integer to use BUSWAIT register.
|
||||
|
||||
renesas,enable-gpio:
|
||||
description: |
|
||||
gpio specifier to check GPIO determining if USB function should be
|
||||
enabled.
|
||||
|
||||
phys:
|
||||
maxItems: 1
|
||||
items:
|
||||
- description: phandle + phy specifier pair.
|
||||
|
||||
phy-names:
|
||||
maxItems: 1
|
||||
items:
|
||||
- const: usb
|
||||
|
||||
dmas:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
|
||||
dma-names:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
items:
|
||||
- const: ch0
|
||||
- const: ch1
|
||||
- const: ch2
|
||||
- const: ch3
|
||||
|
||||
dr_mode: true
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- description: USB 2.0 host
|
||||
- description: USB 2.0 peripheral
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r8a7790-cpg-mssr.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/power/r8a7790-sysc.h>
|
||||
|
||||
usbhs: usb@e6590000 {
|
||||
compatible = "renesas,usbhs-r8a7790", "renesas,rcar-gen2-usbhs";
|
||||
reg = <0 0xe6590000 0 0x100>;
|
||||
interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 704>;
|
||||
};
|
@ -6,10 +6,39 @@ Required properties:
|
||||
- interrupts : <a b> where a is the interrupt number and b represents an
|
||||
encoding of the sense and level information for the interrupt.
|
||||
|
||||
Required sub-node:
|
||||
- connector: The "usb-c-connector" attached to the tcpci chip, the bindings
|
||||
of connector node are specified in
|
||||
Documentation/devicetree/bindings/connector/usb-connector.txt
|
||||
|
||||
Example :
|
||||
rt1711h@4e {
|
||||
compatible = "richtek,rt1711h";
|
||||
reg = <0x4e>;
|
||||
interrupt-parent = <&gpio26>;
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
usb_con: connector {
|
||||
compatible = "usb-c-connector";
|
||||
label = "USB-C";
|
||||
data-role = "dual";
|
||||
power-role = "dual";
|
||||
try-power-role = "sink";
|
||||
source-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_USB_COMM)>;
|
||||
sink-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_USB_COMM)
|
||||
PDO_VAR(5000, 12000, 2000)>;
|
||||
op-sink-microwatt = <10000000>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
usb_con_ss: endpoint {
|
||||
remote-endpoint = <&usb3_data_ss>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
38
Documentation/devicetree/bindings/usb/ti,hd3ss3220.txt
Normal file
38
Documentation/devicetree/bindings/usb/ti,hd3ss3220.txt
Normal file
@ -0,0 +1,38 @@
|
||||
TI HD3SS3220 TypeC DRP Port Controller.
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be "ti,hd3ss3220".
|
||||
- reg: I2C slave address, must be 0x47 or 0x67 based on ADDR pin.
|
||||
- interrupts: An interrupt specifier.
|
||||
|
||||
Required sub-node:
|
||||
- connector: The "usb-c-connector" attached to the hd3ss3220 chip. The
|
||||
bindings of the connector node are specified in:
|
||||
|
||||
Documentation/devicetree/bindings/connector/usb-connector.txt
|
||||
|
||||
Example:
|
||||
hd3ss3220@47 {
|
||||
compatible = "ti,hd3ss3220";
|
||||
reg = <0x47>;
|
||||
interrupt-parent = <&gpio6>;
|
||||
interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
connector {
|
||||
compatible = "usb-c-connector";
|
||||
label = "USB-C";
|
||||
data-role = "dual";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
hd3ss3220_ep: endpoint {
|
||||
remote-endpoint = <&usb3_role_switch>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
86
Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml
Normal file
86
Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml
Normal file
@ -0,0 +1,86 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/usb/ti,j721e-usb.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Bindings for the TI wrapper module for the Cadence USBSS-DRD controller
|
||||
|
||||
maintainers:
|
||||
- Roger Quadros <rogerq@ti.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: ti,j721e-usb
|
||||
|
||||
reg:
|
||||
description: module registers
|
||||
|
||||
power-domains:
|
||||
description:
|
||||
PM domain provider node and an args specifier containing
|
||||
the USB device id value. See,
|
||||
Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
|
||||
|
||||
clocks:
|
||||
description: Clock phandles to usb2_refclk and lpm_clk
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ref
|
||||
- const: lpm
|
||||
|
||||
ti,usb2-only:
|
||||
description:
|
||||
If present, it restricts the controller to USB2.0 mode of
|
||||
operation. Must be present if USB3 PHY is not available
|
||||
for USB.
|
||||
type: boolean
|
||||
|
||||
ti,vbus-divider:
|
||||
description:
|
||||
Should be present if USB VBUS line is connected to the
|
||||
VBUS pin of the SoC via a 1/3 voltage divider.
|
||||
type: boolean
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- power-domains
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/soc/ti,sci_pm_domain.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
cdns_usb@4104000 {
|
||||
compatible = "ti,j721e-usb";
|
||||
reg = <0x00 0x4104000 0x00 0x100>;
|
||||
power-domains = <&k3_pds 288 TI_SCI_PD_EXCLUSIVE>;
|
||||
clocks = <&k3_clks 288 15>, <&k3_clks 288 3>;
|
||||
clock-names = "ref", "lpm";
|
||||
assigned-clocks = <&k3_clks 288 15>; /* USB2_REFCLK */
|
||||
assigned-clock-parents = <&k3_clks 288 16>; /* HFOSC0 */
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
usb@6000000 {
|
||||
compatible = "cdns,usb3";
|
||||
reg = <0x00 0x6000000 0x00 0x10000>,
|
||||
<0x00 0x6010000 0x00 0x10000>,
|
||||
<0x00 0x6020000 0x00 0x10000>;
|
||||
reg-names = "otg", "xhci", "dev";
|
||||
interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>, /* irq.0 */
|
||||
<GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>, /* irq.6 */
|
||||
<GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; /* otgirq.0 */
|
||||
interrupt-names = "host",
|
||||
"peripheral",
|
||||
"otg";
|
||||
maximum-speed = "super-speed";
|
||||
dr_mode = "otg";
|
||||
};
|
||||
};
|
@ -10,6 +10,7 @@ Required properties:
|
||||
- "renesas,xhci-r8a7743" for r8a7743 SoC
|
||||
- "renesas,xhci-r8a7744" for r8a7744 SoC
|
||||
- "renesas,xhci-r8a774a1" for r8a774a1 SoC
|
||||
- "renesas,xhci-r8a774b1" for r8a774b1 SoC
|
||||
- "renesas,xhci-r8a774c0" for r8a774c0 SoC
|
||||
- "renesas,xhci-r8a7790" for r8a7790 SoC
|
||||
- "renesas,xhci-r8a7791" for r8a7791 SoC
|
||||
|
@ -7,11 +7,12 @@ 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,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)
|
||||
|
@ -322,6 +322,25 @@ static void axp288_put_role_sw(void *data)
|
||||
usb_role_switch_put(info->role_sw);
|
||||
}
|
||||
|
||||
static int axp288_extcon_find_role_sw(struct axp288_extcon_info *info)
|
||||
{
|
||||
const struct software_node *swnode;
|
||||
struct fwnode_handle *fwnode;
|
||||
|
||||
if (!x86_match_cpu(cherry_trail_cpu_ids))
|
||||
return 0;
|
||||
|
||||
swnode = software_node_find_by_name(NULL, "intel-xhci-usb-sw");
|
||||
if (!swnode)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
fwnode = software_node_fwnode(swnode);
|
||||
info->role_sw = usb_role_switch_find_by_fwnode(fwnode);
|
||||
fwnode_handle_put(fwnode);
|
||||
|
||||
return info->role_sw ? 0 : -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
static int axp288_extcon_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct axp288_extcon_info *info;
|
||||
@ -343,9 +362,10 @@ static int axp288_extcon_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
||||
info->role_sw = usb_role_switch_get(dev);
|
||||
if (IS_ERR(info->role_sw))
|
||||
return PTR_ERR(info->role_sw);
|
||||
ret = axp288_extcon_find_role_sw(info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (info->role_sw) {
|
||||
ret = devm_add_action_or_reset(dev, axp288_put_role_sw, info);
|
||||
if (ret)
|
||||
@ -440,26 +460,14 @@ static struct platform_driver axp288_extcon_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct device_connection axp288_extcon_role_sw_conn = {
|
||||
.endpoint[0] = "axp288_extcon",
|
||||
.endpoint[1] = "intel_xhci_usb_sw-role-switch",
|
||||
.id = "usb-role-switch",
|
||||
};
|
||||
|
||||
static int __init axp288_extcon_init(void)
|
||||
{
|
||||
if (x86_match_cpu(cherry_trail_cpu_ids))
|
||||
device_connection_add(&axp288_extcon_role_sw_conn);
|
||||
|
||||
return platform_driver_register(&axp288_extcon_driver);
|
||||
}
|
||||
module_init(axp288_extcon_init);
|
||||
|
||||
static void __exit axp288_extcon_exit(void)
|
||||
{
|
||||
if (x86_match_cpu(cherry_trail_cpu_ids))
|
||||
device_connection_remove(&axp288_extcon_role_sw_conn);
|
||||
|
||||
platform_driver_unregister(&axp288_extcon_driver);
|
||||
}
|
||||
module_exit(axp288_extcon_exit);
|
||||
|
@ -108,15 +108,7 @@ void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream)
|
||||
|
||||
void uvc_debugfs_init(void)
|
||||
{
|
||||
struct dentry *dir;
|
||||
|
||||
dir = debugfs_create_dir("uvcvideo", usb_debug_root);
|
||||
if (IS_ERR_OR_NULL(dir)) {
|
||||
uvc_printk(KERN_INFO, "Unable to create debugfs directory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uvc_debugfs_root_dir = dir;
|
||||
uvc_debugfs_root_dir = debugfs_create_dir("uvcvideo", usb_debug_root);
|
||||
}
|
||||
|
||||
void uvc_debugfs_cleanup(void)
|
||||
|
@ -614,7 +614,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(channel->base);
|
||||
|
||||
/* call request_irq for OTG */
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
irq = platform_get_irq_optional(pdev, 0);
|
||||
if (irq >= 0) {
|
||||
INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
|
||||
irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
|
||||
|
@ -43,4 +43,14 @@ config USB_CDNS3_PCI_WRAP
|
||||
If you choose to build this driver as module it will
|
||||
be dynamically linked and module will be called cdns3-pci.ko
|
||||
|
||||
config USB_CDNS3_TI
|
||||
tristate "Cadence USB3 support on TI platforms"
|
||||
depends on ARCH_K3 || COMPILE_TEST
|
||||
default USB_CDNS3
|
||||
help
|
||||
Say 'Y' or 'M' here if you are building for Texas Instruments
|
||||
platforms that contain Cadence USB3 controller core.
|
||||
|
||||
e.g. J721e.
|
||||
|
||||
endif
|
||||
|
@ -14,3 +14,4 @@ endif
|
||||
cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o
|
||||
|
||||
obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci-wrap.o
|
||||
obj-$(CONFIG_USB_CDNS3_TI) += cdns3-ti.o
|
||||
|
236
drivers/usb/cdns3/cdns3-ti.c
Normal file
236
drivers/usb/cdns3/cdns3-ti.c
Normal file
@ -0,0 +1,236 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/**
|
||||
* cdns3-ti.c - TI specific Glue layer for Cadence USB Controller
|
||||
*
|
||||
* Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
/* USB Wrapper register offsets */
|
||||
#define USBSS_PID 0x0
|
||||
#define USBSS_W1 0x4
|
||||
#define USBSS_STATIC_CONFIG 0x8
|
||||
#define USBSS_PHY_TEST 0xc
|
||||
#define USBSS_DEBUG_CTRL 0x10
|
||||
#define USBSS_DEBUG_INFO 0x14
|
||||
#define USBSS_DEBUG_LINK_STATE 0x18
|
||||
#define USBSS_DEVICE_CTRL 0x1c
|
||||
|
||||
/* Wrapper 1 register bits */
|
||||
#define USBSS_W1_PWRUP_RST BIT(0)
|
||||
#define USBSS_W1_OVERCURRENT_SEL BIT(8)
|
||||
#define USBSS_W1_MODESTRAP_SEL BIT(9)
|
||||
#define USBSS_W1_OVERCURRENT BIT(16)
|
||||
#define USBSS_W1_MODESTRAP_MASK GENMASK(18, 17)
|
||||
#define USBSS_W1_MODESTRAP_SHIFT 17
|
||||
#define USBSS_W1_USB2_ONLY BIT(19)
|
||||
|
||||
/* Static config register bits */
|
||||
#define USBSS1_STATIC_PLL_REF_SEL_MASK GENMASK(8, 5)
|
||||
#define USBSS1_STATIC_PLL_REF_SEL_SHIFT 5
|
||||
#define USBSS1_STATIC_LOOPBACK_MODE_MASK GENMASK(4, 3)
|
||||
#define USBSS1_STATIC_LOOPBACK_MODE_SHIFT 3
|
||||
#define USBSS1_STATIC_VBUS_SEL_MASK GENMASK(2, 1)
|
||||
#define USBSS1_STATIC_VBUS_SEL_SHIFT 1
|
||||
#define USBSS1_STATIC_LANE_REVERSE BIT(0)
|
||||
|
||||
/* Modestrap modes */
|
||||
enum modestrap_mode { USBSS_MODESTRAP_MODE_NONE,
|
||||
USBSS_MODESTRAP_MODE_HOST,
|
||||
USBSS_MODESTRAP_MODE_PERIPHERAL};
|
||||
|
||||
struct cdns_ti {
|
||||
struct device *dev;
|
||||
void __iomem *usbss;
|
||||
int usb2_only:1;
|
||||
int vbus_divider:1;
|
||||
struct clk *usb2_refclk;
|
||||
struct clk *lpm_clk;
|
||||
};
|
||||
|
||||
static const int cdns_ti_rate_table[] = { /* in KHZ */
|
||||
9600,
|
||||
10000,
|
||||
12000,
|
||||
19200,
|
||||
20000,
|
||||
24000,
|
||||
25000,
|
||||
26000,
|
||||
38400,
|
||||
40000,
|
||||
58000,
|
||||
50000,
|
||||
52000,
|
||||
};
|
||||
|
||||
static inline u32 cdns_ti_readl(struct cdns_ti *data, u32 offset)
|
||||
{
|
||||
return readl(data->usbss + offset);
|
||||
}
|
||||
|
||||
static inline void cdns_ti_writel(struct cdns_ti *data, u32 offset, u32 value)
|
||||
{
|
||||
writel(value, data->usbss + offset);
|
||||
}
|
||||
|
||||
static int cdns_ti_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct cdns_ti *data;
|
||||
int error;
|
||||
u32 reg;
|
||||
int rate_code, i;
|
||||
unsigned long rate;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
data->dev = dev;
|
||||
|
||||
data->usbss = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(data->usbss)) {
|
||||
dev_err(dev, "can't map IOMEM resource\n");
|
||||
return PTR_ERR(data->usbss);
|
||||
}
|
||||
|
||||
data->usb2_refclk = devm_clk_get(dev, "ref");
|
||||
if (IS_ERR(data->usb2_refclk)) {
|
||||
dev_err(dev, "can't get usb2_refclk\n");
|
||||
return PTR_ERR(data->usb2_refclk);
|
||||
}
|
||||
|
||||
data->lpm_clk = devm_clk_get(dev, "lpm");
|
||||
if (IS_ERR(data->lpm_clk)) {
|
||||
dev_err(dev, "can't get lpm_clk\n");
|
||||
return PTR_ERR(data->lpm_clk);
|
||||
}
|
||||
|
||||
rate = clk_get_rate(data->usb2_refclk);
|
||||
rate /= 1000; /* To KHz */
|
||||
for (i = 0; i < ARRAY_SIZE(cdns_ti_rate_table); i++) {
|
||||
if (cdns_ti_rate_table[i] == rate)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(cdns_ti_rate_table)) {
|
||||
dev_err(dev, "unsupported usb2_refclk rate: %lu KHz\n", rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rate_code = i;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
error = pm_runtime_get_sync(dev);
|
||||
if (error < 0) {
|
||||
dev_err(dev, "pm_runtime_get_sync failed: %d\n", error);
|
||||
goto err_get;
|
||||
}
|
||||
|
||||
/* assert RESET */
|
||||
reg = cdns_ti_readl(data, USBSS_W1);
|
||||
reg &= ~USBSS_W1_PWRUP_RST;
|
||||
cdns_ti_writel(data, USBSS_W1, reg);
|
||||
|
||||
/* set static config */
|
||||
reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG);
|
||||
reg &= ~USBSS1_STATIC_PLL_REF_SEL_MASK;
|
||||
reg |= rate_code << USBSS1_STATIC_PLL_REF_SEL_SHIFT;
|
||||
|
||||
reg &= ~USBSS1_STATIC_VBUS_SEL_MASK;
|
||||
data->vbus_divider = device_property_read_bool(dev, "ti,vbus-divider");
|
||||
if (data->vbus_divider)
|
||||
reg |= 1 << USBSS1_STATIC_VBUS_SEL_SHIFT;
|
||||
|
||||
cdns_ti_writel(data, USBSS_STATIC_CONFIG, reg);
|
||||
reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG);
|
||||
|
||||
/* set USB2_ONLY mode if requested */
|
||||
reg = cdns_ti_readl(data, USBSS_W1);
|
||||
data->usb2_only = device_property_read_bool(dev, "ti,usb2-only");
|
||||
if (data->usb2_only)
|
||||
reg |= USBSS_W1_USB2_ONLY;
|
||||
|
||||
/* set default modestrap */
|
||||
reg |= USBSS_W1_MODESTRAP_SEL;
|
||||
reg &= ~USBSS_W1_MODESTRAP_MASK;
|
||||
reg |= USBSS_MODESTRAP_MODE_NONE << USBSS_W1_MODESTRAP_SHIFT;
|
||||
cdns_ti_writel(data, USBSS_W1, reg);
|
||||
|
||||
/* de-assert RESET */
|
||||
reg |= USBSS_W1_PWRUP_RST;
|
||||
cdns_ti_writel(data, USBSS_W1, reg);
|
||||
|
||||
error = of_platform_populate(node, NULL, NULL, dev);
|
||||
if (error) {
|
||||
dev_err(dev, "failed to create children: %d\n", error);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
pm_runtime_put_sync(data->dev);
|
||||
err_get:
|
||||
pm_runtime_disable(data->dev);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int cdns_ti_remove_core(struct device *dev, void *c)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_ti_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
device_for_each_child(dev, NULL, cdns_ti_remove_core);
|
||||
pm_runtime_put_sync(dev);
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id cdns_ti_of_match[] = {
|
||||
{ .compatible = "ti,j721e-usb", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cdns_ti_of_match);
|
||||
|
||||
static struct platform_driver cdns_ti_driver = {
|
||||
.probe = cdns_ti_probe,
|
||||
.remove = cdns_ti_remove,
|
||||
.driver = {
|
||||
.name = "cdns3-ti",
|
||||
.of_match_table = cdns_ti_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(cdns_ti_driver);
|
||||
|
||||
MODULE_ALIAS("platform:cdns3-ti");
|
||||
MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("Cadence USB3 TI Glue Layer");
|
@ -274,11 +274,14 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event)
|
||||
|
||||
switch (event) {
|
||||
case CI_HDRC_IMX_HSIC_ACTIVE_EVENT:
|
||||
ret = pinctrl_select_state(data->pinctrl,
|
||||
data->pinctrl_hsic_active);
|
||||
if (ret)
|
||||
dev_err(dev, "hsic_active select failed, err=%d\n",
|
||||
ret);
|
||||
if (data->pinctrl) {
|
||||
ret = pinctrl_select_state(data->pinctrl,
|
||||
data->pinctrl_hsic_active);
|
||||
if (ret)
|
||||
dev_err(dev,
|
||||
"hsic_active select failed, err=%d\n",
|
||||
ret);
|
||||
}
|
||||
break;
|
||||
case CI_HDRC_IMX_HSIC_SUSPEND_EVENT:
|
||||
ret = imx_usbmisc_hsic_set_connect(data->usbmisc_data);
|
||||
@ -306,7 +309,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
|
||||
const struct ci_hdrc_imx_platform_flag *imx_platform_flag;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pinctrl_state *pinctrl_hsic_idle;
|
||||
|
||||
of_id = of_match_device(ci_hdrc_imx_dt_ids, dev);
|
||||
if (!of_id)
|
||||
@ -330,12 +332,42 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
|
||||
pdata.flags |= CI_HDRC_IMX_IS_HSIC;
|
||||
data->usbmisc_data->hsic = 1;
|
||||
data->pinctrl = devm_pinctrl_get(dev);
|
||||
if (IS_ERR(data->pinctrl)) {
|
||||
dev_err(dev, "pinctrl get failed, err=%ld\n",
|
||||
if (PTR_ERR(data->pinctrl) == -ENODEV)
|
||||
data->pinctrl = NULL;
|
||||
else if (IS_ERR(data->pinctrl)) {
|
||||
if (PTR_ERR(data->pinctrl) != -EPROBE_DEFER)
|
||||
dev_err(dev, "pinctrl get failed, err=%ld\n",
|
||||
PTR_ERR(data->pinctrl));
|
||||
return PTR_ERR(data->pinctrl);
|
||||
}
|
||||
|
||||
data->hsic_pad_regulator =
|
||||
devm_regulator_get_optional(dev, "hsic");
|
||||
if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) {
|
||||
/* no pad regualator is needed */
|
||||
data->hsic_pad_regulator = NULL;
|
||||
} else if (IS_ERR(data->hsic_pad_regulator)) {
|
||||
if (PTR_ERR(data->hsic_pad_regulator) != -EPROBE_DEFER)
|
||||
dev_err(dev,
|
||||
"Get HSIC pad regulator error: %ld\n",
|
||||
PTR_ERR(data->hsic_pad_regulator));
|
||||
return PTR_ERR(data->hsic_pad_regulator);
|
||||
}
|
||||
|
||||
if (data->hsic_pad_regulator) {
|
||||
ret = regulator_enable(data->hsic_pad_regulator);
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"Failed to enable HSIC pad regulator\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* HSIC pinctrl handling */
|
||||
if (data->pinctrl) {
|
||||
struct pinctrl_state *pinctrl_hsic_idle;
|
||||
|
||||
pinctrl_hsic_idle = pinctrl_lookup_state(data->pinctrl, "idle");
|
||||
if (IS_ERR(pinctrl_hsic_idle)) {
|
||||
dev_err(dev,
|
||||
@ -358,27 +390,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
|
||||
PTR_ERR(data->pinctrl_hsic_active));
|
||||
return PTR_ERR(data->pinctrl_hsic_active);
|
||||
}
|
||||
|
||||
data->hsic_pad_regulator = devm_regulator_get(dev, "hsic");
|
||||
if (PTR_ERR(data->hsic_pad_regulator) == -EPROBE_DEFER) {
|
||||
return -EPROBE_DEFER;
|
||||
} else if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) {
|
||||
/* no pad regualator is needed */
|
||||
data->hsic_pad_regulator = NULL;
|
||||
} else if (IS_ERR(data->hsic_pad_regulator)) {
|
||||
dev_err(dev, "Get HSIC pad regulator error: %ld\n",
|
||||
PTR_ERR(data->hsic_pad_regulator));
|
||||
return PTR_ERR(data->hsic_pad_regulator);
|
||||
}
|
||||
|
||||
if (data->hsic_pad_regulator) {
|
||||
ret = regulator_enable(data->hsic_pad_regulator);
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"Failed to enable HSIC pad regulator\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata.flags & CI_HDRC_PMQOS)
|
||||
@ -433,6 +444,16 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
if (data->usbmisc_data) {
|
||||
if (!IS_ERR(pdata.id_extcon.edev) ||
|
||||
of_property_read_bool(np, "usb-role-switch"))
|
||||
data->usbmisc_data->ext_id = 1;
|
||||
|
||||
if (!IS_ERR(pdata.vbus_extcon.edev) ||
|
||||
of_property_read_bool(np, "usb-role-switch"))
|
||||
data->usbmisc_data->ext_vbus = 1;
|
||||
}
|
||||
|
||||
ret = imx_usbmisc_init_post(data->usbmisc_data);
|
||||
if (ret) {
|
||||
dev_err(dev, "usbmisc post failed, ret=%d\n", ret);
|
||||
|
@ -22,6 +22,8 @@ struct imx_usbmisc_data {
|
||||
unsigned int evdo:1; /* set external vbus divider option */
|
||||
unsigned int ulpi:1; /* connected to an ULPI phy */
|
||||
unsigned int hsic:1; /* HSIC controlller */
|
||||
unsigned int ext_id:1; /* ID from exteranl event */
|
||||
unsigned int ext_vbus:1; /* Vbus from exteranl event */
|
||||
};
|
||||
|
||||
int imx_usbmisc_init(struct imx_usbmisc_data *data);
|
||||
|
@ -24,35 +24,23 @@ struct tegra_udc_soc_info {
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
static const struct tegra_udc_soc_info tegra20_udc_soc_info = {
|
||||
.flags = CI_HDRC_REQUIRES_ALIGNED_DMA,
|
||||
};
|
||||
|
||||
static const struct tegra_udc_soc_info tegra30_udc_soc_info = {
|
||||
.flags = CI_HDRC_REQUIRES_ALIGNED_DMA,
|
||||
};
|
||||
|
||||
static const struct tegra_udc_soc_info tegra114_udc_soc_info = {
|
||||
.flags = CI_HDRC_REQUIRES_ALIGNED_DMA,
|
||||
};
|
||||
|
||||
static const struct tegra_udc_soc_info tegra124_udc_soc_info = {
|
||||
static const struct tegra_udc_soc_info tegra_udc_soc_info = {
|
||||
.flags = CI_HDRC_REQUIRES_ALIGNED_DMA,
|
||||
};
|
||||
|
||||
static const struct of_device_id tegra_udc_of_match[] = {
|
||||
{
|
||||
.compatible = "nvidia,tegra20-udc",
|
||||
.data = &tegra20_udc_soc_info,
|
||||
.data = &tegra_udc_soc_info,
|
||||
}, {
|
||||
.compatible = "nvidia,tegra30-udc",
|
||||
.data = &tegra30_udc_soc_info,
|
||||
.data = &tegra_udc_soc_info,
|
||||
}, {
|
||||
.compatible = "nvidia,tegra114-udc",
|
||||
.data = &tegra114_udc_soc_info,
|
||||
.data = &tegra_udc_soc_info,
|
||||
}, {
|
||||
.compatible = "nvidia,tegra124-udc",
|
||||
.data = &tegra124_udc_soc_info,
|
||||
.data = &tegra_udc_soc_info,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
|
@ -683,7 +683,7 @@ static int ci_get_platdata(struct device *dev,
|
||||
|
||||
if (platdata->dr_mode != USB_DR_MODE_PERIPHERAL) {
|
||||
/* Get the vbus regulator */
|
||||
platdata->reg_vbus = devm_regulator_get(dev, "vbus");
|
||||
platdata->reg_vbus = devm_regulator_get_optional(dev, "vbus");
|
||||
if (PTR_ERR(platdata->reg_vbus) == -EPROBE_DEFER) {
|
||||
return -EPROBE_DEFER;
|
||||
} else if (PTR_ERR(platdata->reg_vbus) == -ENODEV) {
|
||||
|
@ -342,7 +342,7 @@ DEFINE_SHOW_ATTRIBUTE(ci_registers);
|
||||
*/
|
||||
void dbg_create_files(struct ci_hdrc *ci)
|
||||
{
|
||||
ci->debugfs = debugfs_create_dir(dev_name(ci->dev), NULL);
|
||||
ci->debugfs = debugfs_create_dir(dev_name(ci->dev), usb_debug_root);
|
||||
|
||||
debugfs_create_file("device", S_IRUGO, ci->debugfs, ci,
|
||||
&ci_device_fops);
|
||||
|
@ -1524,42 +1524,53 @@ static const struct usb_ep_ops usb_ep_ops = {
|
||||
/******************************************************************************
|
||||
* GADGET block
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* ci_hdrc_gadget_connect: caller makes sure gadget driver is binded
|
||||
*/
|
||||
static void ci_hdrc_gadget_connect(struct usb_gadget *_gadget, int is_active)
|
||||
{
|
||||
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
|
||||
unsigned long flags;
|
||||
|
||||
if (is_active) {
|
||||
pm_runtime_get_sync(&_gadget->dev);
|
||||
hw_device_reset(ci);
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
if (ci->driver) {
|
||||
hw_device_state(ci, ci->ep0out->qh.dma);
|
||||
usb_gadget_set_state(_gadget, USB_STATE_POWERED);
|
||||
usb_udc_vbus_handler(_gadget, true);
|
||||
}
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
} else {
|
||||
usb_udc_vbus_handler(_gadget, false);
|
||||
if (ci->driver)
|
||||
ci->driver->disconnect(&ci->gadget);
|
||||
hw_device_state(ci, 0);
|
||||
if (ci->platdata->notify_event)
|
||||
ci->platdata->notify_event(ci,
|
||||
CI_HDRC_CONTROLLER_STOPPED_EVENT);
|
||||
_gadget_stop_activity(&ci->gadget);
|
||||
pm_runtime_put_sync(&_gadget->dev);
|
||||
usb_gadget_set_state(_gadget, USB_STATE_NOTATTACHED);
|
||||
}
|
||||
}
|
||||
|
||||
static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
|
||||
{
|
||||
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
|
||||
unsigned long flags;
|
||||
int gadget_ready = 0;
|
||||
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
ci->vbus_active = is_active;
|
||||
if (ci->driver)
|
||||
gadget_ready = 1;
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
if (ci->usb_phy)
|
||||
usb_phy_set_charger_state(ci->usb_phy, is_active ?
|
||||
USB_CHARGER_PRESENT : USB_CHARGER_ABSENT);
|
||||
|
||||
if (gadget_ready) {
|
||||
if (is_active) {
|
||||
pm_runtime_get_sync(&_gadget->dev);
|
||||
hw_device_reset(ci);
|
||||
hw_device_state(ci, ci->ep0out->qh.dma);
|
||||
usb_gadget_set_state(_gadget, USB_STATE_POWERED);
|
||||
usb_udc_vbus_handler(_gadget, true);
|
||||
} else {
|
||||
usb_udc_vbus_handler(_gadget, false);
|
||||
if (ci->driver)
|
||||
ci->driver->disconnect(&ci->gadget);
|
||||
hw_device_state(ci, 0);
|
||||
if (ci->platdata->notify_event)
|
||||
ci->platdata->notify_event(ci,
|
||||
CI_HDRC_CONTROLLER_STOPPED_EVENT);
|
||||
_gadget_stop_activity(&ci->gadget);
|
||||
pm_runtime_put_sync(&_gadget->dev);
|
||||
usb_gadget_set_state(_gadget, USB_STATE_NOTATTACHED);
|
||||
}
|
||||
}
|
||||
if (ci->driver)
|
||||
ci_hdrc_gadget_connect(_gadget, is_active);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1612,7 +1623,7 @@ static int ci_udc_selfpowered(struct usb_gadget *_gadget, int is_on)
|
||||
}
|
||||
|
||||
/* Change Data+ pullup status
|
||||
* this func is used by usb_gadget_connect/disconnet
|
||||
* this func is used by usb_gadget_connect/disconnect
|
||||
*/
|
||||
static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on)
|
||||
{
|
||||
@ -1785,18 +1796,10 @@ static int ci_udc_start(struct usb_gadget *gadget,
|
||||
return retval;
|
||||
}
|
||||
|
||||
pm_runtime_get_sync(&ci->gadget.dev);
|
||||
if (ci->vbus_active) {
|
||||
hw_device_reset(ci);
|
||||
} else {
|
||||
if (ci->vbus_active)
|
||||
ci_hdrc_gadget_connect(gadget, 1);
|
||||
else
|
||||
usb_udc_vbus_handler(&ci->gadget, false);
|
||||
pm_runtime_put_sync(&ci->gadget.dev);
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = hw_device_state(ci, ci->ep0out->qh.dma);
|
||||
if (retval)
|
||||
pm_runtime_put_sync(&ci->gadget.dev);
|
||||
|
||||
return retval;
|
||||
}
|
||||
@ -1826,6 +1829,7 @@ static int ci_udc_stop(struct usb_gadget *gadget)
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
ci->driver = NULL;
|
||||
|
||||
if (ci->vbus_active) {
|
||||
hw_device_state(ci, 0);
|
||||
@ -1838,7 +1842,6 @@ static int ci_udc_stop(struct usb_gadget *gadget)
|
||||
pm_runtime_put(&ci->gadget.dev);
|
||||
}
|
||||
|
||||
ci->driver = NULL;
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
ci_udc_stop_for_otg_fsm(ci);
|
||||
|
@ -100,6 +100,9 @@
|
||||
#define MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID MX7D_USB_VBUS_WAKEUP_SOURCE(2)
|
||||
#define MX7D_USB_VBUS_WAKEUP_SOURCE_SESS_END MX7D_USB_VBUS_WAKEUP_SOURCE(3)
|
||||
|
||||
#define MX6_USB_OTG_WAKEUP_BITS (MX6_BM_WAKEUP_ENABLE | MX6_BM_VBUS_WAKEUP | \
|
||||
MX6_BM_ID_WAKEUP)
|
||||
|
||||
struct usbmisc_ops {
|
||||
/* It's called once when probe a usb device */
|
||||
int (*init)(struct imx_usbmisc_data *data);
|
||||
@ -330,14 +333,25 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 usbmisc_wakeup_setting(struct imx_usbmisc_data *data)
|
||||
{
|
||||
u32 wakeup_setting = MX6_USB_OTG_WAKEUP_BITS;
|
||||
|
||||
if (data->ext_id)
|
||||
wakeup_setting &= ~MX6_BM_ID_WAKEUP;
|
||||
|
||||
if (data->ext_vbus)
|
||||
wakeup_setting &= ~MX6_BM_VBUS_WAKEUP;
|
||||
|
||||
return wakeup_setting;
|
||||
}
|
||||
|
||||
static int usbmisc_imx6q_set_wakeup
|
||||
(struct imx_usbmisc_data *data, bool enabled)
|
||||
{
|
||||
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
u32 wakeup_setting = (MX6_BM_WAKEUP_ENABLE |
|
||||
MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP);
|
||||
int ret = 0;
|
||||
|
||||
if (data->index > 3)
|
||||
@ -346,11 +360,12 @@ static int usbmisc_imx6q_set_wakeup
|
||||
spin_lock_irqsave(&usbmisc->lock, flags);
|
||||
val = readl(usbmisc->base + data->index * 4);
|
||||
if (enabled) {
|
||||
val |= wakeup_setting;
|
||||
val &= ~MX6_USB_OTG_WAKEUP_BITS;
|
||||
val |= usbmisc_wakeup_setting(data);
|
||||
} else {
|
||||
if (val & MX6_BM_WAKEUP_INTR)
|
||||
pr_debug("wakeup int at ci_hdrc.%d\n", data->index);
|
||||
val &= ~wakeup_setting;
|
||||
val &= ~MX6_USB_OTG_WAKEUP_BITS;
|
||||
}
|
||||
writel(val, usbmisc->base + data->index * 4);
|
||||
spin_unlock_irqrestore(&usbmisc->lock, flags);
|
||||
@ -547,17 +562,17 @@ static int usbmisc_imx7d_set_wakeup
|
||||
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
u32 wakeup_setting = (MX6_BM_WAKEUP_ENABLE |
|
||||
MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP);
|
||||
|
||||
spin_lock_irqsave(&usbmisc->lock, flags);
|
||||
val = readl(usbmisc->base);
|
||||
if (enabled) {
|
||||
writel(val | wakeup_setting, usbmisc->base);
|
||||
val &= ~MX6_USB_OTG_WAKEUP_BITS;
|
||||
val |= usbmisc_wakeup_setting(data);
|
||||
writel(val, usbmisc->base);
|
||||
} else {
|
||||
if (val & MX6_BM_WAKEUP_INTR)
|
||||
dev_dbg(data->dev, "wakeup int\n");
|
||||
writel(val & ~wakeup_setting, usbmisc->base);
|
||||
writel(val & ~MX6_USB_OTG_WAKEUP_BITS, usbmisc->base);
|
||||
}
|
||||
spin_unlock_irqrestore(&usbmisc->lock, flags);
|
||||
|
||||
|
@ -805,10 +805,10 @@ int usb_get_configuration(struct usb_device *dev)
|
||||
{
|
||||
struct device *ddev = &dev->dev;
|
||||
int ncfg = dev->descriptor.bNumConfigurations;
|
||||
int result = -ENOMEM;
|
||||
unsigned int cfgno, length;
|
||||
unsigned char *bigbuffer;
|
||||
struct usb_config_descriptor *desc;
|
||||
int result;
|
||||
|
||||
if (ncfg > USB_MAXCONFIG) {
|
||||
dev_warn(ddev, "too many configurations: %d, "
|
||||
@ -824,16 +824,16 @@ int usb_get_configuration(struct usb_device *dev)
|
||||
length = ncfg * sizeof(struct usb_host_config);
|
||||
dev->config = kzalloc(length, GFP_KERNEL);
|
||||
if (!dev->config)
|
||||
goto err2;
|
||||
return -ENOMEM;
|
||||
|
||||
length = ncfg * sizeof(char *);
|
||||
dev->rawdescriptors = kzalloc(length, GFP_KERNEL);
|
||||
if (!dev->rawdescriptors)
|
||||
goto err2;
|
||||
return -ENOMEM;
|
||||
|
||||
desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
|
||||
if (!desc)
|
||||
goto err2;
|
||||
return -ENOMEM;
|
||||
|
||||
for (cfgno = 0; cfgno < ncfg; cfgno++) {
|
||||
/* We grab just the first descriptor so we know how long
|
||||
@ -895,9 +895,7 @@ int usb_get_configuration(struct usb_device *dev)
|
||||
err:
|
||||
kfree(desc);
|
||||
dev->descriptor.bNumConfigurations = cfgno;
|
||||
err2:
|
||||
if (result == -ENOMEM)
|
||||
dev_err(ddev, "out of memory\n");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -764,8 +764,15 @@ static int claimintf(struct usb_dev_state *ps, unsigned int ifnum)
|
||||
intf = usb_ifnum_to_if(dev, ifnum);
|
||||
if (!intf)
|
||||
err = -ENOENT;
|
||||
else
|
||||
else {
|
||||
unsigned int old_suppress;
|
||||
|
||||
/* suppress uevents while claiming interface */
|
||||
old_suppress = dev_get_uevent_suppress(&intf->dev);
|
||||
dev_set_uevent_suppress(&intf->dev, 1);
|
||||
err = usb_driver_claim_interface(&usbfs_driver, intf, ps);
|
||||
dev_set_uevent_suppress(&intf->dev, old_suppress);
|
||||
}
|
||||
if (err == 0)
|
||||
set_bit(ifnum, &ps->ifclaimed);
|
||||
return err;
|
||||
@ -785,7 +792,13 @@ static int releaseintf(struct usb_dev_state *ps, unsigned int ifnum)
|
||||
if (!intf)
|
||||
err = -ENOENT;
|
||||
else if (test_and_clear_bit(ifnum, &ps->ifclaimed)) {
|
||||
unsigned int old_suppress;
|
||||
|
||||
/* suppress uevents while releasing interface */
|
||||
old_suppress = dev_get_uevent_suppress(&intf->dev);
|
||||
dev_set_uevent_suppress(&intf->dev, 1);
|
||||
usb_driver_release_interface(&usbfs_driver, intf);
|
||||
dev_set_uevent_suppress(&intf->dev, old_suppress);
|
||||
err = 0;
|
||||
}
|
||||
return err;
|
||||
@ -1550,10 +1563,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
|
||||
uurb->buffer_length = le16_to_cpu(dr->wLength);
|
||||
uurb->buffer += 8;
|
||||
if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
|
||||
is_in = 1;
|
||||
is_in = true;
|
||||
uurb->endpoint |= USB_DIR_IN;
|
||||
} else {
|
||||
is_in = 0;
|
||||
is_in = false;
|
||||
uurb->endpoint &= ~USB_DIR_IN;
|
||||
}
|
||||
if (is_in)
|
||||
|
@ -4930,6 +4930,91 @@ hub_power_remaining(struct usb_hub *hub)
|
||||
return remaining;
|
||||
}
|
||||
|
||||
|
||||
static int descriptors_changed(struct usb_device *udev,
|
||||
struct usb_device_descriptor *old_device_descriptor,
|
||||
struct usb_host_bos *old_bos)
|
||||
{
|
||||
int changed = 0;
|
||||
unsigned index;
|
||||
unsigned serial_len = 0;
|
||||
unsigned len;
|
||||
unsigned old_length;
|
||||
int length;
|
||||
char *buf;
|
||||
|
||||
if (memcmp(&udev->descriptor, old_device_descriptor,
|
||||
sizeof(*old_device_descriptor)) != 0)
|
||||
return 1;
|
||||
|
||||
if ((old_bos && !udev->bos) || (!old_bos && udev->bos))
|
||||
return 1;
|
||||
if (udev->bos) {
|
||||
len = le16_to_cpu(udev->bos->desc->wTotalLength);
|
||||
if (len != le16_to_cpu(old_bos->desc->wTotalLength))
|
||||
return 1;
|
||||
if (memcmp(udev->bos->desc, old_bos->desc, len))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Since the idVendor, idProduct, and bcdDevice values in the
|
||||
* device descriptor haven't changed, we will assume the
|
||||
* Manufacturer and Product strings haven't changed either.
|
||||
* But the SerialNumber string could be different (e.g., a
|
||||
* different flash card of the same brand).
|
||||
*/
|
||||
if (udev->serial)
|
||||
serial_len = strlen(udev->serial) + 1;
|
||||
|
||||
len = serial_len;
|
||||
for (index = 0; index < udev->descriptor.bNumConfigurations; index++) {
|
||||
old_length = le16_to_cpu(udev->config[index].desc.wTotalLength);
|
||||
len = max(len, old_length);
|
||||
}
|
||||
|
||||
buf = kmalloc(len, GFP_NOIO);
|
||||
if (!buf)
|
||||
/* assume the worst */
|
||||
return 1;
|
||||
|
||||
for (index = 0; index < udev->descriptor.bNumConfigurations; index++) {
|
||||
old_length = le16_to_cpu(udev->config[index].desc.wTotalLength);
|
||||
length = usb_get_descriptor(udev, USB_DT_CONFIG, index, buf,
|
||||
old_length);
|
||||
if (length != old_length) {
|
||||
dev_dbg(&udev->dev, "config index %d, error %d\n",
|
||||
index, length);
|
||||
changed = 1;
|
||||
break;
|
||||
}
|
||||
if (memcmp(buf, udev->rawdescriptors[index], old_length)
|
||||
!= 0) {
|
||||
dev_dbg(&udev->dev, "config index %d changed (#%d)\n",
|
||||
index,
|
||||
((struct usb_config_descriptor *) buf)->
|
||||
bConfigurationValue);
|
||||
changed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!changed && serial_len) {
|
||||
length = usb_string(udev, udev->descriptor.iSerialNumber,
|
||||
buf, serial_len);
|
||||
if (length + 1 != serial_len) {
|
||||
dev_dbg(&udev->dev, "serial string error %d\n",
|
||||
length);
|
||||
changed = 1;
|
||||
} else if (memcmp(buf, udev->serial, length) != 0) {
|
||||
dev_dbg(&udev->dev, "serial string changed\n");
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
return changed;
|
||||
}
|
||||
|
||||
static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
|
||||
u16 portchange)
|
||||
{
|
||||
@ -5167,7 +5252,9 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||
{
|
||||
struct usb_port *port_dev = hub->ports[port1 - 1];
|
||||
struct usb_device *udev = port_dev->child;
|
||||
struct usb_device_descriptor descriptor;
|
||||
int status = -ENODEV;
|
||||
int retval;
|
||||
|
||||
dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n", portstatus,
|
||||
portchange, portspeed(hub, portstatus));
|
||||
@ -5188,7 +5275,30 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||
if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
|
||||
udev->state != USB_STATE_NOTATTACHED) {
|
||||
if (portstatus & USB_PORT_STAT_ENABLE) {
|
||||
status = 0; /* Nothing to do */
|
||||
/*
|
||||
* USB-3 connections are initialized automatically by
|
||||
* the hostcontroller hardware. Therefore check for
|
||||
* changed device descriptors before resuscitating the
|
||||
* device.
|
||||
*/
|
||||
descriptor = udev->descriptor;
|
||||
retval = usb_get_device_descriptor(udev,
|
||||
sizeof(udev->descriptor));
|
||||
if (retval < 0) {
|
||||
dev_dbg(&udev->dev,
|
||||
"can't read device descriptor %d\n",
|
||||
retval);
|
||||
} else {
|
||||
if (descriptors_changed(udev, &descriptor,
|
||||
udev->bos)) {
|
||||
dev_dbg(&udev->dev,
|
||||
"device descriptor has changed\n");
|
||||
/* for disconnect() calls */
|
||||
udev->descriptor = descriptor;
|
||||
} else {
|
||||
status = 0; /* Nothing to do */
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_PM
|
||||
} else if (udev->state == USB_STATE_SUSPENDED &&
|
||||
udev->persist_enabled) {
|
||||
@ -5550,90 +5660,6 @@ void usb_hub_cleanup(void)
|
||||
usb_deregister(&hub_driver);
|
||||
} /* usb_hub_cleanup() */
|
||||
|
||||
static int descriptors_changed(struct usb_device *udev,
|
||||
struct usb_device_descriptor *old_device_descriptor,
|
||||
struct usb_host_bos *old_bos)
|
||||
{
|
||||
int changed = 0;
|
||||
unsigned index;
|
||||
unsigned serial_len = 0;
|
||||
unsigned len;
|
||||
unsigned old_length;
|
||||
int length;
|
||||
char *buf;
|
||||
|
||||
if (memcmp(&udev->descriptor, old_device_descriptor,
|
||||
sizeof(*old_device_descriptor)) != 0)
|
||||
return 1;
|
||||
|
||||
if ((old_bos && !udev->bos) || (!old_bos && udev->bos))
|
||||
return 1;
|
||||
if (udev->bos) {
|
||||
len = le16_to_cpu(udev->bos->desc->wTotalLength);
|
||||
if (len != le16_to_cpu(old_bos->desc->wTotalLength))
|
||||
return 1;
|
||||
if (memcmp(udev->bos->desc, old_bos->desc, len))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Since the idVendor, idProduct, and bcdDevice values in the
|
||||
* device descriptor haven't changed, we will assume the
|
||||
* Manufacturer and Product strings haven't changed either.
|
||||
* But the SerialNumber string could be different (e.g., a
|
||||
* different flash card of the same brand).
|
||||
*/
|
||||
if (udev->serial)
|
||||
serial_len = strlen(udev->serial) + 1;
|
||||
|
||||
len = serial_len;
|
||||
for (index = 0; index < udev->descriptor.bNumConfigurations; index++) {
|
||||
old_length = le16_to_cpu(udev->config[index].desc.wTotalLength);
|
||||
len = max(len, old_length);
|
||||
}
|
||||
|
||||
buf = kmalloc(len, GFP_NOIO);
|
||||
if (!buf)
|
||||
/* assume the worst */
|
||||
return 1;
|
||||
|
||||
for (index = 0; index < udev->descriptor.bNumConfigurations; index++) {
|
||||
old_length = le16_to_cpu(udev->config[index].desc.wTotalLength);
|
||||
length = usb_get_descriptor(udev, USB_DT_CONFIG, index, buf,
|
||||
old_length);
|
||||
if (length != old_length) {
|
||||
dev_dbg(&udev->dev, "config index %d, error %d\n",
|
||||
index, length);
|
||||
changed = 1;
|
||||
break;
|
||||
}
|
||||
if (memcmp(buf, udev->rawdescriptors[index], old_length)
|
||||
!= 0) {
|
||||
dev_dbg(&udev->dev, "config index %d changed (#%d)\n",
|
||||
index,
|
||||
((struct usb_config_descriptor *) buf)->
|
||||
bConfigurationValue);
|
||||
changed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!changed && serial_len) {
|
||||
length = usb_string(udev, udev->descriptor.iSerialNumber,
|
||||
buf, serial_len);
|
||||
if (length + 1 != serial_len) {
|
||||
dev_dbg(&udev->dev, "serial string error %d\n",
|
||||
length);
|
||||
changed = 1;
|
||||
} else if (memcmp(buf, udev->serial, length) != 0) {
|
||||
dev_dbg(&udev->dev, "serial string changed\n");
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_reset_and_verify_device - perform a USB port reset to reinitialize a device
|
||||
* @udev: device to reset (not in SUSPENDED or NOTATTACHED state)
|
||||
@ -5814,7 +5840,7 @@ re_enumerate_no_bos:
|
||||
|
||||
/**
|
||||
* usb_reset_device - warn interface drivers and perform a USB port reset
|
||||
* @udev: device to reset (not in SUSPENDED or NOTATTACHED state)
|
||||
* @udev: device to reset (not in NOTATTACHED state)
|
||||
*
|
||||
* Warns all drivers bound to registered interfaces (using their pre_reset
|
||||
* method), performs the port reset, and then lets the drivers know that
|
||||
@ -5842,8 +5868,7 @@ int usb_reset_device(struct usb_device *udev)
|
||||
struct usb_host_config *config = udev->actconfig;
|
||||
struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
|
||||
|
||||
if (udev->state == USB_STATE_NOTATTACHED ||
|
||||
udev->state == USB_STATE_SUSPENDED) {
|
||||
if (udev->state == USB_STATE_NOTATTACHED) {
|
||||
dev_dbg(&udev->dev, "device reset not allowed in state %d\n",
|
||||
udev->state);
|
||||
return -EINVAL;
|
||||
|
@ -524,7 +524,7 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
|
||||
greset |= GRSTCTL_CSFTRST;
|
||||
dwc2_writel(hsotg, greset, GRSTCTL);
|
||||
|
||||
if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_CSFTRST, 50)) {
|
||||
if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_CSFTRST, 10000)) {
|
||||
dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL GRSTCTL_CSFTRST\n",
|
||||
__func__);
|
||||
return -EBUSY;
|
||||
|
@ -134,7 +134,7 @@ struct dwc2_hsotg_req;
|
||||
* @target_frame: Targeted frame num to setup next ISOC transfer
|
||||
* @frame_overrun: Indicates SOF number overrun in DSTS
|
||||
*
|
||||
* This is the driver's state for each registered enpoint, allowing it
|
||||
* This is the driver's state for each registered endpoint, allowing it
|
||||
* to keep track of transactions that need doing. Each endpoint has a
|
||||
* lock to protect the state, to try and avoid using an overall lock
|
||||
* for the host controller as much as possible.
|
||||
|
@ -770,7 +770,7 @@ int dwc2_debugfs_init(struct dwc2_hsotg *hsotg)
|
||||
int ret;
|
||||
struct dentry *root;
|
||||
|
||||
root = debugfs_create_dir(dev_name(hsotg->dev), NULL);
|
||||
root = debugfs_create_dir(dev_name(hsotg->dev), usb_debug_root);
|
||||
hsotg->debug_root = root;
|
||||
|
||||
debugfs_create_file("params", 0444, root, hsotg, ¶ms_fops);
|
||||
|
@ -97,24 +97,24 @@ config USB_DWC3_KEYSTONE
|
||||
Say 'Y' or 'M' here if you have one such device
|
||||
|
||||
config USB_DWC3_MESON_G12A
|
||||
tristate "Amlogic Meson G12A Platforms"
|
||||
depends on OF && COMMON_CLK
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
default USB_DWC3
|
||||
select USB_ROLE_SWITCH
|
||||
tristate "Amlogic Meson G12A Platforms"
|
||||
depends on OF && COMMON_CLK
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
default USB_DWC3
|
||||
select USB_ROLE_SWITCH
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
Support USB2/3 functionality in Amlogic G12A platforms.
|
||||
Say 'Y' or 'M' if you have one such device.
|
||||
help
|
||||
Support USB2/3 functionality in Amlogic G12A platforms.
|
||||
Say 'Y' or 'M' if you have one such device.
|
||||
|
||||
config USB_DWC3_OF_SIMPLE
|
||||
tristate "Generic OF Simple Glue Layer"
|
||||
depends on OF && COMMON_CLK
|
||||
default USB_DWC3
|
||||
help
|
||||
Support USB2/3 functionality in simple SoC integrations.
|
||||
Currently supports Xilinx and Qualcomm DWC USB3 IP.
|
||||
Say 'Y' or 'M' if you have one such device.
|
||||
tristate "Generic OF Simple Glue Layer"
|
||||
depends on OF && COMMON_CLK
|
||||
default USB_DWC3
|
||||
help
|
||||
Support USB2/3 functionality in simple SoC integrations.
|
||||
Currently supports Xilinx and Qualcomm DWC USB3 IP.
|
||||
Say 'Y' or 'M' if you have one such device.
|
||||
|
||||
config USB_DWC3_ST
|
||||
tristate "STMicroelectronics Platforms"
|
||||
|
@ -566,8 +566,11 @@ static int dwc3_core_ulpi_init(struct dwc3 *dwc)
|
||||
*/
|
||||
static int dwc3_phy_setup(struct dwc3 *dwc)
|
||||
{
|
||||
unsigned int hw_mode;
|
||||
u32 reg;
|
||||
|
||||
hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
|
||||
|
||||
/*
|
||||
@ -585,6 +588,14 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
|
||||
if (dwc->revision > DWC3_REVISION_194A)
|
||||
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
|
||||
/*
|
||||
* For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be cleared after
|
||||
* power-on reset, and it can be set after core initialization, which is
|
||||
* after device soft-reset during initialization.
|
||||
*/
|
||||
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD)
|
||||
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
|
||||
if (dwc->u2ss_inp3_quirk)
|
||||
reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
|
||||
|
||||
@ -668,6 +679,14 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
|
||||
if (dwc->revision > DWC3_REVISION_194A)
|
||||
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
|
||||
/*
|
||||
* For DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared after
|
||||
* power-on reset, and it can be set after core initialization, which is
|
||||
* after device soft-reset during initialization.
|
||||
*/
|
||||
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD)
|
||||
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
|
||||
if (dwc->dis_u2_susphy_quirk)
|
||||
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
|
||||
@ -902,9 +921,12 @@ static void dwc3_set_incr_burst_type(struct dwc3 *dwc)
|
||||
*/
|
||||
static int dwc3_core_init(struct dwc3 *dwc)
|
||||
{
|
||||
unsigned int hw_mode;
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
|
||||
|
||||
/*
|
||||
* Write Linux Version Code to our GUID register so it's easy to figure
|
||||
* out which kernel version a bug was found.
|
||||
@ -940,6 +962,21 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
||||
if (ret)
|
||||
goto err0a;
|
||||
|
||||
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD &&
|
||||
dwc->revision > DWC3_REVISION_194A) {
|
||||
if (!dwc->dis_u3_susphy_quirk) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
|
||||
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
|
||||
}
|
||||
|
||||
if (!dwc->dis_u2_susphy_quirk) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||||
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||||
}
|
||||
}
|
||||
|
||||
dwc3_core_setup_global_control(dwc);
|
||||
dwc3_core_num_eps(dwc);
|
||||
|
||||
|
@ -112,7 +112,7 @@ dwc3_gadget_link_string(enum dwc3_link_state link_state)
|
||||
case DWC3_LINK_STATE_RESUME:
|
||||
return "Resume";
|
||||
default:
|
||||
return "UNKNOWN link state\n";
|
||||
return "UNKNOWN link state";
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,7 +141,7 @@ dwc3_gadget_hs_link_string(enum dwc3_link_state link_state)
|
||||
case DWC3_LINK_STATE_RESUME:
|
||||
return "Resume";
|
||||
default:
|
||||
return "UNKNOWN link state\n";
|
||||
return "UNKNOWN link state";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -916,7 +916,7 @@ void dwc3_debugfs_init(struct dwc3 *dwc)
|
||||
dwc->regset->nregs = ARRAY_SIZE(dwc3_regs);
|
||||
dwc->regset->base = dwc->regs - DWC3_GLOBALS_REGS_START;
|
||||
|
||||
root = debugfs_create_dir(dev_name(dwc->dev), NULL);
|
||||
root = debugfs_create_dir(dev_name(dwc->dev), usb_debug_root);
|
||||
dwc->root = root;
|
||||
|
||||
debugfs_create_regset32("regdump", S_IRUGO, root, dwc->regset);
|
||||
|
@ -110,12 +110,9 @@ err_resetc_put:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwc3_of_simple_remove(struct platform_device *pdev)
|
||||
static void __dwc3_of_simple_teardown(struct dwc3_of_simple *simple)
|
||||
{
|
||||
struct dwc3_of_simple *simple = platform_get_drvdata(pdev);
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
of_platform_depopulate(dev);
|
||||
of_platform_depopulate(simple->dev);
|
||||
|
||||
clk_bulk_disable_unprepare(simple->num_clocks, simple->clks);
|
||||
clk_bulk_put_all(simple->num_clocks, simple->clks);
|
||||
@ -126,13 +123,27 @@ static int dwc3_of_simple_remove(struct platform_device *pdev)
|
||||
|
||||
reset_control_put(simple->resets);
|
||||
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_put_noidle(dev);
|
||||
pm_runtime_set_suspended(dev);
|
||||
pm_runtime_disable(simple->dev);
|
||||
pm_runtime_put_noidle(simple->dev);
|
||||
pm_runtime_set_suspended(simple->dev);
|
||||
}
|
||||
|
||||
static int dwc3_of_simple_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dwc3_of_simple *simple = platform_get_drvdata(pdev);
|
||||
|
||||
__dwc3_of_simple_teardown(simple);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwc3_of_simple_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct dwc3_of_simple *simple = platform_get_drvdata(pdev);
|
||||
|
||||
__dwc3_of_simple_teardown(simple);
|
||||
}
|
||||
|
||||
static int __maybe_unused dwc3_of_simple_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct dwc3_of_simple *simple = dev_get_drvdata(dev);
|
||||
@ -190,6 +201,7 @@ MODULE_DEVICE_TABLE(of, of_dwc3_simple_match);
|
||||
static struct platform_driver dwc3_of_simple_driver = {
|
||||
.probe = dwc3_of_simple_probe,
|
||||
.remove = dwc3_of_simple_remove,
|
||||
.shutdown = dwc3_of_simple_shutdown,
|
||||
.driver = {
|
||||
.name = "dwc3-of-simple",
|
||||
.of_match_table = of_dwc3_simple_match,
|
||||
|
@ -794,9 +794,9 @@ static int set_config(struct usb_composite_dev *cdev,
|
||||
result = 0;
|
||||
}
|
||||
|
||||
INFO(cdev, "%s config #%d: %s\n",
|
||||
usb_speed_string(gadget->speed),
|
||||
number, c ? c->label : "unconfigured");
|
||||
DBG(cdev, "%s config #%d: %s\n",
|
||||
usb_speed_string(gadget->speed),
|
||||
number, c ? c->label : "unconfigured");
|
||||
|
||||
if (!c)
|
||||
goto done;
|
||||
|
@ -1544,6 +1544,7 @@ static struct config_group *gadgets_make(
|
||||
gi->composite.resume = NULL;
|
||||
gi->composite.max_speed = USB_SPEED_SUPER;
|
||||
|
||||
spin_lock_init(&gi->spinlock);
|
||||
mutex_init(&gi->lock);
|
||||
INIT_LIST_HEAD(&gi->string_list);
|
||||
INIT_LIST_HEAD(&gi->available_func);
|
||||
|
@ -771,6 +771,24 @@ static struct configfs_item_operations acm_item_ops = {
|
||||
.release = acm_attr_release,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_U_SERIAL_CONSOLE
|
||||
|
||||
static ssize_t f_acm_console_store(struct config_item *item,
|
||||
const char *page, size_t count)
|
||||
{
|
||||
return gserial_set_console(to_f_serial_opts(item)->port_num,
|
||||
page, count);
|
||||
}
|
||||
|
||||
static ssize_t f_acm_console_show(struct config_item *item, char *page)
|
||||
{
|
||||
return gserial_get_console(to_f_serial_opts(item)->port_num, page);
|
||||
}
|
||||
|
||||
CONFIGFS_ATTR(f_acm_, console);
|
||||
|
||||
#endif /* CONFIG_U_SERIAL_CONSOLE */
|
||||
|
||||
static ssize_t f_acm_port_num_show(struct config_item *item, char *page)
|
||||
{
|
||||
return sprintf(page, "%u\n", to_f_serial_opts(item)->port_num);
|
||||
@ -779,6 +797,9 @@ static ssize_t f_acm_port_num_show(struct config_item *item, char *page)
|
||||
CONFIGFS_ATTR_RO(f_acm_, port_num);
|
||||
|
||||
static struct configfs_attribute *acm_attrs[] = {
|
||||
#ifdef CONFIG_U_SERIAL_CONSOLE
|
||||
&f_acm_attr_console,
|
||||
#endif
|
||||
&f_acm_attr_port_num,
|
||||
NULL,
|
||||
};
|
||||
|
@ -432,7 +432,7 @@ static struct usb_function_instance *obex_alloc_inst(void)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
opts->func_inst.free_func_inst = obex_free_inst;
|
||||
ret = gserial_alloc_line(&opts->port_num);
|
||||
ret = gserial_alloc_line_no_console(&opts->port_num);
|
||||
if (ret) {
|
||||
kfree(opts);
|
||||
return ERR_PTR(ret);
|
||||
|
@ -266,6 +266,24 @@ static struct configfs_item_operations serial_item_ops = {
|
||||
.release = serial_attr_release,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_U_SERIAL_CONSOLE
|
||||
|
||||
static ssize_t f_serial_console_store(struct config_item *item,
|
||||
const char *page, size_t count)
|
||||
{
|
||||
return gserial_set_console(to_f_serial_opts(item)->port_num,
|
||||
page, count);
|
||||
}
|
||||
|
||||
static ssize_t f_serial_console_show(struct config_item *item, char *page)
|
||||
{
|
||||
return gserial_get_console(to_f_serial_opts(item)->port_num, page);
|
||||
}
|
||||
|
||||
CONFIGFS_ATTR(f_serial_, console);
|
||||
|
||||
#endif /* CONFIG_U_SERIAL_CONSOLE */
|
||||
|
||||
static ssize_t f_serial_port_num_show(struct config_item *item, char *page)
|
||||
{
|
||||
return sprintf(page, "%u\n", to_f_serial_opts(item)->port_num);
|
||||
@ -274,6 +292,9 @@ static ssize_t f_serial_port_num_show(struct config_item *item, char *page)
|
||||
CONFIGFS_ATTR_RO(f_serial_, port_num);
|
||||
|
||||
static struct configfs_attribute *acm_attrs[] = {
|
||||
#ifdef CONFIG_U_SERIAL_CONSOLE
|
||||
&f_serial_attr_console,
|
||||
#endif
|
||||
&f_serial_attr_port_num,
|
||||
NULL,
|
||||
};
|
||||
|
@ -846,7 +846,7 @@ static void uasp_set_alt(struct f_uas *fu)
|
||||
|
||||
fu->flags = USBG_IS_UAS;
|
||||
|
||||
if (gadget->speed == USB_SPEED_SUPER)
|
||||
if (gadget->speed >= USB_SPEED_SUPER)
|
||||
fu->flags |= USBG_USE_STREAMS;
|
||||
|
||||
config_ep_by_speed(gadget, f, fu->ep_in);
|
||||
@ -2093,6 +2093,16 @@ static void tcm_delayed_set_alt(struct work_struct *wq)
|
||||
usb_composite_setup_continue(fu->function.config->cdev);
|
||||
}
|
||||
|
||||
static int tcm_get_alt(struct usb_function *f, unsigned intf)
|
||||
{
|
||||
if (intf == bot_intf_desc.bInterfaceNumber)
|
||||
return USB_G_ALT_INT_BBB;
|
||||
if (intf == uasp_intf_desc.bInterfaceNumber)
|
||||
return USB_G_ALT_INT_UAS;
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int tcm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
{
|
||||
struct f_uas *fu = to_f_uas(f);
|
||||
@ -2300,6 +2310,7 @@ static struct usb_function *tcm_alloc(struct usb_function_instance *fi)
|
||||
fu->function.bind = tcm_bind;
|
||||
fu->function.unbind = tcm_unbind;
|
||||
fu->function.set_alt = tcm_set_alt;
|
||||
fu->function.get_alt = tcm_get_alt;
|
||||
fu->function.setup = tcm_setup;
|
||||
fu->function.disable = tcm_disable;
|
||||
fu->function.free_func = tcm_free;
|
||||
|
@ -82,14 +82,13 @@
|
||||
#define GS_CONSOLE_BUF_SIZE 8192
|
||||
|
||||
/* console info */
|
||||
struct gscons_info {
|
||||
struct gs_port *port;
|
||||
struct task_struct *console_thread;
|
||||
struct kfifo con_buf;
|
||||
/* protect the buf and busy flag */
|
||||
spinlock_t con_lock;
|
||||
int req_busy;
|
||||
struct usb_request *console_req;
|
||||
struct gs_console {
|
||||
struct console console;
|
||||
struct work_struct work;
|
||||
spinlock_t lock;
|
||||
struct usb_request *req;
|
||||
struct kfifo buf;
|
||||
size_t missed;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -101,8 +100,10 @@ struct gs_port {
|
||||
spinlock_t port_lock; /* guard port_* access */
|
||||
|
||||
struct gserial *port_usb;
|
||||
#ifdef CONFIG_U_SERIAL_CONSOLE
|
||||
struct gs_console *console;
|
||||
#endif
|
||||
|
||||
bool openclose; /* open/close in progress */
|
||||
u8 port_num;
|
||||
|
||||
struct list_head read_pool;
|
||||
@ -586,82 +587,45 @@ static int gs_open(struct tty_struct *tty, struct file *file)
|
||||
{
|
||||
int port_num = tty->index;
|
||||
struct gs_port *port;
|
||||
int status;
|
||||
int status = 0;
|
||||
|
||||
do {
|
||||
mutex_lock(&ports[port_num].lock);
|
||||
port = ports[port_num].port;
|
||||
if (!port)
|
||||
status = -ENODEV;
|
||||
else {
|
||||
spin_lock_irq(&port->port_lock);
|
||||
mutex_lock(&ports[port_num].lock);
|
||||
port = ports[port_num].port;
|
||||
if (!port) {
|
||||
status = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* already open? Great. */
|
||||
if (port->port.count) {
|
||||
status = 0;
|
||||
port->port.count++;
|
||||
|
||||
/* currently opening/closing? wait ... */
|
||||
} else if (port->openclose) {
|
||||
status = -EBUSY;
|
||||
|
||||
/* ... else we do the work */
|
||||
} else {
|
||||
status = -EAGAIN;
|
||||
port->openclose = true;
|
||||
}
|
||||
spin_unlock_irq(&port->port_lock);
|
||||
}
|
||||
mutex_unlock(&ports[port_num].lock);
|
||||
|
||||
switch (status) {
|
||||
default:
|
||||
/* fully handled */
|
||||
return status;
|
||||
case -EAGAIN:
|
||||
/* must do the work */
|
||||
break;
|
||||
case -EBUSY:
|
||||
/* wait for EAGAIN task to finish */
|
||||
msleep(1);
|
||||
/* REVISIT could have a waitchannel here, if
|
||||
* concurrent open performance is important
|
||||
*/
|
||||
break;
|
||||
}
|
||||
} while (status != -EAGAIN);
|
||||
|
||||
/* Do the "real open" */
|
||||
spin_lock_irq(&port->port_lock);
|
||||
|
||||
/* allocate circular buffer on first open */
|
||||
if (!kfifo_initialized(&port->port_write_buf)) {
|
||||
|
||||
spin_unlock_irq(&port->port_lock);
|
||||
|
||||
/*
|
||||
* portmaster's mutex still protects from simultaneous open(),
|
||||
* and close() can't happen, yet.
|
||||
*/
|
||||
|
||||
status = kfifo_alloc(&port->port_write_buf,
|
||||
WRITE_BUF_SIZE, GFP_KERNEL);
|
||||
spin_lock_irq(&port->port_lock);
|
||||
|
||||
if (status) {
|
||||
pr_debug("gs_open: ttyGS%d (%p,%p) no buffer\n",
|
||||
port->port_num, tty, file);
|
||||
port->openclose = false;
|
||||
goto exit_unlock_port;
|
||||
port_num, tty, file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock_irq(&port->port_lock);
|
||||
}
|
||||
|
||||
/* REVISIT if REMOVED (ports[].port NULL), abort the open
|
||||
* to let rmmod work faster (but this way isn't wrong).
|
||||
*/
|
||||
|
||||
/* REVISIT maybe wait for "carrier detect" */
|
||||
/* already open? Great. */
|
||||
if (port->port.count++)
|
||||
goto exit_unlock_port;
|
||||
|
||||
tty->driver_data = port;
|
||||
port->port.tty = tty;
|
||||
|
||||
port->port.count = 1;
|
||||
port->openclose = false;
|
||||
|
||||
/* if connected, start the I/O stream */
|
||||
if (port->port_usb) {
|
||||
struct gserial *gser = port->port_usb;
|
||||
@ -675,20 +639,21 @@ static int gs_open(struct tty_struct *tty, struct file *file)
|
||||
|
||||
pr_debug("gs_open: ttyGS%d (%p,%p)\n", port->port_num, tty, file);
|
||||
|
||||
status = 0;
|
||||
|
||||
exit_unlock_port:
|
||||
spin_unlock_irq(&port->port_lock);
|
||||
out:
|
||||
mutex_unlock(&ports[port_num].lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int gs_writes_finished(struct gs_port *p)
|
||||
static int gs_close_flush_done(struct gs_port *p)
|
||||
{
|
||||
int cond;
|
||||
|
||||
/* return true on disconnect or empty buffer */
|
||||
/* return true on disconnect or empty buffer or if raced with open() */
|
||||
spin_lock_irq(&p->port_lock);
|
||||
cond = (p->port_usb == NULL) || !kfifo_len(&p->port_write_buf);
|
||||
cond = p->port_usb == NULL || !kfifo_len(&p->port_write_buf) ||
|
||||
p->port.count > 1;
|
||||
spin_unlock_irq(&p->port_lock);
|
||||
|
||||
return cond;
|
||||
@ -702,6 +667,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
|
||||
spin_lock_irq(&port->port_lock);
|
||||
|
||||
if (port->port.count != 1) {
|
||||
raced_with_open:
|
||||
if (port->port.count == 0)
|
||||
WARN_ON(1);
|
||||
else
|
||||
@ -711,12 +677,6 @@ static void gs_close(struct tty_struct *tty, struct file *file)
|
||||
|
||||
pr_debug("gs_close: ttyGS%d (%p,%p) ...\n", port->port_num, tty, file);
|
||||
|
||||
/* mark port as closing but in use; we can drop port lock
|
||||
* and sleep if necessary
|
||||
*/
|
||||
port->openclose = true;
|
||||
port->port.count = 0;
|
||||
|
||||
gser = port->port_usb;
|
||||
if (gser && gser->disconnect)
|
||||
gser->disconnect(gser);
|
||||
@ -727,9 +687,13 @@ static void gs_close(struct tty_struct *tty, struct file *file)
|
||||
if (kfifo_len(&port->port_write_buf) > 0 && gser) {
|
||||
spin_unlock_irq(&port->port_lock);
|
||||
wait_event_interruptible_timeout(port->drain_wait,
|
||||
gs_writes_finished(port),
|
||||
gs_close_flush_done(port),
|
||||
GS_CLOSE_TIMEOUT * HZ);
|
||||
spin_lock_irq(&port->port_lock);
|
||||
|
||||
if (port->port.count != 1)
|
||||
goto raced_with_open;
|
||||
|
||||
gser = port->port_usb;
|
||||
}
|
||||
|
||||
@ -742,10 +706,9 @@ static void gs_close(struct tty_struct *tty, struct file *file)
|
||||
else
|
||||
kfifo_reset(&port->port_write_buf);
|
||||
|
||||
port->port.count = 0;
|
||||
port->port.tty = NULL;
|
||||
|
||||
port->openclose = false;
|
||||
|
||||
pr_debug("gs_close: ttyGS%d (%p,%p) done!\n",
|
||||
port->port_num, tty, file);
|
||||
|
||||
@ -889,36 +852,9 @@ static struct tty_driver *gs_tty_driver;
|
||||
|
||||
#ifdef CONFIG_U_SERIAL_CONSOLE
|
||||
|
||||
static struct gscons_info gscons_info;
|
||||
static struct console gserial_cons;
|
||||
|
||||
static struct usb_request *gs_request_new(struct usb_ep *ep)
|
||||
static void gs_console_complete_out(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
struct usb_request *req = usb_ep_alloc_request(ep, GFP_ATOMIC);
|
||||
if (!req)
|
||||
return NULL;
|
||||
|
||||
req->buf = kmalloc(ep->maxpacket, GFP_ATOMIC);
|
||||
if (!req->buf) {
|
||||
usb_ep_free_request(ep, req);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
static void gs_request_free(struct usb_request *req, struct usb_ep *ep)
|
||||
{
|
||||
if (!req)
|
||||
return;
|
||||
|
||||
kfree(req->buf);
|
||||
usb_ep_free_request(ep, req);
|
||||
}
|
||||
|
||||
static void gs_complete_out(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
struct gscons_info *info = &gscons_info;
|
||||
struct gs_console *cons = req->context;
|
||||
|
||||
switch (req->status) {
|
||||
default:
|
||||
@ -927,12 +863,12 @@ static void gs_complete_out(struct usb_ep *ep, struct usb_request *req)
|
||||
/* fall through */
|
||||
case 0:
|
||||
/* normal completion */
|
||||
spin_lock(&info->con_lock);
|
||||
info->req_busy = 0;
|
||||
spin_unlock(&info->con_lock);
|
||||
|
||||
wake_up_process(info->console_thread);
|
||||
spin_lock(&cons->lock);
|
||||
req->length = 0;
|
||||
schedule_work(&cons->work);
|
||||
spin_unlock(&cons->lock);
|
||||
break;
|
||||
case -ECONNRESET:
|
||||
case -ESHUTDOWN:
|
||||
/* disconnect */
|
||||
pr_vdebug("%s: %s shutdown\n", __func__, ep->name);
|
||||
@ -940,190 +876,250 @@ static void gs_complete_out(struct usb_ep *ep, struct usb_request *req)
|
||||
}
|
||||
}
|
||||
|
||||
static int gs_console_connect(int port_num)
|
||||
static void __gs_console_push(struct gs_console *cons)
|
||||
{
|
||||
struct gscons_info *info = &gscons_info;
|
||||
struct gs_port *port;
|
||||
struct usb_request *req = cons->req;
|
||||
struct usb_ep *ep;
|
||||
size_t size;
|
||||
|
||||
if (port_num != gserial_cons.index) {
|
||||
pr_err("%s: port num [%d] is not support console\n",
|
||||
__func__, port_num);
|
||||
return -ENXIO;
|
||||
if (!req)
|
||||
return; /* disconnected */
|
||||
|
||||
if (req->length)
|
||||
return; /* busy */
|
||||
|
||||
ep = cons->console.data;
|
||||
size = kfifo_out(&cons->buf, req->buf, ep->maxpacket);
|
||||
if (!size)
|
||||
return;
|
||||
|
||||
if (cons->missed && ep->maxpacket >= 64) {
|
||||
char buf[64];
|
||||
size_t len;
|
||||
|
||||
len = sprintf(buf, "\n[missed %zu bytes]\n", cons->missed);
|
||||
kfifo_in(&cons->buf, buf, len);
|
||||
cons->missed = 0;
|
||||
}
|
||||
|
||||
port = ports[port_num].port;
|
||||
ep = port->port_usb->in;
|
||||
if (!info->console_req) {
|
||||
info->console_req = gs_request_new(ep);
|
||||
if (!info->console_req)
|
||||
return -ENOMEM;
|
||||
info->console_req->complete = gs_complete_out;
|
||||
}
|
||||
|
||||
info->port = port;
|
||||
spin_lock(&info->con_lock);
|
||||
info->req_busy = 0;
|
||||
spin_unlock(&info->con_lock);
|
||||
pr_vdebug("port[%d] console connect!\n", port_num);
|
||||
return 0;
|
||||
req->length = size;
|
||||
if (usb_ep_queue(ep, req, GFP_ATOMIC))
|
||||
req->length = 0;
|
||||
}
|
||||
|
||||
static void gs_console_disconnect(struct usb_ep *ep)
|
||||
static void gs_console_work(struct work_struct *work)
|
||||
{
|
||||
struct gscons_info *info = &gscons_info;
|
||||
struct usb_request *req = info->console_req;
|
||||
struct gs_console *cons = container_of(work, struct gs_console, work);
|
||||
|
||||
gs_request_free(req, ep);
|
||||
info->console_req = NULL;
|
||||
}
|
||||
spin_lock_irq(&cons->lock);
|
||||
|
||||
static int gs_console_thread(void *data)
|
||||
{
|
||||
struct gscons_info *info = &gscons_info;
|
||||
struct gs_port *port;
|
||||
struct usb_request *req;
|
||||
struct usb_ep *ep;
|
||||
int xfer, ret, count, size;
|
||||
__gs_console_push(cons);
|
||||
|
||||
do {
|
||||
port = info->port;
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (!port || !port->port_usb
|
||||
|| !port->port_usb->in || !info->console_req)
|
||||
goto sched;
|
||||
|
||||
req = info->console_req;
|
||||
ep = port->port_usb->in;
|
||||
|
||||
spin_lock_irq(&info->con_lock);
|
||||
count = kfifo_len(&info->con_buf);
|
||||
size = ep->maxpacket;
|
||||
|
||||
if (count > 0 && !info->req_busy) {
|
||||
set_current_state(TASK_RUNNING);
|
||||
if (count < size)
|
||||
size = count;
|
||||
|
||||
xfer = kfifo_out(&info->con_buf, req->buf, size);
|
||||
req->length = xfer;
|
||||
|
||||
spin_unlock(&info->con_lock);
|
||||
ret = usb_ep_queue(ep, req, GFP_ATOMIC);
|
||||
spin_lock(&info->con_lock);
|
||||
if (ret < 0)
|
||||
info->req_busy = 0;
|
||||
else
|
||||
info->req_busy = 1;
|
||||
|
||||
spin_unlock_irq(&info->con_lock);
|
||||
} else {
|
||||
spin_unlock_irq(&info->con_lock);
|
||||
sched:
|
||||
if (kthread_should_stop()) {
|
||||
set_current_state(TASK_RUNNING);
|
||||
break;
|
||||
}
|
||||
schedule();
|
||||
}
|
||||
} while (1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gs_console_setup(struct console *co, char *options)
|
||||
{
|
||||
struct gscons_info *info = &gscons_info;
|
||||
int status;
|
||||
|
||||
info->port = NULL;
|
||||
info->console_req = NULL;
|
||||
info->req_busy = 0;
|
||||
spin_lock_init(&info->con_lock);
|
||||
|
||||
status = kfifo_alloc(&info->con_buf, GS_CONSOLE_BUF_SIZE, GFP_KERNEL);
|
||||
if (status) {
|
||||
pr_err("%s: allocate console buffer failed\n", __func__);
|
||||
return status;
|
||||
}
|
||||
|
||||
info->console_thread = kthread_create(gs_console_thread,
|
||||
co, "gs_console");
|
||||
if (IS_ERR(info->console_thread)) {
|
||||
pr_err("%s: cannot create console thread\n", __func__);
|
||||
kfifo_free(&info->con_buf);
|
||||
return PTR_ERR(info->console_thread);
|
||||
}
|
||||
wake_up_process(info->console_thread);
|
||||
|
||||
return 0;
|
||||
spin_unlock_irq(&cons->lock);
|
||||
}
|
||||
|
||||
static void gs_console_write(struct console *co,
|
||||
const char *buf, unsigned count)
|
||||
{
|
||||
struct gscons_info *info = &gscons_info;
|
||||
struct gs_console *cons = container_of(co, struct gs_console, console);
|
||||
unsigned long flags;
|
||||
size_t n;
|
||||
|
||||
spin_lock_irqsave(&info->con_lock, flags);
|
||||
kfifo_in(&info->con_buf, buf, count);
|
||||
spin_unlock_irqrestore(&info->con_lock, flags);
|
||||
spin_lock_irqsave(&cons->lock, flags);
|
||||
|
||||
wake_up_process(info->console_thread);
|
||||
n = kfifo_in(&cons->buf, buf, count);
|
||||
if (n < count)
|
||||
cons->missed += count - n;
|
||||
|
||||
if (cons->req && !cons->req->length)
|
||||
schedule_work(&cons->work);
|
||||
|
||||
spin_unlock_irqrestore(&cons->lock, flags);
|
||||
}
|
||||
|
||||
static struct tty_driver *gs_console_device(struct console *co, int *index)
|
||||
{
|
||||
struct tty_driver **p = (struct tty_driver **)co->data;
|
||||
|
||||
if (!*p)
|
||||
return NULL;
|
||||
|
||||
*index = co->index;
|
||||
return *p;
|
||||
return gs_tty_driver;
|
||||
}
|
||||
|
||||
static struct console gserial_cons = {
|
||||
.name = "ttyGS",
|
||||
.write = gs_console_write,
|
||||
.device = gs_console_device,
|
||||
.setup = gs_console_setup,
|
||||
.flags = CON_PRINTBUFFER,
|
||||
.index = -1,
|
||||
.data = &gs_tty_driver,
|
||||
};
|
||||
|
||||
static void gserial_console_init(void)
|
||||
static int gs_console_connect(struct gs_port *port)
|
||||
{
|
||||
register_console(&gserial_cons);
|
||||
struct gs_console *cons = port->console;
|
||||
struct usb_request *req;
|
||||
struct usb_ep *ep;
|
||||
|
||||
if (!cons)
|
||||
return 0;
|
||||
|
||||
ep = port->port_usb->in;
|
||||
req = gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
req->complete = gs_console_complete_out;
|
||||
req->context = cons;
|
||||
req->length = 0;
|
||||
|
||||
spin_lock(&cons->lock);
|
||||
cons->req = req;
|
||||
cons->console.data = ep;
|
||||
spin_unlock(&cons->lock);
|
||||
|
||||
pr_debug("ttyGS%d: console connected!\n", port->port_num);
|
||||
|
||||
schedule_work(&cons->work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gserial_console_exit(void)
|
||||
static void gs_console_disconnect(struct gs_port *port)
|
||||
{
|
||||
struct gscons_info *info = &gscons_info;
|
||||
struct gs_console *cons = port->console;
|
||||
struct usb_request *req;
|
||||
struct usb_ep *ep;
|
||||
|
||||
unregister_console(&gserial_cons);
|
||||
if (!IS_ERR_OR_NULL(info->console_thread))
|
||||
kthread_stop(info->console_thread);
|
||||
kfifo_free(&info->con_buf);
|
||||
if (!cons)
|
||||
return;
|
||||
|
||||
spin_lock(&cons->lock);
|
||||
|
||||
req = cons->req;
|
||||
ep = cons->console.data;
|
||||
cons->req = NULL;
|
||||
|
||||
spin_unlock(&cons->lock);
|
||||
|
||||
if (!req)
|
||||
return;
|
||||
|
||||
usb_ep_dequeue(ep, req);
|
||||
gs_free_req(ep, req);
|
||||
}
|
||||
|
||||
static int gs_console_init(struct gs_port *port)
|
||||
{
|
||||
struct gs_console *cons;
|
||||
int err;
|
||||
|
||||
if (port->console)
|
||||
return 0;
|
||||
|
||||
cons = kzalloc(sizeof(*port->console), GFP_KERNEL);
|
||||
if (!cons)
|
||||
return -ENOMEM;
|
||||
|
||||
strcpy(cons->console.name, "ttyGS");
|
||||
cons->console.write = gs_console_write;
|
||||
cons->console.device = gs_console_device;
|
||||
cons->console.flags = CON_PRINTBUFFER;
|
||||
cons->console.index = port->port_num;
|
||||
|
||||
INIT_WORK(&cons->work, gs_console_work);
|
||||
spin_lock_init(&cons->lock);
|
||||
|
||||
err = kfifo_alloc(&cons->buf, GS_CONSOLE_BUF_SIZE, GFP_KERNEL);
|
||||
if (err) {
|
||||
pr_err("ttyGS%d: allocate console buffer failed\n", port->port_num);
|
||||
kfree(cons);
|
||||
return err;
|
||||
}
|
||||
|
||||
port->console = cons;
|
||||
register_console(&cons->console);
|
||||
|
||||
spin_lock_irq(&port->port_lock);
|
||||
if (port->port_usb)
|
||||
gs_console_connect(port);
|
||||
spin_unlock_irq(&port->port_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gs_console_exit(struct gs_port *port)
|
||||
{
|
||||
struct gs_console *cons = port->console;
|
||||
|
||||
if (!cons)
|
||||
return;
|
||||
|
||||
unregister_console(&cons->console);
|
||||
|
||||
spin_lock_irq(&port->port_lock);
|
||||
if (cons->req)
|
||||
gs_console_disconnect(port);
|
||||
spin_unlock_irq(&port->port_lock);
|
||||
|
||||
cancel_work_sync(&cons->work);
|
||||
kfifo_free(&cons->buf);
|
||||
kfree(cons);
|
||||
port->console = NULL;
|
||||
}
|
||||
|
||||
ssize_t gserial_set_console(unsigned char port_num, const char *page, size_t count)
|
||||
{
|
||||
struct gs_port *port;
|
||||
bool enable;
|
||||
int ret;
|
||||
|
||||
ret = strtobool(page, &enable);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&ports[port_num].lock);
|
||||
port = ports[port_num].port;
|
||||
|
||||
if (WARN_ON(port == NULL)) {
|
||||
ret = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (enable)
|
||||
ret = gs_console_init(port);
|
||||
else
|
||||
gs_console_exit(port);
|
||||
out:
|
||||
mutex_unlock(&ports[port_num].lock);
|
||||
|
||||
return ret < 0 ? ret : count;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gserial_set_console);
|
||||
|
||||
ssize_t gserial_get_console(unsigned char port_num, char *page)
|
||||
{
|
||||
struct gs_port *port;
|
||||
ssize_t ret;
|
||||
|
||||
mutex_lock(&ports[port_num].lock);
|
||||
port = ports[port_num].port;
|
||||
|
||||
if (WARN_ON(port == NULL))
|
||||
ret = -ENXIO;
|
||||
else
|
||||
ret = sprintf(page, "%u\n", !!port->console);
|
||||
|
||||
mutex_unlock(&ports[port_num].lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gserial_get_console);
|
||||
|
||||
#else
|
||||
|
||||
static int gs_console_connect(int port_num)
|
||||
static int gs_console_connect(struct gs_port *port)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gs_console_disconnect(struct usb_ep *ep)
|
||||
static void gs_console_disconnect(struct gs_port *port)
|
||||
{
|
||||
}
|
||||
|
||||
static void gserial_console_init(void)
|
||||
static int gs_console_init(struct gs_port *port)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static void gserial_console_exit(void)
|
||||
static void gs_console_exit(struct gs_port *port)
|
||||
{
|
||||
}
|
||||
|
||||
@ -1172,8 +1168,9 @@ static int gs_closed(struct gs_port *port)
|
||||
int cond;
|
||||
|
||||
spin_lock_irq(&port->port_lock);
|
||||
cond = (port->port.count == 0) && !port->openclose;
|
||||
cond = port->port.count == 0;
|
||||
spin_unlock_irq(&port->port_lock);
|
||||
|
||||
return cond;
|
||||
}
|
||||
|
||||
@ -1197,18 +1194,19 @@ void gserial_free_line(unsigned char port_num)
|
||||
return;
|
||||
}
|
||||
port = ports[port_num].port;
|
||||
gs_console_exit(port);
|
||||
ports[port_num].port = NULL;
|
||||
mutex_unlock(&ports[port_num].lock);
|
||||
|
||||
gserial_free_port(port);
|
||||
tty_unregister_device(gs_tty_driver, port_num);
|
||||
gserial_console_exit();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gserial_free_line);
|
||||
|
||||
int gserial_alloc_line(unsigned char *line_num)
|
||||
int gserial_alloc_line_no_console(unsigned char *line_num)
|
||||
{
|
||||
struct usb_cdc_line_coding coding;
|
||||
struct gs_port *port;
|
||||
struct device *tty_dev;
|
||||
int ret;
|
||||
int port_num;
|
||||
@ -1231,24 +1229,35 @@ int gserial_alloc_line(unsigned char *line_num)
|
||||
|
||||
/* ... and sysfs class devices, so mdev/udev make /dev/ttyGS* */
|
||||
|
||||
tty_dev = tty_port_register_device(&ports[port_num].port->port,
|
||||
port = ports[port_num].port;
|
||||
tty_dev = tty_port_register_device(&port->port,
|
||||
gs_tty_driver, port_num, NULL);
|
||||
if (IS_ERR(tty_dev)) {
|
||||
struct gs_port *port;
|
||||
pr_err("%s: failed to register tty for port %d, err %ld\n",
|
||||
__func__, port_num, PTR_ERR(tty_dev));
|
||||
|
||||
ret = PTR_ERR(tty_dev);
|
||||
port = ports[port_num].port;
|
||||
mutex_lock(&ports[port_num].lock);
|
||||
ports[port_num].port = NULL;
|
||||
mutex_unlock(&ports[port_num].lock);
|
||||
gserial_free_port(port);
|
||||
goto err;
|
||||
}
|
||||
*line_num = port_num;
|
||||
gserial_console_init();
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gserial_alloc_line_no_console);
|
||||
|
||||
int gserial_alloc_line(unsigned char *line_num)
|
||||
{
|
||||
int ret = gserial_alloc_line_no_console(line_num);
|
||||
|
||||
if (!ret && !*line_num)
|
||||
gs_console_init(ports[*line_num].port);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gserial_alloc_line);
|
||||
|
||||
/**
|
||||
@ -1327,7 +1336,7 @@ int gserial_connect(struct gserial *gser, u8 port_num)
|
||||
gser->disconnect(gser);
|
||||
}
|
||||
|
||||
status = gs_console_connect(port_num);
|
||||
status = gs_console_connect(port);
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
|
||||
return status;
|
||||
@ -1359,12 +1368,14 @@ void gserial_disconnect(struct gserial *gser)
|
||||
/* tell the TTY glue not to do I/O here any more */
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
|
||||
gs_console_disconnect(port);
|
||||
|
||||
/* REVISIT as above: how best to track this? */
|
||||
port->port_line_coding = gser->port_line_coding;
|
||||
|
||||
port->port_usb = NULL;
|
||||
gser->ioport = NULL;
|
||||
if (port->port.count > 0 || port->openclose) {
|
||||
if (port->port.count > 0) {
|
||||
wake_up_interruptible(&port->drain_wait);
|
||||
if (port->port.tty)
|
||||
tty_hangup(port->port.tty);
|
||||
@ -1377,7 +1388,7 @@ void gserial_disconnect(struct gserial *gser)
|
||||
|
||||
/* finally, free any unused/unusable I/O buffers */
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
if (port->port.count == 0 && !port->openclose)
|
||||
if (port->port.count == 0)
|
||||
kfifo_free(&port->port_write_buf);
|
||||
gs_free_requests(gser->out, &port->read_pool, NULL);
|
||||
gs_free_requests(gser->out, &port->read_queue, NULL);
|
||||
@ -1386,7 +1397,6 @@ void gserial_disconnect(struct gserial *gser)
|
||||
port->read_allocated = port->read_started =
|
||||
port->write_allocated = port->write_started = 0;
|
||||
|
||||
gs_console_disconnect(gser->in);
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gserial_disconnect);
|
||||
|
@ -54,9 +54,17 @@ struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags);
|
||||
void gs_free_req(struct usb_ep *, struct usb_request *req);
|
||||
|
||||
/* management of individual TTY ports */
|
||||
int gserial_alloc_line_no_console(unsigned char *port_line);
|
||||
int gserial_alloc_line(unsigned char *port_line);
|
||||
void gserial_free_line(unsigned char port_line);
|
||||
|
||||
#ifdef CONFIG_U_SERIAL_CONSOLE
|
||||
|
||||
ssize_t gserial_set_console(unsigned char port_num, const char *page, size_t count);
|
||||
ssize_t gserial_get_console(unsigned char port_num, char *page);
|
||||
|
||||
#endif /* CONFIG_U_SERIAL_CONSOLE */
|
||||
|
||||
/* connect/disconnect is handled by individual functions */
|
||||
int gserial_connect(struct gserial *, u8 port_num);
|
||||
void gserial_disconnect(struct gserial *);
|
||||
|
@ -149,21 +149,21 @@ config USB_ETH_RNDIS
|
||||
is given in comments found in that info file.
|
||||
|
||||
config USB_ETH_EEM
|
||||
bool "Ethernet Emulation Model (EEM) support"
|
||||
depends on USB_ETH
|
||||
bool "Ethernet Emulation Model (EEM) support"
|
||||
depends on USB_ETH
|
||||
select USB_LIBCOMPOSITE
|
||||
select USB_F_EEM
|
||||
help
|
||||
CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM
|
||||
and therefore can be supported by more hardware. Technically ECM and
|
||||
EEM are designed for different applications. The ECM model extends
|
||||
the network interface to the target (e.g. a USB cable modem), and the
|
||||
EEM model is for mobile devices to communicate with hosts using
|
||||
ethernet over USB. For Linux gadgets, however, the interface with
|
||||
the host is the same (a usbX device), so the differences are minimal.
|
||||
help
|
||||
CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM
|
||||
and therefore can be supported by more hardware. Technically ECM and
|
||||
EEM are designed for different applications. The ECM model extends
|
||||
the network interface to the target (e.g. a USB cable modem), and the
|
||||
EEM model is for mobile devices to communicate with hosts using
|
||||
ethernet over USB. For Linux gadgets, however, the interface with
|
||||
the host is the same (a usbX device), so the differences are minimal.
|
||||
|
||||
If you say "y" here, the Ethernet gadget driver will use the EEM
|
||||
protocol rather than ECM. If unsure, say "n".
|
||||
If you say "y" here, the Ethernet gadget driver will use the EEM
|
||||
protocol rather than ECM. If unsure, say "n".
|
||||
|
||||
config USB_G_NCM
|
||||
tristate "Network Control Model (NCM) support"
|
||||
|
@ -105,7 +105,6 @@ static struct usb_function *f_msg;
|
||||
*/
|
||||
static int acm_ms_do_config(struct usb_configuration *c)
|
||||
{
|
||||
struct fsg_opts *opts;
|
||||
int status;
|
||||
|
||||
if (gadget_is_otg(c->cdev->gadget)) {
|
||||
@ -113,8 +112,6 @@ static int acm_ms_do_config(struct usb_configuration *c)
|
||||
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
|
||||
opts = fsg_opts_from_func_inst(fi_msg);
|
||||
|
||||
f_acm = usb_get_function(f_acm_inst);
|
||||
if (IS_ERR(f_acm))
|
||||
return PTR_ERR(f_acm);
|
||||
|
@ -105,7 +105,6 @@ FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
|
||||
|
||||
static int msg_do_config(struct usb_configuration *c)
|
||||
{
|
||||
struct fsg_opts *opts;
|
||||
int ret;
|
||||
|
||||
if (gadget_is_otg(c->cdev->gadget)) {
|
||||
@ -113,8 +112,6 @@ static int msg_do_config(struct usb_configuration *c)
|
||||
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
|
||||
opts = fsg_opts_from_func_inst(fi_msg);
|
||||
|
||||
f_msg = usb_get_function(fi_msg);
|
||||
if (IS_ERR(f_msg))
|
||||
return PTR_ERR(f_msg);
|
||||
|
@ -97,6 +97,36 @@ static unsigned n_ports = 1;
|
||||
module_param(n_ports, uint, 0);
|
||||
MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
|
||||
|
||||
static bool enable = true;
|
||||
|
||||
static int switch_gserial_enable(bool do_enable);
|
||||
|
||||
static int enable_set(const char *s, const struct kernel_param *kp)
|
||||
{
|
||||
bool do_enable;
|
||||
int ret;
|
||||
|
||||
if (!s) /* called for no-arg enable == default */
|
||||
return 0;
|
||||
|
||||
ret = strtobool(s, &do_enable);
|
||||
if (ret || enable == do_enable)
|
||||
return ret;
|
||||
|
||||
ret = switch_gserial_enable(do_enable);
|
||||
if (!ret)
|
||||
enable = do_enable;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct kernel_param_ops enable_ops = {
|
||||
.set = enable_set,
|
||||
.get = param_get_bool,
|
||||
};
|
||||
|
||||
module_param_cb(enable, &enable_ops, &enable, 0644);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct usb_configuration serial_config_driver = {
|
||||
@ -240,6 +270,19 @@ static struct usb_composite_driver gserial_driver = {
|
||||
.unbind = gs_unbind,
|
||||
};
|
||||
|
||||
static int switch_gserial_enable(bool do_enable)
|
||||
{
|
||||
if (!serial_config_driver.label)
|
||||
/* init() was not called, yet */
|
||||
return 0;
|
||||
|
||||
if (do_enable)
|
||||
return usb_composite_probe(&gserial_driver);
|
||||
|
||||
usb_composite_unregister(&gserial_driver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
/* We *could* export two configs; that'd be much cleaner...
|
||||
@ -266,12 +309,16 @@ static int __init init(void)
|
||||
}
|
||||
strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label;
|
||||
|
||||
if (!enable)
|
||||
return 0;
|
||||
|
||||
return usb_composite_probe(&gserial_driver);
|
||||
}
|
||||
module_init(init);
|
||||
|
||||
static void __exit cleanup(void)
|
||||
{
|
||||
usb_composite_unregister(&gserial_driver);
|
||||
if (enable)
|
||||
usb_composite_unregister(&gserial_driver);
|
||||
}
|
||||
module_exit(cleanup);
|
||||
|
@ -120,10 +120,10 @@ config USB_FOTG210_UDC
|
||||
dynamically linked module called "fotg210_udc".
|
||||
|
||||
config USB_GR_UDC
|
||||
tristate "Aeroflex Gaisler GRUSBDC USB Peripheral Controller Driver"
|
||||
depends on HAS_DMA
|
||||
help
|
||||
Select this to support Aeroflex Gaisler GRUSBDC cores from the GRLIB
|
||||
tristate "Aeroflex Gaisler GRUSBDC USB Peripheral Controller Driver"
|
||||
depends on HAS_DMA
|
||||
help
|
||||
Select this to support Aeroflex Gaisler GRUSBDC cores from the GRLIB
|
||||
VHDL IP core library.
|
||||
|
||||
config USB_OMAP
|
||||
@ -441,6 +441,17 @@ config USB_GADGET_XILINX
|
||||
dynamically linked module called "udc-xilinx" and force all
|
||||
gadget drivers to also be dynamically linked.
|
||||
|
||||
config USB_TEGRA_XUDC
|
||||
tristate "NVIDIA Tegra Superspeed USB 3.0 Device Controller"
|
||||
depends on ARCH_TEGRA || COMPILE_TEST
|
||||
depends on PHY_TEGRA_XUSB
|
||||
help
|
||||
Enables NVIDIA Tegra USB 3.0 device mode controller driver.
|
||||
|
||||
Say "y" to link the driver statically, or "m" to build a
|
||||
dynamically linked module called "tegra_xudc" and force all
|
||||
gadget drivers to also be dynamically linked.
|
||||
|
||||
source "drivers/usb/gadget/udc/aspeed-vhub/Kconfig"
|
||||
|
||||
#
|
||||
|
@ -24,6 +24,7 @@ obj-$(CONFIG_USB_BCM63XX_UDC) += bcm63xx_udc.o
|
||||
obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
|
||||
fsl_usb2_udc-y := fsl_udc_core.o
|
||||
fsl_usb2_udc-$(CONFIG_ARCH_MXC) += fsl_mxc_udc.o
|
||||
obj-$(CONFIG_USB_TEGRA_XUDC) += tegra-xudc.o
|
||||
obj-$(CONFIG_USB_M66592) += m66592-udc.o
|
||||
obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o
|
||||
obj-$(CONFIG_USB_RENESAS_USB3) += renesas_usb3.o
|
||||
|
@ -1808,7 +1808,6 @@ static int at91udc_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct at91_udc *udc;
|
||||
int retval;
|
||||
struct resource *res;
|
||||
struct at91_ep *ep;
|
||||
int i;
|
||||
|
||||
@ -1839,8 +1838,7 @@ static int at91udc_probe(struct platform_device *pdev)
|
||||
ep->is_pingpong = 1;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
udc->udp_baseaddr = devm_ioremap_resource(dev, res);
|
||||
udc->udp_baseaddr = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(udc->udp_baseaddr))
|
||||
return PTR_ERR(udc->udp_baseaddr);
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/delay.h>
|
||||
@ -226,7 +227,7 @@ static void usba_init_debugfs(struct usba_udc *udc)
|
||||
struct dentry *root;
|
||||
struct resource *regs_resource;
|
||||
|
||||
root = debugfs_create_dir(udc->gadget.name, NULL);
|
||||
root = debugfs_create_dir(udc->gadget.name, usb_debug_root);
|
||||
udc->debugfs_root = root;
|
||||
|
||||
regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM,
|
||||
|
@ -2248,7 +2248,7 @@ static void bcm63xx_udc_init_debugfs(struct bcm63xx_udc *udc)
|
||||
if (!IS_ENABLED(CONFIG_USB_GADGET_DEBUG_FS))
|
||||
return;
|
||||
|
||||
root = debugfs_create_dir(udc->gadget.name, NULL);
|
||||
root = debugfs_create_dir(udc->gadget.name, usb_debug_root);
|
||||
udc->debugfs_root = root;
|
||||
|
||||
debugfs_create_file("usbd", 0400, root, udc, &bcm63xx_usbd_dbg_fops);
|
||||
@ -2282,7 +2282,6 @@ static int bcm63xx_udc_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct bcm63xx_usbd_platform_data *pd = dev_get_platdata(dev);
|
||||
struct bcm63xx_udc *udc;
|
||||
struct resource *res;
|
||||
int rc = -ENOMEM, i, irq;
|
||||
|
||||
udc = devm_kzalloc(dev, sizeof(*udc), GFP_KERNEL);
|
||||
@ -2298,13 +2297,11 @@ static int bcm63xx_udc_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
udc->usbd_regs = devm_ioremap_resource(dev, res);
|
||||
udc->usbd_regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(udc->usbd_regs))
|
||||
return PTR_ERR(udc->usbd_regs);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
udc->iudma_regs = devm_ioremap_resource(dev, res);
|
||||
udc->iudma_regs = devm_platform_ioremap_resource(pdev, 1);
|
||||
if (IS_ERR(udc->iudma_regs))
|
||||
return PTR_ERR(udc->iudma_regs);
|
||||
|
||||
|
@ -480,7 +480,6 @@ static void bdc_phy_exit(struct bdc *bdc)
|
||||
static int bdc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bdc *bdc;
|
||||
struct resource *res;
|
||||
int ret = -ENOMEM;
|
||||
int irq;
|
||||
u32 temp;
|
||||
@ -508,8 +507,7 @@ static int bdc_probe(struct platform_device *pdev)
|
||||
|
||||
bdc->clk = clk;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
bdc->regs = devm_ioremap_resource(dev, res);
|
||||
bdc->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(bdc->regs)) {
|
||||
dev_err(dev, "ioremap error\n");
|
||||
return -ENOMEM;
|
||||
|
@ -195,7 +195,7 @@ static void handle_link_state_change(struct bdc *bdc, u32 uspc)
|
||||
break;
|
||||
case BDC_LINK_STATE_U0:
|
||||
if (bdc->devstatus & REMOTE_WAKEUP_ISSUED) {
|
||||
bdc->devstatus &= ~REMOTE_WAKEUP_ISSUED;
|
||||
bdc->devstatus &= ~REMOTE_WAKEUP_ISSUED;
|
||||
if (bdc->gadget.speed == USB_SPEED_SUPER) {
|
||||
bdc_function_wake_fh(bdc, 0);
|
||||
bdc->devstatus |= FUNC_WAKE_ISSUED;
|
||||
|
@ -1321,7 +1321,7 @@ static int dummy_perform_transfer(struct urb *urb, struct dummy_request *req,
|
||||
u32 this_sg;
|
||||
bool next_sg;
|
||||
|
||||
to_host = usb_pipein(urb->pipe);
|
||||
to_host = usb_urb_dir_in(urb);
|
||||
rbuf = req->req.buf + req->req.actual;
|
||||
|
||||
if (!urb->num_sgs) {
|
||||
@ -1409,7 +1409,7 @@ top:
|
||||
|
||||
/* FIXME update emulated data toggle too */
|
||||
|
||||
to_host = usb_pipein(urb->pipe);
|
||||
to_host = usb_urb_dir_in(urb);
|
||||
if (unlikely(len == 0))
|
||||
is_short = 1;
|
||||
else {
|
||||
@ -1830,7 +1830,7 @@ restart:
|
||||
|
||||
/* find the gadget's ep for this request (if configured) */
|
||||
address = usb_pipeendpoint (urb->pipe);
|
||||
if (usb_pipein(urb->pipe))
|
||||
if (usb_urb_dir_in(urb))
|
||||
address |= USB_DIR_IN;
|
||||
ep = find_endpoint(dum, address);
|
||||
if (!ep) {
|
||||
@ -2385,7 +2385,7 @@ static inline ssize_t show_urb(char *buf, size_t size, struct urb *urb)
|
||||
s = "?";
|
||||
break;
|
||||
} s; }),
|
||||
ep, ep ? (usb_pipein(urb->pipe) ? "in" : "out") : "",
|
||||
ep, ep ? (usb_urb_dir_in(urb) ? "in" : "out") : "",
|
||||
({ char *s; \
|
||||
switch (usb_pipetype(urb->pipe)) { \
|
||||
case PIPE_CONTROL: \
|
||||
@ -2725,7 +2725,7 @@ static struct platform_driver dummy_hcd_driver = {
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
#define MAX_NUM_UDC 2
|
||||
#define MAX_NUM_UDC 32
|
||||
static struct platform_device *the_udc_pdev[MAX_NUM_UDC];
|
||||
static struct platform_device *the_hcd_pdev[MAX_NUM_UDC];
|
||||
|
||||
|
@ -333,8 +333,8 @@ struct qe_udc {
|
||||
u32 resume_state; /* USB state to resume*/
|
||||
u32 usb_state; /* USB current state */
|
||||
u32 usb_next_state; /* USB next state */
|
||||
u32 ep0_state; /* Enpoint zero state */
|
||||
u32 ep0_dir; /* Enpoint zero direction: can be
|
||||
u32 ep0_state; /* Endpoint zero state */
|
||||
u32 ep0_dir; /* Endpoint zero direction: can be
|
||||
USB_DIR_IN or USB_DIR_OUT*/
|
||||
u32 usb_sof_count; /* SOF count */
|
||||
u32 errors; /* USB ERRORs count */
|
||||
|
@ -1052,10 +1052,11 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep)
|
||||
u32 bitmask;
|
||||
struct ep_queue_head *qh;
|
||||
|
||||
ep = container_of(_ep, struct fsl_ep, ep);
|
||||
if (!_ep || (!ep->ep.desc && ep_index(ep) != 0))
|
||||
if (!_ep || _ep->desc || !(_ep->desc->bEndpointAddress&0xF))
|
||||
return -ENODEV;
|
||||
|
||||
ep = container_of(_ep, struct fsl_ep, ep);
|
||||
|
||||
udc = (struct fsl_udc *)ep->udc;
|
||||
|
||||
if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
|
||||
@ -1208,7 +1209,7 @@ static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
|
||||
}
|
||||
|
||||
/* Change Data+ pullup status
|
||||
* this func is used by usb_gadget_connect/disconnet
|
||||
* this func is used by usb_gadget_connect/disconnect
|
||||
*/
|
||||
static int fsl_pullup(struct usb_gadget *gadget, int is_on)
|
||||
{
|
||||
@ -1595,14 +1596,13 @@ static int process_ep_req(struct fsl_udc *udc, int pipe,
|
||||
struct fsl_req *curr_req)
|
||||
{
|
||||
struct ep_td_struct *curr_td;
|
||||
int td_complete, actual, remaining_length, j, tmp;
|
||||
int actual, remaining_length, j, tmp;
|
||||
int status = 0;
|
||||
int errors = 0;
|
||||
struct ep_queue_head *curr_qh = &udc->ep_qh[pipe];
|
||||
int direction = pipe % 2;
|
||||
|
||||
curr_td = curr_req->head;
|
||||
td_complete = 0;
|
||||
actual = curr_req->req.length;
|
||||
|
||||
for (j = 0; j < curr_req->dtd_count; j++) {
|
||||
@ -1647,11 +1647,9 @@ static int process_ep_req(struct fsl_udc *udc, int pipe,
|
||||
status = -EPROTO;
|
||||
break;
|
||||
} else {
|
||||
td_complete++;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
td_complete++;
|
||||
VDBG("dTD transmitted successful");
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
@ -208,7 +209,7 @@ static void gr_dfs_create(struct gr_udc *dev)
|
||||
{
|
||||
const char *name = "gr_udc_state";
|
||||
|
||||
dev->dfs_root = debugfs_create_dir(dev_name(dev->dev), NULL);
|
||||
dev->dfs_root = debugfs_create_dir(dev_name(dev->dev), usb_debug_root);
|
||||
debugfs_create_file(name, 0444, dev->dfs_root, dev, &gr_dfs_fops);
|
||||
}
|
||||
|
||||
@ -2118,7 +2119,6 @@ static int gr_request_irq(struct gr_udc *dev, int irq)
|
||||
static int gr_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gr_udc *dev;
|
||||
struct resource *res;
|
||||
struct gr_regs __iomem *regs;
|
||||
int retval;
|
||||
u32 status;
|
||||
@ -2128,8 +2128,7 @@ static int gr_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
dev->dev = &pdev->dev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
regs = devm_ioremap_resource(dev->dev, res);
|
||||
regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(regs))
|
||||
return PTR_ERR(regs);
|
||||
|
||||
|
@ -3000,7 +3000,6 @@ static int lpc32xx_udc_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct lpc32xx_udc *udc;
|
||||
int retval, i;
|
||||
struct resource *res;
|
||||
dma_addr_t dma_handle;
|
||||
struct device_node *isp1301_node;
|
||||
|
||||
@ -3048,9 +3047,6 @@ static int lpc32xx_udc_probe(struct platform_device *pdev)
|
||||
* IORESOURCE_IRQ, USB device interrupt number
|
||||
* IORESOURCE_IRQ, USB transceiver interrupt number
|
||||
*/
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENXIO;
|
||||
|
||||
spin_lock_init(&udc->lock);
|
||||
|
||||
@ -3061,7 +3057,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev)
|
||||
return udc->udp_irq[i];
|
||||
}
|
||||
|
||||
udc->udp_baseaddr = devm_ioremap_resource(dev, res);
|
||||
udc->udp_baseaddr = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(udc->udp_baseaddr)) {
|
||||
dev_err(udc->dev, "IO map failure\n");
|
||||
return PTR_ERR(udc->udp_baseaddr);
|
||||
|
@ -138,7 +138,7 @@ struct mv_u3d_op_regs {
|
||||
u32 doorbell; /* doorbell register */
|
||||
};
|
||||
|
||||
/* control enpoint enable registers */
|
||||
/* control endpoint enable registers */
|
||||
struct epxcr {
|
||||
u32 epxoutcr0; /* ep out control 0 register */
|
||||
u32 epxoutcr1; /* ep out control 1 register */
|
||||
|
@ -1519,7 +1519,6 @@ static void pch_udc_free_dma_chain(struct pch_udc_dev *dev,
|
||||
td = phys_to_virt(addr);
|
||||
addr2 = (dma_addr_t)td->next;
|
||||
dma_pool_free(dev->data_requests, td, addr);
|
||||
td->next = 0x00;
|
||||
addr = addr2;
|
||||
}
|
||||
req->chain_len = 1;
|
||||
|
@ -2321,7 +2321,6 @@ static int pxa25x_udc_probe(struct platform_device *pdev)
|
||||
struct pxa25x_udc *dev = &memory;
|
||||
int retval, irq;
|
||||
u32 chiprev;
|
||||
struct resource *res;
|
||||
|
||||
pr_info("%s: version %s\n", driver_name, DRIVER_VERSION);
|
||||
|
||||
@ -2367,8 +2366,7 @@ static int pxa25x_udc_probe(struct platform_device *pdev)
|
||||
if (irq < 0)
|
||||
return -ENODEV;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
dev->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
dev->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(dev->regs))
|
||||
return PTR_ERR(dev->regs);
|
||||
|
||||
|
@ -207,7 +207,7 @@ static void pxa_init_debugfs(struct pxa_udc *udc)
|
||||
{
|
||||
struct dentry *root;
|
||||
|
||||
root = debugfs_create_dir(udc->gadget.name, NULL);
|
||||
root = debugfs_create_dir(udc->gadget.name, usb_debug_root);
|
||||
udc->debugfs_root = root;
|
||||
|
||||
debugfs_create_file("udcstate", 0400, root, udc, &state_dbg_fops);
|
||||
@ -2356,7 +2356,6 @@ MODULE_DEVICE_TABLE(of, udc_pxa_dt_ids);
|
||||
*/
|
||||
static int pxa_udc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *regs;
|
||||
struct pxa_udc *udc = &memory;
|
||||
int retval = 0, gpio;
|
||||
struct pxa2xx_udc_mach_info *mach = dev_get_platdata(&pdev->dev);
|
||||
@ -2378,8 +2377,7 @@ static int pxa_udc_probe(struct platform_device *pdev)
|
||||
udc->gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_ASIS);
|
||||
}
|
||||
|
||||
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
udc->regs = devm_ioremap_resource(&pdev->dev, regs);
|
||||
udc->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(udc->regs))
|
||||
return PTR_ERR(udc->regs);
|
||||
udc->irq = platform_get_irq(pdev, 0);
|
||||
|
@ -1838,7 +1838,7 @@ static int r8a66597_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
char clk_name[8];
|
||||
struct resource *res, *ires;
|
||||
struct resource *ires;
|
||||
int irq;
|
||||
void __iomem *reg = NULL;
|
||||
struct r8a66597 *r8a66597 = NULL;
|
||||
@ -1846,8 +1846,7 @@ static int r8a66597_probe(struct platform_device *pdev)
|
||||
int i;
|
||||
unsigned long irq_trigger;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
reg = devm_ioremap_resource(&pdev->dev, res);
|
||||
reg = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(reg))
|
||||
return PTR_ERR(reg);
|
||||
|
||||
|
@ -775,6 +775,18 @@ static void usb3_irq_epc_int_1_resume(struct renesas_usb3 *usb3)
|
||||
usb3_transition_to_default_state(usb3, false);
|
||||
}
|
||||
|
||||
static void usb3_irq_epc_int_1_suspend(struct renesas_usb3 *usb3)
|
||||
{
|
||||
usb3_disable_irq_1(usb3, USB_INT_1_B2_SPND);
|
||||
|
||||
if (usb3->gadget.speed != USB_SPEED_UNKNOWN &&
|
||||
usb3->gadget.state != USB_STATE_NOTATTACHED) {
|
||||
if (usb3->driver && usb3->driver->suspend)
|
||||
usb3->driver->suspend(&usb3->gadget);
|
||||
usb_gadget_set_state(&usb3->gadget, USB_STATE_SUSPENDED);
|
||||
}
|
||||
}
|
||||
|
||||
static void usb3_irq_epc_int_1_disable(struct renesas_usb3 *usb3)
|
||||
{
|
||||
usb3_stop_usb3_connection(usb3);
|
||||
@ -860,6 +872,9 @@ static void usb3_irq_epc_int_1(struct renesas_usb3 *usb3, u32 int_sta_1)
|
||||
if (int_sta_1 & USB_INT_1_B2_RSUM)
|
||||
usb3_irq_epc_int_1_resume(usb3);
|
||||
|
||||
if (int_sta_1 & USB_INT_1_B2_SPND)
|
||||
usb3_irq_epc_int_1_suspend(usb3);
|
||||
|
||||
if (int_sta_1 & USB_INT_1_SPEED)
|
||||
usb3_irq_epc_int_1_speed(usb3);
|
||||
|
||||
@ -2536,7 +2551,7 @@ static const struct file_operations renesas_usb3_b_device_fops = {
|
||||
static void renesas_usb3_debugfs_init(struct renesas_usb3 *usb3,
|
||||
struct device *dev)
|
||||
{
|
||||
usb3->dentry = debugfs_create_dir(dev_name(dev), NULL);
|
||||
usb3->dentry = debugfs_create_dir(dev_name(dev), usb_debug_root);
|
||||
|
||||
debugfs_create_file("b_device", 0644, usb3->dentry, usb3,
|
||||
&renesas_usb3_b_device_fops);
|
||||
@ -2733,7 +2748,6 @@ static struct usb_role_switch_desc renesas_usb3_role_switch_desc = {
|
||||
static int renesas_usb3_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct renesas_usb3 *usb3;
|
||||
struct resource *res;
|
||||
int irq, ret;
|
||||
const struct renesas_usb3_priv *priv;
|
||||
const struct soc_device_attribute *attr;
|
||||
@ -2752,8 +2766,7 @@ static int renesas_usb3_probe(struct platform_device *pdev)
|
||||
if (!usb3)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
usb3->reg = devm_ioremap_resource(&pdev->dev, res);
|
||||
usb3->reg = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(usb3->reg))
|
||||
return PTR_ERR(usb3->reg);
|
||||
|
||||
|
@ -1263,7 +1263,6 @@ static const struct usb_gadget_ops s3c_hsudc_gadget_ops = {
|
||||
static int s3c_hsudc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
struct s3c_hsudc *hsudc;
|
||||
struct s3c24xx_hsudc_platdata *pd = dev_get_platdata(&pdev->dev);
|
||||
int ret, i;
|
||||
@ -1290,9 +1289,7 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
|
||||
goto err_supplies;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
hsudc->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
hsudc->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(hsudc->regs)) {
|
||||
ret = PTR_ERR(hsudc->regs);
|
||||
goto err_res;
|
||||
|
@ -1978,7 +1978,8 @@ static int __init udc_init(void)
|
||||
|
||||
dprintk(DEBUG_NORMAL, "%s\n", gadget_name);
|
||||
|
||||
s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name, NULL);
|
||||
s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name,
|
||||
usb_debug_root);
|
||||
|
||||
retval = platform_driver_register(&udc_driver_24x0);
|
||||
if (retval)
|
||||
|
3810
drivers/usb/gadget/udc/tegra-xudc.c
Normal file
3810
drivers/usb/gadget/udc/tegra-xudc.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -38,9 +38,9 @@ config USB_XHCI_DBGCAP
|
||||
before enabling this option. If unsure, say 'N'.
|
||||
|
||||
config USB_XHCI_PCI
|
||||
tristate
|
||||
depends on USB_PCI
|
||||
default y
|
||||
tristate
|
||||
depends on USB_PCI
|
||||
default y
|
||||
|
||||
config USB_XHCI_PLATFORM
|
||||
tristate "Generic xHCI driver for a platform device"
|
||||
@ -220,12 +220,12 @@ config USB_EHCI_HCD_ORION
|
||||
Marvell PXA/MMP USB controller" for those.
|
||||
|
||||
config USB_EHCI_HCD_SPEAR
|
||||
tristate "Support for ST SPEAr on-chip EHCI USB controller"
|
||||
depends on USB_EHCI_HCD && PLAT_SPEAR
|
||||
default y
|
||||
---help---
|
||||
Enables support for the on-chip EHCI controller on
|
||||
ST SPEAr chips.
|
||||
tristate "Support for ST SPEAr on-chip EHCI USB controller"
|
||||
depends on USB_EHCI_HCD && PLAT_SPEAR
|
||||
default y
|
||||
---help---
|
||||
Enables support for the on-chip EHCI controller on
|
||||
ST SPEAr chips.
|
||||
|
||||
config USB_EHCI_HCD_STI
|
||||
tristate "Support for ST STiHxxx on-chip EHCI USB controller"
|
||||
@ -237,21 +237,21 @@ config USB_EHCI_HCD_STI
|
||||
STMicroelectronics consumer electronics SoC's.
|
||||
|
||||
config USB_EHCI_HCD_AT91
|
||||
tristate "Support for Atmel on-chip EHCI USB controller"
|
||||
depends on USB_EHCI_HCD && ARCH_AT91
|
||||
default y
|
||||
---help---
|
||||
Enables support for the on-chip EHCI controller on
|
||||
Atmel chips.
|
||||
tristate "Support for Atmel on-chip EHCI USB controller"
|
||||
depends on USB_EHCI_HCD && ARCH_AT91
|
||||
default y
|
||||
---help---
|
||||
Enables support for the on-chip EHCI controller on
|
||||
Atmel chips.
|
||||
|
||||
config USB_EHCI_TEGRA
|
||||
tristate "NVIDIA Tegra HCD support"
|
||||
depends on ARCH_TEGRA
|
||||
select USB_EHCI_ROOT_HUB_TT
|
||||
select USB_TEGRA_PHY
|
||||
help
|
||||
This driver enables support for the internal USB Host Controllers
|
||||
found in NVIDIA Tegra SoCs. The controllers are EHCI compliant.
|
||||
tristate "NVIDIA Tegra HCD support"
|
||||
depends on ARCH_TEGRA
|
||||
select USB_EHCI_ROOT_HUB_TT
|
||||
select USB_TEGRA_PHY
|
||||
help
|
||||
This driver enables support for the internal USB Host Controllers
|
||||
found in NVIDIA Tegra SoCs. The controllers are EHCI compliant.
|
||||
|
||||
config USB_EHCI_HCD_PPC_OF
|
||||
bool "EHCI support for PPC USB controller on OF platform bus"
|
||||
@ -269,10 +269,10 @@ config USB_EHCI_SH
|
||||
If you use the PCI EHCI controller, this option is not necessary.
|
||||
|
||||
config USB_EHCI_EXYNOS
|
||||
tristate "EHCI support for Samsung S5P/EXYNOS SoC Series"
|
||||
depends on ARCH_S5PV210 || ARCH_EXYNOS
|
||||
help
|
||||
Enable support for the Samsung Exynos SOC's on-chip EHCI controller.
|
||||
tristate "EHCI support for Samsung S5P/EXYNOS SoC Series"
|
||||
depends on ARCH_S5PV210 || ARCH_EXYNOS
|
||||
help
|
||||
Enable support for the Samsung Exynos SOC's on-chip EHCI controller.
|
||||
|
||||
config USB_EHCI_MV
|
||||
tristate "EHCI support for Marvell PXA/MMP USB controller"
|
||||
@ -409,12 +409,12 @@ config USB_OHCI_HCD_OMAP1
|
||||
Enables support for the OHCI controller on OMAP1/2 chips.
|
||||
|
||||
config USB_OHCI_HCD_SPEAR
|
||||
tristate "Support for ST SPEAr on-chip OHCI USB controller"
|
||||
depends on USB_OHCI_HCD && PLAT_SPEAR
|
||||
default y
|
||||
---help---
|
||||
Enables support for the on-chip OHCI controller on
|
||||
ST SPEAr chips.
|
||||
tristate "Support for ST SPEAr on-chip OHCI USB controller"
|
||||
depends on USB_OHCI_HCD && PLAT_SPEAR
|
||||
default y
|
||||
---help---
|
||||
Enables support for the on-chip OHCI controller on
|
||||
ST SPEAr chips.
|
||||
|
||||
config USB_OHCI_HCD_STI
|
||||
tristate "Support for ST STiHxxx on-chip OHCI USB controller"
|
||||
@ -426,12 +426,12 @@ config USB_OHCI_HCD_STI
|
||||
STMicroelectronics consumer electronics SoC's.
|
||||
|
||||
config USB_OHCI_HCD_S3C2410
|
||||
tristate "OHCI support for Samsung S3C24xx/S3C64xx SoC series"
|
||||
depends on USB_OHCI_HCD && (ARCH_S3C24XX || ARCH_S3C64XX)
|
||||
default y
|
||||
---help---
|
||||
Enables support for the on-chip OHCI controller on
|
||||
S3C24xx/S3C64xx chips.
|
||||
tristate "OHCI support for Samsung S3C24xx/S3C64xx SoC series"
|
||||
depends on USB_OHCI_HCD && (ARCH_S3C24XX || ARCH_S3C64XX)
|
||||
default y
|
||||
---help---
|
||||
Enables support for the on-chip OHCI controller on
|
||||
S3C24xx/S3C64xx chips.
|
||||
|
||||
config USB_OHCI_HCD_LPC32XX
|
||||
tristate "Support for LPC on-chip OHCI USB controller"
|
||||
@ -440,8 +440,8 @@ config USB_OHCI_HCD_LPC32XX
|
||||
depends on USB_ISP1301
|
||||
default y
|
||||
---help---
|
||||
Enables support for the on-chip OHCI controller on
|
||||
NXP chips.
|
||||
Enables support for the on-chip OHCI controller on
|
||||
NXP chips.
|
||||
|
||||
config USB_OHCI_HCD_PXA27X
|
||||
tristate "Support for PXA27X/PXA3XX on-chip OHCI USB controller"
|
||||
@ -456,8 +456,8 @@ config USB_OHCI_HCD_AT91
|
||||
depends on USB_OHCI_HCD && ARCH_AT91 && OF
|
||||
default y
|
||||
---help---
|
||||
Enables support for the on-chip OHCI controller on
|
||||
Atmel chips.
|
||||
Enables support for the on-chip OHCI controller on
|
||||
Atmel chips.
|
||||
|
||||
config USB_OHCI_HCD_OMAP3
|
||||
tristate "OHCI support for OMAP3 and later chips"
|
||||
@ -545,7 +545,7 @@ config USB_OHCI_EXYNOS
|
||||
tristate "OHCI support for Samsung S5P/EXYNOS SoC Series"
|
||||
depends on ARCH_S5PV210 || ARCH_EXYNOS
|
||||
help
|
||||
Enable support for the Samsung Exynos SOC's on-chip OHCI controller.
|
||||
Enable support for the Samsung Exynos SOC's on-chip OHCI controller.
|
||||
|
||||
config USB_CNS3XXX_OHCI
|
||||
bool "Cavium CNS3XXX OHCI Module (DEPRECATED)"
|
||||
@ -609,8 +609,8 @@ config USB_UHCI_PLATFORM
|
||||
default y if (ARCH_VT8500 || ARCH_ASPEED)
|
||||
|
||||
config USB_UHCI_ASPEED
|
||||
bool
|
||||
default y if ARCH_ASPEED
|
||||
bool
|
||||
default y if ARCH_ASPEED
|
||||
|
||||
config USB_FHCI_HCD
|
||||
tristate "Freescale QE USB Host Controller support"
|
||||
@ -713,14 +713,14 @@ config USB_RENESAS_USBHS_HCD
|
||||
module will be called renesas-usbhs.
|
||||
|
||||
config USB_IMX21_HCD
|
||||
tristate "i.MX21 HCD support"
|
||||
depends on ARM && ARCH_MXC
|
||||
help
|
||||
This driver enables support for the on-chip USB host in the
|
||||
i.MX21 processor.
|
||||
tristate "i.MX21 HCD support"
|
||||
depends on ARM && ARCH_MXC
|
||||
help
|
||||
This driver enables support for the on-chip USB host in the
|
||||
i.MX21 processor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called "imx21-hcd".
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called "imx21-hcd".
|
||||
|
||||
config USB_HCD_BCMA
|
||||
tristate "BCMA usb host driver"
|
||||
|
@ -406,9 +406,12 @@ static int bcma_hcd_probe(struct bcma_device *core)
|
||||
return -ENOMEM;
|
||||
usb_dev->core = core;
|
||||
|
||||
if (core->dev.of_node)
|
||||
if (core->dev.of_node) {
|
||||
usb_dev->gpio_desc = devm_gpiod_get(&core->dev, "vcc",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(usb_dev->gpio_desc))
|
||||
return PTR_ERR(usb_dev->gpio_desc);
|
||||
}
|
||||
|
||||
switch (core->id.id) {
|
||||
case BCMA_CORE_USB20_HOST:
|
||||
|
@ -5646,8 +5646,10 @@ static int fotg210_hcd_probe(struct platform_device *pdev)
|
||||
return retval;
|
||||
|
||||
failed_dis_clk:
|
||||
if (!IS_ERR(fotg210->pclk))
|
||||
if (!IS_ERR(fotg210->pclk)) {
|
||||
clk_disable_unprepare(fotg210->pclk);
|
||||
clk_put(fotg210->pclk);
|
||||
}
|
||||
failed_put_hcd:
|
||||
usb_put_hcd(hcd);
|
||||
fail_create_hcd:
|
||||
@ -5665,8 +5667,10 @@ static int fotg210_hcd_remove(struct platform_device *pdev)
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
|
||||
|
||||
if (!IS_ERR(fotg210->pclk))
|
||||
if (!IS_ERR(fotg210->pclk)) {
|
||||
clk_disable_unprepare(fotg210->pclk);
|
||||
clk_put(fotg210->pclk);
|
||||
}
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
usb_put_hcd(hcd);
|
||||
|
@ -419,7 +419,7 @@ static void create_debug_files(struct imx21 *imx21)
|
||||
{
|
||||
struct dentry *root;
|
||||
|
||||
root = debugfs_create_dir(dev_name(imx21->dev), NULL);
|
||||
root = debugfs_create_dir(dev_name(imx21->dev), usb_debug_root);
|
||||
imx21->debug_root = root;
|
||||
|
||||
debugfs_create_file("status", S_IRUGO, root, imx21, &debug_status_fops);
|
||||
|
@ -2627,7 +2627,7 @@ static int isp1362_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct isp1362_hcd *isp1362_hcd;
|
||||
struct resource *addr, *data, *irq_res;
|
||||
struct resource *data, *irq_res;
|
||||
void __iomem *addr_reg;
|
||||
void __iomem *data_reg;
|
||||
int irq;
|
||||
@ -2651,8 +2651,7 @@ static int isp1362_probe(struct platform_device *pdev)
|
||||
|
||||
irq = irq_res->start;
|
||||
|
||||
addr = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
addr_reg = devm_ioremap_resource(&pdev->dev, addr);
|
||||
addr_reg = devm_platform_ioremap_resource(pdev, 1);
|
||||
if (IS_ERR(addr_reg))
|
||||
return PTR_ERR(addr_reg);
|
||||
|
||||
|
@ -115,7 +115,6 @@ static void at91_start_hc(struct platform_device *pdev)
|
||||
static void at91_stop_hc(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
struct ohci_regs __iomem *regs = hcd->regs;
|
||||
struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
|
||||
|
||||
dev_dbg(&pdev->dev, "stop\n");
|
||||
@ -123,7 +122,7 @@ static void at91_stop_hc(struct platform_device *pdev)
|
||||
/*
|
||||
* Put the USB host controller into reset.
|
||||
*/
|
||||
writel(0, ®s->control);
|
||||
usb_hcd_platform_shutdown(pdev);
|
||||
|
||||
/*
|
||||
* Stop the USB clocks.
|
||||
@ -628,6 +627,7 @@ ohci_hcd_at91_drv_suspend(struct device *dev)
|
||||
|
||||
/* flush the writes */
|
||||
(void) ohci_readl (ohci, &ohci->regs->control);
|
||||
msleep(1);
|
||||
at91_stop_clock(ohci_at91);
|
||||
}
|
||||
|
||||
@ -642,8 +642,8 @@ ohci_hcd_at91_drv_resume(struct device *dev)
|
||||
|
||||
if (ohci_at91->wakeup)
|
||||
disable_irq_wake(hcd->irq);
|
||||
|
||||
at91_start_clock(ohci_at91);
|
||||
else
|
||||
at91_start_clock(ohci_at91);
|
||||
|
||||
ohci_resume(hcd, false);
|
||||
|
||||
|
@ -150,7 +150,7 @@ static void ohci_nxp_stop_hc(void)
|
||||
|
||||
static int ohci_hcd_nxp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = 0;
|
||||
struct usb_hcd *hcd = NULL;
|
||||
const struct hc_driver *driver = &ohci_nxp_hc_driver;
|
||||
struct resource *res;
|
||||
int ret = 0, irq;
|
||||
|
@ -676,12 +676,12 @@ static int oxu_hub_control(struct usb_hcd *hcd,
|
||||
*/
|
||||
|
||||
/* Low level read/write registers functions */
|
||||
static inline u32 oxu_readl(void *base, u32 reg)
|
||||
static inline u32 oxu_readl(void __iomem *base, u32 reg)
|
||||
{
|
||||
return readl(base + reg);
|
||||
}
|
||||
|
||||
static inline void oxu_writel(void *base, u32 reg, u32 val)
|
||||
static inline void oxu_writel(void __iomem *base, u32 reg, u32 val)
|
||||
{
|
||||
writel(val, base + reg);
|
||||
}
|
||||
@ -4063,7 +4063,7 @@ static const struct hc_driver oxu_hc_driver = {
|
||||
* Module stuff
|
||||
*/
|
||||
|
||||
static void oxu_configuration(struct platform_device *pdev, void *base)
|
||||
static void oxu_configuration(struct platform_device *pdev, void __iomem *base)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
@ -4093,7 +4093,7 @@ static void oxu_configuration(struct platform_device *pdev, void *base)
|
||||
oxu_writel(base, OXU_CHIPIRQEN_SET, OXU_USBSPHLPWUI | OXU_USBOTGLPWUI);
|
||||
}
|
||||
|
||||
static int oxu_verify_id(struct platform_device *pdev, void *base)
|
||||
static int oxu_verify_id(struct platform_device *pdev, void __iomem *base)
|
||||
{
|
||||
u32 id;
|
||||
static const char * const bo[] = {
|
||||
@ -4121,7 +4121,7 @@ static int oxu_verify_id(struct platform_device *pdev, void *base)
|
||||
static const struct hc_driver oxu_hc_driver;
|
||||
static struct usb_hcd *oxu_create(struct platform_device *pdev,
|
||||
unsigned long memstart, unsigned long memlen,
|
||||
void *base, int irq, int otg)
|
||||
void __iomem *base, int irq, int otg)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
@ -4158,7 +4158,7 @@ static struct usb_hcd *oxu_create(struct platform_device *pdev,
|
||||
|
||||
static int oxu_init(struct platform_device *pdev,
|
||||
unsigned long memstart, unsigned long memlen,
|
||||
void *base, int irq)
|
||||
void __iomem *base, int irq)
|
||||
{
|
||||
struct oxu_info *info = platform_get_drvdata(pdev);
|
||||
struct usb_hcd *hcd;
|
||||
@ -4207,7 +4207,7 @@ error_create_otg:
|
||||
static int oxu_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
void *base;
|
||||
void __iomem *base;
|
||||
unsigned long memstart, memlen;
|
||||
int irq, ret;
|
||||
struct oxu_info *info;
|
||||
|
@ -71,7 +71,7 @@ INT_MODULE_PARM(testing, 0);
|
||||
/* Some boards misreport power switching/overcurrent*/
|
||||
static bool distrust_firmware = true;
|
||||
module_param(distrust_firmware, bool, 0);
|
||||
MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren"
|
||||
MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurrent"
|
||||
"t setup");
|
||||
static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait);
|
||||
/*
|
||||
|
@ -48,6 +48,7 @@
|
||||
#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_XHCI 0x15e9
|
||||
#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_XHCI 0x15ec
|
||||
#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI 0x15f0
|
||||
#define PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI 0x8a13
|
||||
|
||||
#define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9
|
||||
#define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba
|
||||
@ -212,7 +213,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
||||
pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_XHCI ||
|
||||
pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_XHCI ||
|
||||
pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_XHCI ||
|
||||
pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI))
|
||||
pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI ||
|
||||
pdev->device == PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI))
|
||||
xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
|
||||
|
@ -280,6 +280,9 @@ void xhci_ring_cmd_db(struct xhci_hcd *xhci)
|
||||
return;
|
||||
|
||||
xhci_dbg(xhci, "// Ding dong!\n");
|
||||
|
||||
trace_xhci_ring_host_doorbell(0, DB_VALUE_HOST);
|
||||
|
||||
writel(DB_VALUE_HOST, &xhci->dba->doorbell[0]);
|
||||
/* Flush PCI posted writes */
|
||||
readl(&xhci->dba->doorbell[0]);
|
||||
@ -401,6 +404,9 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
|
||||
if ((ep_state & EP_STOP_CMD_PENDING) || (ep_state & SET_DEQ_PENDING) ||
|
||||
(ep_state & EP_HALTED) || (ep_state & EP_CLEARING_TT))
|
||||
return;
|
||||
|
||||
trace_xhci_ring_ep_doorbell(slot_id, DB_VALUE(ep_index, stream_id));
|
||||
|
||||
writel(DB_VALUE(ep_index, stream_id), db_addr);
|
||||
/* The CPU has better things to do at this point than wait for a
|
||||
* write-posting flush. It'll get there soon enough.
|
||||
@ -651,10 +657,8 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci,
|
||||
}
|
||||
xhci_urb_free_priv(urb_priv);
|
||||
usb_hcd_unlink_urb_from_ep(hcd, urb);
|
||||
spin_unlock(&xhci->lock);
|
||||
trace_xhci_urb_giveback(urb);
|
||||
usb_hcd_giveback_urb(hcd, urb, status);
|
||||
spin_lock(&xhci->lock);
|
||||
}
|
||||
|
||||
static void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci,
|
||||
@ -2740,6 +2744,42 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update Event Ring Dequeue Pointer:
|
||||
* - When all events have finished
|
||||
* - To avoid "Event Ring Full Error" condition
|
||||
*/
|
||||
static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
|
||||
union xhci_trb *event_ring_deq)
|
||||
{
|
||||
u64 temp_64;
|
||||
dma_addr_t deq;
|
||||
|
||||
temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
|
||||
/* If necessary, update the HW's version of the event ring deq ptr. */
|
||||
if (event_ring_deq != xhci->event_ring->dequeue) {
|
||||
deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
|
||||
xhci->event_ring->dequeue);
|
||||
if (deq == 0)
|
||||
xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr\n");
|
||||
/*
|
||||
* Per 4.9.4, Software writes to the ERDP register shall
|
||||
* always advance the Event Ring Dequeue Pointer value.
|
||||
*/
|
||||
if ((temp_64 & (u64) ~ERST_PTR_MASK) ==
|
||||
((u64) deq & (u64) ~ERST_PTR_MASK))
|
||||
return;
|
||||
|
||||
/* Update HC event ring dequeue pointer */
|
||||
temp_64 &= ERST_PTR_MASK;
|
||||
temp_64 |= ((u64) deq & (u64) ~ERST_PTR_MASK);
|
||||
}
|
||||
|
||||
/* Clear the event handler busy flag (RW1C) */
|
||||
temp_64 |= ERST_EHB;
|
||||
xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue);
|
||||
}
|
||||
|
||||
/*
|
||||
* xHCI spec says we can get an interrupt, and if the HC has an error condition,
|
||||
* we might get bad data out of the event ring. Section 4.10.2.7 has a list of
|
||||
@ -2751,9 +2791,9 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
|
||||
union xhci_trb *event_ring_deq;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
unsigned long flags;
|
||||
dma_addr_t deq;
|
||||
u64 temp_64;
|
||||
u32 status;
|
||||
int event_loop = 0;
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
/* Check if the xHC generated the interrupt, or the irq is shared */
|
||||
@ -2807,24 +2847,14 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
|
||||
/* FIXME this should be a delayed service routine
|
||||
* that clears the EHB.
|
||||
*/
|
||||
while (xhci_handle_event(xhci) > 0) {}
|
||||
|
||||
temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
|
||||
/* If necessary, update the HW's version of the event ring deq ptr. */
|
||||
if (event_ring_deq != xhci->event_ring->dequeue) {
|
||||
deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
|
||||
xhci->event_ring->dequeue);
|
||||
if (deq == 0)
|
||||
xhci_warn(xhci, "WARN something wrong with SW event "
|
||||
"ring dequeue ptr.\n");
|
||||
/* Update HC event ring dequeue pointer */
|
||||
temp_64 &= ERST_PTR_MASK;
|
||||
temp_64 |= ((u64) deq & (u64) ~ERST_PTR_MASK);
|
||||
while (xhci_handle_event(xhci) > 0) {
|
||||
if (event_loop++ < TRBS_PER_SEGMENT / 2)
|
||||
continue;
|
||||
xhci_update_erst_dequeue(xhci, event_ring_deq);
|
||||
event_loop = 0;
|
||||
}
|
||||
|
||||
/* Clear the event handler busy flag (RW1C); event ring is empty. */
|
||||
temp_64 |= ERST_EHB;
|
||||
xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue);
|
||||
xhci_update_erst_dequeue(xhci, event_ring_deq);
|
||||
ret = IRQ_HANDLED;
|
||||
|
||||
out:
|
||||
|
@ -42,19 +42,18 @@
|
||||
#define XUSB_CFG_CSB_BASE_ADDR 0x800
|
||||
|
||||
/* FPCI mailbox registers */
|
||||
#define XUSB_CFG_ARU_MBOX_CMD 0x0e4
|
||||
/* XUSB_CFG_ARU_MBOX_CMD */
|
||||
#define MBOX_DEST_FALC BIT(27)
|
||||
#define MBOX_DEST_PME BIT(28)
|
||||
#define MBOX_DEST_SMI BIT(29)
|
||||
#define MBOX_DEST_XHCI BIT(30)
|
||||
#define MBOX_INT_EN BIT(31)
|
||||
#define XUSB_CFG_ARU_MBOX_DATA_IN 0x0e8
|
||||
/* XUSB_CFG_ARU_MBOX_DATA_IN and XUSB_CFG_ARU_MBOX_DATA_OUT */
|
||||
#define CMD_DATA_SHIFT 0
|
||||
#define CMD_DATA_MASK 0xffffff
|
||||
#define CMD_TYPE_SHIFT 24
|
||||
#define CMD_TYPE_MASK 0xff
|
||||
#define XUSB_CFG_ARU_MBOX_DATA_OUT 0x0ec
|
||||
#define XUSB_CFG_ARU_MBOX_OWNER 0x0f0
|
||||
/* XUSB_CFG_ARU_MBOX_OWNER */
|
||||
#define MBOX_OWNER_NONE 0
|
||||
#define MBOX_OWNER_FW 1
|
||||
#define MBOX_OWNER_SW 2
|
||||
@ -146,6 +145,13 @@ struct tegra_xusb_phy_type {
|
||||
unsigned int num;
|
||||
};
|
||||
|
||||
struct tega_xusb_mbox_regs {
|
||||
u16 cmd;
|
||||
u16 data_in;
|
||||
u16 data_out;
|
||||
u16 owner;
|
||||
};
|
||||
|
||||
struct tegra_xusb_soc {
|
||||
const char *firmware;
|
||||
const char * const *supply_names;
|
||||
@ -160,6 +166,8 @@ struct tegra_xusb_soc {
|
||||
} usb2, ulpi, hsic, usb3;
|
||||
} ports;
|
||||
|
||||
struct tega_xusb_mbox_regs mbox;
|
||||
|
||||
bool scale_ss_clock;
|
||||
bool has_ipfs;
|
||||
};
|
||||
@ -395,15 +403,15 @@ static int tegra_xusb_mbox_send(struct tegra_xusb *tegra,
|
||||
* ACK/NAK messages.
|
||||
*/
|
||||
if (!(msg->cmd == MBOX_CMD_ACK || msg->cmd == MBOX_CMD_NAK)) {
|
||||
value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER);
|
||||
value = fpci_readl(tegra, tegra->soc->mbox.owner);
|
||||
if (value != MBOX_OWNER_NONE) {
|
||||
dev_err(tegra->dev, "mailbox is busy\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
fpci_writel(tegra, MBOX_OWNER_SW, XUSB_CFG_ARU_MBOX_OWNER);
|
||||
fpci_writel(tegra, MBOX_OWNER_SW, tegra->soc->mbox.owner);
|
||||
|
||||
value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER);
|
||||
value = fpci_readl(tegra, tegra->soc->mbox.owner);
|
||||
if (value != MBOX_OWNER_SW) {
|
||||
dev_err(tegra->dev, "failed to acquire mailbox\n");
|
||||
return -EBUSY;
|
||||
@ -413,17 +421,17 @@ static int tegra_xusb_mbox_send(struct tegra_xusb *tegra,
|
||||
}
|
||||
|
||||
value = tegra_xusb_mbox_pack(msg);
|
||||
fpci_writel(tegra, value, XUSB_CFG_ARU_MBOX_DATA_IN);
|
||||
fpci_writel(tegra, value, tegra->soc->mbox.data_in);
|
||||
|
||||
value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_CMD);
|
||||
value = fpci_readl(tegra, tegra->soc->mbox.cmd);
|
||||
value |= MBOX_INT_EN | MBOX_DEST_FALC;
|
||||
fpci_writel(tegra, value, XUSB_CFG_ARU_MBOX_CMD);
|
||||
fpci_writel(tegra, value, tegra->soc->mbox.cmd);
|
||||
|
||||
if (wait_for_idle) {
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(250);
|
||||
|
||||
while (time_before(jiffies, timeout)) {
|
||||
value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER);
|
||||
value = fpci_readl(tegra, tegra->soc->mbox.owner);
|
||||
if (value == MBOX_OWNER_NONE)
|
||||
break;
|
||||
|
||||
@ -431,7 +439,7 @@ static int tegra_xusb_mbox_send(struct tegra_xusb *tegra,
|
||||
}
|
||||
|
||||
if (time_after(jiffies, timeout))
|
||||
value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER);
|
||||
value = fpci_readl(tegra, tegra->soc->mbox.owner);
|
||||
|
||||
if (value != MBOX_OWNER_NONE)
|
||||
return -ETIMEDOUT;
|
||||
@ -598,16 +606,16 @@ static irqreturn_t tegra_xusb_mbox_thread(int irq, void *data)
|
||||
|
||||
mutex_lock(&tegra->lock);
|
||||
|
||||
value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_DATA_OUT);
|
||||
value = fpci_readl(tegra, tegra->soc->mbox.data_out);
|
||||
tegra_xusb_mbox_unpack(&msg, value);
|
||||
|
||||
value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_CMD);
|
||||
value = fpci_readl(tegra, tegra->soc->mbox.cmd);
|
||||
value &= ~MBOX_DEST_SMI;
|
||||
fpci_writel(tegra, value, XUSB_CFG_ARU_MBOX_CMD);
|
||||
fpci_writel(tegra, value, tegra->soc->mbox.cmd);
|
||||
|
||||
/* clear mailbox owner if no ACK/NAK is required */
|
||||
if (!tegra_xusb_mbox_cmd_requires_ack(msg.cmd))
|
||||
fpci_writel(tegra, MBOX_OWNER_NONE, XUSB_CFG_ARU_MBOX_OWNER);
|
||||
fpci_writel(tegra, MBOX_OWNER_NONE, tegra->soc->mbox.owner);
|
||||
|
||||
tegra_xusb_mbox_handle(tegra, &msg);
|
||||
|
||||
@ -755,7 +763,6 @@ static int tegra_xusb_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct tegra_xusb *tegra = dev_get_drvdata(dev);
|
||||
|
||||
tegra_xusb_phy_disable(tegra);
|
||||
regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
|
||||
tegra_xusb_clk_disable(tegra);
|
||||
|
||||
@ -779,16 +786,8 @@ static int tegra_xusb_runtime_resume(struct device *dev)
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
err = tegra_xusb_phy_enable(tegra);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "failed to enable PHYs: %d\n", err);
|
||||
goto disable_regulator;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
disable_regulator:
|
||||
regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
|
||||
disable_clk:
|
||||
tegra_xusb_clk_disable(tegra);
|
||||
return err;
|
||||
@ -970,7 +969,7 @@ static int tegra_xusb_powerdomain_init(struct device *dev,
|
||||
static int tegra_xusb_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_xusb_mbox_msg msg;
|
||||
struct resource *res, *regs;
|
||||
struct resource *regs;
|
||||
struct tegra_xusb *tegra;
|
||||
struct xhci_hcd *xhci;
|
||||
unsigned int i, j, k;
|
||||
@ -992,14 +991,12 @@ static int tegra_xusb_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(tegra->regs))
|
||||
return PTR_ERR(tegra->regs);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
tegra->fpci_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
tegra->fpci_base = devm_platform_ioremap_resource(pdev, 1);
|
||||
if (IS_ERR(tegra->fpci_base))
|
||||
return PTR_ERR(tegra->fpci_base);
|
||||
|
||||
if (tegra->soc->has_ipfs) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
|
||||
tegra->ipfs_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
tegra->ipfs_base = devm_platform_ioremap_resource(pdev, 2);
|
||||
if (IS_ERR(tegra->ipfs_base))
|
||||
return PTR_ERR(tegra->ipfs_base);
|
||||
}
|
||||
@ -1128,8 +1125,9 @@ static int tegra_xusb_probe(struct platform_device *pdev)
|
||||
goto put_powerdomains;
|
||||
}
|
||||
|
||||
for (i = 0; i < tegra->soc->num_supplies; i++)
|
||||
tegra->supplies[i].supply = tegra->soc->supply_names[i];
|
||||
regulator_bulk_set_supply_names(tegra->supplies,
|
||||
tegra->soc->supply_names,
|
||||
tegra->soc->num_supplies);
|
||||
|
||||
err = devm_regulator_bulk_get(&pdev->dev, tegra->soc->num_supplies,
|
||||
tegra->supplies);
|
||||
@ -1181,6 +1179,12 @@ static int tegra_xusb_probe(struct platform_device *pdev)
|
||||
*/
|
||||
platform_set_drvdata(pdev, tegra);
|
||||
|
||||
err = tegra_xusb_phy_enable(tegra);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed to enable PHYs: %d\n", err);
|
||||
goto put_hcd;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
if (pm_runtime_enabled(&pdev->dev))
|
||||
err = pm_runtime_get_sync(&pdev->dev);
|
||||
@ -1189,7 +1193,7 @@ static int tegra_xusb_probe(struct platform_device *pdev)
|
||||
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed to enable device: %d\n", err);
|
||||
goto disable_rpm;
|
||||
goto disable_phy;
|
||||
}
|
||||
|
||||
tegra_xusb_config(tegra, regs);
|
||||
@ -1275,9 +1279,11 @@ remove_usb2:
|
||||
put_rpm:
|
||||
if (!pm_runtime_status_suspended(&pdev->dev))
|
||||
tegra_xusb_runtime_suspend(&pdev->dev);
|
||||
disable_rpm:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
put_hcd:
|
||||
usb_put_hcd(tegra->hcd);
|
||||
disable_phy:
|
||||
tegra_xusb_phy_disable(tegra);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
put_powerdomains:
|
||||
if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) {
|
||||
tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC);
|
||||
@ -1314,6 +1320,8 @@ static int tegra_xusb_remove(struct platform_device *pdev)
|
||||
tegra_xusb_powerdomain_remove(&pdev->dev, tegra);
|
||||
}
|
||||
|
||||
tegra_xusb_phy_disable(tegra);
|
||||
|
||||
tegra_xusb_padctl_put(tegra->padctl);
|
||||
|
||||
return 0;
|
||||
@ -1375,6 +1383,12 @@ static const struct tegra_xusb_soc tegra124_soc = {
|
||||
},
|
||||
.scale_ss_clock = true,
|
||||
.has_ipfs = true,
|
||||
.mbox = {
|
||||
.cmd = 0xe4,
|
||||
.data_in = 0xe8,
|
||||
.data_out = 0xec,
|
||||
.owner = 0xf0,
|
||||
},
|
||||
};
|
||||
MODULE_FIRMWARE("nvidia/tegra124/xusb.bin");
|
||||
|
||||
@ -1407,6 +1421,12 @@ static const struct tegra_xusb_soc tegra210_soc = {
|
||||
},
|
||||
.scale_ss_clock = false,
|
||||
.has_ipfs = true,
|
||||
.mbox = {
|
||||
.cmd = 0xe4,
|
||||
.data_in = 0xe8,
|
||||
.data_out = 0xec,
|
||||
.owner = 0xf0,
|
||||
},
|
||||
};
|
||||
MODULE_FIRMWARE("nvidia/tegra210/xusb.bin");
|
||||
|
||||
@ -1432,12 +1452,48 @@ static const struct tegra_xusb_soc tegra186_soc = {
|
||||
},
|
||||
.scale_ss_clock = false,
|
||||
.has_ipfs = false,
|
||||
.mbox = {
|
||||
.cmd = 0xe4,
|
||||
.data_in = 0xe8,
|
||||
.data_out = 0xec,
|
||||
.owner = 0xf0,
|
||||
},
|
||||
};
|
||||
|
||||
static const char * const tegra194_supply_names[] = {
|
||||
};
|
||||
|
||||
static const struct tegra_xusb_phy_type tegra194_phy_types[] = {
|
||||
{ .name = "usb3", .num = 4, },
|
||||
{ .name = "usb2", .num = 4, },
|
||||
};
|
||||
|
||||
static const struct tegra_xusb_soc tegra194_soc = {
|
||||
.firmware = "nvidia/tegra194/xusb.bin",
|
||||
.supply_names = tegra194_supply_names,
|
||||
.num_supplies = ARRAY_SIZE(tegra194_supply_names),
|
||||
.phy_types = tegra194_phy_types,
|
||||
.num_types = ARRAY_SIZE(tegra194_phy_types),
|
||||
.ports = {
|
||||
.usb3 = { .offset = 0, .count = 4, },
|
||||
.usb2 = { .offset = 4, .count = 4, },
|
||||
},
|
||||
.scale_ss_clock = false,
|
||||
.has_ipfs = false,
|
||||
.mbox = {
|
||||
.cmd = 0x68,
|
||||
.data_in = 0x6c,
|
||||
.data_out = 0x70,
|
||||
.owner = 0x74,
|
||||
},
|
||||
};
|
||||
MODULE_FIRMWARE("nvidia/tegra194/xusb.bin");
|
||||
|
||||
static const struct of_device_id tegra_xusb_of_match[] = {
|
||||
{ .compatible = "nvidia,tegra124-xusb", .data = &tegra124_soc },
|
||||
{ .compatible = "nvidia,tegra210-xusb", .data = &tegra210_soc },
|
||||
{ .compatible = "nvidia,tegra186-xusb", .data = &tegra186_soc },
|
||||
{ .compatible = "nvidia,tegra194-xusb", .data = &tegra194_soc },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra_xusb_of_match);
|
||||
|
@ -560,6 +560,32 @@ DEFINE_EVENT(xhci_log_portsc, xhci_hub_status_data,
|
||||
TP_ARGS(portnum, portsc)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(xhci_log_doorbell,
|
||||
TP_PROTO(u32 slot, u32 doorbell),
|
||||
TP_ARGS(slot, doorbell),
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, slot)
|
||||
__field(u32, doorbell)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->slot = slot;
|
||||
__entry->doorbell = doorbell;
|
||||
),
|
||||
TP_printk("Ring doorbell for %s",
|
||||
xhci_decode_doorbell(__entry->slot, __entry->doorbell)
|
||||
)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(xhci_log_doorbell, xhci_ring_ep_doorbell,
|
||||
TP_PROTO(u32 slot, u32 doorbell),
|
||||
TP_ARGS(slot, doorbell)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(xhci_log_doorbell, xhci_ring_host_doorbell,
|
||||
TP_PROTO(u32 slot, u32 doorbell),
|
||||
TP_ARGS(slot, doorbell)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(xhci_dbc_log_request,
|
||||
TP_PROTO(struct dbc_request *req),
|
||||
TP_ARGS(req),
|
||||
|
@ -5301,7 +5301,8 @@ static const struct hc_driver xhci_hc_driver = {
|
||||
* generic hardware linkage
|
||||
*/
|
||||
.irq = xhci_irq,
|
||||
.flags = HCD_MEMORY | HCD_DMA | HCD_USB3 | HCD_SHARED,
|
||||
.flags = HCD_MEMORY | HCD_DMA | HCD_USB3 | HCD_SHARED |
|
||||
HCD_BH,
|
||||
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
|
@ -2580,6 +2580,35 @@ static inline const char *xhci_decode_portsc(u32 portsc)
|
||||
return str;
|
||||
}
|
||||
|
||||
static inline const char *xhci_decode_doorbell(u32 slot, u32 doorbell)
|
||||
{
|
||||
static char str[256];
|
||||
u8 ep;
|
||||
u16 stream;
|
||||
int ret;
|
||||
|
||||
ep = (doorbell & 0xff);
|
||||
stream = doorbell >> 16;
|
||||
|
||||
if (slot == 0) {
|
||||
sprintf(str, "Command Ring %d", doorbell);
|
||||
return str;
|
||||
}
|
||||
ret = sprintf(str, "Slot %d ", slot);
|
||||
if (ep > 0 && ep < 32)
|
||||
ret = sprintf(str + ret, "ep%d%s",
|
||||
ep / 2,
|
||||
ep % 2 ? "in" : "out");
|
||||
else if (ep == 0 || ep < 248)
|
||||
ret = sprintf(str + ret, "Reserved %d", ep);
|
||||
else
|
||||
ret = sprintf(str + ret, "Vendor Defined %d", ep);
|
||||
if (stream)
|
||||
ret = sprintf(str + ret, " Stream %d", stream);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static inline const char *xhci_ep_state_string(u8 state)
|
||||
{
|
||||
switch (state) {
|
||||
|
@ -566,7 +566,6 @@ static int
|
||||
mts_scsi_queuecommand_lck(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback)
|
||||
{
|
||||
struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]);
|
||||
int err = 0;
|
||||
int res;
|
||||
|
||||
MTS_DEBUG_GOT_HERE();
|
||||
@ -613,7 +612,7 @@ mts_scsi_queuecommand_lck(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback
|
||||
|
||||
}
|
||||
out:
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEF_SCSI_QCMD(mts_scsi_queuecommand)
|
||||
|
@ -1032,8 +1032,6 @@ static int check_atl_transfer(struct usb_hcd *hcd, struct ptd *ptd,
|
||||
urb->status = -EOVERFLOW;
|
||||
else if (FROM_DW3_CERR(ptd->dw3))
|
||||
urb->status = -EPIPE; /* Stall */
|
||||
else if (ptd->dw3 & DW3_ERROR_BIT)
|
||||
urb->status = -EPROTO; /* XactErr */
|
||||
else
|
||||
urb->status = -EPROTO; /* Unknown */
|
||||
/*
|
||||
|
@ -181,8 +181,8 @@ config USB_TEST
|
||||
including sample test device firmware and "how to use it".
|
||||
|
||||
config USB_EHSET_TEST_FIXTURE
|
||||
tristate "USB EHSET Test Fixture driver"
|
||||
help
|
||||
tristate "USB EHSET Test Fixture driver"
|
||||
help
|
||||
Say Y here if you want to support the special test fixture device
|
||||
used for the USB-IF Embedded Host High-Speed Electrical Test procedure.
|
||||
|
||||
@ -233,17 +233,17 @@ config USB_HUB_USB251XB
|
||||
Say Y or M here if you need to configure such a device via SMBus.
|
||||
|
||||
config USB_HSIC_USB3503
|
||||
tristate "USB3503 HSIC to USB20 Driver"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver.
|
||||
tristate "USB3503 HSIC to USB20 Driver"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver.
|
||||
|
||||
config USB_HSIC_USB4604
|
||||
tristate "USB4604 HSIC to USB20 Driver"
|
||||
depends on I2C
|
||||
help
|
||||
This option enables support for SMSC USB4604 HSIC to USB 2.0 Driver.
|
||||
tristate "USB4604 HSIC to USB20 Driver"
|
||||
depends on I2C
|
||||
help
|
||||
This option enables support for SMSC USB4604 HSIC to USB 2.0 Driver.
|
||||
|
||||
config USB_LINK_LAYER_TEST
|
||||
tristate "USB Link Layer Test driver"
|
||||
|
@ -164,7 +164,12 @@ static int appledisplay_bl_get_brightness(struct backlight_device *bd)
|
||||
0,
|
||||
pdata->msgdata, 2,
|
||||
ACD_USB_TIMEOUT);
|
||||
brightness = pdata->msgdata[1];
|
||||
if (retval < 2) {
|
||||
if (retval >= 0)
|
||||
retval = -EMSGSIZE;
|
||||
} else {
|
||||
brightness = pdata->msgdata[1];
|
||||
}
|
||||
mutex_unlock(&pdata->sysfslock);
|
||||
|
||||
if (retval < 0)
|
||||
@ -299,6 +304,7 @@ error:
|
||||
if (pdata) {
|
||||
if (pdata->urb) {
|
||||
usb_kill_urb(pdata->urb);
|
||||
cancel_delayed_work_sync(&pdata->work);
|
||||
if (pdata->urbdata)
|
||||
usb_free_coherent(pdata->udev, ACD_URB_BUFFER_LEN,
|
||||
pdata->urbdata, pdata->urb->transfer_dma);
|
||||
|
@ -384,13 +384,17 @@ static int _chaoskey_fill(struct chaoskey *dev)
|
||||
!dev->reading,
|
||||
(started ? NAK_TIMEOUT : ALEA_FIRST_TIMEOUT) );
|
||||
|
||||
if (result < 0)
|
||||
if (result < 0) {
|
||||
usb_kill_urb(dev->urb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
if (result == 0) {
|
||||
result = -ETIMEDOUT;
|
||||
else
|
||||
usb_kill_urb(dev->urb);
|
||||
} else {
|
||||
result = dev->valid;
|
||||
}
|
||||
out:
|
||||
/* Let the device go back to sleep eventually */
|
||||
usb_autopm_put_interface(dev->interface);
|
||||
@ -526,7 +530,21 @@ static int chaoskey_suspend(struct usb_interface *interface,
|
||||
|
||||
static int chaoskey_resume(struct usb_interface *interface)
|
||||
{
|
||||
struct chaoskey *dev;
|
||||
struct usb_device *udev = interface_to_usbdev(interface);
|
||||
|
||||
usb_dbg(interface, "resume");
|
||||
dev = usb_get_intfdata(interface);
|
||||
|
||||
/*
|
||||
* We may have lost power.
|
||||
* In that case the device that needs a long time
|
||||
* for the first requests needs an extended timeout
|
||||
* again
|
||||
*/
|
||||
if (le16_to_cpu(udev->descriptor.idVendor) == ALEA_VENDOR_ID)
|
||||
dev->reads_started = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
@ -333,7 +333,8 @@ static void ftdi_elan_abandon_completions(struct usb_ftdi *ftdi)
|
||||
*respond->result = -ESHUTDOWN;
|
||||
*respond->value = 0;
|
||||
complete(&respond->wait_completion);
|
||||
} mutex_unlock(&ftdi->u132_lock);
|
||||
}
|
||||
mutex_unlock(&ftdi->u132_lock);
|
||||
}
|
||||
|
||||
static void ftdi_elan_abandon_targets(struct usb_ftdi *ftdi)
|
||||
@ -763,7 +764,8 @@ static int ftdi_elan_total_command_size(struct usb_ftdi *ftdi, int command_size)
|
||||
struct u132_command *command = &ftdi->command[COMMAND_MASK &
|
||||
i++];
|
||||
total_size += 5 + command->follows;
|
||||
} return total_size;
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
static int ftdi_elan_command_engine(struct usb_ftdi *ftdi)
|
||||
|
@ -56,11 +56,10 @@ static const struct usb_device_id idmouse_table[] = {
|
||||
#define FTIP_SCROLL 0x24
|
||||
|
||||
#define ftip_command(dev, command, value, index) \
|
||||
usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), command, \
|
||||
usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), command, \
|
||||
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, value, index, NULL, 0, 1000)
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, idmouse_table);
|
||||
static DEFINE_MUTEX(open_disc_mutex);
|
||||
|
||||
/* structure to hold all of our device specific stuff */
|
||||
struct usb_idmouse {
|
||||
@ -158,8 +157,8 @@ static int idmouse_create_image(struct usb_idmouse *dev)
|
||||
|
||||
/* loop over a blocking bulk read to get data from the device */
|
||||
while (bytes_read < IMGSIZE) {
|
||||
result = usb_bulk_msg (dev->udev,
|
||||
usb_rcvbulkpipe (dev->udev, dev->bulk_in_endpointAddr),
|
||||
result = usb_bulk_msg(dev->udev,
|
||||
usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
|
||||
dev->bulk_in_buffer + bytes_read,
|
||||
dev->bulk_in_size, &bulk_read, 5000);
|
||||
if (result < 0) {
|
||||
@ -223,21 +222,17 @@ static int idmouse_open(struct inode *inode, struct file *file)
|
||||
int result;
|
||||
|
||||
/* get the interface from minor number and driver information */
|
||||
interface = usb_find_interface (&idmouse_driver, iminor (inode));
|
||||
interface = usb_find_interface(&idmouse_driver, iminor(inode));
|
||||
if (!interface)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&open_disc_mutex);
|
||||
/* get the device information block from the interface */
|
||||
dev = usb_get_intfdata(interface);
|
||||
if (!dev) {
|
||||
mutex_unlock(&open_disc_mutex);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* lock this device */
|
||||
mutex_lock(&dev->lock);
|
||||
mutex_unlock(&open_disc_mutex);
|
||||
|
||||
/* check if already open */
|
||||
if (dev->open) {
|
||||
@ -251,7 +246,7 @@ static int idmouse_open(struct inode *inode, struct file *file)
|
||||
result = usb_autopm_get_interface(interface);
|
||||
if (result)
|
||||
goto error;
|
||||
result = idmouse_create_image (dev);
|
||||
result = idmouse_create_image(dev);
|
||||
usb_autopm_put_interface(interface);
|
||||
if (result)
|
||||
goto error;
|
||||
@ -280,27 +275,17 @@ static int idmouse_release(struct inode *inode, struct file *file)
|
||||
if (dev == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&open_disc_mutex);
|
||||
/* lock our device */
|
||||
mutex_lock(&dev->lock);
|
||||
|
||||
/* are we really open? */
|
||||
if (dev->open <= 0) {
|
||||
mutex_unlock(&dev->lock);
|
||||
mutex_unlock(&open_disc_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
--dev->open;
|
||||
|
||||
if (!dev->present) {
|
||||
/* the device was unplugged before the file was released */
|
||||
mutex_unlock(&dev->lock);
|
||||
mutex_unlock(&open_disc_mutex);
|
||||
idmouse_delete(dev);
|
||||
} else {
|
||||
mutex_unlock(&dev->lock);
|
||||
mutex_unlock(&open_disc_mutex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -379,7 +364,6 @@ static int idmouse_probe(struct usb_interface *interface,
|
||||
if (result) {
|
||||
/* something prevented us from registering this device */
|
||||
dev_err(&interface->dev, "Unable to allocate minor number.\n");
|
||||
usb_set_intfdata(interface, NULL);
|
||||
idmouse_delete(dev);
|
||||
return result;
|
||||
}
|
||||
@ -392,19 +376,13 @@ static int idmouse_probe(struct usb_interface *interface,
|
||||
|
||||
static void idmouse_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct usb_idmouse *dev;
|
||||
|
||||
/* get device structure */
|
||||
dev = usb_get_intfdata(interface);
|
||||
struct usb_idmouse *dev = usb_get_intfdata(interface);
|
||||
|
||||
/* give back our minor */
|
||||
usb_deregister_dev(interface, &idmouse_class);
|
||||
|
||||
mutex_lock(&open_disc_mutex);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
/* lock the device */
|
||||
mutex_lock(&dev->lock);
|
||||
mutex_unlock(&open_disc_mutex);
|
||||
|
||||
/* prevent device read, write and ioctl */
|
||||
dev->present = 0;
|
||||
|
@ -157,19 +157,19 @@ MODULE_PARM_DESC(interrupt_out_interval, "Interrupt out interval in ms");
|
||||
#define LEGO_USB_TOWER_REQUEST_GET_VERSION 0xFD
|
||||
|
||||
struct tower_reset_reply {
|
||||
__le16 size; /* little-endian */
|
||||
__le16 size;
|
||||
__u8 err_code;
|
||||
__u8 spare;
|
||||
} __attribute__ ((packed));
|
||||
};
|
||||
|
||||
struct tower_get_version_reply {
|
||||
__le16 size; /* little-endian */
|
||||
__le16 size;
|
||||
__u8 err_code;
|
||||
__u8 spare;
|
||||
__u8 major;
|
||||
__u8 minor;
|
||||
__le16 build_no; /* little-endian */
|
||||
} __attribute__ ((packed));
|
||||
__le16 build_no;
|
||||
};
|
||||
|
||||
|
||||
/* table of devices that work with this driver */
|
||||
@ -178,7 +178,7 @@ static const struct usb_device_id tower_table[] = {
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE (usb, tower_table);
|
||||
MODULE_DEVICE_TABLE(usb, tower_table);
|
||||
|
||||
#define LEGO_USB_TOWER_MINOR_BASE 160
|
||||
|
||||
@ -186,13 +186,13 @@ MODULE_DEVICE_TABLE (usb, tower_table);
|
||||
/* Structure to hold all of our device specific stuff */
|
||||
struct lego_usb_tower {
|
||||
struct mutex lock; /* locks this structure */
|
||||
struct usb_device* udev; /* save off the usb device pointer */
|
||||
struct usb_device *udev; /* save off the usb device pointer */
|
||||
unsigned char minor; /* the starting minor number for this device */
|
||||
|
||||
int open_count; /* number of times this port has been opened */
|
||||
unsigned long disconnected:1;
|
||||
|
||||
char* read_buffer;
|
||||
char *read_buffer;
|
||||
size_t read_buffer_length; /* this much came in */
|
||||
size_t read_packet_length; /* this much will be returned on read */
|
||||
spinlock_t read_buffer_lock;
|
||||
@ -202,16 +202,15 @@ struct lego_usb_tower {
|
||||
wait_queue_head_t read_wait;
|
||||
wait_queue_head_t write_wait;
|
||||
|
||||
char* interrupt_in_buffer;
|
||||
struct usb_endpoint_descriptor* interrupt_in_endpoint;
|
||||
struct urb* interrupt_in_urb;
|
||||
char *interrupt_in_buffer;
|
||||
struct usb_endpoint_descriptor *interrupt_in_endpoint;
|
||||
struct urb *interrupt_in_urb;
|
||||
int interrupt_in_interval;
|
||||
int interrupt_in_running;
|
||||
int interrupt_in_done;
|
||||
|
||||
char* interrupt_out_buffer;
|
||||
struct usb_endpoint_descriptor* interrupt_out_endpoint;
|
||||
struct urb* interrupt_out_urb;
|
||||
char *interrupt_out_buffer;
|
||||
struct usb_endpoint_descriptor *interrupt_out_endpoint;
|
||||
struct urb *interrupt_out_urb;
|
||||
int interrupt_out_interval;
|
||||
int interrupt_out_busy;
|
||||
|
||||
@ -219,21 +218,20 @@ struct lego_usb_tower {
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, loff_t *ppos);
|
||||
static ssize_t tower_write (struct file *file, const char __user *buffer, size_t count, loff_t *ppos);
|
||||
static inline void tower_delete (struct lego_usb_tower *dev);
|
||||
static int tower_open (struct inode *inode, struct file *file);
|
||||
static int tower_release (struct inode *inode, struct file *file);
|
||||
static __poll_t tower_poll (struct file *file, poll_table *wait);
|
||||
static loff_t tower_llseek (struct file *file, loff_t off, int whence);
|
||||
static ssize_t tower_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos);
|
||||
static ssize_t tower_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos);
|
||||
static inline void tower_delete(struct lego_usb_tower *dev);
|
||||
static int tower_open(struct inode *inode, struct file *file);
|
||||
static int tower_release(struct inode *inode, struct file *file);
|
||||
static __poll_t tower_poll(struct file *file, poll_table *wait);
|
||||
static loff_t tower_llseek(struct file *file, loff_t off, int whence);
|
||||
|
||||
static void tower_abort_transfers (struct lego_usb_tower *dev);
|
||||
static void tower_check_for_read_packet (struct lego_usb_tower *dev);
|
||||
static void tower_interrupt_in_callback (struct urb *urb);
|
||||
static void tower_interrupt_out_callback (struct urb *urb);
|
||||
static void tower_check_for_read_packet(struct lego_usb_tower *dev);
|
||||
static void tower_interrupt_in_callback(struct urb *urb);
|
||||
static void tower_interrupt_out_callback(struct urb *urb);
|
||||
|
||||
static int tower_probe (struct usb_interface *interface, const struct usb_device_id *id);
|
||||
static void tower_disconnect (struct usb_interface *interface);
|
||||
static int tower_probe(struct usb_interface *interface, const struct usb_device_id *id);
|
||||
static void tower_disconnect(struct usb_interface *interface);
|
||||
|
||||
|
||||
/* file operations needed when we register this driver */
|
||||
@ -288,23 +286,23 @@ static inline void lego_usb_tower_debug_data(struct device *dev,
|
||||
/**
|
||||
* tower_delete
|
||||
*/
|
||||
static inline void tower_delete (struct lego_usb_tower *dev)
|
||||
static inline void tower_delete(struct lego_usb_tower *dev)
|
||||
{
|
||||
/* free data structures */
|
||||
usb_free_urb(dev->interrupt_in_urb);
|
||||
usb_free_urb(dev->interrupt_out_urb);
|
||||
kfree (dev->read_buffer);
|
||||
kfree (dev->interrupt_in_buffer);
|
||||
kfree (dev->interrupt_out_buffer);
|
||||
kfree(dev->read_buffer);
|
||||
kfree(dev->interrupt_in_buffer);
|
||||
kfree(dev->interrupt_out_buffer);
|
||||
usb_put_dev(dev->udev);
|
||||
kfree (dev);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tower_open
|
||||
*/
|
||||
static int tower_open (struct inode *inode, struct file *file)
|
||||
static int tower_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct lego_usb_tower *dev = NULL;
|
||||
int subminor;
|
||||
@ -314,7 +312,6 @@ static int tower_open (struct inode *inode, struct file *file)
|
||||
int result;
|
||||
|
||||
reset_reply = kmalloc(sizeof(*reset_reply), GFP_KERNEL);
|
||||
|
||||
if (!reset_reply) {
|
||||
retval = -ENOMEM;
|
||||
goto exit;
|
||||
@ -323,8 +320,7 @@ static int tower_open (struct inode *inode, struct file *file)
|
||||
nonseekable_open(inode, file);
|
||||
subminor = iminor(inode);
|
||||
|
||||
interface = usb_find_interface (&tower_driver, subminor);
|
||||
|
||||
interface = usb_find_interface(&tower_driver, subminor);
|
||||
if (!interface) {
|
||||
pr_err("error, can't find device for minor %d\n", subminor);
|
||||
retval = -ENODEV;
|
||||
@ -351,15 +347,15 @@ static int tower_open (struct inode *inode, struct file *file)
|
||||
}
|
||||
|
||||
/* reset the tower */
|
||||
result = usb_control_msg (dev->udev,
|
||||
usb_rcvctrlpipe(dev->udev, 0),
|
||||
LEGO_USB_TOWER_REQUEST_RESET,
|
||||
USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
|
||||
0,
|
||||
0,
|
||||
reset_reply,
|
||||
sizeof(*reset_reply),
|
||||
1000);
|
||||
result = usb_control_msg(dev->udev,
|
||||
usb_rcvctrlpipe(dev->udev, 0),
|
||||
LEGO_USB_TOWER_REQUEST_RESET,
|
||||
USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
|
||||
0,
|
||||
0,
|
||||
reset_reply,
|
||||
sizeof(*reset_reply),
|
||||
1000);
|
||||
if (result < 0) {
|
||||
dev_err(&dev->udev->dev,
|
||||
"LEGO USB Tower reset control request failed\n");
|
||||
@ -370,24 +366,22 @@ static int tower_open (struct inode *inode, struct file *file)
|
||||
/* initialize in direction */
|
||||
dev->read_buffer_length = 0;
|
||||
dev->read_packet_length = 0;
|
||||
usb_fill_int_urb (dev->interrupt_in_urb,
|
||||
dev->udev,
|
||||
usb_rcvintpipe(dev->udev, dev->interrupt_in_endpoint->bEndpointAddress),
|
||||
dev->interrupt_in_buffer,
|
||||
usb_endpoint_maxp(dev->interrupt_in_endpoint),
|
||||
tower_interrupt_in_callback,
|
||||
dev,
|
||||
dev->interrupt_in_interval);
|
||||
usb_fill_int_urb(dev->interrupt_in_urb,
|
||||
dev->udev,
|
||||
usb_rcvintpipe(dev->udev, dev->interrupt_in_endpoint->bEndpointAddress),
|
||||
dev->interrupt_in_buffer,
|
||||
usb_endpoint_maxp(dev->interrupt_in_endpoint),
|
||||
tower_interrupt_in_callback,
|
||||
dev,
|
||||
dev->interrupt_in_interval);
|
||||
|
||||
dev->interrupt_in_running = 1;
|
||||
dev->interrupt_in_done = 0;
|
||||
mb();
|
||||
|
||||
retval = usb_submit_urb (dev->interrupt_in_urb, GFP_KERNEL);
|
||||
retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
|
||||
if (retval) {
|
||||
dev_err(&dev->udev->dev,
|
||||
"Couldn't submit interrupt_in_urb %d\n", retval);
|
||||
dev->interrupt_in_running = 0;
|
||||
goto unlock_exit;
|
||||
}
|
||||
|
||||
@ -407,13 +401,12 @@ exit:
|
||||
/**
|
||||
* tower_release
|
||||
*/
|
||||
static int tower_release (struct inode *inode, struct file *file)
|
||||
static int tower_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct lego_usb_tower *dev;
|
||||
int retval = 0;
|
||||
|
||||
dev = file->private_data;
|
||||
|
||||
if (dev == NULL) {
|
||||
retval = -ENODEV;
|
||||
goto exit;
|
||||
@ -421,56 +414,32 @@ static int tower_release (struct inode *inode, struct file *file)
|
||||
|
||||
mutex_lock(&dev->lock);
|
||||
|
||||
if (dev->open_count != 1) {
|
||||
dev_dbg(&dev->udev->dev, "%s: device not opened exactly once\n",
|
||||
__func__);
|
||||
retval = -ENODEV;
|
||||
goto unlock_exit;
|
||||
}
|
||||
|
||||
if (dev->disconnected) {
|
||||
/* the device was unplugged before the file was released */
|
||||
|
||||
/* unlock here as tower_delete frees dev */
|
||||
mutex_unlock(&dev->lock);
|
||||
tower_delete (dev);
|
||||
tower_delete(dev);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* wait until write transfer is finished */
|
||||
if (dev->interrupt_out_busy) {
|
||||
wait_event_interruptible_timeout (dev->write_wait, !dev->interrupt_out_busy, 2 * HZ);
|
||||
wait_event_interruptible_timeout(dev->write_wait, !dev->interrupt_out_busy,
|
||||
2 * HZ);
|
||||
}
|
||||
tower_abort_transfers (dev);
|
||||
|
||||
/* shutdown transfers */
|
||||
usb_kill_urb(dev->interrupt_in_urb);
|
||||
usb_kill_urb(dev->interrupt_out_urb);
|
||||
|
||||
dev->open_count = 0;
|
||||
|
||||
unlock_exit:
|
||||
mutex_unlock(&dev->lock);
|
||||
exit:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tower_abort_transfers
|
||||
* aborts transfers and frees associated data structures
|
||||
*/
|
||||
static void tower_abort_transfers (struct lego_usb_tower *dev)
|
||||
{
|
||||
if (dev == NULL)
|
||||
return;
|
||||
|
||||
/* shutdown transfer */
|
||||
if (dev->interrupt_in_running) {
|
||||
dev->interrupt_in_running = 0;
|
||||
mb();
|
||||
usb_kill_urb(dev->interrupt_in_urb);
|
||||
}
|
||||
if (dev->interrupt_out_busy)
|
||||
usb_kill_urb(dev->interrupt_out_urb);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tower_check_for_read_packet
|
||||
*
|
||||
@ -479,23 +448,23 @@ static void tower_abort_transfers (struct lego_usb_tower *dev)
|
||||
* until it has been there unchanged for at least
|
||||
* dev->packet_timeout_jiffies, or until the buffer is full.
|
||||
*/
|
||||
static void tower_check_for_read_packet (struct lego_usb_tower *dev)
|
||||
static void tower_check_for_read_packet(struct lego_usb_tower *dev)
|
||||
{
|
||||
spin_lock_irq (&dev->read_buffer_lock);
|
||||
spin_lock_irq(&dev->read_buffer_lock);
|
||||
if (!packet_timeout
|
||||
|| time_after(jiffies, dev->read_last_arrival + dev->packet_timeout_jiffies)
|
||||
|| dev->read_buffer_length == read_buffer_size) {
|
||||
dev->read_packet_length = dev->read_buffer_length;
|
||||
}
|
||||
dev->interrupt_in_done = 0;
|
||||
spin_unlock_irq (&dev->read_buffer_lock);
|
||||
spin_unlock_irq(&dev->read_buffer_lock);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tower_poll
|
||||
*/
|
||||
static __poll_t tower_poll (struct file *file, poll_table *wait)
|
||||
static __poll_t tower_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct lego_usb_tower *dev;
|
||||
__poll_t mask = 0;
|
||||
@ -509,12 +478,10 @@ static __poll_t tower_poll (struct file *file, poll_table *wait)
|
||||
poll_wait(file, &dev->write_wait, wait);
|
||||
|
||||
tower_check_for_read_packet(dev);
|
||||
if (dev->read_packet_length > 0) {
|
||||
if (dev->read_packet_length > 0)
|
||||
mask |= EPOLLIN | EPOLLRDNORM;
|
||||
}
|
||||
if (!dev->interrupt_out_busy) {
|
||||
if (!dev->interrupt_out_busy)
|
||||
mask |= EPOLLOUT | EPOLLWRNORM;
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
@ -523,7 +490,7 @@ static __poll_t tower_poll (struct file *file, poll_table *wait)
|
||||
/**
|
||||
* tower_llseek
|
||||
*/
|
||||
static loff_t tower_llseek (struct file *file, loff_t off, int whence)
|
||||
static loff_t tower_llseek(struct file *file, loff_t off, int whence)
|
||||
{
|
||||
return -ESPIPE; /* unseekable */
|
||||
}
|
||||
@ -532,7 +499,7 @@ static loff_t tower_llseek (struct file *file, loff_t off, int whence)
|
||||
/**
|
||||
* tower_read
|
||||
*/
|
||||
static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, loff_t *ppos)
|
||||
static ssize_t tower_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct lego_usb_tower *dev;
|
||||
size_t bytes_to_read;
|
||||
@ -551,7 +518,6 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count,
|
||||
/* verify that the device wasn't unplugged */
|
||||
if (dev->disconnected) {
|
||||
retval = -ENODEV;
|
||||
pr_err("No device or device unplugged %d\n", retval);
|
||||
goto unlock_exit;
|
||||
}
|
||||
|
||||
@ -561,21 +527,19 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count,
|
||||
goto unlock_exit;
|
||||
}
|
||||
|
||||
if (read_timeout) {
|
||||
if (read_timeout)
|
||||
timeout = jiffies + msecs_to_jiffies(read_timeout);
|
||||
}
|
||||
|
||||
/* wait for data */
|
||||
tower_check_for_read_packet (dev);
|
||||
tower_check_for_read_packet(dev);
|
||||
while (dev->read_packet_length == 0) {
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
retval = -EAGAIN;
|
||||
goto unlock_exit;
|
||||
}
|
||||
retval = wait_event_interruptible_timeout(dev->read_wait, dev->interrupt_in_done, dev->packet_timeout_jiffies);
|
||||
if (retval < 0) {
|
||||
if (retval < 0)
|
||||
goto unlock_exit;
|
||||
}
|
||||
|
||||
/* reset read timeout during read or write activity */
|
||||
if (read_timeout
|
||||
@ -583,28 +547,27 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count,
|
||||
timeout = jiffies + msecs_to_jiffies(read_timeout);
|
||||
}
|
||||
/* check for read timeout */
|
||||
if (read_timeout && time_after (jiffies, timeout)) {
|
||||
if (read_timeout && time_after(jiffies, timeout)) {
|
||||
retval = -ETIMEDOUT;
|
||||
goto unlock_exit;
|
||||
}
|
||||
tower_check_for_read_packet (dev);
|
||||
tower_check_for_read_packet(dev);
|
||||
}
|
||||
|
||||
/* copy the data from read_buffer into userspace */
|
||||
bytes_to_read = min(count, dev->read_packet_length);
|
||||
|
||||
if (copy_to_user (buffer, dev->read_buffer, bytes_to_read)) {
|
||||
if (copy_to_user(buffer, dev->read_buffer, bytes_to_read)) {
|
||||
retval = -EFAULT;
|
||||
goto unlock_exit;
|
||||
}
|
||||
|
||||
spin_lock_irq (&dev->read_buffer_lock);
|
||||
spin_lock_irq(&dev->read_buffer_lock);
|
||||
dev->read_buffer_length -= bytes_to_read;
|
||||
dev->read_packet_length -= bytes_to_read;
|
||||
for (i=0; i<dev->read_buffer_length; i++) {
|
||||
for (i = 0; i < dev->read_buffer_length; i++)
|
||||
dev->read_buffer[i] = dev->read_buffer[i+bytes_to_read];
|
||||
}
|
||||
spin_unlock_irq (&dev->read_buffer_lock);
|
||||
spin_unlock_irq(&dev->read_buffer_lock);
|
||||
|
||||
retval = bytes_to_read;
|
||||
|
||||
@ -620,7 +583,7 @@ exit:
|
||||
/**
|
||||
* tower_write
|
||||
*/
|
||||
static ssize_t tower_write (struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
|
||||
static ssize_t tower_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct lego_usb_tower *dev;
|
||||
size_t bytes_to_write;
|
||||
@ -637,7 +600,6 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
|
||||
/* verify that the device wasn't unplugged */
|
||||
if (dev->disconnected) {
|
||||
retval = -ENODEV;
|
||||
pr_err("No device or device unplugged %d\n", retval);
|
||||
goto unlock_exit;
|
||||
}
|
||||
|
||||
@ -653,10 +615,10 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
|
||||
retval = -EAGAIN;
|
||||
goto unlock_exit;
|
||||
}
|
||||
retval = wait_event_interruptible (dev->write_wait, !dev->interrupt_out_busy);
|
||||
if (retval) {
|
||||
retval = wait_event_interruptible(dev->write_wait,
|
||||
!dev->interrupt_out_busy);
|
||||
if (retval)
|
||||
goto unlock_exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* write the data into interrupt_out_buffer from userspace */
|
||||
@ -664,7 +626,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
|
||||
dev_dbg(&dev->udev->dev, "%s: count = %zd, bytes_to_write = %zd\n",
|
||||
__func__, count, bytes_to_write);
|
||||
|
||||
if (copy_from_user (dev->interrupt_out_buffer, buffer, bytes_to_write)) {
|
||||
if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) {
|
||||
retval = -EFAULT;
|
||||
goto unlock_exit;
|
||||
}
|
||||
@ -682,7 +644,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
|
||||
dev->interrupt_out_busy = 1;
|
||||
wmb();
|
||||
|
||||
retval = usb_submit_urb (dev->interrupt_out_urb, GFP_KERNEL);
|
||||
retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
|
||||
if (retval) {
|
||||
dev->interrupt_out_busy = 0;
|
||||
dev_err(&dev->udev->dev,
|
||||
@ -703,7 +665,7 @@ exit:
|
||||
/**
|
||||
* tower_interrupt_in_callback
|
||||
*/
|
||||
static void tower_interrupt_in_callback (struct urb *urb)
|
||||
static void tower_interrupt_in_callback(struct urb *urb)
|
||||
{
|
||||
struct lego_usb_tower *dev = urb->context;
|
||||
int status = urb->status;
|
||||
@ -729,9 +691,9 @@ static void tower_interrupt_in_callback (struct urb *urb)
|
||||
if (urb->actual_length > 0) {
|
||||
spin_lock_irqsave(&dev->read_buffer_lock, flags);
|
||||
if (dev->read_buffer_length + urb->actual_length < read_buffer_size) {
|
||||
memcpy (dev->read_buffer + dev->read_buffer_length,
|
||||
dev->interrupt_in_buffer,
|
||||
urb->actual_length);
|
||||
memcpy(dev->read_buffer + dev->read_buffer_length,
|
||||
dev->interrupt_in_buffer,
|
||||
urb->actual_length);
|
||||
dev->read_buffer_length += urb->actual_length;
|
||||
dev->read_last_arrival = jiffies;
|
||||
dev_dbg(&dev->udev->dev, "%s: received %d bytes\n",
|
||||
@ -744,25 +706,21 @@ static void tower_interrupt_in_callback (struct urb *urb)
|
||||
}
|
||||
|
||||
resubmit:
|
||||
/* resubmit if we're still running */
|
||||
if (dev->interrupt_in_running) {
|
||||
retval = usb_submit_urb (dev->interrupt_in_urb, GFP_ATOMIC);
|
||||
if (retval)
|
||||
dev_err(&dev->udev->dev,
|
||||
"%s: usb_submit_urb failed (%d)\n",
|
||||
__func__, retval);
|
||||
retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC);
|
||||
if (retval) {
|
||||
dev_err(&dev->udev->dev, "%s: usb_submit_urb failed (%d)\n",
|
||||
__func__, retval);
|
||||
}
|
||||
|
||||
exit:
|
||||
dev->interrupt_in_done = 1;
|
||||
wake_up_interruptible (&dev->read_wait);
|
||||
wake_up_interruptible(&dev->read_wait);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tower_interrupt_out_callback
|
||||
*/
|
||||
static void tower_interrupt_out_callback (struct urb *urb)
|
||||
static void tower_interrupt_out_callback(struct urb *urb)
|
||||
{
|
||||
struct lego_usb_tower *dev = urb->context;
|
||||
int status = urb->status;
|
||||
@ -790,48 +748,27 @@ static void tower_interrupt_out_callback (struct urb *urb)
|
||||
* Called by the usb core when a new device is connected that it thinks
|
||||
* this driver might be interested in.
|
||||
*/
|
||||
static int tower_probe (struct usb_interface *interface, const struct usb_device_id *id)
|
||||
static int tower_probe(struct usb_interface *interface, const struct usb_device_id *id)
|
||||
{
|
||||
struct device *idev = &interface->dev;
|
||||
struct usb_device *udev = interface_to_usbdev(interface);
|
||||
struct lego_usb_tower *dev = NULL;
|
||||
struct lego_usb_tower *dev;
|
||||
struct tower_get_version_reply *get_version_reply = NULL;
|
||||
int retval = -ENOMEM;
|
||||
int result;
|
||||
|
||||
/* allocate memory for our device state and initialize it */
|
||||
|
||||
dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL);
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
goto exit;
|
||||
|
||||
mutex_init(&dev->lock);
|
||||
|
||||
dev->udev = usb_get_dev(udev);
|
||||
dev->open_count = 0;
|
||||
dev->disconnected = 0;
|
||||
|
||||
dev->read_buffer = NULL;
|
||||
dev->read_buffer_length = 0;
|
||||
dev->read_packet_length = 0;
|
||||
spin_lock_init (&dev->read_buffer_lock);
|
||||
spin_lock_init(&dev->read_buffer_lock);
|
||||
dev->packet_timeout_jiffies = msecs_to_jiffies(packet_timeout);
|
||||
dev->read_last_arrival = jiffies;
|
||||
|
||||
init_waitqueue_head (&dev->read_wait);
|
||||
init_waitqueue_head (&dev->write_wait);
|
||||
|
||||
dev->interrupt_in_buffer = NULL;
|
||||
dev->interrupt_in_endpoint = NULL;
|
||||
dev->interrupt_in_urb = NULL;
|
||||
dev->interrupt_in_running = 0;
|
||||
dev->interrupt_in_done = 0;
|
||||
|
||||
dev->interrupt_out_buffer = NULL;
|
||||
dev->interrupt_out_endpoint = NULL;
|
||||
dev->interrupt_out_urb = NULL;
|
||||
dev->interrupt_out_busy = 0;
|
||||
init_waitqueue_head(&dev->read_wait);
|
||||
init_waitqueue_head(&dev->write_wait);
|
||||
|
||||
result = usb_find_common_endpoints_reverse(interface->cur_altsetting,
|
||||
NULL, NULL,
|
||||
@ -843,16 +780,16 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
|
||||
goto error;
|
||||
}
|
||||
|
||||
dev->read_buffer = kmalloc (read_buffer_size, GFP_KERNEL);
|
||||
dev->read_buffer = kmalloc(read_buffer_size, GFP_KERNEL);
|
||||
if (!dev->read_buffer)
|
||||
goto error;
|
||||
dev->interrupt_in_buffer = kmalloc (usb_endpoint_maxp(dev->interrupt_in_endpoint), GFP_KERNEL);
|
||||
dev->interrupt_in_buffer = kmalloc(usb_endpoint_maxp(dev->interrupt_in_endpoint), GFP_KERNEL);
|
||||
if (!dev->interrupt_in_buffer)
|
||||
goto error;
|
||||
dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!dev->interrupt_in_urb)
|
||||
goto error;
|
||||
dev->interrupt_out_buffer = kmalloc (write_buffer_size, GFP_KERNEL);
|
||||
dev->interrupt_out_buffer = kmalloc(write_buffer_size, GFP_KERNEL);
|
||||
if (!dev->interrupt_out_buffer)
|
||||
goto error;
|
||||
dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
@ -862,22 +799,21 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
|
||||
dev->interrupt_out_interval = interrupt_out_interval ? interrupt_out_interval : dev->interrupt_out_endpoint->bInterval;
|
||||
|
||||
get_version_reply = kmalloc(sizeof(*get_version_reply), GFP_KERNEL);
|
||||
|
||||
if (!get_version_reply) {
|
||||
retval = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* get the firmware version and log it */
|
||||
result = usb_control_msg (udev,
|
||||
usb_rcvctrlpipe(udev, 0),
|
||||
LEGO_USB_TOWER_REQUEST_GET_VERSION,
|
||||
USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
|
||||
0,
|
||||
0,
|
||||
get_version_reply,
|
||||
sizeof(*get_version_reply),
|
||||
1000);
|
||||
result = usb_control_msg(udev,
|
||||
usb_rcvctrlpipe(udev, 0),
|
||||
LEGO_USB_TOWER_REQUEST_GET_VERSION,
|
||||
USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
|
||||
0,
|
||||
0,
|
||||
get_version_reply,
|
||||
sizeof(*get_version_reply),
|
||||
1000);
|
||||
if (result != sizeof(*get_version_reply)) {
|
||||
if (result >= 0)
|
||||
result = -EIO;
|
||||
@ -892,10 +828,9 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
|
||||
le16_to_cpu(get_version_reply->build_no));
|
||||
|
||||
/* we can register the device now, as it is ready */
|
||||
usb_set_intfdata (interface, dev);
|
||||
|
||||
retval = usb_register_dev (interface, &tower_class);
|
||||
usb_set_intfdata(interface, dev);
|
||||
|
||||
retval = usb_register_dev(interface, &tower_class);
|
||||
if (retval) {
|
||||
/* something prevented us from registering this driver */
|
||||
dev_err(idev, "Not able to get a minor for this device.\n");
|
||||
@ -924,17 +859,17 @@ error:
|
||||
*
|
||||
* Called by the usb core when the device is removed from the system.
|
||||
*/
|
||||
static void tower_disconnect (struct usb_interface *interface)
|
||||
static void tower_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct lego_usb_tower *dev;
|
||||
int minor;
|
||||
|
||||
dev = usb_get_intfdata (interface);
|
||||
dev = usb_get_intfdata(interface);
|
||||
|
||||
minor = dev->minor;
|
||||
|
||||
/* give back our minor and prevent further open() */
|
||||
usb_deregister_dev (interface, &tower_class);
|
||||
usb_deregister_dev(interface, &tower_class);
|
||||
|
||||
/* stop I/O */
|
||||
usb_poison_urb(dev->interrupt_in_urb);
|
||||
@ -945,7 +880,7 @@ static void tower_disconnect (struct usb_interface *interface)
|
||||
/* if the device is not opened, then we clean up right now */
|
||||
if (!dev->open_count) {
|
||||
mutex_unlock(&dev->lock);
|
||||
tower_delete (dev);
|
||||
tower_delete(dev);
|
||||
} else {
|
||||
dev->disconnected = 1;
|
||||
/* wake up pollers */
|
||||
@ -962,6 +897,4 @@ module_usb_driver(tower_driver);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
#ifdef MODULE_LICENSE
|
||||
MODULE_LICENSE("GPL");
|
||||
#endif
|
||||
|
@ -4,7 +4,7 @@ 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---
|
||||
---help---
|
||||
Say Y here if you intend to attach a USB2VGA dongle based on a
|
||||
Net2280 and a SiS315 chip.
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* Internal Register Set Addresses & Default Values acc. to DS00001692C */
|
||||
@ -26,10 +27,6 @@
|
||||
|
||||
#define USB251XB_ADDR_PRODUCT_ID_LSB 0x02
|
||||
#define USB251XB_ADDR_PRODUCT_ID_MSB 0x03
|
||||
#define USB251XB_DEF_PRODUCT_ID_12 0x2512 /* USB2512B/12Bi */
|
||||
#define USB251XB_DEF_PRODUCT_ID_13 0x2513 /* USB2513B/13Bi */
|
||||
#define USB251XB_DEF_PRODUCT_ID_14 0x2514 /* USB2514B/14Bi */
|
||||
#define USB251XB_DEF_PRODUCT_ID_17 0x2517 /* USB2517/17i */
|
||||
|
||||
#define USB251XB_ADDR_DEVICE_ID_LSB 0x04
|
||||
#define USB251XB_ADDR_DEVICE_ID_MSB 0x05
|
||||
@ -74,7 +71,6 @@
|
||||
|
||||
#define USB251XB_ADDR_PRODUCT_STRING_LEN 0x14
|
||||
#define USB251XB_ADDR_PRODUCT_STRING 0x54
|
||||
#define USB251XB_DEF_PRODUCT_STRING "USB251xB/xBi/7i"
|
||||
|
||||
#define USB251XB_ADDR_SERIAL_STRING_LEN 0x15
|
||||
#define USB251XB_ADDR_SERIAL_STRING 0x92
|
||||
@ -116,6 +112,7 @@
|
||||
struct usb251xb {
|
||||
struct device *dev;
|
||||
struct i2c_client *i2c;
|
||||
struct regulator *vdd;
|
||||
u8 skip_config;
|
||||
struct gpio_desc *gpio_reset;
|
||||
u16 vendor_id;
|
||||
@ -159,6 +156,14 @@ struct usb251xb_data {
|
||||
char product_str[USB251XB_STRING_BUFSIZE / 2]; /* ASCII string */
|
||||
};
|
||||
|
||||
static const struct usb251xb_data usb2422_data = {
|
||||
.product_id = 0x2422,
|
||||
.port_cnt = 2,
|
||||
.led_support = false,
|
||||
.bat_support = true,
|
||||
.product_str = "USB2422",
|
||||
};
|
||||
|
||||
static const struct usb251xb_data usb2512b_data = {
|
||||
.product_id = 0x2512,
|
||||
.port_cnt = 2,
|
||||
@ -261,20 +266,19 @@ static int usb251x_check_gpio_chip(struct usb251xb *hub)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void usb251xb_reset(struct usb251xb *hub, int state)
|
||||
static void usb251xb_reset(struct usb251xb *hub)
|
||||
{
|
||||
if (!hub->gpio_reset)
|
||||
return;
|
||||
|
||||
i2c_lock_bus(hub->i2c->adapter, I2C_LOCK_SEGMENT);
|
||||
|
||||
gpiod_set_value_cansleep(hub->gpio_reset, state);
|
||||
gpiod_set_value_cansleep(hub->gpio_reset, 1);
|
||||
usleep_range(1, 10); /* >=1us RESET_N asserted */
|
||||
gpiod_set_value_cansleep(hub->gpio_reset, 0);
|
||||
|
||||
/* wait for hub recovery/stabilization */
|
||||
if (!state)
|
||||
usleep_range(500, 750); /* >=500us at power on */
|
||||
else
|
||||
usleep_range(1, 10); /* >=1us at power down */
|
||||
usleep_range(500, 750); /* >=500us after RESET_N deasserted */
|
||||
|
||||
i2c_unlock_bus(hub->i2c->adapter, I2C_LOCK_SEGMENT);
|
||||
}
|
||||
@ -292,7 +296,7 @@ static int usb251xb_connect(struct usb251xb *hub)
|
||||
i2c_wb[0] = 0x01;
|
||||
i2c_wb[1] = USB251XB_STATUS_COMMAND_ATTACH;
|
||||
|
||||
usb251xb_reset(hub, 0);
|
||||
usb251xb_reset(hub);
|
||||
|
||||
err = i2c_smbus_write_i2c_block_data(hub->i2c,
|
||||
USB251XB_ADDR_STATUS_COMMAND, 2, i2c_wb);
|
||||
@ -342,7 +346,7 @@ static int usb251xb_connect(struct usb251xb *hub)
|
||||
i2c_wb[USB251XB_ADDR_PORT_MAP_7] = hub->port_map7;
|
||||
i2c_wb[USB251XB_ADDR_STATUS_COMMAND] = USB251XB_STATUS_COMMAND_ATTACH;
|
||||
|
||||
usb251xb_reset(hub, 0);
|
||||
usb251xb_reset(hub);
|
||||
|
||||
/* write registers */
|
||||
for (i = 0; i < (USB251XB_I2C_REG_SZ / USB251XB_I2C_WRITE_SZ); i++) {
|
||||
@ -420,6 +424,10 @@ static int usb251xb_get_ofdata(struct usb251xb *hub,
|
||||
return err;
|
||||
}
|
||||
|
||||
hub->vdd = devm_regulator_get(dev, "vdd");
|
||||
if (IS_ERR(hub->vdd))
|
||||
return PTR_ERR(hub->vdd);
|
||||
|
||||
if (of_property_read_u16_array(np, "vendor-id", &hub->vendor_id, 1))
|
||||
hub->vendor_id = USB251XB_DEF_VENDOR_ID;
|
||||
|
||||
@ -593,6 +601,9 @@ static int usb251xb_get_ofdata(struct usb251xb *hub,
|
||||
|
||||
static const struct of_device_id usb251xb_of_match[] = {
|
||||
{
|
||||
.compatible = "microchip,usb2422",
|
||||
.data = &usb2422_data,
|
||||
}, {
|
||||
.compatible = "microchip,usb2512b",
|
||||
.data = &usb2512b_data,
|
||||
}, {
|
||||
@ -665,6 +676,10 @@ static int usb251xb_probe(struct usb251xb *hub)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regulator_enable(hub->vdd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = usb251xb_connect(hub);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to connect hub (%d)\n", err);
|
||||
@ -692,7 +707,31 @@ static int usb251xb_i2c_probe(struct i2c_client *i2c,
|
||||
return usb251xb_probe(hub);
|
||||
}
|
||||
|
||||
static int __maybe_unused usb251xb_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct usb251xb *hub = i2c_get_clientdata(client);
|
||||
|
||||
return regulator_disable(hub->vdd);
|
||||
}
|
||||
|
||||
static int __maybe_unused usb251xb_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct usb251xb *hub = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
err = regulator_enable(hub->vdd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return usb251xb_connect(hub);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(usb251xb_pm_ops, usb251xb_suspend, usb251xb_resume);
|
||||
|
||||
static const struct i2c_device_id usb251xb_id[] = {
|
||||
{ "usb2422", 0 },
|
||||
{ "usb2512b", 0 },
|
||||
{ "usb2512bi", 0 },
|
||||
{ "usb2513b", 0 },
|
||||
@ -709,6 +748,7 @@ static struct i2c_driver usb251xb_i2c_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = of_match_ptr(usb251xb_of_match),
|
||||
.pm = &usb251xb_pm_ops,
|
||||
},
|
||||
.probe = usb251xb_i2c_probe,
|
||||
.id_table = usb251xb_id,
|
||||
|
@ -153,6 +153,15 @@ static void ep0_stall_set(struct mtu3_ep *mep0, bool set, u32 pktrdy)
|
||||
set ? "SEND" : "CLEAR", decode_ep0_state(mtu));
|
||||
}
|
||||
|
||||
static void ep0_do_status_stage(struct mtu3 *mtu)
|
||||
{
|
||||
void __iomem *mbase = mtu->mac_base;
|
||||
u32 value;
|
||||
|
||||
value = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS;
|
||||
mtu3_writel(mbase, U3D_EP0CSR, value | EP0_SETUPPKTRDY | EP0_DATAEND);
|
||||
}
|
||||
|
||||
static int ep0_queue(struct mtu3_ep *mep0, struct mtu3_request *mreq);
|
||||
|
||||
static void ep0_dummy_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
@ -297,8 +306,7 @@ static int handle_test_mode(struct mtu3 *mtu, struct usb_ctrlrequest *setup)
|
||||
ep0_load_test_packet(mtu);
|
||||
|
||||
/* send status before entering test mode. */
|
||||
value = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS;
|
||||
mtu3_writel(mbase, U3D_EP0CSR, value | EP0_SETUPPKTRDY | EP0_DATAEND);
|
||||
ep0_do_status_stage(mtu);
|
||||
|
||||
/* wait for ACK status sent by host */
|
||||
readl_poll_timeout_atomic(mbase + U3D_EP0CSR, value,
|
||||
@ -632,7 +640,6 @@ __acquires(mtu->lock)
|
||||
{
|
||||
struct usb_ctrlrequest setup;
|
||||
struct mtu3_request *mreq;
|
||||
void __iomem *mbase = mtu->mac_base;
|
||||
int handled = 0;
|
||||
|
||||
ep0_read_setup(mtu, &setup);
|
||||
@ -664,14 +671,19 @@ finish:
|
||||
if (mtu->test_mode) {
|
||||
; /* nothing to do */
|
||||
} else if (handled == USB_GADGET_DELAYED_STATUS) {
|
||||
/* handle the delay STATUS phase till receive ep_queue on ep0 */
|
||||
mtu->delayed_status = true;
|
||||
|
||||
mreq = next_ep0_request(mtu);
|
||||
if (mreq) {
|
||||
/* already asked us to continue delayed status */
|
||||
ep0_do_status_stage(mtu);
|
||||
ep0_req_giveback(mtu, &mreq->request);
|
||||
} else {
|
||||
/* do delayed STATUS stage till receive ep0_queue */
|
||||
mtu->delayed_status = true;
|
||||
}
|
||||
} else if (le16_to_cpu(setup.wLength) == 0) { /* no data stage */
|
||||
|
||||
mtu3_writel(mbase, U3D_EP0CSR,
|
||||
(mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS)
|
||||
| EP0_SETUPPKTRDY | EP0_DATAEND);
|
||||
|
||||
ep0_do_status_stage(mtu);
|
||||
/* complete zlp request directly */
|
||||
mreq = next_ep0_request(mtu);
|
||||
if (mreq && !mreq->request.length)
|
||||
@ -802,12 +814,9 @@ static int ep0_queue(struct mtu3_ep *mep, struct mtu3_request *mreq)
|
||||
}
|
||||
|
||||
if (mtu->delayed_status) {
|
||||
u32 csr;
|
||||
|
||||
mtu->delayed_status = false;
|
||||
csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS;
|
||||
csr |= EP0_SETUPPKTRDY | EP0_DATAEND;
|
||||
mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr);
|
||||
ep0_do_status_stage(mtu);
|
||||
/* needn't giveback the request for handling delay STATUS */
|
||||
return 0;
|
||||
}
|
||||
|
@ -2431,14 +2431,12 @@ static int musb_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
int irq = platform_get_irq_byname(pdev, "mc");
|
||||
struct resource *iomem;
|
||||
void __iomem *base;
|
||||
|
||||
if (irq <= 0)
|
||||
return -ENODEV;
|
||||
|
||||
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(dev, iomem);
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
|
@ -325,7 +325,7 @@ void musb_init_debugfs(struct musb *musb)
|
||||
{
|
||||
struct dentry *root;
|
||||
|
||||
root = debugfs_create_dir(dev_name(musb->controller), NULL);
|
||||
root = debugfs_create_dir(dev_name(musb->controller), usb_debug_root);
|
||||
musb->debugfs_root = root;
|
||||
|
||||
debugfs_create_file("regdump", S_IRUGO, root, musb, &musb_regdump_fops);
|
||||
|
@ -411,7 +411,7 @@ static int dsps_musb_dbg_init(struct musb *musb, struct dsps_glue *glue)
|
||||
char buf[128];
|
||||
|
||||
sprintf(buf, "%s.dsps", dev_name(musb->controller));
|
||||
root = debugfs_create_dir(buf, NULL);
|
||||
root = debugfs_create_dir(buf, usb_debug_root);
|
||||
glue->dbgfs_root = root;
|
||||
|
||||
glue->regset.regs = dsps_musb_regs;
|
||||
|
@ -1085,7 +1085,6 @@ static int musb_gadget_disable(struct usb_ep *ep)
|
||||
u8 epnum;
|
||||
struct musb_ep *musb_ep;
|
||||
void __iomem *epio;
|
||||
int status = 0;
|
||||
|
||||
musb_ep = to_musb_ep(ep);
|
||||
musb = musb_ep->musb;
|
||||
@ -1118,7 +1117,7 @@ static int musb_gadget_disable(struct usb_ep *ep)
|
||||
|
||||
musb_dbg(musb, "%s", musb_ep->end_point.name);
|
||||
|
||||
return status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1316,7 +1315,7 @@ done:
|
||||
}
|
||||
|
||||
/*
|
||||
* Set or clear the halt bit of an endpoint. A halted enpoint won't tx/rx any
|
||||
* Set or clear the halt bit of an endpoint. A halted endpoint won't tx/rx any
|
||||
* data but will queue requests.
|
||||
*
|
||||
* exported to ep0 code
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user