mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 06:31:52 +00:00
USB / Thunderbolt changes for 6.4-rc1
Here is the large set of USB and Thunderbolt changes for 6.4-rc1. "biggest" thing in here is the removal of two obsolete drivers, u132-hcd and ftdi-elan, making this a net-removal of code overall. Other than the driver removals, included in here are: - Thunderbolt updates for new hardware and features - xhci driver updates and fixes - dwc3 driver updates and fixes - gadget core and driver updates and features added - mtu3 driver updates - dwc2 driver fixes and updates - usb-serial driver updates - typec driver updates and fixes - platform remove callback changes - dts updates and conversions - other small changes All have been in linux-next for a while with no reported problems. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZEqC+g8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ynP6QCg0MnpRjOSFyAB0t9LWFng4rRikj4AoIpxvs2T GbU7NdPHU3fddq0KB+Nd =M+Ib -----END PGP SIGNATURE----- Merge tag 'usb-6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB / Thunderbolt updates from Greg KH: "Here is the large set of USB and Thunderbolt changes for 6.4-rc1. The "biggest" thing in here is the removal of two obsolete drivers, u132-hcd and ftdi-elan, making this a net-removal of code overall. Other than the driver removals, included in here are: - Thunderbolt updates for new hardware and features - xhci driver updates and fixes - dwc3 driver updates and fixes - gadget core and driver updates and features added - mtu3 driver updates - dwc2 driver fixes and updates - usb-serial driver updates - typec driver updates and fixes - platform remove callback changes - dts updates and conversions - other small changes All have been in linux-next for a while with no reported problems" * tag 'usb-6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (177 commits) usb: dwc3: gadget: Refactor EP0 forced stall/restart into a separate API usb: dwc3: gadget: Execute gadget stop after halting the controller media: radio-shark: Add endpoint checks USB: sisusbvga: Add endpoint checks USB: core: Add routines for endpoint checks in old drivers usb: dwc3: gadget: Stall and restart EP0 if host is unresponsive dt-bindings: usb: snps,dwc3: Add 'snps,parkmode-disable-hs-quirk' quirk usb: dwc3: core: add support for disabling High-speed park mode dt-bindings: usb: ci-hdrc-usb2: allow multiple PHYs usb: mtu3: add optional clock xhci_ck and frmcnt_ck dt-bindings: usb: mtu3: add two optional clocks usb: mtu3: expose role-switch control to userspace usb: mtu3: unlock @mtu->lock just before giving back request usb: mtu3: fix kernel panic at qmu transfer done irq handler usb: mtu3: use boolean return value usb: mtu3: give back request when rx error happens usb: chipidea: fix missing goto in `ci_hdrc_probe` usb: gadget: udc: core: Prevent redundant calls to pullup usb: gadget: udc: core: Invoke usb_gadget_connect only when started usb: typec: ucsi: don't print PPM init deferred errors ...
This commit is contained in:
commit
4010e62b5b
@ -76,7 +76,7 @@ Date: Dec 2014
|
||||
KernelVersion: 4.0
|
||||
Description: Default camera terminal descriptors
|
||||
|
||||
All attributes read only:
|
||||
All attributes read only except bmControls, which is read/write:
|
||||
|
||||
======================== ====================================
|
||||
bmControls bitmap specifying which controls are
|
||||
@ -101,7 +101,7 @@ Date: Dec 2014
|
||||
KernelVersion: 4.0
|
||||
Description: Default processing unit descriptors
|
||||
|
||||
All attributes read only:
|
||||
All attributes read only except bmControls, which is read/write:
|
||||
|
||||
=============== ========================================
|
||||
iProcessing index of string descriptor
|
||||
|
@ -23,3 +23,55 @@ Description:
|
||||
Reading this attribute gives the state of the DbC. It
|
||||
can be one of the following states: disabled, enabled,
|
||||
initialized, connected, configured and stalled.
|
||||
|
||||
What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_idVendor
|
||||
Date: March 2023
|
||||
Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
|
||||
Description:
|
||||
This dbc_idVendor attribute lets us change the idVendor field
|
||||
presented in the USB device descriptor by this xhci debug
|
||||
device.
|
||||
Value can only be changed while debug capability (DbC) is in
|
||||
disabled state to prevent USB device descriptor change while
|
||||
connected to a USB host.
|
||||
The default value is 0x1d6b (Linux Foundation).
|
||||
It can be any 16-bit integer.
|
||||
|
||||
What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_idProduct
|
||||
Date: March 2023
|
||||
Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
|
||||
Description:
|
||||
This dbc_idProduct attribute lets us change the idProduct field
|
||||
presented in the USB device descriptor by this xhci debug
|
||||
device.
|
||||
Value can only be changed while debug capability (DbC) is in
|
||||
disabled state to prevent USB device descriptor change while
|
||||
connected to a USB host.
|
||||
The default value is 0x0010. It can be any 16-bit integer.
|
||||
|
||||
What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_bcdDevice
|
||||
Date: March 2023
|
||||
Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
|
||||
Description:
|
||||
This dbc_bcdDevice attribute lets us change the bcdDevice field
|
||||
presented in the USB device descriptor by this xhci debug
|
||||
device.
|
||||
Value can only be changed while debug capability (DbC) is in
|
||||
disabled state to prevent USB device descriptor change while
|
||||
connected to a USB host.
|
||||
The default value is 0x0010. (device rev 0.10)
|
||||
It can be any 16-bit integer.
|
||||
|
||||
What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_bInterfaceProtocol
|
||||
Date: March 2023
|
||||
Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
|
||||
Description:
|
||||
This attribute lets us change the bInterfaceProtocol field
|
||||
presented in the USB Interface descriptor by the xhci debug
|
||||
device.
|
||||
Value can only be changed while debug capability (DbC) is in
|
||||
disabled state to prevent USB descriptor change while
|
||||
connected to a USB host.
|
||||
The default value is 1 (GNU Remote Debug command).
|
||||
Other permissible value is 0 which is for vendor defined debug
|
||||
target.
|
||||
|
@ -2,8 +2,8 @@
|
||||
# Copyright 2019 BayLibre, SAS
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/usb/amlogic,meson-g12a-usb-ctrl.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
$id: http://devicetree.org/schemas/usb/amlogic,meson-g12a-usb-ctrl.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Amlogic Meson G12A DWC3 USB SoC Controller Glue
|
||||
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Broadcom STB USB EHCI Controller
|
||||
|
||||
allOf:
|
||||
- $ref: "usb-hcd.yaml"
|
||||
- $ref: usb-hcd.yaml
|
||||
|
||||
maintainers:
|
||||
- Al Cooper <alcooperx@gmail.com>
|
||||
|
@ -1,159 +0,0 @@
|
||||
* USB2 ChipIdea USB controller for ci13xxx
|
||||
|
||||
Required properties:
|
||||
- compatible: should be one of:
|
||||
"fsl,imx23-usb"
|
||||
"fsl,imx27-usb"
|
||||
"fsl,imx28-usb"
|
||||
"fsl,imx6q-usb"
|
||||
"fsl,imx6sl-usb"
|
||||
"fsl,imx6sx-usb"
|
||||
"fsl,imx6ul-usb"
|
||||
"fsl,imx7d-usb"
|
||||
"fsl,imx7ulp-usb"
|
||||
"fsl,imx8mm-usb"
|
||||
"lsi,zevio-usb"
|
||||
"qcom,ci-hdrc"
|
||||
"chipidea,usb2"
|
||||
"xlnx,zynq-usb-2.20a"
|
||||
"nvidia,tegra20-udc"
|
||||
"nvidia,tegra30-udc"
|
||||
"nvidia,tegra114-udc"
|
||||
"nvidia,tegra124-udc"
|
||||
- reg: base address and length of the registers
|
||||
- interrupts: interrupt for the USB controller
|
||||
|
||||
Recommended properies:
|
||||
- phy_type: the type of the phy connected to the core. Should be one
|
||||
of "utmi", "utmi_wide", "ulpi", "serial" or "hsic". Without this
|
||||
property the PORTSC register won't be touched.
|
||||
- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg"
|
||||
|
||||
Deprecated properties:
|
||||
- usb-phy: phandle for the PHY device. Use "phys" instead.
|
||||
- fsl,usbphy: phandle of usb phy that connects to the port. Use "phys" instead.
|
||||
|
||||
Optional properties:
|
||||
- clocks: reference to the USB clock
|
||||
- phys: reference to the USB PHY
|
||||
- phy-names: should be "usb-phy"
|
||||
- vbus-supply: reference to the VBUS regulator
|
||||
- maximum-speed: limit the maximum connection speed to "full-speed".
|
||||
- tpl-support: TPL (Targeted Peripheral List) feature for targeted hosts
|
||||
- itc-setting: interrupt threshold control register control, the setting
|
||||
should be aligned with ITC bits at register USBCMD.
|
||||
- ahb-burst-config: it is vendor dependent, the required value should be
|
||||
aligned with AHBBRST at SBUSCFG, the range is from 0x0 to 0x7. This
|
||||
property is used to change AHB burst configuration, check the chipidea
|
||||
spec for meaning of each value. If this property is not existed, it
|
||||
will use the reset value.
|
||||
- tx-burst-size-dword: it is vendor dependent, the tx burst size in dword
|
||||
(4 bytes), This register represents the maximum length of a the burst
|
||||
in 32-bit words while moving data from system memory to the USB
|
||||
bus, the value of this property will only take effect if property
|
||||
"ahb-burst-config" is set to 0, if this property is missing the reset
|
||||
default of the hardware implementation will be used.
|
||||
- rx-burst-size-dword: it is vendor dependent, the rx burst size in dword
|
||||
(4 bytes), This register represents the maximum length of a the burst
|
||||
in 32-bit words while moving data from the USB bus to system memory,
|
||||
the value of this property will only take effect if property
|
||||
"ahb-burst-config" is set to 0, if this property is missing the reset
|
||||
default of the hardware implementation will be used.
|
||||
- extcon: phandles to external connector devices. First phandle should point to
|
||||
external connector, which provide "USB" cable events, the second should point
|
||||
to external connector device, which provide "USB-HOST" cable events. If one
|
||||
of the external connector devices is not required, empty <0> phandle should
|
||||
be specified.
|
||||
- phy-clkgate-delay-us: the delay time (us) between putting the PHY into
|
||||
low power mode and gating the PHY clock.
|
||||
- non-zero-ttctrl-ttha: after setting this property, the value of register
|
||||
ttctrl.ttha will be 0x7f; if not, the value will be 0x0, this is the default
|
||||
value. It needs to be very carefully for setting this property, it is
|
||||
recommended that consult with your IC engineer before setting this value.
|
||||
On the most of chipidea platforms, the "usage_tt" flag at RTL is 0, so this
|
||||
property only affects siTD.
|
||||
If this property is not set, the max packet size is 1023 bytes, and if
|
||||
the total of packet size for pervious transactions are more than 256 bytes,
|
||||
it can't accept any transactions within this frame. The use case is single
|
||||
transaction, but higher frame rate.
|
||||
If this property is set, the max packet size is 188 bytes, it can handle
|
||||
more transactions than above case, it can accept transactions until it
|
||||
considers the left room size within frame is less than 188 bytes, software
|
||||
needs to make sure it does not send more than 90%
|
||||
maximum_periodic_data_per_frame. The use case is multiple transactions, but
|
||||
less frame rate.
|
||||
- mux-controls: The mux control for toggling host/device output of this
|
||||
controller. It's expected that a mux state of 0 indicates device mode and a
|
||||
mux state of 1 indicates host mode.
|
||||
- mux-control-names: Shall be "usb_switch" if mux-controls is specified.
|
||||
- pinctrl-names: Names for optional pin modes in "default", "host", "device".
|
||||
In case of HSIC-mode, "idle" and "active" pin modes are mandatory. In this
|
||||
case, the "idle" state needs to pull down the data and strobe pin
|
||||
and the "active" state needs to pull up the strobe pin.
|
||||
- pinctrl-n: alternate pin modes
|
||||
|
||||
i.mx specific properties
|
||||
- fsl,usbmisc: phandler of non-core register device, with one
|
||||
argument that indicate usb controller index
|
||||
- disable-over-current: disable over current detect
|
||||
- over-current-active-low: over current signal polarity is active low.
|
||||
- over-current-active-high: over current signal polarity is active high.
|
||||
It's recommended to specify the over current polarity.
|
||||
- power-active-high: power signal polarity is active high
|
||||
- external-vbus-divider: enables off-chip resistor divider for Vbus
|
||||
- samsung,picophy-pre-emp-curr-control: HS Transmitter Pre-Emphasis Current
|
||||
Control. This signal controls the amount of current sourced to the
|
||||
USB_OTG*_DP and USB_OTG*_DN pins after a J-to-K or K-to-J transition.
|
||||
The range is from 0x0 to 0x3, the default value is 0x1.
|
||||
Details can refer to TXPREEMPAMPTUNE0 bits of USBNC_n_PHY_CFG1.
|
||||
- samsung,picophy-dc-vol-level-adjust: HS DC Voltage Level Adjustment.
|
||||
Adjust the high-speed transmitter DC level voltage.
|
||||
The range is from 0x0 to 0xf, the default value is 0x3.
|
||||
Details can refer to TXVREFTUNE0 bits of USBNC_n_PHY_CFG1.
|
||||
|
||||
Example:
|
||||
|
||||
usb@f7ed0000 {
|
||||
compatible = "chipidea,usb2";
|
||||
reg = <0xf7ed0000 0x10000>;
|
||||
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&chip CLKID_USB0>;
|
||||
phys = <&usb_phy0>;
|
||||
phy-names = "usb-phy";
|
||||
vbus-supply = <®_usb0_vbus>;
|
||||
itc-setting = <0x4>; /* 4 micro-frames */
|
||||
/* Incremental burst of unspecified length */
|
||||
ahb-burst-config = <0x0>;
|
||||
tx-burst-size-dword = <0x10>; /* 64 bytes */
|
||||
rx-burst-size-dword = <0x10>;
|
||||
extcon = <0>, <&usb_id>;
|
||||
phy-clkgate-delay-us = <400>;
|
||||
mux-controls = <&usb_switch>;
|
||||
mux-control-names = "usb_switch";
|
||||
};
|
||||
|
||||
Example for HSIC:
|
||||
|
||||
usb@2184400 {
|
||||
compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
|
||||
reg = <0x02184400 0x200>;
|
||||
interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX6QDL_CLK_USBOH3>;
|
||||
fsl,usbphy = <&usbphynop1>;
|
||||
fsl,usbmisc = <&usbmisc 2>;
|
||||
phy_type = "hsic";
|
||||
dr_mode = "host";
|
||||
ahb-burst-config = <0x0>;
|
||||
tx-burst-size-dword = <0x10>;
|
||||
rx-burst-size-dword = <0x10>;
|
||||
pinctrl-names = "idle", "active";
|
||||
pinctrl-0 = <&pinctrl_usbh2_idle>;
|
||||
pinctrl-1 = <&pinctrl_usbh2_active>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
usbnet: ethernet@1 {
|
||||
compatible = "usb424,9730";
|
||||
reg = <1>;
|
||||
};
|
||||
};
|
448
Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml
Normal file
448
Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml
Normal file
@ -0,0 +1,448 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/usb/ci-hdrc-usb2.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: USB2 ChipIdea USB controller
|
||||
|
||||
maintainers:
|
||||
- Xu Yang <xu.yang_2@nxp.com>
|
||||
- Peng Fan <peng.fan@nxp.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- chipidea,usb2
|
||||
- lsi,zevio-usb
|
||||
- nvidia,tegra20-ehci
|
||||
- nvidia,tegra20-udc
|
||||
- nvidia,tegra30-ehci
|
||||
- nvidia,tegra30-udc
|
||||
- nvidia,tegra114-udc
|
||||
- nvidia,tegra124-udc
|
||||
- qcom,ci-hdrc
|
||||
- items:
|
||||
- enum:
|
||||
- nvidia,tegra114-ehci
|
||||
- nvidia,tegra124-ehci
|
||||
- nvidia,tegra210-ehci
|
||||
- const: nvidia,tegra30-ehci
|
||||
- items:
|
||||
- enum:
|
||||
- fsl,imx23-usb
|
||||
- fsl,imx25-usb
|
||||
- fsl,imx28-usb
|
||||
- fsl,imx50-usb
|
||||
- fsl,imx51-usb
|
||||
- fsl,imx53-usb
|
||||
- fsl,imx6q-usb
|
||||
- fsl,imx6sl-usb
|
||||
- fsl,imx6sx-usb
|
||||
- fsl,imx6ul-usb
|
||||
- fsl,imx7d-usb
|
||||
- fsl,vf610-usb
|
||||
- const: fsl,imx27-usb
|
||||
- items:
|
||||
- const: fsl,imx8dxl-usb
|
||||
- const: fsl,imx7ulp-usb
|
||||
- const: fsl,imx6ul-usb
|
||||
- items:
|
||||
- enum:
|
||||
- fsl,imx8mm-usb
|
||||
- fsl,imx8mn-usb
|
||||
- const: fsl,imx7d-usb
|
||||
- const: fsl,imx27-usb
|
||||
- items:
|
||||
- enum:
|
||||
- fsl,imx6sll-usb
|
||||
- fsl,imx7ulp-usb
|
||||
- const: fsl,imx6ul-usb
|
||||
- const: fsl,imx27-usb
|
||||
- items:
|
||||
- const: xlnx,zynq-usb-2.20a
|
||||
- const: chipidea,usb2
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
interrupts:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
dr_mode: true
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
maxItems: 1
|
||||
|
||||
"#reset-cells":
|
||||
const: 1
|
||||
|
||||
phy_type: true
|
||||
|
||||
itc-setting:
|
||||
description:
|
||||
interrupt threshold control register control, the setting should be
|
||||
aligned with ITC bits at register USBCMD.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
ahb-burst-config:
|
||||
description:
|
||||
it is vendor dependent, the required value should be aligned with
|
||||
AHBBRST at SBUSCFG, the range is from 0x0 to 0x7. This property is
|
||||
used to change AHB burst configuration, check the chipidea spec for
|
||||
meaning of each value. If this property is not existed, it will use
|
||||
the reset value.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0x0
|
||||
maximum: 0x7
|
||||
|
||||
tx-burst-size-dword:
|
||||
description:
|
||||
it is vendor dependent, the tx burst size in dword (4 bytes), This
|
||||
register represents the maximum length of a the burst in 32-bit
|
||||
words while moving data from system memory to the USB bus, the value
|
||||
of this property will only take effect if property "ahb-burst-config"
|
||||
is set to 0, if this property is missing the reset default of the
|
||||
hardware implementation will be used.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0x0
|
||||
maximum: 0x20
|
||||
|
||||
rx-burst-size-dword:
|
||||
description:
|
||||
it is vendor dependent, the rx burst size in dword (4 bytes), This
|
||||
register represents the maximum length of a the burst in 32-bit words
|
||||
while moving data from the USB bus to system memory, the value of
|
||||
this property will only take effect if property "ahb-burst-config"
|
||||
is set to 0, if this property is missing the reset default of the
|
||||
hardware implementation will be used.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0x0
|
||||
maximum: 0x20
|
||||
|
||||
extcon:
|
||||
description:
|
||||
Phandles to external connector devices. First phandle should point
|
||||
to external connector, which provide "USB" cable events, the second
|
||||
should point to external connector device, which provide "USB-HOST"
|
||||
cable events. If one of the external connector devices is not
|
||||
required, empty <0> phandle should be specified.
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
minItems: 1
|
||||
items:
|
||||
- description: vbus extcon
|
||||
- description: id extcon
|
||||
|
||||
phy-clkgate-delay-us:
|
||||
description:
|
||||
The delay time (us) between putting the PHY into low power mode and
|
||||
gating the PHY clock.
|
||||
|
||||
non-zero-ttctrl-ttha:
|
||||
description:
|
||||
After setting this property, the value of register ttctrl.ttha
|
||||
will be 0x7f; if not, the value will be 0x0, this is the default
|
||||
value. It needs to be very carefully for setting this property, it
|
||||
is recommended that consult with your IC engineer before setting
|
||||
this value. On the most of chipidea platforms, the "usage_tt" flag
|
||||
at RTL is 0, so this property only affects siTD.
|
||||
|
||||
If this property is not set, the max packet size is 1023 bytes, and
|
||||
if the total of packet size for pervious transactions are more than
|
||||
256 bytes, it can't accept any transactions within this frame. The
|
||||
use case is single transaction, but higher frame rate.
|
||||
|
||||
If this property is set, the max packet size is 188 bytes, it can
|
||||
handle more transactions than above case, it can accept transactions
|
||||
until it considers the left room size within frame is less than 188
|
||||
bytes, software needs to make sure it does not send more than 90%
|
||||
maximum_periodic_data_per_frame. The use case is multiple
|
||||
transactions, but less frame rate.
|
||||
type: boolean
|
||||
|
||||
mux-controls:
|
||||
description:
|
||||
The mux control for toggling host/device output of this controller.
|
||||
It's expected that a mux state of 0 indicates device mode and a mux
|
||||
state of 1 indicates host mode.
|
||||
maxItems: 1
|
||||
|
||||
mux-control-names:
|
||||
const: usb_switch
|
||||
|
||||
operating-points-v2:
|
||||
description: A phandle to the OPP table containing the performance states.
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
||||
pinctrl-names:
|
||||
description:
|
||||
Names for optional pin modes in "default", "host", "device".
|
||||
In case of HSIC-mode, "idle" and "active" pin modes are mandatory.
|
||||
In this case, the "idle" state needs to pull down the data and
|
||||
strobe pin and the "active" state needs to pull up the strobe pin.
|
||||
oneOf:
|
||||
- items:
|
||||
- const: idle
|
||||
- const: active
|
||||
- items:
|
||||
- const: default
|
||||
- enum:
|
||||
- host
|
||||
- device
|
||||
- items:
|
||||
- const: default
|
||||
|
||||
pinctrl-0:
|
||||
maxItems: 1
|
||||
|
||||
pinctrl-1:
|
||||
maxItems: 1
|
||||
|
||||
phys:
|
||||
maxItems: 1
|
||||
|
||||
phy-names:
|
||||
const: usb-phy
|
||||
|
||||
phy-select:
|
||||
description:
|
||||
Phandler of TCSR node with two argument that indicate register
|
||||
offset, and phy index
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
items:
|
||||
- description: phandle to TCSR node
|
||||
- description: register offset
|
||||
- description: phy index
|
||||
|
||||
vbus-supply:
|
||||
description: reference to the VBUS regulator.
|
||||
|
||||
fsl,usbmisc:
|
||||
description:
|
||||
Phandler of non-core register device, with one argument that
|
||||
indicate usb controller index
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
items:
|
||||
- items:
|
||||
- description: phandle to usbmisc node
|
||||
- description: index of usb controller
|
||||
|
||||
fsl,anatop:
|
||||
description: phandle for the anatop node.
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
||||
disable-over-current:
|
||||
type: boolean
|
||||
description: disable over current detect
|
||||
|
||||
over-current-active-low:
|
||||
type: boolean
|
||||
description: over current signal polarity is active low
|
||||
|
||||
over-current-active-high:
|
||||
type: boolean
|
||||
description:
|
||||
Over current signal polarity is active high. It's recommended to
|
||||
specify the over current polarity.
|
||||
|
||||
power-active-high:
|
||||
type: boolean
|
||||
description: power signal polarity is active high
|
||||
|
||||
external-vbus-divider:
|
||||
type: boolean
|
||||
description: enables off-chip resistor divider for Vbus
|
||||
|
||||
samsung,picophy-pre-emp-curr-control:
|
||||
description:
|
||||
HS Transmitter Pre-Emphasis Current Control. This signal controls
|
||||
the amount of current sourced to the USB_OTG*_DP and USB_OTG*_DN
|
||||
pins after a J-to-K or K-to-J transition. The range is from 0x0 to
|
||||
0x3, the default value is 0x1. Details can refer to TXPREEMPAMPTUNE0
|
||||
bits of USBNC_n_PHY_CFG1.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0x0
|
||||
maximum: 0x3
|
||||
|
||||
samsung,picophy-dc-vol-level-adjust:
|
||||
description:
|
||||
HS DC Voltage Level Adjustment. Adjust the high-speed transmitter DC
|
||||
level voltage. The range is from 0x0 to 0xf, the default value is
|
||||
0x3. Details can refer to TXVREFTUNE0 bits of USBNC_n_PHY_CFG1.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0x0
|
||||
maximum: 0xf
|
||||
|
||||
usb-phy:
|
||||
description: phandle for the PHY device. Use "phys" instead.
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
deprecated: true
|
||||
|
||||
fsl,usbphy:
|
||||
description: phandle of usb phy that connects to the port. Use "phys" instead.
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
deprecated: true
|
||||
|
||||
nvidia,phy:
|
||||
description: phandle of usb phy that connects to the port. Use "phys" instead.
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
deprecated: true
|
||||
|
||||
nvidia,needs-double-reset:
|
||||
description: Indicates double reset or not.
|
||||
type: boolean
|
||||
deprecated: true
|
||||
|
||||
port:
|
||||
description:
|
||||
Any connector to the data bus of this controller should be modelled
|
||||
using the OF graph bindings specified, if the "usb-role-switch"
|
||||
property is used.
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
ulpi:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
patternProperties:
|
||||
"^phy(-[0-9])?$":
|
||||
description: The phy child node for Qcom chips.
|
||||
type: object
|
||||
$ref: /schemas/phy/qcom,usb-hs-phy.yaml
|
||||
|
||||
dependencies:
|
||||
port: [ usb-role-switch ]
|
||||
mux-controls: [ mux-control-names ]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
allOf:
|
||||
- $ref: usb-hcd.yaml#
|
||||
- $ref: usb-drd.yaml#
|
||||
- if:
|
||||
properties:
|
||||
phy_type:
|
||||
const: hsic
|
||||
required:
|
||||
- phy_type
|
||||
then:
|
||||
properties:
|
||||
pinctrl-names:
|
||||
items:
|
||||
- const: idle
|
||||
- const: active
|
||||
else:
|
||||
properties:
|
||||
pinctrl-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
oneOf:
|
||||
- items:
|
||||
- const: default
|
||||
- enum:
|
||||
- host
|
||||
- device
|
||||
- items:
|
||||
- const: default
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- chipidea,usb2
|
||||
- lsi,zevio-usb
|
||||
- nvidia,tegra20-udc
|
||||
- nvidia,tegra30-udc
|
||||
- nvidia,tegra114-udc
|
||||
- nvidia,tegra124-udc
|
||||
- qcom,ci-hdrc
|
||||
- xlnx,zynq-usb-2.20a
|
||||
then:
|
||||
properties:
|
||||
fsl,usbmisc: false
|
||||
disable-over-current: false
|
||||
over-current-active-low: false
|
||||
over-current-active-high: false
|
||||
power-active-high: false
|
||||
external-vbus-divider: false
|
||||
samsung,picophy-pre-emp-curr-control: false
|
||||
samsung,picophy-dc-vol-level-adjust: false
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/berlin2.h>
|
||||
|
||||
usb@f7ed0000 {
|
||||
compatible = "chipidea,usb2";
|
||||
reg = <0xf7ed0000 0x10000>;
|
||||
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&chip CLKID_USB0>;
|
||||
phys = <&usb_phy0>;
|
||||
phy-names = "usb-phy";
|
||||
vbus-supply = <®_usb0_vbus>;
|
||||
itc-setting = <0x4>; /* 4 micro-frames */
|
||||
/* Incremental burst of unspecified length */
|
||||
ahb-burst-config = <0x0>;
|
||||
tx-burst-size-dword = <0x10>; /* 64 bytes */
|
||||
rx-burst-size-dword = <0x10>;
|
||||
extcon = <0>, <&usb_id>;
|
||||
phy-clkgate-delay-us = <400>;
|
||||
mux-controls = <&usb_switch>;
|
||||
mux-control-names = "usb_switch";
|
||||
};
|
||||
|
||||
# Example for HSIC:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/imx6qdl-clock.h>
|
||||
|
||||
usb@2184400 {
|
||||
compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
|
||||
reg = <0x02184400 0x200>;
|
||||
interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX6QDL_CLK_USBOH3>;
|
||||
fsl,usbphy = <&usbphynop1>;
|
||||
fsl,usbmisc = <&usbmisc 2>;
|
||||
phy_type = "hsic";
|
||||
dr_mode = "host";
|
||||
ahb-burst-config = <0x0>;
|
||||
tx-burst-size-dword = <0x10>;
|
||||
rx-burst-size-dword = <0x10>;
|
||||
pinctrl-names = "idle", "active";
|
||||
pinctrl-0 = <&pinctrl_usbh2_idle>;
|
||||
pinctrl-1 = <&pinctrl_usbh2_active>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ethernet@1 {
|
||||
compatible = "usb424,9730";
|
||||
reg = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -75,11 +75,14 @@ properties:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: otg
|
||||
- const: utmi
|
||||
minItems: 1
|
||||
|
||||
disable-over-current:
|
||||
type: boolean
|
||||
|
@ -1,8 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/usb/fcs,fsa4480.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
$id: http://devicetree.org/schemas/usb/fcs,fsa4480.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ON Semiconductor Analog Audio Switch
|
||||
|
||||
|
48
Documentation/devicetree/bindings/usb/fsl,imx8mq-dwc3.yaml
Normal file
48
Documentation/devicetree/bindings/usb/fsl,imx8mq-dwc3.yaml
Normal file
@ -0,0 +1,48 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/usb/fsl,imx8mq-dwc3.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NXP iMX8MQ Soc USB Controller
|
||||
|
||||
maintainers:
|
||||
- Li Jun <jun.li@nxp.com>
|
||||
- Peng Fan <peng.fan@nxp.com>
|
||||
|
||||
select:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- fsl,imx8mq-dwc3
|
||||
required:
|
||||
- compatible
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: fsl,imx8mq-dwc3
|
||||
- const: snps,dwc3
|
||||
|
||||
allOf:
|
||||
- $ref: snps,dwc3.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/imx8mq-clock.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
usb_dwc3_1: usb@38200000 {
|
||||
compatible = "fsl,imx8mq-dwc3", "snps,dwc3";
|
||||
reg = <0x38200000 0x10000>;
|
||||
clocks = <&clk IMX8MQ_CLK_USB2_CTRL_ROOT>,
|
||||
<&clk IMX8MQ_CLK_USB_CORE_REF>,
|
||||
<&clk IMX8MQ_CLK_32K>;
|
||||
clock-names = "bus_early", "ref", "suspend";
|
||||
interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
|
||||
phys = <&usb3_phy1>, <&usb3_phy1>;
|
||||
phy-names = "usb2-phy", "usb3-phy";
|
||||
};
|
68
Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml
Normal file
68
Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml
Normal file
@ -0,0 +1,68 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/usb/fsl,usbmisc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Freescale i.MX wrapper module for Chipidea USB2 controller
|
||||
|
||||
maintainers:
|
||||
- Xu Yang <xu.yang_2@nxp.com>
|
||||
- Peng Fan <peng.fan@nxp.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- fsl,imx25-usbmisc
|
||||
- fsl,imx27-usbmisc
|
||||
- fsl,imx35-usbmisc
|
||||
- fsl,imx51-usbmisc
|
||||
- fsl,imx53-usbmisc
|
||||
- fsl,imx6q-usbmisc
|
||||
- fsl,vf610-usbmisc
|
||||
- items:
|
||||
- enum:
|
||||
- fsl,imx6ul-usbmisc
|
||||
- fsl,imx6sl-usbmisc
|
||||
- fsl,imx6sx-usbmisc
|
||||
- fsl,imx7d-usbmisc
|
||||
- const: fsl,imx6q-usbmisc
|
||||
- items:
|
||||
- enum:
|
||||
- fsl,imx7ulp-usbmisc
|
||||
- fsl,imx8mm-usbmisc
|
||||
- fsl,imx8mn-usbmisc
|
||||
- const: fsl,imx7d-usbmisc
|
||||
- const: fsl,imx6q-usbmisc
|
||||
- items:
|
||||
- const: fsl,imx6sll-usbmisc
|
||||
- const: fsl,imx6ul-usbmisc
|
||||
- const: fsl,imx6q-usbmisc
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#index-cells':
|
||||
const: 1
|
||||
description: Cells used to describe usb controller index.
|
||||
deprecated: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
usbmisc@2184800 {
|
||||
compatible = "fsl,imx6q-usbmisc";
|
||||
reg = <0x02184800 0x200>;
|
||||
#index-cells = <1>;
|
||||
};
|
||||
|
||||
...
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
|
||||
allOf:
|
||||
- $ref: "usb-hcd.yaml"
|
||||
- $ref: usb-hcd.yaml
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -148,7 +148,7 @@ allOf:
|
||||
properties:
|
||||
transceiver: false
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Mathias Nyman <mathias.nyman@intel.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "usb-xhci.yaml#"
|
||||
- $ref: usb-xhci.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -1,8 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/usb/gpio-sbu-mux.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
$id: http://devicetree.org/schemas/usb/gpio-sbu-mux.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: GPIO-based SBU mux
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/usb/maxim,max33359.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
$id: http://devicetree.org/schemas/usb/maxim,max33359.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Maxim TCPCI Type-C PD controller
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/usb/mediatek,mt6360-tcpc.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
$id: http://devicetree.org/schemas/usb/mediatek,mt6360-tcpc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Mediatek MT6360 Type-C Port Switch and Power Delivery controller
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/usb/mediatek,mt6370-tcpc.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
$id: http://devicetree.org/schemas/usb/mediatek,mt6370-tcpc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MediatTek MT6370 Type-C Port Switch and Power Delivery controller
|
||||
|
||||
|
@ -11,7 +11,7 @@ maintainers:
|
||||
- Chunfeng Yun <chunfeng.yun@mediatek.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "usb-xhci.yaml"
|
||||
- $ref: usb-xhci.yaml
|
||||
|
||||
description: |
|
||||
There are two scenarios:
|
||||
@ -77,6 +77,7 @@ properties:
|
||||
- description: Mcu bus clock for register access
|
||||
- description: DMA bus clock for data transfer
|
||||
- description: controller clock
|
||||
- description: frame count clock
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
@ -86,14 +87,7 @@ properties:
|
||||
- const: mcu_ck
|
||||
- const: dma_ck
|
||||
- const: xhci_ck
|
||||
|
||||
assigned-clocks:
|
||||
minItems: 1
|
||||
maxItems: 5
|
||||
|
||||
assigned-clock-parents:
|
||||
minItems: 1
|
||||
maxItems: 5
|
||||
- const: frmcnt_ck
|
||||
|
||||
phys:
|
||||
description:
|
||||
|
@ -11,7 +11,7 @@ maintainers:
|
||||
- Chunfeng Yun <chunfeng.yun@mediatek.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "usb-drd.yaml"
|
||||
- $ref: usb-drd.yaml
|
||||
|
||||
description: |
|
||||
The DRD controller has a glue layer IPPC (IP Port Control), and its host is
|
||||
@ -66,6 +66,8 @@ properties:
|
||||
- description: Reference clock used by low power mode etc
|
||||
- description: Mcu bus clock for register access
|
||||
- description: DMA bus clock for data transfer
|
||||
- description: DRD controller clock
|
||||
- description: Frame count clock
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
@ -74,6 +76,8 @@ properties:
|
||||
- const: ref_ck
|
||||
- const: mcu_ck
|
||||
- const: dma_ck
|
||||
- const: xhci_ck
|
||||
- const: frmcnt_ck
|
||||
|
||||
phys:
|
||||
description:
|
||||
@ -204,9 +208,9 @@ patternProperties:
|
||||
example if the host mode is enabled.
|
||||
|
||||
dependencies:
|
||||
connector: [ 'usb-role-switch' ]
|
||||
port: [ 'usb-role-switch' ]
|
||||
role-switch-default-mode: [ 'usb-role-switch' ]
|
||||
connector: [ usb-role-switch ]
|
||||
port: [ usb-role-switch ]
|
||||
role-switch-default-mode: [ usb-role-switch ]
|
||||
wakeup-source: [ 'mediatek,syscon-wakeup' ]
|
||||
|
||||
required:
|
||||
|
@ -68,8 +68,8 @@ properties:
|
||||
type: object
|
||||
|
||||
dependencies:
|
||||
usb-role-switch: [ 'connector' ]
|
||||
connector: [ 'usb-role-switch' ]
|
||||
usb-role-switch: [ connector ]
|
||||
connector: [ usb-role-switch ]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
@ -1,8 +1,8 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/usb/nvidia,tegra-xudc.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
$id: http://devicetree.org/schemas/usb/nvidia,tegra-xudc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NVIDIA Tegra XUSB device mode controller (XUDC)
|
||||
|
||||
|
72
Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml
Normal file
72
Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml
Normal file
@ -0,0 +1,72 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/usb/nxp,ptn5110.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NXP PTN5110 Typec Port Cotroller
|
||||
|
||||
maintainers:
|
||||
- Li Jun <jun.li@nxp.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: nxp,ptn5110
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
connector:
|
||||
type: object
|
||||
$ref: /schemas/connector/usb-connector.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- connector
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/usb/pd.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
tcpci@50 {
|
||||
compatible = "nxp,ptn5110";
|
||||
reg = <0x50>;
|
||||
interrupt-parent = <&gpio3>;
|
||||
interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
usb_con: connector {
|
||||
compatible = "usb-c-connector";
|
||||
label = "USB-C";
|
||||
data-role = "dual";
|
||||
power-role = "dual";
|
||||
try-power-role = "sink";
|
||||
source-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_USB_COMM)>;
|
||||
sink-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_USB_COMM) PDO_VAR(5000, 12000, 2000)>;
|
||||
op-sink-microwatt = <10000000>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
typec1_dr_sw: endpoint {
|
||||
remote-endpoint = <&usb1_drd_sw>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -21,6 +21,7 @@ properties:
|
||||
- qcom,msm8994-dwc3
|
||||
- qcom,msm8996-dwc3
|
||||
- qcom,msm8998-dwc3
|
||||
- qcom,qcm2290-dwc3
|
||||
- qcom,qcs404-dwc3
|
||||
- qcom,sc7180-dwc3
|
||||
- qcom,sc7280-dwc3
|
||||
@ -301,6 +302,7 @@ allOf:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,qcm2290-dwc3
|
||||
- qcom,sm6115-dwc3
|
||||
- qcom,sm6125-dwc3
|
||||
- qcom,sm8150-dwc3
|
||||
|
@ -26,7 +26,7 @@ properties:
|
||||
phandle to the regulator that provides power to the hub.
|
||||
|
||||
peer-hub:
|
||||
$ref: '/schemas/types.yaml#/definitions/phandle'
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
phandle to the peer hub on the controller.
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/usb/richtek,rt1711h.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
$id: http://devicetree.org/schemas/usb/richtek,rt1711h.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Richtek RT1711H Type-C Port Switch and Power Delivery controller
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/usb/richtek,rt1719.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
$id: http://devicetree.org/schemas/usb/richtek,rt1719.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Richtek RT1719 sink-only Type-C PD controller
|
||||
|
||||
|
@ -14,6 +14,7 @@ properties:
|
||||
enum:
|
||||
- smsc,usb3503
|
||||
- smsc,usb3503a
|
||||
- smsc,usb3803
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@ -33,6 +34,12 @@ properties:
|
||||
description: >
|
||||
GPIO for reset
|
||||
|
||||
bypass-gpios:
|
||||
maxItems: 1
|
||||
description: >
|
||||
GPIO for bypass.
|
||||
Control signal to select between HUB MODE and BYPASS MODE.
|
||||
|
||||
disabled-ports:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
minItems: 1
|
||||
@ -46,9 +53,10 @@ properties:
|
||||
|
||||
initial-mode:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [1, 2]
|
||||
description: >
|
||||
Specifies initial mode. 1 for Hub mode, 2 for standby mode.
|
||||
Specifies initial mode. 1 for Hub mode, 2 for standby mode and 3 for bypass mode.
|
||||
In bypass mode the downstream port 3 is connected to the upstream port with low
|
||||
switch resistance R_on.
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
@ -71,6 +79,29 @@ properties:
|
||||
required:
|
||||
- compatible
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
not:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- smsc,usb3803
|
||||
then:
|
||||
properties:
|
||||
bypass-gpios: false
|
||||
|
||||
- if:
|
||||
required:
|
||||
- bypass-gpios
|
||||
then:
|
||||
properties:
|
||||
initial-mode:
|
||||
enum: [1, 2, 3]
|
||||
else:
|
||||
properties:
|
||||
initial-mode:
|
||||
enum: [1, 2]
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
@ -92,6 +123,25 @@ examples:
|
||||
};
|
||||
};
|
||||
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
usb-hub@8 {
|
||||
compatible = "smsc,usb3803";
|
||||
reg = <0x08>;
|
||||
connect-gpios = <&gpx3 0 1>;
|
||||
disabled-ports = <2 3>;
|
||||
intn-gpios = <&gpx3 4 1>;
|
||||
reset-gpios = <&gpx3 5 1>;
|
||||
bypass-gpios = <&gpx3 6 1>;
|
||||
initial-mode = <3>;
|
||||
clocks = <&clks 80>;
|
||||
clock-names = "refclk";
|
||||
};
|
||||
};
|
||||
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
|
@ -70,6 +70,10 @@ properties:
|
||||
|
||||
dma-coherent: true
|
||||
|
||||
extcon:
|
||||
maxItems: 1
|
||||
deprecated: true
|
||||
|
||||
iommus:
|
||||
maxItems: 1
|
||||
|
||||
@ -232,6 +236,11 @@ properties:
|
||||
When set, all SuperSpeed bus instances in park mode are disabled.
|
||||
type: boolean
|
||||
|
||||
snps,parkmode-disable-hs-quirk:
|
||||
description:
|
||||
When set, all HighSpeed bus instances in park mode are disabled.
|
||||
type: boolean
|
||||
|
||||
snps,dis_metastability_quirk:
|
||||
description:
|
||||
When set, disable metastability workaround. CAUTION! Use only if you are
|
||||
@ -256,6 +265,14 @@ properties:
|
||||
of resume. This option is to support certain legacy ULPI PHYs.
|
||||
type: boolean
|
||||
|
||||
snps,ulpi-ext-vbus-drv:
|
||||
description:
|
||||
Some ULPI USB PHY does not support internal VBUS supply, and driving
|
||||
the CPEN pin, requires the configuration of the ulpi DRVVBUSEXTERNAL
|
||||
bit. When set, the xhci host will configure the USB2 PHY drives VBUS
|
||||
with an external supply.
|
||||
type: boolean
|
||||
|
||||
snps,is-utmi-l1-suspend:
|
||||
description:
|
||||
True when DWC3 asserts output signal utmi_l1_suspend_n, false when
|
||||
@ -365,6 +382,22 @@ properties:
|
||||
This port is used with the 'usb-role-switch' property to connect the
|
||||
dwc3 to type C connector.
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
description:
|
||||
Those ports should be used with any connector to the data bus of this
|
||||
controller using the OF graph bindings specified if the "usb-role-switch"
|
||||
property is used.
|
||||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: High Speed (HS) data bus.
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: Super Speed (SS) data bus.
|
||||
|
||||
wakeup-source:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
|
@ -1,8 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/usb/st,stusb160x.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
$id: http://devicetree.org/schemas/usb/st,stusb160x.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: STMicroelectronics STUSB160x Type-C controller
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/usb/ti,j721e-usb.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
$id: http://devicetree.org/schemas/usb/ti,j721e-usb.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: TI wrapper module for the Cadence USBSS-DRD controller
|
||||
|
||||
@ -53,12 +53,6 @@ properties:
|
||||
VBUS pin of the SoC via a 1/3 voltage divider.
|
||||
type: boolean
|
||||
|
||||
assigned-clocks:
|
||||
maxItems: 1
|
||||
|
||||
assigned-clock-parents:
|
||||
maxItems: 1
|
||||
|
||||
'#address-cells':
|
||||
const: 2
|
||||
|
||||
|
@ -34,14 +34,6 @@ properties:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
assigned-clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
assigned-clock-parents:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
description: Should contain a phandle to a PM domain provider node
|
||||
|
@ -1,8 +1,8 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/usb/ti,tps6598x.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
$id: http://devicetree.org/schemas/usb/ti,tps6598x.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments 6598x Type-C Port Switch and Power Delivery controller
|
||||
|
||||
@ -35,8 +35,6 @@ properties:
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
|
||||
additionalProperties: true
|
||||
|
||||
|
@ -1,49 +0,0 @@
|
||||
TCPCI(Typec port cotroller interface) binding
|
||||
---------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible: should be set one of following:
|
||||
- "nxp,ptn5110" for NXP USB PD TCPC PHY IC ptn5110.
|
||||
|
||||
- reg: the i2c slave address of typec port controller device.
|
||||
- interrupt-parent: the phandle to the interrupt controller which provides
|
||||
the interrupt.
|
||||
- interrupts: interrupt specification for tcpci alert.
|
||||
|
||||
Required sub-node:
|
||||
- connector: The "usb-c-connector" attached to the tcpci chip, the bindings
|
||||
of connector node are specified in
|
||||
Documentation/devicetree/bindings/connector/usb-connector.yaml
|
||||
|
||||
Example:
|
||||
|
||||
ptn5110@50 {
|
||||
compatible = "nxp,ptn5110";
|
||||
reg = <0x50>;
|
||||
interrupt-parent = <&gpio3>;
|
||||
interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
usb_con: connector {
|
||||
compatible = "usb-c-connector";
|
||||
label = "USB-C";
|
||||
data-role = "dual";
|
||||
power-role = "dual";
|
||||
try-power-role = "sink";
|
||||
source-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_USB_COMM)>;
|
||||
sink-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_USB_COMM)
|
||||
PDO_VAR(5000, 12000, 2000)>;
|
||||
op-sink-microwatt = <10000000>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
usb_con_ss: endpoint {
|
||||
remote-endpoint = <&usb3_data_ss>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -76,7 +76,6 @@ patternProperties:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: true
|
||||
|
@ -27,6 +27,9 @@ properties:
|
||||
vcc-supply:
|
||||
description: phandle to the regulator that provides power to the PHY.
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Mathias Nyman <mathias.nyman@intel.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "usb-hcd.yaml#"
|
||||
- $ref: usb-hcd.yaml#
|
||||
|
||||
properties:
|
||||
usb2-lpm-disable:
|
||||
|
@ -1,19 +0,0 @@
|
||||
* Freescale i.MX non-core registers
|
||||
|
||||
Required properties:
|
||||
- #index-cells: Cells used to describe usb controller index. Should be <1>
|
||||
- compatible: Should be one of below:
|
||||
"fsl,imx6q-usbmisc" for imx6q
|
||||
"fsl,vf610-usbmisc" for Vybrid vf610
|
||||
"fsl,imx6sx-usbmisc" for imx6sx
|
||||
"fsl,imx7d-usbmisc" for imx7d
|
||||
"fsl,imx7ulp-usbmisc" for imx7ulp
|
||||
"fsl,imx8mm-usbmisc" for imx8mm
|
||||
- reg: Should contain registers location and length
|
||||
|
||||
Examples:
|
||||
usbmisc@2184800 {
|
||||
#index-cells = <1>;
|
||||
compatible = "fsl,imx6q-usbmisc";
|
||||
reg = <0x02184800 0x200>;
|
||||
};
|
@ -275,6 +275,34 @@ out with 0x00, for example:
|
||||
|
||||
bNrInPins and baSourceID function in the same way.
|
||||
|
||||
Configuring Supported Controls for Camera Terminal and Processing Unit
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Camera Terminal and Processing Units in the UVC chain also have bmControls
|
||||
attributes which function similarly to the same field in an Extension Unit.
|
||||
Unlike XUs however, the meaning of the bitflag for these units is defined in
|
||||
the UVC specification; you should consult the "Camera Terminal Descriptor" and
|
||||
"Processing Unit Descriptor" sections for an enumeration of the flags.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Set the Processing Unit's bmControls, flagging Brightness, Contrast
|
||||
# and Hue as available controls:
|
||||
echo 0x05 > $FUNCTION/control/processing/default/bmControls
|
||||
|
||||
# Set the Camera Terminal's bmControls, flagging Focus Absolute and
|
||||
# Focus Relative as available controls:
|
||||
echo 0x60 > $FUNCTION/control/terminal/camera/default/bmControls
|
||||
|
||||
If you do not set these fields then by default the Auto-Exposure Mode control
|
||||
for the Camera Terminal and the Brightness control for the Processing Unit will
|
||||
be flagged as available; if they are not supported you should set the field to
|
||||
0x00.
|
||||
|
||||
Note that the size of the bmControls field for a Camera Terminal or Processing
|
||||
Unit is fixed by the UVC specification, and so the bControlSize attribute is
|
||||
read-only here.
|
||||
|
||||
Custom Strings Support
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -189,7 +189,7 @@
|
||||
};
|
||||
|
||||
usbotg1: usb@40330000 {
|
||||
compatible = "fsl,imx7ulp-usb", "fsl,imx6ul-usb";
|
||||
compatible = "fsl,imx7ulp-usb", "fsl,imx6ul-usb", "fsl,imx27-usb";
|
||||
reg = <0x40330000 0x200>;
|
||||
interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&pcc2 IMX7ULP_CLK_USB0>;
|
||||
@ -202,7 +202,8 @@
|
||||
};
|
||||
|
||||
usbmisc1: usbmisc@40330200 {
|
||||
compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc";
|
||||
compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc",
|
||||
"fsl,imx6q-usbmisc";
|
||||
#index-cells = <1>;
|
||||
reg = <0x40330200 0x200>;
|
||||
};
|
||||
|
@ -1130,8 +1130,8 @@
|
||||
usbotg_hs: usb-otg@49000000 {
|
||||
compatible = "st,stm32mp15-hsotg", "snps,dwc2";
|
||||
reg = <0x49000000 0x10000>;
|
||||
clocks = <&rcc USBO_K>;
|
||||
clock-names = "otg";
|
||||
clocks = <&rcc USBO_K>, <&usbphyc>;
|
||||
clock-names = "otg", "utmi";
|
||||
resets = <&rcc USBO_R>;
|
||||
reset-names = "dwc2";
|
||||
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
@ -35,7 +35,7 @@ conn_subsys: bus@5b000000 {
|
||||
};
|
||||
|
||||
usbotg1: usb@5b0d0000 {
|
||||
compatible = "fsl,imx7ulp-usb";
|
||||
compatible = "fsl,imx7ulp-usb", "fsl,imx6ul-usb", "fsl,imx27-usb";
|
||||
reg = <0x5b0d0000 0x200>;
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
|
||||
@ -51,7 +51,7 @@ conn_subsys: bus@5b000000 {
|
||||
|
||||
usbmisc1: usbmisc@5b0d0200 {
|
||||
#index-cells = <1>;
|
||||
compatible = "fsl,imx7ulp-usbmisc", "fsl,imx6q-usbmisc";
|
||||
compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc", "fsl,imx6q-usbmisc";
|
||||
reg = <0x5b0d0200 0x200>;
|
||||
};
|
||||
|
||||
|
@ -34,7 +34,7 @@
|
||||
};
|
||||
|
||||
usbotg2: usb@5b0e0000 {
|
||||
compatible = "fsl,imx8dxl-usb", "fsl,imx7ulp-usb";
|
||||
compatible = "fsl,imx8dxl-usb", "fsl,imx7ulp-usb", "fsl,imx6ul-usb";
|
||||
reg = <0x5b0e0000 0x200>;
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>;
|
||||
@ -49,7 +49,6 @@
|
||||
ahb-burst-config = <0x0>;
|
||||
tx-burst-size-dword = <0x10>;
|
||||
rx-burst-size-dword = <0x10>;
|
||||
#stream-id-cells = <1>;
|
||||
power-domains = <&pd IMX_SC_R_USB_1>;
|
||||
status = "disabled";
|
||||
|
||||
@ -63,7 +62,7 @@
|
||||
|
||||
usbmisc2: usbmisc@5b0e0200 {
|
||||
#index-cells = <1>;
|
||||
compatible = "fsl,imx7ulp-usbmisc";
|
||||
compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc", "fsl,imx6q-usbmisc";
|
||||
reg = <0x5b0e0200 0x200>;
|
||||
};
|
||||
|
||||
|
@ -1253,7 +1253,7 @@
|
||||
};
|
||||
|
||||
usbotg1: usb@32e40000 {
|
||||
compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb";
|
||||
compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb", "fsl,imx27-usb";
|
||||
reg = <0x32e40000 0x200>;
|
||||
interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clk IMX8MM_CLK_USB1_CTRL_ROOT>;
|
||||
@ -1267,13 +1267,14 @@
|
||||
};
|
||||
|
||||
usbmisc1: usbmisc@32e40200 {
|
||||
compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc";
|
||||
compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc",
|
||||
"fsl,imx6q-usbmisc";
|
||||
#index-cells = <1>;
|
||||
reg = <0x32e40200 0x200>;
|
||||
};
|
||||
|
||||
usbotg2: usb@32e50000 {
|
||||
compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb";
|
||||
compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb", "fsl,imx27-usb";
|
||||
reg = <0x32e50000 0x200>;
|
||||
interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clk IMX8MM_CLK_USB1_CTRL_ROOT>;
|
||||
@ -1287,7 +1288,8 @@
|
||||
};
|
||||
|
||||
usbmisc2: usbmisc@32e50200 {
|
||||
compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc";
|
||||
compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc",
|
||||
"fsl,imx6q-usbmisc";
|
||||
#index-cells = <1>;
|
||||
reg = <0x32e50200 0x200>;
|
||||
};
|
||||
|
@ -1146,7 +1146,7 @@
|
||||
};
|
||||
|
||||
usbotg1: usb@32e40000 {
|
||||
compatible = "fsl,imx8mn-usb", "fsl,imx7d-usb";
|
||||
compatible = "fsl,imx8mn-usb", "fsl,imx7d-usb", "fsl,imx27-usb";
|
||||
reg = <0x32e40000 0x200>;
|
||||
interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clk IMX8MN_CLK_USB1_CTRL_ROOT>;
|
||||
@ -1160,7 +1160,8 @@
|
||||
};
|
||||
|
||||
usbmisc1: usbmisc@32e40200 {
|
||||
compatible = "fsl,imx8mn-usbmisc", "fsl,imx7d-usbmisc";
|
||||
compatible = "fsl,imx8mn-usbmisc", "fsl,imx7d-usbmisc",
|
||||
"fsl,imx6q-usbmisc";
|
||||
#index-cells = <1>;
|
||||
reg = <0x32e40200 0x200>;
|
||||
};
|
||||
|
@ -1453,7 +1453,6 @@
|
||||
phys = <&usb3_phy0>, <&usb3_phy0>;
|
||||
phy-names = "usb2-phy", "usb3-phy";
|
||||
power-domains = <&pgc_otg1>;
|
||||
usb3-resume-missing-cas;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -1485,7 +1484,6 @@
|
||||
phys = <&usb3_phy1>, <&usb3_phy1>;
|
||||
phy-names = "usb2-phy", "usb3-phy";
|
||||
power-domains = <&pgc_otg2>;
|
||||
usb3-resume-missing-cas;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -497,7 +497,6 @@ CONFIG_USB_EHCI_ROOT_HUB_TT=y
|
||||
CONFIG_USB_OHCI_HCD=m
|
||||
CONFIG_USB_OHCI_HCD_PLATFORM=m
|
||||
CONFIG_USB_UHCI_HCD=m
|
||||
CONFIG_USB_U132_HCD=m
|
||||
CONFIG_USB_SL811_HCD=m
|
||||
CONFIG_USB_SL811_CS=m
|
||||
CONFIG_USB_ACM=m
|
||||
@ -554,7 +553,6 @@ CONFIG_USB_LCD=m
|
||||
CONFIG_USB_CYPRESS_CY7C63=m
|
||||
CONFIG_USB_CYTHERM=m
|
||||
CONFIG_USB_IDMOUSE=m
|
||||
CONFIG_USB_FTDI_ELAN=m
|
||||
CONFIG_USB_APPLEDISPLAY=m
|
||||
CONFIG_USB_SISUSBVGA=m
|
||||
CONFIG_USB_LD=m
|
||||
|
@ -845,7 +845,6 @@ CONFIG_USB_OHCI_HCD=m
|
||||
CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
|
||||
CONFIG_USB_OHCI_HCD_PPC_OF_LE=y
|
||||
CONFIG_USB_UHCI_HCD=m
|
||||
CONFIG_USB_U132_HCD=m
|
||||
CONFIG_USB_SL811_HCD=m
|
||||
CONFIG_USB_ACM=m
|
||||
CONFIG_USB_PRINTER=m
|
||||
@ -908,7 +907,6 @@ CONFIG_USB_SEVSEG=m
|
||||
CONFIG_USB_LEGOTOWER=m
|
||||
CONFIG_USB_LCD=m
|
||||
CONFIG_USB_IDMOUSE=m
|
||||
CONFIG_USB_FTDI_ELAN=m
|
||||
CONFIG_USB_APPLEDISPLAY=m
|
||||
CONFIG_USB_SISUSBVGA=m
|
||||
CONFIG_USB_LD=m
|
||||
|
@ -316,6 +316,16 @@ static int usb_shark_probe(struct usb_interface *intf,
|
||||
{
|
||||
struct shark_device *shark;
|
||||
int retval = -ENOMEM;
|
||||
static const u8 ep_addresses[] = {
|
||||
SHARK_IN_EP | USB_DIR_IN,
|
||||
SHARK_OUT_EP | USB_DIR_OUT,
|
||||
0};
|
||||
|
||||
/* Are the expected endpoints present? */
|
||||
if (!usb_check_int_endpoints(intf, ep_addresses)) {
|
||||
dev_err(&intf->dev, "Invalid radioSHARK device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL);
|
||||
if (!shark)
|
||||
|
@ -282,6 +282,16 @@ static int usb_shark_probe(struct usb_interface *intf,
|
||||
{
|
||||
struct shark_device *shark;
|
||||
int retval = -ENOMEM;
|
||||
static const u8 ep_addresses[] = {
|
||||
SHARK_IN_EP | USB_DIR_IN,
|
||||
SHARK_OUT_EP | USB_DIR_OUT,
|
||||
0};
|
||||
|
||||
/* Are the expected endpoints present? */
|
||||
if (!usb_check_int_endpoints(intf, ep_addresses)) {
|
||||
dev_err(&intf->dev, "Invalid radioSHARK2 device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL);
|
||||
if (!shark)
|
||||
|
@ -341,7 +341,7 @@ static struct acpi_device *tb_acpi_find_companion(struct device *dev)
|
||||
*/
|
||||
if (tb_is_switch(dev))
|
||||
return tb_acpi_switch_find_companion(tb_to_switch(dev));
|
||||
else if (tb_is_usb4_port_device(dev))
|
||||
if (tb_is_usb4_port_device(dev))
|
||||
return acpi_find_child_by_adr(ACPI_COMPANION(dev->parent),
|
||||
tb_to_usb4_port_device(dev)->port->port);
|
||||
return NULL;
|
||||
|
@ -1033,7 +1033,7 @@ static int tb_cfg_get_error(struct tb_ctl *ctl, enum tb_cfg_space space,
|
||||
|
||||
if (res->tb_error == TB_CFG_ERROR_LOCK)
|
||||
return -EACCES;
|
||||
else if (res->tb_error == TB_CFG_ERROR_PORT_NOT_CONNECTED)
|
||||
if (res->tb_error == TB_CFG_ERROR_PORT_NOT_CONNECTED)
|
||||
return -ENOTCONN;
|
||||
|
||||
return -EIO;
|
||||
|
@ -416,7 +416,7 @@ static int tb_drom_parse_entries(struct tb_switch *sw, size_t header_size)
|
||||
if (pos + 1 == drom_size || pos + entry->len > drom_size
|
||||
|| !entry->len) {
|
||||
tb_sw_warn(sw, "DROM buffer overrun\n");
|
||||
return -EILSEQ;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
switch (entry->type) {
|
||||
@ -471,14 +471,13 @@ err:
|
||||
|
||||
static int tb_drom_copy_nvm(struct tb_switch *sw, u16 *size)
|
||||
{
|
||||
u32 drom_offset;
|
||||
u16 drom_offset;
|
||||
int ret;
|
||||
|
||||
if (!sw->dma_port)
|
||||
return -ENODEV;
|
||||
|
||||
ret = tb_sw_read(sw, &drom_offset, TB_CFG_SWITCH,
|
||||
sw->cap_plug_events + 12, 1);
|
||||
ret = tb_eeprom_get_drom_offset(sw, &drom_offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -513,7 +512,7 @@ err_free:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usb4_copy_host_drom(struct tb_switch *sw, u16 *size)
|
||||
static int usb4_copy_drom(struct tb_switch *sw, u16 *size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -536,15 +535,40 @@ static int usb4_copy_host_drom(struct tb_switch *sw, u16 *size)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tb_drom_read_n(struct tb_switch *sw, u16 offset, u8 *val,
|
||||
size_t count)
|
||||
static int tb_drom_bit_bang(struct tb_switch *sw, u16 *size)
|
||||
{
|
||||
if (tb_switch_is_usb4(sw))
|
||||
return usb4_switch_drom_read(sw, offset, val, count);
|
||||
return tb_eeprom_read_n(sw, offset, val, count);
|
||||
int ret;
|
||||
|
||||
ret = tb_eeprom_read_n(sw, 14, (u8 *)size, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*size &= 0x3ff;
|
||||
*size += TB_DROM_DATA_START;
|
||||
|
||||
tb_sw_dbg(sw, "reading DROM (length: %#x)\n", *size);
|
||||
if (*size < sizeof(struct tb_drom_header)) {
|
||||
tb_sw_warn(sw, "DROM too small, aborting\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
sw->drom = kzalloc(*size, GFP_KERNEL);
|
||||
if (!sw->drom)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = tb_eeprom_read_n(sw, 0, sw->drom, *size);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
kfree(sw->drom);
|
||||
sw->drom = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tb_drom_parse(struct tb_switch *sw)
|
||||
static int tb_drom_parse_v1(struct tb_switch *sw)
|
||||
{
|
||||
const struct tb_drom_header *header =
|
||||
(const struct tb_drom_header *)sw->drom;
|
||||
@ -555,7 +579,7 @@ static int tb_drom_parse(struct tb_switch *sw)
|
||||
tb_sw_warn(sw,
|
||||
"DROM UID CRC8 mismatch (expected: %#x, got: %#x)\n",
|
||||
header->uid_crc8, crc);
|
||||
return -EILSEQ;
|
||||
return -EIO;
|
||||
}
|
||||
if (!sw->uid)
|
||||
sw->uid = header->uid;
|
||||
@ -589,6 +613,85 @@ static int usb4_drom_parse(struct tb_switch *sw)
|
||||
return tb_drom_parse_entries(sw, USB4_DROM_HEADER_SIZE);
|
||||
}
|
||||
|
||||
static int tb_drom_parse(struct tb_switch *sw, u16 size)
|
||||
{
|
||||
const struct tb_drom_header *header = (const void *)sw->drom;
|
||||
int ret;
|
||||
|
||||
if (header->data_len + TB_DROM_DATA_START != size) {
|
||||
tb_sw_warn(sw, "DROM size mismatch\n");
|
||||
ret = -EIO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
tb_sw_dbg(sw, "DROM version: %d\n", header->device_rom_revision);
|
||||
|
||||
switch (header->device_rom_revision) {
|
||||
case 3:
|
||||
ret = usb4_drom_parse(sw);
|
||||
break;
|
||||
default:
|
||||
tb_sw_warn(sw, "DROM device_rom_revision %#x unknown\n",
|
||||
header->device_rom_revision);
|
||||
fallthrough;
|
||||
case 1:
|
||||
ret = tb_drom_parse_v1(sw);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
tb_sw_warn(sw, "parsing DROM failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
kfree(sw->drom);
|
||||
sw->drom = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tb_drom_host_read(struct tb_switch *sw)
|
||||
{
|
||||
u16 size;
|
||||
|
||||
if (tb_switch_is_usb4(sw)) {
|
||||
usb4_switch_read_uid(sw, &sw->uid);
|
||||
if (!usb4_copy_drom(sw, &size))
|
||||
return tb_drom_parse(sw, size);
|
||||
} else {
|
||||
if (!tb_drom_copy_efi(sw, &size))
|
||||
return tb_drom_parse(sw, size);
|
||||
|
||||
if (!tb_drom_copy_nvm(sw, &size))
|
||||
return tb_drom_parse(sw, size);
|
||||
|
||||
tb_drom_read_uid_only(sw, &sw->uid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tb_drom_device_read(struct tb_switch *sw)
|
||||
{
|
||||
u16 size;
|
||||
int ret;
|
||||
|
||||
if (tb_switch_is_usb4(sw)) {
|
||||
usb4_switch_read_uid(sw, &sw->uid);
|
||||
ret = usb4_copy_drom(sw, &size);
|
||||
} else {
|
||||
ret = tb_drom_bit_bang(sw, &size);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return tb_drom_parse(sw, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* tb_drom_read() - Copy DROM to sw->drom and parse it
|
||||
* @sw: Router whose DROM to read and parse
|
||||
@ -601,103 +704,10 @@ static int usb4_drom_parse(struct tb_switch *sw)
|
||||
*/
|
||||
int tb_drom_read(struct tb_switch *sw)
|
||||
{
|
||||
u16 size;
|
||||
struct tb_drom_header *header;
|
||||
int res, retries = 1;
|
||||
|
||||
if (sw->drom)
|
||||
return 0;
|
||||
|
||||
if (tb_route(sw) == 0) {
|
||||
/*
|
||||
* Apple's NHI EFI driver supplies a DROM for the root switch
|
||||
* in a device property. Use it if available.
|
||||
*/
|
||||
if (tb_drom_copy_efi(sw, &size) == 0)
|
||||
goto parse;
|
||||
|
||||
/* Non-Apple hardware has the DROM as part of NVM */
|
||||
if (tb_drom_copy_nvm(sw, &size) == 0)
|
||||
goto parse;
|
||||
|
||||
/*
|
||||
* USB4 hosts may support reading DROM through router
|
||||
* operations.
|
||||
*/
|
||||
if (tb_switch_is_usb4(sw)) {
|
||||
usb4_switch_read_uid(sw, &sw->uid);
|
||||
if (!usb4_copy_host_drom(sw, &size))
|
||||
goto parse;
|
||||
} else {
|
||||
/*
|
||||
* The root switch contains only a dummy drom
|
||||
* (header only, no entries). Hardcode the
|
||||
* configuration here.
|
||||
*/
|
||||
tb_drom_read_uid_only(sw, &sw->uid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = tb_drom_read_n(sw, 14, (u8 *) &size, 2);
|
||||
if (res)
|
||||
return res;
|
||||
size &= 0x3ff;
|
||||
size += TB_DROM_DATA_START;
|
||||
tb_sw_dbg(sw, "reading drom (length: %#x)\n", size);
|
||||
if (size < sizeof(*header)) {
|
||||
tb_sw_warn(sw, "drom too small, aborting\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
sw->drom = kzalloc(size, GFP_KERNEL);
|
||||
if (!sw->drom)
|
||||
return -ENOMEM;
|
||||
read:
|
||||
res = tb_drom_read_n(sw, 0, sw->drom, size);
|
||||
if (res)
|
||||
goto err;
|
||||
|
||||
parse:
|
||||
header = (void *) sw->drom;
|
||||
|
||||
if (header->data_len + TB_DROM_DATA_START != size) {
|
||||
tb_sw_warn(sw, "drom size mismatch\n");
|
||||
if (retries--) {
|
||||
msleep(100);
|
||||
goto read;
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
|
||||
tb_sw_dbg(sw, "DROM version: %d\n", header->device_rom_revision);
|
||||
|
||||
switch (header->device_rom_revision) {
|
||||
case 3:
|
||||
res = usb4_drom_parse(sw);
|
||||
break;
|
||||
default:
|
||||
tb_sw_warn(sw, "DROM device_rom_revision %#x unknown\n",
|
||||
header->device_rom_revision);
|
||||
fallthrough;
|
||||
case 1:
|
||||
res = tb_drom_parse(sw);
|
||||
break;
|
||||
}
|
||||
|
||||
/* If the DROM parsing fails, wait a moment and retry once */
|
||||
if (res == -EILSEQ && retries--) {
|
||||
tb_sw_warn(sw, "parsing DROM failed\n");
|
||||
msleep(100);
|
||||
goto read;
|
||||
}
|
||||
|
||||
if (!res)
|
||||
return 0;
|
||||
|
||||
err:
|
||||
kfree(sw->drom);
|
||||
sw->drom = NULL;
|
||||
return -EIO;
|
||||
if (!tb_route(sw))
|
||||
return tb_drom_host_read(sw);
|
||||
return tb_drom_device_read(sw);
|
||||
}
|
||||
|
@ -526,7 +526,8 @@ static int nhi_alloc_hop(struct tb_nhi *nhi, struct tb_ring *ring)
|
||||
ring->hop);
|
||||
ret = -EBUSY;
|
||||
goto err_unlock;
|
||||
} else if (!ring->is_tx && nhi->rx_rings[ring->hop]) {
|
||||
}
|
||||
if (!ring->is_tx && nhi->rx_rings[ring->hop]) {
|
||||
dev_warn(&nhi->pdev->dev, "RX hop %d already allocated\n",
|
||||
ring->hop);
|
||||
ret = -EBUSY;
|
||||
|
@ -271,9 +271,9 @@ static int nvm_authenticate(struct tb_switch *sw, bool auth_only)
|
||||
}
|
||||
sw->nvm->authenticating = true;
|
||||
return usb4_switch_nvm_authenticate(sw);
|
||||
} else if (auth_only) {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
if (auth_only)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
sw->nvm->authenticating = true;
|
||||
if (!tb_route(sw)) {
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#include "sb_regs.h"
|
||||
#include "tb.h"
|
||||
@ -851,7 +852,7 @@ bool usb4_switch_query_dp_resource(struct tb_switch *sw, struct tb_port *in)
|
||||
*/
|
||||
if (ret == -EOPNOTSUPP)
|
||||
return true;
|
||||
else if (ret)
|
||||
if (ret)
|
||||
return false;
|
||||
|
||||
return !status;
|
||||
@ -877,7 +878,7 @@ int usb4_switch_alloc_dp_resource(struct tb_switch *sw, struct tb_port *in)
|
||||
&status);
|
||||
if (ret == -EOPNOTSUPP)
|
||||
return 0;
|
||||
else if (ret)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return status ? -EBUSY : 0;
|
||||
@ -900,7 +901,7 @@ int usb4_switch_dealloc_dp_resource(struct tb_switch *sw, struct tb_port *in)
|
||||
&status);
|
||||
if (ret == -EOPNOTSUPP)
|
||||
return 0;
|
||||
else if (ret)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return status ? -EIO : 0;
|
||||
@ -1302,6 +1303,20 @@ static int usb4_port_sb_write(struct tb_port *port, enum usb4_sb_target target,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb4_port_sb_opcode_err_to_errno(u32 val)
|
||||
{
|
||||
switch (val) {
|
||||
case 0:
|
||||
return 0;
|
||||
case USB4_SB_OPCODE_ERR:
|
||||
return -EAGAIN;
|
||||
case USB4_SB_OPCODE_ONS:
|
||||
return -EOPNOTSUPP;
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
static int usb4_port_sb_op(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, enum usb4_sb_opcode opcode, int timeout_msec)
|
||||
{
|
||||
@ -1324,21 +1339,8 @@ static int usb4_port_sb_op(struct tb_port *port, enum usb4_sb_target target,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (val) {
|
||||
case 0:
|
||||
return 0;
|
||||
|
||||
case USB4_SB_OPCODE_ERR:
|
||||
return -EAGAIN;
|
||||
|
||||
case USB4_SB_OPCODE_ONS:
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
default:
|
||||
if (val != opcode)
|
||||
return -EIO;
|
||||
break;
|
||||
}
|
||||
if (val != opcode)
|
||||
return usb4_port_sb_opcode_err_to_errno(val);
|
||||
} while (ktime_before(ktime_get(), timeout));
|
||||
|
||||
return -ETIMEDOUT;
|
||||
@ -1813,12 +1815,13 @@ int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (val) {
|
||||
ret = usb4_port_sb_opcode_err_to_errno(val);
|
||||
switch (ret) {
|
||||
case 0:
|
||||
*status = 0;
|
||||
return 0;
|
||||
|
||||
case USB4_SB_OPCODE_ERR:
|
||||
case -EAGAIN:
|
||||
ret = usb4_port_retimer_read(port, index, USB4_SB_METADATA,
|
||||
&metadata, sizeof(metadata));
|
||||
if (ret)
|
||||
@ -1827,11 +1830,8 @@ int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index,
|
||||
*status = metadata & USB4_SB_METADATA_NVM_AUTH_WRITE_MASK;
|
||||
return 0;
|
||||
|
||||
case USB4_SB_OPCODE_ONS:
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
default:
|
||||
return -EIO;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1995,7 +1995,7 @@ static unsigned int usb3_bw_to_mbps(u32 bw, u8 scale)
|
||||
unsigned long uframes;
|
||||
|
||||
uframes = bw * 512UL << scale;
|
||||
return DIV_ROUND_CLOSEST(uframes * 8000, 1000 * 1000);
|
||||
return DIV_ROUND_CLOSEST(uframes * 8000, MEGA);
|
||||
}
|
||||
|
||||
static u32 mbps_to_usb3_bw(unsigned int mbps, u8 scale)
|
||||
@ -2003,7 +2003,7 @@ static u32 mbps_to_usb3_bw(unsigned int mbps, u8 scale)
|
||||
unsigned long uframes;
|
||||
|
||||
/* 1 uframe is 1/8 ms (125 us) -> 1 / 8000 s */
|
||||
uframes = ((unsigned long)mbps * 1000 * 1000) / 8000;
|
||||
uframes = ((unsigned long)mbps * MEGA) / 8000;
|
||||
return DIV_ROUND_UP(uframes, 512UL << scale);
|
||||
}
|
||||
|
||||
|
@ -1178,9 +1178,8 @@ static int tb_xdomain_get_uuid(struct tb_xdomain *xd)
|
||||
if (xd->state_retries-- > 0) {
|
||||
dev_dbg(&xd->dev, "failed to request UUID, retrying\n");
|
||||
return -EAGAIN;
|
||||
} else {
|
||||
dev_dbg(&xd->dev, "failed to read remote UUID\n");
|
||||
}
|
||||
dev_dbg(&xd->dev, "failed to read remote UUID\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1367,12 +1366,10 @@ static int tb_xdomain_get_properties(struct tb_xdomain *xd)
|
||||
dev_dbg(&xd->dev,
|
||||
"failed to request remote properties, retrying\n");
|
||||
return -EAGAIN;
|
||||
} else {
|
||||
/* Give up now */
|
||||
dev_err(&xd->dev,
|
||||
"failed read XDomain properties from %pUb\n",
|
||||
xd->remote_uuid);
|
||||
}
|
||||
/* Give up now */
|
||||
dev_err(&xd->dev, "failed read XDomain properties from %pUb\n",
|
||||
xd->remote_uuid);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -2179,13 +2176,12 @@ static struct tb_xdomain *switch_find_xdomain(struct tb_switch *sw,
|
||||
if (xd->remote_uuid &&
|
||||
uuid_equal(xd->remote_uuid, lookup->uuid))
|
||||
return xd;
|
||||
} else if (lookup->link &&
|
||||
lookup->link == xd->link &&
|
||||
lookup->depth == xd->depth) {
|
||||
return xd;
|
||||
} else if (lookup->route &&
|
||||
lookup->route == xd->route) {
|
||||
return xd;
|
||||
} else {
|
||||
if (lookup->link && lookup->link == xd->link &&
|
||||
lookup->depth == xd->depth)
|
||||
return xd;
|
||||
if (lookup->route && lookup->route == xd->route)
|
||||
return xd;
|
||||
}
|
||||
} else if (tb_port_has_remote(port)) {
|
||||
xd = switch_find_xdomain(port->remote->sw, lookup);
|
||||
|
@ -133,35 +133,6 @@ comment "USB port drivers"
|
||||
|
||||
if USB
|
||||
|
||||
config USB_USS720
|
||||
tristate "USS720 parport driver"
|
||||
depends on PARPORT
|
||||
select PARPORT_NOT_PC
|
||||
help
|
||||
This driver is for USB parallel port adapters that use the Lucent
|
||||
Technologies USS-720 chip. These cables are plugged into your USB
|
||||
port and provide USB compatibility to peripherals designed with
|
||||
parallel port interfaces.
|
||||
|
||||
The chip has two modes: automatic mode and manual mode. In automatic
|
||||
mode, it looks to the computer like a standard USB printer. Only
|
||||
printers may be connected to the USS-720 in this mode. The generic
|
||||
USB printer driver ("USB Printer support", above) may be used in
|
||||
that mode, and you can say N here if you want to use the chip only
|
||||
in this mode.
|
||||
|
||||
Manual mode is not limited to printers, any parallel port
|
||||
device should work. This driver utilizes manual mode.
|
||||
Note however that some operations are three orders of magnitude
|
||||
slower than on a PCI/ISA Parallel Port, so timing critical
|
||||
applications might not work.
|
||||
|
||||
Say Y here if you own an USS-720 USB->Parport cable and intend to
|
||||
connect anything other than a printer to it.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called uss720.
|
||||
|
||||
source "drivers/usb/serial/Kconfig"
|
||||
|
||||
source "drivers/usb/misc/Kconfig"
|
||||
|
@ -31,7 +31,6 @@ obj-$(CONFIG_USB_FHCI_HCD) += host/
|
||||
obj-$(CONFIG_USB_XHCI_HCD) += host/
|
||||
obj-$(CONFIG_USB_SL811_HCD) += host/
|
||||
obj-$(CONFIG_USB_ISP1362_HCD) += host/
|
||||
obj-$(CONFIG_USB_U132_HCD) += host/
|
||||
obj-$(CONFIG_USB_R8A66597_HCD) += host/
|
||||
obj-$(CONFIG_USB_FSL_USB2) += host/
|
||||
obj-$(CONFIG_USB_FOTG210_HCD) += host/
|
||||
|
@ -107,8 +107,7 @@ static inline char *cdns3_decode_ep0_irq(char *str,
|
||||
* Prints out all TRBs in the endpoint ring, even those after the Link TRB.
|
||||
*.
|
||||
*/
|
||||
static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep,
|
||||
struct cdns3_trb *ring, char *str)
|
||||
static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep, char *str)
|
||||
{
|
||||
dma_addr_t addr = priv_ep->trb_pool_dma;
|
||||
struct cdns3_trb *trb;
|
||||
@ -136,9 +135,6 @@ static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep,
|
||||
"\t\tfree trbs: %d, CCS=%d, PCS=%d\n",
|
||||
priv_ep->free_trbs, priv_ep->ccs, priv_ep->pcs);
|
||||
|
||||
if (trb_per_sector > TRBS_PER_SEGMENT)
|
||||
trb_per_sector = TRBS_PER_SEGMENT;
|
||||
|
||||
if (trb_per_sector > TRBS_PER_SEGMENT) {
|
||||
sprintf(str + ret, "\t\tTransfer ring %d too big\n",
|
||||
trb_per_sector);
|
||||
@ -146,7 +142,7 @@ static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep,
|
||||
}
|
||||
|
||||
for (i = 0; i < trb_per_sector; ++i) {
|
||||
trb = &ring[i];
|
||||
trb = &priv_ep->trb_pool[i];
|
||||
ret += sprintf(str + ret,
|
||||
"\t\t@%pad %08x %08x %08x\n", &addr,
|
||||
le32_to_cpu(trb->buffer),
|
||||
|
@ -100,13 +100,12 @@ DECLARE_EVENT_CLASS(cdns3_log_usb_irq,
|
||||
TP_STRUCT__entry(
|
||||
__field(enum usb_device_speed, speed)
|
||||
__field(u32, usb_ists)
|
||||
__dynamic_array(char, str, CDNS3_MSG_MAX)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->speed = cdns3_get_speed(priv_dev);
|
||||
__entry->usb_ists = usb_ists;
|
||||
),
|
||||
TP_printk("%s", cdns3_decode_usb_irq(__get_str(str), __entry->speed,
|
||||
TP_printk("%s", cdns3_decode_usb_irq(__get_buf(CDNS3_MSG_MAX), __entry->speed,
|
||||
__entry->usb_ists))
|
||||
);
|
||||
|
||||
@ -124,7 +123,6 @@ DECLARE_EVENT_CLASS(cdns3_log_epx_irq,
|
||||
__field(u32, ep_traddr)
|
||||
__field(u32, ep_last_sid)
|
||||
__field(u32, use_streams)
|
||||
__dynamic_array(char, str, CDNS3_MSG_MAX)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__assign_str(ep_name, priv_ep->name);
|
||||
@ -134,7 +132,7 @@ DECLARE_EVENT_CLASS(cdns3_log_epx_irq,
|
||||
__entry->use_streams = priv_ep->use_streams;
|
||||
),
|
||||
TP_printk("%s, ep_traddr: %08x ep_last_sid: %08x use_streams: %d",
|
||||
cdns3_decode_epx_irq(__get_str(str),
|
||||
cdns3_decode_epx_irq(__get_buf(CDNS3_MSG_MAX),
|
||||
__get_str(ep_name),
|
||||
__entry->ep_sts),
|
||||
__entry->ep_traddr,
|
||||
@ -153,13 +151,12 @@ DECLARE_EVENT_CLASS(cdns3_log_ep0_irq,
|
||||
TP_STRUCT__entry(
|
||||
__field(int, ep_dir)
|
||||
__field(u32, ep_sts)
|
||||
__dynamic_array(char, str, CDNS3_MSG_MAX)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->ep_dir = priv_dev->selected_ep;
|
||||
__entry->ep_sts = ep_sts;
|
||||
),
|
||||
TP_printk("%s", cdns3_decode_ep0_irq(__get_str(str),
|
||||
TP_printk("%s", cdns3_decode_ep0_irq(__get_buf(CDNS3_MSG_MAX),
|
||||
__entry->ep_dir,
|
||||
__entry->ep_sts))
|
||||
);
|
||||
@ -178,7 +175,6 @@ DECLARE_EVENT_CLASS(cdns3_log_ctrl,
|
||||
__field(u16, wValue)
|
||||
__field(u16, wIndex)
|
||||
__field(u16, wLength)
|
||||
__dynamic_array(char, str, CDNS3_MSG_MAX)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->bRequestType = ctrl->bRequestType;
|
||||
@ -187,7 +183,7 @@ DECLARE_EVENT_CLASS(cdns3_log_ctrl,
|
||||
__entry->wIndex = le16_to_cpu(ctrl->wIndex);
|
||||
__entry->wLength = le16_to_cpu(ctrl->wLength);
|
||||
),
|
||||
TP_printk("%s", usb_decode_ctrl(__get_str(str), CDNS3_MSG_MAX,
|
||||
TP_printk("%s", usb_decode_ctrl(__get_buf(CDNS3_MSG_MAX), CDNS3_MSG_MAX,
|
||||
__entry->bRequestType,
|
||||
__entry->bRequest, __entry->wValue,
|
||||
__entry->wIndex, __entry->wLength)
|
||||
@ -438,22 +434,16 @@ DECLARE_EVENT_CLASS(cdns3_log_ring,
|
||||
TP_PROTO(struct cdns3_endpoint *priv_ep),
|
||||
TP_ARGS(priv_ep),
|
||||
TP_STRUCT__entry(
|
||||
__dynamic_array(u8, ring, TRB_RING_SIZE)
|
||||
__dynamic_array(u8, priv_ep, sizeof(struct cdns3_endpoint))
|
||||
__dynamic_array(char, buffer,
|
||||
(TRBS_PER_SEGMENT * 65) + CDNS3_MSG_MAX)
|
||||
GET_TRBS_PER_SEGMENT(priv_ep->type) > TRBS_PER_SEGMENT ?
|
||||
CDNS3_MSG_MAX :
|
||||
(GET_TRBS_PER_SEGMENT(priv_ep->type) * 65) + CDNS3_MSG_MAX)
|
||||
),
|
||||
TP_fast_assign(
|
||||
memcpy(__get_dynamic_array(priv_ep), priv_ep,
|
||||
sizeof(struct cdns3_endpoint));
|
||||
memcpy(__get_dynamic_array(ring), priv_ep->trb_pool,
|
||||
TRB_RING_SIZE);
|
||||
cdns3_dbg_ring(priv_ep, __get_str(buffer));
|
||||
),
|
||||
|
||||
TP_printk("%s",
|
||||
cdns3_dbg_ring((struct cdns3_endpoint *)__get_str(priv_ep),
|
||||
(struct cdns3_trb *)__get_str(ring),
|
||||
__get_str(buffer)))
|
||||
TP_printk("%s", __get_str(buffer))
|
||||
);
|
||||
|
||||
DEFINE_EVENT(cdns3_log_ring, cdns3_ring,
|
||||
|
@ -271,7 +271,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_ctrl,
|
||||
__field(u16, wValue)
|
||||
__field(u16, wIndex)
|
||||
__field(u16, wLength)
|
||||
__dynamic_array(char, str, CDNSP_MSG_MAX)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->bRequestType = ctrl->bRequestType;
|
||||
@ -280,7 +279,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_ctrl,
|
||||
__entry->wIndex = le16_to_cpu(ctrl->wIndex);
|
||||
__entry->wLength = le16_to_cpu(ctrl->wLength);
|
||||
),
|
||||
TP_printk("%s", usb_decode_ctrl(__get_str(str), CDNSP_MSG_MAX,
|
||||
TP_printk("%s", usb_decode_ctrl(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX,
|
||||
__entry->bRequestType,
|
||||
__entry->bRequest, __entry->wValue,
|
||||
__entry->wIndex, __entry->wLength)
|
||||
@ -345,7 +344,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_trb,
|
||||
__field(u32, field3)
|
||||
__field(union cdnsp_trb *, trb)
|
||||
__field(dma_addr_t, trb_dma)
|
||||
__dynamic_array(char, str, CDNSP_MSG_MAX)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->type = ring->type;
|
||||
@ -359,7 +357,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_trb,
|
||||
|
||||
),
|
||||
TP_printk("%s: %s trb: %p(%pad)", cdnsp_ring_type_string(__entry->type),
|
||||
cdnsp_decode_trb(__get_str(str), CDNSP_MSG_MAX,
|
||||
cdnsp_decode_trb(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX,
|
||||
__entry->field0, __entry->field1,
|
||||
__entry->field2, __entry->field3),
|
||||
__entry->trb, &__entry->trb_dma
|
||||
@ -544,7 +542,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_ep_ctx,
|
||||
__field(u32, info2)
|
||||
__field(u64, deq)
|
||||
__field(u32, tx_info)
|
||||
__dynamic_array(char, str, CDNSP_MSG_MAX)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->info = le32_to_cpu(ctx->ep_info);
|
||||
@ -552,7 +549,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_ep_ctx,
|
||||
__entry->deq = le64_to_cpu(ctx->deq);
|
||||
__entry->tx_info = le32_to_cpu(ctx->tx_info);
|
||||
),
|
||||
TP_printk("%s", cdnsp_decode_ep_context(__get_str(str), CDNSP_MSG_MAX,
|
||||
TP_printk("%s", cdnsp_decode_ep_context(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX,
|
||||
__entry->info, __entry->info2,
|
||||
__entry->deq, __entry->tx_info)
|
||||
)
|
||||
@ -777,7 +774,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_portsc,
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, portnum)
|
||||
__field(u32, portsc)
|
||||
__dynamic_array(char, str, CDNSP_MSG_MAX)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->portnum = portnum;
|
||||
@ -785,7 +781,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_portsc,
|
||||
),
|
||||
TP_printk("port-%d: %s",
|
||||
__entry->portnum,
|
||||
cdnsp_decode_portsc(__get_str(str), CDNSP_MSG_MAX,
|
||||
cdnsp_decode_portsc(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX,
|
||||
__entry->portsc)
|
||||
)
|
||||
);
|
||||
|
@ -14,5 +14,5 @@ ci_hdrc-$(CONFIG_USB_OTG_FSM) += otg_fsm.o
|
||||
obj-$(CONFIG_USB_CHIPIDEA_GENERIC) += ci_hdrc_usb2.o
|
||||
obj-$(CONFIG_USB_CHIPIDEA_MSM) += ci_hdrc_msm.o
|
||||
obj-$(CONFIG_USB_CHIPIDEA_PCI) += ci_hdrc_pci.o
|
||||
obj-$(CONFIG_USB_CHIPIDEA_IMX) += ci_hdrc_imx.o usbmisc_imx.o
|
||||
obj-$(CONFIG_USB_CHIPIDEA_IMX) += usbmisc_imx.o ci_hdrc_imx.o
|
||||
obj-$(CONFIG_USB_CHIPIDEA_TEGRA) += ci_hdrc_tegra.o
|
||||
|
@ -152,12 +152,12 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
|
||||
* Check the various over current related properties. If over current
|
||||
* detection is disabled we're not interested in the polarity.
|
||||
*/
|
||||
if (of_find_property(np, "disable-over-current", NULL)) {
|
||||
if (of_property_read_bool(np, "disable-over-current")) {
|
||||
data->disable_oc = 1;
|
||||
} else if (of_find_property(np, "over-current-active-high", NULL)) {
|
||||
} else if (of_property_read_bool(np, "over-current-active-high")) {
|
||||
data->oc_pol_active_low = 0;
|
||||
data->oc_pol_configured = 1;
|
||||
} else if (of_find_property(np, "over-current-active-low", NULL)) {
|
||||
} else if (of_property_read_bool(np, "over-current-active-low")) {
|
||||
data->oc_pol_active_low = 1;
|
||||
data->oc_pol_configured = 1;
|
||||
} else {
|
||||
|
@ -753,7 +753,7 @@ static int ci_get_platdata(struct device *dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (of_find_property(dev->of_node, "non-zero-ttctrl-ttha", NULL))
|
||||
if (of_property_read_bool(dev->of_node, "non-zero-ttctrl-ttha"))
|
||||
platdata->flags |= CI_HDRC_SET_NON_ZERO_TTHA;
|
||||
|
||||
ext_id = ERR_PTR(-ENODEV);
|
||||
@ -1108,7 +1108,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
|
||||
ret = ci_usb_phy_init(ci);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to init phy: %d\n", ret);
|
||||
return ret;
|
||||
goto ulpi_exit;
|
||||
}
|
||||
|
||||
ci->hw_bank.phys = res->start;
|
||||
|
@ -247,60 +247,6 @@ static int ci_otg_show(struct seq_file *s, void *unused)
|
||||
}
|
||||
DEFINE_SHOW_ATTRIBUTE(ci_otg);
|
||||
|
||||
static int ci_role_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct ci_hdrc *ci = s->private;
|
||||
|
||||
if (ci->role != CI_ROLE_END)
|
||||
seq_printf(s, "%s\n", ci_role(ci)->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct seq_file *s = file->private_data;
|
||||
struct ci_hdrc *ci = s->private;
|
||||
enum ci_role role;
|
||||
char buf[8];
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
|
||||
return -EFAULT;
|
||||
|
||||
for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
|
||||
if (ci->roles[role] &&
|
||||
!strncmp(buf, ci->roles[role]->name,
|
||||
strlen(ci->roles[role]->name)))
|
||||
break;
|
||||
|
||||
if (role == CI_ROLE_END || role == ci->role)
|
||||
return -EINVAL;
|
||||
|
||||
pm_runtime_get_sync(ci->dev);
|
||||
disable_irq(ci->irq);
|
||||
ci_role_stop(ci);
|
||||
ret = ci_role_start(ci, role);
|
||||
enable_irq(ci->irq);
|
||||
pm_runtime_put_sync(ci->dev);
|
||||
|
||||
return ret ? ret : count;
|
||||
}
|
||||
|
||||
static int ci_role_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, ci_role_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations ci_role_fops = {
|
||||
.open = ci_role_open,
|
||||
.write = ci_role_write,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int ci_registers_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct ci_hdrc *ci = s->private;
|
||||
@ -354,7 +300,6 @@ void dbg_create_files(struct ci_hdrc *ci)
|
||||
if (ci_otg_is_fsm_mode(ci))
|
||||
debugfs_create_file("otg", S_IRUGO, dir, ci, &ci_otg_fops);
|
||||
|
||||
debugfs_create_file("role", S_IRUGO | S_IWUSR, dir, ci, &ci_role_fops);
|
||||
debugfs_create_file("registers", S_IRUGO, dir, ci, &ci_registers_fops);
|
||||
}
|
||||
|
||||
|
@ -81,15 +81,11 @@ int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
obj = acpi_evaluate_dsm(port_handle, &guid, 0,
|
||||
USB_DSM_DISABLE_U1_U2_FOR_PORT, NULL);
|
||||
|
||||
if (!obj)
|
||||
return -ENODEV;
|
||||
|
||||
if (obj->type != ACPI_TYPE_INTEGER) {
|
||||
obj = acpi_evaluate_dsm_typed(port_handle, &guid, 0,
|
||||
USB_DSM_DISABLE_U1_U2_FOR_PORT, NULL,
|
||||
ACPI_TYPE_INTEGER);
|
||||
if (!obj) {
|
||||
dev_dbg(&hdev->dev, "evaluate port-%d _DSM failed\n", port1);
|
||||
ACPI_FREE(obj);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -206,6 +206,82 @@ int usb_find_common_endpoints_reverse(struct usb_host_interface *alt,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_find_common_endpoints_reverse);
|
||||
|
||||
/**
|
||||
* usb_find_endpoint() - Given an endpoint address, search for the endpoint's
|
||||
* usb_host_endpoint structure in an interface's current altsetting.
|
||||
* @intf: the interface whose current altsetting should be searched
|
||||
* @ep_addr: the endpoint address (number and direction) to find
|
||||
*
|
||||
* Search the altsetting's list of endpoints for one with the specified address.
|
||||
*
|
||||
* Return: Pointer to the usb_host_endpoint if found, %NULL otherwise.
|
||||
*/
|
||||
static const struct usb_host_endpoint *usb_find_endpoint(
|
||||
const struct usb_interface *intf, unsigned int ep_addr)
|
||||
{
|
||||
int n;
|
||||
const struct usb_host_endpoint *ep;
|
||||
|
||||
n = intf->cur_altsetting->desc.bNumEndpoints;
|
||||
ep = intf->cur_altsetting->endpoint;
|
||||
for (; n > 0; (--n, ++ep)) {
|
||||
if (ep->desc.bEndpointAddress == ep_addr)
|
||||
return ep;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_check_bulk_endpoints - Check whether an interface's current altsetting
|
||||
* contains a set of bulk endpoints with the given addresses.
|
||||
* @intf: the interface whose current altsetting should be searched
|
||||
* @ep_addrs: 0-terminated array of the endpoint addresses (number and
|
||||
* direction) to look for
|
||||
*
|
||||
* Search for endpoints with the specified addresses and check their types.
|
||||
*
|
||||
* Return: %true if all the endpoints are found and are bulk, %false otherwise.
|
||||
*/
|
||||
bool usb_check_bulk_endpoints(
|
||||
const struct usb_interface *intf, const u8 *ep_addrs)
|
||||
{
|
||||
const struct usb_host_endpoint *ep;
|
||||
|
||||
for (; *ep_addrs; ++ep_addrs) {
|
||||
ep = usb_find_endpoint(intf, *ep_addrs);
|
||||
if (!ep || !usb_endpoint_xfer_bulk(&ep->desc))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_check_bulk_endpoints);
|
||||
|
||||
/**
|
||||
* usb_check_int_endpoints - Check whether an interface's current altsetting
|
||||
* contains a set of interrupt endpoints with the given addresses.
|
||||
* @intf: the interface whose current altsetting should be searched
|
||||
* @ep_addrs: 0-terminated array of the endpoint addresses (number and
|
||||
* direction) to look for
|
||||
*
|
||||
* Search for endpoints with the specified addresses and check their types.
|
||||
*
|
||||
* Return: %true if all the endpoints are found and are interrupt,
|
||||
* %false otherwise.
|
||||
*/
|
||||
bool usb_check_int_endpoints(
|
||||
const struct usb_interface *intf, const u8 *ep_addrs)
|
||||
{
|
||||
const struct usb_host_endpoint *ep;
|
||||
|
||||
for (; *ep_addrs; ++ep_addrs) {
|
||||
ep = usb_find_endpoint(intf, *ep_addrs);
|
||||
if (!ep || !usb_endpoint_xfer_int(&ep->desc))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_check_int_endpoints);
|
||||
|
||||
/**
|
||||
* usb_find_alt_setting() - Given a configuration, find the alternate setting
|
||||
* for the given interface.
|
||||
|
@ -1003,6 +1003,7 @@ struct dwc2_hregs_backup {
|
||||
* @ctrl_out_desc: EP0 OUT data phase desc chain pointer
|
||||
* @irq: Interrupt request line number
|
||||
* @clk: Pointer to otg clock
|
||||
* @utmi_clk: Pointer to utmi_clk clock
|
||||
* @reset: Pointer to dwc2 reset controller
|
||||
* @reset_ecc: Pointer to dwc2 optional reset controller in Stratix10.
|
||||
* @regset: A pointer to a struct debugfs_regset32, which contains
|
||||
@ -1065,6 +1066,7 @@ struct dwc2_hsotg {
|
||||
void *priv;
|
||||
int irq;
|
||||
struct clk *clk;
|
||||
struct clk *utmi_clk;
|
||||
struct reset_control *reset;
|
||||
struct reset_control *reset_ecc;
|
||||
|
||||
|
@ -1078,7 +1078,7 @@ static void dwc2_pick_first_frame(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
|
||||
earliest_frame = dwc2_frame_num_inc(frame_number, 1);
|
||||
next_active_frame = earliest_frame;
|
||||
|
||||
/* Get the "no microframe schduler" out of the way... */
|
||||
/* Get the "no microframe scheduler" out of the way... */
|
||||
if (!hsotg->params.uframe_sched) {
|
||||
if (qh->do_split)
|
||||
/* Splits are active at microframe 0 minus 1 */
|
||||
|
@ -508,8 +508,7 @@ static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg)
|
||||
of_usb_update_otg_caps(hsotg->dev->of_node, &p->otg_caps);
|
||||
}
|
||||
|
||||
if (of_find_property(hsotg->dev->of_node, "disable-over-current", NULL))
|
||||
p->oc_disable = true;
|
||||
p->oc_disable = of_property_read_bool(hsotg->dev->of_node, "disable-over-current");
|
||||
}
|
||||
|
||||
static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg)
|
||||
|
@ -101,10 +101,16 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (hsotg->utmi_clk) {
|
||||
ret = clk_prepare_enable(hsotg->utmi_clk);
|
||||
if (ret)
|
||||
goto err_dis_reg;
|
||||
}
|
||||
|
||||
if (hsotg->clk) {
|
||||
ret = clk_prepare_enable(hsotg->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_dis_utmi_clk;
|
||||
}
|
||||
|
||||
if (hsotg->uphy) {
|
||||
@ -113,10 +119,29 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
|
||||
ret = hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
|
||||
} else {
|
||||
ret = phy_init(hsotg->phy);
|
||||
if (ret == 0)
|
||||
if (ret == 0) {
|
||||
ret = phy_power_on(hsotg->phy);
|
||||
if (ret)
|
||||
phy_exit(hsotg->phy);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret)
|
||||
goto err_dis_clk;
|
||||
|
||||
return 0;
|
||||
|
||||
err_dis_clk:
|
||||
if (hsotg->clk)
|
||||
clk_disable_unprepare(hsotg->clk);
|
||||
|
||||
err_dis_utmi_clk:
|
||||
if (hsotg->utmi_clk)
|
||||
clk_disable_unprepare(hsotg->utmi_clk);
|
||||
|
||||
err_dis_reg:
|
||||
regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -156,6 +181,9 @@ static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg)
|
||||
if (hsotg->clk)
|
||||
clk_disable_unprepare(hsotg->clk);
|
||||
|
||||
if (hsotg->utmi_clk)
|
||||
clk_disable_unprepare(hsotg->utmi_clk);
|
||||
|
||||
return regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
|
||||
}
|
||||
|
||||
@ -232,6 +260,11 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
|
||||
if (IS_ERR(hsotg->clk))
|
||||
return dev_err_probe(hsotg->dev, PTR_ERR(hsotg->clk), "cannot get otg clock\n");
|
||||
|
||||
hsotg->utmi_clk = devm_clk_get_optional(hsotg->dev, "utmi");
|
||||
if (IS_ERR(hsotg->utmi_clk))
|
||||
return dev_err_probe(hsotg->dev, PTR_ERR(hsotg->utmi_clk),
|
||||
"cannot get utmi clock\n");
|
||||
|
||||
/* Regulators */
|
||||
for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++)
|
||||
hsotg->supplies[i].supply = dwc2_hsotg_supply_names[i];
|
||||
|
@ -534,90 +534,6 @@ void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
|
||||
}
|
||||
|
||||
static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
|
||||
{
|
||||
if (!dwc->has_hibernation)
|
||||
return 0;
|
||||
|
||||
if (!dwc->nr_scratch)
|
||||
return 0;
|
||||
|
||||
dwc->scratchbuf = kmalloc_array(dwc->nr_scratch,
|
||||
DWC3_SCRATCHBUF_SIZE, GFP_KERNEL);
|
||||
if (!dwc->scratchbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
|
||||
{
|
||||
dma_addr_t scratch_addr;
|
||||
u32 param;
|
||||
int ret;
|
||||
|
||||
if (!dwc->has_hibernation)
|
||||
return 0;
|
||||
|
||||
if (!dwc->nr_scratch)
|
||||
return 0;
|
||||
|
||||
/* should never fall here */
|
||||
if (!WARN_ON(dwc->scratchbuf))
|
||||
return 0;
|
||||
|
||||
scratch_addr = dma_map_single(dwc->sysdev, dwc->scratchbuf,
|
||||
dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
|
||||
DMA_BIDIRECTIONAL);
|
||||
if (dma_mapping_error(dwc->sysdev, scratch_addr)) {
|
||||
dev_err(dwc->sysdev, "failed to map scratch buffer\n");
|
||||
ret = -EFAULT;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
dwc->scratch_addr = scratch_addr;
|
||||
|
||||
param = lower_32_bits(scratch_addr);
|
||||
|
||||
ret = dwc3_send_gadget_generic_command(dwc,
|
||||
DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param);
|
||||
if (ret < 0)
|
||||
goto err1;
|
||||
|
||||
param = upper_32_bits(scratch_addr);
|
||||
|
||||
ret = dwc3_send_gadget_generic_command(dwc,
|
||||
DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param);
|
||||
if (ret < 0)
|
||||
goto err1;
|
||||
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
dma_unmap_single(dwc->sysdev, dwc->scratch_addr, dwc->nr_scratch *
|
||||
DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dwc3_free_scratch_buffers(struct dwc3 *dwc)
|
||||
{
|
||||
if (!dwc->has_hibernation)
|
||||
return;
|
||||
|
||||
if (!dwc->nr_scratch)
|
||||
return;
|
||||
|
||||
/* should never fall here */
|
||||
if (!WARN_ON(dwc->scratchbuf))
|
||||
return;
|
||||
|
||||
dma_unmap_single(dwc->sysdev, dwc->scratch_addr, dwc->nr_scratch *
|
||||
DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
|
||||
kfree(dwc->scratchbuf);
|
||||
}
|
||||
|
||||
static void dwc3_core_num_eps(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_hwparams *parms = &dwc->hwparams;
|
||||
@ -800,11 +716,91 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
|
||||
if (dwc->dis_u2_freeclk_exists_quirk || dwc->gfladj_refclk_lpm_sel)
|
||||
reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
|
||||
|
||||
/*
|
||||
* Some ULPI USB PHY does not support internal VBUS supply, to drive
|
||||
* the CPEN pin requires the configuration of the ULPI DRVVBUSEXTERNAL
|
||||
* bit of OTG_CTRL register. Controller configures the USB2 PHY
|
||||
* ULPIEXTVBUSDRV bit[17] of the GUSB2PHYCFG register to drive vBus
|
||||
* with an external supply.
|
||||
*/
|
||||
if (dwc->ulpi_ext_vbus_drv)
|
||||
reg |= DWC3_GUSB2PHYCFG_ULPIEXTVBUSDRV;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_phy_init(struct dwc3 *dwc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
usb_phy_init(dwc->usb2_phy);
|
||||
usb_phy_init(dwc->usb3_phy);
|
||||
|
||||
ret = phy_init(dwc->usb2_generic_phy);
|
||||
if (ret < 0)
|
||||
goto err_shutdown_usb3_phy;
|
||||
|
||||
ret = phy_init(dwc->usb3_generic_phy);
|
||||
if (ret < 0)
|
||||
goto err_exit_usb2_phy;
|
||||
|
||||
return 0;
|
||||
|
||||
err_exit_usb2_phy:
|
||||
phy_exit(dwc->usb2_generic_phy);
|
||||
err_shutdown_usb3_phy:
|
||||
usb_phy_shutdown(dwc->usb3_phy);
|
||||
usb_phy_shutdown(dwc->usb2_phy);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dwc3_phy_exit(struct dwc3 *dwc)
|
||||
{
|
||||
phy_exit(dwc->usb3_generic_phy);
|
||||
phy_exit(dwc->usb2_generic_phy);
|
||||
|
||||
usb_phy_shutdown(dwc->usb3_phy);
|
||||
usb_phy_shutdown(dwc->usb2_phy);
|
||||
}
|
||||
|
||||
static int dwc3_phy_power_on(struct dwc3 *dwc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
usb_phy_set_suspend(dwc->usb2_phy, 0);
|
||||
usb_phy_set_suspend(dwc->usb3_phy, 0);
|
||||
|
||||
ret = phy_power_on(dwc->usb2_generic_phy);
|
||||
if (ret < 0)
|
||||
goto err_suspend_usb3_phy;
|
||||
|
||||
ret = phy_power_on(dwc->usb3_generic_phy);
|
||||
if (ret < 0)
|
||||
goto err_power_off_usb2_phy;
|
||||
|
||||
return 0;
|
||||
|
||||
err_power_off_usb2_phy:
|
||||
phy_power_off(dwc->usb2_generic_phy);
|
||||
err_suspend_usb3_phy:
|
||||
usb_phy_set_suspend(dwc->usb3_phy, 1);
|
||||
usb_phy_set_suspend(dwc->usb2_phy, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dwc3_phy_power_off(struct dwc3 *dwc)
|
||||
{
|
||||
phy_power_off(dwc->usb3_generic_phy);
|
||||
phy_power_off(dwc->usb2_generic_phy);
|
||||
|
||||
usb_phy_set_suspend(dwc->usb3_phy, 1);
|
||||
usb_phy_set_suspend(dwc->usb2_phy, 1);
|
||||
}
|
||||
|
||||
static int dwc3_clk_enable(struct dwc3 *dwc)
|
||||
{
|
||||
int ret;
|
||||
@ -840,17 +836,8 @@ static void dwc3_clk_disable(struct dwc3 *dwc)
|
||||
static void dwc3_core_exit(struct dwc3 *dwc)
|
||||
{
|
||||
dwc3_event_buffers_cleanup(dwc);
|
||||
|
||||
usb_phy_set_suspend(dwc->usb2_phy, 1);
|
||||
usb_phy_set_suspend(dwc->usb3_phy, 1);
|
||||
phy_power_off(dwc->usb2_generic_phy);
|
||||
phy_power_off(dwc->usb3_generic_phy);
|
||||
|
||||
usb_phy_shutdown(dwc->usb2_phy);
|
||||
usb_phy_shutdown(dwc->usb3_phy);
|
||||
phy_exit(dwc->usb2_generic_phy);
|
||||
phy_exit(dwc->usb3_generic_phy);
|
||||
|
||||
dwc3_phy_power_off(dwc);
|
||||
dwc3_phy_exit(dwc);
|
||||
dwc3_clk_disable(dwc);
|
||||
reset_control_assert(dwc->reset);
|
||||
}
|
||||
@ -877,7 +864,6 @@ static bool dwc3_core_is_valid(struct dwc3 *dwc)
|
||||
|
||||
static void dwc3_core_setup_global_control(struct dwc3 *dwc)
|
||||
{
|
||||
u32 hwparams4 = dwc->hwparams.hwparams4;
|
||||
u32 reg;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
@ -905,9 +891,6 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc)
|
||||
reg &= ~DWC3_GCTL_DSBLCLKGTNG;
|
||||
break;
|
||||
case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
|
||||
/* enable hibernation here */
|
||||
dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);
|
||||
|
||||
/*
|
||||
* REVISIT Enabling this bit so that host-mode hibernation
|
||||
* will work. Device-mode hibernation is not yet implemented.
|
||||
@ -1096,7 +1079,7 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
||||
|
||||
ret = dwc3_phy_setup(dwc);
|
||||
if (ret)
|
||||
goto err0;
|
||||
return ret;
|
||||
|
||||
if (!dwc->ulpi_ready) {
|
||||
ret = dwc3_core_ulpi_init(dwc);
|
||||
@ -1105,7 +1088,7 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
||||
dwc3_core_soft_reset(dwc);
|
||||
ret = -EPROBE_DEFER;
|
||||
}
|
||||
goto err0;
|
||||
return ret;
|
||||
}
|
||||
dwc->ulpi_ready = true;
|
||||
}
|
||||
@ -1113,25 +1096,17 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
||||
if (!dwc->phys_ready) {
|
||||
ret = dwc3_core_get_phy(dwc);
|
||||
if (ret)
|
||||
goto err0a;
|
||||
goto err_exit_ulpi;
|
||||
dwc->phys_ready = true;
|
||||
}
|
||||
|
||||
usb_phy_init(dwc->usb2_phy);
|
||||
usb_phy_init(dwc->usb3_phy);
|
||||
ret = phy_init(dwc->usb2_generic_phy);
|
||||
if (ret < 0)
|
||||
goto err0a;
|
||||
|
||||
ret = phy_init(dwc->usb3_generic_phy);
|
||||
if (ret < 0) {
|
||||
phy_exit(dwc->usb2_generic_phy);
|
||||
goto err0a;
|
||||
}
|
||||
ret = dwc3_phy_init(dwc);
|
||||
if (ret)
|
||||
goto err_exit_ulpi;
|
||||
|
||||
ret = dwc3_core_soft_reset(dwc);
|
||||
if (ret)
|
||||
goto err1;
|
||||
goto err_exit_phy;
|
||||
|
||||
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD &&
|
||||
!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) {
|
||||
@ -1151,10 +1126,6 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
||||
dwc3_core_setup_global_control(dwc);
|
||||
dwc3_core_num_eps(dwc);
|
||||
|
||||
ret = dwc3_setup_scratch_buffers(dwc);
|
||||
if (ret)
|
||||
goto err1;
|
||||
|
||||
/* Set power down scale of suspend_clk */
|
||||
dwc3_set_power_down_clk_scale(dwc);
|
||||
|
||||
@ -1166,20 +1137,14 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
||||
|
||||
dwc3_set_incr_burst_type(dwc);
|
||||
|
||||
usb_phy_set_suspend(dwc->usb2_phy, 0);
|
||||
usb_phy_set_suspend(dwc->usb3_phy, 0);
|
||||
ret = phy_power_on(dwc->usb2_generic_phy);
|
||||
if (ret < 0)
|
||||
goto err2;
|
||||
|
||||
ret = phy_power_on(dwc->usb3_generic_phy);
|
||||
if (ret < 0)
|
||||
goto err3;
|
||||
dwc3_phy_power_on(dwc);
|
||||
if (ret)
|
||||
goto err_exit_phy;
|
||||
|
||||
ret = dwc3_event_buffers_setup(dwc);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to setup event buffers\n");
|
||||
goto err4;
|
||||
goto err_power_off_phy;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1233,6 +1198,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
||||
if (dwc->parkmode_disable_ss_quirk)
|
||||
reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS;
|
||||
|
||||
if (dwc->parkmode_disable_hs_quirk)
|
||||
reg |= DWC3_GUCTL1_PARKMODE_DISABLE_HS;
|
||||
|
||||
if (DWC3_VER_IS_WITHIN(DWC3, 290A, ANY) &&
|
||||
(dwc->maximum_speed == USB_SPEED_HIGH ||
|
||||
dwc->maximum_speed == USB_SPEED_FULL))
|
||||
@ -1296,26 +1264,13 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
||||
|
||||
return 0;
|
||||
|
||||
err4:
|
||||
phy_power_off(dwc->usb3_generic_phy);
|
||||
|
||||
err3:
|
||||
phy_power_off(dwc->usb2_generic_phy);
|
||||
|
||||
err2:
|
||||
usb_phy_set_suspend(dwc->usb2_phy, 1);
|
||||
usb_phy_set_suspend(dwc->usb3_phy, 1);
|
||||
|
||||
err1:
|
||||
usb_phy_shutdown(dwc->usb2_phy);
|
||||
usb_phy_shutdown(dwc->usb3_phy);
|
||||
phy_exit(dwc->usb2_generic_phy);
|
||||
phy_exit(dwc->usb3_generic_phy);
|
||||
|
||||
err0a:
|
||||
err_power_off_phy:
|
||||
dwc3_phy_power_off(dwc);
|
||||
err_exit_phy:
|
||||
dwc3_phy_exit(dwc);
|
||||
err_exit_ulpi:
|
||||
dwc3_ulpi_exit(dwc);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1553,8 +1508,12 @@ static void dwc3_get_properties(struct dwc3 *dwc)
|
||||
"snps,dis-tx-ipgap-linecheck-quirk");
|
||||
dwc->resume_hs_terminations = device_property_read_bool(dev,
|
||||
"snps,resume-hs-terminations");
|
||||
dwc->ulpi_ext_vbus_drv = device_property_read_bool(dev,
|
||||
"snps,ulpi-ext-vbus-drv");
|
||||
dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev,
|
||||
"snps,parkmode-disable-ss-quirk");
|
||||
dwc->parkmode_disable_hs_quirk = device_property_read_bool(dev,
|
||||
"snps,parkmode-disable-hs-quirk");
|
||||
dwc->gfladj_refclk_lpm_sel = device_property_read_bool(dev,
|
||||
"snps,gfladj-refclk-lpm-sel-quirk");
|
||||
|
||||
@ -1750,15 +1709,71 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
|
||||
return edev;
|
||||
}
|
||||
|
||||
static int dwc3_get_clocks(struct dwc3 *dwc)
|
||||
{
|
||||
struct device *dev = dwc->dev;
|
||||
|
||||
if (!dev->of_node)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Clocks are optional, but new DT platforms should support all clocks
|
||||
* as required by the DT-binding.
|
||||
* Some devices have different clock names in legacy device trees,
|
||||
* check for them to retain backwards compatibility.
|
||||
*/
|
||||
dwc->bus_clk = devm_clk_get_optional(dev, "bus_early");
|
||||
if (IS_ERR(dwc->bus_clk)) {
|
||||
return dev_err_probe(dev, PTR_ERR(dwc->bus_clk),
|
||||
"could not get bus clock\n");
|
||||
}
|
||||
|
||||
if (dwc->bus_clk == NULL) {
|
||||
dwc->bus_clk = devm_clk_get_optional(dev, "bus_clk");
|
||||
if (IS_ERR(dwc->bus_clk)) {
|
||||
return dev_err_probe(dev, PTR_ERR(dwc->bus_clk),
|
||||
"could not get bus clock\n");
|
||||
}
|
||||
}
|
||||
|
||||
dwc->ref_clk = devm_clk_get_optional(dev, "ref");
|
||||
if (IS_ERR(dwc->ref_clk)) {
|
||||
return dev_err_probe(dev, PTR_ERR(dwc->ref_clk),
|
||||
"could not get ref clock\n");
|
||||
}
|
||||
|
||||
if (dwc->ref_clk == NULL) {
|
||||
dwc->ref_clk = devm_clk_get_optional(dev, "ref_clk");
|
||||
if (IS_ERR(dwc->ref_clk)) {
|
||||
return dev_err_probe(dev, PTR_ERR(dwc->ref_clk),
|
||||
"could not get ref clock\n");
|
||||
}
|
||||
}
|
||||
|
||||
dwc->susp_clk = devm_clk_get_optional(dev, "suspend");
|
||||
if (IS_ERR(dwc->susp_clk)) {
|
||||
return dev_err_probe(dev, PTR_ERR(dwc->susp_clk),
|
||||
"could not get suspend clock\n");
|
||||
}
|
||||
|
||||
if (dwc->susp_clk == NULL) {
|
||||
dwc->susp_clk = devm_clk_get_optional(dev, "suspend_clk");
|
||||
if (IS_ERR(dwc->susp_clk)) {
|
||||
return dev_err_probe(dev, PTR_ERR(dwc->susp_clk),
|
||||
"could not get suspend clock\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res, dwc_res;
|
||||
struct dwc3 *dwc;
|
||||
|
||||
int ret;
|
||||
|
||||
void __iomem *regs;
|
||||
struct dwc3 *dwc;
|
||||
int ret;
|
||||
|
||||
dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
|
||||
if (!dwc)
|
||||
@ -1797,77 +1812,25 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
dwc->reset = devm_reset_control_array_get_optional_shared(dev);
|
||||
if (IS_ERR(dwc->reset)) {
|
||||
ret = PTR_ERR(dwc->reset);
|
||||
goto put_usb_psy;
|
||||
goto err_put_psy;
|
||||
}
|
||||
|
||||
if (dev->of_node) {
|
||||
/*
|
||||
* Clocks are optional, but new DT platforms should support all
|
||||
* clocks as required by the DT-binding.
|
||||
* Some devices have different clock names in legacy device trees,
|
||||
* check for them to retain backwards compatibility.
|
||||
*/
|
||||
dwc->bus_clk = devm_clk_get_optional(dev, "bus_early");
|
||||
if (IS_ERR(dwc->bus_clk)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(dwc->bus_clk),
|
||||
"could not get bus clock\n");
|
||||
goto put_usb_psy;
|
||||
}
|
||||
|
||||
if (dwc->bus_clk == NULL) {
|
||||
dwc->bus_clk = devm_clk_get_optional(dev, "bus_clk");
|
||||
if (IS_ERR(dwc->bus_clk)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(dwc->bus_clk),
|
||||
"could not get bus clock\n");
|
||||
goto put_usb_psy;
|
||||
}
|
||||
}
|
||||
|
||||
dwc->ref_clk = devm_clk_get_optional(dev, "ref");
|
||||
if (IS_ERR(dwc->ref_clk)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(dwc->ref_clk),
|
||||
"could not get ref clock\n");
|
||||
goto put_usb_psy;
|
||||
}
|
||||
|
||||
if (dwc->ref_clk == NULL) {
|
||||
dwc->ref_clk = devm_clk_get_optional(dev, "ref_clk");
|
||||
if (IS_ERR(dwc->ref_clk)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(dwc->ref_clk),
|
||||
"could not get ref clock\n");
|
||||
goto put_usb_psy;
|
||||
}
|
||||
}
|
||||
|
||||
dwc->susp_clk = devm_clk_get_optional(dev, "suspend");
|
||||
if (IS_ERR(dwc->susp_clk)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(dwc->susp_clk),
|
||||
"could not get suspend clock\n");
|
||||
goto put_usb_psy;
|
||||
}
|
||||
|
||||
if (dwc->susp_clk == NULL) {
|
||||
dwc->susp_clk = devm_clk_get_optional(dev, "suspend_clk");
|
||||
if (IS_ERR(dwc->susp_clk)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(dwc->susp_clk),
|
||||
"could not get suspend clock\n");
|
||||
goto put_usb_psy;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = dwc3_get_clocks(dwc);
|
||||
if (ret)
|
||||
goto err_put_psy;
|
||||
|
||||
ret = reset_control_deassert(dwc->reset);
|
||||
if (ret)
|
||||
goto put_usb_psy;
|
||||
goto err_put_psy;
|
||||
|
||||
ret = dwc3_clk_enable(dwc);
|
||||
if (ret)
|
||||
goto assert_reset;
|
||||
goto err_assert_reset;
|
||||
|
||||
if (!dwc3_core_is_valid(dwc)) {
|
||||
dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
|
||||
ret = -ENODEV;
|
||||
goto disable_clks;
|
||||
goto err_disable_clks;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, dwc);
|
||||
@ -1877,19 +1840,17 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
DWC3_GHWPARAMS0_AWIDTH(dwc->hwparams.hwparams0) == 64) {
|
||||
ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64));
|
||||
if (ret)
|
||||
goto disable_clks;
|
||||
goto err_disable_clks;
|
||||
}
|
||||
|
||||
spin_lock_init(&dwc->lock);
|
||||
mutex_init(&dwc->mutex);
|
||||
|
||||
pm_runtime_get_noresume(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY);
|
||||
pm_runtime_enable(dev);
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0)
|
||||
goto err1;
|
||||
|
||||
pm_runtime_forbid(dev);
|
||||
|
||||
@ -1897,27 +1858,23 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to allocate event buffers\n");
|
||||
ret = -ENOMEM;
|
||||
goto err2;
|
||||
goto err_allow_rpm;
|
||||
}
|
||||
|
||||
dwc->edev = dwc3_get_extcon(dwc);
|
||||
if (IS_ERR(dwc->edev)) {
|
||||
ret = dev_err_probe(dwc->dev, PTR_ERR(dwc->edev), "failed to get extcon\n");
|
||||
goto err3;
|
||||
goto err_free_event_buffers;
|
||||
}
|
||||
|
||||
ret = dwc3_get_dr_mode(dwc);
|
||||
if (ret)
|
||||
goto err3;
|
||||
|
||||
ret = dwc3_alloc_scratch_buffers(dwc);
|
||||
if (ret)
|
||||
goto err3;
|
||||
goto err_free_event_buffers;
|
||||
|
||||
ret = dwc3_core_init(dwc);
|
||||
if (ret) {
|
||||
dev_err_probe(dev, ret, "failed to initialize core\n");
|
||||
goto err4;
|
||||
goto err_free_event_buffers;
|
||||
}
|
||||
|
||||
dwc3_check_params(dwc);
|
||||
@ -1925,46 +1882,31 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
|
||||
ret = dwc3_core_init_mode(dwc);
|
||||
if (ret)
|
||||
goto err5;
|
||||
goto err_exit_debugfs;
|
||||
|
||||
pm_runtime_put(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err5:
|
||||
err_exit_debugfs:
|
||||
dwc3_debugfs_exit(dwc);
|
||||
dwc3_event_buffers_cleanup(dwc);
|
||||
|
||||
usb_phy_set_suspend(dwc->usb2_phy, 1);
|
||||
usb_phy_set_suspend(dwc->usb3_phy, 1);
|
||||
phy_power_off(dwc->usb2_generic_phy);
|
||||
phy_power_off(dwc->usb3_generic_phy);
|
||||
|
||||
usb_phy_shutdown(dwc->usb2_phy);
|
||||
usb_phy_shutdown(dwc->usb3_phy);
|
||||
phy_exit(dwc->usb2_generic_phy);
|
||||
phy_exit(dwc->usb3_generic_phy);
|
||||
|
||||
dwc3_phy_power_off(dwc);
|
||||
dwc3_phy_exit(dwc);
|
||||
dwc3_ulpi_exit(dwc);
|
||||
|
||||
err4:
|
||||
dwc3_free_scratch_buffers(dwc);
|
||||
|
||||
err3:
|
||||
err_free_event_buffers:
|
||||
dwc3_free_event_buffers(dwc);
|
||||
|
||||
err2:
|
||||
pm_runtime_allow(&pdev->dev);
|
||||
|
||||
err1:
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
disable_clks:
|
||||
err_allow_rpm:
|
||||
pm_runtime_allow(dev);
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_dont_use_autosuspend(dev);
|
||||
pm_runtime_set_suspended(dev);
|
||||
pm_runtime_put_noidle(dev);
|
||||
err_disable_clks:
|
||||
dwc3_clk_disable(dwc);
|
||||
assert_reset:
|
||||
err_assert_reset:
|
||||
reset_control_assert(dwc->reset);
|
||||
put_usb_psy:
|
||||
err_put_psy:
|
||||
if (dwc->usb_psy)
|
||||
power_supply_put(dwc->usb_psy);
|
||||
|
||||
@ -1983,12 +1925,13 @@ static int dwc3_remove(struct platform_device *pdev)
|
||||
dwc3_core_exit(dwc);
|
||||
dwc3_ulpi_exit(dwc);
|
||||
|
||||
pm_runtime_allow(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
|
||||
dwc3_free_event_buffers(dwc);
|
||||
dwc3_free_scratch_buffers(dwc);
|
||||
|
||||
if (dwc->usb_psy)
|
||||
power_supply_put(dwc->usb_psy);
|
||||
|
@ -263,6 +263,7 @@
|
||||
#define DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK BIT(26)
|
||||
#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24)
|
||||
#define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT(17)
|
||||
#define DWC3_GUCTL1_PARKMODE_DISABLE_HS BIT(16)
|
||||
#define DWC3_GUCTL1_RESUME_OPMODE_HS_HOST BIT(10)
|
||||
|
||||
/* Global Status Register */
|
||||
@ -280,6 +281,7 @@
|
||||
/* Global USB2 PHY Configuration Register */
|
||||
#define DWC3_GUSB2PHYCFG_PHYSOFTRST BIT(31)
|
||||
#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS BIT(30)
|
||||
#define DWC3_GUSB2PHYCFG_ULPIEXTVBUSDRV BIT(17)
|
||||
#define DWC3_GUSB2PHYCFG_SUSPHY BIT(6)
|
||||
#define DWC3_GUSB2PHYCFG_ULPI_UTMI BIT(4)
|
||||
#define DWC3_GUSB2PHYCFG_ENBLSLPM BIT(8)
|
||||
@ -526,6 +528,7 @@
|
||||
#define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c
|
||||
#define DWC3_DGCMD_SET_ENDPOINT_PRIME 0x0d
|
||||
#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10
|
||||
#define DWC3_DGCMD_DEV_NOTIFICATION 0x07
|
||||
|
||||
#define DWC3_DGCMD_STATUS(n) (((n) >> 12) & 0x0F)
|
||||
#define DWC3_DGCMD_CMDACT BIT(10)
|
||||
@ -538,6 +541,8 @@
|
||||
#define DWC3_DGCMDPAR_TX_FIFO BIT(5)
|
||||
#define DWC3_DGCMDPAR_LOOPBACK_DIS (0 << 0)
|
||||
#define DWC3_DGCMDPAR_LOOPBACK_ENA BIT(0)
|
||||
#define DWC3_DGCMDPAR_DN_FUNC_WAKE BIT(0)
|
||||
#define DWC3_DGCMDPAR_INTF_SEL(n) ((n) << 4)
|
||||
|
||||
/* Device Endpoint Command Register */
|
||||
#define DWC3_DEPCMD_PARAM_SHIFT 16
|
||||
@ -969,12 +974,10 @@ struct dwc3_scratchpad_array {
|
||||
* @drd_work: workqueue used for role swapping
|
||||
* @ep0_trb: trb which is used for the ctrl_req
|
||||
* @bounce: address of bounce buffer
|
||||
* @scratchbuf: address of scratch buffer
|
||||
* @setup_buf: used while precessing STD USB requests
|
||||
* @ep0_trb_addr: dma address of @ep0_trb
|
||||
* @bounce_addr: dma address of @bounce
|
||||
* @ep0_usb_req: dummy req used while handling STD USB requests
|
||||
* @scratch_addr: dma address of scratchbuf
|
||||
* @ep0_in_setup: one control transfer is completed and enter setup phase
|
||||
* @lock: for synchronizing
|
||||
* @mutex: for mode switching
|
||||
@ -999,7 +1002,6 @@ struct dwc3_scratchpad_array {
|
||||
* @current_otg_role: current role of operation while using the OTG block
|
||||
* @desired_otg_role: desired role of operation while using the OTG block
|
||||
* @otg_restart_host: flag that OTG controller needs to restart host
|
||||
* @nr_scratch: number of scratch buffers
|
||||
* @u1u2: only used on revisions <1.83a for workaround
|
||||
* @maximum_speed: maximum speed requested (mainly for testing purposes)
|
||||
* @max_ssp_rate: SuperSpeed Plus maximum signaling rate and lane count
|
||||
@ -1056,7 +1058,6 @@ struct dwc3_scratchpad_array {
|
||||
* @delayed_status: true when gadget driver asks for delayed status
|
||||
* @ep0_bounced: true when we used bounce buffer
|
||||
* @ep0_expect_in: true when we expect a DATA IN transfer
|
||||
* @has_hibernation: true when dwc3 was configured with Hibernation
|
||||
* @sysdev_is_parent: true when dwc3 device has a parent driver
|
||||
* @has_lpm_erratum: true when core was configured with LPM Erratum. Note that
|
||||
* there's now way for software to detect this in runtime.
|
||||
@ -1100,8 +1101,12 @@ struct dwc3_scratchpad_array {
|
||||
* check during HS transmit.
|
||||
* @resume_hs_terminations: Set if we enable quirk for fixing improper crc
|
||||
* generation after resume from suspend.
|
||||
* @ulpi_ext_vbus_drv: Set to confiure the upli chip to drives CPEN pin
|
||||
* VBUS with an external supply.
|
||||
* @parkmode_disable_ss_quirk: set if we need to disable all SuperSpeed
|
||||
* instances in park mode.
|
||||
* @parkmode_disable_hs_quirk: set if we need to disable all HishSpeed
|
||||
* instances in park mode.
|
||||
* @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
|
||||
* @tx_de_emphasis: Tx de-emphasis value
|
||||
* 0 - -6dB de-emphasis
|
||||
@ -1110,6 +1115,7 @@ struct dwc3_scratchpad_array {
|
||||
* 3 - Reserved
|
||||
* @dis_metastability_quirk: set to disable metastability quirk.
|
||||
* @dis_split_quirk: set to disable split boundary.
|
||||
* @wakeup_configured: set if the device is configured for remote wakeup.
|
||||
* @imod_interval: set the interrupt moderation interval in 250ns
|
||||
* increments or 0 to disable.
|
||||
* @max_cfg_eps: current max number of IN eps used across all USB configs.
|
||||
@ -1123,11 +1129,9 @@ struct dwc3 {
|
||||
struct work_struct drd_work;
|
||||
struct dwc3_trb *ep0_trb;
|
||||
void *bounce;
|
||||
void *scratchbuf;
|
||||
u8 *setup_buf;
|
||||
dma_addr_t ep0_trb_addr;
|
||||
dma_addr_t bounce_addr;
|
||||
dma_addr_t scratch_addr;
|
||||
struct dwc3_request ep0_usb_req;
|
||||
struct completion ep0_in_setup;
|
||||
|
||||
@ -1187,7 +1191,6 @@ struct dwc3 {
|
||||
u32 current_otg_role;
|
||||
u32 desired_otg_role;
|
||||
bool otg_restart_host;
|
||||
u32 nr_scratch;
|
||||
u32 u1u2;
|
||||
u32 maximum_speed;
|
||||
u32 gadget_max_speed;
|
||||
@ -1284,7 +1287,6 @@ struct dwc3 {
|
||||
unsigned delayed_status:1;
|
||||
unsigned ep0_bounced:1;
|
||||
unsigned ep0_expect_in:1;
|
||||
unsigned has_hibernation:1;
|
||||
unsigned sysdev_is_parent:1;
|
||||
unsigned has_lpm_erratum:1;
|
||||
unsigned is_utmi_l1_suspend:1;
|
||||
@ -1317,7 +1319,9 @@ struct dwc3 {
|
||||
unsigned dis_del_phy_power_chg_quirk:1;
|
||||
unsigned dis_tx_ipgap_linecheck_quirk:1;
|
||||
unsigned resume_hs_terminations:1;
|
||||
unsigned ulpi_ext_vbus_drv:1;
|
||||
unsigned parkmode_disable_ss_quirk:1;
|
||||
unsigned parkmode_disable_hs_quirk:1;
|
||||
unsigned gfladj_refclk_lpm_sel:1;
|
||||
|
||||
unsigned tx_de_emphasis_quirk:1;
|
||||
@ -1327,6 +1331,7 @@ struct dwc3 {
|
||||
|
||||
unsigned dis_split_quirk:1;
|
||||
unsigned async_callbacks:1;
|
||||
unsigned wakeup_configured:1;
|
||||
|
||||
u16 imod_interval;
|
||||
|
||||
|
@ -72,6 +72,8 @@ dwc3_gadget_generic_cmd_string(u8 cmd)
|
||||
return "Set Endpoint Prime";
|
||||
case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK:
|
||||
return "Run SoC Bus Loopback Test";
|
||||
case DWC3_DGCMD_DEV_NOTIFICATION:
|
||||
return "Device Notification";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
@ -88,6 +88,9 @@ static const struct debugfs_reg32 dwc3_regs[] = {
|
||||
dump_register(GPRTBIMAP_HS1),
|
||||
dump_register(GPRTBIMAP_FS0),
|
||||
dump_register(GPRTBIMAP_FS1),
|
||||
dump_register(GUCTL2),
|
||||
dump_register(VER_NUMBER),
|
||||
dump_register(VER_TYPE),
|
||||
|
||||
dump_register(GUSB2PHYCFG(0)),
|
||||
dump_register(GUSB2PHYCFG(1)),
|
||||
@ -229,6 +232,8 @@ static const struct debugfs_reg32 dwc3_regs[] = {
|
||||
dump_register(GEVNTCOUNT(0)),
|
||||
|
||||
dump_register(GHWPARAMS8),
|
||||
dump_register(GUCTL3),
|
||||
dump_register(GFLADJ),
|
||||
dump_register(DCFG),
|
||||
dump_register(DCTL),
|
||||
dump_register(DEVTEN),
|
||||
|
@ -11,12 +11,14 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
/* USB WRAPPER register offsets */
|
||||
#define USBSS_PID 0x0
|
||||
#define USBSS_OVERCURRENT_CTRL 0x4
|
||||
@ -45,6 +47,10 @@
|
||||
#define USBSS_PHY_VBUS_SEL_SHIFT 1
|
||||
#define USBSS_PHY_LANE_REVERSE BIT(0)
|
||||
|
||||
/* CORE STAT register bits */
|
||||
#define USBSS_CORE_OPERATIONAL_MODE_MASK GENMASK(13, 12)
|
||||
#define USBSS_CORE_OPERATIONAL_MODE_SHIFT 12
|
||||
|
||||
/* MODE CONTROL register bits */
|
||||
#define USBSS_MODE_VALID BIT(0)
|
||||
|
||||
@ -54,6 +60,13 @@
|
||||
#define USBSS_WAKEUP_CFG_SESSVALID_EN BIT(1)
|
||||
#define USBSS_WAKEUP_CFG_VBUSVALID_EN BIT(0)
|
||||
|
||||
#define USBSS_WAKEUP_CFG_ALL (USBSS_WAKEUP_CFG_VBUSVALID_EN | \
|
||||
USBSS_WAKEUP_CFG_SESSVALID_EN | \
|
||||
USBSS_WAKEUP_CFG_LINESTATE_EN | \
|
||||
USBSS_WAKEUP_CFG_OVERCURRENT_EN)
|
||||
|
||||
#define USBSS_WAKEUP_CFG_NONE 0
|
||||
|
||||
/* WAKEUP STAT register bits */
|
||||
#define USBSS_WAKEUP_STAT_OVERCURRENT BIT(4)
|
||||
#define USBSS_WAKEUP_STAT_LINESTATE BIT(3)
|
||||
@ -97,6 +110,7 @@ struct dwc3_data {
|
||||
struct regmap *syscon;
|
||||
unsigned int offset;
|
||||
unsigned int vbus_divider;
|
||||
u32 wakeup_stat;
|
||||
};
|
||||
|
||||
static const int dwc3_ti_rate_table[] = { /* in KHZ */
|
||||
@ -233,6 +247,12 @@ static int dwc3_ti_probe(struct platform_device *pdev)
|
||||
reg |= USBSS_MODE_VALID;
|
||||
dwc3_ti_writel(data, USBSS_MODE_CONTROL, reg);
|
||||
|
||||
/* Device has capability to wakeup system from sleep */
|
||||
device_set_wakeup_capable(dev, true);
|
||||
ret = device_wakeup_enable(dev);
|
||||
if (ret)
|
||||
dev_err(dev, "couldn't enable device as a wakeup source: %d\n", ret);
|
||||
|
||||
/* Setting up autosuspend */
|
||||
pm_runtime_set_autosuspend_delay(dev, DWC3_AM62_AUTOSUSPEND_DELAY);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
@ -281,6 +301,27 @@ static int dwc3_ti_remove(struct platform_device *pdev)
|
||||
static int dwc3_ti_suspend_common(struct device *dev)
|
||||
{
|
||||
struct dwc3_data *data = dev_get_drvdata(dev);
|
||||
u32 reg, current_prtcap_dir;
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
reg = dwc3_ti_readl(data, USBSS_CORE_STAT);
|
||||
current_prtcap_dir = (reg & USBSS_CORE_OPERATIONAL_MODE_MASK)
|
||||
>> USBSS_CORE_OPERATIONAL_MODE_SHIFT;
|
||||
/* Set wakeup config enable bits */
|
||||
reg = dwc3_ti_readl(data, USBSS_WAKEUP_CONFIG);
|
||||
if (current_prtcap_dir == DWC3_GCTL_PRTCAP_HOST) {
|
||||
reg = USBSS_WAKEUP_CFG_LINESTATE_EN | USBSS_WAKEUP_CFG_OVERCURRENT_EN;
|
||||
} else {
|
||||
reg = USBSS_WAKEUP_CFG_VBUSVALID_EN | USBSS_WAKEUP_CFG_SESSVALID_EN;
|
||||
/*
|
||||
* Enable LINESTATE wake up only if connected to bus
|
||||
* and in U2/L3 state else it causes spurious wake-up.
|
||||
*/
|
||||
}
|
||||
dwc3_ti_writel(data, USBSS_WAKEUP_CONFIG, reg);
|
||||
/* clear wakeup status so we know what caused the wake up */
|
||||
dwc3_ti_writel(data, USBSS_WAKEUP_STAT, USBSS_WAKEUP_STAT_CLR);
|
||||
}
|
||||
|
||||
clk_disable_unprepare(data->usb2_refclk);
|
||||
|
||||
@ -290,9 +331,18 @@ static int dwc3_ti_suspend_common(struct device *dev)
|
||||
static int dwc3_ti_resume_common(struct device *dev)
|
||||
{
|
||||
struct dwc3_data *data = dev_get_drvdata(dev);
|
||||
u32 reg;
|
||||
|
||||
clk_prepare_enable(data->usb2_refclk);
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
/* Clear wakeup config enable bits */
|
||||
dwc3_ti_writel(data, USBSS_WAKEUP_CONFIG, USBSS_WAKEUP_CFG_NONE);
|
||||
}
|
||||
|
||||
reg = dwc3_ti_readl(data, USBSS_WAKEUP_STAT);
|
||||
data->wakeup_stat = reg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -388,107 +388,41 @@ static void dwc3_pci_remove(struct pci_dev *pci)
|
||||
}
|
||||
|
||||
static const struct pci_device_id dwc3_pci_id_table[] = {
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BSW),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
{ PCI_DEVICE_DATA(INTEL, BSW, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, BYT, &dwc3_pci_intel_byt_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, MRFLD, &dwc3_pci_intel_mrfld_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, CMLLP, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, CMLH, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, SPTLP, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, SPTH, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, BXT, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, BXT_M, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, APL, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, KBP, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, GLK, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, CNPLP, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, CNPH, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, CNPV, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, ICLLP, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, EHL, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, TGPLP, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, TGPH, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, JSP, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, ADL, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, ADL_PCH, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, ADLN, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, ADLN_PCH, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, ADLS, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, RPL, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, RPLS, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, MTLM, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, MTLP, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, MTL, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, MTLS, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, TGL, &dwc3_pci_intel_swnode) },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BYT),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_byt_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MRFLD),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_mrfld_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CMLLP),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CMLH),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTLP),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTH),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT_M),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_APL),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_KBP),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_GLK),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPLP),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPH),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPV),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHL),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPLP),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPH),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_JSP),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL_PCH),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLN),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLN_PCH),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLS),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPL),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPLS),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLM),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLP),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLS),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGL),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_NL_USB),
|
||||
(kernel_ulong_t) &dwc3_pci_amd_swnode, },
|
||||
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MR),
|
||||
(kernel_ulong_t)&dwc3_pci_amd_mr_swnode, },
|
||||
{ PCI_DEVICE_DATA(AMD, NL_USB, &dwc3_pci_amd_swnode) },
|
||||
{ PCI_DEVICE_DATA(AMD, MR, &dwc3_pci_amd_mr_swnode) },
|
||||
|
||||
{ } /* Terminating Entry */
|
||||
};
|
||||
|
@ -30,6 +30,8 @@
|
||||
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep);
|
||||
static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
struct dwc3_ep *dep, struct dwc3_request *req);
|
||||
static int dwc3_ep0_delegate_req(struct dwc3 *dwc,
|
||||
struct usb_ctrlrequest *ctrl);
|
||||
|
||||
static void dwc3_ep0_prepare_one_trb(struct dwc3_ep *dep,
|
||||
dma_addr_t buf_dma, u32 len, u32 type, bool chain)
|
||||
@ -356,6 +358,9 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
|
||||
usb_status |= 1 << USB_DEV_STAT_U1_ENABLED;
|
||||
if (reg & DWC3_DCTL_INITU2ENA)
|
||||
usb_status |= 1 << USB_DEV_STAT_U2_ENABLED;
|
||||
} else {
|
||||
usb_status |= dwc->gadget->wakeup_armed <<
|
||||
USB_DEVICE_REMOTE_WAKEUP;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -365,7 +370,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
|
||||
* Function Remote Wake Capable D0
|
||||
* Function Remote Wakeup D1
|
||||
*/
|
||||
break;
|
||||
return dwc3_ep0_delegate_req(dwc, ctrl);
|
||||
|
||||
case USB_RECIP_ENDPOINT:
|
||||
dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
|
||||
@ -476,6 +481,10 @@ static int dwc3_ep0_handle_device(struct dwc3 *dwc,
|
||||
|
||||
switch (wValue) {
|
||||
case USB_DEVICE_REMOTE_WAKEUP:
|
||||
if (dwc->wakeup_configured)
|
||||
dwc->gadget->wakeup_armed = set;
|
||||
else
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
/*
|
||||
* 9.4.1 says only for SS, in AddressState only for
|
||||
@ -510,13 +519,7 @@ static int dwc3_ep0_handle_intf(struct dwc3 *dwc,
|
||||
|
||||
switch (wValue) {
|
||||
case USB_INTRF_FUNC_SUSPEND:
|
||||
/*
|
||||
* REVISIT: Ideally we would enable some low power mode here,
|
||||
* however it's unclear what we should be doing here.
|
||||
*
|
||||
* For now, we're not doing anything, just making sure we return
|
||||
* 0 so USB Command Verifier tests pass without any errors.
|
||||
*/
|
||||
ret = dwc3_ep0_delegate_req(dwc, ctrl);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
|
@ -139,6 +139,24 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static void dwc3_ep0_reset_state(struct dwc3 *dwc)
|
||||
{
|
||||
unsigned int dir;
|
||||
|
||||
if (dwc->ep0state != EP0_SETUP_PHASE) {
|
||||
dir = !!dwc->ep0_expect_in;
|
||||
if (dwc->ep0state == EP0_DATA_PHASE)
|
||||
dwc3_ep0_end_control_data(dwc, dwc->eps[dir]);
|
||||
else
|
||||
dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]);
|
||||
|
||||
dwc->eps[0]->trb_enqueue = 0;
|
||||
dwc->eps[1]->trb_enqueue = 0;
|
||||
|
||||
dwc3_ep0_stall_and_restart(dwc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_ep_inc_trb - increment a trb index.
|
||||
* @index: Pointer to the TRB index to increment.
|
||||
@ -258,7 +276,7 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned int cmd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __dwc3_gadget_wakeup(struct dwc3 *dwc);
|
||||
static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async);
|
||||
|
||||
/**
|
||||
* dwc3_send_gadget_ep_cmd - issue an endpoint command
|
||||
@ -325,7 +343,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd,
|
||||
|
||||
fallthrough;
|
||||
case DWC3_LINK_STATE_U3:
|
||||
ret = __dwc3_gadget_wakeup(dwc);
|
||||
ret = __dwc3_gadget_wakeup(dwc, false);
|
||||
dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n",
|
||||
ret);
|
||||
break;
|
||||
@ -2273,6 +2291,22 @@ static const struct usb_ep_ops dwc3_gadget_ep_ops = {
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static void dwc3_gadget_enable_linksts_evts(struct dwc3 *dwc, bool set)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
if (DWC3_VER_IS_PRIOR(DWC3, 250A))
|
||||
return;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DEVTEN);
|
||||
if (set)
|
||||
reg |= DWC3_DEVTEN_ULSTCNGEN;
|
||||
else
|
||||
reg &= ~DWC3_DEVTEN_ULSTCNGEN;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
|
||||
}
|
||||
|
||||
static int dwc3_gadget_get_frame(struct usb_gadget *g)
|
||||
{
|
||||
struct dwc3 *dwc = gadget_to_dwc(g);
|
||||
@ -2280,7 +2314,7 @@ static int dwc3_gadget_get_frame(struct usb_gadget *g)
|
||||
return __dwc3_gadget_get_frame(dwc);
|
||||
}
|
||||
|
||||
static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
|
||||
static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async)
|
||||
{
|
||||
int retries;
|
||||
|
||||
@ -2311,9 +2345,13 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (async)
|
||||
dwc3_gadget_enable_linksts_evts(dwc, true);
|
||||
|
||||
ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV);
|
||||
if (ret < 0) {
|
||||
dev_err(dwc->dev, "failed to put link in Recovery\n");
|
||||
dwc3_gadget_enable_linksts_evts(dwc, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2325,6 +2363,13 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since link status change events are enabled we will receive
|
||||
* an U0 event when wakeup is successful. So bail out.
|
||||
*/
|
||||
if (async)
|
||||
return 0;
|
||||
|
||||
/* poll until Link State changes to ON */
|
||||
retries = 20000;
|
||||
|
||||
@ -2350,13 +2395,77 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
if (!dwc->wakeup_configured) {
|
||||
dev_err(dwc->dev, "remote wakeup not configured\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
ret = __dwc3_gadget_wakeup(dwc);
|
||||
if (!dwc->gadget->wakeup_armed) {
|
||||
dev_err(dwc->dev, "not armed for remote wakeup\n");
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = __dwc3_gadget_wakeup(dwc, true);
|
||||
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dwc3_resume_gadget(struct dwc3 *dwc);
|
||||
|
||||
static int dwc3_gadget_func_wakeup(struct usb_gadget *g, int intf_id)
|
||||
{
|
||||
struct dwc3 *dwc = gadget_to_dwc(g);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
int link_state;
|
||||
|
||||
if (!dwc->wakeup_configured) {
|
||||
dev_err(dwc->dev, "remote wakeup not configured\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
/*
|
||||
* If the link is in U3, signal for remote wakeup and wait for the
|
||||
* link to transition to U0 before sending device notification.
|
||||
*/
|
||||
link_state = dwc3_gadget_get_link_state(dwc);
|
||||
if (link_state == DWC3_LINK_STATE_U3) {
|
||||
ret = __dwc3_gadget_wakeup(dwc, false);
|
||||
if (ret) {
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
dwc3_resume_gadget(dwc);
|
||||
dwc->link_state = DWC3_LINK_STATE_U0;
|
||||
}
|
||||
|
||||
ret = dwc3_send_gadget_generic_command(dwc, DWC3_DGCMD_DEV_NOTIFICATION,
|
||||
DWC3_DGCMDPAR_DN_FUNC_WAKE |
|
||||
DWC3_DGCMDPAR_INTF_SEL(intf_id));
|
||||
if (ret)
|
||||
dev_err(dwc->dev, "function remote wakeup failed, ret:%d\n", ret);
|
||||
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwc3_gadget_set_remote_wakeup(struct usb_gadget *g, int set)
|
||||
{
|
||||
struct dwc3 *dwc = gadget_to_dwc(g);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
dwc->wakeup_configured = !!set;
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
|
||||
int is_selfpowered)
|
||||
{
|
||||
@ -2478,7 +2587,7 @@ static void __dwc3_gadget_set_speed(struct dwc3 *dwc)
|
||||
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
|
||||
}
|
||||
|
||||
static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
|
||||
static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
|
||||
{
|
||||
u32 reg;
|
||||
u32 timeout = 2000;
|
||||
@ -2497,17 +2606,11 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
|
||||
reg &= ~DWC3_DCTL_KEEP_CONNECT;
|
||||
reg |= DWC3_DCTL_RUN_STOP;
|
||||
|
||||
if (dwc->has_hibernation)
|
||||
reg |= DWC3_DCTL_KEEP_CONNECT;
|
||||
|
||||
__dwc3_gadget_set_speed(dwc);
|
||||
dwc->pullups_connected = true;
|
||||
} else {
|
||||
reg &= ~DWC3_DCTL_RUN_STOP;
|
||||
|
||||
if (dwc->has_hibernation && !suspend)
|
||||
reg &= ~DWC3_DCTL_KEEP_CONNECT;
|
||||
|
||||
dwc->pullups_connected = false;
|
||||
}
|
||||
|
||||
@ -2532,29 +2635,17 @@ static int __dwc3_gadget_start(struct dwc3 *dwc);
|
||||
static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
dwc->connected = false;
|
||||
|
||||
/*
|
||||
* Per databook, when we want to stop the gadget, if a control transfer
|
||||
* is still in process, complete it and get the core into setup phase.
|
||||
* Attempt to end pending SETUP status phase, and not wait for the
|
||||
* function to do so.
|
||||
*/
|
||||
if (dwc->ep0state != EP0_SETUP_PHASE) {
|
||||
int ret;
|
||||
|
||||
if (dwc->delayed_status)
|
||||
dwc3_ep0_send_delayed_status(dwc);
|
||||
|
||||
reinit_completion(&dwc->ep0_in_setup);
|
||||
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
ret = wait_for_completion_timeout(&dwc->ep0_in_setup,
|
||||
msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT));
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
if (ret == 0)
|
||||
dev_warn(dwc->dev, "timed out waiting for SETUP phase\n");
|
||||
}
|
||||
if (dwc->delayed_status)
|
||||
dwc3_ep0_send_delayed_status(dwc);
|
||||
|
||||
/*
|
||||
* In the Synopsys DesignWare Cores USB3 Databook Rev. 3.30a
|
||||
@ -2564,9 +2655,28 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc)
|
||||
* bit.
|
||||
*/
|
||||
dwc3_stop_active_transfers(dwc);
|
||||
__dwc3_gadget_stop(dwc);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
/*
|
||||
* Per databook, when we want to stop the gadget, if a control transfer
|
||||
* is still in process, complete it and get the core into setup phase.
|
||||
* In case the host is unresponsive to a SETUP transaction, forcefully
|
||||
* stall the transfer, and move back to the SETUP phase, so that any
|
||||
* pending endxfers can be executed.
|
||||
*/
|
||||
if (dwc->ep0state != EP0_SETUP_PHASE) {
|
||||
reinit_completion(&dwc->ep0_in_setup);
|
||||
|
||||
ret = wait_for_completion_timeout(&dwc->ep0_in_setup,
|
||||
msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT));
|
||||
if (ret == 0) {
|
||||
dev_warn(dwc->dev, "wait for SETUP phase timed out\n");
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
dwc3_ep0_reset_state(dwc);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: if the GEVNTCOUNT indicates events in the event buffer, the
|
||||
* driver needs to acknowledge them before the controller can halt.
|
||||
@ -2574,7 +2684,19 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc)
|
||||
* remaining event generated by the controller while polling for
|
||||
* DSTS.DEVCTLHLT.
|
||||
*/
|
||||
return dwc3_gadget_run_stop(dwc, false, false);
|
||||
ret = dwc3_gadget_run_stop(dwc, false);
|
||||
|
||||
/*
|
||||
* Stop the gadget after controller is halted, so that if needed, the
|
||||
* events to update EP0 state can still occur while the run/stop
|
||||
* routine polls for the halted state. DEVTEN is cleared as part of
|
||||
* gadget stop.
|
||||
*/
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
__dwc3_gadget_stop(dwc);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
|
||||
@ -2628,7 +2750,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
|
||||
|
||||
dwc3_event_buffers_setup(dwc);
|
||||
__dwc3_gadget_start(dwc);
|
||||
ret = dwc3_gadget_run_stop(dwc, true, false);
|
||||
ret = dwc3_gadget_run_stop(dwc, true);
|
||||
}
|
||||
|
||||
pm_runtime_put(dwc->dev);
|
||||
@ -2982,6 +3104,8 @@ static void dwc3_gadget_async_callbacks(struct usb_gadget *g, bool enable)
|
||||
static const struct usb_gadget_ops dwc3_gadget_ops = {
|
||||
.get_frame = dwc3_gadget_get_frame,
|
||||
.wakeup = dwc3_gadget_wakeup,
|
||||
.func_wakeup = dwc3_gadget_func_wakeup,
|
||||
.set_remote_wakeup = dwc3_gadget_set_remote_wakeup,
|
||||
.set_selfpowered = dwc3_gadget_set_selfpowered,
|
||||
.pullup = dwc3_gadget_pullup,
|
||||
.udc_start = dwc3_gadget_start,
|
||||
@ -3827,18 +3951,11 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
|
||||
|
||||
dwc->gadget->speed = USB_SPEED_UNKNOWN;
|
||||
dwc->setup_packet_pending = false;
|
||||
dwc->gadget->wakeup_armed = false;
|
||||
dwc3_gadget_enable_linksts_evts(dwc, false);
|
||||
usb_gadget_set_state(dwc->gadget, USB_STATE_NOTATTACHED);
|
||||
|
||||
if (dwc->ep0state != EP0_SETUP_PHASE) {
|
||||
unsigned int dir;
|
||||
|
||||
dir = !!dwc->ep0_expect_in;
|
||||
if (dwc->ep0state == EP0_DATA_PHASE)
|
||||
dwc3_ep0_end_control_data(dwc, dwc->eps[dir]);
|
||||
else
|
||||
dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]);
|
||||
dwc3_ep0_stall_and_restart(dwc);
|
||||
}
|
||||
dwc3_ep0_reset_state(dwc);
|
||||
}
|
||||
|
||||
static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
|
||||
@ -3892,20 +4009,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
|
||||
* phase. So ensure that EP0 is in setup phase by issuing a stall
|
||||
* and restart if EP0 is not in setup phase.
|
||||
*/
|
||||
if (dwc->ep0state != EP0_SETUP_PHASE) {
|
||||
unsigned int dir;
|
||||
|
||||
dir = !!dwc->ep0_expect_in;
|
||||
if (dwc->ep0state == EP0_DATA_PHASE)
|
||||
dwc3_ep0_end_control_data(dwc, dwc->eps[dir]);
|
||||
else
|
||||
dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]);
|
||||
|
||||
dwc->eps[0]->trb_enqueue = 0;
|
||||
dwc->eps[1]->trb_enqueue = 0;
|
||||
|
||||
dwc3_ep0_stall_and_restart(dwc);
|
||||
}
|
||||
dwc3_ep0_reset_state(dwc);
|
||||
|
||||
/*
|
||||
* In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a
|
||||
@ -3920,6 +4024,8 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
|
||||
reg &= ~DWC3_DCTL_TSTCTRL_MASK;
|
||||
dwc3_gadget_dctl_write_safe(dwc, reg);
|
||||
dwc->test_mode = false;
|
||||
dwc->gadget->wakeup_armed = false;
|
||||
dwc3_gadget_enable_linksts_evts(dwc, false);
|
||||
dwc3_clear_stall_all_ep(dwc);
|
||||
|
||||
/* Reset device address to zero */
|
||||
@ -4072,7 +4178,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
|
||||
*/
|
||||
}
|
||||
|
||||
static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
|
||||
static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc, unsigned int evtinfo)
|
||||
{
|
||||
/*
|
||||
* TODO take core out of low power mode when that's
|
||||
@ -4084,6 +4190,8 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
|
||||
dwc->gadget_driver->resume(dwc->gadget);
|
||||
spin_lock(&dwc->lock);
|
||||
}
|
||||
|
||||
dwc->link_state = evtinfo & DWC3_LINK_STATE_MASK;
|
||||
}
|
||||
|
||||
static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
|
||||
@ -4165,6 +4273,12 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
|
||||
}
|
||||
|
||||
switch (next) {
|
||||
case DWC3_LINK_STATE_U0:
|
||||
if (dwc->gadget->wakeup_armed) {
|
||||
dwc3_gadget_enable_linksts_evts(dwc, false);
|
||||
dwc3_resume_gadget(dwc);
|
||||
}
|
||||
break;
|
||||
case DWC3_LINK_STATE_U1:
|
||||
if (dwc->speed == USB_SPEED_SUPER)
|
||||
dwc3_suspend_gadget(dwc);
|
||||
@ -4195,30 +4309,6 @@ static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc,
|
||||
dwc->link_state = next;
|
||||
}
|
||||
|
||||
static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc,
|
||||
unsigned int evtinfo)
|
||||
{
|
||||
unsigned int is_ss = evtinfo & BIT(4);
|
||||
|
||||
/*
|
||||
* WORKAROUND: DWC3 revision 2.20a with hibernation support
|
||||
* have a known issue which can cause USB CV TD.9.23 to fail
|
||||
* randomly.
|
||||
*
|
||||
* Because of this issue, core could generate bogus hibernation
|
||||
* events which SW needs to ignore.
|
||||
*
|
||||
* Refers to:
|
||||
*
|
||||
* STAR#9000546576: Device Mode Hibernation: Issue in USB 2.0
|
||||
* Device Fallback from SuperSpeed
|
||||
*/
|
||||
if (is_ss ^ (dwc->speed == USB_SPEED_SUPER))
|
||||
return;
|
||||
|
||||
/* enter hibernation here */
|
||||
}
|
||||
|
||||
static void dwc3_gadget_interrupt(struct dwc3 *dwc,
|
||||
const struct dwc3_event_devt *event)
|
||||
{
|
||||
@ -4233,29 +4323,18 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
|
||||
dwc3_gadget_conndone_interrupt(dwc);
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_WAKEUP:
|
||||
dwc3_gadget_wakeup_interrupt(dwc);
|
||||
dwc3_gadget_wakeup_interrupt(dwc, event->event_info);
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_HIBER_REQ:
|
||||
if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation,
|
||||
"unexpected hibernation event\n"))
|
||||
break;
|
||||
|
||||
dwc3_gadget_hibernation_interrupt(dwc, event->event_info);
|
||||
dev_WARN_ONCE(dwc->dev, true, "unexpected hibernation event\n");
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
|
||||
dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_SUSPEND:
|
||||
/* It changed to be suspend event for version 2.30a and above */
|
||||
if (!DWC3_VER_IS_PRIOR(DWC3, 230A)) {
|
||||
/*
|
||||
* Ignore suspend event until the gadget enters into
|
||||
* USB_STATE_CONFIGURED state.
|
||||
*/
|
||||
if (dwc->gadget->state >= USB_STATE_CONFIGURED)
|
||||
dwc3_gadget_suspend_interrupt(dwc,
|
||||
event->event_info);
|
||||
}
|
||||
if (!DWC3_VER_IS_PRIOR(DWC3, 230A))
|
||||
dwc3_gadget_suspend_interrupt(dwc, event->event_info);
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_SOF:
|
||||
case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
|
||||
@ -4417,11 +4496,6 @@ static int dwc3_gadget_get_irq(struct dwc3 *dwc)
|
||||
goto out;
|
||||
|
||||
irq = platform_get_irq(dwc3_pdev, 0);
|
||||
if (irq > 0)
|
||||
goto out;
|
||||
|
||||
if (!irq)
|
||||
irq = -EINVAL;
|
||||
|
||||
out:
|
||||
return irq;
|
||||
@ -4493,6 +4567,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
|
||||
dwc->gadget->sg_supported = true;
|
||||
dwc->gadget->name = "dwc3-gadget";
|
||||
dwc->gadget->lpm_capable = !dwc->usb2_gadget_lpm_disable;
|
||||
dwc->gadget->wakeup_capable = true;
|
||||
|
||||
/*
|
||||
* FIXME We might be setting max_speed to <SUPER, however versions
|
||||
@ -4584,7 +4659,7 @@ int dwc3_gadget_suspend(struct dwc3 *dwc)
|
||||
if (!dwc->gadget_driver)
|
||||
return 0;
|
||||
|
||||
dwc3_gadget_run_stop(dwc, false, false);
|
||||
dwc3_gadget_run_stop(dwc, false);
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
dwc3_disconnect_gadget(dwc);
|
||||
@ -4605,7 +4680,7 @@ int dwc3_gadget_resume(struct dwc3 *dwc)
|
||||
if (ret < 0)
|
||||
goto err0;
|
||||
|
||||
ret = dwc3_gadget_run_stop(dwc, true, false);
|
||||
ret = dwc3_gadget_run_stop(dwc, true);
|
||||
if (ret < 0)
|
||||
goto err1;
|
||||
|
||||
|
@ -52,13 +52,8 @@ static int dwc3_host_get_irq(struct dwc3 *dwc)
|
||||
goto out;
|
||||
|
||||
irq = platform_get_irq(dwc3_pdev, 0);
|
||||
if (irq > 0) {
|
||||
if (irq > 0)
|
||||
dwc3_host_fill_xhci_irq_res(dwc, irq, NULL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!irq)
|
||||
irq = -EINVAL;
|
||||
|
||||
out:
|
||||
return irq;
|
||||
|
@ -54,14 +54,13 @@ DECLARE_EVENT_CLASS(dwc3_log_event,
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, event)
|
||||
__field(u32, ep0state)
|
||||
__dynamic_array(char, str, DWC3_MSG_MAX)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->event = event;
|
||||
__entry->ep0state = dwc->ep0state;
|
||||
),
|
||||
TP_printk("event (%08x): %s", __entry->event,
|
||||
dwc3_decode_event(__get_str(str), DWC3_MSG_MAX,
|
||||
dwc3_decode_event(__get_buf(DWC3_MSG_MAX), DWC3_MSG_MAX,
|
||||
__entry->event, __entry->ep0state))
|
||||
);
|
||||
|
||||
@ -79,7 +78,6 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl,
|
||||
__field(__u16, wValue)
|
||||
__field(__u16, wIndex)
|
||||
__field(__u16, wLength)
|
||||
__dynamic_array(char, str, DWC3_MSG_MAX)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->bRequestType = ctrl->bRequestType;
|
||||
@ -88,7 +86,7 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl,
|
||||
__entry->wIndex = le16_to_cpu(ctrl->wIndex);
|
||||
__entry->wLength = le16_to_cpu(ctrl->wLength);
|
||||
),
|
||||
TP_printk("%s", usb_decode_ctrl(__get_str(str), DWC3_MSG_MAX,
|
||||
TP_printk("%s", usb_decode_ctrl(__get_buf(DWC3_MSG_MAX), DWC3_MSG_MAX,
|
||||
__entry->bRequestType,
|
||||
__entry->bRequest, __entry->wValue,
|
||||
__entry->wIndex, __entry->wLength)
|
||||
|
@ -492,6 +492,46 @@ int usb_interface_id(struct usb_configuration *config,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_interface_id);
|
||||
|
||||
/**
|
||||
* usb_func_wakeup - sends function wake notification to the host.
|
||||
* @func: function that sends the remote wakeup notification.
|
||||
*
|
||||
* Applicable to devices operating at enhanced superspeed when usb
|
||||
* functions are put in function suspend state and armed for function
|
||||
* remote wakeup. On completion, function wake notification is sent. If
|
||||
* the device is in low power state it tries to bring the device to active
|
||||
* state before sending the wake notification. Since it is a synchronous
|
||||
* call, caller must take care of not calling it in interrupt context.
|
||||
* For devices operating at lower speeds returns negative errno.
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*/
|
||||
int usb_func_wakeup(struct usb_function *func)
|
||||
{
|
||||
struct usb_gadget *gadget = func->config->cdev->gadget;
|
||||
int id;
|
||||
|
||||
if (!gadget->ops->func_wakeup)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!func->func_wakeup_armed) {
|
||||
ERROR(func->config->cdev, "not armed for func remote wakeup\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (id = 0; id < MAX_CONFIG_INTERFACES; id++)
|
||||
if (func->config->interface[id] == func)
|
||||
break;
|
||||
|
||||
if (id == MAX_CONFIG_INTERFACES) {
|
||||
ERROR(func->config->cdev, "Invalid function\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return gadget->ops->func_wakeup(gadget, id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_func_wakeup);
|
||||
|
||||
static u8 encode_bMaxPower(enum usb_device_speed speed,
|
||||
struct usb_configuration *c)
|
||||
{
|
||||
@ -513,6 +553,19 @@ static u8 encode_bMaxPower(enum usb_device_speed speed,
|
||||
return min(val, 900U) / 8;
|
||||
}
|
||||
|
||||
void check_remote_wakeup_config(struct usb_gadget *g,
|
||||
struct usb_configuration *c)
|
||||
{
|
||||
if (USB_CONFIG_ATT_WAKEUP & c->bmAttributes) {
|
||||
/* Reset the rw bit if gadget is not capable of it */
|
||||
if (!g->wakeup_capable && g->ops->set_remote_wakeup) {
|
||||
WARN(c->cdev, "Clearing wakeup bit for config c.%d\n",
|
||||
c->bConfigurationValue);
|
||||
c->bmAttributes &= ~USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int config_buf(struct usb_configuration *config,
|
||||
enum usb_device_speed speed, void *buf, u8 type)
|
||||
{
|
||||
@ -888,6 +941,9 @@ static void reset_config(struct usb_composite_dev *cdev)
|
||||
if (f->disable)
|
||||
f->disable(f);
|
||||
|
||||
/* Section 9.1.1.6, disable remote wakeup when device is reset */
|
||||
f->func_wakeup_armed = false;
|
||||
|
||||
bitmap_zero(f->endpoints, 32);
|
||||
}
|
||||
cdev->config = NULL;
|
||||
@ -994,6 +1050,11 @@ static int set_config(struct usb_composite_dev *cdev,
|
||||
power = min(power, 500U);
|
||||
else
|
||||
power = min(power, 900U);
|
||||
|
||||
if (USB_CONFIG_ATT_WAKEUP & c->bmAttributes)
|
||||
usb_gadget_set_remote_wakeup(gadget, 1);
|
||||
else
|
||||
usb_gadget_set_remote_wakeup(gadget, 0);
|
||||
done:
|
||||
if (power <= USB_SELF_POWER_VBUS_MAX_DRAW)
|
||||
usb_gadget_set_selfpowered(gadget);
|
||||
@ -1948,9 +2009,20 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
f = cdev->config->interface[intf];
|
||||
if (!f)
|
||||
break;
|
||||
status = f->get_status ? f->get_status(f) : 0;
|
||||
if (status < 0)
|
||||
break;
|
||||
|
||||
if (f->get_status) {
|
||||
status = f->get_status(f);
|
||||
if (status < 0)
|
||||
break;
|
||||
} else {
|
||||
/* Set D0 and D1 bits based on func wakeup capability */
|
||||
if (f->config->bmAttributes & USB_CONFIG_ATT_WAKEUP) {
|
||||
status |= USB_INTRF_STAT_FUNC_RW_CAP;
|
||||
if (f->func_wakeup_armed)
|
||||
status |= USB_INTRF_STAT_FUNC_RW;
|
||||
}
|
||||
}
|
||||
|
||||
put_unaligned_le16(status & 0x0000ffff, req->buf);
|
||||
break;
|
||||
/*
|
||||
@ -1972,8 +2044,44 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
if (!f)
|
||||
break;
|
||||
value = 0;
|
||||
if (f->func_suspend)
|
||||
if (f->func_suspend) {
|
||||
value = f->func_suspend(f, w_index >> 8);
|
||||
/* SetFeature(FUNCTION_SUSPEND) */
|
||||
} else if (ctrl->bRequest == USB_REQ_SET_FEATURE) {
|
||||
if (!(f->config->bmAttributes &
|
||||
USB_CONFIG_ATT_WAKEUP) &&
|
||||
(w_index & USB_INTRF_FUNC_SUSPEND_RW))
|
||||
break;
|
||||
|
||||
f->func_wakeup_armed = !!(w_index &
|
||||
USB_INTRF_FUNC_SUSPEND_RW);
|
||||
|
||||
if (w_index & USB_INTRF_FUNC_SUSPEND_LP) {
|
||||
if (f->suspend && !f->func_suspended) {
|
||||
f->suspend(f);
|
||||
f->func_suspended = true;
|
||||
}
|
||||
/*
|
||||
* Handle cases where host sends function resume
|
||||
* through SetFeature(FUNCTION_SUSPEND) but low power
|
||||
* bit reset
|
||||
*/
|
||||
} else {
|
||||
if (f->resume && f->func_suspended) {
|
||||
f->resume(f);
|
||||
f->func_suspended = false;
|
||||
}
|
||||
}
|
||||
/* ClearFeature(FUNCTION_SUSPEND) */
|
||||
} else if (ctrl->bRequest == USB_REQ_CLEAR_FEATURE) {
|
||||
f->func_wakeup_armed = false;
|
||||
|
||||
if (f->resume && f->func_suspended) {
|
||||
f->resume(f);
|
||||
f->func_suspended = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (value < 0) {
|
||||
ERROR(cdev,
|
||||
"func_suspend() returned error %d\n",
|
||||
@ -2515,7 +2623,12 @@ void composite_resume(struct usb_gadget *gadget)
|
||||
cdev->driver->resume(cdev);
|
||||
if (cdev->config) {
|
||||
list_for_each_entry(f, &cdev->config->functions, list) {
|
||||
if (f->resume)
|
||||
/*
|
||||
* Check for func_suspended flag to see if the function is
|
||||
* in USB3 FUNCTION_SUSPEND state. In this case resume is
|
||||
* done via FUNCTION_SUSPEND feature selector.
|
||||
*/
|
||||
if (f->resume && !f->func_suspended)
|
||||
f->resume(f);
|
||||
}
|
||||
|
||||
@ -2530,6 +2643,10 @@ void composite_resume(struct usb_gadget *gadget)
|
||||
usb_gadget_clear_selfpowered(gadget);
|
||||
|
||||
usb_gadget_vbus_draw(gadget, maxpower);
|
||||
} else {
|
||||
maxpower = CONFIG_USB_GADGET_VBUS_DRAW;
|
||||
maxpower = min(maxpower, 100U);
|
||||
usb_gadget_vbus_draw(gadget, maxpower);
|
||||
}
|
||||
|
||||
cdev->suspended = 0;
|
||||
|
@ -1761,6 +1761,9 @@ static int configfs_composite_bind(struct usb_gadget *gadget,
|
||||
if (gadget_is_otg(gadget))
|
||||
c->descriptors = otg_desc;
|
||||
|
||||
/* Properly configure the bmAttributes wakeup bit */
|
||||
check_remote_wakeup_config(gadget, c);
|
||||
|
||||
cfg = container_of(c, struct config_usb_cfg, c);
|
||||
if (!list_empty(&cfg->string_list)) {
|
||||
i = 0;
|
||||
|
@ -885,6 +885,26 @@ static struct usb_function_instance *ecm_alloc_inst(void)
|
||||
return &opts->func_inst;
|
||||
}
|
||||
|
||||
static void ecm_suspend(struct usb_function *f)
|
||||
{
|
||||
struct f_ecm *ecm = func_to_ecm(f);
|
||||
struct usb_composite_dev *cdev = ecm->port.func.config->cdev;
|
||||
|
||||
DBG(cdev, "ECM Suspend\n");
|
||||
|
||||
gether_suspend(&ecm->port);
|
||||
}
|
||||
|
||||
static void ecm_resume(struct usb_function *f)
|
||||
{
|
||||
struct f_ecm *ecm = func_to_ecm(f);
|
||||
struct usb_composite_dev *cdev = ecm->port.func.config->cdev;
|
||||
|
||||
DBG(cdev, "ECM Resume\n");
|
||||
|
||||
gether_resume(&ecm->port);
|
||||
}
|
||||
|
||||
static void ecm_free(struct usb_function *f)
|
||||
{
|
||||
struct f_ecm *ecm;
|
||||
@ -952,6 +972,8 @@ static struct usb_function *ecm_alloc(struct usb_function_instance *fi)
|
||||
ecm->port.func.setup = ecm_setup;
|
||||
ecm->port.func.disable = ecm_disable;
|
||||
ecm->port.func.free_func = ecm_free;
|
||||
ecm->port.func.suspend = ecm_suspend;
|
||||
ecm->port.func.resume = ecm_resume;
|
||||
|
||||
return &ecm->port.func;
|
||||
}
|
||||
|
@ -335,8 +335,6 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
|
||||
ssize_t ret;
|
||||
char *data;
|
||||
|
||||
ENTER();
|
||||
|
||||
/* Fast check if setup was canceled */
|
||||
if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
|
||||
return -EIDRM;
|
||||
@ -512,8 +510,6 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
|
||||
size_t n;
|
||||
int ret;
|
||||
|
||||
ENTER();
|
||||
|
||||
/* Fast check if setup was canceled */
|
||||
if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
|
||||
return -EIDRM;
|
||||
@ -612,8 +608,6 @@ static int ffs_ep0_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct ffs_data *ffs = inode->i_private;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (ffs->state == FFS_CLOSING)
|
||||
return -EBUSY;
|
||||
|
||||
@ -627,8 +621,6 @@ static int ffs_ep0_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct ffs_data *ffs = file->private_data;
|
||||
|
||||
ENTER();
|
||||
|
||||
ffs_data_closed(ffs);
|
||||
|
||||
return 0;
|
||||
@ -640,8 +632,6 @@ static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)
|
||||
struct usb_gadget *gadget = ffs->gadget;
|
||||
long ret;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (code == FUNCTIONFS_INTERFACE_REVMAP) {
|
||||
struct ffs_function *func = ffs->func;
|
||||
ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV;
|
||||
@ -715,7 +705,6 @@ static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
|
||||
{
|
||||
struct ffs_io_data *io_data = req->context;
|
||||
|
||||
ENTER();
|
||||
if (req->status)
|
||||
io_data->status = req->status;
|
||||
else
|
||||
@ -856,8 +845,6 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
|
||||
struct ffs_io_data *io_data = req->context;
|
||||
struct ffs_data *ffs = io_data->ffs;
|
||||
|
||||
ENTER();
|
||||
|
||||
io_data->status = req->status ? req->status : req->actual;
|
||||
usb_ep_free_request(_ep, req);
|
||||
|
||||
@ -1161,8 +1148,6 @@ ffs_epfile_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct ffs_epfile *epfile = inode->i_private;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
|
||||
return -ENODEV;
|
||||
|
||||
@ -1179,8 +1164,6 @@ static int ffs_aio_cancel(struct kiocb *kiocb)
|
||||
unsigned long flags;
|
||||
int value;
|
||||
|
||||
ENTER();
|
||||
|
||||
spin_lock_irqsave(&epfile->ffs->eps_lock, flags);
|
||||
|
||||
if (io_data && io_data->ep && io_data->req)
|
||||
@ -1198,8 +1181,6 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
|
||||
struct ffs_io_data io_data, *p = &io_data;
|
||||
ssize_t res;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (!is_sync_kiocb(kiocb)) {
|
||||
p = kzalloc(sizeof(io_data), GFP_KERNEL);
|
||||
if (!p)
|
||||
@ -1235,8 +1216,6 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
|
||||
struct ffs_io_data io_data, *p = &io_data;
|
||||
ssize_t res;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (!is_sync_kiocb(kiocb)) {
|
||||
p = kzalloc(sizeof(io_data), GFP_KERNEL);
|
||||
if (!p)
|
||||
@ -1284,8 +1263,6 @@ ffs_epfile_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct ffs_epfile *epfile = inode->i_private;
|
||||
|
||||
ENTER();
|
||||
|
||||
__ffs_epfile_read_buffer_free(epfile);
|
||||
ffs_data_closed(epfile->ffs);
|
||||
|
||||
@ -1299,8 +1276,6 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code,
|
||||
struct ffs_ep *ep;
|
||||
int ret;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
|
||||
return -ENODEV;
|
||||
|
||||
@ -1399,8 +1374,6 @@ ffs_sb_make_inode(struct super_block *sb, void *data,
|
||||
{
|
||||
struct inode *inode;
|
||||
|
||||
ENTER();
|
||||
|
||||
inode = new_inode(sb);
|
||||
|
||||
if (inode) {
|
||||
@ -1432,8 +1405,6 @@ static struct dentry *ffs_sb_create_file(struct super_block *sb,
|
||||
struct dentry *dentry;
|
||||
struct inode *inode;
|
||||
|
||||
ENTER();
|
||||
|
||||
dentry = d_alloc_name(sb->s_root, name);
|
||||
if (!dentry)
|
||||
return NULL;
|
||||
@ -1468,8 +1439,6 @@ static int ffs_sb_fill(struct super_block *sb, struct fs_context *fc)
|
||||
struct inode *inode;
|
||||
struct ffs_data *ffs = data->ffs_data;
|
||||
|
||||
ENTER();
|
||||
|
||||
ffs->sb = sb;
|
||||
data->ffs_data = NULL;
|
||||
sb->s_fs_info = ffs;
|
||||
@ -1521,8 +1490,6 @@ static int ffs_fs_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
||||
struct fs_parse_result result;
|
||||
int opt;
|
||||
|
||||
ENTER();
|
||||
|
||||
opt = fs_parse(fc, ffs_fs_fs_parameters, param, &result);
|
||||
if (opt < 0)
|
||||
return opt;
|
||||
@ -1572,8 +1539,6 @@ static int ffs_fs_get_tree(struct fs_context *fc)
|
||||
struct ffs_data *ffs;
|
||||
int ret;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (!fc->source)
|
||||
return invalf(fc, "No source specified");
|
||||
|
||||
@ -1640,8 +1605,6 @@ static int ffs_fs_init_fs_context(struct fs_context *fc)
|
||||
static void
|
||||
ffs_fs_kill_sb(struct super_block *sb)
|
||||
{
|
||||
ENTER();
|
||||
|
||||
kill_litter_super(sb);
|
||||
if (sb->s_fs_info)
|
||||
ffs_data_closed(sb->s_fs_info);
|
||||
@ -1663,8 +1626,6 @@ static int functionfs_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ENTER();
|
||||
|
||||
ret = register_filesystem(&ffs_fs_type);
|
||||
if (!ret)
|
||||
pr_info("file system registered\n");
|
||||
@ -1676,8 +1637,6 @@ static int functionfs_init(void)
|
||||
|
||||
static void functionfs_cleanup(void)
|
||||
{
|
||||
ENTER();
|
||||
|
||||
pr_info("unloading\n");
|
||||
unregister_filesystem(&ffs_fs_type);
|
||||
}
|
||||
@ -1690,15 +1649,11 @@ static void ffs_data_reset(struct ffs_data *ffs);
|
||||
|
||||
static void ffs_data_get(struct ffs_data *ffs)
|
||||
{
|
||||
ENTER();
|
||||
|
||||
refcount_inc(&ffs->ref);
|
||||
}
|
||||
|
||||
static void ffs_data_opened(struct ffs_data *ffs)
|
||||
{
|
||||
ENTER();
|
||||
|
||||
refcount_inc(&ffs->ref);
|
||||
if (atomic_add_return(1, &ffs->opened) == 1 &&
|
||||
ffs->state == FFS_DEACTIVATED) {
|
||||
@ -1709,8 +1664,6 @@ static void ffs_data_opened(struct ffs_data *ffs)
|
||||
|
||||
static void ffs_data_put(struct ffs_data *ffs)
|
||||
{
|
||||
ENTER();
|
||||
|
||||
if (refcount_dec_and_test(&ffs->ref)) {
|
||||
pr_info("%s(): freeing\n", __func__);
|
||||
ffs_data_clear(ffs);
|
||||
@ -1729,8 +1682,6 @@ static void ffs_data_closed(struct ffs_data *ffs)
|
||||
struct ffs_epfile *epfiles;
|
||||
unsigned long flags;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (atomic_dec_and_test(&ffs->opened)) {
|
||||
if (ffs->no_disconnect) {
|
||||
ffs->state = FFS_DEACTIVATED;
|
||||
@ -1765,8 +1716,6 @@ static struct ffs_data *ffs_data_new(const char *dev_name)
|
||||
if (!ffs)
|
||||
return NULL;
|
||||
|
||||
ENTER();
|
||||
|
||||
ffs->io_completion_wq = alloc_ordered_workqueue("%s", 0, dev_name);
|
||||
if (!ffs->io_completion_wq) {
|
||||
kfree(ffs);
|
||||
@ -1793,8 +1742,6 @@ static void ffs_data_clear(struct ffs_data *ffs)
|
||||
struct ffs_epfile *epfiles;
|
||||
unsigned long flags;
|
||||
|
||||
ENTER();
|
||||
|
||||
ffs_closed(ffs);
|
||||
|
||||
BUG_ON(ffs->gadget);
|
||||
@ -1826,8 +1773,6 @@ static void ffs_data_clear(struct ffs_data *ffs)
|
||||
|
||||
static void ffs_data_reset(struct ffs_data *ffs)
|
||||
{
|
||||
ENTER();
|
||||
|
||||
ffs_data_clear(ffs);
|
||||
|
||||
ffs->raw_descs_data = NULL;
|
||||
@ -1861,8 +1806,6 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
|
||||
struct usb_gadget_strings **lang;
|
||||
int first_id;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (WARN_ON(ffs->state != FFS_ACTIVE
|
||||
|| test_and_set_bit(FFS_FL_BOUND, &ffs->flags)))
|
||||
return -EBADFD;
|
||||
@ -1894,8 +1837,6 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
|
||||
|
||||
static void functionfs_unbind(struct ffs_data *ffs)
|
||||
{
|
||||
ENTER();
|
||||
|
||||
if (!WARN_ON(!ffs->gadget)) {
|
||||
/* dequeue before freeing ep0req */
|
||||
usb_ep_dequeue(ffs->gadget->ep0, ffs->ep0req);
|
||||
@ -1914,8 +1855,6 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
|
||||
struct ffs_epfile *epfile, *epfiles;
|
||||
unsigned i, count;
|
||||
|
||||
ENTER();
|
||||
|
||||
count = ffs->eps_count;
|
||||
epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL);
|
||||
if (!epfiles)
|
||||
@ -1946,8 +1885,6 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
|
||||
{
|
||||
struct ffs_epfile *epfile = epfiles;
|
||||
|
||||
ENTER();
|
||||
|
||||
for (; count; --count, ++epfile) {
|
||||
BUG_ON(mutex_is_locked(&epfile->mutex));
|
||||
if (epfile->dentry) {
|
||||
@ -2064,8 +2001,6 @@ static int __must_check ffs_do_single_desc(char *data, unsigned len,
|
||||
u8 length;
|
||||
int ret;
|
||||
|
||||
ENTER();
|
||||
|
||||
/* At least two bytes are required: length and type */
|
||||
if (len < 2) {
|
||||
pr_vdebug("descriptor too short\n");
|
||||
@ -2204,8 +2139,6 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
|
||||
unsigned long num = 0;
|
||||
int current_class = -1;
|
||||
|
||||
ENTER();
|
||||
|
||||
for (;;) {
|
||||
int ret;
|
||||
|
||||
@ -2243,8 +2176,6 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
|
||||
struct ffs_desc_helper *helper = priv;
|
||||
struct usb_endpoint_descriptor *d;
|
||||
|
||||
ENTER();
|
||||
|
||||
switch (type) {
|
||||
case FFS_DESCRIPTOR:
|
||||
break;
|
||||
@ -2292,8 +2223,11 @@ static int __ffs_do_os_desc_header(enum ffs_os_desc_type *next_type,
|
||||
u16 bcd_version = le16_to_cpu(desc->bcdVersion);
|
||||
u16 w_index = le16_to_cpu(desc->wIndex);
|
||||
|
||||
if (bcd_version != 1) {
|
||||
pr_vdebug("unsupported os descriptors version: %d",
|
||||
if (bcd_version == 0x1) {
|
||||
pr_warn("bcdVersion must be 0x0100, stored in Little Endian order. "
|
||||
"Userspace driver should be fixed, accepting 0x0001 for compatibility.\n");
|
||||
} else if (bcd_version != 0x100) {
|
||||
pr_vdebug("unsupported os descriptors version: 0x%x\n",
|
||||
bcd_version);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -2326,8 +2260,6 @@ static int __must_check ffs_do_single_os_desc(char *data, unsigned len,
|
||||
int ret;
|
||||
const unsigned _len = len;
|
||||
|
||||
ENTER();
|
||||
|
||||
/* loop over all ext compat/ext prop descriptors */
|
||||
while (feature_count--) {
|
||||
ret = entity(type, h, data, len, priv);
|
||||
@ -2349,8 +2281,6 @@ static int __must_check ffs_do_os_descs(unsigned count,
|
||||
const unsigned _len = len;
|
||||
unsigned long num = 0;
|
||||
|
||||
ENTER();
|
||||
|
||||
for (num = 0; num < count; ++num) {
|
||||
int ret;
|
||||
enum ffs_os_desc_type type;
|
||||
@ -2413,8 +2343,6 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type,
|
||||
struct ffs_data *ffs = priv;
|
||||
u8 length;
|
||||
|
||||
ENTER();
|
||||
|
||||
switch (type) {
|
||||
case FFS_OS_DESC_EXT_COMPAT: {
|
||||
struct usb_ext_compat_desc *d = data;
|
||||
@ -2490,8 +2418,6 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
|
||||
int ret = -EINVAL, i;
|
||||
struct ffs_desc_helper helper;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (get_unaligned_le32(data + 4) != len)
|
||||
goto error;
|
||||
|
||||
@ -2622,8 +2548,6 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
|
||||
const char *data = _data;
|
||||
struct usb_string *s;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (len < 16 ||
|
||||
get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
|
||||
get_unaligned_le32(data + 4) != len)
|
||||
@ -3082,8 +3006,6 @@ static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f,
|
||||
struct ffs_data *ffs_data;
|
||||
int ret;
|
||||
|
||||
ENTER();
|
||||
|
||||
/*
|
||||
* Legacy gadget triggers binding in functionfs_ready_callback,
|
||||
* which already uses locking; taking the same lock here would
|
||||
@ -3160,8 +3082,6 @@ static int _ffs_func_bind(struct usb_configuration *c,
|
||||
vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length);
|
||||
char *vlabuf;
|
||||
|
||||
ENTER();
|
||||
|
||||
/* Has descriptors only for speeds gadget does not support */
|
||||
if (!(full | high | super))
|
||||
return -ENOTSUPP;
|
||||
@ -3365,8 +3285,6 @@ static int ffs_func_setup(struct usb_function *f,
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
ENTER();
|
||||
|
||||
pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType);
|
||||
pr_vdebug("creq->bRequest = %02x\n", creq->bRequest);
|
||||
pr_vdebug("creq->wValue = %04x\n", le16_to_cpu(creq->wValue));
|
||||
@ -3441,13 +3359,11 @@ static bool ffs_func_req_match(struct usb_function *f,
|
||||
|
||||
static void ffs_func_suspend(struct usb_function *f)
|
||||
{
|
||||
ENTER();
|
||||
ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND);
|
||||
}
|
||||
|
||||
static void ffs_func_resume(struct usb_function *f)
|
||||
{
|
||||
ENTER();
|
||||
ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME);
|
||||
}
|
||||
|
||||
@ -3611,7 +3527,6 @@ static void ffs_func_unbind(struct usb_configuration *c,
|
||||
unsigned count = ffs->eps_count;
|
||||
unsigned long flags;
|
||||
|
||||
ENTER();
|
||||
if (ffs->func == func) {
|
||||
ffs_func_eps_disable(func);
|
||||
ffs->func = NULL;
|
||||
@ -3651,8 +3566,6 @@ static struct usb_function *ffs_alloc(struct usb_function_instance *fi)
|
||||
{
|
||||
struct ffs_function *func;
|
||||
|
||||
ENTER();
|
||||
|
||||
func = kzalloc(sizeof(*func), GFP_KERNEL);
|
||||
if (!func)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
@ -3753,7 +3666,6 @@ static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data)
|
||||
int ret = 0;
|
||||
struct ffs_dev *ffs_dev;
|
||||
|
||||
ENTER();
|
||||
ffs_dev_lock();
|
||||
|
||||
ffs_dev = _ffs_find_dev(dev_name);
|
||||
@ -3776,7 +3688,6 @@ static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data)
|
||||
|
||||
static void ffs_release_dev(struct ffs_dev *ffs_dev)
|
||||
{
|
||||
ENTER();
|
||||
ffs_dev_lock();
|
||||
|
||||
if (ffs_dev && ffs_dev->mounted) {
|
||||
@ -3798,7 +3709,6 @@ static int ffs_ready(struct ffs_data *ffs)
|
||||
struct ffs_dev *ffs_obj;
|
||||
int ret = 0;
|
||||
|
||||
ENTER();
|
||||
ffs_dev_lock();
|
||||
|
||||
ffs_obj = ffs->private_data;
|
||||
@ -3831,7 +3741,6 @@ static void ffs_closed(struct ffs_data *ffs)
|
||||
struct f_fs_opts *opts;
|
||||
struct config_item *ci;
|
||||
|
||||
ENTER();
|
||||
ffs_dev_lock();
|
||||
|
||||
ffs_obj = ffs->private_data;
|
||||
|
@ -437,6 +437,20 @@ static inline int is_promisc(u16 cdc_filter)
|
||||
return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
|
||||
}
|
||||
|
||||
static int ether_wakeup_host(struct gether *port)
|
||||
{
|
||||
int ret;
|
||||
struct usb_function *func = &port->func;
|
||||
struct usb_gadget *gadget = func->config->cdev->gadget;
|
||||
|
||||
if (func->func_suspended)
|
||||
ret = usb_func_wakeup(func);
|
||||
else
|
||||
ret = usb_gadget_wakeup(gadget);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *net)
|
||||
{
|
||||
@ -456,6 +470,15 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
|
||||
in = NULL;
|
||||
cdc_filter = 0;
|
||||
}
|
||||
|
||||
if (dev->port_usb && dev->port_usb->is_suspend) {
|
||||
DBG(dev, "Port suspended. Triggering wakeup\n");
|
||||
netif_stop_queue(net);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
ether_wakeup_host(dev->port_usb);
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
if (!in) {
|
||||
@ -1014,6 +1037,45 @@ int gether_set_ifname(struct net_device *net, const char *name, int len)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gether_set_ifname);
|
||||
|
||||
void gether_suspend(struct gether *link)
|
||||
{
|
||||
struct eth_dev *dev = link->ioport;
|
||||
unsigned long flags;
|
||||
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
if (atomic_read(&dev->tx_qlen)) {
|
||||
/*
|
||||
* There is a transfer in progress. So we trigger a remote
|
||||
* wakeup to inform the host.
|
||||
*/
|
||||
ether_wakeup_host(dev->port_usb);
|
||||
return;
|
||||
}
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
link->is_suspend = true;
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gether_suspend);
|
||||
|
||||
void gether_resume(struct gether *link)
|
||||
{
|
||||
struct eth_dev *dev = link->ioport;
|
||||
unsigned long flags;
|
||||
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
if (netif_queue_stopped(dev->net))
|
||||
netif_start_queue(dev->net);
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
link->is_suspend = false;
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gether_resume);
|
||||
|
||||
/*
|
||||
* gether_cleanup - remove Ethernet-over-USB device
|
||||
* Context: may sleep
|
||||
@ -1176,6 +1238,7 @@ void gether_disconnect(struct gether *link)
|
||||
|
||||
spin_lock(&dev->lock);
|
||||
dev->port_usb = NULL;
|
||||
link->is_suspend = false;
|
||||
spin_unlock(&dev->lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gether_disconnect);
|
||||
|
@ -79,6 +79,7 @@ struct gether {
|
||||
/* called on network open/close */
|
||||
void (*open)(struct gether *);
|
||||
void (*close)(struct gether *);
|
||||
bool is_suspend;
|
||||
};
|
||||
|
||||
#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \
|
||||
@ -258,6 +259,9 @@ int gether_set_ifname(struct net_device *net, const char *name, int len);
|
||||
|
||||
void gether_cleanup(struct eth_dev *dev);
|
||||
|
||||
void gether_suspend(struct gether *link);
|
||||
void gether_resume(struct gether *link);
|
||||
|
||||
/* connect/disconnect is handled by individual functions */
|
||||
struct net_device *gether_connect(struct gether *);
|
||||
void gether_disconnect(struct gether *);
|
||||
|
@ -32,8 +32,6 @@
|
||||
# define ffs_dump_mem(prefix, ptr, len) do { } while (0)
|
||||
#endif /* VERBOSE_DEBUG */
|
||||
|
||||
#define ENTER() pr_vdebug("%s()\n", __func__)
|
||||
|
||||
struct f_fs_opts;
|
||||
|
||||
struct ffs_dev {
|
||||
|
@ -334,6 +334,64 @@ UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, 8);
|
||||
|
||||
#undef UVCG_DEFAULT_PROCESSING_ATTR
|
||||
|
||||
static ssize_t uvcg_default_processing_bm_controls_store(
|
||||
struct config_item *item, const char *page, size_t len)
|
||||
{
|
||||
struct config_group *group = to_config_group(item);
|
||||
struct mutex *su_mutex = &group->cg_subsys->su_mutex;
|
||||
struct uvc_processing_unit_descriptor *pd;
|
||||
struct config_item *opts_item;
|
||||
struct f_uvc_opts *opts;
|
||||
u8 *bm_controls, *tmp;
|
||||
unsigned int i;
|
||||
int ret, n = 0;
|
||||
|
||||
mutex_lock(su_mutex);
|
||||
|
||||
opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
|
||||
opts = to_f_uvc_opts(opts_item);
|
||||
pd = &opts->uvc_processing;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
if (opts->refcnt) {
|
||||
ret = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ret = __uvcg_iter_item_entries(page, len, __uvcg_count_item_entries, &n,
|
||||
sizeof(u8));
|
||||
if (ret)
|
||||
goto unlock;
|
||||
|
||||
if (n > pd->bControlSize) {
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
tmp = bm_controls = kcalloc(n, sizeof(u8), GFP_KERNEL);
|
||||
if (!bm_controls) {
|
||||
ret = -ENOMEM;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ret = __uvcg_iter_item_entries(page, len, __uvcg_fill_item_entries, &tmp,
|
||||
sizeof(u8));
|
||||
if (ret)
|
||||
goto free_mem;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
pd->bmControls[i] = bm_controls[i];
|
||||
|
||||
ret = len;
|
||||
|
||||
free_mem:
|
||||
kfree(bm_controls);
|
||||
unlock:
|
||||
mutex_unlock(&opts->lock);
|
||||
mutex_unlock(su_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t uvcg_default_processing_bm_controls_show(
|
||||
struct config_item *item, char *page)
|
||||
{
|
||||
@ -363,7 +421,7 @@ static ssize_t uvcg_default_processing_bm_controls_show(
|
||||
return result;
|
||||
}
|
||||
|
||||
UVC_ATTR_RO(uvcg_default_processing_, bm_controls, bmControls);
|
||||
UVC_ATTR(uvcg_default_processing_, bm_controls, bmControls);
|
||||
|
||||
static struct configfs_attribute *uvcg_default_processing_attrs[] = {
|
||||
&uvcg_default_processing_attr_b_unit_id,
|
||||
@ -445,6 +503,65 @@ UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength,
|
||||
|
||||
#undef UVCG_DEFAULT_CAMERA_ATTR
|
||||
|
||||
static ssize_t uvcg_default_camera_bm_controls_store(
|
||||
struct config_item *item, const char *page, size_t len)
|
||||
{
|
||||
struct config_group *group = to_config_group(item);
|
||||
struct mutex *su_mutex = &group->cg_subsys->su_mutex;
|
||||
struct uvc_camera_terminal_descriptor *cd;
|
||||
struct config_item *opts_item;
|
||||
struct f_uvc_opts *opts;
|
||||
u8 *bm_controls, *tmp;
|
||||
unsigned int i;
|
||||
int ret, n = 0;
|
||||
|
||||
mutex_lock(su_mutex);
|
||||
|
||||
opts_item = group->cg_item.ci_parent->ci_parent->ci_parent->
|
||||
ci_parent;
|
||||
opts = to_f_uvc_opts(opts_item);
|
||||
cd = &opts->uvc_camera_terminal;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
if (opts->refcnt) {
|
||||
ret = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ret = __uvcg_iter_item_entries(page, len, __uvcg_count_item_entries, &n,
|
||||
sizeof(u8));
|
||||
if (ret)
|
||||
goto unlock;
|
||||
|
||||
if (n > cd->bControlSize) {
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
tmp = bm_controls = kcalloc(n, sizeof(u8), GFP_KERNEL);
|
||||
if (!bm_controls) {
|
||||
ret = -ENOMEM;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ret = __uvcg_iter_item_entries(page, len, __uvcg_fill_item_entries, &tmp,
|
||||
sizeof(u8));
|
||||
if (ret)
|
||||
goto free_mem;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
cd->bmControls[i] = bm_controls[i];
|
||||
|
||||
ret = len;
|
||||
|
||||
free_mem:
|
||||
kfree(bm_controls);
|
||||
unlock:
|
||||
mutex_unlock(&opts->lock);
|
||||
mutex_unlock(su_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t uvcg_default_camera_bm_controls_show(
|
||||
struct config_item *item, char *page)
|
||||
{
|
||||
@ -474,7 +591,7 @@ static ssize_t uvcg_default_camera_bm_controls_show(
|
||||
return result;
|
||||
}
|
||||
|
||||
UVC_ATTR_RO(uvcg_default_camera_, bm_controls, bmControls);
|
||||
UVC_ATTR(uvcg_default_camera_, bm_controls, bmControls);
|
||||
|
||||
static struct configfs_attribute *uvcg_default_camera_attrs[] = {
|
||||
&uvcg_default_camera_attr_b_terminal_id,
|
||||
|
@ -180,8 +180,6 @@ static int __init gfs_init(void)
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (func_num < 2) {
|
||||
gfs_single_func = true;
|
||||
func_num = 1;
|
||||
@ -242,8 +240,6 @@ static void __exit gfs_exit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (gfs_registered)
|
||||
usb_composite_unregister(&gfs_driver);
|
||||
gfs_registered = false;
|
||||
@ -316,8 +312,6 @@ static int gfs_bind(struct usb_composite_dev *cdev)
|
||||
#endif
|
||||
int ret, i;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (missing_funcs)
|
||||
return -ENODEV;
|
||||
#if defined CONFIG_USB_FUNCTIONFS_ETH
|
||||
@ -445,9 +439,6 @@ static int gfs_unbind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
ENTER();
|
||||
|
||||
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
usb_put_function(f_rndis);
|
||||
usb_put_function_instance(fi_rndis);
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/usb.h>
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/bcd.h>
|
||||
|
@ -37,6 +37,10 @@ static struct bus_type gadget_bus_type;
|
||||
* @vbus: for udcs who care about vbus status, this value is real vbus status;
|
||||
* for udcs who do not care about vbus status, this value is always true
|
||||
* @started: the UDC's started state. True if the UDC had started.
|
||||
* @connect_lock: protects udc->vbus, udc->started, gadget->connect, gadget->deactivate related
|
||||
* functions. usb_gadget_connect_locked, usb_gadget_disconnect_locked,
|
||||
* usb_udc_connect_control_locked, usb_gadget_udc_start_locked, usb_gadget_udc_stop_locked are
|
||||
* called with this lock held.
|
||||
*
|
||||
* This represents the internal data structure which is used by the UDC-class
|
||||
* to hold information about udc driver and gadget together.
|
||||
@ -48,6 +52,7 @@ struct usb_udc {
|
||||
struct list_head list;
|
||||
bool vbus;
|
||||
bool started;
|
||||
struct mutex connect_lock;
|
||||
};
|
||||
|
||||
static struct class *udc_class;
|
||||
@ -513,6 +518,33 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_wakeup);
|
||||
|
||||
/**
|
||||
* usb_gadget_set_remote_wakeup - configures the device remote wakeup feature.
|
||||
* @gadget:the device being configured for remote wakeup
|
||||
* @set:value to be configured.
|
||||
*
|
||||
* set to one to enable remote wakeup feature and zero to disable it.
|
||||
*
|
||||
* returns zero on success, else negative errno.
|
||||
*/
|
||||
int usb_gadget_set_remote_wakeup(struct usb_gadget *gadget, int set)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!gadget->ops->set_remote_wakeup) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = gadget->ops->set_remote_wakeup(gadget, set);
|
||||
|
||||
out:
|
||||
trace_usb_gadget_set_remote_wakeup(gadget, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_set_remote_wakeup);
|
||||
|
||||
/**
|
||||
* usb_gadget_set_selfpowered - sets the device selfpowered feature.
|
||||
* @gadget:the device being declared as self-powered
|
||||
@ -660,17 +692,9 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_vbus_disconnect);
|
||||
|
||||
/**
|
||||
* usb_gadget_connect - software-controlled connect to USB host
|
||||
* @gadget:the peripheral being connected
|
||||
*
|
||||
* Enables the D+ (or potentially D-) pullup. The host will start
|
||||
* enumerating this gadget when the pullup is active and a VBUS session
|
||||
* is active (the link is powered).
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*/
|
||||
int usb_gadget_connect(struct usb_gadget *gadget)
|
||||
/* Internal version of usb_gadget_connect needs to be called with connect_lock held. */
|
||||
static int usb_gadget_connect_locked(struct usb_gadget *gadget)
|
||||
__must_hold(&gadget->udc->connect_lock)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@ -679,10 +703,15 @@ int usb_gadget_connect(struct usb_gadget *gadget)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (gadget->deactivated) {
|
||||
if (gadget->connected)
|
||||
goto out;
|
||||
|
||||
if (gadget->deactivated || !gadget->udc->started) {
|
||||
/*
|
||||
* If gadget is deactivated we only save new state.
|
||||
* Gadget will be connected automatically after activation.
|
||||
*
|
||||
* udc first needs to be started before gadget can be pulled up.
|
||||
*/
|
||||
gadget->connected = true;
|
||||
goto out;
|
||||
@ -697,22 +726,32 @@ out:
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_connect);
|
||||
|
||||
/**
|
||||
* usb_gadget_disconnect - software-controlled disconnect from USB host
|
||||
* @gadget:the peripheral being disconnected
|
||||
* usb_gadget_connect - software-controlled connect to USB host
|
||||
* @gadget:the peripheral being connected
|
||||
*
|
||||
* Disables the D+ (or potentially D-) pullup, which the host may see
|
||||
* as a disconnect (when a VBUS session is active). Not all systems
|
||||
* support software pullup controls.
|
||||
*
|
||||
* Following a successful disconnect, invoke the ->disconnect() callback
|
||||
* for the current gadget driver so that UDC drivers don't need to.
|
||||
* Enables the D+ (or potentially D-) pullup. The host will start
|
||||
* enumerating this gadget when the pullup is active and a VBUS session
|
||||
* is active (the link is powered).
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*/
|
||||
int usb_gadget_disconnect(struct usb_gadget *gadget)
|
||||
int usb_gadget_connect(struct usb_gadget *gadget)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&gadget->udc->connect_lock);
|
||||
ret = usb_gadget_connect_locked(gadget);
|
||||
mutex_unlock(&gadget->udc->connect_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_connect);
|
||||
|
||||
/* Internal version of usb_gadget_disconnect needs to be called with connect_lock held. */
|
||||
static int usb_gadget_disconnect_locked(struct usb_gadget *gadget)
|
||||
__must_hold(&gadget->udc->connect_lock)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@ -724,10 +763,12 @@ int usb_gadget_disconnect(struct usb_gadget *gadget)
|
||||
if (!gadget->connected)
|
||||
goto out;
|
||||
|
||||
if (gadget->deactivated) {
|
||||
if (gadget->deactivated || !gadget->udc->started) {
|
||||
/*
|
||||
* If gadget is deactivated we only save new state.
|
||||
* Gadget will stay disconnected after activation.
|
||||
*
|
||||
* udc should have been started before gadget being pulled down.
|
||||
*/
|
||||
gadget->connected = false;
|
||||
goto out;
|
||||
@ -747,6 +788,30 @@ out:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_gadget_disconnect - software-controlled disconnect from USB host
|
||||
* @gadget:the peripheral being disconnected
|
||||
*
|
||||
* Disables the D+ (or potentially D-) pullup, which the host may see
|
||||
* as a disconnect (when a VBUS session is active). Not all systems
|
||||
* support software pullup controls.
|
||||
*
|
||||
* Following a successful disconnect, invoke the ->disconnect() callback
|
||||
* for the current gadget driver so that UDC drivers don't need to.
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*/
|
||||
int usb_gadget_disconnect(struct usb_gadget *gadget)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&gadget->udc->connect_lock);
|
||||
ret = usb_gadget_disconnect_locked(gadget);
|
||||
mutex_unlock(&gadget->udc->connect_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_disconnect);
|
||||
|
||||
/**
|
||||
@ -767,10 +832,11 @@ int usb_gadget_deactivate(struct usb_gadget *gadget)
|
||||
if (gadget->deactivated)
|
||||
goto out;
|
||||
|
||||
mutex_lock(&gadget->udc->connect_lock);
|
||||
if (gadget->connected) {
|
||||
ret = usb_gadget_disconnect(gadget);
|
||||
ret = usb_gadget_disconnect_locked(gadget);
|
||||
if (ret)
|
||||
goto out;
|
||||
goto unlock;
|
||||
|
||||
/*
|
||||
* If gadget was being connected before deactivation, we want
|
||||
@ -780,6 +846,8 @@ int usb_gadget_deactivate(struct usb_gadget *gadget)
|
||||
}
|
||||
gadget->deactivated = true;
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&gadget->udc->connect_lock);
|
||||
out:
|
||||
trace_usb_gadget_deactivate(gadget, ret);
|
||||
|
||||
@ -803,6 +871,7 @@ int usb_gadget_activate(struct usb_gadget *gadget)
|
||||
if (!gadget->deactivated)
|
||||
goto out;
|
||||
|
||||
mutex_lock(&gadget->udc->connect_lock);
|
||||
gadget->deactivated = false;
|
||||
|
||||
/*
|
||||
@ -810,7 +879,8 @@ int usb_gadget_activate(struct usb_gadget *gadget)
|
||||
* while it was being deactivated, we call usb_gadget_connect().
|
||||
*/
|
||||
if (gadget->connected)
|
||||
ret = usb_gadget_connect(gadget);
|
||||
ret = usb_gadget_connect_locked(gadget);
|
||||
mutex_unlock(&gadget->udc->connect_lock);
|
||||
|
||||
out:
|
||||
trace_usb_gadget_activate(gadget, ret);
|
||||
@ -1051,12 +1121,13 @@ EXPORT_SYMBOL_GPL(usb_gadget_set_state);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static void usb_udc_connect_control(struct usb_udc *udc)
|
||||
/* Acquire connect_lock before calling this function. */
|
||||
static void usb_udc_connect_control_locked(struct usb_udc *udc) __must_hold(&udc->connect_lock)
|
||||
{
|
||||
if (udc->vbus)
|
||||
usb_gadget_connect(udc->gadget);
|
||||
if (udc->vbus && udc->started)
|
||||
usb_gadget_connect_locked(udc->gadget);
|
||||
else
|
||||
usb_gadget_disconnect(udc->gadget);
|
||||
usb_gadget_disconnect_locked(udc->gadget);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1072,10 +1143,12 @@ void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status)
|
||||
{
|
||||
struct usb_udc *udc = gadget->udc;
|
||||
|
||||
mutex_lock(&udc->connect_lock);
|
||||
if (udc) {
|
||||
udc->vbus = status;
|
||||
usb_udc_connect_control(udc);
|
||||
usb_udc_connect_control_locked(udc);
|
||||
}
|
||||
mutex_unlock(&udc->connect_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_udc_vbus_handler);
|
||||
|
||||
@ -1097,7 +1170,7 @@ void usb_gadget_udc_reset(struct usb_gadget *gadget,
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
|
||||
|
||||
/**
|
||||
* usb_gadget_udc_start - tells usb device controller to start up
|
||||
* usb_gadget_udc_start_locked - tells usb device controller to start up
|
||||
* @udc: The UDC to be started
|
||||
*
|
||||
* This call is issued by the UDC Class driver when it's about
|
||||
@ -1108,8 +1181,11 @@ EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
|
||||
* necessary to have it powered on.
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*
|
||||
* Caller should acquire connect_lock before invoking this function.
|
||||
*/
|
||||
static inline int usb_gadget_udc_start(struct usb_udc *udc)
|
||||
static inline int usb_gadget_udc_start_locked(struct usb_udc *udc)
|
||||
__must_hold(&udc->connect_lock)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -1126,7 +1202,7 @@ static inline int usb_gadget_udc_start(struct usb_udc *udc)
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_gadget_udc_stop - tells usb device controller we don't need it anymore
|
||||
* usb_gadget_udc_stop_locked - tells usb device controller we don't need it anymore
|
||||
* @udc: The UDC to be stopped
|
||||
*
|
||||
* This call is issued by the UDC Class driver after calling
|
||||
@ -1135,8 +1211,11 @@ static inline int usb_gadget_udc_start(struct usb_udc *udc)
|
||||
* The details are implementation specific, but it can go as
|
||||
* far as powering off UDC completely and disable its data
|
||||
* line pullups.
|
||||
*
|
||||
* Caller should acquire connect lock before invoking this function.
|
||||
*/
|
||||
static inline void usb_gadget_udc_stop(struct usb_udc *udc)
|
||||
static inline void usb_gadget_udc_stop_locked(struct usb_udc *udc)
|
||||
__must_hold(&udc->connect_lock)
|
||||
{
|
||||
if (!udc->started) {
|
||||
dev_err(&udc->dev, "UDC had already stopped\n");
|
||||
@ -1295,6 +1374,7 @@ int usb_add_gadget(struct usb_gadget *gadget)
|
||||
|
||||
udc->gadget = gadget;
|
||||
gadget->udc = udc;
|
||||
mutex_init(&udc->connect_lock);
|
||||
|
||||
udc->started = false;
|
||||
|
||||
@ -1496,11 +1576,15 @@ static int gadget_bind_driver(struct device *dev)
|
||||
if (ret)
|
||||
goto err_bind;
|
||||
|
||||
ret = usb_gadget_udc_start(udc);
|
||||
if (ret)
|
||||
mutex_lock(&udc->connect_lock);
|
||||
ret = usb_gadget_udc_start_locked(udc);
|
||||
if (ret) {
|
||||
mutex_unlock(&udc->connect_lock);
|
||||
goto err_start;
|
||||
}
|
||||
usb_gadget_enable_async_callbacks(udc);
|
||||
usb_udc_connect_control(udc);
|
||||
usb_udc_connect_control_locked(udc);
|
||||
mutex_unlock(&udc->connect_lock);
|
||||
|
||||
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
|
||||
return 0;
|
||||
@ -1531,12 +1615,14 @@ static void gadget_unbind_driver(struct device *dev)
|
||||
|
||||
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
|
||||
|
||||
usb_gadget_disconnect(gadget);
|
||||
mutex_lock(&udc->connect_lock);
|
||||
usb_gadget_disconnect_locked(gadget);
|
||||
usb_gadget_disable_async_callbacks(udc);
|
||||
if (gadget->irq)
|
||||
synchronize_irq(gadget->irq);
|
||||
udc->driver->unbind(gadget);
|
||||
usb_gadget_udc_stop(udc);
|
||||
usb_gadget_udc_stop_locked(udc);
|
||||
mutex_unlock(&udc->connect_lock);
|
||||
|
||||
mutex_lock(&udc_lock);
|
||||
driver->is_bound = false;
|
||||
@ -1622,11 +1708,15 @@ static ssize_t soft_connect_store(struct device *dev,
|
||||
}
|
||||
|
||||
if (sysfs_streq(buf, "connect")) {
|
||||
usb_gadget_udc_start(udc);
|
||||
usb_gadget_connect(udc->gadget);
|
||||
mutex_lock(&udc->connect_lock);
|
||||
usb_gadget_udc_start_locked(udc);
|
||||
usb_gadget_connect_locked(udc->gadget);
|
||||
mutex_unlock(&udc->connect_lock);
|
||||
} else if (sysfs_streq(buf, "disconnect")) {
|
||||
usb_gadget_disconnect(udc->gadget);
|
||||
usb_gadget_udc_stop(udc);
|
||||
mutex_lock(&udc->connect_lock);
|
||||
usb_gadget_disconnect_locked(udc->gadget);
|
||||
usb_gadget_udc_stop_locked(udc);
|
||||
mutex_unlock(&udc->connect_lock);
|
||||
} else {
|
||||
dev_err(dev, "unsupported command '%s'\n", buf);
|
||||
ret = -EINVAL;
|
||||
|
@ -1319,7 +1319,7 @@ MODULE_DEVICE_TABLE(of, max3420_udc_of_match);
|
||||
static struct spi_driver max3420_driver = {
|
||||
.driver = {
|
||||
.name = "max3420-udc",
|
||||
.of_match_table = of_match_ptr(max3420_udc_of_match),
|
||||
.of_match_table = max3420_udc_of_match,
|
||||
},
|
||||
.probe = max3420_probe,
|
||||
.remove = max3420_remove,
|
||||
|
@ -2229,7 +2229,11 @@ static int mv_udc_probe(struct platform_device *pdev)
|
||||
INIT_LIST_HEAD(&udc->status_req->queue);
|
||||
|
||||
/* allocate a small amount of memory to get valid address */
|
||||
udc->status_req->req.buf = kzalloc(8, GFP_KERNEL);
|
||||
udc->status_req->req.buf = devm_kzalloc(&pdev->dev, 8, GFP_KERNEL);
|
||||
if (!udc->status_req->req.buf) {
|
||||
retval = -ENOMEM;
|
||||
goto err_destroy_dma;
|
||||
}
|
||||
udc->status_req->req.dma = DMA_ADDR_INVALID;
|
||||
|
||||
udc->resume_state = USB_STATE_NOTATTACHED;
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sys_soc.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
@ -2661,6 +2660,7 @@ static int renesas_usb3_remove(struct platform_device *pdev)
|
||||
debugfs_remove_recursive(usb3->dentry);
|
||||
device_remove_file(&pdev->dev, &dev_attr_role);
|
||||
|
||||
cancel_work_sync(&usb3->role_work);
|
||||
usb_role_switch_unregister(usb3->role_sw);
|
||||
|
||||
usb_del_gadget_udc(&usb3->gadget);
|
||||
@ -2781,13 +2781,6 @@ static void renesas_usb3_init_ram(struct renesas_usb3 *usb3, struct device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
static const struct renesas_usb3_priv renesas_usb3_priv_r8a7795_es1 = {
|
||||
.ramsize_per_ramif = SZ_16K,
|
||||
.num_ramif = 2,
|
||||
.ramsize_per_pipe = SZ_4K,
|
||||
.workaround_for_vbus = true,
|
||||
};
|
||||
|
||||
static const struct renesas_usb3_priv renesas_usb3_priv_gen3 = {
|
||||
.ramsize_per_ramif = SZ_16K,
|
||||
.num_ramif = 4,
|
||||
@ -2829,14 +2822,6 @@ static const struct of_device_id usb3_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, usb3_of_match);
|
||||
|
||||
static const struct soc_device_attribute renesas_usb3_quirks_match[] = {
|
||||
{
|
||||
.soc_id = "r8a7795", .revision = "ES1.*",
|
||||
.data = &renesas_usb3_priv_r8a7795_es1,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static const unsigned int renesas_usb3_cable[] = {
|
||||
EXTCON_USB,
|
||||
EXTCON_USB_HOST,
|
||||
@ -2854,13 +2839,8 @@ static int renesas_usb3_probe(struct platform_device *pdev)
|
||||
struct renesas_usb3 *usb3;
|
||||
int irq, ret;
|
||||
const struct renesas_usb3_priv *priv;
|
||||
const struct soc_device_attribute *attr;
|
||||
|
||||
attr = soc_device_match(renesas_usb3_quirks_match);
|
||||
if (attr)
|
||||
priv = attr->data;
|
||||
else
|
||||
priv = of_device_get_match_data(&pdev->dev);
|
||||
priv = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
@ -3039,7 +3019,7 @@ static struct platform_driver renesas_usb3_driver = {
|
||||
.driver = {
|
||||
.name = udc_name,
|
||||
.pm = &renesas_usb3_pm_ops,
|
||||
.of_match_table = of_match_ptr(usb3_of_match),
|
||||
.of_match_table = usb3_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(renesas_usb3_driver);
|
||||
|
@ -545,17 +545,6 @@ static inline void usbf_ep_dma_reg_bitclr(struct usbf_ep *ep, uint offset,
|
||||
usbf_ep_dma_reg_writel(ep, offset, tmp);
|
||||
}
|
||||
|
||||
static inline void usbf_ep_dma_reg_clrset(struct usbf_ep *ep, uint offset,
|
||||
u32 clr, u32 set)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
tmp = usbf_ep_dma_reg_readl(ep, offset);
|
||||
tmp &= ~clr;
|
||||
tmp |= set;
|
||||
usbf_ep_dma_reg_writel(ep, offset, tmp);
|
||||
}
|
||||
|
||||
static void usbf_ep0_send_null(struct usbf_ep *ep0, bool is_data1)
|
||||
{
|
||||
u32 set;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user