USB / Thunderbolt changes for 6.10-rc1

Here is the big set of USB and Thunderbolt changes for 6.10-rc1.
 Nothing hugely earth-shattering, just constant forward progress for
 hardware support of new devices and cleanups over the drivers.
 
 Included in here are:
   - Thunderbolt / USB 4 driver updates
   - typec driver updates
   - dwc3 driver updates
   - gadget driver updates
   - uss720 driver id additions and fixes (people use USB->arallel port
     devices still!)
   - onboard-hub driver rename and additions for new hardware
   - xhci driver updates
   - other small USB driver updates and additions for quirks and api
     changes
 
 All of these have been in linux-next for a while with no reported
 problems.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZk4E7w8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+yn0kACgr3uvAWXvfb9R4vCpC65F4f49ZQwAoIkHQBPl
 /5HdrlIIYW2OzdUixH3e
 =e3pI
 -----END PGP SIGNATURE-----

Merge tag 'usb-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB / Thunderbolt updates from Greg KH:
 "Here is the big set of USB and Thunderbolt changes for 6.10-rc1.
  Nothing hugely earth-shattering, just constant forward progress for
  hardware support of new devices and cleanups over the drivers.

  Included in here are:

   - Thunderbolt / USB 4 driver updates

   - typec driver updates

   - dwc3 driver updates

   - gadget driver updates

   - uss720 driver id additions and fixes (people use USB->arallel port
     devices still!)

   - onboard-hub driver rename and additions for new hardware

   - xhci driver updates

   - other small USB driver updates and additions for quirks and api
     changes

  All of these have been in linux-next for a while with no reported
  problems"

* tag 'usb-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (154 commits)
  drm/bridge: aux-hpd-bridge: correct devm_drm_dp_hpd_bridge_add() stub
  usb: fotg210: Add missing kernel doc description
  usb: dwc3: core: Fix unused variable warning in core driver
  usb: typec: tipd: rely on i2c_get_match_data()
  usb: typec: tipd: fix event checking for tps6598x
  usb: typec: tipd: fix event checking for tps25750
  dt-bindings: usb: qcom,dwc3: fix interrupt max items
  usb: fotg210: Use *-y instead of *-objs in Makefile
  usb: phy: tegra: Replace of_gpio.h by proper one
  usb: typec: ucsi: displayport: Fix potential deadlock
  usb: typec: qcom-pmic-typec: split HPD bridge alloc and registration
  usb: musc: Remove unused list 'buffers'
  usb: dwc3: Wait unconditionally after issuing EndXfer command
  usb: gadget: u_audio: Clear uac pointer when freed.
  usb: gadget: u_audio: Fix race condition use of controls after free during gadget unbind.
  dt-bindings: usb: dwc3: Add QDU1000 compatible
  usb: core: Remove the useless struct usb_devmap which is just a bitmap
  MAINTAINERS: Remove {ehci,uhci}-platform.c from ARM/VT8500 entry
  USB: usb_parse_endpoint: ignore reserved bits
  usb: xhci: compact 'trb_in_td()' arguments
  ...
This commit is contained in:
Linus Torvalds 2024-05-22 11:40:09 -07:00
commit 89601f675b
118 changed files with 2755 additions and 1941 deletions

View File

@ -5,4 +5,5 @@ Contact: Matthias Kaehlcke <matthias@kaehlcke.net>
linux-usb@vger.kernel.org
Description:
(RW) Controls whether the USB hub remains always powered
during system suspend or not.
during system suspend or not. This attribute is not
available for non-hub devices.

View File

@ -0,0 +1,63 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/xmos,xvf3500.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: XMOS XVF3500 VocalFusion Voice Processor
maintainers:
- Javier Carrasco <javier.carrasco@wolfvision.net>
description:
The XMOS XVF3500 VocalFusion Voice Processor is a low-latency, 32-bit
multicore controller for voice processing.
https://www.xmos.com/xvf3500/
allOf:
- $ref: /schemas/usb/usb-device.yaml#
properties:
compatible:
const: usb20b1,0013
reg: true
reset-gpios:
maxItems: 1
vdd-supply:
description:
Regulator for the 1V0 supply.
vddio-supply:
description:
Regulator for the 3V3 supply.
required:
- compatible
- reg
- reset-gpios
- vdd-supply
- vddio-supply
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
usb {
#address-cells = <1>;
#size-cells = <0>;
voice_processor: voice-processor@1 {
compatible = "usb20b1,0013";
reg = <1>;
reset-gpios = <&gpio 5 GPIO_ACTIVE_LOW>;
vdd-supply = <&vcc1v0>;
vddio-supply = <&vcc3v3>;
};
};
...

View File

@ -0,0 +1,200 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/usb/chipidea,usb2-common.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: USB2 ChipIdea USB controller Common Properties
maintainers:
- Xu Yang <xu.yang_2@nxp.com>
properties:
reg:
minItems: 1
maxItems: 2
interrupts:
minItems: 1
maxItems: 2
clocks:
minItems: 1
maxItems: 3
clock-names:
minItems: 1
maxItems: 3
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 previous 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
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
- const: host
- const: device
- 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
vbus-supply:
description: reference to the VBUS regulator.
usb-phy:
description: phandle for the PHY device. Use "phys" instead.
maxItems: 1
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
dependencies:
port: [ usb-role-switch ]
mux-controls: [ mux-control-names ]
required:
- reg
- interrupts
allOf:
- $ref: usb-hcd.yaml#
- $ref: usb-drd.yaml#
additionalProperties: true

View File

@ -0,0 +1,287 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/usb/chipidea,usb2-imx.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP USB2 ChipIdea USB controller
maintainers:
- Xu Yang <xu.yang_2@nxp.com>
properties:
compatible:
oneOf:
- enum:
- fsl,imx27-usb
- items:
- enum:
- fsl,imx23-usb
- fsl,imx25-usb
- fsl,imx28-usb
- fsl,imx35-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:
- enum:
- fsl,imx8dxl-usb
- fsl,imx8ulp-usb
- const: fsl,imx7ulp-usb
- const: fsl,imx6ul-usb
- items:
- enum:
- fsl,imx8mm-usb
- fsl,imx8mn-usb
- fsl,imx93-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
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
minItems: 1
maxItems: 3
clock-names:
minItems: 1
maxItems: 3
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
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
fsl,picophy-rise-fall-time-adjust:
description:
HS Transmitter Rise/Fall Time Adjustment. Adjust the rise/fall times
of the high-speed transmitter waveform. It has no unit. The rise/fall
time will be increased or decreased by a certain percentage relative
to design default time. (0:-10%; 1:design default; 2:+15%; 3:+20%)
Details can refer to TXRISETUNE0 bit of USBNC_n_PHY_CFG1.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 3
default: 1
fsl,usbphy:
description: phandle of usb phy that connects to the port. Use "phys" instead.
$ref: /schemas/types.yaml#/definitions/phandle
deprecated: true
required:
- compatible
allOf:
- $ref: chipidea,usb2-common.yaml#
- if:
properties:
phy_type:
const: hsic
required:
- phy_type
then:
properties:
pinctrl-names:
items:
- const: idle
- const: active
# imx27 Soc needs three clocks
- if:
properties:
compatible:
const: fsl,imx27-usb
then:
properties:
clocks:
minItems: 3
clock-names:
items:
- const: ipg
- const: ahb
- const: per
# imx25 and imx35 Soc need three clocks
- if:
properties:
compatible:
contains:
enum:
- fsl,imx25-usb
- fsl,imx35-usb
then:
properties:
clocks:
minItems: 3
clock-names:
items:
- const: ipg
- const: ahb
- const: per
# imx93 Soc needs two clocks
- if:
properties:
compatible:
contains:
enum:
- fsl,imx93-usb
then:
properties:
clocks:
minItems: 2
maxItems: 2
clock-names:
items:
- const: usb_ctrl_root
- const: usb_wakeup
# imx7d Soc need one clock
- if:
properties:
compatible:
items:
- const: fsl,imx7d-usb
- const: fsl,imx27-usb
then:
properties:
clocks:
maxItems: 1
clock-names: false
# other Soc need one clock
- if:
properties:
compatible:
contains:
enum:
- fsl,imx23-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,imx8mm-usb
- fsl,imx8mn-usb
- fsl,vf610-usb
then:
properties:
clocks:
maxItems: 1
clock-names: false
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/imx7d-clock.h>
usb@30b10000 {
compatible = "fsl,imx7d-usb", "fsl,imx27-usb";
reg = <0x30b10000 0x200>;
interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX7D_USB_CTRL_CLK>;
fsl,usbphy = <&usbphynop1>;
fsl,usbmisc = <&usbmisc1 0>;
phy-clkgate-delay-us = <400>;
};
# 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

@ -15,7 +15,6 @@ properties:
oneOf:
- enum:
- chipidea,usb2
- fsl,imx27-usb
- lsi,zevio-usb
- nuvoton,npcm750-udc
- nvidia,tegra20-ehci
@ -31,40 +30,6 @@ properties:
- nvidia,tegra124-ehci
- nvidia,tegra210-ehci
- const: nvidia,tegra30-ehci
- items:
- enum:
- fsl,imx23-usb
- fsl,imx25-usb
- fsl,imx28-usb
- fsl,imx35-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:
- enum:
- fsl,imx8dxl-usb
- fsl,imx8ulp-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
@ -73,163 +38,18 @@ properties:
- nuvoton,npcm845-udc
- const: nuvoton,npcm750-udc
reg:
minItems: 1
maxItems: 2
interrupts:
minItems: 1
maxItems: 2
clocks:
minItems: 1
maxItems: 3
maxItems: 2
clock-names:
minItems: 1
maxItems: 3
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 previous 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
maxItems: 2
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
@ -240,87 +60,6 @@ properties:
- 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
fsl,picophy-rise-fall-time-adjust:
description:
HS Transmitter Rise/Fall Time Adjustment. Adjust the rise/fall times
of the high-speed transmitter waveform. It has no unit. The rise/fall
time will be increased or decreased by a certain percentage relative
to design default time. (0:-10%; 1:design default; 2:+15%; 3:+20%)
Details can refer to TXRISETUNE0 bit of USBNC_n_PHY_CFG1.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 3
default: 1
usb-phy:
description: phandle for the PHY device. Use "phys" instead.
maxItems: 1
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
@ -331,16 +70,6 @@ properties:
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
@ -350,67 +79,13 @@ properties:
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: chipidea,usb2-common.yaml#
- $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
- nuvoton,npcm750-udc
- 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
@ -438,33 +113,4 @@ examples:
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

