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:
Linus Torvalds 2023-04-27 11:42:11 -07:00
commit 4010e62b5b
179 changed files with 3334 additions and 7869 deletions

View File

@ -76,7 +76,7 @@ Date: Dec 2014
KernelVersion: 4.0 KernelVersion: 4.0
Description: Default camera terminal descriptors 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 bmControls bitmap specifying which controls are
@ -101,7 +101,7 @@ Date: Dec 2014
KernelVersion: 4.0 KernelVersion: 4.0
Description: Default processing unit descriptors Description: Default processing unit descriptors
All attributes read only: All attributes read only except bmControls, which is read/write:
=============== ======================================== =============== ========================================
iProcessing index of string descriptor iProcessing index of string descriptor

View File

@ -23,3 +23,55 @@ Description:
Reading this attribute gives the state of the DbC. It Reading this attribute gives the state of the DbC. It
can be one of the following states: disabled, enabled, can be one of the following states: disabled, enabled,
initialized, connected, configured and stalled. 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.

View File

@ -2,8 +2,8 @@
# Copyright 2019 BayLibre, SAS # Copyright 2019 BayLibre, SAS
%YAML 1.2 %YAML 1.2
--- ---
$id: "http://devicetree.org/schemas/usb/amlogic,meson-g12a-usb-ctrl.yaml#" $id: http://devicetree.org/schemas/usb/amlogic,meson-g12a-usb-ctrl.yaml#
$schema: "http://devicetree.org/meta-schemas/core.yaml#" $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic Meson G12A DWC3 USB SoC Controller Glue title: Amlogic Meson G12A DWC3 USB SoC Controller Glue

View File

@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Broadcom STB USB EHCI Controller title: Broadcom STB USB EHCI Controller
allOf: allOf:
- $ref: "usb-hcd.yaml" - $ref: usb-hcd.yaml
maintainers: maintainers:
- Al Cooper <alcooperx@gmail.com> - Al Cooper <alcooperx@gmail.com>

View File

@ -1,159 +0,0 @@
* USB2 ChipIdea USB controller for ci13xxx
Required properties:
- compatible: should be one of:
"fsl,imx23-usb"
"fsl,imx27-usb"
"fsl,imx28-usb"
"fsl,imx6q-usb"
"fsl,imx6sl-usb"
"fsl,imx6sx-usb"
"fsl,imx6ul-usb"
"fsl,imx7d-usb"
"fsl,imx7ulp-usb"
"fsl,imx8mm-usb"
"lsi,zevio-usb"
"qcom,ci-hdrc"
"chipidea,usb2"
"xlnx,zynq-usb-2.20a"
"nvidia,tegra20-udc"
"nvidia,tegra30-udc"
"nvidia,tegra114-udc"
"nvidia,tegra124-udc"
- reg: base address and length of the registers
- interrupts: interrupt for the USB controller
Recommended properies:
- phy_type: the type of the phy connected to the core. Should be one
of "utmi", "utmi_wide", "ulpi", "serial" or "hsic". Without this
property the PORTSC register won't be touched.
- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg"
Deprecated properties:
- usb-phy: phandle for the PHY device. Use "phys" instead.
- fsl,usbphy: phandle of usb phy that connects to the port. Use "phys" instead.
Optional properties:
- clocks: reference to the USB clock
- phys: reference to the USB PHY
- phy-names: should be "usb-phy"
- vbus-supply: reference to the VBUS regulator
- maximum-speed: limit the maximum connection speed to "full-speed".
- tpl-support: TPL (Targeted Peripheral List) feature for targeted hosts
- itc-setting: interrupt threshold control register control, the setting
should be aligned with ITC bits at register USBCMD.
- ahb-burst-config: it is vendor dependent, the required value should be
aligned with AHBBRST at SBUSCFG, the range is from 0x0 to 0x7. This
property is used to change AHB burst configuration, check the chipidea
spec for meaning of each value. If this property is not existed, it
will use the reset value.
- tx-burst-size-dword: it is vendor dependent, the tx burst size in dword
(4 bytes), This register represents the maximum length of a the burst
in 32-bit words while moving data from system memory to the USB
bus, the value of this property will only take effect if property
"ahb-burst-config" is set to 0, if this property is missing the reset
default of the hardware implementation will be used.
- rx-burst-size-dword: it is vendor dependent, the rx burst size in dword
(4 bytes), This register represents the maximum length of a the burst
in 32-bit words while moving data from the USB bus to system memory,
the value of this property will only take effect if property
"ahb-burst-config" is set to 0, if this property is missing the reset
default of the hardware implementation will be used.
- extcon: phandles to external connector devices. First phandle should point to
external connector, which provide "USB" cable events, the second should point
to external connector device, which provide "USB-HOST" cable events. If one
of the external connector devices is not required, empty <0> phandle should
be specified.
- phy-clkgate-delay-us: the delay time (us) between putting the PHY into
low power mode and gating the PHY clock.
- non-zero-ttctrl-ttha: after setting this property, the value of register
ttctrl.ttha will be 0x7f; if not, the value will be 0x0, this is the default
value. It needs to be very carefully for setting this property, it is
recommended that consult with your IC engineer before setting this value.
On the most of chipidea platforms, the "usage_tt" flag at RTL is 0, so this
property only affects siTD.
If this property is not set, the max packet size is 1023 bytes, and if
the total of packet size for pervious transactions are more than 256 bytes,
it can't accept any transactions within this frame. The use case is single
transaction, but higher frame rate.
If this property is set, the max packet size is 188 bytes, it can handle
more transactions than above case, it can accept transactions until it
considers the left room size within frame is less than 188 bytes, software
needs to make sure it does not send more than 90%
maximum_periodic_data_per_frame. The use case is multiple transactions, but
less frame rate.
- mux-controls: The mux control for toggling host/device output of this
controller. It's expected that a mux state of 0 indicates device mode and a
mux state of 1 indicates host mode.
- mux-control-names: Shall be "usb_switch" if mux-controls is specified.
- pinctrl-names: Names for optional pin modes in "default", "host", "device".
In case of HSIC-mode, "idle" and "active" pin modes are mandatory. In this
case, the "idle" state needs to pull down the data and strobe pin
and the "active" state needs to pull up the strobe pin.
- pinctrl-n: alternate pin modes
i.mx specific properties
- fsl,usbmisc: phandler of non-core register device, with one
argument that indicate usb controller index
- disable-over-current: disable over current detect
- over-current-active-low: over current signal polarity is active low.
- over-current-active-high: over current signal polarity is active high.
It's recommended to specify the over current polarity.
- power-active-high: power signal polarity is active high
- external-vbus-divider: enables off-chip resistor divider for Vbus
- samsung,picophy-pre-emp-curr-control: HS Transmitter Pre-Emphasis Current
Control. This signal controls the amount of current sourced to the
USB_OTG*_DP and USB_OTG*_DN pins after a J-to-K or K-to-J transition.
The range is from 0x0 to 0x3, the default value is 0x1.
Details can refer to TXPREEMPAMPTUNE0 bits of USBNC_n_PHY_CFG1.
- samsung,picophy-dc-vol-level-adjust: HS DC Voltage Level Adjustment.
Adjust the high-speed transmitter DC level voltage.
The range is from 0x0 to 0xf, the default value is 0x3.
Details can refer to TXVREFTUNE0 bits of USBNC_n_PHY_CFG1.
Example:
usb@f7ed0000 {
compatible = "chipidea,usb2";
reg = <0xf7ed0000 0x10000>;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&chip CLKID_USB0>;
phys = <&usb_phy0>;
phy-names = "usb-phy";
vbus-supply = <&reg_usb0_vbus>;
itc-setting = <0x4>; /* 4 micro-frames */
/* Incremental burst of unspecified length */
ahb-burst-config = <0x0>;
tx-burst-size-dword = <0x10>; /* 64 bytes */
rx-burst-size-dword = <0x10>;
extcon = <0>, <&usb_id>;
phy-clkgate-delay-us = <400>;
mux-controls = <&usb_switch>;
mux-control-names = "usb_switch";
};
Example for HSIC:
usb@2184400 {
compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
reg = <0x02184400 0x200>;
interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6QDL_CLK_USBOH3>;
fsl,usbphy = <&usbphynop1>;
fsl,usbmisc = <&usbmisc 2>;
phy_type = "hsic";
dr_mode = "host";
ahb-burst-config = <0x0>;
tx-burst-size-dword = <0x10>;
rx-burst-size-dword = <0x10>;
pinctrl-names = "idle", "active";
pinctrl-0 = <&pinctrl_usbh2_idle>;
pinctrl-1 = <&pinctrl_usbh2_active>;
#address-cells = <1>;
#size-cells = <0>;
usbnet: ethernet@1 {
compatible = "usb424,9730";
reg = <1>;
};
};

View 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 = <&reg_usb0_vbus>;
itc-setting = <0x4>; /* 4 micro-frames */
/* Incremental burst of unspecified length */
ahb-burst-config = <0x0>;
tx-burst-size-dword = <0x10>; /* 64 bytes */
rx-burst-size-dword = <0x10>;
extcon = <0>, <&usb_id>;
phy-clkgate-delay-us = <400>;
mux-controls = <&usb_switch>;
mux-control-names = "usb_switch";
};
# Example for HSIC:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/imx6qdl-clock.h>
usb@2184400 {
compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
reg = <0x02184400 0x200>;
interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6QDL_CLK_USBOH3>;
fsl,usbphy = <&usbphynop1>;
fsl,usbmisc = <&usbmisc 2>;
phy_type = "hsic";
dr_mode = "host";
ahb-burst-config = <0x0>;
tx-burst-size-dword = <0x10>;
rx-burst-size-dword = <0x10>;
pinctrl-names = "idle", "active";
pinctrl-0 = <&pinctrl_usbh2_idle>;
pinctrl-1 = <&pinctrl_usbh2_active>;
#address-cells = <1>;
#size-cells = <0>;
ethernet@1 {
compatible = "usb424,9730";
reg = <1>;
};
};
...

View File

@ -75,11 +75,14 @@ properties:
maxItems: 1 maxItems: 1
clocks: clocks:
maxItems: 1 minItems: 1
maxItems: 2
clock-names: clock-names:
items: items:
- const: otg - const: otg
- const: utmi
minItems: 1
disable-over-current: disable-over-current:
type: boolean type: boolean

View File

@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2 %YAML 1.2
--- ---
$id: "http://devicetree.org/schemas/usb/fcs,fsa4480.yaml#" $id: http://devicetree.org/schemas/usb/fcs,fsa4480.yaml#
$schema: "http://devicetree.org/meta-schemas/core.yaml#" $schema: http://devicetree.org/meta-schemas/core.yaml#
title: ON Semiconductor Analog Audio Switch title: ON Semiconductor Analog Audio Switch

View 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";
};

View 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>;
};
...

View File

@ -10,7 +10,7 @@ maintainers:
- Greg Kroah-Hartman <gregkh@linuxfoundation.org> - Greg Kroah-Hartman <gregkh@linuxfoundation.org>
allOf: allOf:
- $ref: "usb-hcd.yaml" - $ref: usb-hcd.yaml
- if: - if:
properties: properties:
compatible: compatible:

View File

@ -148,7 +148,7 @@ allOf:
properties: properties:
transceiver: false transceiver: false
additionalProperties: false unevaluatedProperties: false
examples: examples:
- | - |

View File

@ -10,7 +10,7 @@ maintainers:
- Mathias Nyman <mathias.nyman@intel.com> - Mathias Nyman <mathias.nyman@intel.com>
allOf: allOf:
- $ref: "usb-xhci.yaml#" - $ref: usb-xhci.yaml#
properties: properties:
compatible: compatible:

View File

@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2 %YAML 1.2
--- ---
$id: "http://devicetree.org/schemas/usb/gpio-sbu-mux.yaml#" $id: http://devicetree.org/schemas/usb/gpio-sbu-mux.yaml#
$schema: "http://devicetree.org/meta-schemas/core.yaml#" $schema: http://devicetree.org/meta-schemas/core.yaml#
title: GPIO-based SBU mux title: GPIO-based SBU mux

View File

@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2 %YAML 1.2
--- ---
$id: "http://devicetree.org/schemas/usb/maxim,max33359.yaml#" $id: http://devicetree.org/schemas/usb/maxim,max33359.yaml#
$schema: "http://devicetree.org/meta-schemas/core.yaml#" $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Maxim TCPCI Type-C PD controller title: Maxim TCPCI Type-C PD controller

View File

@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2 %YAML 1.2
--- ---
$id: "http://devicetree.org/schemas/usb/mediatek,mt6360-tcpc.yaml#" $id: http://devicetree.org/schemas/usb/mediatek,mt6360-tcpc.yaml#
$schema: "http://devicetree.org/meta-schemas/core.yaml#" $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Mediatek MT6360 Type-C Port Switch and Power Delivery controller title: Mediatek MT6360 Type-C Port Switch and Power Delivery controller

View File

@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2 %YAML 1.2
--- ---
$id: "http://devicetree.org/schemas/usb/mediatek,mt6370-tcpc.yaml#" $id: http://devicetree.org/schemas/usb/mediatek,mt6370-tcpc.yaml#
$schema: "http://devicetree.org/meta-schemas/core.yaml#" $schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediatTek MT6370 Type-C Port Switch and Power Delivery controller title: MediatTek MT6370 Type-C Port Switch and Power Delivery controller

View File

@ -11,7 +11,7 @@ maintainers:
- Chunfeng Yun <chunfeng.yun@mediatek.com> - Chunfeng Yun <chunfeng.yun@mediatek.com>
allOf: allOf:
- $ref: "usb-xhci.yaml" - $ref: usb-xhci.yaml
description: | description: |
There are two scenarios: There are two scenarios:
@ -77,6 +77,7 @@ properties:
- description: Mcu bus clock for register access - description: Mcu bus clock for register access
- description: DMA bus clock for data transfer - description: DMA bus clock for data transfer
- description: controller clock - description: controller clock
- description: frame count clock
clock-names: clock-names:
minItems: 1 minItems: 1
@ -86,14 +87,7 @@ properties:
- const: mcu_ck - const: mcu_ck
- const: dma_ck - const: dma_ck
- const: xhci_ck - const: xhci_ck
- const: frmcnt_ck
assigned-clocks:
minItems: 1
maxItems: 5
assigned-clock-parents:
minItems: 1
maxItems: 5
phys: phys:
description: description:

View File

@ -11,7 +11,7 @@ maintainers:
- Chunfeng Yun <chunfeng.yun@mediatek.com> - Chunfeng Yun <chunfeng.yun@mediatek.com>
allOf: allOf:
- $ref: "usb-drd.yaml" - $ref: usb-drd.yaml
description: | description: |
The DRD controller has a glue layer IPPC (IP Port Control), and its host is 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: Reference clock used by low power mode etc
- description: Mcu bus clock for register access - description: Mcu bus clock for register access
- description: DMA bus clock for data transfer - description: DMA bus clock for data transfer
- description: DRD controller clock
- description: Frame count clock
clock-names: clock-names:
minItems: 1 minItems: 1
@ -74,6 +76,8 @@ properties:
- const: ref_ck - const: ref_ck
- const: mcu_ck - const: mcu_ck
- const: dma_ck - const: dma_ck
- const: xhci_ck
- const: frmcnt_ck
phys: phys:
description: description:
@ -204,9 +208,9 @@ patternProperties:
example if the host mode is enabled. example if the host mode is enabled.
dependencies: dependencies:
connector: [ 'usb-role-switch' ] connector: [ usb-role-switch ]
port: [ 'usb-role-switch' ] port: [ usb-role-switch ]
role-switch-default-mode: [ 'usb-role-switch' ] role-switch-default-mode: [ usb-role-switch ]
wakeup-source: [ 'mediatek,syscon-wakeup' ] wakeup-source: [ 'mediatek,syscon-wakeup' ]
required: required:

View File

@ -68,8 +68,8 @@ properties:
type: object type: object
dependencies: dependencies:
usb-role-switch: [ 'connector' ] usb-role-switch: [ connector ]
connector: [ 'usb-role-switch' ] connector: [ usb-role-switch ]
required: required:
- compatible - compatible

View File

@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2 %YAML 1.2
--- ---
$id: "http://devicetree.org/schemas/usb/nvidia,tegra-xudc.yaml#" $id: http://devicetree.org/schemas/usb/nvidia,tegra-xudc.yaml#
$schema: "http://devicetree.org/meta-schemas/core.yaml#" $schema: http://devicetree.org/meta-schemas/core.yaml#
title: NVIDIA Tegra XUSB device mode controller (XUDC) title: NVIDIA Tegra XUSB device mode controller (XUDC)