@ -51,7 +51,6 @@ examples:
#include <dt-bindings/gpio/gpio.h>
usb {
dr_mode = "host";
#address-cells = <1>;
#size-cells = <0>;

View File

@ -59,6 +59,7 @@ properties:
- const: amcc,dwc-otg
- const: apm,apm82181-dwc-otg
- const: snps,dwc2
- const: sophgo,cv1800-usb
- const: st,stm32f4x9-fsotg
- const: st,stm32f4x9-hsotg
- const: st,stm32f7-hsotg

View File

@ -0,0 +1,63 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/usb/microchip,usb2514.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Microchip USB2514 Hub Controller
maintainers:
- Fabio Estevam <festevam@gmail.com>
allOf:
- $ref: usb-hcd.yaml#
properties:
compatible:
enum:
- usb424,2412
- usb424,2417
- usb424,2514
reg: true
reset-gpios:
description: GPIO connected to the RESET_N pin.
vdd-supply:
description: 3.3V power supply.
clocks:
description: External 24MHz clock connected to the CLKIN pin.
maxItems: 1
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/imx6qdl-clock.h>
#include <dt-bindings/gpio/gpio.h>
usb {
#address-cells = <1>;
#size-cells = <0>;
usb-hub@1 {
compatible = "usb424,2514";
reg = <1>;
clocks = <&clks IMX6QDL_CLK_CKO>;
reset-gpios = <&gpio7 12 GPIO_ACTIVE_LOW>;
vdd-supply = <&reg_3v3_hub>;
#address-cells = <1>;
#size-cells = <0>;
ethernet@1 {
compatible = "usbb95,772b";
reg = <1>;
};
};
};

View File

@ -26,10 +26,12 @@ properties:
- qcom,msm8998-dwc3
- qcom,qcm2290-dwc3
- qcom,qcs404-dwc3
- qcom,qdu1000-dwc3
- qcom,sa8775p-dwc3
- qcom,sc7180-dwc3
- qcom,sc7280-dwc3
- qcom,sc8280xp-dwc3
- qcom,sc8280xp-dwc3-mp
- qcom,sdm660-dwc3
- qcom,sdm670-dwc3
- qcom,sdm845-dwc3
@ -117,11 +119,11 @@ properties:
exception of SDM670/SDM845/SM6350.
- ss_phy_irq: Used for remote wakeup in Super Speed mode of operation.
minItems: 2
maxItems: 5
maxItems: 18
interrupt-names:
minItems: 2
maxItems: 5
maxItems: 18
qcom,select-utmi-as-pipe-clk:
description:
@ -245,6 +247,7 @@ allOf:
contains:
enum:
- qcom,ipq8074-dwc3
- qcom,qdu1000-dwc3
then:
properties:
clocks:
@ -282,6 +285,7 @@ allOf:
contains:
enum:
- qcom,sc8280xp-dwc3
- qcom,sc8280xp-dwc3-mp
- qcom,x1e80100-dwc3
then:
properties:
@ -440,6 +444,7 @@ allOf:
- qcom,ipq4019-dwc3
- qcom,ipq8064-dwc3
- qcom,msm8994-dwc3
- qcom,qdu1000-dwc3
- qcom,sa8775p-dwc3
- qcom,sc7180-dwc3
- qcom,sc7280-dwc3
@ -470,6 +475,38 @@ allOf:
- const: dm_hs_phy_irq
- const: ss_phy_irq
- if:
properties:
compatible:
contains:
enum:
- qcom,sc8280xp-dwc3-mp
then:
properties:
interrupts:
minItems: 18
maxItems: 18
interrupt-names:
items:
- const: pwr_event_1
- const: pwr_event_2
- const: pwr_event_3
- const: pwr_event_4
- const: hs_phy_1
- const: hs_phy_2
- const: hs_phy_3
- const: hs_phy_4
- const: dp_hs_phy_1
- const: dm_hs_phy_1
- const: dp_hs_phy_2
- const: dm_hs_phy_2
- const: dp_hs_phy_3
- const: dm_hs_phy_3
- const: dp_hs_phy_4
- const: dm_hs_phy_4
- const: ss_phy_1
- const: ss_phy_2
additionalProperties: false
examples:

View File

@ -21,6 +21,7 @@ properties:
- items:
- enum:
- qcom,pm6150-typec
- qcom,pm7250b-typec
- const: qcom,pm8150b-typec
- items:
- enum:
@ -192,15 +193,22 @@ examples:
port@0 {
reg = <0>;
pmic_typec_mux_out: endpoint {
remote-endpoint = <&usb_phy_typec_mux_in>;
pmic_typec_hs_in: endpoint {
remote-endpoint = <&usb_hs_out>;
};
};
port@1 {
reg = <1>;
pmic_typec_role_switch_out: endpoint {
remote-endpoint = <&usb_role_switch_in>;
pmic_typec_ss_in: endpoint {
remote-endpoint = <&usb_phy_typec_ss_out>;
};
};
port@2 {
reg = <2>;
pmic_typec_sbu: endpoint {
remote-endpoint = <&usb_mux_sbu>;
};
};
};
@ -212,8 +220,8 @@ examples:
dr_mode = "otg";
usb-role-switch;
port {
usb_role_switch_in: endpoint {
remote-endpoint = <&pmic_typec_role_switch_out>;
usb_hs_out: endpoint {
remote-endpoint = <&pmic_typec_hs_in>;
};
};
};
@ -221,8 +229,19 @@ examples:
usb-phy {
orientation-switch;
port {
usb_phy_typec_mux_in: endpoint {
remote-endpoint = <&pmic_typec_mux_out>;
usb_phy_typec_ss_out: endpoint {
remote-endpoint = <&pmic_typec_ss_in>;
};
};
};
usb-mux {
orientation-switch;
mode-switch;
port {
usb_mux_sbu: endpoint {
remote-endpoint = <&pmic_typec_sbu>;
};
};
};

View File

@ -19,10 +19,14 @@ properties:
- items:
- enum:
- renesas,usbhs-r7s9210 # RZ/A2
- const: renesas,rza2-usbhs
- items:
- enum:
- renesas,usbhs-r9a07g043 # RZ/G2UL and RZ/Five
- renesas,usbhs-r9a07g044 # RZ/G2{L,LC}
- renesas,usbhs-r9a07g054 # RZ/V2L
- const: renesas,rza2-usbhs
- const: renesas,rzg2l-usbhs
- items:
- enum:

View File

@ -12,6 +12,7 @@ maintainers:
properties:
compatible:
enum:
- google,gs101-dwusb3
- samsung,exynos5250-dwusb3
- samsung,exynos5433-dwusb3
- samsung,exynos7-dwusb3
@ -55,6 +56,23 @@ required:
- vdd33-supply
allOf:
- if:
properties:
compatible:
contains:
const: google,gs101-dwusb3
then:
properties:
clocks:
minItems: 4
maxItems: 4
clock-names:
items:
- const: bus_early
- const: susp_clk
- const: link_aclk
- const: link_pclk
- if:
properties:
compatible:

View File

@ -85,15 +85,16 @@ properties:
phys:
minItems: 1
maxItems: 2
maxItems: 19
phy-names:
minItems: 1
maxItems: 2
items:
enum:
- usb2-phy
- usb3-phy
maxItems: 19
oneOf:
- items:
enum: [ usb2-phy, usb3-phy ]
- items:
pattern: "^usb(2-([0-9]|1[0-4])|3-[0-3])$"
power-domains:
description:

View File

@ -1,18 +0,0 @@
Generic Platform UHCI Controller
-----------------------------------------------------
Required properties:
- compatible : "generic-uhci" (deprecated: "platform-uhci")
- reg : Should contain 1 register ranges(address and length)
- interrupts : UHCI controller interrupt
additionally the properties from usb-hcd.yaml (in the current directory) are
supported.
Example:
uhci@d8007b00 {
compatible = "generic-uhci";
reg = <0xd8007b00 0x200>;
interrupts = <43>;
};

View File

@ -0,0 +1,75 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/usb/usb-uhci.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Generic Platform UHCI Controller
maintainers:
- Greg Kroah-Hartman <gregkh@linuxfoundation.org>
properties:
compatible:
oneOf:
- const: generic-uhci
- const: platform-uhci
deprecated: true
- items:
- enum:
- aspeed,ast2400-uhci
- aspeed,ast2500-uhci
- aspeed,ast2600-uhci
- const: generic-uhci
reg:
maxItems: 1
interrupts:
maxItems: 1
'#ports':
$ref: /schemas/types.yaml#/definitions/uint32
clocks:
maxItems: 1
required:
- compatible
- reg
- interrupts
allOf:
- $ref: usb-hcd.yaml
- if:
properties:
compatible:
contains:
const: generic-uhci
then:
required:
- clocks
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/aspeed-clock.h>
usb@d8007b00 {
compatible = "generic-uhci";
reg = <0xd8007b00 0x200>;
interrupts = <43>;
clocks = <&syscon ASPEED_CLK_GATE_USBUHCICLK>;
};
- |
#include <dt-bindings/clock/aspeed-clock.h>
usb@1e6b0000 {
compatible = "aspeed,ast2500-uhci", "generic-uhci";
reg = <0x1e6b0000 0x100>;
interrupts = <14>;
#ports = <2>;
clocks = <&syscon ASPEED_CLK_GATE_USBUHCICLK>;
};
...

View File

@ -3087,8 +3087,6 @@ F: drivers/mmc/host/wmt-sdmmc.c
F: drivers/pwm/pwm-vt8500.c
F: drivers/rtc/rtc-vt8500.c
F: drivers/tty/serial/vt8500_serial.c
F: drivers/usb/host/ehci-platform.c
F: drivers/usb/host/uhci-platform.c
F: drivers/video/fbdev/vt8500lcdfb.*
F: drivers/video/fbdev/wm8505fb*
F: drivers/video/fbdev/wmt_ge_rops.*
@ -16691,8 +16689,8 @@ ONBOARD USB HUB DRIVER
M: Matthias Kaehlcke <mka@chromium.org>
L: linux-usb@vger.kernel.org
S: Maintained
F: Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-hub
F: drivers/usb/misc/onboard_usb_hub.c
F: Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-dev
F: drivers/usb/misc/onboard_usb_dev.c
ONENAND FLASH DRIVER
M: Kyungmin Park <kyungmin.park@samsung.com>

View File

@ -885,7 +885,7 @@ CONFIG_USB_CHIPIDEA_UDC=y
CONFIG_USB_CHIPIDEA_HOST=y
CONFIG_USB_ISP1760=y
CONFIG_USB_HSIC_USB3503=y
CONFIG_USB_ONBOARD_HUB=m
CONFIG_USB_ONBOARD_DEV=m
CONFIG_AB8500_USB=y
CONFIG_KEYSTONE_USB_PHY=m
CONFIG_NOP_USB_XCEIV=y

View File

@ -813,7 +813,7 @@
hsusb: usb@11c60000 {
compatible = "renesas,usbhs-r9a07g043",
"renesas,rza2-usbhs";
"renesas,rzg2l-usbhs";
reg = <0 0x11c60000 0 0x10000>;
interrupts = <SOC_PERIPHERAL_IRQ(100) IRQ_TYPE_EDGE_RISING>,
<SOC_PERIPHERAL_IRQ(101) IRQ_TYPE_LEVEL_HIGH>,

View File

@ -1217,7 +1217,7 @@
hsusb: usb@11c60000 {
compatible = "renesas,usbhs-r9a07g044",
"renesas,rza2-usbhs";
"renesas,rzg2l-usbhs";
reg = <0 0x11c60000 0 0x10000>;
interrupts = <GIC_SPI 100 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,

View File

@ -1225,7 +1225,7 @@
hsusb: usb@11c60000 {
compatible = "renesas,usbhs-r9a07g054",
"renesas,rza2-usbhs";
"renesas,rzg2l-usbhs";
reg = <0 0x11c60000 0 0x10000>;
interrupts = <GIC_SPI 100 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,

View File

@ -1073,7 +1073,7 @@ CONFIG_USB_SERIAL_FTDI_SIO=m
CONFIG_USB_SERIAL_OPTION=m
CONFIG_USB_QCOM_EUD=m
CONFIG_USB_HSIC_USB3503=y
CONFIG_USB_ONBOARD_HUB=m
CONFIG_USB_ONBOARD_DEV=m
CONFIG_NOP_USB_XCEIV=y
CONFIG_USB_MXS_PHY=m
CONFIG_USB_GADGET=y

View File

@ -87,7 +87,7 @@ CONFIG_DRM_PARADE_PS8640=y
CONFIG_DRM_LONTIUM_LT9611UXC=y
CONFIG_PHY_QCOM_USB_HS=y
CONFIG_QCOM_GPI_DMA=y
CONFIG_USB_ONBOARD_HUB=y
CONFIG_USB_ONBOARD_DEV=y
CONFIG_NVMEM_QCOM_QFPROM=y
CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2=y
@ -97,7 +97,7 @@ CONFIG_USB_RTL8152=y
# db820c ethernet
CONFIG_ATL1C=y
# Chromebooks ethernet
CONFIG_USB_ONBOARD_HUB=y
CONFIG_USB_ONBOARD_DEV=y
# 888 HDK ethernet
CONFIG_USB_LAN78XX=y

View File

@ -348,16 +348,11 @@ static void pmic_glink_remove(struct platform_device *pdev)
mutex_unlock(&__pmic_glink_lock);
}
static const unsigned long pmic_glink_sc8180x_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) |
BIT(PMIC_GLINK_CLIENT_ALTMODE);
static const unsigned long pmic_glink_sm8450_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) |
BIT(PMIC_GLINK_CLIENT_ALTMODE) |
BIT(PMIC_GLINK_CLIENT_UCSI);
static const struct of_device_id pmic_glink_of_match[] = {
{ .compatible = "qcom,sc8180x-pmic-glink", .data = &pmic_glink_sc8180x_client_mask },
{ .compatible = "qcom,sc8280xp-pmic-glink", .data = &pmic_glink_sc8180x_client_mask },
{ .compatible = "qcom,pmic-glink", .data = &pmic_glink_sm8450_client_mask },
{}
};

View File

@ -1346,7 +1346,7 @@ static int switch_basic_regs_show(struct tb_switch *sw, struct seq_file *s)
if (tb_switch_is_usb4(sw))
dwords = ARRAY_SIZE(data);
else
dwords = 7;
dwords = 5;
ret = tb_sw_read(sw, data, TB_CFG_SWITCH, 0, dwords);
if (ret)

View File

@ -2532,6 +2532,7 @@ struct tb *icm_probe(struct tb_nhi *nhi)
case PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_2C_NHI:
case PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_4C_NHI:
icm->can_upgrade_nvm = true;
icm->is_supported = icm_tgl_is_supported;
icm->get_mode = icm_ar_get_mode;
icm->driver_ready = icm_tr_driver_ready;

View File

@ -199,8 +199,10 @@ static void tb_retimer_nvm_authenticate_status(struct tb_port *port, u32 *status
* If the retimer has it set, store it for the new retimer
* device instance.
*/
for (i = 1; i <= TB_MAX_RETIMER_INDEX; i++)
usb4_port_retimer_nvm_authenticate_status(port, i, &status[i]);
for (i = 1; i <= TB_MAX_RETIMER_INDEX; i++) {
if (usb4_port_retimer_nvm_authenticate_status(port, i, &status[i]))
break;
}
}
static void tb_retimer_set_inbound_sbtx(struct tb_port *port)
@ -234,8 +236,10 @@ static void tb_retimer_unset_inbound_sbtx(struct tb_port *port)
tb_port_dbg(port, "disabling sideband transactions\n");
for (i = TB_MAX_RETIMER_INDEX; i >= 1; i--)
usb4_port_retimer_unset_inbound_sbtx(port, i);
for (i = TB_MAX_RETIMER_INDEX; i >= 1; i--) {
if (usb4_port_retimer_unset_inbound_sbtx(port, i))
break;
}
}
static ssize_t nvm_authenticate_store(struct device *dev,

View File

@ -498,8 +498,9 @@ static struct tb_tunnel *tb_find_first_usb3_tunnel(struct tb *tb,
* @consumed_down: Consumed downstream bandwidth (Mb/s)
*
* Calculates consumed USB3 and PCIe bandwidth at @port between path
* from @src_port to @dst_port. Does not take tunnel starting from
* @src_port and ending from @src_port into account.
* from @src_port to @dst_port. Does not take USB3 tunnel starting from
* @src_port and ending on @src_port into account because that bandwidth is
* already included in as part of the "first hop" USB3 tunnel.
*/
static int tb_consumed_usb3_pcie_bandwidth(struct tb *tb,
struct tb_port *src_port,
@ -514,8 +515,8 @@ static int tb_consumed_usb3_pcie_bandwidth(struct tb *tb,
*consumed_up = *consumed_down = 0;
tunnel = tb_find_first_usb3_tunnel(tb, src_port, dst_port);
if (tunnel && tunnel->src_port != src_port &&
tunnel->dst_port != dst_port) {
if (tunnel && !tb_port_is_usb3_down(src_port) &&
!tb_port_is_usb3_up(dst_port)) {
int ret;
ret = tb_tunnel_consumed_bandwidth(tunnel, consumed_up,

View File

@ -98,12 +98,6 @@ struct cfg_reset_pkg {
struct tb_cfg_header header;
} __packed;
/* TB_CFG_PKG_PREPARE_TO_SLEEP */
struct cfg_pts_pkg {
struct tb_cfg_header header;
u32 data;
} __packed;
/* ICM messages */
enum icm_pkg_code {

View File

@ -87,23 +87,32 @@ static inline const char *show_data(struct trace_seq *p, u8 type,
const char *prefix = "";
int i;
show_route(p, data);
switch (type) {
case TB_CFG_PKG_READ:
case TB_CFG_PKG_WRITE:
show_route(p, data);
show_data_read_write(p, data);
break;
case TB_CFG_PKG_ERROR:
show_route(p, data);
show_data_error(p, data);
break;
case TB_CFG_PKG_EVENT:
show_route(p, data);
show_data_event(p, data);
break;
case TB_CFG_PKG_ICM_EVENT:
case TB_CFG_PKG_ICM_CMD:
case TB_CFG_PKG_ICM_RESP:
/* ICM messages always target the host router */
trace_seq_puts(p, "route=0, ");
break;
default:
show_route(p, data);
break;
}

View File

@ -1435,10 +1435,10 @@ err_free:
* @in: DP in adapter port
* @out: DP out adapter port
* @link_nr: Preferred lane adapter when the link is not bonded
* @max_up: Maximum available upstream bandwidth for the DP tunnel (%0
* if not limited)
* @max_down: Maximum available downstream bandwidth for the DP tunnel
* (%0 if not limited)
* @max_up: Maximum available upstream bandwidth for the DP tunnel.
* %0 if no available bandwidth.
* @max_down: Maximum available downstream bandwidth for the DP tunnel.
* %0 if no available bandwidth.
*
* Allocates a tunnel between @in and @out that is capable of tunneling
* Display Port traffic.
@ -2048,10 +2048,10 @@ err_free:
* @tb: Pointer to the domain structure
* @up: USB3 upstream adapter port
* @down: USB3 downstream adapter port
* @max_up: Maximum available upstream bandwidth for the USB3 tunnel (%0
* if not limited).
* @max_down: Maximum available downstream bandwidth for the USB3 tunnel
* (%0 if not limited).
* @max_up: Maximum available upstream bandwidth for the USB3 tunnel.
* %0 if no available bandwidth.
* @max_down: Maximum available downstream bandwidth for the USB3 tunnel.
* %0 if no available bandwidth.
*
* Allocate an USB3 tunnel. The ports must be of type @TB_TYPE_USB3_UP and
* @TB_TYPE_USB3_DOWN.
@ -2066,24 +2066,19 @@ struct tb_tunnel *tb_tunnel_alloc_usb3(struct tb *tb, struct tb_port *up,
struct tb_path *path;
int max_rate = 0;
/*
* Check that we have enough bandwidth available for the new
* USB3 tunnel.
*/
if (max_up > 0 || max_down > 0) {
if (!tb_route(down->sw) && (max_up > 0 || max_down > 0)) {
/*
* For USB3 isochronous transfers, we allow bandwidth which is
* not higher than 90% of maximum supported bandwidth by USB3
* adapters.
*/
max_rate = tb_usb3_max_link_rate(down, up);
if (max_rate < 0)
return NULL;
/* Only 90% can be allocated for USB3 isochronous transfers */
max_rate = max_rate * 90 / 100;
tb_port_dbg(up, "required bandwidth for USB3 tunnel %d Mb/s\n",
tb_port_dbg(up, "maximum required bandwidth for USB3 tunnel %d Mb/s\n",
max_rate);
if (max_rate > max_up || max_rate > max_down) {
tb_port_warn(up, "not enough bandwidth for USB3 tunnel\n");
return NULL;
}
}
tunnel = tb_tunnel_alloc(tb, 2, TB_TUNNEL_USB3);
@ -2115,8 +2110,8 @@ struct tb_tunnel *tb_tunnel_alloc_usb3(struct tb *tb, struct tb_port *up,
tunnel->paths[TB_USB3_PATH_UP] = path;
if (!tb_route(down->sw)) {
tunnel->allocated_up = max_rate;
tunnel->allocated_down = max_rate;
tunnel->allocated_up = min(max_rate, max_up);
tunnel->allocated_down = min(max_rate, max_down);
tunnel->init = tb_usb3_init;
tunnel->consumed_bandwidth = tb_usb3_consumed_bandwidth;

View File

@ -52,6 +52,10 @@ enum usb4_ba_index {
#define USB4_BA_VALUE_MASK GENMASK(31, 16)
#define USB4_BA_VALUE_SHIFT 16
/* Delays in us used with usb4_port_wait_for_bit() */
#define USB4_PORT_DELAY 50
#define USB4_PORT_SB_DELAY 5000
static int usb4_native_switch_op(struct tb_switch *sw, u16 opcode,
u32 *metadata, u8 *status,
const void *tx_data, size_t tx_dwords,
@ -1245,7 +1249,7 @@ void usb4_port_unconfigure_xdomain(struct tb_port *port)
}
static int usb4_port_wait_for_bit(struct tb_port *port, u32 offset, u32 bit,
u32 value, int timeout_msec)
u32 value, int timeout_msec, unsigned long delay_usec)
{
ktime_t timeout = ktime_add_ms(ktime_get(), timeout_msec);
@ -1260,7 +1264,7 @@ static int usb4_port_wait_for_bit(struct tb_port *port, u32 offset, u32 bit,
if ((val & bit) == value)
return 0;
usleep_range(50, 100);
fsleep(delay_usec);
} while (ktime_before(ktime_get(), timeout));
return -ETIMEDOUT;
@ -1308,7 +1312,7 @@ static int usb4_port_sb_read(struct tb_port *port, enum usb4_sb_target target,
return ret;
ret = usb4_port_wait_for_bit(port, port->cap_usb4 + PORT_CS_1,
PORT_CS_1_PND, 0, 500);
PORT_CS_1_PND, 0, 500, USB4_PORT_SB_DELAY);
if (ret)
return ret;
@ -1355,7 +1359,7 @@ static int usb4_port_sb_write(struct tb_port *port, enum usb4_sb_target target,
return ret;
ret = usb4_port_wait_for_bit(port, port->cap_usb4 + PORT_CS_1,
PORT_CS_1_PND, 0, 500);
PORT_CS_1_PND, 0, 500, USB4_PORT_SB_DELAY);
if (ret)
return ret;
@ -1410,6 +1414,8 @@ static int usb4_port_sb_op(struct tb_port *port, enum usb4_sb_target target,
if (val != opcode)
return usb4_port_sb_opcode_err_to_errno(val);
fsleep(USB4_PORT_SB_DELAY);
} while (ktime_before(ktime_get(), timeout));
return -ETIMEDOUT;
@ -1591,13 +1597,14 @@ int usb4_port_asym_start(struct tb_port *port)
* port started the symmetry transition.
*/
ret = usb4_port_wait_for_bit(port, port->cap_usb4 + PORT_CS_19,
PORT_CS_19_START_ASYM, 0, 1000);
PORT_CS_19_START_ASYM, 0, 1000,
USB4_PORT_DELAY);
if (ret)
return ret;
/* Then wait for the transtion to be completed */
return usb4_port_wait_for_bit(port, port->cap_usb4 + PORT_CS_18,
PORT_CS_18_TIP, 0, 5000);
PORT_CS_18_TIP, 0, 5000, USB4_PORT_DELAY);
}
/**
@ -2123,7 +2130,8 @@ static int usb4_usb3_port_cm_request(struct tb_port *port, bool request)
*/
val &= ADP_USB3_CS_2_CMR;
return usb4_port_wait_for_bit(port, port->cap_adap + ADP_USB3_CS_1,
ADP_USB3_CS_1_HCA, val, 1500);
ADP_USB3_CS_1_HCA, val, 1500,
USB4_PORT_DELAY);
}
static inline int usb4_usb3_port_set_cm_request(struct tb_port *port)

View File

@ -250,7 +250,7 @@ static int tb_xdp_handle_error(const struct tb_xdp_error_response *res)
case ERROR_UNKNOWN_DOMAIN:
return -EIO;
case ERROR_NOT_SUPPORTED:
return -ENOTSUPP;
return -EOPNOTSUPP;
case ERROR_NOT_READY:
return -EAGAIN;
default:

View File

@ -212,7 +212,7 @@ static int imx_get_clks(struct device *dev)
/* Get wakeup clock. Not all of the platforms need to
* handle this clock. So make it optional.
*/
data->clk_wakeup = devm_clk_get_optional(dev, "usb_wakeup_clk");
data->clk_wakeup = devm_clk_get_optional(dev, "usb_wakeup");
if (IS_ERR(data->clk_wakeup))
ret = dev_err_probe(dev, PTR_ERR(data->clk_wakeup),
"Failed to get wakeup clk\n");

View File

@ -80,15 +80,13 @@ clk_err:
return ret;
}
static int npcm_udc_remove(struct platform_device *pdev)
static void npcm_udc_remove(struct platform_device *pdev)
{
struct npcm_udc_data *ci = platform_get_drvdata(pdev);
pm_runtime_disable(&pdev->dev);
ci_hdrc_remove_device(ci->ci);
clk_disable_unprepare(ci->core_clk);
return 0;
}
static const struct of_device_id npcm_udc_dt_match[] = {
@ -100,7 +98,7 @@ MODULE_DEVICE_TABLE(of, npcm_udc_dt_match);
static struct platform_driver npcm_udc_driver = {
.probe = npcm_udc_probe,
.remove = npcm_udc_remove,
.remove_new = npcm_udc_remove,
.driver = {
.name = "npcm_udc",
.of_match_table = npcm_udc_dt_match,

View File

@ -1084,10 +1084,6 @@ static int ci_hdrc_probe(struct platform_device *pdev)
return -ENODEV;
}
ret = ci_ulpi_init(ci);
if (ret)
return ret;
if (ci->platdata->phy) {
ci->phy = ci->platdata->phy;
} else if (ci->platdata->usb_phy) {
@ -1142,6 +1138,10 @@ static int ci_hdrc_probe(struct platform_device *pdev)
goto ulpi_exit;
}
ret = ci_ulpi_init(ci);
if (ret)
return ret;
ci->hw_bank.phys = res->start;
ci->irq = platform_get_irq(pdev, 0);

View File

@ -68,11 +68,6 @@ int ci_ulpi_init(struct ci_hdrc *ci)
if (ci->platdata->phy_mode != USBPHY_INTERFACE_MODE_ULPI)
return 0;
/*
* Set PORTSC correctly so we can read/write ULPI registers for
* identification purposes
*/
hw_phymode_configure(ci);
ci->ulpi_ops.read = ci_ulpi_read;
ci->ulpi_ops.write = ci_ulpi_write;

View File

@ -12,8 +12,8 @@ usbcore-$(CONFIG_OF) += of.o
usbcore-$(CONFIG_USB_PCI) += hcd-pci.o
usbcore-$(CONFIG_ACPI) += usb-acpi.o
ifdef CONFIG_USB_ONBOARD_HUB
usbcore-y += ../misc/onboard_usb_hub_pdevs.o
ifdef CONFIG_USB_ONBOARD_DEV
usbcore-y += ../misc/onboard_usb_dev_pdevs.o
endif
obj-$(CONFIG_USB) += usbcore.o

View File

@ -279,11 +279,11 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
goto skip_to_next_endpoint_or_interface_descriptor;
}
i = d->bEndpointAddress & ~USB_ENDPOINT_DIR_MASK;
if (i >= 16 || i == 0) {
i = d->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
if (i == 0) {
dev_notice(ddev, "config %d interface %d altsetting %d has an "
"invalid endpoint with address 0x%X, skipping\n",
cfgno, inum, asnum, d->bEndpointAddress);
"invalid descriptor for endpoint zero, skipping\n",
cfgno, inum, asnum);
goto skip_to_next_endpoint_or_interface_descriptor;
}

View File

@ -866,7 +866,7 @@ static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
*/
static void usb_bus_init (struct usb_bus *bus)
{
memset (&bus->devmap, 0, sizeof(struct usb_devmap));
memset(&bus->devmap, 0, sizeof(bus->devmap));
bus->devnum_next = 1;
@ -962,7 +962,7 @@ static int register_root_hub(struct usb_hcd *hcd)
usb_dev->devnum = devnum;
usb_dev->bus->devnum_next = devnum + 1;
set_bit (devnum, usb_dev->bus->devmap.devicemap);
set_bit(devnum, usb_dev->bus->devmap);
usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
mutex_lock(&usb_bus_idr_lock);

View File

@ -23,7 +23,7 @@
#include <linux/usb.h>
#include <linux/usbdevice_fs.h>
#include <linux/usb/hcd.h>
#include <linux/usb/onboard_hub.h>
#include <linux/usb/onboard_dev.h>
#include <linux/usb/otg.h>
#include <linux/usb/quirks.h>
#include <linux/workqueue.h>
@ -1814,7 +1814,7 @@ static void hub_disconnect(struct usb_interface *intf)
if (hub->quirk_disable_autosuspend)
usb_autopm_put_interface(intf);
onboard_hub_destroy_pdevs(&hub->onboard_hub_devs);
onboard_dev_destroy_pdevs(&hub->onboard_devs);
hub_put(hub);
}
@ -1933,7 +1933,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
INIT_DELAYED_WORK(&hub->leds, led_work);
INIT_DELAYED_WORK(&hub->init_work, NULL);
INIT_WORK(&hub->events, hub_event);
INIT_LIST_HEAD(&hub->onboard_hub_devs);
INIT_LIST_HEAD(&hub->onboard_devs);
spin_lock_init(&hub->irq_urb_lock);
timer_setup(&hub->irq_urb_retry, hub_retry_irq_urb, 0);
usb_get_intf(intf);
@ -1963,7 +1963,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
}
if (hub_configure(hub, &desc->endpoint[0].desc) >= 0) {
onboard_hub_create_pdevs(hdev, &hub->onboard_hub_devs);
onboard_dev_create_pdevs(hdev, &hub->onboard_devs);
return 0;
}
@ -2207,13 +2207,12 @@ static void choose_devnum(struct usb_device *udev)
mutex_lock(&bus->devnum_next_mutex);
/* Try to allocate the next devnum beginning at bus->devnum_next. */
devnum = find_next_zero_bit(bus->devmap.devicemap, 128,
bus->devnum_next);
devnum = find_next_zero_bit(bus->devmap, 128, bus->devnum_next);
if (devnum >= 128)
devnum = find_next_zero_bit(bus->devmap.devicemap, 128, 1);
devnum = find_next_zero_bit(bus->devmap, 128, 1);
bus->devnum_next = (devnum >= 127 ? 1 : devnum + 1);
if (devnum < 128) {
set_bit(devnum, bus->devmap.devicemap);
set_bit(devnum, bus->devmap);
udev->devnum = devnum;
}
mutex_unlock(&bus->devnum_next_mutex);
@ -2222,7 +2221,7 @@ static void choose_devnum(struct usb_device *udev)
static void release_devnum(struct usb_device *udev)
{
if (udev->devnum > 0) {
clear_bit(udev->devnum, udev->bus->devmap.devicemap);
clear_bit(udev->devnum, udev->bus->devmap);
udev->devnum = -1;
}
}

View File

@ -74,7 +74,7 @@ struct usb_hub {
spinlock_t irq_urb_lock;
struct timer_list irq_urb_retry;
struct usb_port **ports;
struct list_head onboard_hub_devs;
struct list_head onboard_devs;
};
/**

View File

@ -249,6 +249,11 @@ void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup,
dwc2_writel(hsotg, gpwrdn, GPWRDN);
udelay(10);
/* Reset ULPI latch */
gpwrdn = dwc2_readl(hsotg, GPWRDN);
gpwrdn &= ~GPWRDN_ULPI_LATCH_EN_DURING_HIB_ENTRY;
dwc2_writel(hsotg, gpwrdn, GPWRDN);
/* Disable PMU interrupt */
gpwrdn = dwc2_readl(hsotg, GPWRDN);
gpwrdn &= ~GPWRDN_PMUINTSEL;
@ -975,6 +980,41 @@ void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg)
dwc2_writel(hsotg, hcfg, HCFG);
}
static void dwc2_set_clock_switch_timer(struct dwc2_hsotg *hsotg)
{
u32 grstctl, gsnpsid, val = 0;
gsnpsid = dwc2_readl(hsotg, GSNPSID);
/*
* Applicable only to HSOTG core v5.00a or higher.
* Not applicable to HS/FS IOT devices.
*/
if ((gsnpsid & ~DWC2_CORE_REV_MASK) != DWC2_OTG_ID ||
gsnpsid < DWC2_CORE_REV_5_00a)
return;
if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI &&
hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED) ||
(hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED) ||
(hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED &&
hsotg->hw_params.fs_phy_type != GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED)) {
val = GRSTCTL_CLOCK_SWITH_TIMER_VALUE_DIS;
}
if (hsotg->params.speed == DWC2_SPEED_PARAM_LOW &&
hsotg->hw_params.hs_phy_type != GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED &&
hsotg->hw_params.fs_phy_type != GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED) {
val = GRSTCTL_CLOCK_SWITH_TIMER_VALUE_147;
}
grstctl = dwc2_readl(hsotg, GRSTCTL);
grstctl &= ~GRSTCTL_CLOCK_SWITH_TIMER_MASK;
grstctl |= GRSTCTL_CLOCK_SWITH_TIMER(val);
dwc2_writel(hsotg, grstctl, GRSTCTL);
}
static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
{
u32 usbcfg, ggpio, i2cctl;
@ -992,6 +1032,8 @@ static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
usbcfg |= GUSBCFG_PHYSEL;
dwc2_writel(hsotg, usbcfg, GUSBCFG);
dwc2_set_clock_switch_timer(hsotg);
/* Reset after a PHY select */
retval = dwc2_core_reset(hsotg, false);

View File

@ -288,6 +288,11 @@ enum dwc2_ep0_state {
* core has been configured to work at either data path
* width.
* 8 or 16 (default 16 if available)
* @eusb2_disc: Specifies whether eUSB2 PHY disconnect support flow
* applicable or no. Applicable in device mode of HSOTG
* and HS IOT cores v5.00 or higher.
* 0 - eUSB2 PHY disconnect support flow not applicable
* 1 - eUSB2 PHY disconnect support flow applicable
* @phy_ulpi_ddr: Specifies whether the ULPI operates at double or single
* data rate. This parameter is only applicable if phy_type
* is ULPI.
@ -442,6 +447,7 @@ struct dwc2_core_params {
#define DWC2_SPEED_PARAM_LOW 2
u8 phy_utmi_width;
bool eusb2_disc;
bool phy_ulpi_ddr;
bool phy_ulpi_ext_vbus;
bool enable_dynamic_fifo;
@ -1110,8 +1116,10 @@ struct dwc2_hsotg {
#define DWC2_CORE_REV_3_10a 0x4f54310a
#define DWC2_CORE_REV_4_00a 0x4f54400a
#define DWC2_CORE_REV_4_20a 0x4f54420a
#define DWC2_CORE_REV_5_00a 0x4f54500a
#define DWC2_FS_IOT_REV_1_00a 0x5531100a
#define DWC2_HS_IOT_REV_1_00a 0x5532100a
#define DWC2_HS_IOT_REV_5_00a 0x5532500a
#define DWC2_CORE_REV_MASK 0x0000ffff
/* DWC OTG HW Core ID */

View File

@ -84,6 +84,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
u32 gotgint;
u32 gotgctl;
u32 gintmsk;
u32 pcgctl;
gotgint = dwc2_readl(hsotg, GOTGINT);
gotgctl = dwc2_readl(hsotg, GOTGCTL);
@ -96,8 +97,22 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
dwc2_op_state_str(hsotg));
gotgctl = dwc2_readl(hsotg, GOTGCTL);
if (dwc2_is_device_mode(hsotg))
if (dwc2_is_device_mode(hsotg)) {
if (hsotg->params.eusb2_disc) {
/* Clear the Gate hclk. */
pcgctl = dwc2_readl(hsotg, PCGCTL);
pcgctl &= ~PCGCTL_GATEHCLK;
dwc2_writel(hsotg, pcgctl, PCGCTL);
udelay(5);
/* Clear Phy Clock bit. */
pcgctl = dwc2_readl(hsotg, PCGCTL);
pcgctl &= ~PCGCTL_STOPPCLK;
dwc2_writel(hsotg, pcgctl, PCGCTL);
udelay(5);
}
dwc2_hsotg_disconnect(hsotg);
}
if (hsotg->op_state == OTG_STATE_B_HOST) {
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
@ -117,7 +132,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
* disconnected
*/
/* Reset to a clean state */
hsotg->lx_state = DWC2_L0;
hsotg->lx_state = DWC2_L3;
}
gotgctl = dwc2_readl(hsotg, GOTGCTL);
@ -286,7 +301,7 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
hsotg->lx_state);
if (dwc2_is_device_mode(hsotg)) {
if (hsotg->lx_state == DWC2_L2) {
if (hsotg->lx_state != DWC2_L0) {
if (hsotg->in_ppd) {
ret = dwc2_exit_partial_power_down(hsotg, 0,
true);
@ -714,6 +729,11 @@ static inline void dwc_handle_gpwrdn_disc_det(struct dwc2_hsotg *hsotg,
gpwrdn_tmp &= ~GPWRDN_PMUINTSEL;
dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
/* Reset ULPI latch */
gpwrdn = dwc2_readl(hsotg, GPWRDN);
gpwrdn &= ~GPWRDN_ULPI_LATCH_EN_DURING_HIB_ENTRY;
dwc2_writel(hsotg, gpwrdn, GPWRDN);
/* De-assert Wakeup Logic */
gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
gpwrdn_tmp &= ~GPWRDN_PMUACTV;

View File

@ -686,6 +686,7 @@ static int params_show(struct seq_file *seq, void *v)
print_param(seq, p, host_channels);
print_param(seq, p, phy_type);
print_param(seq, p, phy_utmi_width);
print_param(seq, p, eusb2_disc);
print_param(seq, p, phy_ulpi_ddr);
print_param(seq, p, phy_ulpi_ext_vbus);
print_param(seq, p, i2c_enable);

View File

@ -3424,8 +3424,11 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
dwc2_hsotg_init_fifo(hsotg);
if (!is_usb_reset)
if (!is_usb_reset) {
dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON);
if (hsotg->params.eusb2_disc)
dwc2_set_bit(hsotg, GOTGCTL, GOTGCTL_EUSB2_DISC_SUPP);
}
dcfg |= DCFG_EPMISCNT(1);
@ -5316,6 +5319,8 @@ void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg)
int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg)
{
u32 gpwrdn;
u32 gusbcfg;
u32 pcgcctl;
int ret = 0;
/* Change to L2(suspend) state */
@ -5335,6 +5340,22 @@ int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg)
}
gpwrdn = GPWRDN_PWRDNRSTN;
udelay(10);
gusbcfg = dwc2_readl(hsotg, GUSBCFG);
if (gusbcfg & GUSBCFG_ULPI_UTMI_SEL) {
/* ULPI interface */
gpwrdn |= GPWRDN_ULPI_LATCH_EN_DURING_HIB_ENTRY;
}
dwc2_writel(hsotg, gpwrdn, GPWRDN);
udelay(10);
/* Suspend the Phy Clock */
pcgcctl = dwc2_readl(hsotg, PCGCTL);
pcgcctl |= PCGCTL_STOPPCLK;
dwc2_writel(hsotg, pcgcctl, PCGCTL);
udelay(10);
gpwrdn = dwc2_readl(hsotg, GPWRDN);
gpwrdn |= GPWRDN_PMUACTV;
dwc2_writel(hsotg, gpwrdn, GPWRDN);
udelay(10);
@ -5435,6 +5456,11 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,
if (reset)
dwc2_clear_bit(hsotg, DCFG, DCFG_DEVADDR_MASK);
/* Reset ULPI latch */
gpwrdn = dwc2_readl(hsotg, GPWRDN);
gpwrdn &= ~GPWRDN_ULPI_LATCH_EN_DURING_HIB_ENTRY;
dwc2_writel(hsotg, gpwrdn, GPWRDN);
/* De-assert Wakeup Logic */
gpwrdn = dwc2_readl(hsotg, GPWRDN);
gpwrdn &= ~GPWRDN_PMUACTV;

View File

@ -5525,6 +5525,11 @@ int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg)
gusbcfg = dwc2_readl(hsotg, GUSBCFG);
if (gusbcfg & GUSBCFG_ULPI_UTMI_SEL) {
/* ULPI interface */
udelay(10);
gpwrdn = dwc2_readl(hsotg, GPWRDN);
gpwrdn |= GPWRDN_ULPI_LATCH_EN_DURING_HIB_ENTRY;
dwc2_writel(hsotg, gpwrdn, GPWRDN);
udelay(10);
/* Suspend the Phy Clock */
pcgcctl = dwc2_readl(hsotg, PCGCTL);
pcgcctl |= PCGCTL_STOPPCLK;
@ -5631,6 +5636,11 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG);
dwc2_writel(hsotg, hr->hcfg, HCFG);
/* Reset ULPI latch */
gpwrdn = dwc2_readl(hsotg, GPWRDN);
gpwrdn &= ~GPWRDN_ULPI_LATCH_EN_DURING_HIB_ENTRY;
dwc2_writel(hsotg, gpwrdn, GPWRDN);
/* De-assert Wakeup Logic */
if (!(rem_wakeup && hsotg->hw_params.snpsid >= DWC2_CORE_REV_4_30a)) {
gpwrdn = dwc2_readl(hsotg, GPWRDN);

View File

@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/seq_buf.h>
#include <linux/slab.h>
#include <linux/usb.h>
@ -359,41 +360,6 @@ static unsigned long *dwc2_get_ls_map(struct dwc2_hsotg *hsotg,
}
#ifdef DWC2_PRINT_SCHEDULE
/*
* cat_printf() - A printf() + strcat() helper
*
* This is useful for concatenating a bunch of strings where each string is
* constructed using printf.
*
* @buf: The destination buffer; will be updated to point after the printed
* data.
* @size: The number of bytes in the buffer (includes space for '\0').
* @fmt: The format for printf.
* @...: The args for printf.
*/
static __printf(3, 4)
void cat_printf(char **buf, size_t *size, const char *fmt, ...)
{
va_list args;
int i;
if (*size == 0)
return;
va_start(args, fmt);
i = vsnprintf(*buf, *size, fmt, args);
va_end(args);
if (i >= *size) {
(*buf)[*size - 1] = '\0';
*buf += *size;
*size = 0;
} else {
*buf += i;
*size -= i;
}
}
/*
* pmap_print() - Print the given periodic map
*
@ -416,9 +382,7 @@ static void pmap_print(unsigned long *map, int bits_per_period,
int period;
for (period = 0; period < periods_in_map; period++) {
char tmp[64];
char *buf = tmp;
size_t buf_size = sizeof(tmp);
DECLARE_SEQ_BUF(buf, 64);
int period_start = period * bits_per_period;
int period_end = period_start + bits_per_period;
int start = 0;
@ -442,19 +406,19 @@ static void pmap_print(unsigned long *map, int bits_per_period,
continue;
if (!printed)
cat_printf(&buf, &buf_size, "%s %d: ",
period_name, period);
seq_buf_printf(&buf, "%s %d: ",
period_name, period);
else
cat_printf(&buf, &buf_size, ", ");
seq_buf_puts(&buf, ", ");
printed = true;
cat_printf(&buf, &buf_size, "%d %s -%3d %s", start,
units, start + count - 1, units);
seq_buf_printf(&buf, "%d %s -%3d %s", start,
units, start + count - 1, units);
count = 0;
}
if (printed)
print_fn(tmp, print_data);
print_fn(seq_buf_str(&buf), print_data);
}
}

View File

@ -11,6 +11,7 @@
#define HSOTG_REG(x) (x)
#define GOTGCTL HSOTG_REG(0x000)
#define GOTGCTL_EUSB2_DISC_SUPP BIT(28)
#define GOTGCTL_CHIRPEN BIT(27)
#define GOTGCTL_MULT_VALID_BC_MASK (0x1f << 22)
#define GOTGCTL_MULT_VALID_BC_SHIFT 22
@ -98,6 +99,17 @@
#define GRSTCTL_AHBIDLE BIT(31)
#define GRSTCTL_DMAREQ BIT(30)
#define GRSTCTL_CSFTRST_DONE BIT(29)
#define GRSTCTL_CLOCK_SWITH_TIMER_MASK (0x7 << 11)
#define GRSTCTL_CLOCK_SWITH_TIMER_SHIFT 11
#define GRSTCTL_CLOCK_SWITH_TIMER_VALUE_19 0x0
#define GRSTCTL_CLOCK_SWITH_TIMER_VALUE_15 0x1
#define GRSTCTL_CLOCK_SWITH_TIMER_VALUE_147 0x2
#define GRSTCTL_CLOCK_SWITH_TIMER_VALUE_50 0x3
#define GRSTCTL_CLOCK_SWITH_TIMER_VALUE_100 0x4
#define GRSTCTL_CLOCK_SWITH_TIMER_VALUE_125 0x5
#define GRSTCTL_CLOCK_SWITH_TIMER_VALUE_200 0x6
#define GRSTCTL_CLOCK_SWITH_TIMER_VALUE_DIS 0x7
#define GRSTCTL_CLOCK_SWITH_TIMER(_x) ((_x) << 11)
#define GRSTCTL_TXFNUM_MASK (0x1f << 6)
#define GRSTCTL_TXFNUM_SHIFT 6
#define GRSTCTL_TXFNUM_LIMIT 0x1f
@ -332,6 +344,8 @@
#define GLPMCFG_LPMCAP BIT(0)
#define GPWRDN HSOTG_REG(0x0058)
#define GPWRDN_ULPI_LATCH_EN_DURING_HIB_ENTRY BIT(29)
#define GPWRDN_MULT_VAL_ID_BC_MASK (0x1f << 24)
#define GPWRDN_MULT_VAL_ID_BC_SHIFT 24
#define GPWRDN_ADP_INT BIT(23)

View File

@ -201,6 +201,25 @@ static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg)
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT;
}
static void dwc2_set_cv1800_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
p->otg_caps.hnp_support = false;
p->otg_caps.srp_support = false;
p->host_dma = false;
p->g_dma = false;
p->speed = DWC2_SPEED_PARAM_HIGH;
p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI;
p->phy_utmi_width = 16;
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT;
p->lpm = false;
p->lpm_clock_gating = false;
p->besl = false;
p->hird_threshold_en = false;
p->power_down = DWC2_POWER_DOWN_PARAM_NONE;
}
static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
@ -295,6 +314,8 @@ const struct of_device_id dwc2_of_match_table[] = {
.data = dwc2_set_amlogic_a1_params },
{ .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params },
{ .compatible = "apm,apm82181-dwc-otg", .data = dwc2_set_amcc_params },
{ .compatible = "sophgo,cv1800-usb",
.data = dwc2_set_cv1800_params },
{ .compatible = "st,stm32f4x9-fsotg",
.data = dwc2_set_stm32f4x9_fsotg_params },
{ .compatible = "st,stm32f4x9-hsotg" },
@ -475,6 +496,7 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg)
dwc2_set_param_lpm(hsotg);
p->phy_ulpi_ddr = false;
p->phy_ulpi_ext_vbus = false;
p->eusb2_disc = false;
p->enable_dynamic_fifo = hw->enable_dynamic_fifo;
p->en_multiple_tx_fifo = hw->en_multiple_tx_fifo;
@ -737,6 +759,25 @@ static void dwc2_check_param_tx_fifo_sizes(struct dwc2_hsotg *hsotg)
}
}
static void dwc2_check_param_eusb2_disc(struct dwc2_hsotg *hsotg)
{
u32 gsnpsid;
if (!hsotg->params.eusb2_disc)
return;
gsnpsid = dwc2_readl(hsotg, GSNPSID);
/*
* eusb2_disc not supported by FS IOT devices.
* For other cores, it supported starting from version 5.00a
*/
if ((gsnpsid & ~DWC2_CORE_REV_MASK) == DWC2_FS_IOT_ID ||
(gsnpsid & DWC2_CORE_REV_MASK) <
(DWC2_CORE_REV_5_00a & DWC2_CORE_REV_MASK)) {
hsotg->params.eusb2_disc = false;
return;
}
}
#define CHECK_RANGE(_param, _min, _max, _def) do { \
if ((int)(hsotg->params._param) < (_min) || \
(hsotg->params._param) > (_max)) { \
@ -765,6 +806,8 @@ static void dwc2_check_params(struct dwc2_hsotg *hsotg)
dwc2_check_param_speed(hsotg);
dwc2_check_param_phy_utmi_width(hsotg);
dwc2_check_param_power_down(hsotg);
dwc2_check_param_eusb2_disc(hsotg);
CHECK_BOOL(enable_dynamic_fifo, hw->enable_dynamic_fifo);
CHECK_BOOL(en_multiple_tx_fifo, hw->en_multiple_tx_fifo);
CHECK_BOOL(i2c_enable, hw->i2c_enable);

View File

@ -39,6 +39,7 @@
#include "io.h"
#include "debug.h"
#include "../host/xhci-ext-caps.h"
#define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */
@ -144,6 +145,7 @@ static void __dwc3_set_mode(struct work_struct *work)
int ret;
u32 reg;
u32 desired_dr_role;
int i;
mutex_lock(&dwc->mutex);
spin_lock_irqsave(&dwc->lock, flags);
@ -221,8 +223,12 @@ static void __dwc3_set_mode(struct work_struct *work)
} else {
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, true);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
for (i = 0; i < dwc->num_usb2_ports; i++)
phy_set_mode(dwc->usb2_generic_phy[i], PHY_MODE_USB_HOST);
for (i = 0; i < dwc->num_usb3_ports; i++)
phy_set_mode(dwc->usb3_generic_phy[i], PHY_MODE_USB_HOST);
if (dwc->dis_split_quirk) {
reg = dwc3_readl(dwc->regs, DWC3_GUCTL3);
reg |= DWC3_GUCTL3_SPLITDISABLE;
@ -237,8 +243,8 @@ static void __dwc3_set_mode(struct work_struct *work)
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, false);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb3_generic_phy[0], PHY_MODE_USB_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret)
@ -506,6 +512,13 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)
static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned int length)
{
struct dwc3_event_buffer *evt;
unsigned int hw_mode;
hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
if (hw_mode == DWC3_GHWPARAMS0_MODE_HOST) {
dwc->ev_buf = NULL;
return 0;
}
evt = dwc3_alloc_one_event_buffer(dwc, length);
if (IS_ERR(evt)) {
@ -527,6 +540,9 @@ int dwc3_event_buffers_setup(struct dwc3 *dwc)
{
struct dwc3_event_buffer *evt;
if (!dwc->ev_buf)
return 0;
evt = dwc->ev_buf;
evt->lpos = 0;
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0),
@ -544,6 +560,9 @@ void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
{
struct dwc3_event_buffer *evt;
if (!dwc->ev_buf)
return;
evt = dwc->ev_buf;
evt->lpos = 0;
@ -596,19 +615,11 @@ static int dwc3_core_ulpi_init(struct dwc3 *dwc)
return ret;
}
/**
* dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
* @dwc: Pointer to our controller context structure
*
* Returns 0 on success. The USB PHY interfaces are configured but not
* initialized. The PHY interfaces and the PHYs get initialized together with
* the core in dwc3_core_init.
*/
static int dwc3_phy_setup(struct dwc3 *dwc)
static int dwc3_ss_phy_setup(struct dwc3 *dwc, int index)
{
u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(index));
/*
* Make sure UX_EXIT_PX is cleared as that causes issues with some
@ -655,9 +666,16 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
if (dwc->dis_del_phy_power_chg_quirk)
reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(index), reg);
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
return 0;
}
static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index)
{
u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(index));
/* Select the HS PHY interface */
switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) {
@ -669,7 +687,7 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
} else if (dwc->hsphy_interface &&
!strncmp(dwc->hsphy_interface, "ulpi", 4)) {
reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg);
} else {
/* Relying on default value. */
if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI))
@ -727,7 +745,35 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
if (dwc->ulpi_ext_vbus_drv)
reg |= DWC3_GUSB2PHYCFG_ULPIEXTVBUSDRV;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg);
return 0;
}
/**
* dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
* @dwc: Pointer to our controller context structure
*
* Returns 0 on success. The USB PHY interfaces are configured but not
* initialized. The PHY interfaces and the PHYs get initialized together with
* the core in dwc3_core_init.
*/
static int dwc3_phy_setup(struct dwc3 *dwc)
{
int i;
int ret;
for (i = 0; i < dwc->num_usb3_ports; i++) {
ret = dwc3_ss_phy_setup(dwc, i);
if (ret)
return ret;
}
for (i = 0; i < dwc->num_usb2_ports; i++) {
ret = dwc3_hs_phy_setup(dwc, i);
if (ret)
return ret;
}
return 0;
}
@ -735,23 +781,34 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
static int dwc3_phy_init(struct dwc3 *dwc)
{
int ret;
int i;
int j;
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;
for (i = 0; i < dwc->num_usb2_ports; i++) {
ret = phy_init(dwc->usb2_generic_phy[i]);
if (ret < 0)
goto err_exit_usb2_phy;
}
ret = phy_init(dwc->usb3_generic_phy);
if (ret < 0)
goto err_exit_usb2_phy;
for (j = 0; j < dwc->num_usb3_ports; j++) {
ret = phy_init(dwc->usb3_generic_phy[j]);
if (ret < 0)
goto err_exit_usb3_phy;
}
return 0;
err_exit_usb3_phy:
while (--j >= 0)
phy_exit(dwc->usb3_generic_phy[j]);
err_exit_usb2_phy:
phy_exit(dwc->usb2_generic_phy);
err_shutdown_usb3_phy:
while (--i >= 0)
phy_exit(dwc->usb2_generic_phy[i]);
usb_phy_shutdown(dwc->usb3_phy);
usb_phy_shutdown(dwc->usb2_phy);
@ -760,8 +817,13 @@ err_shutdown_usb3_phy:
static void dwc3_phy_exit(struct dwc3 *dwc)
{
phy_exit(dwc->usb3_generic_phy);
phy_exit(dwc->usb2_generic_phy);
int i;
for (i = 0; i < dwc->num_usb3_ports; i++)
phy_exit(dwc->usb3_generic_phy[i]);
for (i = 0; i < dwc->num_usb2_ports; i++)
phy_exit(dwc->usb2_generic_phy[i]);
usb_phy_shutdown(dwc->usb3_phy);
usb_phy_shutdown(dwc->usb2_phy);
@ -770,23 +832,34 @@ static void dwc3_phy_exit(struct dwc3 *dwc)
static int dwc3_phy_power_on(struct dwc3 *dwc)
{
int ret;
int i;
int j;
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;
for (i = 0; i < dwc->num_usb2_ports; i++) {
ret = phy_power_on(dwc->usb2_generic_phy[i]);
if (ret < 0)
goto err_power_off_usb2_phy;
}
ret = phy_power_on(dwc->usb3_generic_phy);
if (ret < 0)
goto err_power_off_usb2_phy;
for (j = 0; j < dwc->num_usb3_ports; j++) {
ret = phy_power_on(dwc->usb3_generic_phy[j]);
if (ret < 0)
goto err_power_off_usb3_phy;
}
return 0;
err_power_off_usb3_phy:
while (--j >= 0)
phy_power_off(dwc->usb3_generic_phy[j]);
err_power_off_usb2_phy:
phy_power_off(dwc->usb2_generic_phy);
err_suspend_usb3_phy:
while (--i >= 0)
phy_power_off(dwc->usb2_generic_phy[i]);
usb_phy_set_suspend(dwc->usb3_phy, 1);
usb_phy_set_suspend(dwc->usb2_phy, 1);
@ -795,8 +868,13 @@ err_suspend_usb3_phy:
static void dwc3_phy_power_off(struct dwc3 *dwc)
{
phy_power_off(dwc->usb3_generic_phy);
phy_power_off(dwc->usb2_generic_phy);
int i;
for (i = 0; i < dwc->num_usb3_ports; i++)
phy_power_off(dwc->usb3_generic_phy[i]);
for (i = 0; i < dwc->num_usb2_ports; i++)
phy_power_off(dwc->usb2_generic_phy[i]);
usb_phy_set_suspend(dwc->usb3_phy, 1);
usb_phy_set_suspend(dwc->usb2_phy, 1);
@ -1306,10 +1384,13 @@ static int dwc3_core_init(struct dwc3 *dwc)
if (dwc->parkmode_disable_hs_quirk)
reg |= DWC3_GUCTL1_PARKMODE_DISABLE_HS;
if (DWC3_VER_IS_WITHIN(DWC3, 290A, ANY) &&
(dwc->maximum_speed == USB_SPEED_HIGH ||
dwc->maximum_speed == USB_SPEED_FULL))
reg |= DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK;
if (DWC3_VER_IS_WITHIN(DWC3, 290A, ANY)) {
if (dwc->maximum_speed == USB_SPEED_FULL ||
dwc->maximum_speed == USB_SPEED_HIGH)
reg |= DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK;
else
reg &= ~DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK;
}
dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
}
@ -1344,7 +1425,9 @@ static int dwc3_core_get_phy(struct dwc3 *dwc)
{
struct device *dev = dwc->dev;
struct device_node *node = dev->of_node;
char phy_name[9];
int ret;
u8 i;
if (node) {
dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
@ -1370,22 +1453,38 @@ static int dwc3_core_get_phy(struct dwc3 *dwc)
return dev_err_probe(dev, ret, "no usb3 phy configured\n");
}
dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy");
if (IS_ERR(dwc->usb2_generic_phy)) {
ret = PTR_ERR(dwc->usb2_generic_phy);
if (ret == -ENOSYS || ret == -ENODEV)
dwc->usb2_generic_phy = NULL;
for (i = 0; i < dwc->num_usb2_ports; i++) {
if (dwc->num_usb2_ports == 1)
snprintf(phy_name, sizeof(phy_name), "usb2-phy");
else
return dev_err_probe(dev, ret, "no usb2 phy configured\n");
snprintf(phy_name, sizeof(phy_name), "usb2-%u", i);
dwc->usb2_generic_phy[i] = devm_phy_get(dev, phy_name);
if (IS_ERR(dwc->usb2_generic_phy[i])) {
ret = PTR_ERR(dwc->usb2_generic_phy[i]);
if (ret == -ENOSYS || ret == -ENODEV)
dwc->usb2_generic_phy[i] = NULL;
else
return dev_err_probe(dev, ret, "failed to lookup phy %s\n",
phy_name);
}
}
dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy");
if (IS_ERR(dwc->usb3_generic_phy)) {
ret = PTR_ERR(dwc->usb3_generic_phy);
if (ret == -ENOSYS || ret == -ENODEV)
dwc->usb3_generic_phy = NULL;
for (i = 0; i < dwc->num_usb3_ports; i++) {
if (dwc->num_usb3_ports == 1)
snprintf(phy_name, sizeof(phy_name), "usb3-phy");
else
return dev_err_probe(dev, ret, "no usb3 phy configured\n");
snprintf(phy_name, sizeof(phy_name), "usb3-%u", i);
dwc->usb3_generic_phy[i] = devm_phy_get(dev, phy_name);
if (IS_ERR(dwc->usb3_generic_phy[i])) {
ret = PTR_ERR(dwc->usb3_generic_phy[i]);
if (ret == -ENOSYS || ret == -ENODEV)
dwc->usb3_generic_phy[i] = NULL;
else
return dev_err_probe(dev, ret, "failed to lookup phy %s\n",
phy_name);
}
}
return 0;
@ -1395,6 +1494,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
{
struct device *dev = dwc->dev;
int ret;
int i;
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
@ -1402,8 +1502,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, false);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb3_generic_phy[0], PHY_MODE_USB_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret)
@ -1414,8 +1514,10 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, true);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
for (i = 0; i < dwc->num_usb2_ports; i++)
phy_set_mode(dwc->usb2_generic_phy[i], PHY_MODE_USB_HOST);
for (i = 0; i < dwc->num_usb3_ports; i++)
phy_set_mode(dwc->usb3_generic_phy[i], PHY_MODE_USB_HOST);
ret = dwc3_host_init(dwc);
if (ret)
@ -1867,10 +1969,60 @@ static int dwc3_get_clocks(struct dwc3 *dwc)
return 0;
}
static int dwc3_get_num_ports(struct dwc3 *dwc)
{
void __iomem *base;
u8 major_revision;
u32 offset;
u32 val;
/*
* Remap xHCI address space to access XHCI ext cap regs since it is
* needed to get information on number of ports present.
*/
base = ioremap(dwc->xhci_resources[0].start,
resource_size(&dwc->xhci_resources[0]));
if (!base)
return -ENOMEM;
offset = 0;
do {
offset = xhci_find_next_ext_cap(base, offset,
XHCI_EXT_CAPS_PROTOCOL);
if (!offset)
break;
val = readl(base + offset);
major_revision = XHCI_EXT_PORT_MAJOR(val);
val = readl(base + offset + 0x08);
if (major_revision == 0x03) {
dwc->num_usb3_ports += XHCI_EXT_PORT_COUNT(val);
} else if (major_revision <= 0x02) {
dwc->num_usb2_ports += XHCI_EXT_PORT_COUNT(val);
} else {
dev_warn(dwc->dev, "unrecognized port major revision %d\n",
major_revision);
}
} while (1);
dev_dbg(dwc->dev, "hs-ports: %u ss-ports: %u\n",
dwc->num_usb2_ports, dwc->num_usb3_ports);
iounmap(base);
if (dwc->num_usb2_ports > DWC3_USB2_MAX_PORTS ||
dwc->num_usb3_ports > DWC3_USB3_MAX_PORTS)
return -EINVAL;
return 0;
}
static int dwc3_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res, dwc_res;
unsigned int hw_mode;
void __iomem *regs;
struct dwc3 *dwc;
int ret;
@ -1954,6 +2106,20 @@ static int dwc3_probe(struct platform_device *pdev)
goto err_disable_clks;
}
/*
* Currently only DWC3 controllers that are host-only capable
* can have more than one port.
*/
hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
if (hw_mode == DWC3_GHWPARAMS0_MODE_HOST) {
ret = dwc3_get_num_ports(dwc);
if (ret)
goto err_disable_clks;
} else {
dwc->num_usb2_ports = 1;
dwc->num_usb3_ports = 1;
}
spin_lock_init(&dwc->lock);
mutex_init(&dwc->mutex);
@ -2086,6 +2252,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
{
unsigned long flags;
u32 reg;
int i;
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
@ -2104,17 +2271,21 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
/* Let controller to suspend HSPHY before PHY driver suspends */
if (dwc->dis_u2_susphy_quirk ||
dwc->dis_enblslpm_quirk) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
reg |= DWC3_GUSB2PHYCFG_ENBLSLPM |
DWC3_GUSB2PHYCFG_SUSPHY;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
for (i = 0; i < dwc->num_usb2_ports; i++) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i));
reg |= DWC3_GUSB2PHYCFG_ENBLSLPM |
DWC3_GUSB2PHYCFG_SUSPHY;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg);
}
/* Give some time for USB2 PHY to suspend */
usleep_range(5000, 6000);
}
phy_pm_runtime_put_sync(dwc->usb2_generic_phy);
phy_pm_runtime_put_sync(dwc->usb3_generic_phy);
for (i = 0; i < dwc->num_usb2_ports; i++)
phy_pm_runtime_put_sync(dwc->usb2_generic_phy[i]);
for (i = 0; i < dwc->num_usb3_ports; i++)
phy_pm_runtime_put_sync(dwc->usb3_generic_phy[i]);
break;
case DWC3_GCTL_PRTCAP_OTG:
/* do nothing during runtime_suspend */
@ -2144,6 +2315,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
unsigned long flags;
int ret;
u32 reg;
int i;
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
@ -2163,17 +2335,21 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
break;
}
/* Restore GUSB2PHYCFG bits that were modified in suspend */
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
if (dwc->dis_u2_susphy_quirk)
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
for (i = 0; i < dwc->num_usb2_ports; i++) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i));
if (dwc->dis_u2_susphy_quirk)
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
if (dwc->dis_enblslpm_quirk)
reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
if (dwc->dis_enblslpm_quirk)
reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg);
}
phy_pm_runtime_get_sync(dwc->usb2_generic_phy);
phy_pm_runtime_get_sync(dwc->usb3_generic_phy);
for (i = 0; i < dwc->num_usb2_ports; i++)
phy_pm_runtime_get_sync(dwc->usb2_generic_phy[i]);
for (i = 0; i < dwc->num_usb3_ports; i++)
phy_pm_runtime_get_sync(dwc->usb3_generic_phy[i]);
break;
case DWC3_GCTL_PRTCAP_OTG:
/* nothing to do on runtime_resume */

View File

@ -33,6 +33,13 @@
#include <linux/power_supply.h>
/*
* DWC3 Multiport controllers support up to 15 High-Speed PHYs
* and 4 SuperSpeed PHYs.
*/
#define DWC3_USB2_MAX_PORTS 15
#define DWC3_USB3_MAX_PORTS 4
#define DWC3_MSG_MAX 500
/* Global constants */
@ -1037,8 +1044,10 @@ struct dwc3_scratchpad_array {
* @usb_psy: pointer to power supply interface.
* @usb2_phy: pointer to USB2 PHY
* @usb3_phy: pointer to USB3 PHY
* @usb2_generic_phy: pointer to USB2 PHY
* @usb3_generic_phy: pointer to USB3 PHY
* @usb2_generic_phy: pointer to array of USB2 PHYs
* @usb3_generic_phy: pointer to array of USB3 PHYs
* @num_usb2_ports: number of USB2 ports
* @num_usb3_ports: number of USB3 ports
* @phys_ready: flag to indicate that PHYs are ready
* @ulpi: pointer to ulpi interface
* @ulpi_ready: flag to indicate that ULPI is initialized
@ -1184,8 +1193,11 @@ struct dwc3 {
struct usb_phy *usb2_phy;
struct usb_phy *usb3_phy;
struct phy *usb2_generic_phy;
struct phy *usb3_generic_phy;
struct phy *usb2_generic_phy[DWC3_USB2_MAX_PORTS];
struct phy *usb3_generic_phy[DWC3_USB3_MAX_PORTS];
u8 num_usb2_ports;
u8 num_usb3_ports;
bool phys_ready;

View File

@ -331,6 +331,7 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
u32 reg;
int id;
unsigned long flags;
int i;
if (dwc->dr_mode != USB_DR_MODE_OTG)
return;
@ -386,9 +387,12 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
} else {
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, true);
if (dwc->usb2_generic_phy)
phy_set_mode(dwc->usb2_generic_phy,
PHY_MODE_USB_HOST);
for (i = 0; i < dwc->num_usb2_ports; i++) {
if (dwc->usb2_generic_phy[i]) {
phy_set_mode(dwc->usb2_generic_phy[i],
PHY_MODE_USB_HOST);
}
}
}
break;
case DWC3_OTG_ROLE_DEVICE:
@ -400,9 +404,8 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, false);
if (dwc->usb2_generic_phy)
phy_set_mode(dwc->usb2_generic_phy,
PHY_MODE_USB_DEVICE);
if (dwc->usb2_generic_phy[0])
phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret)
dev_err(dwc->dev, "failed to initialize peripheral\n");