View 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>;
};
};
};
};
};
};

View File

@ -21,6 +21,7 @@ properties:
- qcom,msm8994-dwc3 - qcom,msm8994-dwc3
- qcom,msm8996-dwc3 - qcom,msm8996-dwc3
- qcom,msm8998-dwc3 - qcom,msm8998-dwc3
- qcom,qcm2290-dwc3
- qcom,qcs404-dwc3 - qcom,qcs404-dwc3
- qcom,sc7180-dwc3 - qcom,sc7180-dwc3
- qcom,sc7280-dwc3 - qcom,sc7280-dwc3
@ -301,6 +302,7 @@ allOf:
compatible: compatible:
contains: contains:
enum: enum:
- qcom,qcm2290-dwc3
- qcom,sm6115-dwc3 - qcom,sm6115-dwc3
- qcom,sm6125-dwc3 - qcom,sm6125-dwc3
- qcom,sm8150-dwc3 - qcom,sm8150-dwc3

View File

@ -26,7 +26,7 @@ properties:
phandle to the regulator that provides power to the hub. phandle to the regulator that provides power to the hub.
peer-hub: peer-hub:
$ref: '/schemas/types.yaml#/definitions/phandle' $ref: /schemas/types.yaml#/definitions/phandle
description: description:
phandle to the peer hub on the controller. phandle to the peer hub on the controller.

View File

@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2 %YAML 1.2
--- ---
$id: "http://devicetree.org/schemas/usb/richtek,rt1711h.yaml#" $id: http://devicetree.org/schemas/usb/richtek,rt1711h.yaml#
$schema: "http://devicetree.org/meta-schemas/core.yaml#" $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Richtek RT1711H Type-C Port Switch and Power Delivery controller title: Richtek RT1711H Type-C Port Switch and Power Delivery controller

View File

@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2 %YAML 1.2
--- ---
$id: "http://devicetree.org/schemas/usb/richtek,rt1719.yaml#" $id: http://devicetree.org/schemas/usb/richtek,rt1719.yaml#
$schema: "http://devicetree.org/meta-schemas/core.yaml#" $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Richtek RT1719 sink-only Type-C PD controller title: Richtek RT1719 sink-only Type-C PD controller

View File

@ -14,6 +14,7 @@ properties:
enum: enum:
- smsc,usb3503 - smsc,usb3503
- smsc,usb3503a - smsc,usb3503a
- smsc,usb3803
reg: reg:
maxItems: 1 maxItems: 1
@ -33,6 +34,12 @@ properties:
description: > description: >
GPIO for reset GPIO for reset
bypass-gpios:
maxItems: 1
description: >
GPIO for bypass.
Control signal to select between HUB MODE and BYPASS MODE.
disabled-ports: disabled-ports:
$ref: /schemas/types.yaml#/definitions/uint32-array $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1 minItems: 1
@ -46,9 +53,10 @@ properties:
initial-mode: initial-mode:
$ref: /schemas/types.yaml#/definitions/uint32 $ref: /schemas/types.yaml#/definitions/uint32
enum: [1, 2]
description: > 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: clocks:
maxItems: 1 maxItems: 1
@ -71,6 +79,29 @@ properties:
required: required:
- compatible - 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 additionalProperties: false
examples: 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> #include <dt-bindings/gpio/gpio.h>

View File

@ -70,6 +70,10 @@ properties:
dma-coherent: true dma-coherent: true
extcon:
maxItems: 1
deprecated: true
iommus: iommus:
maxItems: 1 maxItems: 1
@ -232,6 +236,11 @@ properties:
When set, all SuperSpeed bus instances in park mode are disabled. When set, all SuperSpeed bus instances in park mode are disabled.
type: boolean 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: snps,dis_metastability_quirk:
description: description:
When set, disable metastability workaround. CAUTION! Use only if you are 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. of resume. This option is to support certain legacy ULPI PHYs.
type: boolean 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: snps,is-utmi-l1-suspend:
description: description:
True when DWC3 asserts output signal utmi_l1_suspend_n, false when 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 This port is used with the 'usb-role-switch' property to connect the
dwc3 to type C connector. 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: wakeup-source:
$ref: /schemas/types.yaml#/definitions/flag $ref: /schemas/types.yaml#/definitions/flag
description: description:

View File

@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2 %YAML 1.2
--- ---
$id: "http://devicetree.org/schemas/usb/st,stusb160x.yaml#" $id: http://devicetree.org/schemas/usb/st,stusb160x.yaml#
$schema: "http://devicetree.org/meta-schemas/core.yaml#" $schema: http://devicetree.org/meta-schemas/core.yaml#
title: STMicroelectronics STUSB160x Type-C controller title: STMicroelectronics STUSB160x Type-C controller

View File

@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
%YAML 1.2 %YAML 1.2
--- ---
$id: "http://devicetree.org/schemas/usb/ti,j721e-usb.yaml#" $id: http://devicetree.org/schemas/usb/ti,j721e-usb.yaml#
$schema: "http://devicetree.org/meta-schemas/core.yaml#" $schema: http://devicetree.org/meta-schemas/core.yaml#
title: TI wrapper module for the Cadence USBSS-DRD controller 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. VBUS pin of the SoC via a 1/3 voltage divider.
type: boolean type: boolean
assigned-clocks:
maxItems: 1
assigned-clock-parents:
maxItems: 1
'#address-cells': '#address-cells':
const: 2 const: 2

View File

@ -34,14 +34,6 @@ properties:
minItems: 1 minItems: 1
maxItems: 2 maxItems: 2
assigned-clocks:
minItems: 1
maxItems: 2
assigned-clock-parents:
minItems: 1
maxItems: 2
power-domains: power-domains:
maxItems: 1 maxItems: 1
description: Should contain a phandle to a PM domain provider node description: Should contain a phandle to a PM domain provider node

View File

@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2 %YAML 1.2
--- ---
$id: "http://devicetree.org/schemas/usb/ti,tps6598x.yaml#" $id: http://devicetree.org/schemas/usb/ti,tps6598x.yaml#
$schema: "http://devicetree.org/meta-schemas/core.yaml#" $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments 6598x Type-C Port Switch and Power Delivery controller title: Texas Instruments 6598x Type-C Port Switch and Power Delivery controller
@ -35,8 +35,6 @@ properties:
required: required:
- compatible - compatible
- reg - reg
- interrupts
- interrupt-names
additionalProperties: true additionalProperties: true

View File

@ -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>;
};
};
};
};
};

View File

@ -76,7 +76,6 @@ patternProperties:
maxItems: 1 maxItems: 1
required: required:
- compatible
- reg - reg
additionalProperties: true additionalProperties: true

View File

@ -27,6 +27,9 @@ properties:
vcc-supply: vcc-supply:
description: phandle to the regulator that provides power to the PHY. description: phandle to the regulator that provides power to the PHY.
power-domains:
maxItems: 1
reset-gpios: reset-gpios:
maxItems: 1 maxItems: 1

View File

@ -10,7 +10,7 @@ maintainers:
- Mathias Nyman <mathias.nyman@intel.com> - Mathias Nyman <mathias.nyman@intel.com>
allOf: allOf:
- $ref: "usb-hcd.yaml#" - $ref: usb-hcd.yaml#
properties: properties:
usb2-lpm-disable: usb2-lpm-disable:

View File

@ -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>;
};

View File

@ -275,6 +275,34 @@ out with 0x00, for example:
bNrInPins and baSourceID function in the same way. 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 Custom Strings Support
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~

View File

@ -189,7 +189,7 @@
}; };
usbotg1: usb@40330000 { usbotg1: usb@40330000 {
compatible = "fsl,imx7ulp-usb", "fsl,imx6ul-usb"; compatible = "fsl,imx7ulp-usb", "fsl,imx6ul-usb", "fsl,imx27-usb";
reg = <0x40330000 0x200>; reg = <0x40330000 0x200>;
interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&pcc2 IMX7ULP_CLK_USB0>; clocks = <&pcc2 IMX7ULP_CLK_USB0>;
@ -202,7 +202,8 @@
}; };
usbmisc1: usbmisc@40330200 { usbmisc1: usbmisc@40330200 {
compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc"; compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc",
"fsl,imx6q-usbmisc";
#index-cells = <1>; #index-cells = <1>;
reg = <0x40330200 0x200>; reg = <0x40330200 0x200>;
}; };

View File

@ -1130,8 +1130,8 @@
usbotg_hs: usb-otg@49000000 { usbotg_hs: usb-otg@49000000 {
compatible = "st,stm32mp15-hsotg", "snps,dwc2"; compatible = "st,stm32mp15-hsotg", "snps,dwc2";
reg = <0x49000000 0x10000>; reg = <0x49000000 0x10000>;
clocks = <&rcc USBO_K>; clocks = <&rcc USBO_K>, <&usbphyc>;
clock-names = "otg"; clock-names = "otg", "utmi";
resets = <&rcc USBO_R>; resets = <&rcc USBO_R>;
reset-names = "dwc2"; reset-names = "dwc2";
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;

View File

@ -35,7 +35,7 @@ conn_subsys: bus@5b000000 {
}; };
usbotg1: usb@5b0d0000 { usbotg1: usb@5b0d0000 {
compatible = "fsl,imx7ulp-usb"; compatible = "fsl,imx7ulp-usb", "fsl,imx6ul-usb", "fsl,imx27-usb";
reg = <0x5b0d0000 0x200>; reg = <0x5b0d0000 0x200>;
interrupt-parent = <&gic>; interrupt-parent = <&gic>;
interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
@ -51,7 +51,7 @@ conn_subsys: bus@5b000000 {
usbmisc1: usbmisc@5b0d0200 { usbmisc1: usbmisc@5b0d0200 {
#index-cells = <1>; #index-cells = <1>;
compatible = "fsl,imx7ulp-usbmisc", "fsl,imx6q-usbmisc"; compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc", "fsl,imx6q-usbmisc";
reg = <0x5b0d0200 0x200>; reg = <0x5b0d0200 0x200>;
}; };

View File

@ -34,7 +34,7 @@
}; };
usbotg2: usb@5b0e0000 { usbotg2: usb@5b0e0000 {
compatible = "fsl,imx8dxl-usb", "fsl,imx7ulp-usb"; compatible = "fsl,imx8dxl-usb", "fsl,imx7ulp-usb", "fsl,imx6ul-usb";
reg = <0x5b0e0000 0x200>; reg = <0x5b0e0000 0x200>;
interrupt-parent = <&gic>; interrupt-parent = <&gic>;
interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>;
@ -49,7 +49,6 @@
ahb-burst-config = <0x0>; ahb-burst-config = <0x0>;
tx-burst-size-dword = <0x10>; tx-burst-size-dword = <0x10>;
rx-burst-size-dword = <0x10>; rx-burst-size-dword = <0x10>;
#stream-id-cells = <1>;
power-domains = <&pd IMX_SC_R_USB_1>; power-domains = <&pd IMX_SC_R_USB_1>;
status = "disabled"; status = "disabled";
@ -63,7 +62,7 @@
usbmisc2: usbmisc@5b0e0200 { usbmisc2: usbmisc@5b0e0200 {
#index-cells = <1>; #index-cells = <1>;
compatible = "fsl,imx7ulp-usbmisc"; compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc", "fsl,imx6q-usbmisc";
reg = <0x5b0e0200 0x200>; reg = <0x5b0e0200 0x200>;
}; };

View File

@ -1253,7 +1253,7 @@
}; };
usbotg1: usb@32e40000 { usbotg1: usb@32e40000 {
compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb"; compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb", "fsl,imx27-usb";
reg = <0x32e40000 0x200>; reg = <0x32e40000 0x200>;
interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MM_CLK_USB1_CTRL_ROOT>; clocks = <&clk IMX8MM_CLK_USB1_CTRL_ROOT>;
@ -1267,13 +1267,14 @@
}; };
usbmisc1: usbmisc@32e40200 { usbmisc1: usbmisc@32e40200 {
compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc"; compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc",
"fsl,imx6q-usbmisc";
#index-cells = <1>; #index-cells = <1>;
reg = <0x32e40200 0x200>; reg = <0x32e40200 0x200>;
}; };
usbotg2: usb@32e50000 { usbotg2: usb@32e50000 {
compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb"; compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb", "fsl,imx27-usb";
reg = <0x32e50000 0x200>; reg = <0x32e50000 0x200>;
interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MM_CLK_USB1_CTRL_ROOT>; clocks = <&clk IMX8MM_CLK_USB1_CTRL_ROOT>;
@ -1287,7 +1288,8 @@
}; };
usbmisc2: usbmisc@32e50200 { usbmisc2: usbmisc@32e50200 {
compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc"; compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc",
"fsl,imx6q-usbmisc";
#index-cells = <1>; #index-cells = <1>;
reg = <0x32e50200 0x200>; reg = <0x32e50200 0x200>;
}; };

View File

@ -1146,7 +1146,7 @@
}; };
usbotg1: usb@32e40000 { usbotg1: usb@32e40000 {
compatible = "fsl,imx8mn-usb", "fsl,imx7d-usb"; compatible = "fsl,imx8mn-usb", "fsl,imx7d-usb", "fsl,imx27-usb";
reg = <0x32e40000 0x200>; reg = <0x32e40000 0x200>;
interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MN_CLK_USB1_CTRL_ROOT>; clocks = <&clk IMX8MN_CLK_USB1_CTRL_ROOT>;
@ -1160,7 +1160,8 @@
}; };
usbmisc1: usbmisc@32e40200 { usbmisc1: usbmisc@32e40200 {
compatible = "fsl,imx8mn-usbmisc", "fsl,imx7d-usbmisc"; compatible = "fsl,imx8mn-usbmisc", "fsl,imx7d-usbmisc",
"fsl,imx6q-usbmisc";
#index-cells = <1>; #index-cells = <1>;
reg = <0x32e40200 0x200>; reg = <0x32e40200 0x200>;
}; };

View File

@ -1453,7 +1453,6 @@
phys = <&usb3_phy0>, <&usb3_phy0>; phys = <&usb3_phy0>, <&usb3_phy0>;
phy-names = "usb2-phy", "usb3-phy"; phy-names = "usb2-phy", "usb3-phy";
power-domains = <&pgc_otg1>; power-domains = <&pgc_otg1>;
usb3-resume-missing-cas;
status = "disabled"; status = "disabled";
}; };
@ -1485,7 +1484,6 @@
phys = <&usb3_phy1>, <&usb3_phy1>; phys = <&usb3_phy1>, <&usb3_phy1>;
phy-names = "usb2-phy", "usb3-phy"; phy-names = "usb2-phy", "usb3-phy";
power-domains = <&pgc_otg2>; power-domains = <&pgc_otg2>;
usb3-resume-missing-cas;
status = "disabled"; status = "disabled";
}; };

View File

@ -497,7 +497,6 @@ CONFIG_USB_EHCI_ROOT_HUB_TT=y
CONFIG_USB_OHCI_HCD=m CONFIG_USB_OHCI_HCD=m
CONFIG_USB_OHCI_HCD_PLATFORM=m CONFIG_USB_OHCI_HCD_PLATFORM=m
CONFIG_USB_UHCI_HCD=m CONFIG_USB_UHCI_HCD=m
CONFIG_USB_U132_HCD=m
CONFIG_USB_SL811_HCD=m CONFIG_USB_SL811_HCD=m
CONFIG_USB_SL811_CS=m CONFIG_USB_SL811_CS=m
CONFIG_USB_ACM=m CONFIG_USB_ACM=m
@ -554,7 +553,6 @@ CONFIG_USB_LCD=m
CONFIG_USB_CYPRESS_CY7C63=m CONFIG_USB_CYPRESS_CY7C63=m
CONFIG_USB_CYTHERM=m CONFIG_USB_CYTHERM=m
CONFIG_USB_IDMOUSE=m CONFIG_USB_IDMOUSE=m
CONFIG_USB_FTDI_ELAN=m
CONFIG_USB_APPLEDISPLAY=m CONFIG_USB_APPLEDISPLAY=m
CONFIG_USB_SISUSBVGA=m CONFIG_USB_SISUSBVGA=m
CONFIG_USB_LD=m CONFIG_USB_LD=m

View File