View File

@ -169,6 +169,12 @@ static const struct dwc3_exynos_driverdata exynos850_drvdata = {
.suspend_clk_idx = -1,
};
static const struct dwc3_exynos_driverdata gs101_drvdata = {
.clk_names = { "bus_early", "susp_clk", "link_aclk", "link_pclk" },
.num_clks = 4,
.suspend_clk_idx = 1,
};
static const struct of_device_id exynos_dwc3_match[] = {
{
.compatible = "samsung,exynos5250-dwusb3",
@ -182,12 +188,14 @@ static const struct of_device_id exynos_dwc3_match[] = {
}, {
.compatible = "samsung,exynos850-dwusb3",
.data = &exynos850_drvdata,
}, {
.compatible = "google,gs101-dwusb3",
.data = &gs101_drvdata,
}, {
}
};
MODULE_DEVICE_TABLE(of, exynos_dwc3_match);
#ifdef CONFIG_PM_SLEEP
static int dwc3_exynos_suspend(struct device *dev)
{
struct dwc3_exynos *exynos = dev_get_drvdata(dev);
@ -230,14 +238,8 @@ static int dwc3_exynos_resume(struct device *dev)
return 0;
}
static const struct dev_pm_ops dwc3_exynos_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(dwc3_exynos_suspend, dwc3_exynos_resume)
};
#define DEV_PM_OPS (&dwc3_exynos_dev_pm_ops)
#else
#define DEV_PM_OPS NULL
#endif /* CONFIG_PM_SLEEP */
static DEFINE_SIMPLE_DEV_PM_OPS(dwc3_exynos_dev_pm_ops,
dwc3_exynos_suspend, dwc3_exynos_resume);
static struct platform_driver dwc3_exynos_driver = {
.probe = dwc3_exynos_probe,
@ -245,7 +247,7 @@ static struct platform_driver dwc3_exynos_driver = {
.driver = {
.name = "exynos-dwc3",
.of_match_table = exynos_dwc3_match,
.pm = DEV_PM_OPS,
.pm = pm_sleep_ptr(&dwc3_exynos_dev_pm_ops),
},
};

View File

@ -8,6 +8,7 @@
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*/
#include <linux/dmi.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@ -220,6 +221,7 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc,
if (pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
struct gpio_desc *gpio;
const char *bios_ver;
int ret;
/* On BYT the FW does not always enable the refclock */
@ -277,8 +279,12 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc,
* detection. These can be identified by them _not_
* using the standard ACPI battery and ac drivers.
*/
bios_ver = dmi_get_system_info(DMI_BIOS_VERSION);
if (acpi_dev_present("INT33FD", "1", 2) &&
acpi_quirk_skip_acpi_ac_and_battery()) {
acpi_quirk_skip_acpi_ac_and_battery() &&
/* Lenovo Yoga Tablet 2 Pro 1380 uses LC824206XA instead */
!(bios_ver &&
strstarts(bios_ver, "BLADE_21.X64.0005.R00.1504101516"))) {
dev_info(&pdev->dev, "Using TUSB1211 phy for charger detection\n");
swnode = &dwc3_pci_intel_phy_charger_detect_swnode;
}

View File

@ -36,7 +36,6 @@
#define PIPE3_PHYSTATUS_SW BIT(3)
#define PIPE_UTMI_CLK_DIS BIT(8)
#define PWR_EVNT_IRQ_STAT_REG 0x58
#define PWR_EVNT_LPM_IN_L2_MASK BIT(4)
#define PWR_EVNT_LPM_OUT_L2_MASK BIT(5)
@ -52,6 +51,24 @@
#define APPS_USB_AVG_BW 0
#define APPS_USB_PEAK_BW MBps_to_icc(40)
/* Qualcomm SoCs with multiport support has up to 4 ports */
#define DWC3_QCOM_MAX_PORTS 4
static const u32 pwr_evnt_irq_stat_reg[DWC3_QCOM_MAX_PORTS] = {
0x58,
0x1dc,
0x228,
0x238,
};
struct dwc3_qcom_port {
int qusb2_phy_irq;
int dp_hs_phy_irq;
int dm_hs_phy_irq;
int ss_phy_irq;
enum usb_device_speed usb2_speed;
};
struct dwc3_qcom {
struct device *dev;
void __iomem *qscratch_base;
@ -59,12 +76,8 @@ struct dwc3_qcom {
struct clk **clks;
int num_clocks;
struct reset_control *resets;
int qusb2_phy_irq;
int dp_hs_phy_irq;
int dm_hs_phy_irq;
int ss_phy_irq;
enum usb_device_speed usb2_speed;
struct dwc3_qcom_port ports[DWC3_QCOM_MAX_PORTS];
u8 num_ports;
struct extcon_dev *edev;
struct extcon_dev *host_edev;
@ -303,7 +316,7 @@ static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom)
return dwc->xhci;
}
static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom)
static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom, int port_index)
{
struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
struct usb_device *udev;
@ -314,14 +327,8 @@ static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom)
*/
hcd = platform_get_drvdata(dwc->xhci);
/*
* It is possible to query the speed of all children of
* USB2.0 root hub via usb_hub_for_each_child(). DWC3 code
* currently supports only 1 port per controller. So
* this is sufficient.
*/
#ifdef CONFIG_USB
udev = usb_hub_find_child(hcd->self.root_hub, 1);
udev = usb_hub_find_child(hcd->self.root_hub, port_index + 1);
#else
udev = NULL;
#endif
@ -352,26 +359,26 @@ static void dwc3_qcom_disable_wakeup_irq(int irq)
disable_irq_nosync(irq);
}
static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom)
static void dwc3_qcom_disable_port_interrupts(struct dwc3_qcom_port *port)
{
dwc3_qcom_disable_wakeup_irq(qcom->qusb2_phy_irq);
dwc3_qcom_disable_wakeup_irq(port->qusb2_phy_irq);
if (qcom->usb2_speed == USB_SPEED_LOW) {
dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq);
} else if ((qcom->usb2_speed == USB_SPEED_HIGH) ||
(qcom->usb2_speed == USB_SPEED_FULL)) {
dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq);
if (port->usb2_speed == USB_SPEED_LOW) {
dwc3_qcom_disable_wakeup_irq(port->dm_hs_phy_irq);
} else if ((port->usb2_speed == USB_SPEED_HIGH) ||
(port->usb2_speed == USB_SPEED_FULL)) {
dwc3_qcom_disable_wakeup_irq(port->dp_hs_phy_irq);
} else {
dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq);
dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq);
dwc3_qcom_disable_wakeup_irq(port->dp_hs_phy_irq);
dwc3_qcom_disable_wakeup_irq(port->dm_hs_phy_irq);
}
dwc3_qcom_disable_wakeup_irq(qcom->ss_phy_irq);
dwc3_qcom_disable_wakeup_irq(port->ss_phy_irq);
}
static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
static void dwc3_qcom_enable_port_interrupts(struct dwc3_qcom_port *port)
{
dwc3_qcom_enable_wakeup_irq(qcom->qusb2_phy_irq, 0);
dwc3_qcom_enable_wakeup_irq(port->qusb2_phy_irq, 0);
/*
* Configure DP/DM line interrupts based on the USB2 device attached to
@ -382,21 +389,37 @@ static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
* DP and DM lines as rising edge to detect HS/HS/LS device connect scenario.
*/
if (qcom->usb2_speed == USB_SPEED_LOW) {
dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq,
IRQ_TYPE_EDGE_FALLING);
} else if ((qcom->usb2_speed == USB_SPEED_HIGH) ||
(qcom->usb2_speed == USB_SPEED_FULL)) {
dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq,
IRQ_TYPE_EDGE_FALLING);
if (port->usb2_speed == USB_SPEED_LOW) {
dwc3_qcom_enable_wakeup_irq(port->dm_hs_phy_irq,
IRQ_TYPE_EDGE_FALLING);
} else if ((port->usb2_speed == USB_SPEED_HIGH) ||
(port->usb2_speed == USB_SPEED_FULL)) {
dwc3_qcom_enable_wakeup_irq(port->dp_hs_phy_irq,
IRQ_TYPE_EDGE_FALLING);
} else {
dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq,
IRQ_TYPE_EDGE_RISING);
dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq,
IRQ_TYPE_EDGE_RISING);
dwc3_qcom_enable_wakeup_irq(port->dp_hs_phy_irq,
IRQ_TYPE_EDGE_RISING);
dwc3_qcom_enable_wakeup_irq(port->dm_hs_phy_irq,
IRQ_TYPE_EDGE_RISING);
}
dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq, 0);
dwc3_qcom_enable_wakeup_irq(port->ss_phy_irq, 0);
}
static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom)
{
int i;
for (i = 0; i < qcom->num_ports; i++)
dwc3_qcom_disable_port_interrupts(&qcom->ports[i]);
}
static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
{
int i;
for (i = 0; i < qcom->num_ports; i++)
dwc3_qcom_enable_port_interrupts(&qcom->ports[i]);
}
static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup)
@ -407,9 +430,11 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup)
if (qcom->is_suspended)
return 0;
val = readl(qcom->qscratch_base + PWR_EVNT_IRQ_STAT_REG);
if (!(val & PWR_EVNT_LPM_IN_L2_MASK))
dev_err(qcom->dev, "HS-PHY not in L2\n");
for (i = 0; i < qcom->num_ports; i++) {
val = readl(qcom->qscratch_base + pwr_evnt_irq_stat_reg[i]);
if (!(val & PWR_EVNT_LPM_IN_L2_MASK))
dev_err(qcom->dev, "port-%d HS-PHY not in L2\n", i + 1);
}
for (i = qcom->num_clocks - 1; i >= 0; i--)
clk_disable_unprepare(qcom->clks[i]);
@ -423,7 +448,8 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup)
* freezable workqueue.
*/
if (dwc3_qcom_is_host(qcom) && wakeup) {
qcom->usb2_speed = dwc3_qcom_read_usb2_speed(qcom);
for (i = 0; i < qcom->num_ports; i++)
qcom->ports[i].usb2_speed = dwc3_qcom_read_usb2_speed(qcom, i);
dwc3_qcom_enable_interrupts(qcom);
}
@ -457,8 +483,11 @@ static int dwc3_qcom_resume(struct dwc3_qcom *qcom, bool wakeup)
dev_warn(qcom->dev, "failed to enable interconnect: %d\n", ret);
/* Clear existing events from PHY related to L2 in/out */
dwc3_qcom_setbits(qcom->qscratch_base, PWR_EVNT_IRQ_STAT_REG,
PWR_EVNT_LPM_IN_L2_MASK | PWR_EVNT_LPM_OUT_L2_MASK);
for (i = 0; i < qcom->num_ports; i++) {
dwc3_qcom_setbits(qcom->qscratch_base,
pwr_evnt_irq_stat_reg[i],
PWR_EVNT_LPM_IN_L2_MASK | PWR_EVNT_LPM_OUT_L2_MASK);
}
qcom->is_suspended = false;
@ -501,63 +530,123 @@ static void dwc3_qcom_select_utmi_clk(struct dwc3_qcom *qcom)
PIPE_UTMI_CLK_DIS);
}
static int dwc3_qcom_setup_irq(struct platform_device *pdev)
static int dwc3_qcom_request_irq(struct dwc3_qcom *qcom, int irq,
const char *name)
{
int ret;
/* Keep wakeup interrupts disabled until suspend */
ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
qcom_dwc3_resume_irq,
IRQF_ONESHOT | IRQF_NO_AUTOEN,
name, qcom);
if (ret)
dev_err(qcom->dev, "failed to request irq %s: %d\n", name, ret);
return ret;
}
static int dwc3_qcom_setup_port_irq(struct platform_device *pdev, int port_index, bool is_multiport)
{
struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
const char *irq_name;
int irq;
int ret;
if (is_multiport)
irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dp_hs_phy_%d", port_index + 1);
else
irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dp_hs_phy_irq");
if (!irq_name)
return -ENOMEM;
irq = platform_get_irq_byname_optional(pdev, irq_name);
if (irq > 0) {
ret = dwc3_qcom_request_irq(qcom, irq, irq_name);
if (ret)
return ret;
qcom->ports[port_index].dp_hs_phy_irq = irq;
}
if (is_multiport)
irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dm_hs_phy_%d", port_index + 1);
else
irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dm_hs_phy_irq");
if (!irq_name)
return -ENOMEM;
irq = platform_get_irq_byname_optional(pdev, irq_name);
if (irq > 0) {
ret = dwc3_qcom_request_irq(qcom, irq, irq_name);
if (ret)
return ret;
qcom->ports[port_index].dm_hs_phy_irq = irq;
}
if (is_multiport)
irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "ss_phy_%d", port_index + 1);
else
irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "ss_phy_irq");
if (!irq_name)
return -ENOMEM;
irq = platform_get_irq_byname_optional(pdev, irq_name);
if (irq > 0) {
ret = dwc3_qcom_request_irq(qcom, irq, irq_name);
if (ret)
return ret;
qcom->ports[port_index].ss_phy_irq = irq;
}
if (is_multiport)
return 0;
irq = platform_get_irq_byname_optional(pdev, "qusb2_phy");
if (irq > 0) {
/* Keep wakeup interrupts disabled until suspend */
ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
qcom_dwc3_resume_irq,
IRQF_ONESHOT | IRQF_NO_AUTOEN,
"qcom_dwc3 QUSB2", qcom);
if (ret) {
dev_err(qcom->dev, "qusb2_phy_irq failed: %d\n", ret);
ret = dwc3_qcom_request_irq(qcom, irq, "qusb2_phy");
if (ret)
return ret;
}
qcom->qusb2_phy_irq = irq;
qcom->ports[port_index].qusb2_phy_irq = irq;
}
irq = platform_get_irq_byname_optional(pdev, "dp_hs_phy_irq");
if (irq > 0) {
ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
qcom_dwc3_resume_irq,
IRQF_ONESHOT | IRQF_NO_AUTOEN,
"qcom_dwc3 DP_HS", qcom);
if (ret) {
dev_err(qcom->dev, "dp_hs_phy_irq failed: %d\n", ret);
return ret;
}
qcom->dp_hs_phy_irq = irq;
return 0;
}
static int dwc3_qcom_find_num_ports(struct platform_device *pdev)
{
char irq_name[14];
int port_num;
int irq;
irq = platform_get_irq_byname_optional(pdev, "dp_hs_phy_1");
if (irq <= 0)
return 1;
for (port_num = 2; port_num <= DWC3_QCOM_MAX_PORTS; port_num++) {
sprintf(irq_name, "dp_hs_phy_%d", port_num);
irq = platform_get_irq_byname_optional(pdev, irq_name);
if (irq <= 0)
return port_num - 1;
}
irq = platform_get_irq_byname_optional(pdev, "dm_hs_phy_irq");
if (irq > 0) {
ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
qcom_dwc3_resume_irq,
IRQF_ONESHOT | IRQF_NO_AUTOEN,
"qcom_dwc3 DM_HS", qcom);
if (ret) {
dev_err(qcom->dev, "dm_hs_phy_irq failed: %d\n", ret);
return ret;
}
qcom->dm_hs_phy_irq = irq;
}
return DWC3_QCOM_MAX_PORTS;
}
irq = platform_get_irq_byname_optional(pdev, "ss_phy_irq");
if (irq > 0) {
ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
qcom_dwc3_resume_irq,
IRQF_ONESHOT | IRQF_NO_AUTOEN,
"qcom_dwc3 SS", qcom);
if (ret) {
dev_err(qcom->dev, "ss_phy_irq failed: %d\n", ret);
static int dwc3_qcom_setup_irq(struct platform_device *pdev)
{
struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
bool is_multiport;
int ret;
int i;
qcom->num_ports = dwc3_qcom_find_num_ports(pdev);
is_multiport = (qcom->num_ports > 1);
for (i = 0; i < qcom->num_ports; i++) {
ret = dwc3_qcom_setup_port_irq(pdev, i, is_multiport);
if (ret)
return ret;
}
qcom->ss_phy_irq = irq;
}
return 0;

View File

@ -1699,7 +1699,6 @@ static int __dwc3_gadget_get_frame(struct dwc3 *dwc)
*/
static int __dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool interrupt)
{
struct dwc3 *dwc = dep->dwc;
struct dwc3_gadget_ep_cmd_params params;
u32 cmd;
int ret;
@ -1724,8 +1723,7 @@ static int __dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool int
dep->resource_index = 0;
if (!interrupt) {
if (!DWC3_IP_IS(DWC3) || DWC3_VER_IS_PRIOR(DWC3, 310A))
mdelay(1);
mdelay(1);
dep->flags &= ~DWC3_EP_TRANSFER_STARTED;
} else if (!ret) {
dep->flags |= DWC3_EP_END_TRANSFER_PENDING;

View File

@ -1,10 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
# This setup links the different object files into one single
# module so we don't have to EXPORT() a lot of internal symbols
# or create unnecessary submodules.
fotg210-objs-y += fotg210-core.o
fotg210-objs-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o
fotg210-objs-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o
fotg210-objs := $(fotg210-objs-y)
obj-$(CONFIG_USB_FOTG210) += fotg210.o
fotg210-y := fotg210-core.o
fotg210-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o
fotg210-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o

View File

@ -95,6 +95,7 @@ static int fotg210_gemini_init(struct fotg210 *fotg, struct resource *res,
/**
* fotg210_vbus() - Called by gadget driver to enable/disable VBUS
* @fotg: pointer to a private fotg210 object
* @enable: true to enable VBUS, false to disable VBUS
*/
void fotg210_vbus(struct fotg210 *fotg, bool enable)

View File

@ -45,6 +45,7 @@
#include "configfs.h"
#define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */
#define MAX_ALT_SETTINGS 2 /* Allow up to 2 alt settings to be set. */
#define DMABUF_ENQUEUE_TIMEOUT_MS 5000
@ -82,6 +83,7 @@ struct ffs_function {
short *interfaces_nums;
struct usb_function function;
int cur_alt[MAX_CONFIG_INTERFACES];
};
@ -105,6 +107,7 @@ static int __must_check ffs_func_eps_enable(struct ffs_function *func);
static int ffs_func_bind(struct usb_configuration *,
struct usb_function *);
static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned);
static int ffs_func_get_alt(struct usb_function *f, unsigned int intf);
static void ffs_func_disable(struct usb_function *);
static int ffs_func_setup(struct usb_function *,
const struct usb_ctrlrequest *);
@ -3712,6 +3715,15 @@ static void ffs_reset_work(struct work_struct *work)
ffs_data_reset(ffs);
}
static int ffs_func_get_alt(struct usb_function *f,
unsigned int interface)
{
struct ffs_function *func = ffs_func_from_usb(f);
int intf = ffs_func_revmap_intf(func, interface);
return (intf < 0) ? intf : func->cur_alt[interface];
}
static int ffs_func_set_alt(struct usb_function *f,
unsigned interface, unsigned alt)
{
@ -3719,6 +3731,9 @@ static int ffs_func_set_alt(struct usb_function *f,
struct ffs_data *ffs = func->ffs;
int ret = 0, intf;
if (alt > MAX_ALT_SETTINGS)
return -EINVAL;
if (alt != (unsigned)-1) {
intf = ffs_func_revmap_intf(func, interface);
if (intf < 0)
@ -3746,8 +3761,10 @@ static int ffs_func_set_alt(struct usb_function *f,
ffs->func = func;
ret = ffs_func_eps_enable(func);
if (ret >= 0)
if (ret >= 0) {
ffs_event_add(ffs, FUNCTIONFS_ENABLE);
func->cur_alt[interface] = alt;
}
return ret;
}
@ -4074,6 +4091,7 @@ static struct usb_function *ffs_alloc(struct usb_function_instance *fi)
func->function.bind = ffs_func_bind;
func->function.unbind = ffs_func_unbind;
func->function.set_alt = ffs_func_set_alt;
func->function.get_alt = ffs_func_get_alt;
func->function.disable = ffs_func_disable;
func->function.setup = ffs_func_setup;
func->function.req_match = ffs_func_req_match;

View File

@ -1029,9 +1029,9 @@ static inline int hidg_get_minor(void)
{
int ret;
ret = ida_simple_get(&hidg_ida, 0, 0, GFP_KERNEL);
ret = ida_alloc(&hidg_ida, GFP_KERNEL);
if (ret >= HIDG_MINORS) {
ida_simple_remove(&hidg_ida, ret);
ida_free(&hidg_ida, ret);
ret = -ENODEV;
}
@ -1176,7 +1176,7 @@ static const struct config_item_type hid_func_type = {
static inline void hidg_put_minor(int minor)
{
ida_simple_remove(&hidg_ida, minor);
ida_free(&hidg_ida, minor);
}
static void hidg_free_inst(struct usb_function_instance *f)

View File

@ -1312,9 +1312,9 @@ static inline int gprinter_get_minor(void)
{
int ret;
ret = ida_simple_get(&printer_ida, 0, 0, GFP_KERNEL);
ret = ida_alloc(&printer_ida, GFP_KERNEL);
if (ret >= PRINTER_MINORS) {
ida_simple_remove(&printer_ida, ret);
ida_free(&printer_ida, ret);
ret = -ENODEV;
}
@ -1323,7 +1323,7 @@ static inline int gprinter_get_minor(void)
static inline void gprinter_put_minor(int minor)
{
ida_simple_remove(&printer_ida, minor);
ida_free(&printer_ida, minor);
}
static int gprinter_setup(int);

View File

@ -869,12 +869,12 @@ EXPORT_SYMBOL_GPL(rndis_msg_parser);
static inline int rndis_get_nr(void)
{
return ida_simple_get(&rndis_ida, 0, 1000, GFP_KERNEL);
return ida_alloc_max(&rndis_ida, 999, GFP_KERNEL);
}
static inline void rndis_put_nr(int nr)
{
ida_simple_remove(&rndis_ida, nr);
ida_free(&rndis_ida, nr);
}
struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v)

View File

@ -57,13 +57,13 @@ struct uac_rtd_params {
/* Volume/Mute controls and their state */
int fu_id; /* Feature Unit ID */
struct snd_kcontrol *snd_kctl_volume;
struct snd_kcontrol *snd_kctl_mute;
struct snd_ctl_elem_id snd_kctl_volume_id;
struct snd_ctl_elem_id snd_kctl_mute_id;
s16 volume_min, volume_max, volume_res;
s16 volume;
int mute;
struct snd_kcontrol *snd_kctl_rate; /* read-only current rate */
struct snd_ctl_elem_id snd_kctl_rate_id; /* read-only current rate */
int srate; /* selected samplerate */
int active; /* playback/capture running */
@ -494,14 +494,13 @@ static inline void free_ep_fback(struct uac_rtd_params *prm, struct usb_ep *ep)
static void set_active(struct uac_rtd_params *prm, bool active)
{
// notifying through the Rate ctrl
struct snd_kcontrol *kctl = prm->snd_kctl_rate;
unsigned long flags;
spin_lock_irqsave(&prm->lock, flags);
if (prm->active != active) {
prm->active = active;
snd_ctl_notify(prm->uac->card, SNDRV_CTL_EVENT_MASK_VALUE,
&kctl->id);
&prm->snd_kctl_rate_id);
}
spin_unlock_irqrestore(&prm->lock, flags);
}
@ -807,7 +806,7 @@ int u_audio_set_volume(struct g_audio *audio_dev, int playback, s16 val)
if (change)
snd_ctl_notify(uac->card, SNDRV_CTL_EVENT_MASK_VALUE,
&prm->snd_kctl_volume->id);
&prm->snd_kctl_volume_id);
return 0;
}
@ -856,7 +855,7 @@ int u_audio_set_mute(struct g_audio *audio_dev, int playback, int val)
if (change)
snd_ctl_notify(uac->card, SNDRV_CTL_EVENT_MASK_VALUE,
&prm->snd_kctl_mute->id);
&prm->snd_kctl_mute_id);
return 0;
}
@ -1243,7 +1242,7 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
if (err < 0)
goto snd_fail;
strscpy(pcm->name, pcm_name, sizeof(pcm->name));
strscpy(pcm->name, pcm_name);
pcm->private_data = uac;
uac->pcm = pcm;
@ -1257,7 +1256,7 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
if ((c_chmask && g_audio->in_ep_fback)
|| (p_chmask && params->p_fu.id)
|| (c_chmask && params->c_fu.id))
strscpy(card->mixername, card_name, sizeof(card->driver));
strscpy(card->mixername, card_name);
if (c_chmask && g_audio->in_ep_fback) {
kctl = snd_ctl_new1(&u_audio_controls[UAC_FBACK_CTRL],
@ -1331,7 +1330,7 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
err = snd_ctl_add(card, kctl);
if (err < 0)
goto snd_fail;
prm->snd_kctl_mute = kctl;
prm->snd_kctl_mute_id = kctl->id;
prm->mute = 0;
}
@ -1359,7 +1358,7 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
err = snd_ctl_add(card, kctl);
if (err < 0)
goto snd_fail;
prm->snd_kctl_volume = kctl;
prm->snd_kctl_volume_id = kctl->id;
prm->volume = fu->volume_max;
prm->volume_max = fu->volume_max;
prm->volume_min = fu->volume_min;
@ -1383,12 +1382,13 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
err = snd_ctl_add(card, kctl);
if (err < 0)
goto snd_fail;
prm->snd_kctl_rate = kctl;
prm->snd_kctl_rate_id = kctl->id;
}
strscpy(card->driver, card_name, sizeof(card->driver));
strscpy(card->shortname, card_name, sizeof(card->shortname));
sprintf(card->longname, "%s %i", card_name, card->dev->id);
strscpy(card->driver, card_name);
strscpy(card->shortname, card_name);
snprintf(card->longname, sizeof(card->longname), "%s %i",
card_name, card->dev->id);
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
NULL, 0, BUFF_SIZE_MAX);
@ -1420,6 +1420,8 @@ void g_audio_cleanup(struct g_audio *g_audio)
return;
uac = g_audio->uac;
g_audio->uac = NULL;
card = uac->card;
if (card)
snd_card_free_when_closed(card);

View File

@ -1032,7 +1032,7 @@ int gether_set_ifname(struct net_device *net, const char *name, int len)
if (!p || p[1] != 'd' || strchr(p + 2, '%'))
return -EINVAL;
strncpy(net->name, tmp, sizeof(net->name));
strscpy(net->name, tmp);
dev->ifname_set = true;
return 0;

View File

@ -13,6 +13,7 @@
#include "uvc_configfs.h"
#include <linux/sort.h>
#include <linux/usb/uvc.h>
#include <linux/usb/video.h>
/* -----------------------------------------------------------------------------
@ -2260,6 +2261,8 @@ static ssize_t uvcg_uncompressed_guid_format_store(struct config_item *item,
struct f_uvc_opts *opts;
struct config_item *opts_item;
struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex;
const struct uvc_format_desc *format;
u8 tmpguidFormat[sizeof(ch->desc.guidFormat)];
int ret;
mutex_lock(su_mutex); /* for navigating configfs hierarchy */
@ -2273,7 +2276,16 @@ static ssize_t uvcg_uncompressed_guid_format_store(struct config_item *item,
goto end;
}
memcpy(ch->desc.guidFormat, page,
memcpy(tmpguidFormat, page,
min(sizeof(tmpguidFormat), len));
format = uvc_format_by_guid(tmpguidFormat);
if (!format) {
ret = -EINVAL;
goto end;
}
memcpy(ch->desc.guidFormat, tmpguidFormat,
min(sizeof(ch->desc.guidFormat), len));
ret = sizeof(ch->desc.guidFormat);

View File

@ -260,12 +260,26 @@ uvc_v4l2_try_format(struct file *file, void *fh, struct v4l2_format *fmt)
if (!uframe)
return -EINVAL;
fmt->fmt.pix.width = uframe->frame.w_width;
fmt->fmt.pix.height = uframe->frame.w_height;
if (uformat->type == UVCG_UNCOMPRESSED) {
struct uvcg_uncompressed *u =
to_uvcg_uncompressed(&uformat->group.cg_item);
if (!u)
return 0;
v4l2_fill_pixfmt(&fmt->fmt.pix, fmt->fmt.pix.pixelformat,
uframe->frame.w_width, uframe->frame.w_height);
if (fmt->fmt.pix.sizeimage != (uvc_v4l2_get_bytesperline(uformat, uframe) *
uframe->frame.w_height))
return -EINVAL;
} else {
fmt->fmt.pix.width = uframe->frame.w_width;
fmt->fmt.pix.height = uframe->frame.w_height;
fmt->fmt.pix.bytesperline = uvc_v4l2_get_bytesperline(uformat, uframe);
fmt->fmt.pix.sizeimage = uvc_get_frame_size(uformat, uframe);
fmt->fmt.pix.pixelformat = to_uvc_format(uformat)->fcc;
}
fmt->fmt.pix.field = V4L2_FIELD_NONE;
fmt->fmt.pix.bytesperline = uvc_v4l2_get_bytesperline(uformat, uframe);
fmt->fmt.pix.sizeimage = uvc_get_frame_size(uformat, uframe);
fmt->fmt.pix.pixelformat = to_uvc_format(uformat)->fcc;
fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
fmt->fmt.pix.priv = 0;

View File

@ -1426,8 +1426,16 @@ int usb_add_gadget(struct usb_gadget *gadget)
if (ret)
goto err_free_id;
ret = sysfs_create_link(&udc->dev.kobj,
&gadget->dev.kobj, "gadget");
if (ret)
goto err_del_gadget;
return 0;
err_del_gadget:
device_del(&gadget->dev);
err_free_id:
ida_free(&gadget_id_numbers, gadget->id_number);
@ -1536,6 +1544,7 @@ void usb_del_gadget(struct usb_gadget *gadget)
mutex_unlock(&udc_lock);
kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
sysfs_remove_link(&udc->dev.kobj, "gadget");
flush_work(&gadget->work);
device_del(&gadget->dev);
ida_free(&gadget_id_numbers, gadget->id_number);

View File

@ -30,7 +30,7 @@
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/hrtimer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
@ -50,6 +50,8 @@
#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */
#define POWER_BUDGET_3 900 /* in mA */
#define DUMMY_TIMER_INT_NSECS 125000 /* 1 microframe */
static const char driver_name[] = "dummy_hcd";
static const char driver_desc[] = "USB Host+Gadget Emulator";
@ -240,7 +242,7 @@ enum dummy_rh_state {
struct dummy_hcd {
struct dummy *dum;
enum dummy_rh_state rh_state;
struct timer_list timer;
struct hrtimer timer;
u32 port_status;
u32 old_status;
unsigned long re_timeout;
@ -1301,8 +1303,8 @@ static int dummy_urb_enqueue(
urb->error_count = 1; /* mark as a new urb */
/* kick the scheduler, it'll do the rest */
if (!timer_pending(&dum_hcd->timer))
mod_timer(&dum_hcd->timer, jiffies + 1);
if (!hrtimer_active(&dum_hcd->timer))
hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS), HRTIMER_MODE_REL);
done:
spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
@ -1323,7 +1325,7 @@ static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
rc = usb_hcd_check_unlink_urb(hcd, urb, status);
if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING &&
!list_empty(&dum_hcd->urbp_list))
mod_timer(&dum_hcd->timer, jiffies);
hrtimer_start(&dum_hcd->timer, ns_to_ktime(0), HRTIMER_MODE_REL);
spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
return rc;
@ -1777,7 +1779,7 @@ static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
* drivers except that the callbacks are invoked from soft interrupt
* context.
*/
static void dummy_timer(struct timer_list *t)
static enum hrtimer_restart dummy_timer(struct hrtimer *t)
{
struct dummy_hcd *dum_hcd = from_timer(dum_hcd, t, timer);
struct dummy *dum = dum_hcd->dum;
@ -1808,8 +1810,6 @@ static void dummy_timer(struct timer_list *t)
break;
}
/* FIXME if HZ != 1000 this will probably misbehave ... */
/* look at each urb queued by the host side driver */
spin_lock_irqsave(&dum->lock, flags);
@ -1817,7 +1817,7 @@ static void dummy_timer(struct timer_list *t)
dev_err(dummy_dev(dum_hcd),
"timer fired with no URBs pending?\n");
spin_unlock_irqrestore(&dum->lock, flags);
return;
return HRTIMER_NORESTART;
}
dum_hcd->next_frame_urbp = NULL;
@ -1995,10 +1995,12 @@ return_urb:
dum_hcd->udev = NULL;
} else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
/* want a 1 msec delay here */
mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1));
hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS), HRTIMER_MODE_REL);
}
spin_unlock_irqrestore(&dum->lock, flags);
return HRTIMER_NORESTART;
}
/*-------------------------------------------------------------------------*/
@ -2387,7 +2389,7 @@ static int dummy_bus_resume(struct usb_hcd *hcd)
dum_hcd->rh_state = DUMMY_RH_RUNNING;
set_link_state(dum_hcd);
if (!list_empty(&dum_hcd->urbp_list))
mod_timer(&dum_hcd->timer, jiffies);
hrtimer_start(&dum_hcd->timer, ns_to_ktime(0), HRTIMER_MODE_REL);
hcd->state = HC_STATE_RUNNING;
}
spin_unlock_irq(&dum_hcd->dum->lock);
@ -2465,7 +2467,8 @@ static DEVICE_ATTR_RO(urbs);
static int dummy_start_ss(struct dummy_hcd *dum_hcd)
{
timer_setup(&dum_hcd->timer, dummy_timer, 0);
hrtimer_init(&dum_hcd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
dum_hcd->timer.function = dummy_timer;
dum_hcd->rh_state = DUMMY_RH_RUNNING;
dum_hcd->stream_en_ep = 0;
INIT_LIST_HEAD(&dum_hcd->urbp_list);
@ -2494,7 +2497,8 @@ static int dummy_start(struct usb_hcd *hcd)
return dummy_start_ss(dum_hcd);
spin_lock_init(&dum_hcd->dum->lock);
timer_setup(&dum_hcd->timer, dummy_timer, 0);
hrtimer_init(&dum_hcd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
dum_hcd->timer.function = dummy_timer;
dum_hcd->rh_state = DUMMY_RH_RUNNING;
INIT_LIST_HEAD(&dum_hcd->urbp_list);
@ -2513,8 +2517,11 @@ static int dummy_start(struct usb_hcd *hcd)
static void dummy_stop(struct usb_hcd *hcd)
{
device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
hrtimer_cancel(&dum_hcd->timer);
device_remove_file(dummy_dev(dum_hcd), &dev_attr_urbs);
dev_info(dummy_dev(dum_hcd), "stopped\n");
}
/*-------------------------------------------------------------------------*/

View File

@ -1307,7 +1307,7 @@ static int mv_u3d_eps_init(struct mv_u3d *u3d)
/* initialize ep0, ep0 in/out use eps[1] */
ep = &u3d->eps[1];
ep->u3d = u3d;
strncpy(ep->name, "ep0", sizeof(ep->name));
strscpy(ep->name, "ep0");
ep->ep.name = ep->name;
ep->ep.ops = &mv_u3d_ep_ops;
ep->wedge = 0;
@ -1337,7 +1337,7 @@ static int mv_u3d_eps_init(struct mv_u3d *u3d)
ep->ep.caps.dir_out = true;
}
ep->u3d = u3d;
strncpy(ep->name, name, sizeof(ep->name));
strscpy(ep->name, name);
ep->ep.name = ep->name;
ep->ep.caps.type_iso = true;

View File

@ -56,7 +56,6 @@
/* ISO too */
#define USE_ISO
#define DRIVER_DESC "OMAP UDC driver"
#define DRIVER_VERSION "4 October 2004"
#define OMAP_DMA_USB_W2FC_TX0 29
@ -110,7 +109,6 @@ MODULE_PARM_DESC(use_dma, "enable/disable DMA");
static const char driver_name[] = "omap_udc";
static const char driver_desc[] = DRIVER_DESC;
/*-------------------------------------------------------------------------*/
@ -2299,13 +2297,11 @@ static int proc_udc_show(struct seq_file *s, void *_)
spin_lock_irqsave(&udc->lock, flags);
seq_printf(s, "%s, version: " DRIVER_VERSION
seq_printf(s, "OMAP UDC driver, version: " DRIVER_VERSION
#ifdef USE_ISO
" (iso)"
#endif
"%s\n",
driver_desc,
use_dma ? " (dma)" : "");
"%s\n", use_dma ? " (dma)" : "");
tmp = omap_readw(UDC_REV) & 0xff;
seq_printf(s,
@ -2994,6 +2990,6 @@ static struct platform_driver udc_driver = {
module_platform_driver(udc_driver);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_DESCRIPTION("OMAP UDC driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:omap_udc");

View File

@ -430,13 +430,13 @@ static void qh_lines(struct ehci_hcd *ehci, struct ehci_qh *qh,
mark = '/';
}
switch ((scratch >> 8) & 0x03) {
case 0:
case PID_CODE_OUT:
type = "out";
break;
case 1:
case PID_CODE_IN:
type = "in";
break;
case 2:
case PID_CODE_SETUP:
type = "setup";
break;
default:
@ -602,10 +602,10 @@ static unsigned output_buf_tds_dir(char *buf, struct ehci_hcd *ehci,
list_for_each_entry(qtd, &qh->qtd_list, qtd_list) {
temp++;
switch ((hc32_to_cpu(ehci, qtd->hw_token) >> 8) & 0x03) {
case 0:
case PID_CODE_OUT:
type = "out";
continue;
case 1:
case PID_CODE_IN:
type = "in";
continue;
}

View File

@ -159,20 +159,16 @@ static int exynos_ehci_probe(struct platform_device *pdev)
err = exynos_ehci_get_phy(&pdev->dev, exynos_ehci);
if (err)
goto fail_clk;
goto fail_io;
exynos_ehci->clk = devm_clk_get(&pdev->dev, "usbhost");
exynos_ehci->clk = devm_clk_get_enabled(&pdev->dev, "usbhost");
if (IS_ERR(exynos_ehci->clk)) {
dev_err(&pdev->dev, "Failed to get usbhost clock\n");
err = PTR_ERR(exynos_ehci->clk);
goto fail_clk;
goto fail_io;
}
err = clk_prepare_enable(exynos_ehci->clk);
if (err)
goto fail_clk;
hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(hcd->regs)) {
err = PTR_ERR(hcd->regs);
@ -223,8 +219,6 @@ fail_add_hcd:
exynos_ehci_phy_disable(&pdev->dev);
pdev->dev.of_node = exynos_ehci->of_node;
fail_io:
clk_disable_unprepare(exynos_ehci->clk);
fail_clk:
usb_put_hcd(hcd);
return err;
}
@ -240,12 +234,9 @@ static void exynos_ehci_remove(struct platform_device *pdev)
exynos_ehci_phy_disable(&pdev->dev);
clk_disable_unprepare(exynos_ehci->clk);
usb_put_hcd(hcd);
}
#ifdef CONFIG_PM
static int exynos_ehci_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
@ -288,15 +279,9 @@ static int exynos_ehci_resume(struct device *dev)
ehci_resume(hcd, false);
return 0;
}
#else
#define exynos_ehci_suspend NULL
#define exynos_ehci_resume NULL
#endif
static const struct dev_pm_ops exynos_ehci_pm_ops = {
.suspend = exynos_ehci_suspend,
.resume = exynos_ehci_resume,
};
static DEFINE_SIMPLE_DEV_PM_OPS(exynos_ehci_pm_ops,
exynos_ehci_suspend, exynos_ehci_resume);
#ifdef CONFIG_OF
static const struct of_device_id exynos_ehci_match[] = {
@ -312,7 +297,7 @@ static struct platform_driver exynos_ehci_driver = {
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "exynos-ehci",
.pm = &exynos_ehci_pm_ops,
.pm = pm_ptr(&exynos_ehci_pm_ops),
.of_match_table = of_match_ptr(exynos_ehci_match),
}
};

View File

@ -27,10 +27,6 @@
/*-------------------------------------------------------------------------*/
/* PID Codes that are used here, from EHCI specification, Table 3-16. */
#define PID_CODE_IN 1
#define PID_CODE_SETUP 2
/* fill a qtd, returning how much of the buffer we were able to queue up */
static unsigned int
@ -230,7 +226,7 @@ static int qtd_copy_status (
/* fs/ls interrupt xfer missed the complete-split */
status = -EPROTO;
} else if (token & QTD_STS_DBE) {
status = (QTD_PID (token) == 1) /* IN ? */
status = (QTD_PID(token) == PID_CODE_IN) /* IN ? */
? -ENOSR /* hc couldn't read data */
: -ECOMM; /* hc couldn't write data */
} else if (token & QTD_STS_XACT) {
@ -606,7 +602,7 @@ qh_urb_transaction (
/* SETUP pid */
qtd_fill(ehci, qtd, urb->setup_dma,
sizeof (struct usb_ctrlrequest),
token | (2 /* "setup" */ << 8), 8);
token | (PID_CODE_SETUP << 8), 8);
/* ... and always at least one more pid */
token ^= QTD_TOGGLE;
@ -620,7 +616,7 @@ qh_urb_transaction (
/* for zero length DATA stages, STATUS is always IN */
if (len == 0)
token |= (1 /* "in" */ << 8);
token |= (PID_CODE_IN << 8);
}
/*
@ -642,7 +638,7 @@ qh_urb_transaction (
}
if (is_input)
token |= (1 /* "in" */ << 8);
token |= (PID_CODE_IN << 8);
/* else it's already initted to "out" pid (0 << 8) */
maxpacket = usb_endpoint_maxp(&urb->ep->desc);
@ -709,7 +705,7 @@ qh_urb_transaction (
if (usb_pipecontrol (urb->pipe)) {
one_more = 1;
token ^= 0x0100; /* "in" <--> "out" */
token ^= (PID_CODE_IN << 8); /* "in" <--> "out" */
token |= QTD_TOGGLE; /* force DATA1 */
} else if (usb_pipeout(urb->pipe)
&& (urb->transfer_flags & URB_ZERO_PACKET)
@ -1203,7 +1199,7 @@ static int ehci_submit_single_step_set_feature(
/* SETUP pid, and interrupt after SETUP completion */
qtd_fill(ehci, qtd, urb->setup_dma,
sizeof(struct usb_ctrlrequest),
QTD_IOC | token | (2 /* "setup" */ << 8), 8);
QTD_IOC | token | (PID_CODE_SETUP << 8), 8);
submit_async(ehci, urb, &qtd_list, GFP_ATOMIC);
return 0; /*Return now; we shall come back after 15 seconds*/
@ -1216,7 +1212,7 @@ static int ehci_submit_single_step_set_feature(
token ^= QTD_TOGGLE; /*We need to start IN with DATA-1 Pid-sequence*/
buf = urb->transfer_dma;
token |= (1 /* "in" */ << 8); /*This is IN stage*/
token |= (PID_CODE_IN << 8); /*This is IN stage*/
maxpacket = usb_endpoint_maxp(&urb->ep->desc);
@ -1229,7 +1225,7 @@ static int ehci_submit_single_step_set_feature(
qtd->hw_alt_next = EHCI_LIST_END(ehci);
/* STATUS stage for GetDesc control request */
token ^= 0x0100; /* "in" <--> "out" */
token ^= (PID_CODE_IN << 8); /* "in" <--> "out" */
token |= QTD_TOGGLE; /* force DATA1 */
qtd_prev = qtd;

View File

@ -321,10 +321,16 @@ struct ehci_qtd {
size_t length; /* length of buffer */
} __aligned(32);
/* PID Codes that are used here, from EHCI specification, Table 3-16. */
#define PID_CODE_OUT 0
#define PID_CODE_IN 1
#define PID_CODE_SETUP 2
/* mask NakCnt+T in qh->hw_alt_next */
#define QTD_MASK(ehci) cpu_to_hc32(ehci, ~0x1f)
#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1)
#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && \
QTD_PID(token) == PID_CODE_IN)
/*-------------------------------------------------------------------------*/

View File

@ -135,20 +135,16 @@ static int exynos_ohci_probe(struct platform_device *pdev)
err = exynos_ohci_get_phy(&pdev->dev, exynos_ohci);
if (err)
goto fail_clk;
goto fail_io;
exynos_ohci->clk = devm_clk_get(&pdev->dev, "usbhost");
exynos_ohci->clk = devm_clk_get_enabled(&pdev->dev, "usbhost");
if (IS_ERR(exynos_ohci->clk)) {
dev_err(&pdev->dev, "Failed to get usbhost clock\n");
err = PTR_ERR(exynos_ohci->clk);
goto fail_clk;
goto fail_io;
}
err = clk_prepare_enable(exynos_ohci->clk);
if (err)
goto fail_clk;
hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(hcd->regs)) {
err = PTR_ERR(hcd->regs);
@ -191,8 +187,6 @@ fail_add_hcd:
exynos_ohci_phy_disable(&pdev->dev);
pdev->dev.of_node = exynos_ohci->of_node;
fail_io:
clk_disable_unprepare(exynos_ohci->clk);
fail_clk:
usb_put_hcd(hcd);
return err;
}
@ -208,8 +202,6 @@ static void exynos_ohci_remove(struct platform_device *pdev)
exynos_ohci_phy_disable(&pdev->dev);
clk_disable_unprepare(exynos_ohci->clk);
usb_put_hcd(hcd);
}
@ -221,7 +213,6 @@ static void exynos_ohci_shutdown(struct platform_device *pdev)
hcd->driver->shutdown(hcd);
}
#ifdef CONFIG_PM
static int exynos_ohci_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
@ -258,19 +249,13 @@ static int exynos_ohci_resume(struct device *dev)
return 0;
}
#else
#define exynos_ohci_suspend NULL
#define exynos_ohci_resume NULL
#endif
static const struct ohci_driver_overrides exynos_overrides __initconst = {
.extra_priv_size = sizeof(struct exynos_ohci_hcd),
};
static const struct dev_pm_ops exynos_ohci_pm_ops = {
.suspend = exynos_ohci_suspend,
.resume = exynos_ohci_resume,
};
static DEFINE_SIMPLE_DEV_PM_OPS(exynos_ohci_pm_ops,
exynos_ohci_suspend, exynos_ohci_resume);
#ifdef CONFIG_OF
static const struct of_device_id exynos_ohci_match[] = {
@ -286,7 +271,7 @@ static struct platform_driver exynos_ohci_driver = {
.shutdown = exynos_ohci_shutdown,
.driver = {
.name = "exynos-ohci",
.pm = &exynos_ohci_pm_ops,
.pm = pm_ptr(&exynos_ohci_pm_ops),
.of_match_table = of_match_ptr(exynos_ohci_match),
}
};

View File

@ -516,7 +516,7 @@ static int xhci_dbc_mem_init(struct xhci_dbc *dbc, gfp_t flags)
goto string_fail;
/* Setup ERST register: */
writel(dbc->erst.erst_size, &dbc->regs->ersts);
writel(dbc->erst.num_entries, &dbc->regs->ersts);
lo_hi_writeq(dbc->erst.erst_dma_addr, &dbc->regs->erstba);
deq = xhci_trb_virt_to_dma(dbc->ring_evt->deq_seg,

View File

@ -536,7 +536,7 @@ static void xhci_free_stream_ctx(struct xhci_hcd *xhci,
struct xhci_stream_ctx *stream_ctx, dma_addr_t dma)
{
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs;
size_t size = array_size(sizeof(struct xhci_stream_ctx), num_stream_ctxs);
if (size > MEDIUM_STREAM_ARRAY_SIZE)
dma_free_coherent(dev, size, stream_ctx, dma);
@ -561,7 +561,7 @@ static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci,
gfp_t mem_flags)
{
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
size_t size = size_mul(sizeof(struct xhci_stream_ctx), num_stream_ctxs);
size_t size = array_size(sizeof(struct xhci_stream_ctx), num_stream_ctxs);
if (size > MEDIUM_STREAM_ARRAY_SIZE)
return dma_alloc_coherent(dev, size, dma, mem_flags);
@ -1638,7 +1638,7 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
goto fail_sp;
xhci->scratchpad->sp_array = dma_alloc_coherent(dev,
size_mul(sizeof(u64), num_sp),
array_size(sizeof(u64), num_sp),
&xhci->scratchpad->sp_dma, flags);
if (!xhci->scratchpad->sp_array)
goto fail_sp2;
@ -1671,7 +1671,7 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
kfree(xhci->scratchpad->sp_buffers);
fail_sp3:
dma_free_coherent(dev, num_sp * sizeof(u64),
dma_free_coherent(dev, array_size(sizeof(u64), num_sp),
xhci->scratchpad->sp_array,
xhci->scratchpad->sp_dma);
@ -1700,7 +1700,7 @@ static void scratchpad_free(struct xhci_hcd *xhci)
xhci->scratchpad->sp_array[i]);
}
kfree(xhci->scratchpad->sp_buffers);
dma_free_coherent(dev, num_sp * sizeof(u64),
dma_free_coherent(dev, array_size(sizeof(u64), num_sp),
xhci->scratchpad->sp_array,
xhci->scratchpad->sp_dma);
kfree(xhci->scratchpad);
@ -1778,7 +1778,7 @@ static int xhci_alloc_erst(struct xhci_hcd *xhci,
struct xhci_segment *seg;
struct xhci_erst_entry *entry;
size = size_mul(sizeof(struct xhci_erst_entry), evt_ring->num_segs);
size = array_size(sizeof(struct xhci_erst_entry), evt_ring->num_segs);
erst->entries = dma_alloc_coherent(xhci_to_hcd(xhci)->self.sysdev,
size, &erst->erst_dma_addr, flags);
if (!erst->entries)
@ -1829,7 +1829,7 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
if (!ir)
return;
erst_size = sizeof(struct xhci_erst_entry) * ir->erst.num_entries;
erst_size = array_size(sizeof(struct xhci_erst_entry), ir->erst.num_entries);
if (ir->erst.entries)
dma_free_coherent(dev, erst_size,
ir->erst.entries,
@ -1950,7 +1950,6 @@ no_bw:
kfree(xhci->usb3_rhub.ports);
kfree(xhci->hw_ports);
kfree(xhci->rh_bw);
kfree(xhci->ext_caps);
for (i = 0; i < xhci->num_port_caps; i++)
kfree(xhci->port_caps[i].psi);
kfree(xhci->port_caps);
@ -1961,7 +1960,6 @@ no_bw:
xhci->usb3_rhub.ports = NULL;
xhci->hw_ports = NULL;
xhci->rh_bw = NULL;
xhci->ext_caps = NULL;
xhci->port_caps = NULL;
xhci->interrupters = NULL;
@ -2089,10 +2087,7 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
port_cap->maj_rev = major_revision;
port_cap->min_rev = minor_revision;
/* cache usb2 port capabilities */
if (major_revision < 0x03 && xhci->num_ext_caps < max_caps)
xhci->ext_caps[xhci->num_ext_caps++] = temp;
port_cap->protocol_caps = temp;
if ((xhci->hci_version >= 0x100) && (major_revision != 0x03) &&
(temp & XHCI_HLC)) {
@ -2212,11 +2207,6 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
XHCI_EXT_CAPS_PROTOCOL);
}
xhci->ext_caps = kcalloc_node(cap_count, sizeof(*xhci->ext_caps),
flags, dev_to_node(dev));
if (!xhci->ext_caps)
return -ENOMEM;
xhci->port_caps = kcalloc_node(cap_count, sizeof(*xhci->port_caps),
flags, dev_to_node(dev));
if (!xhci->port_caps)
@ -2269,24 +2259,24 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
}
static struct xhci_interrupter *
xhci_alloc_interrupter(struct xhci_hcd *xhci, int segs, gfp_t flags)
xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int segs, gfp_t flags)
{
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
struct xhci_interrupter *ir;
unsigned int num_segs = segs;
unsigned int max_segs;
int ret;
if (!segs)
segs = ERST_DEFAULT_SEGS;
max_segs = BIT(HCS_ERST_MAX(xhci->hcs_params2));
segs = min(segs, max_segs);
ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev));
if (!ir)
return NULL;
/* number of ring segments should be greater than 0 */
if (segs <= 0)
num_segs = min_t(unsigned int, 1 << HCS_ERST_MAX(xhci->hcs_params2),
ERST_MAX_SEGS);
ir->event_ring = xhci_ring_alloc(xhci, num_segs, 1, TYPE_EVENT, 0,
flags);
ir->event_ring = xhci_ring_alloc(xhci, segs, 1, TYPE_EVENT, 0, flags);
if (!ir->event_ring) {
xhci_warn(xhci, "Failed to allocate interrupter event ring\n");
kfree(ir);
@ -2344,7 +2334,7 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
}
struct xhci_interrupter *
xhci_create_secondary_interrupter(struct usb_hcd *hcd, int num_seg)
xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct xhci_interrupter *ir;
@ -2354,7 +2344,7 @@ xhci_create_secondary_interrupter(struct usb_hcd *hcd, int num_seg)
if (!xhci->interrupters || xhci->max_interrupters <= 1)
return NULL;
ir = xhci_alloc_interrupter(xhci, num_seg, GFP_KERNEL);
ir = xhci_alloc_interrupter(xhci, segs, GFP_KERNEL);
if (!ir)
return NULL;

View File

@ -45,8 +45,16 @@
#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI 0x9d2f
#define PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI 0x0aa8
#define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI 0x1aa8
#define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8
#define PCI_DEVICE_ID_INTEL_DNV_XHCI 0x19d0
#define PCI_DEVICE_ID_INTEL_APOLLO_LAKE_XHCI 0x5aa8
#define PCI_DEVICE_ID_INTEL_DENVERTON_XHCI 0x19d0
#define PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI 0x8a13
#define PCI_DEVICE_ID_INTEL_TIGER_LAKE_XHCI 0x9a13
#define PCI_DEVICE_ID_INTEL_COMET_LAKE_XHCI 0xa3af
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI 0x51ed
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_N_PCH_XHCI 0x54ed
/* Thunderbolt */
#define PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_XHCI 0x1138
#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_XHCI 0x15b5
#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_XHCI 0x15b6
#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_LP_XHCI 0x15c1
@ -55,12 +63,6 @@
#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_XHCI 0x15e9
#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_XHCI 0x15ec
#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI 0x15f0
#define PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI 0x8a13
#define PCI_DEVICE_ID_INTEL_CML_XHCI 0xa3af
#define PCI_DEVICE_ID_INTEL_TIGER_LAKE_XHCI 0x9a13
#define PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_XHCI 0x1138
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI 0x51ed
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_N_PCH_XHCI 0x54ed
#define PCI_DEVICE_ID_AMD_RENOIR_XHCI 0x1639
#define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9
@ -270,17 +272,12 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
"QUIRK: Fresco Logic revision %u "
"has broken MSI implementation",
pdev->revision);
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
}
if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1009)
xhci->quirks |= XHCI_BROKEN_STREAMS;
if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1100)
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
if (pdev->vendor == PCI_VENDOR_ID_NEC)
xhci->quirks |= XHCI_NEC_HOST;
@ -307,11 +304,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
xhci->quirks |= XHCI_RESET_ON_RESUME;
}
if (pdev->vendor == PCI_VENDOR_ID_AMD) {
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
if (pdev->device == 0x43f7)
xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
}
if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x43f7)
xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
if ((pdev->vendor == PCI_VENDOR_ID_AMD) &&
((pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4) ||
@ -356,9 +350,9 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_DNV_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_CML_XHCI)) {
pdev->device == PCI_DEVICE_ID_INTEL_APOLLO_LAKE_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_DENVERTON_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_COMET_LAKE_XHCI)) {
xhci->quirks |= XHCI_PME_STUCK_QUIRK;
}
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
@ -367,14 +361,14 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
(pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI))
pdev->device == PCI_DEVICE_ID_INTEL_APOLLO_LAKE_XHCI))
xhci->quirks |= XHCI_INTEL_USB_ROLE_SW;
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
(pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_DNV_XHCI))
pdev->device == PCI_DEVICE_ID_INTEL_APOLLO_LAKE_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_DENVERTON_XHCI))
xhci->quirks |= XHCI_MISSING_CAS;
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
@ -399,12 +393,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
pdev->device == PCI_DEVICE_ID_EJ168) {
xhci->quirks |= XHCI_RESET_ON_RESUME;
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
xhci->quirks |= XHCI_BROKEN_STREAMS;
}
if (pdev->vendor == PCI_VENDOR_ID_RENESAS &&
pdev->device == 0x0014) {
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
xhci->quirks |= XHCI_ZERO_64B_REGS;
}
if (pdev->vendor == PCI_VENDOR_ID_RENESAS &&
@ -434,7 +426,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
}
if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
pdev->device == PCI_DEVICE_ID_ASMEDIA_1042A_XHCI) {
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
xhci->quirks |= XHCI_NO_64BIT_SUPPORT;
}
if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
@ -889,10 +880,10 @@ static const struct xhci_driver_data reneses_data = {
/* PCI driver selection metadata; PCI hotplugging uses this */
static const struct pci_device_id pci_ids[] = {
{ PCI_DEVICE(0x1912, 0x0014),
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0014),
.driver_data = (unsigned long)&reneses_data,
},
{ PCI_DEVICE(0x1912, 0x0015),
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0015),
.driver_data = (unsigned long)&reneses_data,
},
/* handle any USB 3.0 xHCI controller */

View File

@ -214,8 +214,7 @@ static int xhci_rcar_resume_quirk(struct usb_hcd *hcd)
*/
#define SET_XHCI_PLAT_PRIV_FOR_RCAR(firmware) \
.firmware_name = firmware, \
.quirks = XHCI_NO_64BIT_SUPPORT | XHCI_TRUST_TX_LENGTH | \
XHCI_SLOW_SUSPEND, \
.quirks = XHCI_NO_64BIT_SUPPORT | XHCI_SLOW_SUSPEND, \
.init_quirk = xhci_rcar_init_quirk, \
.plat_start = xhci_rcar_start, \
.resume_quirk = xhci_rcar_resume_quirk,
@ -229,8 +228,7 @@ static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = {
};
static const struct xhci_plat_priv xhci_plat_renesas_rzv2m = {
.quirks = XHCI_NO_64BIT_SUPPORT | XHCI_TRUST_TX_LENGTH |
XHCI_SLOW_SUSPEND,
.quirks = XHCI_NO_64BIT_SUPPORT | XHCI_SLOW_SUSPEND,
.init_quirk = xhci_rzv2m_init_quirk,
.plat_start = xhci_rzv2m_start,
};

View File

@ -308,7 +308,7 @@ static unsigned int xhci_num_trbs_free(struct xhci_hcd *xhci, struct xhci_ring *
free += last_on_seg - enq;
enq_seg = enq_seg->next;
enq = enq_seg->trbs;
} while (i++ <= ring->num_segs);
} while (i++ < ring->num_segs);
return free;
}
@ -351,10 +351,8 @@ static unsigned int xhci_ring_expansion_needed(struct xhci_hcd *xhci, struct xhc
while (new_segs > 0) {
seg = seg->next;
if (seg == ring->deq_seg) {
xhci_dbg(xhci, "Ring expansion by %d segments needed\n",
new_segs);
xhci_dbg(xhci, "Adding %d trbs moves enq %d trbs into deq seg\n",
num_trbs, trbs_past_seg % TRBS_PER_SEGMENT);
xhci_dbg(xhci, "Adding %d trbs requires expanding ring by %d segments\n",
num_trbs, new_segs);
return new_segs;
}
new_segs--;
@ -1026,8 +1024,7 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep)
td->urb->stream_id);
hw_deq &= ~0xf;
if (td->cancel_status == TD_HALTED ||
trb_in_td(xhci, td->start_seg, td->first_trb, td->last_trb, hw_deq, false)) {
if (td->cancel_status == TD_HALTED || trb_in_td(xhci, td, hw_deq, false)) {
switch (td->cancel_status) {
case TD_CLEARED: /* TD is already no-op */
case TD_CLEARING_CACHE: /* set TR deq command already queued */
@ -1084,8 +1081,7 @@ static struct xhci_td *find_halted_td(struct xhci_virt_ep *ep)
hw_deq = xhci_get_hw_deq(ep->xhci, ep->vdev, ep->ep_index, 0);
hw_deq &= ~0xf;
td = list_first_entry(&ep->ring->td_list, struct xhci_td, td_list);
if (trb_in_td(ep->xhci, td->start_seg, td->first_trb,
td->last_trb, hw_deq, false))
if (trb_in_td(ep->xhci, td, hw_deq, false))
return td;
}
return NULL;
@ -2051,25 +2047,19 @@ cleanup:
}
/*
* This TD is defined by the TRBs starting at start_trb in start_seg and ending
* at end_trb, which may be in another segment. If the suspect DMA address is a
* TRB in this TD, this function returns that TRB's segment. Otherwise it
* returns 0.
* If the suspect DMA address is a TRB in this TD, this function returns that
* TRB's segment. Otherwise it returns 0.
*/
struct xhci_segment *trb_in_td(struct xhci_hcd *xhci,
struct xhci_segment *start_seg,
union xhci_trb *start_trb,
union xhci_trb *end_trb,
dma_addr_t suspect_dma,
bool debug)
struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, struct xhci_td *td, dma_addr_t suspect_dma,
bool debug)
{
dma_addr_t start_dma;
dma_addr_t end_seg_dma;
dma_addr_t end_trb_dma;
struct xhci_segment *cur_seg;
start_dma = xhci_trb_virt_to_dma(start_seg, start_trb);
cur_seg = start_seg;
start_dma = xhci_trb_virt_to_dma(td->start_seg, td->first_trb);
cur_seg = td->start_seg;
do {
if (start_dma == 0)
@ -2078,7 +2068,7 @@ struct xhci_segment *trb_in_td(struct xhci_hcd *xhci,
end_seg_dma = xhci_trb_virt_to_dma(cur_seg,
&cur_seg->trbs[TRBS_PER_SEGMENT - 1]);
/* If the end TRB isn't in this segment, this is set to 0 */
end_trb_dma = xhci_trb_virt_to_dma(cur_seg, end_trb);
end_trb_dma = xhci_trb_virt_to_dma(cur_seg, td->last_trb);
if (debug)
xhci_warn(xhci,
@ -2112,7 +2102,7 @@ struct xhci_segment *trb_in_td(struct xhci_hcd *xhci,
}
cur_seg = cur_seg->next;
start_dma = xhci_trb_virt_to_dma(cur_seg, &cur_seg->trbs[0]);
} while (cur_seg != start_seg);
} while (cur_seg != td->start_seg);
return NULL;
}
@ -2399,8 +2389,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
break;
if (remaining) {
frame->status = short_framestatus;
if (xhci->quirks & XHCI_TRUST_TX_LENGTH)
sum_trbs_for_length = true;
sum_trbs_for_length = true;
break;
}
frame->status = 0;
@ -2590,7 +2579,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
struct xhci_ep_ctx *ep_ctx;
u32 trb_comp_code;
int td_num = 0;
bool handling_skipped_tds = false;
slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1;
@ -2628,16 +2616,17 @@ static int handle_tx_event(struct xhci_hcd *xhci,
else
xhci_handle_halted_endpoint(xhci, ep, NULL,
EP_SOFT_RESET);
goto cleanup;
break;
case COMP_RING_UNDERRUN:
case COMP_RING_OVERRUN:
case COMP_STOPPED_LENGTH_INVALID:
goto cleanup;
break;
default:
xhci_err(xhci, "ERROR Transfer event for unknown stream ring slot %u ep %u\n",
slot_id, ep_index);
goto err_out;
}
return 0;
}
/* Count current td numbers if ep->skip is set */
@ -2650,15 +2639,11 @@ static int handle_tx_event(struct xhci_hcd *xhci,
* transfer type
*/
case COMP_SUCCESS:
if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0)
break;
if (xhci->quirks & XHCI_TRUST_TX_LENGTH ||
ep_ring->last_td_was_short)
if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
trb_comp_code = COMP_SHORT_PACKET;
else
xhci_warn_ratelimited(xhci,
"WARN Successful completion on short TX for slot %u ep %u: needs XHCI_TRUST_TX_LENGTH quirk?\n",
slot_id, ep_index);
xhci_dbg(xhci, "Successful completion on short TX for slot %u ep %u with last td short %d\n",
slot_id, ep_index, ep_ring->last_td_was_short);
}
break;
case COMP_SHORT_PACKET:
break;
@ -2730,19 +2715,19 @@ static int handle_tx_event(struct xhci_hcd *xhci,
*/
xhci_dbg(xhci, "underrun event on endpoint\n");
if (!list_empty(&ep_ring->td_list))
xhci_dbg(xhci, "Underrun Event for slot %d ep %d "
"still with TDs queued?\n",
TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
ep_index);
goto cleanup;
xhci_dbg(xhci, "Underrun Event for slot %u ep %d still with TDs queued?\n",
slot_id, ep_index);
if (ep->skip)
break;
return 0;
case COMP_RING_OVERRUN:
xhci_dbg(xhci, "overrun event on endpoint\n");
if (!list_empty(&ep_ring->td_list))
xhci_dbg(xhci, "Overrun Event for slot %d ep %d "
"still with TDs queued?\n",
TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
ep_index);
goto cleanup;
xhci_dbg(xhci, "Overrun Event for slot %u ep %d still with TDs queued?\n",
slot_id, ep_index);
if (ep->skip)
break;
return 0;
case COMP_MISSED_SERVICE_ERROR:
/*
* When encounter missed service error, one or more isoc tds
@ -2754,13 +2739,13 @@ static int handle_tx_event(struct xhci_hcd *xhci,
xhci_dbg(xhci,
"Miss service interval error for slot %u ep %u, set skip flag\n",
slot_id, ep_index);
goto cleanup;
return 0;
case COMP_NO_PING_RESPONSE_ERROR:
ep->skip = true;
xhci_dbg(xhci,
"No Ping response error for slot %u ep %u, Skip one Isoc TD\n",
slot_id, ep_index);
goto cleanup;
return 0;
case COMP_INCOMPATIBLE_DEVICE_ERROR:
/* needs disable slot command to recover */
@ -2777,7 +2762,9 @@ static int handle_tx_event(struct xhci_hcd *xhci,
xhci_warn(xhci,
"ERROR Unknown event condition %u for slot %u ep %u , HC probably busted\n",
trb_comp_code, slot_id, ep_index);
goto cleanup;
if (ep->skip)
break;
return 0;
}
do {
@ -2796,9 +2783,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
if (!(trb_comp_code == COMP_STOPPED ||
trb_comp_code == COMP_STOPPED_LENGTH_INVALID ||
ep_ring->last_td_was_short)) {
xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n",
TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
ep_index);
xhci_warn(xhci, "WARN Event TRB for slot %u ep %d with no TDs queued?\n",
slot_id, ep_index);
}
if (ep->skip) {
ep->skip = false;
@ -2811,7 +2797,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
xhci_handle_halted_endpoint(xhci, ep, NULL,
EP_HARD_RESET);
}
goto cleanup;
return 0;
}
/* We've skipped all the TDs on the ep ring when ep->skip set */
@ -2819,7 +2805,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
ep->skip = false;
xhci_dbg(xhci, "All tds on the ep_ring skipped. Clear skip flag for slot %u ep %u.\n",
slot_id, ep_index);
goto cleanup;
return 0;
}
td = list_first_entry(&ep_ring->td_list, struct xhci_td,
@ -2828,8 +2814,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
td_num--;
/* Is this a TRB in the currently executing TD? */
ep_seg = trb_in_td(xhci, td->start_seg, td->first_trb,
td->last_trb, ep_trb_dma, false);
ep_seg = trb_in_td(xhci, td, ep_trb_dma, false);
/*
* Skip the Force Stopped Event. The event_trb(event_dma) of FSE
@ -2841,14 +2826,14 @@ static int handle_tx_event(struct xhci_hcd *xhci,
*/
if (!ep_seg && (trb_comp_code == COMP_STOPPED ||
trb_comp_code == COMP_STOPPED_LENGTH_INVALID)) {
goto cleanup;
continue;
}
if (!ep_seg) {
if (ep->skip && usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
skip_isoc_td(xhci, td, ep, status);
goto cleanup;
continue;
}
/*
@ -2858,7 +2843,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
if ((xhci->quirks & XHCI_SPURIOUS_SUCCESS) &&
ep_ring->last_td_was_short) {
ep_ring->last_td_was_short = false;
goto cleanup;
return 0;
}
/*
@ -2876,8 +2861,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
!list_is_last(&td->td_list, &ep_ring->td_list)) {
struct xhci_td *td_next = list_next_entry(td, td_list);
ep_seg = trb_in_td(xhci, td_next->start_seg, td_next->first_trb,
td_next->last_trb, ep_trb_dma, false);
ep_seg = trb_in_td(xhci, td_next, ep_trb_dma, false);
if (ep_seg) {
/* give back previous TD, start handling new */
xhci_dbg(xhci, "Missing TD completion event after mid TD error\n");
@ -2896,8 +2880,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
"part of current TD ep_index %d "
"comp_code %u\n", ep_index,
trb_comp_code);
trb_in_td(xhci, td->start_seg, td->first_trb,
td->last_trb, ep_trb_dma, true);
trb_in_td(xhci, td, ep_trb_dma, true);
return -ESHUTDOWN;
}
}
@ -2933,30 +2917,24 @@ static int handle_tx_event(struct xhci_hcd *xhci,
trb_comp_code))
xhci_handle_halted_endpoint(xhci, ep, td,
EP_HARD_RESET);
goto cleanup;
} else {
td->status = status;
/* update the urb's actual_length and give back to the core */
if (usb_endpoint_xfer_control(&td->urb->ep->desc))
process_ctrl_td(xhci, ep, ep_ring, td, ep_trb, event);
else if (usb_endpoint_xfer_isoc(&td->urb->ep->desc))
process_isoc_td(xhci, ep, ep_ring, td, ep_trb, event);
else
process_bulk_intr_td(xhci, ep, ep_ring, td, ep_trb, event);
}
td->status = status;
/* update the urb's actual_length and give back to the core */
if (usb_endpoint_xfer_control(&td->urb->ep->desc))
process_ctrl_td(xhci, ep, ep_ring, td, ep_trb, event);
else if (usb_endpoint_xfer_isoc(&td->urb->ep->desc))
process_isoc_td(xhci, ep, ep_ring, td, ep_trb, event);
else
process_bulk_intr_td(xhci, ep, ep_ring, td, ep_trb, event);
cleanup:
handling_skipped_tds = ep->skip &&
trb_comp_code != COMP_MISSED_SERVICE_ERROR &&
trb_comp_code != COMP_NO_PING_RESPONSE_ERROR;
/*
* If ep->skip is set, it means there are missed tds on the
* endpoint ring need to take care of.
* Process them as short transfer until reach the td pointed by
* the event.
*/
} while (handling_skipped_tds);
} while (ep->skip);
return 0;