@ -845,7 +845,6 @@ CONFIG_USB_OHCI_HCD=m
CONFIG_USB_OHCI_HCD_PPC_OF_BE=y CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
CONFIG_USB_OHCI_HCD_PPC_OF_LE=y CONFIG_USB_OHCI_HCD_PPC_OF_LE=y
CONFIG_USB_UHCI_HCD=m CONFIG_USB_UHCI_HCD=m
CONFIG_USB_U132_HCD=m
CONFIG_USB_SL811_HCD=m CONFIG_USB_SL811_HCD=m
CONFIG_USB_ACM=m CONFIG_USB_ACM=m
CONFIG_USB_PRINTER=m CONFIG_USB_PRINTER=m
@ -908,7 +907,6 @@ CONFIG_USB_SEVSEG=m
CONFIG_USB_LEGOTOWER=m CONFIG_USB_LEGOTOWER=m
CONFIG_USB_LCD=m CONFIG_USB_LCD=m
CONFIG_USB_IDMOUSE=m CONFIG_USB_IDMOUSE=m
CONFIG_USB_FTDI_ELAN=m
CONFIG_USB_APPLEDISPLAY=m CONFIG_USB_APPLEDISPLAY=m
CONFIG_USB_SISUSBVGA=m CONFIG_USB_SISUSBVGA=m
CONFIG_USB_LD=m CONFIG_USB_LD=m

View File

@ -316,6 +316,16 @@ static int usb_shark_probe(struct usb_interface *intf,
{ {
struct shark_device *shark; struct shark_device *shark;
int retval = -ENOMEM; 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); shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL);
if (!shark) if (!shark)

View File

@ -282,6 +282,16 @@ static int usb_shark_probe(struct usb_interface *intf,
{ {
struct shark_device *shark; struct shark_device *shark;
int retval = -ENOMEM; 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); shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL);
if (!shark) if (!shark)

View File

@ -341,7 +341,7 @@ static struct acpi_device *tb_acpi_find_companion(struct device *dev)
*/ */
if (tb_is_switch(dev)) if (tb_is_switch(dev))
return tb_acpi_switch_find_companion(tb_to_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), return acpi_find_child_by_adr(ACPI_COMPANION(dev->parent),
tb_to_usb4_port_device(dev)->port->port); tb_to_usb4_port_device(dev)->port->port);
return NULL; return NULL;

View File

@ -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) if (res->tb_error == TB_CFG_ERROR_LOCK)
return -EACCES; 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 -ENOTCONN;
return -EIO; return -EIO;

View File

@ -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 if (pos + 1 == drom_size || pos + entry->len > drom_size
|| !entry->len) { || !entry->len) {
tb_sw_warn(sw, "DROM buffer overrun\n"); tb_sw_warn(sw, "DROM buffer overrun\n");
return -EILSEQ; return -EIO;
} }
switch (entry->type) { switch (entry->type) {
@ -471,14 +471,13 @@ err:
static int tb_drom_copy_nvm(struct tb_switch *sw, u16 *size) static int tb_drom_copy_nvm(struct tb_switch *sw, u16 *size)
{ {
u32 drom_offset; u16 drom_offset;
int ret; int ret;
if (!sw->dma_port) if (!sw->dma_port)
return -ENODEV; return -ENODEV;
ret = tb_sw_read(sw, &drom_offset, TB_CFG_SWITCH, ret = tb_eeprom_get_drom_offset(sw, &drom_offset);
sw->cap_plug_events + 12, 1);
if (ret) if (ret)
return ret; return ret;
@ -513,7 +512,7 @@ err_free:
return ret; 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; int ret;
@ -536,15 +535,40 @@ static int usb4_copy_host_drom(struct tb_switch *sw, u16 *size)
return ret; return ret;
} }
static int tb_drom_read_n(struct tb_switch *sw, u16 offset, u8 *val, static int tb_drom_bit_bang(struct tb_switch *sw, u16 *size)
size_t count)
{ {
if (tb_switch_is_usb4(sw)) int ret;
return usb4_switch_drom_read(sw, offset, val, count);
return tb_eeprom_read_n(sw, offset, val, count); 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 *header =
(const struct tb_drom_header *)sw->drom; (const struct tb_drom_header *)sw->drom;
@ -555,7 +579,7 @@ static int tb_drom_parse(struct tb_switch *sw)
tb_sw_warn(sw, tb_sw_warn(sw,
"DROM UID CRC8 mismatch (expected: %#x, got: %#x)\n", "DROM UID CRC8 mismatch (expected: %#x, got: %#x)\n",
header->uid_crc8, crc); header->uid_crc8, crc);
return -EILSEQ; return -EIO;
} }
if (!sw->uid) if (!sw->uid)
sw->uid = header->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); 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 * tb_drom_read() - Copy DROM to sw->drom and parse it
* @sw: Router whose DROM to read and parse * @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) int tb_drom_read(struct tb_switch *sw)
{ {
u16 size;
struct tb_drom_header *header;
int res, retries = 1;
if (sw->drom) if (sw->drom)
return 0; return 0;
if (tb_route(sw) == 0) { if (!tb_route(sw))
/* return tb_drom_host_read(sw);
* Apple's NHI EFI driver supplies a DROM for the root switch return tb_drom_device_read(sw);
* 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;
} }

View File

@ -526,7 +526,8 @@ static int nhi_alloc_hop(struct tb_nhi *nhi, struct tb_ring *ring)
ring->hop); ring->hop);
ret = -EBUSY; ret = -EBUSY;
goto err_unlock; 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", dev_warn(&nhi->pdev->dev, "RX hop %d already allocated\n",
ring->hop); ring->hop);
ret = -EBUSY; ret = -EBUSY;

View File

@ -271,9 +271,9 @@ static int nvm_authenticate(struct tb_switch *sw, bool auth_only)
} }
sw->nvm->authenticating = true; sw->nvm->authenticating = true;
return usb4_switch_nvm_authenticate(sw); return usb4_switch_nvm_authenticate(sw);
} else if (auth_only) {
return -EOPNOTSUPP;
} }
if (auth_only)
return -EOPNOTSUPP;
sw->nvm->authenticating = true; sw->nvm->authenticating = true;
if (!tb_route(sw)) { if (!tb_route(sw)) {

View File

@ -9,6 +9,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/ktime.h> #include <linux/ktime.h>
#include <linux/units.h>
#include "sb_regs.h" #include "sb_regs.h"
#include "tb.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) if (ret == -EOPNOTSUPP)
return true; return true;
else if (ret) if (ret)
return false; return false;
return !status; return !status;
@ -877,7 +878,7 @@ int usb4_switch_alloc_dp_resource(struct tb_switch *sw, struct tb_port *in)
&status); &status);
if (ret == -EOPNOTSUPP) if (ret == -EOPNOTSUPP)
return 0; return 0;
else if (ret) if (ret)
return ret; return ret;
return status ? -EBUSY : 0; return status ? -EBUSY : 0;
@ -900,7 +901,7 @@ int usb4_switch_dealloc_dp_resource(struct tb_switch *sw, struct tb_port *in)
&status); &status);
if (ret == -EOPNOTSUPP) if (ret == -EOPNOTSUPP)
return 0; return 0;
else if (ret) if (ret)
return ret; return ret;
return status ? -EIO : 0; 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; 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, 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) 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) if (ret)
return ret; return ret;
switch (val) { if (val != opcode)
case 0: return usb4_port_sb_opcode_err_to_errno(val);
return 0;
case USB4_SB_OPCODE_ERR:
return -EAGAIN;
case USB4_SB_OPCODE_ONS:
return -EOPNOTSUPP;
default:
if (val != opcode)
return -EIO;
break;
}
} while (ktime_before(ktime_get(), timeout)); } while (ktime_before(ktime_get(), timeout));
return -ETIMEDOUT; return -ETIMEDOUT;
@ -1813,12 +1815,13 @@ int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index,
if (ret) if (ret)
return ret; return ret;
switch (val) { ret = usb4_port_sb_opcode_err_to_errno(val);
switch (ret) {
case 0: case 0:
*status = 0; *status = 0;
return 0; return 0;
case USB4_SB_OPCODE_ERR: case -EAGAIN:
ret = usb4_port_retimer_read(port, index, USB4_SB_METADATA, ret = usb4_port_retimer_read(port, index, USB4_SB_METADATA,
&metadata, sizeof(metadata)); &metadata, sizeof(metadata));
if (ret) 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; *status = metadata & USB4_SB_METADATA_NVM_AUTH_WRITE_MASK;
return 0; return 0;
case USB4_SB_OPCODE_ONS:
return -EOPNOTSUPP;
default: default:
return -EIO; return ret;
} }
} }
@ -1995,7 +1995,7 @@ static unsigned int usb3_bw_to_mbps(u32 bw, u8 scale)
unsigned long uframes; unsigned long uframes;
uframes = bw * 512UL << scale; 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) 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; unsigned long uframes;
/* 1 uframe is 1/8 ms (125 us) -> 1 / 8000 s */ /* 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); return DIV_ROUND_UP(uframes, 512UL << scale);
} }

View File

@ -1178,9 +1178,8 @@ static int tb_xdomain_get_uuid(struct tb_xdomain *xd)
if (xd->state_retries-- > 0) { if (xd->state_retries-- > 0) {
dev_dbg(&xd->dev, "failed to request UUID, retrying\n"); dev_dbg(&xd->dev, "failed to request UUID, retrying\n");
return -EAGAIN; 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; return ret;
} }
@ -1367,12 +1366,10 @@ static int tb_xdomain_get_properties(struct tb_xdomain *xd)
dev_dbg(&xd->dev, dev_dbg(&xd->dev,
"failed to request remote properties, retrying\n"); "failed to request remote properties, retrying\n");
return -EAGAIN; 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; return ret;
} }
@ -2179,13 +2176,12 @@ static struct tb_xdomain *switch_find_xdomain(struct tb_switch *sw,
if (xd->remote_uuid && if (xd->remote_uuid &&
uuid_equal(xd->remote_uuid, lookup->uuid)) uuid_equal(xd->remote_uuid, lookup->uuid))
return xd; return xd;
} else if (lookup->link && } else {
lookup->link == xd->link && if (lookup->link && lookup->link == xd->link &&
lookup->depth == xd->depth) { lookup->depth == xd->depth)
return xd; return xd;
} else if (lookup->route && if (lookup->route && lookup->route == xd->route)
lookup->route == xd->route) { return xd;
return xd;
} }
} else if (tb_port_has_remote(port)) { } else if (tb_port_has_remote(port)) {
xd = switch_find_xdomain(port->remote->sw, lookup); xd = switch_find_xdomain(port->remote->sw, lookup);

View File

@ -133,35 +133,6 @@ comment "USB port drivers"
if USB 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/serial/Kconfig"
source "drivers/usb/misc/Kconfig" source "drivers/usb/misc/Kconfig"

View File

@ -31,7 +31,6 @@ obj-$(CONFIG_USB_FHCI_HCD) += host/
obj-$(CONFIG_USB_XHCI_HCD) += host/ obj-$(CONFIG_USB_XHCI_HCD) += host/
obj-$(CONFIG_USB_SL811_HCD) += host/ obj-$(CONFIG_USB_SL811_HCD) += host/
obj-$(CONFIG_USB_ISP1362_HCD) += host/ obj-$(CONFIG_USB_ISP1362_HCD) += host/
obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_USB_R8A66597_HCD) += host/ obj-$(CONFIG_USB_R8A66597_HCD) += host/
obj-$(CONFIG_USB_FSL_USB2) += host/ obj-$(CONFIG_USB_FSL_USB2) += host/
obj-$(CONFIG_USB_FOTG210_HCD) += host/ obj-$(CONFIG_USB_FOTG210_HCD) += host/

View File

@ -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. * 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, static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep, char *str)
struct cdns3_trb *ring, char *str)
{ {
dma_addr_t addr = priv_ep->trb_pool_dma; dma_addr_t addr = priv_ep->trb_pool_dma;
struct cdns3_trb *trb; 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", "\t\tfree trbs: %d, CCS=%d, PCS=%d\n",
priv_ep->free_trbs, priv_ep->ccs, priv_ep->pcs); 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) { if (trb_per_sector > TRBS_PER_SEGMENT) {
sprintf(str + ret, "\t\tTransfer ring %d too big\n", sprintf(str + ret, "\t\tTransfer ring %d too big\n",
trb_per_sector); 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) { for (i = 0; i < trb_per_sector; ++i) {
trb = &ring[i]; trb = &priv_ep->trb_pool[i];
ret += sprintf(str + ret, ret += sprintf(str + ret,
"\t\t@%pad %08x %08x %08x\n", &addr, "\t\t@%pad %08x %08x %08x\n", &addr,
le32_to_cpu(trb->buffer), le32_to_cpu(trb->buffer),

View File

@ -100,13 +100,12 @@ DECLARE_EVENT_CLASS(cdns3_log_usb_irq,
TP_STRUCT__entry( TP_STRUCT__entry(
__field(enum usb_device_speed, speed) __field(enum usb_device_speed, speed)
__field(u32, usb_ists) __field(u32, usb_ists)
__dynamic_array(char, str, CDNS3_MSG_MAX)
), ),
TP_fast_assign( TP_fast_assign(
__entry->speed = cdns3_get_speed(priv_dev); __entry->speed = cdns3_get_speed(priv_dev);
__entry->usb_ists = usb_ists; __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)) __entry->usb_ists))
); );
@ -124,7 +123,6 @@ DECLARE_EVENT_CLASS(cdns3_log_epx_irq,
__field(u32, ep_traddr) __field(u32, ep_traddr)
__field(u32, ep_last_sid) __field(u32, ep_last_sid)
__field(u32, use_streams) __field(u32, use_streams)
__dynamic_array(char, str, CDNS3_MSG_MAX)
), ),
TP_fast_assign( TP_fast_assign(
__assign_str(ep_name, priv_ep->name); __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; __entry->use_streams = priv_ep->use_streams;
), ),
TP_printk("%s, ep_traddr: %08x ep_last_sid: %08x use_streams: %d", 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), __get_str(ep_name),
__entry->ep_sts), __entry->ep_sts),
__entry->ep_traddr, __entry->ep_traddr,
@ -153,13 +151,12 @@ DECLARE_EVENT_CLASS(cdns3_log_ep0_irq,
TP_STRUCT__entry( TP_STRUCT__entry(
__field(int, ep_dir) __field(int, ep_dir)
__field(u32, ep_sts) __field(u32, ep_sts)
__dynamic_array(char, str, CDNS3_MSG_MAX)
), ),
TP_fast_assign( TP_fast_assign(
__entry->ep_dir = priv_dev->selected_ep; __entry->ep_dir = priv_dev->selected_ep;
__entry->ep_sts = ep_sts; __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_dir,
__entry->ep_sts)) __entry->ep_sts))
); );
@ -178,7 +175,6 @@ DECLARE_EVENT_CLASS(cdns3_log_ctrl,
__field(u16, wValue) __field(u16, wValue)
__field(u16, wIndex) __field(u16, wIndex)
__field(u16, wLength) __field(u16, wLength)
__dynamic_array(char, str, CDNS3_MSG_MAX)
), ),
TP_fast_assign( TP_fast_assign(
__entry->bRequestType = ctrl->bRequestType; __entry->bRequestType = ctrl->bRequestType;
@ -187,7 +183,7 @@ DECLARE_EVENT_CLASS(cdns3_log_ctrl,
__entry->wIndex = le16_to_cpu(ctrl->wIndex); __entry->wIndex = le16_to_cpu(ctrl->wIndex);
__entry->wLength = le16_to_cpu(ctrl->wLength); __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->bRequestType,
__entry->bRequest, __entry->wValue, __entry->bRequest, __entry->wValue,
__entry->wIndex, __entry->wLength) __entry->wIndex, __entry->wLength)
@ -438,22 +434,16 @@ DECLARE_EVENT_CLASS(cdns3_log_ring,
TP_PROTO(struct cdns3_endpoint *priv_ep), TP_PROTO(struct cdns3_endpoint *priv_ep),
TP_ARGS(priv_ep), TP_ARGS(priv_ep),
TP_STRUCT__entry( TP_STRUCT__entry(
__dynamic_array(u8, ring, TRB_RING_SIZE)
__dynamic_array(u8, priv_ep, sizeof(struct cdns3_endpoint))
__dynamic_array(char, buffer, __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( TP_fast_assign(
memcpy(__get_dynamic_array(priv_ep), priv_ep, cdns3_dbg_ring(priv_ep, __get_str(buffer));
sizeof(struct cdns3_endpoint));
memcpy(__get_dynamic_array(ring), priv_ep->trb_pool,
TRB_RING_SIZE);
), ),
TP_printk("%s", TP_printk("%s", __get_str(buffer))
cdns3_dbg_ring((struct cdns3_endpoint *)__get_str(priv_ep),
(struct cdns3_trb *)__get_str(ring),
__get_str(buffer)))
); );
DEFINE_EVENT(cdns3_log_ring, cdns3_ring, DEFINE_EVENT(cdns3_log_ring, cdns3_ring,

View File

@ -271,7 +271,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_ctrl,
__field(u16, wValue) __field(u16, wValue)
__field(u16, wIndex) __field(u16, wIndex)
__field(u16, wLength) __field(u16, wLength)
__dynamic_array(char, str, CDNSP_MSG_MAX)
), ),
TP_fast_assign( TP_fast_assign(
__entry->bRequestType = ctrl->bRequestType; __entry->bRequestType = ctrl->bRequestType;
@ -280,7 +279,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_ctrl,
__entry->wIndex = le16_to_cpu(ctrl->wIndex); __entry->wIndex = le16_to_cpu(ctrl->wIndex);
__entry->wLength = le16_to_cpu(ctrl->wLength); __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->bRequestType,
__entry->bRequest, __entry->wValue, __entry->bRequest, __entry->wValue,
__entry->wIndex, __entry->wLength) __entry->wIndex, __entry->wLength)
@ -345,7 +344,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_trb,
__field(u32, field3) __field(u32, field3)
__field(union cdnsp_trb *, trb) __field(union cdnsp_trb *, trb)
__field(dma_addr_t, trb_dma) __field(dma_addr_t, trb_dma)
__dynamic_array(char, str, CDNSP_MSG_MAX)
), ),
TP_fast_assign( TP_fast_assign(
__entry->type = ring->type; __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), 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->field0, __entry->field1,
__entry->field2, __entry->field3), __entry->field2, __entry->field3),
__entry->trb, &__entry->trb_dma __entry->trb, &__entry->trb_dma
@ -544,7 +542,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_ep_ctx,
__field(u32, info2) __field(u32, info2)
__field(u64, deq) __field(u64, deq)
__field(u32, tx_info) __field(u32, tx_info)
__dynamic_array(char, str, CDNSP_MSG_MAX)
), ),
TP_fast_assign( TP_fast_assign(
__entry->info = le32_to_cpu(ctx->ep_info); __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->deq = le64_to_cpu(ctx->deq);
__entry->tx_info = le32_to_cpu(ctx->tx_info); __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->info, __entry->info2,
__entry->deq, __entry->tx_info) __entry->deq, __entry->tx_info)
) )
@ -777,7 +774,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_portsc,
TP_STRUCT__entry( TP_STRUCT__entry(
__field(u32, portnum) __field(u32, portnum)
__field(u32, portsc) __field(u32, portsc)
__dynamic_array(char, str, CDNSP_MSG_MAX)
), ),
TP_fast_assign( TP_fast_assign(
__entry->portnum = portnum; __entry->portnum = portnum;
@ -785,7 +781,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_portsc,
), ),
TP_printk("port-%d: %s", TP_printk("port-%d: %s",
__entry->portnum, __entry->portnum,
cdnsp_decode_portsc(__get_str(str), CDNSP_MSG_MAX, cdnsp_decode_portsc(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX,
__entry->portsc) __entry->portsc)
) )
); );

View File

@ -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_GENERIC) += ci_hdrc_usb2.o
obj-$(CONFIG_USB_CHIPIDEA_MSM) += ci_hdrc_msm.o obj-$(CONFIG_USB_CHIPIDEA_MSM) += ci_hdrc_msm.o
obj-$(CONFIG_USB_CHIPIDEA_PCI) += ci_hdrc_pci.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 obj-$(CONFIG_USB_CHIPIDEA_TEGRA) += ci_hdrc_tegra.o

View File

@ -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 * Check the various over current related properties. If over current
* detection is disabled we're not interested in the polarity. * 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; 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_active_low = 0;
data->oc_pol_configured = 1; 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_active_low = 1;
data->oc_pol_configured = 1; data->oc_pol_configured = 1;
} else { } else {

View File

@ -753,7 +753,7 @@ static int ci_get_platdata(struct device *dev,
return ret; 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; platdata->flags |= CI_HDRC_SET_NON_ZERO_TTHA;
ext_id = ERR_PTR(-ENODEV); ext_id = ERR_PTR(-ENODEV);
@ -1108,7 +1108,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
ret = ci_usb_phy_init(ci); ret = ci_usb_phy_init(ci);
if (ret) { if (ret) {
dev_err(dev, "unable to init phy: %d\n", ret); dev_err(dev, "unable to init phy: %d\n", ret);
return ret; goto ulpi_exit;
} }
ci->hw_bank.phys = res->start; ci->hw_bank.phys = res->start;

View File

@ -247,60 +247,6 @@ static int ci_otg_show(struct seq_file *s, void *unused)
} }
DEFINE_SHOW_ATTRIBUTE(ci_otg); 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) static int ci_registers_show(struct seq_file *s, void *unused)
{ {
struct ci_hdrc *ci = s->private; 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)) if (ci_otg_is_fsm_mode(ci))
debugfs_create_file("otg", S_IRUGO, dir, ci, &ci_otg_fops); 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); debugfs_create_file("registers", S_IRUGO, dir, ci, &ci_registers_fops);
} }

View File

@ -81,15 +81,11 @@ int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index)
return -ENODEV; return -ENODEV;
} }
obj = acpi_evaluate_dsm(port_handle, &guid, 0, obj = acpi_evaluate_dsm_typed(port_handle, &guid, 0,
USB_DSM_DISABLE_U1_U2_FOR_PORT, NULL); USB_DSM_DISABLE_U1_U2_FOR_PORT, NULL,
ACPI_TYPE_INTEGER);
if (!obj) if (!obj) {
return -ENODEV;
if (obj->type != ACPI_TYPE_INTEGER) {
dev_dbg(&hdev->dev, "evaluate port-%d _DSM failed\n", port1); dev_dbg(&hdev->dev, "evaluate port-%d _DSM failed\n", port1);
ACPI_FREE(obj);
return -EINVAL; return -EINVAL;
} }

View File

@ -206,6 +206,82 @@ int usb_find_common_endpoints_reverse(struct usb_host_interface *alt,
} }
EXPORT_SYMBOL_GPL(usb_find_common_endpoints_reverse); 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 * usb_find_alt_setting() - Given a configuration, find the alternate setting
* for the given interface. * for the given interface.

View File

@ -1003,6 +1003,7 @@ struct dwc2_hregs_backup {
* @ctrl_out_desc: EP0 OUT data phase desc chain pointer * @ctrl_out_desc: EP0 OUT data phase desc chain pointer
* @irq: Interrupt request line number * @irq: Interrupt request line number
* @clk: Pointer to otg clock * @clk: Pointer to otg clock
* @utmi_clk: Pointer to utmi_clk clock
* @reset: Pointer to dwc2 reset controller * @reset: Pointer to dwc2 reset controller
* @reset_ecc: Pointer to dwc2 optional reset controller in Stratix10. * @reset_ecc: Pointer to dwc2 optional reset controller in Stratix10.
* @regset: A pointer to a struct debugfs_regset32, which contains * @regset: A pointer to a struct debugfs_regset32, which contains
@ -1065,6 +1066,7 @@ struct dwc2_hsotg {
void *priv; void *priv;
int irq; int irq;
struct clk *clk; struct clk *clk;
struct clk *utmi_clk;
struct reset_control *reset; struct reset_control *reset;
struct reset_control *reset_ecc; struct reset_control *reset_ecc;

View File

@ -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); earliest_frame = dwc2_frame_num_inc(frame_number, 1);
next_active_frame = earliest_frame; 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 (!hsotg->params.uframe_sched) {
if (qh->do_split) if (qh->do_split)
/* Splits are active at microframe 0 minus 1 */ /* Splits are active at microframe 0 minus 1 */

View File

@ -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); 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 = of_property_read_bool(hsotg->dev->of_node, "disable-over-current");
p->oc_disable = true;
} }
static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg) static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg)