View File

@ -4507,35 +4507,13 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
return 0;
}
/* check if a usb2 port supports a given extened capability protocol
* only USB2 ports extended protocol capability values are cached.
* Return 1 if capability is supported
*/
static int xhci_check_usb2_port_capability(struct xhci_hcd *xhci, int port,
unsigned capability)
{
u32 port_offset, port_count;
int i;
for (i = 0; i < xhci->num_ext_caps; i++) {
if (xhci->ext_caps[i] & capability) {
/* port offsets starts at 1 */
port_offset = XHCI_EXT_PORT_OFF(xhci->ext_caps[i]) - 1;
port_count = XHCI_EXT_PORT_COUNT(xhci->ext_caps[i]);
if (port >= port_offset &&
port < port_offset + port_count)
return 1;
}
}
return 0;
}
static int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
int portnum = udev->portnum - 1;
struct xhci_port *port;
u32 capability;
if (hcd->speed >= HCD_USB3 || !udev->lpm_capable)
if (hcd->speed >= HCD_USB3 || !udev->lpm_capable || !xhci->hw_lpm_support)
return 0;
/* we only support lpm for non-hub device connected to root hub yet */
@ -4543,14 +4521,14 @@ static int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
udev->descriptor.bDeviceClass == USB_CLASS_HUB)
return 0;
if (xhci->hw_lpm_support == 1 &&
xhci_check_usb2_port_capability(
xhci, portnum, XHCI_HLC)) {
port = xhci->usb2_rhub.ports[udev->portnum - 1];
capability = port->port_cap->protocol_caps;
if (capability & XHCI_HLC) {
udev->usb2_hw_lpm_capable = 1;
udev->l1_params.timeout = XHCI_L1_TIMEOUT;
udev->l1_params.besl = XHCI_DEFAULT_BESL;
if (xhci_check_usb2_port_capability(xhci, portnum,
XHCI_BLC))
if (capability & XHCI_BLC)
udev->usb2_hw_lpm_besl_capable = 1;
}

View File

@ -1376,8 +1376,6 @@ struct xhci_erst {
unsigned int num_entries;
/* xhci->event_ring keeps track of segment dma addresses */
dma_addr_t erst_dma_addr;
/* Num entries the ERST can contain */
unsigned int erst_size;
};
struct xhci_scratchpad {
@ -1392,8 +1390,8 @@ struct urb_priv {
struct xhci_td td[] __counted_by(num_tds);
};
/* Reasonable limit for number of Event Ring segments (spec allows 32k) */
#define ERST_MAX_SEGS 2
/* Number of Event Ring segments to allocate, when amount is not specified. (spec allows 32k) */
#define ERST_DEFAULT_SEGS 2
/* Poll every 60 seconds */
#define POLL_TIMEOUT 60
/* Stop endpoint command timeout (secs) for URB cancellation watchdog timer */
@ -1451,6 +1449,7 @@ struct xhci_port_cap {
u8 psi_uid_count;
u8 maj_rev;
u8 min_rev;
u32 protocol_caps;
};
struct xhci_port {
@ -1589,7 +1588,7 @@ struct xhci_hcd {
#define XHCI_RESET_ON_RESUME BIT_ULL(7)
#define XHCI_SW_BW_CHECKING BIT_ULL(8)
#define XHCI_AMD_0x96_HOST BIT_ULL(9)
#define XHCI_TRUST_TX_LENGTH BIT_ULL(10)
#define XHCI_TRUST_TX_LENGTH BIT_ULL(10) /* Deprecated */
#define XHCI_LPM_SUPPORT BIT_ULL(11)
#define XHCI_INTEL_HOST BIT_ULL(12)
#define XHCI_SPURIOUS_REBOOT BIT_ULL(13)
@ -1640,9 +1639,6 @@ struct xhci_hcd {
unsigned broken_suspend:1;
/* Indicates that omitting hcd is supported if root hub has no ports */
unsigned allow_single_roothub:1;
/* cached usb2 extened protocol capabilites */
u32 *ext_caps;
unsigned int num_ext_caps;
/* cached extended protocol port capabilities */
struct xhci_port_cap *port_caps;
unsigned int num_port_caps;
@ -1729,8 +1725,6 @@ static inline bool xhci_has_one_roothub(struct xhci_hcd *xhci)
dev_err(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
#define xhci_warn(xhci, fmt, args...) \
dev_warn(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
#define xhci_warn_ratelimited(xhci, fmt, args...) \
dev_warn_ratelimited(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
#define xhci_info(xhci, fmt, args...) \
dev_info(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
@ -1833,7 +1827,7 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
void xhci_free_container_ctx(struct xhci_hcd *xhci,
struct xhci_container_ctx *ctx);
struct xhci_interrupter *
xhci_create_secondary_interrupter(struct usb_hcd *hcd, int num_seg);
xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs);
void xhci_remove_secondary_interrupter(struct usb_hcd
*hcd, struct xhci_interrupter *ir);
@ -1876,9 +1870,8 @@ int xhci_alloc_tt_info(struct xhci_hcd *xhci,
/* xHCI ring, segment, TRB, and TD functions */
dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb);
struct xhci_segment *trb_in_td(struct xhci_hcd *xhci,
struct xhci_segment *start_seg, union xhci_trb *start_trb,
union xhci_trb *end_trb, dma_addr_t suspect_dma, bool debug);
struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, struct xhci_td *td,
dma_addr_t suspect_dma, bool debug);
int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code);
void xhci_ring_cmd_db(struct xhci_hcd *xhci);
int xhci_queue_slot_control(struct xhci_hcd *xhci, struct xhci_command *cmd,
@ -2340,7 +2333,12 @@ static inline const char *xhci_decode_portsc(char *str, u32 portsc)
{
int ret;
ret = sprintf(str, "%s %s %s Link:%s PortSpeed:%d ",
ret = sprintf(str, "0x%08x ", portsc);
if (portsc == ~(u32)0)
return str;
ret += sprintf(str + ret, "%s %s %s Link:%s PortSpeed:%d ",
portsc & PORT_POWER ? "Powered" : "Powered-off",
portsc & PORT_CONNECT ? "Connected" : "Not-connected",
portsc & PORT_PE ? "Enabled" : "Disabled",

View File

@ -316,18 +316,18 @@ config BRCM_USB_PINMAP
signals, which are typically on dedicated pins on the chip,
to any gpio.
config USB_ONBOARD_HUB
tristate "Onboard USB hub support"
config USB_ONBOARD_DEV
tristate "Onboard USB device support"
depends on OF
help
Say Y here if you want to support discrete onboard USB hubs that
don't require an additional control bus for initialization, but
need some non-trivial form of initialization, such as enabling a
power regulator. An example for such a hub is the Realtek
RTS5411.
Say Y here if you want to support discrete onboard USB devices
that don't require an additional control bus for initialization,
but need some non-trivial form of initialization, such as
enabling a power regulator. An example for such device is the
Realtek RTS5411 hub.
This driver can be used as a module but its state (module vs
builtin) must match the state of the USB subsystem. Enabling
this config will enable the driver and it will automatically
match the state of the USB subsystem. If this driver is a
module it will be called onboard_usb_hub.
module it will be called onboard_usb_dev.

View File

@ -33,4 +33,4 @@ obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o
obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/
obj-$(CONFIG_USB_LINK_LAYER_TEST) += lvstest.o
obj-$(CONFIG_BRCM_USB_PINMAP) += brcmstb-usb-pinmap.o
obj-$(CONFIG_USB_ONBOARD_HUB) += onboard_usb_hub.o
obj-$(CONFIG_USB_ONBOARD_DEV) += onboard_usb_dev.o

View File

@ -0,0 +1,550 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for onboard USB devices
*
* Copyright (c) 2022, Google LLC
*/
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/suspend.h>
#include <linux/sysfs.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/usb/onboard_dev.h>
#include <linux/workqueue.h>
#include "onboard_usb_dev.h"
static void onboard_dev_attach_usb_driver(struct work_struct *work);
static struct usb_device_driver onboard_dev_usbdev_driver;
static DECLARE_WORK(attach_usb_driver_work, onboard_dev_attach_usb_driver);
/************************** Platform driver **************************/
struct usbdev_node {
struct usb_device *udev;
struct list_head list;
};
struct onboard_dev {
struct regulator_bulk_data supplies[MAX_SUPPLIES];
struct device *dev;
const struct onboard_dev_pdata *pdata;
struct gpio_desc *reset_gpio;
bool always_powered_in_suspend;
bool is_powered_on;
bool going_away;
struct list_head udev_list;
struct mutex lock;
struct clk *clk;
};
static int onboard_dev_get_regulators(struct onboard_dev *onboard_dev)
{
const char * const *supply_names = onboard_dev->pdata->supply_names;
unsigned int num_supplies = onboard_dev->pdata->num_supplies;
struct device *dev = onboard_dev->dev;
unsigned int i;
int err;
if (num_supplies > MAX_SUPPLIES)
return dev_err_probe(dev, -EINVAL, "max %d supplies supported!\n",
MAX_SUPPLIES);
for (i = 0; i < num_supplies; i++)
onboard_dev->supplies[i].supply = supply_names[i];
err = devm_regulator_bulk_get(dev, num_supplies, onboard_dev->supplies);
if (err)
dev_err(dev, "Failed to get regulator supplies: %pe\n",
ERR_PTR(err));
return err;
}
static int onboard_dev_power_on(struct onboard_dev *onboard_dev)
{
int err;
err = clk_prepare_enable(onboard_dev->clk);
if (err) {
dev_err(onboard_dev->dev, "failed to enable clock: %pe\n",
ERR_PTR(err));
return err;
}
err = regulator_bulk_enable(onboard_dev->pdata->num_supplies,
onboard_dev->supplies);
if (err) {
dev_err(onboard_dev->dev, "failed to enable supplies: %pe\n",
ERR_PTR(err));
goto disable_clk;
}
fsleep(onboard_dev->pdata->reset_us);
gpiod_set_value_cansleep(onboard_dev->reset_gpio, 0);
onboard_dev->is_powered_on = true;
return 0;
disable_clk:
clk_disable_unprepare(onboard_dev->clk);
return err;
}
static int onboard_dev_power_off(struct onboard_dev *onboard_dev)
{
int err;
gpiod_set_value_cansleep(onboard_dev->reset_gpio, 1);
err = regulator_bulk_disable(onboard_dev->pdata->num_supplies,
onboard_dev->supplies);
if (err) {
dev_err(onboard_dev->dev, "failed to disable supplies: %pe\n",
ERR_PTR(err));
return err;
}
clk_disable_unprepare(onboard_dev->clk);
onboard_dev->is_powered_on = false;
return 0;
}
static int __maybe_unused onboard_dev_suspend(struct device *dev)
{
struct onboard_dev *onboard_dev = dev_get_drvdata(dev);
struct usbdev_node *node;
bool power_off = true;
if (onboard_dev->always_powered_in_suspend)
return 0;
mutex_lock(&onboard_dev->lock);
list_for_each_entry(node, &onboard_dev->udev_list, list) {
if (!device_may_wakeup(node->udev->bus->controller))
continue;
if (usb_wakeup_enabled_descendants(node->udev)) {
power_off = false;
break;
}
}
mutex_unlock(&onboard_dev->lock);
if (!power_off)
return 0;
return onboard_dev_power_off(onboard_dev);
}
static int __maybe_unused onboard_dev_resume(struct device *dev)
{
struct onboard_dev *onboard_dev = dev_get_drvdata(dev);
if (onboard_dev->is_powered_on)
return 0;
return onboard_dev_power_on(onboard_dev);
}
static inline void get_udev_link_name(const struct usb_device *udev, char *buf,
size_t size)
{
snprintf(buf, size, "usb_dev.%s", dev_name(&udev->dev));
}
static int onboard_dev_add_usbdev(struct onboard_dev *onboard_dev,
struct usb_device *udev)
{
struct usbdev_node *node;
char link_name[64];
int err;
mutex_lock(&onboard_dev->lock);
if (onboard_dev->going_away) {
err = -EINVAL;
goto error;
}
node = kzalloc(sizeof(*node), GFP_KERNEL);
if (!node) {
err = -ENOMEM;
goto error;
}
node->udev = udev;
list_add(&node->list, &onboard_dev->udev_list);
mutex_unlock(&onboard_dev->lock);
get_udev_link_name(udev, link_name, sizeof(link_name));
WARN_ON(sysfs_create_link(&onboard_dev->dev->kobj, &udev->dev.kobj,
link_name));
return 0;
error:
mutex_unlock(&onboard_dev->lock);
return err;
}
static void onboard_dev_remove_usbdev(struct onboard_dev *onboard_dev,
const struct usb_device *udev)
{
struct usbdev_node *node;
char link_name[64];
get_udev_link_name(udev, link_name, sizeof(link_name));
sysfs_remove_link(&onboard_dev->dev->kobj, link_name);
mutex_lock(&onboard_dev->lock);
list_for_each_entry(node, &onboard_dev->udev_list, list) {
if (node->udev == udev) {
list_del(&node->list);
kfree(node);
break;
}
}
mutex_unlock(&onboard_dev->lock);
}
static ssize_t always_powered_in_suspend_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
const struct onboard_dev *onboard_dev = dev_get_drvdata(dev);
return sysfs_emit(buf, "%d\n", onboard_dev->always_powered_in_suspend);
}
static ssize_t always_powered_in_suspend_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct onboard_dev *onboard_dev = dev_get_drvdata(dev);
bool val;
int ret;
ret = kstrtobool(buf, &val);
if (ret < 0)
return ret;
onboard_dev->always_powered_in_suspend = val;
return count;
}
static DEVICE_ATTR_RW(always_powered_in_suspend);
static struct attribute *onboard_dev_attrs[] = {
&dev_attr_always_powered_in_suspend.attr,
NULL,
};
static umode_t onboard_dev_attrs_are_visible(struct kobject *kobj,
struct attribute *attr,
int n)
{
struct device *dev = kobj_to_dev(kobj);
struct onboard_dev *onboard_dev = dev_get_drvdata(dev);
if (attr == &dev_attr_always_powered_in_suspend.attr &&
!onboard_dev->pdata->is_hub)
return 0;
return attr->mode;
}
static const struct attribute_group onboard_dev_group = {
.is_visible = onboard_dev_attrs_are_visible,
.attrs = onboard_dev_attrs,
};
__ATTRIBUTE_GROUPS(onboard_dev);
static void onboard_dev_attach_usb_driver(struct work_struct *work)
{
int err;
err = driver_attach(&onboard_dev_usbdev_driver.driver);
if (err)
pr_err("Failed to attach USB driver: %pe\n", ERR_PTR(err));
}
static int onboard_dev_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct onboard_dev *onboard_dev;
int err;
onboard_dev = devm_kzalloc(dev, sizeof(*onboard_dev), GFP_KERNEL);
if (!onboard_dev)
return -ENOMEM;
onboard_dev->pdata = device_get_match_data(dev);
if (!onboard_dev->pdata)
return -EINVAL;
if (!onboard_dev->pdata->is_hub)
onboard_dev->always_powered_in_suspend = true;
onboard_dev->dev = dev;
err = onboard_dev_get_regulators(onboard_dev);
if (err)
return err;
onboard_dev->clk = devm_clk_get_optional(dev, NULL);
if (IS_ERR(onboard_dev->clk))
return dev_err_probe(dev, PTR_ERR(onboard_dev->clk),
"failed to get clock\n");
onboard_dev->reset_gpio = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(onboard_dev->reset_gpio))
return dev_err_probe(dev, PTR_ERR(onboard_dev->reset_gpio),
"failed to get reset GPIO\n");
mutex_init(&onboard_dev->lock);
INIT_LIST_HEAD(&onboard_dev->udev_list);
dev_set_drvdata(dev, onboard_dev);
err = onboard_dev_power_on(onboard_dev);
if (err)
return err;
/*
* The USB driver might have been detached from the USB devices by
* onboard_dev_remove() (e.g. through an 'unbind' by userspace),
* make sure to re-attach it if needed.
*
* This needs to be done deferred to avoid self-deadlocks on systems
* with nested onboard hubs.
*/
schedule_work(&attach_usb_driver_work);
return 0;
}
static void onboard_dev_remove(struct platform_device *pdev)
{
struct onboard_dev *onboard_dev = dev_get_drvdata(&pdev->dev);
struct usbdev_node *node;
struct usb_device *udev;
onboard_dev->going_away = true;
mutex_lock(&onboard_dev->lock);
/* unbind the USB devices to avoid dangling references to this device */
while (!list_empty(&onboard_dev->udev_list)) {
node = list_first_entry(&onboard_dev->udev_list,
struct usbdev_node, list);
udev = node->udev;
/*
* Unbinding the driver will call onboard_dev_remove_usbdev(),
* which acquires onboard_dev->lock. We must release the lock
* first.
*/
get_device(&udev->dev);
mutex_unlock(&onboard_dev->lock);
device_release_driver(&udev->dev);
put_device(&udev->dev);
mutex_lock(&onboard_dev->lock);
}
mutex_unlock(&onboard_dev->lock);
onboard_dev_power_off(onboard_dev);
}
MODULE_DEVICE_TABLE(of, onboard_dev_match);
static const struct dev_pm_ops __maybe_unused onboard_dev_pm_ops = {
SET_LATE_SYSTEM_SLEEP_PM_OPS(onboard_dev_suspend, onboard_dev_resume)
};
static struct platform_driver onboard_dev_driver = {
.probe = onboard_dev_probe,
.remove_new = onboard_dev_remove,
.driver = {
.name = "onboard-usb-dev",
.of_match_table = onboard_dev_match,
.pm = pm_ptr(&onboard_dev_pm_ops),
.dev_groups = onboard_dev_groups,
},
};
/************************** USB driver **************************/
#define VENDOR_ID_CYPRESS 0x04b4
#define VENDOR_ID_GENESYS 0x05e3
#define VENDOR_ID_MICROCHIP 0x0424
#define VENDOR_ID_REALTEK 0x0bda
#define VENDOR_ID_TI 0x0451
#define VENDOR_ID_VIA 0x2109
#define VENDOR_ID_XMOS 0x20B1
/*
* Returns the onboard_dev platform device that is associated with the USB
* device passed as parameter.
*/
static struct onboard_dev *_find_onboard_dev(struct device *dev)
{
struct platform_device *pdev;
struct device_node *np;
struct onboard_dev *onboard_dev;
pdev = of_find_device_by_node(dev->of_node);
if (!pdev) {
np = of_parse_phandle(dev->of_node, "peer-hub", 0);
if (!np) {
dev_err(dev, "failed to find device node for peer hub\n");
return ERR_PTR(-EINVAL);
}
pdev = of_find_device_by_node(np);
of_node_put(np);
if (!pdev)
return ERR_PTR(-ENODEV);
}
onboard_dev = dev_get_drvdata(&pdev->dev);
put_device(&pdev->dev);
/*
* The presence of drvdata indicates that the platform driver finished
* probing. This handles the case where (conceivably) we could be
* running at the exact same time as the platform driver's probe. If
* we detect the race we request probe deferral and we'll come back and
* try again.
*/
if (!onboard_dev)
return ERR_PTR(-EPROBE_DEFER);
return onboard_dev;
}
static int onboard_dev_usbdev_probe(struct usb_device *udev)
{
struct device *dev = &udev->dev;
struct onboard_dev *onboard_dev;
int err;
/* ignore supported devices without device tree node */
if (!dev->of_node)
return -ENODEV;
onboard_dev = _find_onboard_dev(dev);
if (IS_ERR(onboard_dev))
return PTR_ERR(onboard_dev);
dev_set_drvdata(dev, onboard_dev);
err = onboard_dev_add_usbdev(onboard_dev, udev);
if (err)
return err;
return 0;
}
static void onboard_dev_usbdev_disconnect(struct usb_device *udev)
{
struct onboard_dev *onboard_dev = dev_get_drvdata(&udev->dev);
onboard_dev_remove_usbdev(onboard_dev, udev);
}
static const struct usb_device_id onboard_dev_id_table[] = {
{ USB_DEVICE(VENDOR_ID_CYPRESS, 0x6504) }, /* CYUSB33{0,1,2}x/CYUSB230x 3.0 HUB */
{ USB_DEVICE(VENDOR_ID_CYPRESS, 0x6506) }, /* CYUSB33{0,1,2}x/CYUSB230x 2.0 HUB */
{ USB_DEVICE(VENDOR_ID_CYPRESS, 0x6570) }, /* CY7C6563x 2.0 HUB */
{ USB_DEVICE(VENDOR_ID_GENESYS, 0x0608) }, /* Genesys Logic GL850G USB 2.0 HUB */
{ USB_DEVICE(VENDOR_ID_GENESYS, 0x0610) }, /* Genesys Logic GL852G USB 2.0 HUB */
{ USB_DEVICE(VENDOR_ID_GENESYS, 0x0620) }, /* Genesys Logic GL3523 USB 3.1 HUB */
{ USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2412) }, /* USB2412 USB 2.0 HUB */
{ USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2514) }, /* USB2514B USB 2.0 HUB */
{ USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2517) }, /* USB2517 USB 2.0 HUB */
{ USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2744) }, /* USB5744 USB 2.0 HUB */
{ USB_DEVICE(VENDOR_ID_MICROCHIP, 0x5744) }, /* USB5744 USB 3.0 HUB */
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x0411) }, /* RTS5411 USB 3.1 HUB */
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x5411) }, /* RTS5411 USB 2.1 HUB */
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x0414) }, /* RTS5414 USB 3.2 HUB */
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x5414) }, /* RTS5414 USB 2.1 HUB */
{ USB_DEVICE(VENDOR_ID_TI, 0x8025) }, /* TI USB8020B 3.0 HUB */
{ USB_DEVICE(VENDOR_ID_TI, 0x8027) }, /* TI USB8020B 2.0 HUB */
{ USB_DEVICE(VENDOR_ID_TI, 0x8140) }, /* TI USB8041 3.0 HUB */
{ USB_DEVICE(VENDOR_ID_TI, 0x8142) }, /* TI USB8041 2.0 HUB */
{ USB_DEVICE(VENDOR_ID_VIA, 0x0817) }, /* VIA VL817 3.1 HUB */
{ USB_DEVICE(VENDOR_ID_VIA, 0x2817) }, /* VIA VL817 2.0 HUB */
{ USB_DEVICE(VENDOR_ID_XMOS, 0x0013) }, /* XMOS XVF3500 Voice Processor */
{}
};
MODULE_DEVICE_TABLE(usb, onboard_dev_id_table);
static struct usb_device_driver onboard_dev_usbdev_driver = {
.name = "onboard-usb-dev",
.probe = onboard_dev_usbdev_probe,
.disconnect = onboard_dev_usbdev_disconnect,
.generic_subclass = 1,
.supports_autosuspend = 1,
.id_table = onboard_dev_id_table,
};
static int __init onboard_dev_init(void)
{
int ret;
ret = usb_register_device_driver(&onboard_dev_usbdev_driver, THIS_MODULE);
if (ret)
return ret;
ret = platform_driver_register(&onboard_dev_driver);
if (ret)
usb_deregister_device_driver(&onboard_dev_usbdev_driver);
return ret;
}
module_init(onboard_dev_init);
static void __exit onboard_dev_exit(void)
{
usb_deregister_device_driver(&onboard_dev_usbdev_driver);
platform_driver_unregister(&onboard_dev_driver);
cancel_work_sync(&attach_usb_driver_work);
}
module_exit(onboard_dev_exit);
MODULE_AUTHOR("Matthias Kaehlcke <mka@chromium.org>");
MODULE_DESCRIPTION("Driver for discrete onboard USB devices");
MODULE_LICENSE("GPL v2");

View File

@ -3,65 +3,96 @@
* Copyright (c) 2022, Google LLC
*/
#ifndef _USB_MISC_ONBOARD_USB_HUB_H
#define _USB_MISC_ONBOARD_USB_HUB_H
#ifndef _USB_MISC_ONBOARD_USB_DEV_H
#define _USB_MISC_ONBOARD_USB_DEV_H
struct onboard_hub_pdata {
#define MAX_SUPPLIES 2
struct onboard_dev_pdata {
unsigned long reset_us; /* reset pulse width in us */
unsigned int num_supplies; /* number of supplies */
const char * const supply_names[MAX_SUPPLIES];
bool is_hub;
};
static const struct onboard_hub_pdata microchip_usb424_data = {
static const struct onboard_dev_pdata microchip_usb424_data = {
.reset_us = 1,
.num_supplies = 1,
.supply_names = { "vdd" },
.is_hub = true,
};
static const struct onboard_hub_pdata microchip_usb5744_data = {
static const struct onboard_dev_pdata microchip_usb5744_data = {
.reset_us = 0,
.num_supplies = 2,
.supply_names = { "vdd", "vdd2" },
.is_hub = true,
};
static const struct onboard_hub_pdata realtek_rts5411_data = {
static const struct onboard_dev_pdata realtek_rts5411_data = {
.reset_us = 0,
.num_supplies = 1,
.supply_names = { "vdd" },
.is_hub = true,
};
static const struct onboard_hub_pdata ti_tusb8020b_data = {
static const struct onboard_dev_pdata ti_tusb8020b_data = {
.reset_us = 3000,
.num_supplies = 1,
.supply_names = { "vdd" },
.is_hub = true,
};
static const struct onboard_hub_pdata ti_tusb8041_data = {
static const struct onboard_dev_pdata ti_tusb8041_data = {
.reset_us = 3000,
.num_supplies = 1,
.supply_names = { "vdd" },
.is_hub = true,
};
static const struct onboard_hub_pdata cypress_hx3_data = {
static const struct onboard_dev_pdata cypress_hx3_data = {
.reset_us = 10000,
.num_supplies = 2,
.supply_names = { "vdd", "vdd2" },
.is_hub = true,
};
static const struct onboard_hub_pdata cypress_hx2vl_data = {
static const struct onboard_dev_pdata cypress_hx2vl_data = {
.reset_us = 1,
.num_supplies = 1,
.supply_names = { "vdd" },
.is_hub = true,
};
static const struct onboard_hub_pdata genesys_gl850g_data = {
static const struct onboard_dev_pdata genesys_gl850g_data = {
.reset_us = 3,
.num_supplies = 1,
.supply_names = { "vdd" },
.is_hub = true,
};
static const struct onboard_hub_pdata genesys_gl852g_data = {
static const struct onboard_dev_pdata genesys_gl852g_data = {
.reset_us = 50,
.num_supplies = 1,
.supply_names = { "vdd" },
.is_hub = true,
};
static const struct onboard_hub_pdata vialab_vl817_data = {
static const struct onboard_dev_pdata vialab_vl817_data = {
.reset_us = 10,
.num_supplies = 1,
.supply_names = { "vdd" },
.is_hub = true,
};
static const struct of_device_id onboard_hub_match[] = {
static const struct onboard_dev_pdata xmos_xvf3500_data = {
.reset_us = 1,
.num_supplies = 2,
.supply_names = { "vdd", "vddio" },
.is_hub = false,
};
static const struct of_device_id onboard_dev_match[] = {
{ .compatible = "usb424,2412", .data = &microchip_usb424_data, },
{ .compatible = "usb424,2514", .data = &microchip_usb424_data, },
{ .compatible = "usb424,2517", .data = &microchip_usb424_data, },
@ -84,7 +115,8 @@ static const struct of_device_id onboard_hub_match[] = {
{ .compatible = "usbbda,5414", .data = &realtek_rts5411_data, },
{ .compatible = "usb2109,817", .data = &vialab_vl817_data, },
{ .compatible = "usb2109,2817", .data = &vialab_vl817_data, },
{ .compatible = "usb20b1,0013", .data = &xmos_xvf3500_data, },
{}
};
#endif /* _USB_MISC_ONBOARD_USB_HUB_H */
#endif /* _USB_MISC_ONBOARD_USB_DEV_H */

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* API for creating and destroying USB onboard hub platform devices
* API for creating and destroying USB onboard platform devices
*
* Copyright (c) 2022, Google LLC
*/
@ -15,29 +15,30 @@
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/usb/of.h>
#include <linux/usb/onboard_hub.h>
#include <linux/usb/onboard_dev.h>
#include "onboard_usb_hub.h"
#include "onboard_usb_dev.h"
struct pdev_list_entry {
struct platform_device *pdev;
struct list_head node;
};
static bool of_is_onboard_usb_hub(const struct device_node *np)
static bool of_is_onboard_usb_dev(struct device_node *np)
{
return !!of_match_node(onboard_hub_match, np);
return !!of_match_node(onboard_dev_match, np);
}
/**
* onboard_hub_create_pdevs -- create platform devices for onboard USB hubs
* @parent_hub : parent hub to scan for connected onboard hubs
* @pdev_list : list of onboard hub platform devices owned by the parent hub
* onboard_dev_create_pdevs -- create platform devices for onboard USB devices
* @parent_hub : parent hub to scan for connected onboard devices
* @pdev_list : list of onboard platform devices owned by the parent hub
*
* Creates a platform device for each supported onboard hub that is connected to
* the given parent hub. The platform device is in charge of initializing the
* hub (enable regulators, take the hub out of reset, ...) and can optionally
* control whether the hub remains powered during system suspend or not.
* Creates a platform device for each supported onboard device that is connected
* to the given parent hub. The platform device is in charge of initializing the
* device (enable regulators, take the device out of reset, ...). For onboard
* hubs, it can optionally control whether the device remains powered during
* system suspend or not.
*
* To keep track of the platform devices they are added to a list that is owned
* by the parent hub.
@ -50,9 +51,9 @@ static bool of_is_onboard_usb_hub(const struct device_node *np)
* node. That means the root hubs of the primary and secondary HCD share the
* same device tree node (the HCD node). As a result this function can be called
* twice with the same DT node for root hubs. We only want to create a single
* platform device for each physical onboard hub, hence for root hubs the loop
* is only executed for the root hub of the primary HCD. Since the function
* scans through all child nodes it still creates pdevs for onboard hubs
* platform device for each physical onboard device, hence for root hubs the
* loop is only executed for the root hub of the primary HCD. Since the function
* scans through all child nodes it still creates pdevs for onboard devices
* connected to the root hub of the secondary HCD if needed.
*
* Further there must be only one platform device for onboard hubs with a peer
@ -63,7 +64,7 @@ static bool of_is_onboard_usb_hub(const struct device_node *np)
* the function processes the nodes of both peers. A platform device is only
* created if the peer hub doesn't have one already.
*/
void onboard_hub_create_pdevs(struct usb_device *parent_hub, struct list_head *pdev_list)
void onboard_dev_create_pdevs(struct usb_device *parent_hub, struct list_head *pdev_list)
{
int i;
struct usb_hcd *hcd = bus_to_hcd(parent_hub->bus);
@ -82,7 +83,7 @@ void onboard_hub_create_pdevs(struct usb_device *parent_hub, struct list_head *p
if (!np)
continue;
if (!of_is_onboard_usb_hub(np))
if (!of_is_onboard_usb_dev(np))
goto node_put;
npc = of_parse_phandle(np, "peer-hub", 0);
@ -104,7 +105,7 @@ void onboard_hub_create_pdevs(struct usb_device *parent_hub, struct list_head *p
pdev = of_platform_device_create(np, NULL, &parent_hub->dev);
if (!pdev) {
dev_err(&parent_hub->dev,
"failed to create platform device for onboard hub '%pOF'\n", np);
"failed to create platform device for onboard dev '%pOF'\n", np);
goto node_put;
}
@ -121,16 +122,16 @@ node_put:
of_node_put(np);
}
}
EXPORT_SYMBOL_GPL(onboard_hub_create_pdevs);
EXPORT_SYMBOL_GPL(onboard_dev_create_pdevs);
/**
* onboard_hub_destroy_pdevs -- free resources of onboard hub platform devices
* @pdev_list : list of onboard hub platform devices
* onboard_dev_destroy_pdevs -- free resources of onboard platform devices
* @pdev_list : list of onboard platform devices
*
* Destroys the platform devices in the given list and frees the memory associated
* with the list entry.
*/
void onboard_hub_destroy_pdevs(struct list_head *pdev_list)
void onboard_dev_destroy_pdevs(struct list_head *pdev_list)
{
struct pdev_list_entry *pdle, *tmp;
@ -140,4 +141,4 @@ void onboard_hub_destroy_pdevs(struct list_head *pdev_list)
kfree(pdle);
}
}
EXPORT_SYMBOL_GPL(onboard_hub_destroy_pdevs);
EXPORT_SYMBOL_GPL(onboard_dev_destroy_pdevs);

View File

@ -1,507 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for onboard USB hubs
*
* Copyright (c) 2022, Google LLC
*/
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/suspend.h>
#include <linux/sysfs.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/usb/onboard_hub.h>
#include <linux/workqueue.h>
#include "onboard_usb_hub.h"
/*
* Use generic names, as the actual names might differ between hubs. If a new
* hub requires more than the currently supported supplies, add a new one here.
*/
static const char * const supply_names[] = {
"vdd",
"vdd2",
};
#define MAX_SUPPLIES ARRAY_SIZE(supply_names)
static void onboard_hub_attach_usb_driver(struct work_struct *work);
static struct usb_device_driver onboard_hub_usbdev_driver;
static DECLARE_WORK(attach_usb_driver_work, onboard_hub_attach_usb_driver);
/************************** Platform driver **************************/
struct usbdev_node {
struct usb_device *udev;
struct list_head list;
};
struct onboard_hub {
struct regulator_bulk_data supplies[MAX_SUPPLIES];
struct device *dev;
const struct onboard_hub_pdata *pdata;
struct gpio_desc *reset_gpio;
bool always_powered_in_suspend;
bool is_powered_on;
bool going_away;
struct list_head udev_list;
struct mutex lock;
struct clk *clk;
};
static int onboard_hub_power_on(struct onboard_hub *hub)
{
int err;
err = clk_prepare_enable(hub->clk);
if (err) {
dev_err(hub->dev, "failed to enable clock: %pe\n", ERR_PTR(err));
return err;
}
err = regulator_bulk_enable(hub->pdata->num_supplies, hub->supplies);
if (err) {
dev_err(hub->dev, "failed to enable supplies: %pe\n", ERR_PTR(err));
goto disable_clk;
}
fsleep(hub->pdata->reset_us);
gpiod_set_value_cansleep(hub->reset_gpio, 0);
hub->is_powered_on = true;
return 0;
disable_clk:
clk_disable_unprepare(hub->clk);
return err;
}
static int onboard_hub_power_off(struct onboard_hub *hub)
{
int err;
gpiod_set_value_cansleep(hub->reset_gpio, 1);
err = regulator_bulk_disable(hub->pdata->num_supplies, hub->supplies);
if (err) {
dev_err(hub->dev, "failed to disable supplies: %pe\n", ERR_PTR(err));
return err;
}
clk_disable_unprepare(hub->clk);
hub->is_powered_on = false;
return 0;
}
static int __maybe_unused onboard_hub_suspend(struct device *dev)
{
struct onboard_hub *hub = dev_get_drvdata(dev);
struct usbdev_node *node;
bool power_off = true;
if (hub->always_powered_in_suspend)
return 0;
mutex_lock(&hub->lock);
list_for_each_entry(node, &hub->udev_list, list) {
if (!device_may_wakeup(node->udev->bus->controller))
continue;
if (usb_wakeup_enabled_descendants(node->udev)) {
power_off = false;
break;
}
}
mutex_unlock(&hub->lock);
if (!power_off)
return 0;
return onboard_hub_power_off(hub);
}
static int __maybe_unused onboard_hub_resume(struct device *dev)
{
struct onboard_hub *hub = dev_get_drvdata(dev);
if (hub->is_powered_on)
return 0;
return onboard_hub_power_on(hub);
}
static inline void get_udev_link_name(const struct usb_device *udev, char *buf, size_t size)
{
snprintf(buf, size, "usb_dev.%s", dev_name(&udev->dev));
}
static int onboard_hub_add_usbdev(struct onboard_hub *hub, struct usb_device *udev)
{
struct usbdev_node *node;
char link_name[64];
int err;
mutex_lock(&hub->lock);
if (hub->going_away) {
err = -EINVAL;
goto error;
}
node = kzalloc(sizeof(*node), GFP_KERNEL);
if (!node) {
err = -ENOMEM;
goto error;
}
node->udev = udev;
list_add(&node->list, &hub->udev_list);
mutex_unlock(&hub->lock);
get_udev_link_name(udev, link_name, sizeof(link_name));
WARN_ON(sysfs_create_link(&hub->dev->kobj, &udev->dev.kobj, link_name));
return 0;
error:
mutex_unlock(&hub->lock);
return err;
}
static void onboard_hub_remove_usbdev(struct onboard_hub *hub, const struct usb_device *udev)
{
struct usbdev_node *node;
char link_name[64];
get_udev_link_name(udev, link_name, sizeof(link_name));
sysfs_remove_link(&hub->dev->kobj, link_name);
mutex_lock(&hub->lock);
list_for_each_entry(node, &hub->udev_list, list) {
if (node->udev == udev) {
list_del(&node->list);
kfree(node);
break;
}
}
mutex_unlock(&hub->lock);
}
static ssize_t always_powered_in_suspend_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
const struct onboard_hub *hub = dev_get_drvdata(dev);
return sysfs_emit(buf, "%d\n", hub->always_powered_in_suspend);
}
static ssize_t always_powered_in_suspend_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct onboard_hub *hub = dev_get_drvdata(dev);
bool val;
int ret;
ret = kstrtobool(buf, &val);
if (ret < 0)
return ret;
hub->always_powered_in_suspend = val;
return count;
}
static DEVICE_ATTR_RW(always_powered_in_suspend);
static struct attribute *onboard_hub_attrs[] = {
&dev_attr_always_powered_in_suspend.attr,
NULL,
};
ATTRIBUTE_GROUPS(onboard_hub);
static void onboard_hub_attach_usb_driver(struct work_struct *work)
{
int err;
err = driver_attach(&onboard_hub_usbdev_driver.driver);
if (err)
pr_err("Failed to attach USB driver: %pe\n", ERR_PTR(err));
}
static int onboard_hub_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct onboard_hub *hub;
unsigned int i;
int err;
hub = devm_kzalloc(dev, sizeof(*hub), GFP_KERNEL);
if (!hub)
return -ENOMEM;
hub->pdata = device_get_match_data(dev);
if (!hub->pdata)
return -EINVAL;
if (hub->pdata->num_supplies > MAX_SUPPLIES)
return dev_err_probe(dev, -EINVAL, "max %zu supplies supported!\n",
MAX_SUPPLIES);
for (i = 0; i < hub->pdata->num_supplies; i++)
hub->supplies[i].supply = supply_names[i];
err = devm_regulator_bulk_get(dev, hub->pdata->num_supplies, hub->supplies);
if (err) {
dev_err(dev, "Failed to get regulator supplies: %pe\n", ERR_PTR(err));
return err;
}
hub->clk = devm_clk_get_optional(dev, NULL);
if (IS_ERR(hub->clk))
return dev_err_probe(dev, PTR_ERR(hub->clk), "failed to get clock\n");
hub->reset_gpio = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(hub->reset_gpio))
return dev_err_probe(dev, PTR_ERR(hub->reset_gpio), "failed to get reset GPIO\n");
hub->dev = dev;
mutex_init(&hub->lock);
INIT_LIST_HEAD(&hub->udev_list);
dev_set_drvdata(dev, hub);
err = onboard_hub_power_on(hub);
if (err)
return err;
/*
* The USB driver might have been detached from the USB devices by
* onboard_hub_remove() (e.g. through an 'unbind' by userspace),
* make sure to re-attach it if needed.
*
* This needs to be done deferred to avoid self-deadlocks on systems
* with nested onboard hubs.
*/
schedule_work(&attach_usb_driver_work);
return 0;
}
static void onboard_hub_remove(struct platform_device *pdev)
{
struct onboard_hub *hub = dev_get_drvdata(&pdev->dev);
struct usbdev_node *node;
struct usb_device *udev;
hub->going_away = true;
mutex_lock(&hub->lock);
/* unbind the USB devices to avoid dangling references to this device */
while (!list_empty(&hub->udev_list)) {
node = list_first_entry(&hub->udev_list, struct usbdev_node, list);
udev = node->udev;
/*
* Unbinding the driver will call onboard_hub_remove_usbdev(),
* which acquires hub->lock. We must release the lock first.
*/
get_device(&udev->dev);
mutex_unlock(&hub->lock);
device_release_driver(&udev->dev);
put_device(&udev->dev);
mutex_lock(&hub->lock);
}
mutex_unlock(&hub->lock);
onboard_hub_power_off(hub);
}
MODULE_DEVICE_TABLE(of, onboard_hub_match);
static const struct dev_pm_ops __maybe_unused onboard_hub_pm_ops = {
SET_LATE_SYSTEM_SLEEP_PM_OPS(onboard_hub_suspend, onboard_hub_resume)
};
static struct platform_driver onboard_hub_driver = {
.probe = onboard_hub_probe,
.remove_new = onboard_hub_remove,
.driver = {
.name = "onboard-usb-hub",
.of_match_table = onboard_hub_match,
.pm = pm_ptr(&onboard_hub_pm_ops),
.dev_groups = onboard_hub_groups,
},
};
/************************** USB driver **************************/
#define VENDOR_ID_CYPRESS 0x04b4
#define VENDOR_ID_GENESYS 0x05e3
#define VENDOR_ID_MICROCHIP 0x0424
#define VENDOR_ID_REALTEK 0x0bda
#define VENDOR_ID_TI 0x0451
#define VENDOR_ID_VIA 0x2109
/*
* Returns the onboard_hub platform device that is associated with the USB
* device passed as parameter.
*/
static struct onboard_hub *_find_onboard_hub(struct device *dev)
{
struct platform_device *pdev;
struct device_node *np;
struct onboard_hub *hub;
pdev = of_find_device_by_node(dev->of_node);
if (!pdev) {
np = of_parse_phandle(dev->of_node, "peer-hub", 0);
if (!np) {
dev_err(dev, "failed to find device node for peer hub\n");
return ERR_PTR(-EINVAL);
}
pdev = of_find_device_by_node(np);
of_node_put(np);
if (!pdev)
return ERR_PTR(-ENODEV);
}
hub = dev_get_drvdata(&pdev->dev);
put_device(&pdev->dev);
/*
* The presence of drvdata ('hub') indicates that the platform driver
* finished probing. This handles the case where (conceivably) we could
* be running at the exact same time as the platform driver's probe. If
* we detect the race we request probe deferral and we'll come back and
* try again.
*/
if (!hub)
return ERR_PTR(-EPROBE_DEFER);
return hub;
}
static int onboard_hub_usbdev_probe(struct usb_device *udev)
{
struct device *dev = &udev->dev;
struct onboard_hub *hub;
int err;
/* ignore supported hubs without device tree node */
if (!dev->of_node)
return -ENODEV;
hub = _find_onboard_hub(dev);
if (IS_ERR(hub))
return PTR_ERR(hub);
dev_set_drvdata(dev, hub);
err = onboard_hub_add_usbdev(hub, udev);
if (err)
return err;
return 0;
}
static void onboard_hub_usbdev_disconnect(struct usb_device *udev)
{
struct onboard_hub *hub = dev_get_drvdata(&udev->dev);
onboard_hub_remove_usbdev(hub, udev);
}
static const struct usb_device_id onboard_hub_id_table[] = {
{ USB_DEVICE(VENDOR_ID_CYPRESS, 0x6504) }, /* CYUSB33{0,1,2}x/CYUSB230x 3.0 */
{ USB_DEVICE(VENDOR_ID_CYPRESS, 0x6506) }, /* CYUSB33{0,1,2}x/CYUSB230x 2.0 */
{ USB_DEVICE(VENDOR_ID_CYPRESS, 0x6570) }, /* CY7C6563x 2.0 */
{ USB_DEVICE(VENDOR_ID_GENESYS, 0x0608) }, /* Genesys Logic GL850G USB 2.0 */
{ USB_DEVICE(VENDOR_ID_GENESYS, 0x0610) }, /* Genesys Logic GL852G USB 2.0 */
{ USB_DEVICE(VENDOR_ID_GENESYS, 0x0620) }, /* Genesys Logic GL3523 USB 3.1 */
{ USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2412) }, /* USB2412 USB 2.0 */
{ USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2514) }, /* USB2514B USB 2.0 */
{ USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2517) }, /* USB2517 USB 2.0 */
{ USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2744) }, /* USB5744 USB 2.0 */
{ USB_DEVICE(VENDOR_ID_MICROCHIP, 0x5744) }, /* USB5744 USB 3.0 */
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x0411) }, /* RTS5411 USB 3.1 */
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x5411) }, /* RTS5411 USB 2.1 */
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x0414) }, /* RTS5414 USB 3.2 */
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x5414) }, /* RTS5414 USB 2.1 */
{ USB_DEVICE(VENDOR_ID_TI, 0x8025) }, /* TI USB8020B 3.0 */
{ USB_DEVICE(VENDOR_ID_TI, 0x8027) }, /* TI USB8020B 2.0 */
{ USB_DEVICE(VENDOR_ID_TI, 0x8140) }, /* TI USB8041 3.0 */
{ USB_DEVICE(VENDOR_ID_TI, 0x8142) }, /* TI USB8041 2.0 */
{ USB_DEVICE(VENDOR_ID_VIA, 0x0817) }, /* VIA VL817 3.1 */
{ USB_DEVICE(VENDOR_ID_VIA, 0x2817) }, /* VIA VL817 2.0 */
{}
};
MODULE_DEVICE_TABLE(usb, onboard_hub_id_table);
static struct usb_device_driver onboard_hub_usbdev_driver = {
.name = "onboard-usb-hub",
.probe = onboard_hub_usbdev_probe,
.disconnect = onboard_hub_usbdev_disconnect,
.generic_subclass = 1,
.supports_autosuspend = 1,
.id_table = onboard_hub_id_table,
};
static int __init onboard_hub_init(void)
{
int ret;
ret = usb_register_device_driver(&onboard_hub_usbdev_driver, THIS_MODULE);
if (ret)
return ret;
ret = platform_driver_register(&onboard_hub_driver);
if (ret)
usb_deregister_device_driver(&onboard_hub_usbdev_driver);
return ret;
}
module_init(onboard_hub_init);
static void __exit onboard_hub_exit(void)
{
usb_deregister_device_driver(&onboard_hub_usbdev_driver);
platform_driver_unregister(&onboard_hub_driver);
cancel_work_sync(&attach_usb_driver_work);
}
module_exit(onboard_hub_exit);
MODULE_AUTHOR("Matthias Kaehlcke <mka@chromium.org>");
MODULE_DESCRIPTION("Driver for discrete onboard USB hubs");
MODULE_LICENSE("GPL v2");