View File

@ -101,10 +101,16 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
if (ret) if (ret)
return ret; return ret;
if (hsotg->utmi_clk) {
ret = clk_prepare_enable(hsotg->utmi_clk);
if (ret)
goto err_dis_reg;
}
if (hsotg->clk) { if (hsotg->clk) {
ret = clk_prepare_enable(hsotg->clk); ret = clk_prepare_enable(hsotg->clk);
if (ret) if (ret)
return ret; goto err_dis_utmi_clk;
} }
if (hsotg->uphy) { 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); ret = hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
} else { } else {
ret = phy_init(hsotg->phy); ret = phy_init(hsotg->phy);
if (ret == 0) if (ret == 0) {
ret = phy_power_on(hsotg->phy); 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; return ret;
} }
@ -156,6 +181,9 @@ static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg)
if (hsotg->clk) if (hsotg->clk)
clk_disable_unprepare(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); 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)) if (IS_ERR(hsotg->clk))
return dev_err_probe(hsotg->dev, PTR_ERR(hsotg->clk), "cannot get otg clock\n"); 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 */ /* Regulators */
for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++) for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++)
hsotg->supplies[i].supply = dwc2_hsotg_supply_names[i]; hsotg->supplies[i].supply = dwc2_hsotg_supply_names[i];

View File