View File

@ -677,7 +677,7 @@ static int uss720_probe(struct usb_interface *intf,
struct parport_uss720_private *priv;
struct parport *pp;
unsigned char reg;
int i;
int ret;
dev_dbg(&intf->dev, "probe: vendor id 0x%x, device id 0x%x\n",
le16_to_cpu(usbdev->descriptor.idVendor),
@ -688,12 +688,12 @@ static int uss720_probe(struct usb_interface *intf,
usb_put_dev(usbdev);
return -ENODEV;
}
i = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2);
dev_dbg(&intf->dev, "set interface result %d\n", i);
ret = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2);
dev_dbg(&intf->dev, "set interface result %d\n", ret);
interface = intf->cur_altsetting;
if (interface->desc.bNumEndpoints < 3) {
if (interface->desc.bNumEndpoints < 2) {
usb_put_dev(usbdev);
return -ENODEV;
}
@ -719,18 +719,27 @@ static int uss720_probe(struct usb_interface *intf,
priv->pp = pp;
pp->private_data = priv;
pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_ECP | PARPORT_MODE_COMPAT;
pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_COMPAT;
if (interface->desc.bNumEndpoints >= 3)
pp->modes |= PARPORT_MODE_ECP;
pp->dev = &usbdev->dev;
/* set the USS720 control register to manual mode, no ECP compression, enable all ints */
set_1284_register(pp, 7, 0x00, GFP_KERNEL);
set_1284_register(pp, 6, 0x30, GFP_KERNEL); /* PS/2 mode */
set_1284_register(pp, 2, 0x0c, GFP_KERNEL);
/* debugging */
get_1284_register(pp, 0, &reg, GFP_KERNEL);
dev_dbg(&intf->dev, "reg: %7ph\n", priv->reg);
i = usb_find_last_int_in_endpoint(interface, &epd);
if (!i) {
/* The Belkin F5U002 Rev 2 P80453-B USB parallel port adapter shares the
* device ID 050d:0002 with some other device that works with this
* driver, but it itself does not. Detect and handle the bad cable
* here. */
ret = get_1284_register(pp, 0, &reg, GFP_KERNEL);
dev_dbg(&intf->dev, "reg: %7ph\n", priv->reg);
if (ret < 0)
return ret;
ret = usb_find_last_int_in_endpoint(interface, &epd);
if (!ret) {
dev_dbg(&intf->dev, "epaddr %d interval %d\n",
epd->bEndpointAddress, epd->bInterval);
}
@ -766,14 +775,15 @@ static void uss720_disconnect(struct usb_interface *intf)
/* table of cables that work through this driver */
static const struct usb_device_id uss720_table[] = {
{ USB_DEVICE(0x047e, 0x1001) },
{ USB_DEVICE(0x04b8, 0x0002) },
{ USB_DEVICE(0x04b8, 0x0003) },
{ USB_DEVICE(0x047e, 0x1001) }, /* Infowave 901-0030 */
{ USB_DEVICE(0x04b8, 0x0002) }, /* Epson CAEUL0002 ISD-103 */
{ USB_DEVICE(0x04b8, 0x0003) }, /* Epson ISD-101 */
{ USB_DEVICE(0x050d, 0x0002) },
{ USB_DEVICE(0x050d, 0x1202) },
{ USB_DEVICE(0x050d, 0x1202) }, /* Belkin F5U120-PC */
{ USB_DEVICE(0x0557, 0x2001) },
{ USB_DEVICE(0x05ab, 0x0002) },
{ USB_DEVICE(0x06c6, 0x0100) },
{ USB_DEVICE(0x05ab, 0x0002) }, /* Belkin F5U002 ISD-101 */
{ USB_DEVICE(0x05ab, 0x1001) }, /* Belkin F5U002 P80453-A */
{ USB_DEVICE(0x06c6, 0x0100) }, /* Infowave ISD-103 */
{ USB_DEVICE(0x0729, 0x1284) },
{ USB_DEVICE(0x1293, 0x0002) },
{ } /* Terminating entry */

View File

@ -1156,15 +1156,6 @@ void musb_free_request(struct usb_ep *ep, struct usb_request *req)
kfree(request);
}
static LIST_HEAD(buffers);
struct free_record {
struct list_head list;
struct device *dev;
unsigned bytes;
dma_addr_t dma;
};
/*
* Context: controller locked, IRQs blocked.
*/

View File

@ -1005,7 +1005,6 @@ struct platform_driver fsl_otg_driver = {
.remove_new = fsl_otg_remove,
.driver = {
.name = driver_name,
.owner = THIS_MODULE,
},
};

View File

@ -71,6 +71,7 @@ static void nop_reset(struct usb_phy_generic *nop)
gpiod_set_value_cansleep(nop->gpiod_reset, 1);
usleep_range(10000, 20000);
gpiod_set_value_cansleep(nop->gpiod_reset, 0);
usleep_range(10000, 30000);
}
/* interface to regulator framework */

View File

@ -363,14 +363,14 @@ static void usbhsc_clk_disable_unprepare(struct usbhs_priv *priv)
* platform default param
*/
/* commonly used on old SH-Mobile SoCs */
/* commonly used on old SH-Mobile and RZ/G2L family SoCs */
static struct renesas_usbhs_driver_pipe_config usbhsc_default_pipe[] = {
RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_CONTROL, 64, 0x00, false),
RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_ISOC, 1024, 0x08, false),
RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_ISOC, 1024, 0x18, false),
RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x28, true),
RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x38, true),
RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_ISOC, 1024, 0x08, true),
RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_ISOC, 1024, 0x28, true),
RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x48, true),
RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x58, true),
RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x68, true),
RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_INT, 64, 0x04, false),
RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_INT, 64, 0x05, false),
RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_INT, 64, 0x06, false),
@ -565,6 +565,18 @@ static const struct of_device_id usbhs_of_match[] = {
.compatible = "renesas,usbhs-r8a77995",
.data = &usbhs_rcar_gen3_with_pll_plat_info,
},
{
.compatible = "renesas,usbhs-r9a07g043",
.data = &usbhs_rzg2l_plat_info,
},
{
.compatible = "renesas,usbhs-r9a07g044",
.data = &usbhs_rzg2l_plat_info,
},
{
.compatible = "renesas,usbhs-r9a07g054",
.data = &usbhs_rzg2l_plat_info,
},
{
.compatible = "renesas,rcar-gen2-usbhs",
.data = &usbhs_rcar_gen2_plat_info,
@ -581,7 +593,11 @@ static const struct of_device_id usbhs_of_match[] = {
.compatible = "renesas,rza2-usbhs",
.data = &usbhs_rza2_plat_info,
},
{ },
{
.compatible = "renesas,rzg2l-usbhs",
.data = &usbhs_rzg2l_plat_info,
},
{ }
};
MODULE_DEVICE_TABLE(of, usbhs_of_match);
@ -595,16 +611,11 @@ static int usbhs_probe(struct platform_device *pdev)
u32 tmp;
int irq;
/* check device node */
if (dev_of_node(dev))
info = of_device_get_match_data(dev);
else
info = renesas_usbhs_get_info(pdev);
/* check platform information */
info = of_device_get_match_data(dev);
if (!info) {
dev_err(dev, "no platform information\n");
return -EINVAL;
info = dev_get_platdata(dev);
if (!info)
return dev_err_probe(dev, -EINVAL, "no platform info\n");
}
/* platform data */

View File

@ -3,3 +3,4 @@
extern const struct renesas_usbhs_platform_info usbhs_rza1_plat_info;
extern const struct renesas_usbhs_platform_info usbhs_rza2_plat_info;
extern const struct renesas_usbhs_platform_info usbhs_rzg2l_plat_info;

View File

@ -71,3 +71,16 @@ const struct renesas_usbhs_platform_info usbhs_rza2_plat_info = {
.has_new_pipe_configs = 1,
},
};
const struct renesas_usbhs_platform_info usbhs_rzg2l_plat_info = {
.platform_callback = {
.hardware_init = usbhs_rza2_hardware_init,
.hardware_exit = usbhs_rza2_hardware_exit,
.power_ctrl = usbhs_rza2_power_ctrl,
.get_id = usbhs_get_id_as_gadget,
},
.driver_param = {
.has_cnen = 1,
.cfifo_byte_addr = 1,
},
};

View File

@ -802,7 +802,6 @@ static struct typec_altmode_driver dp_altmode_driver = {
.remove = dp_altmode_remove,
.driver = {
.name = "typec_displayport",
.owner = THIS_MODULE,
.dev_groups = displayport_groups,
},
};

View File

@ -35,7 +35,6 @@ static struct typec_altmode_driver nvidia_altmode_driver = {
.remove = nvidia_altmode_remove,
.driver = {
.name = "typec_nvidia",
.owner = THIS_MODULE,
},
};
module_typec_altmode_driver(nvidia_altmode_driver);

View File

@ -60,7 +60,7 @@ config TYPEC_MUX_PTN36502
tristate "NXP PTN36502 Type-C redriver driver"
depends on I2C
depends on DRM || DRM=n
select DRM_PANEL_BRIDGE if DRM
select DRM_AUX_BRIDGE if DRM_BRIDGE && OF
select REGMAP_I2C
help
Say Y or M if your system has a NXP PTN36502 Type-C redriver chip

View File

@ -48,10 +48,10 @@ static int gpio_sbu_switch_set(struct typec_switch_dev *sw,
}
if (enabled != sbu_mux->enabled)
gpiod_set_value(sbu_mux->enable_gpio, enabled);
gpiod_set_value_cansleep(sbu_mux->enable_gpio, enabled);
if (swapped != sbu_mux->swapped)
gpiod_set_value(sbu_mux->select_gpio, swapped);
gpiod_set_value_cansleep(sbu_mux->select_gpio, swapped);
sbu_mux->enabled = enabled;
sbu_mux->swapped = swapped;
@ -82,7 +82,7 @@ static int gpio_sbu_mux_set(struct typec_mux_dev *mux,
break;
}
gpiod_set_value(sbu_mux->enable_gpio, sbu_mux->enabled);
gpiod_set_value_cansleep(sbu_mux->enable_gpio, sbu_mux->enabled);
mutex_unlock(&sbu_mux->lock);
@ -141,7 +141,7 @@ static void gpio_sbu_mux_remove(struct platform_device *pdev)
{
struct gpio_sbu_mux *sbu_mux = platform_get_drvdata(pdev);
gpiod_set_value(sbu_mux->enable_gpio, 0);
gpiod_set_value_cansleep(sbu_mux->enable_gpio, 0);
typec_mux_unregister(sbu_mux->mux);
typec_switch_unregister(sbu_mux->sw);

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