@ -534,90 +534,6 @@ void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); 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) static void dwc3_core_num_eps(struct dwc3 *dwc)
{ {
struct dwc3_hwparams *parms = &dwc->hwparams; 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) if (dwc->dis_u2_freeclk_exists_quirk || dwc->gfladj_refclk_lpm_sel)
reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS; 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); dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
return 0; 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) static int dwc3_clk_enable(struct dwc3 *dwc)
{ {
int ret; int ret;
@ -840,17 +836,8 @@ static void dwc3_clk_disable(struct dwc3 *dwc)
static void dwc3_core_exit(struct dwc3 *dwc) static void dwc3_core_exit(struct dwc3 *dwc)
{ {
dwc3_event_buffers_cleanup(dwc); dwc3_event_buffers_cleanup(dwc);
dwc3_phy_power_off(dwc);
usb_phy_set_suspend(dwc->usb2_phy, 1); dwc3_phy_exit(dwc);
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_clk_disable(dwc); dwc3_clk_disable(dwc);
reset_control_assert(dwc->reset); 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) static void dwc3_core_setup_global_control(struct dwc3 *dwc)
{ {
u32 hwparams4 = dwc->hwparams.hwparams4;
u32 reg; u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_GCTL); 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; reg &= ~DWC3_GCTL_DSBLCLKGTNG;
break; break;
case DWC3_GHWPARAMS1_EN_PWROPT_HIB: 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 * REVISIT Enabling this bit so that host-mode hibernation
* will work. Device-mode hibernation is not yet implemented. * 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); ret = dwc3_phy_setup(dwc);
if (ret) if (ret)
goto err0; return ret;
if (!dwc->ulpi_ready) { if (!dwc->ulpi_ready) {
ret = dwc3_core_ulpi_init(dwc); ret = dwc3_core_ulpi_init(dwc);
@ -1105,7 +1088,7 @@ static int dwc3_core_init(struct dwc3 *dwc)
dwc3_core_soft_reset(dwc); dwc3_core_soft_reset(dwc);
ret = -EPROBE_DEFER; ret = -EPROBE_DEFER;
} }
goto err0; return ret;
} }
dwc->ulpi_ready = true; dwc->ulpi_ready = true;
} }
@ -1113,25 +1096,17 @@ static int dwc3_core_init(struct dwc3 *dwc)
if (!dwc->phys_ready) { if (!dwc->phys_ready) {
ret = dwc3_core_get_phy(dwc); ret = dwc3_core_get_phy(dwc);
if (ret) if (ret)
goto err0a; goto err_exit_ulpi;
dwc->phys_ready = true; dwc->phys_ready = true;
} }
usb_phy_init(dwc->usb2_phy); ret = dwc3_phy_init(dwc);
usb_phy_init(dwc->usb3_phy); if (ret)
ret = phy_init(dwc->usb2_generic_phy); goto err_exit_ulpi;
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_core_soft_reset(dwc); ret = dwc3_core_soft_reset(dwc);
if (ret) if (ret)
goto err1; goto err_exit_phy;
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD &&
!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) { !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_setup_global_control(dwc);
dwc3_core_num_eps(dwc); dwc3_core_num_eps(dwc);
ret = dwc3_setup_scratch_buffers(dwc);
if (ret)
goto err1;
/* Set power down scale of suspend_clk */ /* Set power down scale of suspend_clk */
dwc3_set_power_down_clk_scale(dwc); 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); dwc3_set_incr_burst_type(dwc);
usb_phy_set_suspend(dwc->usb2_phy, 0); dwc3_phy_power_on(dwc);
usb_phy_set_suspend(dwc->usb3_phy, 0); if (ret)
ret = phy_power_on(dwc->usb2_generic_phy); goto err_exit_phy;
if (ret < 0)
goto err2;
ret = phy_power_on(dwc->usb3_generic_phy);
if (ret < 0)
goto err3;
ret = dwc3_event_buffers_setup(dwc); ret = dwc3_event_buffers_setup(dwc);
if (ret) { if (ret) {
dev_err(dwc->dev, "failed to setup event buffers\n"); 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) if (dwc->parkmode_disable_ss_quirk)
reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS; 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) && if (DWC3_VER_IS_WITHIN(DWC3, 290A, ANY) &&
(dwc->maximum_speed == USB_SPEED_HIGH || (dwc->maximum_speed == USB_SPEED_HIGH ||
dwc->maximum_speed == USB_SPEED_FULL)) dwc->maximum_speed == USB_SPEED_FULL))
@ -1296,26 +1264,13 @@ static int dwc3_core_init(struct dwc3 *dwc)
return 0; return 0;
err4: err_power_off_phy:
phy_power_off(dwc->usb3_generic_phy); dwc3_phy_power_off(dwc);
err_exit_phy:
err3: dwc3_phy_exit(dwc);
phy_power_off(dwc->usb2_generic_phy); err_exit_ulpi:
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:
dwc3_ulpi_exit(dwc); dwc3_ulpi_exit(dwc);
err0:
return ret; return ret;
} }
@ -1553,8 +1508,12 @@ static void dwc3_get_properties(struct dwc3 *dwc)
"snps,dis-tx-ipgap-linecheck-quirk"); "snps,dis-tx-ipgap-linecheck-quirk");
dwc->resume_hs_terminations = device_property_read_bool(dev, dwc->resume_hs_terminations = device_property_read_bool(dev,
"snps,resume-hs-terminations"); "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, dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev,
"snps,parkmode-disable-ss-quirk"); "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, dwc->gfladj_refclk_lpm_sel = device_property_read_bool(dev,
"snps,gfladj-refclk-lpm-sel-quirk"); "snps,gfladj-refclk-lpm-sel-quirk");
@ -1750,15 +1709,71 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
return edev; 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) static int dwc3_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct resource *res, dwc_res; struct resource *res, dwc_res;
struct dwc3 *dwc;
int ret;
void __iomem *regs; void __iomem *regs;
struct dwc3 *dwc;
int ret;
dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL); dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
if (!dwc) if (!dwc)
@ -1797,77 +1812,25 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->reset = devm_reset_control_array_get_optional_shared(dev); dwc->reset = devm_reset_control_array_get_optional_shared(dev);
if (IS_ERR(dwc->reset)) { if (IS_ERR(dwc->reset)) {
ret = PTR_ERR(dwc->reset); ret = PTR_ERR(dwc->reset);
goto put_usb_psy; goto err_put_psy;
} }
if (dev->of_node) { ret = dwc3_get_clocks(dwc);
/* if (ret)
* Clocks are optional, but new DT platforms should support all goto err_put_psy;
* 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 = reset_control_deassert(dwc->reset); ret = reset_control_deassert(dwc->reset);
if (ret) if (ret)
goto put_usb_psy; goto err_put_psy;
ret = dwc3_clk_enable(dwc); ret = dwc3_clk_enable(dwc);
if (ret) if (ret)
goto assert_reset; goto err_assert_reset;
if (!dwc3_core_is_valid(dwc)) { if (!dwc3_core_is_valid(dwc)) {
dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
ret = -ENODEV; ret = -ENODEV;
goto disable_clks; goto err_disable_clks;
} }
platform_set_drvdata(pdev, dwc); platform_set_drvdata(pdev, dwc);
@ -1877,19 +1840,17 @@ static int dwc3_probe(struct platform_device *pdev)
DWC3_GHWPARAMS0_AWIDTH(dwc->hwparams.hwparams0) == 64) { DWC3_GHWPARAMS0_AWIDTH(dwc->hwparams.hwparams0) == 64) {
ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64)); ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64));
if (ret) if (ret)
goto disable_clks; goto err_disable_clks;
} }
spin_lock_init(&dwc->lock); spin_lock_init(&dwc->lock);
mutex_init(&dwc->mutex); mutex_init(&dwc->mutex);
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev); pm_runtime_set_active(dev);
pm_runtime_use_autosuspend(dev); pm_runtime_use_autosuspend(dev);
pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY); pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY);
pm_runtime_enable(dev); pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev);
if (ret < 0)
goto err1;
pm_runtime_forbid(dev); pm_runtime_forbid(dev);
@ -1897,27 +1858,23 @@ static int dwc3_probe(struct platform_device *pdev)
if (ret) { if (ret) {
dev_err(dwc->dev, "failed to allocate event buffers\n"); dev_err(dwc->dev, "failed to allocate event buffers\n");
ret = -ENOMEM; ret = -ENOMEM;
goto err2; goto err_allow_rpm;
} }
dwc->edev = dwc3_get_extcon(dwc); dwc->edev = dwc3_get_extcon(dwc);
if (IS_ERR(dwc->edev)) { if (IS_ERR(dwc->edev)) {
ret = dev_err_probe(dwc->dev, PTR_ERR(dwc->edev), "failed to get extcon\n"); 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); ret = dwc3_get_dr_mode(dwc);
if (ret) if (ret)
goto err3; goto err_free_event_buffers;
ret = dwc3_alloc_scratch_buffers(dwc);
if (ret)
goto err3;
ret = dwc3_core_init(dwc); ret = dwc3_core_init(dwc);
if (ret) { if (ret) {
dev_err_probe(dev, ret, "failed to initialize core\n"); dev_err_probe(dev, ret, "failed to initialize core\n");
goto err4; goto err_free_event_buffers;
} }
dwc3_check_params(dwc); dwc3_check_params(dwc);
@ -1925,46 +1882,31 @@ static int dwc3_probe(struct platform_device *pdev)
ret = dwc3_core_init_mode(dwc); ret = dwc3_core_init_mode(dwc);
if (ret) if (ret)
goto err5; goto err_exit_debugfs;
pm_runtime_put(dev); pm_runtime_put(dev);
return 0; return 0;
err5: err_exit_debugfs:
dwc3_debugfs_exit(dwc); dwc3_debugfs_exit(dwc);
dwc3_event_buffers_cleanup(dwc); dwc3_event_buffers_cleanup(dwc);
dwc3_phy_power_off(dwc);
usb_phy_set_suspend(dwc->usb2_phy, 1); dwc3_phy_exit(dwc);
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_ulpi_exit(dwc); dwc3_ulpi_exit(dwc);
err_free_event_buffers:
err4:
dwc3_free_scratch_buffers(dwc);
err3:
dwc3_free_event_buffers(dwc); dwc3_free_event_buffers(dwc);
err_allow_rpm:
err2: pm_runtime_allow(dev);
pm_runtime_allow(&pdev->dev); pm_runtime_disable(dev);
pm_runtime_dont_use_autosuspend(dev);
err1: pm_runtime_set_suspended(dev);
pm_runtime_put_sync(&pdev->dev); pm_runtime_put_noidle(dev);
pm_runtime_disable(&pdev->dev); err_disable_clks:
disable_clks:
dwc3_clk_disable(dwc); dwc3_clk_disable(dwc);
assert_reset: err_assert_reset:
reset_control_assert(dwc->reset); reset_control_assert(dwc->reset);
put_usb_psy: err_put_psy:
if (dwc->usb_psy) if (dwc->usb_psy)
power_supply_put(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_core_exit(dwc);
dwc3_ulpi_exit(dwc); dwc3_ulpi_exit(dwc);
pm_runtime_allow(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev); pm_runtime_put_noidle(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev); pm_runtime_set_suspended(&pdev->dev);
dwc3_free_event_buffers(dwc); dwc3_free_event_buffers(dwc);
dwc3_free_scratch_buffers(dwc);
if (dwc->usb_psy) if (dwc->usb_psy)
power_supply_put(dwc->usb_psy); power_supply_put(dwc->usb_psy);

View File

@ -263,6 +263,7 @@
#define DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK BIT(26) #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_DEV_L1_EXIT_BY_HW BIT(24)
#define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT(17) #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) #define DWC3_GUCTL1_RESUME_OPMODE_HS_HOST BIT(10)
/* Global Status Register */ /* Global Status Register */
@ -280,6 +281,7 @@
/* Global USB2 PHY Configuration Register */ /* Global USB2 PHY Configuration Register */
#define DWC3_GUSB2PHYCFG_PHYSOFTRST BIT(31) #define DWC3_GUSB2PHYCFG_PHYSOFTRST BIT(31)
#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS BIT(30) #define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS BIT(30)
#define DWC3_GUSB2PHYCFG_ULPIEXTVBUSDRV BIT(17)
#define DWC3_GUSB2PHYCFG_SUSPHY BIT(6) #define DWC3_GUSB2PHYCFG_SUSPHY BIT(6)
#define DWC3_GUSB2PHYCFG_ULPI_UTMI BIT(4) #define DWC3_GUSB2PHYCFG_ULPI_UTMI BIT(4)
#define DWC3_GUSB2PHYCFG_ENBLSLPM BIT(8) #define DWC3_GUSB2PHYCFG_ENBLSLPM BIT(8)
@ -526,6 +528,7 @@
#define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c #define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c
#define DWC3_DGCMD_SET_ENDPOINT_PRIME 0x0d #define DWC3_DGCMD_SET_ENDPOINT_PRIME 0x0d
#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10 #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_STATUS(n) (((n) >> 12) & 0x0F)
#define DWC3_DGCMD_CMDACT BIT(10) #define DWC3_DGCMD_CMDACT BIT(10)
@ -538,6 +541,8 @@
#define DWC3_DGCMDPAR_TX_FIFO BIT(5) #define DWC3_DGCMDPAR_TX_FIFO BIT(5)
#define DWC3_DGCMDPAR_LOOPBACK_DIS (0 << 0) #define DWC3_DGCMDPAR_LOOPBACK_DIS (0 << 0)
#define DWC3_DGCMDPAR_LOOPBACK_ENA BIT(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 */ /* Device Endpoint Command Register */
#define DWC3_DEPCMD_PARAM_SHIFT 16 #define DWC3_DEPCMD_PARAM_SHIFT 16
@ -969,12 +974,10 @@ struct dwc3_scratchpad_array {
* @drd_work: workqueue used for role swapping * @drd_work: workqueue used for role swapping
* @ep0_trb: trb which is used for the ctrl_req * @ep0_trb: trb which is used for the ctrl_req
* @bounce: address of bounce buffer * @bounce: address of bounce buffer
* @scratchbuf: address of scratch buffer
* @setup_buf: used while precessing STD USB requests * @setup_buf: used while precessing STD USB requests
* @ep0_trb_addr: dma address of @ep0_trb * @ep0_trb_addr: dma address of @ep0_trb
* @bounce_addr: dma address of @bounce * @bounce_addr: dma address of @bounce
* @ep0_usb_req: dummy req used while handling STD USB requests * @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 * @ep0_in_setup: one control transfer is completed and enter setup phase
* @lock: for synchronizing * @lock: for synchronizing
* @mutex: for mode switching * @mutex: for mode switching
@ -999,7 +1002,6 @@ struct dwc3_scratchpad_array {
* @current_otg_role: current role of operation while using the OTG block * @current_otg_role: current role of operation while using the OTG block
* @desired_otg_role: desired 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 * @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 * @u1u2: only used on revisions <1.83a for workaround
* @maximum_speed: maximum speed requested (mainly for testing purposes) * @maximum_speed: maximum speed requested (mainly for testing purposes)
* @max_ssp_rate: SuperSpeed Plus maximum signaling rate and lane count * @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 * @delayed_status: true when gadget driver asks for delayed status
* @ep0_bounced: true when we used bounce buffer * @ep0_bounced: true when we used bounce buffer
* @ep0_expect_in: true when we expect a DATA IN transfer * @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 * @sysdev_is_parent: true when dwc3 device has a parent driver
* @has_lpm_erratum: true when core was configured with LPM Erratum. Note that * @has_lpm_erratum: true when core was configured with LPM Erratum. Note that
* there's now way for software to detect this in runtime. * there's now way for software to detect this in runtime.
@ -1100,8 +1101,12 @@ struct dwc3_scratchpad_array {
* check during HS transmit. * check during HS transmit.
* @resume_hs_terminations: Set if we enable quirk for fixing improper crc * @resume_hs_terminations: Set if we enable quirk for fixing improper crc
* generation after resume from suspend. * 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 * @parkmode_disable_ss_quirk: set if we need to disable all SuperSpeed
* instances in park mode. * 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_quirk: set if we enable Tx de-emphasis quirk
* @tx_de_emphasis: Tx de-emphasis value * @tx_de_emphasis: Tx de-emphasis value
* 0 - -6dB de-emphasis * 0 - -6dB de-emphasis
@ -1110,6 +1115,7 @@ struct dwc3_scratchpad_array {
* 3 - Reserved * 3 - Reserved
* @dis_metastability_quirk: set to disable metastability quirk. * @dis_metastability_quirk: set to disable metastability quirk.
* @dis_split_quirk: set to disable split boundary. * @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 * @imod_interval: set the interrupt moderation interval in 250ns
* increments or 0 to disable. * increments or 0 to disable.
* @max_cfg_eps: current max number of IN eps used across all USB configs. * @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 work_struct drd_work;
struct dwc3_trb *ep0_trb; struct dwc3_trb *ep0_trb;
void *bounce; void *bounce;
void *scratchbuf;
u8 *setup_buf; u8 *setup_buf;
dma_addr_t ep0_trb_addr; dma_addr_t ep0_trb_addr;
dma_addr_t bounce_addr; dma_addr_t bounce_addr;
dma_addr_t scratch_addr;
struct dwc3_request ep0_usb_req; struct dwc3_request ep0_usb_req;
struct completion ep0_in_setup; struct completion ep0_in_setup;
@ -1187,7 +1191,6 @@ struct dwc3 {
u32 current_otg_role; u32 current_otg_role;
u32 desired_otg_role; u32 desired_otg_role;
bool otg_restart_host; bool otg_restart_host;
u32 nr_scratch;
u32 u1u2; u32 u1u2;
u32 maximum_speed; u32 maximum_speed;
u32 gadget_max_speed; u32 gadget_max_speed;
@ -1284,7 +1287,6 @@ struct dwc3 {
unsigned delayed_status:1; unsigned delayed_status:1;
unsigned ep0_bounced:1; unsigned ep0_bounced:1;
unsigned ep0_expect_in:1; unsigned ep0_expect_in:1;
unsigned has_hibernation:1;
unsigned sysdev_is_parent:1; unsigned sysdev_is_parent:1;
unsigned has_lpm_erratum:1; unsigned has_lpm_erratum:1;
unsigned is_utmi_l1_suspend:1; unsigned is_utmi_l1_suspend:1;
@ -1317,7 +1319,9 @@ struct dwc3 {
unsigned dis_del_phy_power_chg_quirk:1; unsigned dis_del_phy_power_chg_quirk:1;
unsigned dis_tx_ipgap_linecheck_quirk:1; unsigned dis_tx_ipgap_linecheck_quirk:1;
unsigned resume_hs_terminations:1; unsigned resume_hs_terminations:1;
unsigned ulpi_ext_vbus_drv:1;
unsigned parkmode_disable_ss_quirk:1; unsigned parkmode_disable_ss_quirk:1;
unsigned parkmode_disable_hs_quirk:1;
unsigned gfladj_refclk_lpm_sel:1; unsigned gfladj_refclk_lpm_sel:1;
unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis_quirk:1;
@ -1327,6 +1331,7 @@ struct dwc3 {
unsigned dis_split_quirk:1; unsigned dis_split_quirk:1;
unsigned async_callbacks:1; unsigned async_callbacks:1;
unsigned wakeup_configured:1;
u16 imod_interval; u16 imod_interval;

View File

@ -72,6 +72,8 @@ dwc3_gadget_generic_cmd_string(u8 cmd)
return "Set Endpoint Prime"; return "Set Endpoint Prime";
case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK: case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK:
return "Run SoC Bus Loopback Test"; return "Run SoC Bus Loopback Test";
case DWC3_DGCMD_DEV_NOTIFICATION:
return "Device Notification";
default: default:
return "UNKNOWN"; return "UNKNOWN";
} }

View File

@ -88,6 +88,9 @@ static const struct debugfs_reg32 dwc3_regs[] = {
dump_register(GPRTBIMAP_HS1), dump_register(GPRTBIMAP_HS1),
dump_register(GPRTBIMAP_FS0), dump_register(GPRTBIMAP_FS0),
dump_register(GPRTBIMAP_FS1), dump_register(GPRTBIMAP_FS1),
dump_register(GUCTL2),
dump_register(VER_NUMBER),
dump_register(VER_TYPE),
dump_register(GUSB2PHYCFG(0)), dump_register(GUSB2PHYCFG(0)),
dump_register(GUSB2PHYCFG(1)), dump_register(GUSB2PHYCFG(1)),
@ -229,6 +232,8 @@ static const struct debugfs_reg32 dwc3_regs[] = {
dump_register(GEVNTCOUNT(0)), dump_register(GEVNTCOUNT(0)),
dump_register(GHWPARAMS8), dump_register(GHWPARAMS8),
dump_register(GUCTL3),
dump_register(GFLADJ),
dump_register(DCFG), dump_register(DCFG),
dump_register(DCTL), dump_register(DCTL),
dump_register(DEVTEN), dump_register(DEVTEN),

View File

@ -11,12 +11,14 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_platform.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include "core.h"
/* USB WRAPPER register offsets */ /* USB WRAPPER register offsets */
#define USBSS_PID 0x0 #define USBSS_PID 0x0
#define USBSS_OVERCURRENT_CTRL 0x4 #define USBSS_OVERCURRENT_CTRL 0x4
@ -45,6 +47,10 @@
#define USBSS_PHY_VBUS_SEL_SHIFT 1 #define USBSS_PHY_VBUS_SEL_SHIFT 1
#define USBSS_PHY_LANE_REVERSE BIT(0) #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 */ /* MODE CONTROL register bits */
#define USBSS_MODE_VALID BIT(0) #define USBSS_MODE_VALID BIT(0)
@ -54,6 +60,13 @@
#define USBSS_WAKEUP_CFG_SESSVALID_EN BIT(1) #define USBSS_WAKEUP_CFG_SESSVALID_EN BIT(1)
#define USBSS_WAKEUP_CFG_VBUSVALID_EN BIT(0) #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 */ /* WAKEUP STAT register bits */
#define USBSS_WAKEUP_STAT_OVERCURRENT BIT(4) #define USBSS_WAKEUP_STAT_OVERCURRENT BIT(4)
#define USBSS_WAKEUP_STAT_LINESTATE BIT(3) #define USBSS_WAKEUP_STAT_LINESTATE BIT(3)
@ -97,6 +110,7 @@ struct dwc3_data {
struct regmap *syscon; struct regmap *syscon;
unsigned int offset; unsigned int offset;
unsigned int vbus_divider; unsigned int vbus_divider;
u32 wakeup_stat;
}; };
static const int dwc3_ti_rate_table[] = { /* in KHZ */ 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; reg |= USBSS_MODE_VALID;
dwc3_ti_writel(data, USBSS_MODE_CONTROL, reg); 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 */ /* Setting up autosuspend */
pm_runtime_set_autosuspend_delay(dev, DWC3_AM62_AUTOSUSPEND_DELAY); pm_runtime_set_autosuspend_delay(dev, DWC3_AM62_AUTOSUSPEND_DELAY);
pm_runtime_use_autosuspend(dev); 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) static int dwc3_ti_suspend_common(struct device *dev)
{ {
struct dwc3_data *data = dev_get_drvdata(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); 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) static int dwc3_ti_resume_common(struct device *dev)
{ {
struct dwc3_data *data = dev_get_drvdata(dev); struct dwc3_data *data = dev_get_drvdata(dev);
u32 reg;
clk_prepare_enable(data->usb2_refclk); 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; return 0;
} }

View File

@ -388,107 +388,41 @@ static void dwc3_pci_remove(struct pci_dev *pci)
} }
static const struct pci_device_id dwc3_pci_id_table[] = { static const struct pci_device_id dwc3_pci_id_table[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BSW), { PCI_DEVICE_DATA(INTEL, BSW, &dwc3_pci_intel_swnode) },
(kernel_ulong_t) &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), { PCI_DEVICE_DATA(AMD, NL_USB, &dwc3_pci_amd_swnode) },
(kernel_ulong_t) &dwc3_pci_intel_byt_swnode, }, { PCI_DEVICE_DATA(AMD, MR, &dwc3_pci_amd_mr_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, },
{ } /* Terminating Entry */ { } /* Terminating Entry */
}; };

View File

@ -30,6 +30,8 @@
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep); static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep);
static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
struct dwc3_ep *dep, struct dwc3_request *req); 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, static void dwc3_ep0_prepare_one_trb(struct dwc3_ep *dep,
dma_addr_t buf_dma, u32 len, u32 type, bool chain) 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; usb_status |= 1 << USB_DEV_STAT_U1_ENABLED;
if (reg & DWC3_DCTL_INITU2ENA) if (reg & DWC3_DCTL_INITU2ENA)
usb_status |= 1 << USB_DEV_STAT_U2_ENABLED; usb_status |= 1 << USB_DEV_STAT_U2_ENABLED;
} else {
usb_status |= dwc->gadget->wakeup_armed <<
USB_DEVICE_REMOTE_WAKEUP;
} }
break; break;
@ -365,7 +370,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
* Function Remote Wake Capable D0 * Function Remote Wake Capable D0
* Function Remote Wakeup D1 * Function Remote Wakeup D1
*/ */
break; return dwc3_ep0_delegate_req(dwc, ctrl);
case USB_RECIP_ENDPOINT: case USB_RECIP_ENDPOINT:
dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex); dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
@ -476,6 +481,10 @@ static int dwc3_ep0_handle_device(struct dwc3 *dwc,
switch (wValue) { switch (wValue) {
case USB_DEVICE_REMOTE_WAKEUP: case USB_DEVICE_REMOTE_WAKEUP:
if (dwc->wakeup_configured)
dwc->gadget->wakeup_armed = set;
else
ret = -EINVAL;
break; break;
/* /*
* 9.4.1 says only for SS, in AddressState only for * 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) { switch (wValue) {
case USB_INTRF_FUNC_SUSPEND: case USB_INTRF_FUNC_SUSPEND:
/* ret = dwc3_ep0_delegate_req(dwc, ctrl);
* 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.
*/
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;

View File

@ -139,6 +139,24 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
return -ETIMEDOUT; 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. * dwc3_ep_inc_trb - increment a trb index.
* @index: Pointer to the TRB index to increment. * @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; 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 * 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; fallthrough;
case DWC3_LINK_STATE_U3: 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", dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n",
ret); ret);
break; 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) static int dwc3_gadget_get_frame(struct usb_gadget *g)
{ {
struct dwc3 *dwc = gadget_to_dwc(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); 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; int retries;
@ -2311,9 +2345,13 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
return -EINVAL; return -EINVAL;
} }
if (async)
dwc3_gadget_enable_linksts_evts(dwc, true);
ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV); ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV);
if (ret < 0) { if (ret < 0) {
dev_err(dwc->dev, "failed to put link in Recovery\n"); dev_err(dwc->dev, "failed to put link in Recovery\n");
dwc3_gadget_enable_linksts_evts(dwc, false);
return ret; return ret;
} }
@ -2325,6 +2363,13 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_DCTL, reg); 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 */ /* poll until Link State changes to ON */
retries = 20000; retries = 20000;
@ -2350,13 +2395,77 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
unsigned long flags; unsigned long flags;
int ret; int ret;
if (!dwc->wakeup_configured) {
dev_err(dwc->dev, "remote wakeup not configured\n");
return -EINVAL;
}
spin_lock_irqsave(&dwc->lock, flags); 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); spin_unlock_irqrestore(&dwc->lock, flags);
return ret; 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, static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
int is_selfpowered) int is_selfpowered)
{ {
@ -2478,7 +2587,7 @@ static void __dwc3_gadget_set_speed(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_DCFG, reg); 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 reg;
u32 timeout = 2000; 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_KEEP_CONNECT;
reg |= DWC3_DCTL_RUN_STOP; reg |= DWC3_DCTL_RUN_STOP;
if (dwc->has_hibernation)
reg |= DWC3_DCTL_KEEP_CONNECT;
__dwc3_gadget_set_speed(dwc); __dwc3_gadget_set_speed(dwc);
dwc->pullups_connected = true; dwc->pullups_connected = true;
} else { } else {
reg &= ~DWC3_DCTL_RUN_STOP; reg &= ~DWC3_DCTL_RUN_STOP;
if (dwc->has_hibernation && !suspend)
reg &= ~DWC3_DCTL_KEEP_CONNECT;
dwc->pullups_connected = false; 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) static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc)
{ {
unsigned long flags; unsigned long flags;
int ret;
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
dwc->connected = false; dwc->connected = false;
/* /*
* Per databook, when we want to stop the gadget, if a control transfer * Attempt to end pending SETUP status phase, and not wait for the
* is still in process, complete it and get the core into setup phase. * function to do so.
*/ */
if (dwc->ep0state != EP0_SETUP_PHASE) { if (dwc->delayed_status)
int ret; dwc3_ep0_send_delayed_status(dwc);
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");
}
/* /*
* In the Synopsys DesignWare Cores USB3 Databook Rev. 3.30a * In the Synopsys DesignWare Cores USB3 Databook Rev. 3.30a
@ -2564,9 +2655,28 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc)
* bit. * bit.
*/ */
dwc3_stop_active_transfers(dwc); dwc3_stop_active_transfers(dwc);
__dwc3_gadget_stop(dwc);
spin_unlock_irqrestore(&dwc->lock, flags); 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 * Note: if the GEVNTCOUNT indicates events in the event buffer, the
* driver needs to acknowledge them before the controller can halt. * 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 * remaining event generated by the controller while polling for
* DSTS.DEVCTLHLT. * 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) 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_event_buffers_setup(dwc);
__dwc3_gadget_start(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); 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 = { static const struct usb_gadget_ops dwc3_gadget_ops = {
.get_frame = dwc3_gadget_get_frame, .get_frame = dwc3_gadget_get_frame,
.wakeup = dwc3_gadget_wakeup, .wakeup = dwc3_gadget_wakeup,
.func_wakeup = dwc3_gadget_func_wakeup,
.set_remote_wakeup = dwc3_gadget_set_remote_wakeup,
.set_selfpowered = dwc3_gadget_set_selfpowered, .set_selfpowered = dwc3_gadget_set_selfpowered,
.pullup = dwc3_gadget_pullup, .pullup = dwc3_gadget_pullup,
.udc_start = dwc3_gadget_start, .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->gadget->speed = USB_SPEED_UNKNOWN;
dwc->setup_packet_pending = false; 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); usb_gadget_set_state(dwc->gadget, USB_STATE_NOTATTACHED);
if (dwc->ep0state != EP0_SETUP_PHASE) { dwc3_ep0_reset_state(dwc);
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);
}
} }
static void dwc3_gadget_reset_interrupt(struct dwc3 *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 * phase. So ensure that EP0 is in setup phase by issuing a stall
* and restart if EP0 is not in setup phase. * and restart if EP0 is not in setup phase.
*/ */
if (dwc->ep0state != EP0_SETUP_PHASE) { dwc3_ep0_reset_state(dwc);
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);
}
/* /*
* In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a * 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; reg &= ~DWC3_DCTL_TSTCTRL_MASK;
dwc3_gadget_dctl_write_safe(dwc, reg); dwc3_gadget_dctl_write_safe(dwc, reg);
dwc->test_mode = false; dwc->test_mode = false;
dwc->gadget->wakeup_armed = false;
dwc3_gadget_enable_linksts_evts(dwc, false);
dwc3_clear_stall_all_ep(dwc); dwc3_clear_stall_all_ep(dwc);
/* Reset device address to zero */ /* 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 * 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); dwc->gadget_driver->resume(dwc->gadget);
spin_lock(&dwc->lock); spin_lock(&dwc->lock);
} }
dwc->link_state = evtinfo & DWC3_LINK_STATE_MASK;
} }
static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, 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) { 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: case DWC3_LINK_STATE_U1:
if (dwc->speed == USB_SPEED_SUPER) if (dwc->speed == USB_SPEED_SUPER)
dwc3_suspend_gadget(dwc); dwc3_suspend_gadget(dwc);
@ -4195,30 +4309,6 @@ static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc,
dwc->link_state = next; 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, static void dwc3_gadget_interrupt(struct dwc3 *dwc,
const struct dwc3_event_devt *event) const struct dwc3_event_devt *event)
{ {
@ -4233,29 +4323,18 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
dwc3_gadget_conndone_interrupt(dwc); dwc3_gadget_conndone_interrupt(dwc);
break; break;
case DWC3_DEVICE_EVENT_WAKEUP: case DWC3_DEVICE_EVENT_WAKEUP:
dwc3_gadget_wakeup_interrupt(dwc); dwc3_gadget_wakeup_interrupt(dwc, event->event_info);
break; break;
case DWC3_DEVICE_EVENT_HIBER_REQ: case DWC3_DEVICE_EVENT_HIBER_REQ:
if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation, dev_WARN_ONCE(dwc->dev, true, "unexpected hibernation event\n");
"unexpected hibernation event\n"))
break;
dwc3_gadget_hibernation_interrupt(dwc, event->event_info);
break; break;
case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE: case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
dwc3_gadget_linksts_change_interrupt(dwc, event->event_info); dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
break; break;
case DWC3_DEVICE_EVENT_SUSPEND: case DWC3_DEVICE_EVENT_SUSPEND:
/* It changed to be suspend event for version 2.30a and above */ /* It changed to be suspend event for version 2.30a and above */
if (!DWC3_VER_IS_PRIOR(DWC3, 230A)) { if (!DWC3_VER_IS_PRIOR(DWC3, 230A))
/* dwc3_gadget_suspend_interrupt(dwc, event->event_info);
* 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);
}
break; break;
case DWC3_DEVICE_EVENT_SOF: case DWC3_DEVICE_EVENT_SOF:
case DWC3_DEVICE_EVENT_ERRATIC_ERROR: case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
@ -4417,11 +4496,6 @@ static int dwc3_gadget_get_irq(struct dwc3 *dwc)
goto out; goto out;
irq = platform_get_irq(dwc3_pdev, 0); irq = platform_get_irq(dwc3_pdev, 0);
if (irq > 0)
goto out;
if (!irq)
irq = -EINVAL;
out: out:
return irq; return irq;
@ -4493,6 +4567,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
dwc->gadget->sg_supported = true; dwc->gadget->sg_supported = true;
dwc->gadget->name = "dwc3-gadget"; dwc->gadget->name = "dwc3-gadget";
dwc->gadget->lpm_capable = !dwc->usb2_gadget_lpm_disable; 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 * 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) if (!dwc->gadget_driver)
return 0; return 0;
dwc3_gadget_run_stop(dwc, false, false); dwc3_gadget_run_stop(dwc, false);
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
dwc3_disconnect_gadget(dwc); dwc3_disconnect_gadget(dwc);
@ -4605,7 +4680,7 @@ int dwc3_gadget_resume(struct dwc3 *dwc)
if (ret < 0) if (ret < 0)
goto err0; goto err0;
ret = dwc3_gadget_run_stop(dwc, true, false); ret = dwc3_gadget_run_stop(dwc, true);
if (ret < 0) if (ret < 0)
goto err1; goto err1;

View File

@ -52,13 +52,8 @@ static int dwc3_host_get_irq(struct dwc3 *dwc)
goto out; goto out;
irq = platform_get_irq(dwc3_pdev, 0); irq = platform_get_irq(dwc3_pdev, 0);
if (irq > 0) { if (irq > 0)
dwc3_host_fill_xhci_irq_res(dwc, irq, NULL); dwc3_host_fill_xhci_irq_res(dwc, irq, NULL);
goto out;
}
if (!irq)
irq = -EINVAL;
out: out:
return irq; return irq;

View File

@ -54,14 +54,13 @@ DECLARE_EVENT_CLASS(dwc3_log_event,
TP_STRUCT__entry( TP_STRUCT__entry(
__field(u32, event) __field(u32, event)
__field(u32, ep0state) __field(u32, ep0state)
__dynamic_array(char, str, DWC3_MSG_MAX)
), ),
TP_fast_assign( TP_fast_assign(
__entry->event = event; __entry->event = event;
__entry->ep0state = dwc->ep0state; __entry->ep0state = dwc->ep0state;
), ),
TP_printk("event (%08x): %s", __entry->event, 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)) __entry->event, __entry->ep0state))
); );
@ -79,7 +78,6 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl,
__field(__u16, wValue) __field(__u16, wValue)
__field(__u16, wIndex) __field(__u16, wIndex)
__field(__u16, wLength) __field(__u16, wLength)
__dynamic_array(char, str, DWC3_MSG_MAX)
), ),
TP_fast_assign( TP_fast_assign(
__entry->bRequestType = ctrl->bRequestType; __entry->bRequestType = ctrl->bRequestType;
@ -88,7 +86,7 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl,
__entry->wIndex = le16_to_cpu(ctrl->wIndex); __entry->wIndex = le16_to_cpu(ctrl->wIndex);
__entry->wLength = le16_to_cpu(ctrl->wLength); __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->bRequestType,
__entry->bRequest, __entry->wValue, __entry->bRequest, __entry->wValue,
__entry->wIndex, __entry->wLength) __entry->wIndex, __entry->wLength)

View File

@ -492,6 +492,46 @@ int usb_interface_id(struct usb_configuration *config,
} }
EXPORT_SYMBOL_GPL(usb_interface_id); 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, static u8 encode_bMaxPower(enum usb_device_speed speed,
struct usb_configuration *c) struct usb_configuration *c)
{ {
@ -513,6 +553,19 @@ static u8 encode_bMaxPower(enum usb_device_speed speed,
return min(val, 900U) / 8; 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, static int config_buf(struct usb_configuration *config,
enum usb_device_speed speed, void *buf, u8 type) 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) if (f->disable)
f->disable(f); 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); bitmap_zero(f->endpoints, 32);
} }
cdev->config = NULL; cdev->config = NULL;
@ -994,6 +1050,11 @@ static int set_config(struct usb_composite_dev *cdev,
power = min(power, 500U); power = min(power, 500U);
else else
power = min(power, 900U); 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: done:
if (power <= USB_SELF_POWER_VBUS_MAX_DRAW) if (power <= USB_SELF_POWER_VBUS_MAX_DRAW)
usb_gadget_set_selfpowered(gadget); 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]; f = cdev->config->interface[intf];
if (!f) if (!f)
break; break;
status = f->get_status ? f->get_status(f) : 0;
if (status < 0) if (f->get_status) {
break; 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); put_unaligned_le16(status & 0x0000ffff, req->buf);
break; break;
/* /*
@ -1972,8 +2044,44 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
if (!f) if (!f)
break; break;
value = 0; value = 0;
if (f->func_suspend) if (f->func_suspend) {
value = f->func_suspend(f, w_index >> 8); 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) { if (value < 0) {
ERROR(cdev, ERROR(cdev,
"func_suspend() returned error %d\n", "func_suspend() returned error %d\n",
@ -2515,7 +2623,12 @@ void composite_resume(struct usb_gadget *gadget)
cdev->driver->resume(cdev); cdev->driver->resume(cdev);
if (cdev->config) { if (cdev->config) {
list_for_each_entry(f, &cdev->config->functions, list) { 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); f->resume(f);
} }
@ -2530,6 +2643,10 @@ void composite_resume(struct usb_gadget *gadget)
usb_gadget_clear_selfpowered(gadget); usb_gadget_clear_selfpowered(gadget);
usb_gadget_vbus_draw(gadget, maxpower); 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; cdev->suspended = 0;

View File

@ -1761,6 +1761,9 @@ static int configfs_composite_bind(struct usb_gadget *gadget,
if (gadget_is_otg(gadget)) if (gadget_is_otg(gadget))
c->descriptors = otg_desc; 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); cfg = container_of(c, struct config_usb_cfg, c);
if (!list_empty(&cfg->string_list)) { if (!list_empty(&cfg->string_list)) {
i = 0; i = 0;

View File

@ -885,6 +885,26 @@ static struct usb_function_instance *ecm_alloc_inst(void)
return &opts->func_inst; 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) static void ecm_free(struct usb_function *f)
{ {
struct f_ecm *ecm; 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.setup = ecm_setup;
ecm->port.func.disable = ecm_disable; ecm->port.func.disable = ecm_disable;
ecm->port.func.free_func = ecm_free; ecm->port.func.free_func = ecm_free;
ecm->port.func.suspend = ecm_suspend;
ecm->port.func.resume = ecm_resume;
return &ecm->port.func; return &ecm->port.func;
} }

View File

@ -335,8 +335,6 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
ssize_t ret; ssize_t ret;
char *data; char *data;
ENTER();
/* Fast check if setup was canceled */ /* Fast check if setup was canceled */
if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
return -EIDRM; return -EIDRM;
@ -512,8 +510,6 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
size_t n; size_t n;
int ret; int ret;
ENTER();
/* Fast check if setup was canceled */ /* Fast check if setup was canceled */
if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
return -EIDRM; return -EIDRM;
@ -612,8 +608,6 @@ static int ffs_ep0_open(struct inode *inode, struct file *file)
{ {
struct ffs_data *ffs = inode->i_private; struct ffs_data *ffs = inode->i_private;
ENTER();
if (ffs->state == FFS_CLOSING) if (ffs->state == FFS_CLOSING)
return -EBUSY; return -EBUSY;
@ -627,8 +621,6 @@ static int ffs_ep0_release(struct inode *inode, struct file *file)
{ {
struct ffs_data *ffs = file->private_data; struct ffs_data *ffs = file->private_data;
ENTER();
ffs_data_closed(ffs); ffs_data_closed(ffs);
return 0; 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; struct usb_gadget *gadget = ffs->gadget;
long ret; long ret;
ENTER();
if (code == FUNCTIONFS_INTERFACE_REVMAP) { if (code == FUNCTIONFS_INTERFACE_REVMAP) {
struct ffs_function *func = ffs->func; struct ffs_function *func = ffs->func;
ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV; 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; struct ffs_io_data *io_data = req->context;
ENTER();
if (req->status) if (req->status)
io_data->status = req->status; io_data->status = req->status;
else 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_io_data *io_data = req->context;
struct ffs_data *ffs = io_data->ffs; struct ffs_data *ffs = io_data->ffs;
ENTER();
io_data->status = req->status ? req->status : req->actual; io_data->status = req->status ? req->status : req->actual;
usb_ep_free_request(_ep, req); 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; struct ffs_epfile *epfile = inode->i_private;
ENTER();
if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
return -ENODEV; return -ENODEV;
@ -1179,8 +1164,6 @@ static int ffs_aio_cancel(struct kiocb *kiocb)
unsigned long flags; unsigned long flags;
int value; int value;
ENTER();
spin_lock_irqsave(&epfile->ffs->eps_lock, flags); spin_lock_irqsave(&epfile->ffs->eps_lock, flags);
if (io_data && io_data->ep && io_data->req) 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; struct ffs_io_data io_data, *p = &io_data;
ssize_t res; ssize_t res;
ENTER();
if (!is_sync_kiocb(kiocb)) { if (!is_sync_kiocb(kiocb)) {
p = kzalloc(sizeof(io_data), GFP_KERNEL); p = kzalloc(sizeof(io_data), GFP_KERNEL);
if (!p) 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; struct ffs_io_data io_data, *p = &io_data;
ssize_t res; ssize_t res;
ENTER();
if (!is_sync_kiocb(kiocb)) { if (!is_sync_kiocb(kiocb)) {
p = kzalloc(sizeof(io_data), GFP_KERNEL); p = kzalloc(sizeof(io_data), GFP_KERNEL);
if (!p) if (!p)
@ -1284,8 +1263,6 @@ ffs_epfile_release(struct inode *inode, struct file *file)
{ {
struct ffs_epfile *epfile = inode->i_private; struct ffs_epfile *epfile = inode->i_private;
ENTER();
__ffs_epfile_read_buffer_free(epfile); __ffs_epfile_read_buffer_free(epfile);
ffs_data_closed(epfile->ffs); ffs_data_closed(epfile->ffs);
@ -1299,8 +1276,6 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code,
struct ffs_ep *ep; struct ffs_ep *ep;
int ret; int ret;
ENTER();
if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
return -ENODEV; return -ENODEV;
@ -1399,8 +1374,6 @@ ffs_sb_make_inode(struct super_block *sb, void *data,
{ {
struct inode *inode; struct inode *inode;
ENTER();
inode = new_inode(sb); inode = new_inode(sb);
if (inode) { if (inode) {
@ -1432,8 +1405,6 @@ static struct dentry *ffs_sb_create_file(struct super_block *sb,
struct dentry *dentry; struct dentry *dentry;
struct inode *inode; struct inode *inode;
ENTER();
dentry = d_alloc_name(sb->s_root, name); dentry = d_alloc_name(sb->s_root, name);
if (!dentry) if (!dentry)
return NULL; return NULL;
@ -1468,8 +1439,6 @@ static int ffs_sb_fill(struct super_block *sb, struct fs_context *fc)
struct inode *inode; struct inode *inode;
struct ffs_data *ffs = data->ffs_data; struct ffs_data *ffs = data->ffs_data;
ENTER();
ffs->sb = sb; ffs->sb = sb;
data->ffs_data = NULL; data->ffs_data = NULL;
sb->s_fs_info = ffs; 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; struct fs_parse_result result;
int opt; int opt;
ENTER();
opt = fs_parse(fc, ffs_fs_fs_parameters, param, &result); opt = fs_parse(fc, ffs_fs_fs_parameters, param, &result);
if (opt < 0) if (opt < 0)
return opt; return opt;
@ -1572,8 +1539,6 @@ static int ffs_fs_get_tree(struct fs_context *fc)
struct ffs_data *ffs; struct ffs_data *ffs;
int ret; int ret;
ENTER();
if (!fc->source) if (!fc->source)
return invalf(fc, "No source specified"); return invalf(fc, "No source specified");
@ -1640,8 +1605,6 @@ static int ffs_fs_init_fs_context(struct fs_context *fc)
static void static void
ffs_fs_kill_sb(struct super_block *sb) ffs_fs_kill_sb(struct super_block *sb)
{ {
ENTER();
kill_litter_super(sb); kill_litter_super(sb);
if (sb->s_fs_info) if (sb->s_fs_info)
ffs_data_closed(sb->s_fs_info); ffs_data_closed(sb->s_fs_info);
@ -1663,8 +1626,6 @@ static int functionfs_init(void)
{ {
int ret; int ret;
ENTER();
ret = register_filesystem(&ffs_fs_type); ret = register_filesystem(&ffs_fs_type);
if (!ret) if (!ret)
pr_info("file system registered\n"); pr_info("file system registered\n");
@ -1676,8 +1637,6 @@ static int functionfs_init(void)
static void functionfs_cleanup(void) static void functionfs_cleanup(void)
{ {
ENTER();
pr_info("unloading\n"); pr_info("unloading\n");
unregister_filesystem(&ffs_fs_type); 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) static void ffs_data_get(struct ffs_data *ffs)
{ {
ENTER();
refcount_inc(&ffs->ref); refcount_inc(&ffs->ref);
} }
static void ffs_data_opened(struct ffs_data *ffs) static void ffs_data_opened(struct ffs_data *ffs)
{ {
ENTER();
refcount_inc(&ffs->ref); refcount_inc(&ffs->ref);
if (atomic_add_return(1, &ffs->opened) == 1 && if (atomic_add_return(1, &ffs->opened) == 1 &&
ffs->state == FFS_DEACTIVATED) { 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) static void ffs_data_put(struct ffs_data *ffs)
{ {
ENTER();
if (refcount_dec_and_test(&ffs->ref)) { if (refcount_dec_and_test(&ffs->ref)) {
pr_info("%s(): freeing\n", __func__); pr_info("%s(): freeing\n", __func__);
ffs_data_clear(ffs); ffs_data_clear(ffs);
@ -1729,8 +1682,6 @@ static void ffs_data_closed(struct ffs_data *ffs)
struct ffs_epfile *epfiles; struct ffs_epfile *epfiles;
unsigned long flags; unsigned long flags;
ENTER();
if (atomic_dec_and_test(&ffs->opened)) { if (atomic_dec_and_test(&ffs->opened)) {
if (ffs->no_disconnect) { if (ffs->no_disconnect) {
ffs->state = FFS_DEACTIVATED; ffs->state = FFS_DEACTIVATED;
@ -1765,8 +1716,6 @@ static struct ffs_data *ffs_data_new(const char *dev_name)
if (!ffs) if (!ffs)
return NULL; return NULL;
ENTER();
ffs->io_completion_wq = alloc_ordered_workqueue("%s", 0, dev_name); ffs->io_completion_wq = alloc_ordered_workqueue("%s", 0, dev_name);
if (!ffs->io_completion_wq) { if (!ffs->io_completion_wq) {
kfree(ffs); kfree(ffs);
@ -1793,8 +1742,6 @@ static void ffs_data_clear(struct ffs_data *ffs)
struct ffs_epfile *epfiles; struct ffs_epfile *epfiles;
unsigned long flags; unsigned long flags;
ENTER();
ffs_closed(ffs); ffs_closed(ffs);
BUG_ON(ffs->gadget); 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) static void ffs_data_reset(struct ffs_data *ffs)
{ {
ENTER();
ffs_data_clear(ffs); ffs_data_clear(ffs);
ffs->raw_descs_data = NULL; 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; struct usb_gadget_strings **lang;
int first_id; int first_id;
ENTER();
if (WARN_ON(ffs->state != FFS_ACTIVE if (WARN_ON(ffs->state != FFS_ACTIVE
|| test_and_set_bit(FFS_FL_BOUND, &ffs->flags))) || test_and_set_bit(FFS_FL_BOUND, &ffs->flags)))
return -EBADFD; 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) static void functionfs_unbind(struct ffs_data *ffs)
{ {
ENTER();
if (!WARN_ON(!ffs->gadget)) { if (!WARN_ON(!ffs->gadget)) {
/* dequeue before freeing ep0req */ /* dequeue before freeing ep0req */
usb_ep_dequeue(ffs->gadget->ep0, ffs->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; struct ffs_epfile *epfile, *epfiles;
unsigned i, count; unsigned i, count;
ENTER();
count = ffs->eps_count; count = ffs->eps_count;
epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL); epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL);
if (!epfiles) if (!epfiles)
@ -1946,8 +1885,6 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
{ {
struct ffs_epfile *epfile = epfiles; struct ffs_epfile *epfile = epfiles;
ENTER();
for (; count; --count, ++epfile) { for (; count; --count, ++epfile) {
BUG_ON(mutex_is_locked(&epfile->mutex)); BUG_ON(mutex_is_locked(&epfile->mutex));
if (epfile->dentry) { if (epfile->dentry) {
@ -2064,8 +2001,6 @@ static int __must_check ffs_do_single_desc(char *data, unsigned len,
u8 length; u8 length;
int ret; int ret;
ENTER();
/* At least two bytes are required: length and type */ /* At least two bytes are required: length and type */
if (len < 2) { if (len < 2) {
pr_vdebug("descriptor too short\n"); 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; unsigned long num = 0;
int current_class = -1; int current_class = -1;
ENTER();
for (;;) { for (;;) {
int ret; int ret;
@ -2243,8 +2176,6 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
struct ffs_desc_helper *helper = priv; struct ffs_desc_helper *helper = priv;
struct usb_endpoint_descriptor *d; struct usb_endpoint_descriptor *d;
ENTER();
switch (type) { switch (type) {
case FFS_DESCRIPTOR: case FFS_DESCRIPTOR:
break; 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 bcd_version = le16_to_cpu(desc->bcdVersion);
u16 w_index = le16_to_cpu(desc->wIndex); u16 w_index = le16_to_cpu(desc->wIndex);
if (bcd_version != 1) { if (bcd_version == 0x1) {
pr_vdebug("unsupported os descriptors version: %d", 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); bcd_version);
return -EINVAL; return -EINVAL;
} }
@ -2326,8 +2260,6 @@ static int __must_check ffs_do_single_os_desc(char *data, unsigned len,
int ret; int ret;
const unsigned _len = len; const unsigned _len = len;
ENTER();
/* loop over all ext compat/ext prop descriptors */ /* loop over all ext compat/ext prop descriptors */
while (feature_count--) { while (feature_count--) {
ret = entity(type, h, data, len, priv); 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; const unsigned _len = len;
unsigned long num = 0; unsigned long num = 0;
ENTER();
for (num = 0; num < count; ++num) { for (num = 0; num < count; ++num) {
int ret; int ret;
enum ffs_os_desc_type type; 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; struct ffs_data *ffs = priv;
u8 length; u8 length;
ENTER();
switch (type) { switch (type) {
case FFS_OS_DESC_EXT_COMPAT: { case FFS_OS_DESC_EXT_COMPAT: {
struct usb_ext_compat_desc *d = data; 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; int ret = -EINVAL, i;
struct ffs_desc_helper helper; struct ffs_desc_helper helper;
ENTER();
if (get_unaligned_le32(data + 4) != len) if (get_unaligned_le32(data + 4) != len)
goto error; goto error;
@ -2622,8 +2548,6 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
const char *data = _data; const char *data = _data;
struct usb_string *s; struct usb_string *s;
ENTER();
if (len < 16 || if (len < 16 ||
get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC || get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
get_unaligned_le32(data + 4) != len) 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; struct ffs_data *ffs_data;
int ret; int ret;
ENTER();
/* /*
* Legacy gadget triggers binding in functionfs_ready_callback, * Legacy gadget triggers binding in functionfs_ready_callback,
* which already uses locking; taking the same lock here would * 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); vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length);
char *vlabuf; char *vlabuf;
ENTER();
/* Has descriptors only for speeds gadget does not support */ /* Has descriptors only for speeds gadget does not support */
if (!(full | high | super)) if (!(full | high | super))
return -ENOTSUPP; return -ENOTSUPP;
@ -3365,8 +3285,6 @@ static int ffs_func_setup(struct usb_function *f,
unsigned long flags; unsigned long flags;
int ret; int ret;
ENTER();
pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType); pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType);
pr_vdebug("creq->bRequest = %02x\n", creq->bRequest); pr_vdebug("creq->bRequest = %02x\n", creq->bRequest);
pr_vdebug("creq->wValue = %04x\n", le16_to_cpu(creq->wValue)); 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) static void ffs_func_suspend(struct usb_function *f)
{ {
ENTER();
ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND); ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND);
} }
static void ffs_func_resume(struct usb_function *f) static void ffs_func_resume(struct usb_function *f)
{ {
ENTER();
ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME); 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 count = ffs->eps_count;
unsigned long flags; unsigned long flags;
ENTER();
if (ffs->func == func) { if (ffs->func == func) {
ffs_func_eps_disable(func); ffs_func_eps_disable(func);
ffs->func = NULL; ffs->func = NULL;
@ -3651,8 +3566,6 @@ static struct usb_function *ffs_alloc(struct usb_function_instance *fi)
{ {
struct ffs_function *func; struct ffs_function *func;
ENTER();
func = kzalloc(sizeof(*func), GFP_KERNEL); func = kzalloc(sizeof(*func), GFP_KERNEL);
if (!func) if (!func)
return ERR_PTR(-ENOMEM); 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; int ret = 0;
struct ffs_dev *ffs_dev; struct ffs_dev *ffs_dev;
ENTER();
ffs_dev_lock(); ffs_dev_lock();
ffs_dev = _ffs_find_dev(dev_name); 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) static void ffs_release_dev(struct ffs_dev *ffs_dev)
{ {
ENTER();
ffs_dev_lock(); ffs_dev_lock();
if (ffs_dev && ffs_dev->mounted) { if (ffs_dev && ffs_dev->mounted) {
@ -3798,7 +3709,6 @@ static int ffs_ready(struct ffs_data *ffs)
struct ffs_dev *ffs_obj; struct ffs_dev *ffs_obj;
int ret = 0; int ret = 0;
ENTER();
ffs_dev_lock(); ffs_dev_lock();
ffs_obj = ffs->private_data; ffs_obj = ffs->private_data;
@ -3831,7 +3741,6 @@ static void ffs_closed(struct ffs_data *ffs)
struct f_fs_opts *opts; struct f_fs_opts *opts;
struct config_item *ci; struct config_item *ci;
ENTER();
ffs_dev_lock(); ffs_dev_lock();
ffs_obj = ffs->private_data; ffs_obj = ffs->private_data;

View File

@ -437,6 +437,20 @@ static inline int is_promisc(u16 cdc_filter)
return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS; 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, static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
struct net_device *net) struct net_device *net)
{ {
@ -456,6 +470,15 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
in = NULL; in = NULL;
cdc_filter = 0; 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); spin_unlock_irqrestore(&dev->lock, flags);
if (!in) { 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); 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 * gether_cleanup - remove Ethernet-over-USB device
* Context: may sleep * Context: may sleep
@ -1176,6 +1238,7 @@ void gether_disconnect(struct gether *link)
spin_lock(&dev->lock); spin_lock(&dev->lock);
dev->port_usb = NULL; dev->port_usb = NULL;
link->is_suspend = false;
spin_unlock(&dev->lock); spin_unlock(&dev->lock);
} }
EXPORT_SYMBOL_GPL(gether_disconnect); EXPORT_SYMBOL_GPL(gether_disconnect);

View File

@ -79,6 +79,7 @@ struct gether {
/* called on network open/close */ /* called on network open/close */
void (*open)(struct gether *); void (*open)(struct gether *);
void (*close)(struct gether *); void (*close)(struct gether *);
bool is_suspend;
}; };
#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ #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_cleanup(struct eth_dev *dev);
void gether_suspend(struct gether *link);
void gether_resume(struct gether *link);
/* connect/disconnect is handled by individual functions */ /* connect/disconnect is handled by individual functions */
struct net_device *gether_connect(struct gether *); struct net_device *gether_connect(struct gether *);
void gether_disconnect(struct gether *); void gether_disconnect(struct gether *);

View File

@ -32,8 +32,6 @@
# define ffs_dump_mem(prefix, ptr, len) do { } while (0) # define ffs_dump_mem(prefix, ptr, len) do { } while (0)
#endif /* VERBOSE_DEBUG */ #endif /* VERBOSE_DEBUG */
#define ENTER() pr_vdebug("%s()\n", __func__)
struct f_fs_opts; struct f_fs_opts;
struct ffs_dev { struct ffs_dev {

View File

@ -334,6 +334,64 @@ UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, 8);
#undef UVCG_DEFAULT_PROCESSING_ATTR #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( static ssize_t uvcg_default_processing_bm_controls_show(
struct config_item *item, char *page) struct config_item *item, char *page)
{ {
@ -363,7 +421,7 @@ static ssize_t uvcg_default_processing_bm_controls_show(
return result; 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[] = { static struct configfs_attribute *uvcg_default_processing_attrs[] = {
&uvcg_default_processing_attr_b_unit_id, &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 #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( static ssize_t uvcg_default_camera_bm_controls_show(
struct config_item *item, char *page) struct config_item *item, char *page)
{ {
@ -474,7 +591,7 @@ static ssize_t uvcg_default_camera_bm_controls_show(
return result; 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[] = { static struct configfs_attribute *uvcg_default_camera_attrs[] = {
&uvcg_default_camera_attr_b_terminal_id, &uvcg_default_camera_attr_b_terminal_id,

View File

@ -180,8 +180,6 @@ static int __init gfs_init(void)
int i; int i;
int ret = 0; int ret = 0;
ENTER();
if (func_num < 2) { if (func_num < 2) {
gfs_single_func = true; gfs_single_func = true;
func_num = 1; func_num = 1;
@ -242,8 +240,6 @@ static void __exit gfs_exit(void)
{ {
int i; int i;
ENTER();
if (gfs_registered) if (gfs_registered)
usb_composite_unregister(&gfs_driver); usb_composite_unregister(&gfs_driver);
gfs_registered = false; gfs_registered = false;
@ -316,8 +312,6 @@ static int gfs_bind(struct usb_composite_dev *cdev)
#endif #endif
int ret, i; int ret, i;
ENTER();
if (missing_funcs) if (missing_funcs)
return -ENODEV; return -ENODEV;
#if defined CONFIG_USB_FUNCTIONFS_ETH #if defined CONFIG_USB_FUNCTIONFS_ETH
@ -445,9 +439,6 @@ static int gfs_unbind(struct usb_composite_dev *cdev)
{ {
int i; int i;
ENTER();
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS #ifdef CONFIG_USB_FUNCTIONFS_RNDIS
usb_put_function(f_rndis); usb_put_function(f_rndis);
usb_put_function_instance(fi_rndis); usb_put_function_instance(fi_rndis);

View File

@ -21,7 +21,6 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/usb/gadget.h> #include <linux/usb/gadget.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>

View File

@ -21,7 +21,6 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/usb/gadget.h> #include <linux/usb/gadget.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/usb.h> #include <linux/usb.h>

View File

@ -21,7 +21,6 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/usb/gadget.h> #include <linux/usb/gadget.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>

View File

@ -21,7 +21,6 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/usb/gadget.h> #include <linux/usb/gadget.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>

View File

@ -21,7 +21,6 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/usb/gadget.h> #include <linux/usb/gadget.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/bcd.h> #include <linux/bcd.h>

View File

@ -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; * @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 * 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. * @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 * This represents the internal data structure which is used by the UDC-class
* to hold information about udc driver and gadget together. * to hold information about udc driver and gadget together.
@ -48,6 +52,7 @@ struct usb_udc {
struct list_head list; struct list_head list;
bool vbus; bool vbus;
bool started; bool started;
struct mutex connect_lock;
}; };
static struct class *udc_class; static struct class *udc_class;
@ -513,6 +518,33 @@ out:
} }
EXPORT_SYMBOL_GPL(usb_gadget_wakeup); 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. * usb_gadget_set_selfpowered - sets the device selfpowered feature.
* @gadget:the device being declared as self-powered * @gadget:the device being declared as self-powered
@ -660,17 +692,9 @@ out:
} }
EXPORT_SYMBOL_GPL(usb_gadget_vbus_disconnect); EXPORT_SYMBOL_GPL(usb_gadget_vbus_disconnect);
/** /* Internal version of usb_gadget_connect needs to be called with connect_lock held. */
* usb_gadget_connect - software-controlled connect to USB host static int usb_gadget_connect_locked(struct usb_gadget *gadget)
* @gadget:the peripheral being connected __must_hold(&gadget->udc->connect_lock)
*
* 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)
{ {
int ret = 0; int ret = 0;
@ -679,10 +703,15 @@ int usb_gadget_connect(struct usb_gadget *gadget)
goto out; 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. * If gadget is deactivated we only save new state.
* Gadget will be connected automatically after activation. * Gadget will be connected automatically after activation.
*
* udc first needs to be started before gadget can be pulled up.
*/ */
gadget->connected = true; gadget->connected = true;
goto out; goto out;
@ -697,22 +726,32 @@ out:
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(usb_gadget_connect);
/** /**
* usb_gadget_disconnect - software-controlled disconnect from USB host * usb_gadget_connect - software-controlled connect to USB host
* @gadget:the peripheral being disconnected * @gadget:the peripheral being connected
* *
* Disables the D+ (or potentially D-) pullup, which the host may see * Enables the D+ (or potentially D-) pullup. The host will start
* as a disconnect (when a VBUS session is active). Not all systems * enumerating this gadget when the pullup is active and a VBUS session
* support software pullup controls. * is active (the link is powered).
*
* 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. * 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; int ret = 0;
@ -724,10 +763,12 @@ int usb_gadget_disconnect(struct usb_gadget *gadget)
if (!gadget->connected) if (!gadget->connected)
goto out; goto out;
if (gadget->deactivated) { if (gadget->deactivated || !gadget->udc->started) {
/* /*
* If gadget is deactivated we only save new state. * If gadget is deactivated we only save new state.
* Gadget will stay disconnected after activation. * Gadget will stay disconnected after activation.
*
* udc should have been started before gadget being pulled down.
*/ */
gadget->connected = false; gadget->connected = false;
goto out; goto out;
@ -747,6 +788,30 @@ out:
return ret; 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); EXPORT_SYMBOL_GPL(usb_gadget_disconnect);
/** /**
@ -767,10 +832,11 @@ int usb_gadget_deactivate(struct usb_gadget *gadget)
if (gadget->deactivated) if (gadget->deactivated)
goto out; goto out;
mutex_lock(&gadget->udc->connect_lock);
if (gadget->connected) { if (gadget->connected) {
ret = usb_gadget_disconnect(gadget); ret = usb_gadget_disconnect_locked(gadget);
if (ret) if (ret)
goto out; goto unlock;
/* /*
* If gadget was being connected before deactivation, we want * If gadget was being connected before deactivation, we want
@ -780,6 +846,8 @@ int usb_gadget_deactivate(struct usb_gadget *gadget)
} }
gadget->deactivated = true; gadget->deactivated = true;
unlock:
mutex_unlock(&gadget->udc->connect_lock);
out: out:
trace_usb_gadget_deactivate(gadget, ret); trace_usb_gadget_deactivate(gadget, ret);
@ -803,6 +871,7 @@ int usb_gadget_activate(struct usb_gadget *gadget)
if (!gadget->deactivated) if (!gadget->deactivated)
goto out; goto out;
mutex_lock(&gadget->udc->connect_lock);
gadget->deactivated = false; 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(). * while it was being deactivated, we call usb_gadget_connect().
*/ */
if (gadget->connected) if (gadget->connected)
ret = usb_gadget_connect(gadget); ret = usb_gadget_connect_locked(gadget);
mutex_unlock(&gadget->udc->connect_lock);
out: out:
trace_usb_gadget_activate(gadget, ret); 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) if (udc->vbus && udc->started)
usb_gadget_connect(udc->gadget); usb_gadget_connect_locked(udc->gadget);
else 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; struct usb_udc *udc = gadget->udc;
mutex_lock(&udc->connect_lock);
if (udc) { if (udc) {
udc->vbus = status; 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); 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); 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 * @udc: The UDC to be started
* *
* This call is issued by the UDC Class driver when it's about * 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. * necessary to have it powered on.
* *
* Returns zero on success, else negative errno. * 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; 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 * @udc: The UDC to be stopped
* *
* This call is issued by the UDC Class driver after calling * 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 * The details are implementation specific, but it can go as
* far as powering off UDC completely and disable its data * far as powering off UDC completely and disable its data
* line pullups. * 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) { if (!udc->started) {
dev_err(&udc->dev, "UDC had already stopped\n"); dev_err(&udc->dev, "UDC had already stopped\n");
@ -1295,6 +1374,7 @@ int usb_add_gadget(struct usb_gadget *gadget)
udc->gadget = gadget; udc->gadget = gadget;
gadget->udc = udc; gadget->udc = udc;
mutex_init(&udc->connect_lock);
udc->started = false; udc->started = false;
@ -1496,11 +1576,15 @@ static int gadget_bind_driver(struct device *dev)
if (ret) if (ret)
goto err_bind; goto err_bind;
ret = usb_gadget_udc_start(udc); mutex_lock(&udc->connect_lock);
if (ret) ret = usb_gadget_udc_start_locked(udc);
if (ret) {
mutex_unlock(&udc->connect_lock);
goto err_start; goto err_start;
}
usb_gadget_enable_async_callbacks(udc); 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); kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
return 0; return 0;
@ -1531,12 +1615,14 @@ static void gadget_unbind_driver(struct device *dev)
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); 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); usb_gadget_disable_async_callbacks(udc);
if (gadget->irq) if (gadget->irq)
synchronize_irq(gadget->irq); synchronize_irq(gadget->irq);
udc->driver->unbind(gadget); udc->driver->unbind(gadget);
usb_gadget_udc_stop(udc); usb_gadget_udc_stop_locked(udc);
mutex_unlock(&udc->connect_lock);
mutex_lock(&udc_lock); mutex_lock(&udc_lock);
driver->is_bound = false; driver->is_bound = false;
@ -1622,11 +1708,15 @@ static ssize_t soft_connect_store(struct device *dev,
} }
if (sysfs_streq(buf, "connect")) { if (sysfs_streq(buf, "connect")) {
usb_gadget_udc_start(udc); mutex_lock(&udc->connect_lock);
usb_gadget_connect(udc->gadget); usb_gadget_udc_start_locked(udc);
usb_gadget_connect_locked(udc->gadget);
mutex_unlock(&udc->connect_lock);
} else if (sysfs_streq(buf, "disconnect")) { } else if (sysfs_streq(buf, "disconnect")) {
usb_gadget_disconnect(udc->gadget); mutex_lock(&udc->connect_lock);
usb_gadget_udc_stop(udc); usb_gadget_disconnect_locked(udc->gadget);
usb_gadget_udc_stop_locked(udc);
mutex_unlock(&udc->connect_lock);
} else { } else {
dev_err(dev, "unsupported command '%s'\n", buf); dev_err(dev, "unsupported command '%s'\n", buf);
ret = -EINVAL; ret = -EINVAL;

View File

@ -1319,7 +1319,7 @@ MODULE_DEVICE_TABLE(of, max3420_udc_of_match);
static struct spi_driver max3420_driver = { static struct spi_driver max3420_driver = {
.driver = { .driver = {
.name = "max3420-udc", .name = "max3420-udc",
.of_match_table = of_match_ptr(max3420_udc_of_match), .of_match_table = max3420_udc_of_match,
}, },
.probe = max3420_probe, .probe = max3420_probe,
.remove = max3420_remove, .remove = max3420_remove,

View File

@ -2229,7 +2229,11 @@ static int mv_udc_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&udc->status_req->queue); INIT_LIST_HEAD(&udc->status_req->queue);
/* allocate a small amount of memory to get valid address */ /* 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->status_req->req.dma = DMA_ADDR_INVALID;
udc->resume_state = USB_STATE_NOTATTACHED; udc->resume_state = USB_STATE_NOTATTACHED;

View File

@ -22,7 +22,6 @@
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/sys_soc.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/usb/ch9.h> #include <linux/usb/ch9.h>
#include <linux/usb/gadget.h> #include <linux/usb/gadget.h>
@ -2661,6 +2660,7 @@ static int renesas_usb3_remove(struct platform_device *pdev)
debugfs_remove_recursive(usb3->dentry); debugfs_remove_recursive(usb3->dentry);
device_remove_file(&pdev->dev, &dev_attr_role); device_remove_file(&pdev->dev, &dev_attr_role);
cancel_work_sync(&usb3->role_work);
usb_role_switch_unregister(usb3->role_sw); usb_role_switch_unregister(usb3->role_sw);
usb_del_gadget_udc(&usb3->gadget); 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 = { static const struct renesas_usb3_priv renesas_usb3_priv_gen3 = {
.ramsize_per_ramif = SZ_16K, .ramsize_per_ramif = SZ_16K,
.num_ramif = 4, .num_ramif = 4,
@ -2829,14 +2822,6 @@ static const struct of_device_id usb3_of_match[] = {
}; };
MODULE_DEVICE_TABLE(of, 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[] = { static const unsigned int renesas_usb3_cable[] = {
EXTCON_USB, EXTCON_USB,
EXTCON_USB_HOST, EXTCON_USB_HOST,
@ -2854,13 +2839,8 @@ static int renesas_usb3_probe(struct platform_device *pdev)
struct renesas_usb3 *usb3; struct renesas_usb3 *usb3;
int irq, ret; int irq, ret;
const struct renesas_usb3_priv *priv; const struct renesas_usb3_priv *priv;
const struct soc_device_attribute *attr;
attr = soc_device_match(renesas_usb3_quirks_match); priv = of_device_get_match_data(&pdev->dev);
if (attr)
priv = attr->data;
else
priv = of_device_get_match_data(&pdev->dev);
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) if (irq < 0)
@ -3039,7 +3019,7 @@ static struct platform_driver renesas_usb3_driver = {
.driver = { .driver = {
.name = udc_name, .name = udc_name,
.pm = &renesas_usb3_pm_ops, .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); module_platform_driver(renesas_usb3_driver);

View File

@ -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); 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) static void usbf_ep0_send_null(struct usbf_ep *ep0, bool is_data1)
{ {
u32 set; u32 set;

Some files were not shown because too many files have changed in this diff Show More