USB / Thunderbolt changes for 6.0-rc1
Here is the big set of Thunderbolt and USB changes for 6.0-rc1. Lots of little things here, nothing major, just constant development on some new hardware support and cleanups of older drivers. Highlights of this pull request are: - lots of typec changes and improvements for new hardware - new gadget controller driver - thunderbolt support for new hardware - the normal set of new usb-serial device ids and cleanups - loads of dwc3 controller fixes and improvements - mtu3 driver updates - testusb fixes for longtime issues (not many people use this tool it seems.) - minor driver fixes and improvements over the USB tree - chromeos platform driver changes were added and then reverted as they depened on some typec changes, but the cross-tree merges caused problems so they will come back later through the platform tree. All of these have been in linux-next for a while now with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYup5Rg8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yko/ACfYD9mdlr4WleUpVw5/uNywN6sL9EAn1tv0V8W cUTAoWxAf5orClAC22ZU =Vcqd -----END PGP SIGNATURE----- Merge tag 'usb-6.0-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 Thunderbolt and USB changes for 6.0-rc1. Lots of little things here, nothing major, just constant development on some new hardware support and cleanups of older drivers. Highlights are: - lots of typec changes and improvements for new hardware - new gadget controller driver - thunderbolt support for new hardware - the normal set of new usb-serial device ids and cleanups - loads of dwc3 controller fixes and improvements - mtu3 driver updates - testusb fixes for longtime issues (not many people use this tool it seems.) - minor driver fixes and improvements over the USB tree - chromeos platform driver changes were added and then reverted as they depened on some typec changes, but the cross-tree merges caused problems so they will come back later through the platform tree. All of these have been in linux-next for a while now with no reported issues" * tag 'usb-6.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (193 commits) usb: misc: onboard_usb_hub: Remove duplicated power_on delay usb: misc: onboard_usb_hub: Add TI USB8041 hub support usb: misc: onboard_usb_hub: Add reset-gpio support USB: usbsevseg: convert sysfs snprintf to sysfs_emit dt-bindings: usb: Add binding for TI USB8041 hub controller ARM: multi_v7_defconfig: enable USB onboard HUB driver ARM: dts: stm32: add support for USB2514B onboard hub on stm32mp15xx-dkx usb: misc: onboard-hub: add support for Microchip USB2514B USB 2.0 hub dt-bindings: usb: generic-ehci: allow usb-hcd schema properties usb: typec: ucsi: stm32g0: add bootloader support usb: typec: ucsi: stm32g0: add support for stm32g0 controller dt-bindings: usb: typec: add bindings for stm32g0 controller usb: typec: ucsi: Acknowledge the GET_ERROR_STATUS command completion usb: cdns3: change place of 'priv_ep' assignment in cdns3_gadget_ep_dequeue(), cdns3_gadget_ep_enable() usb/chipidea: fix repeated words in comments usb: renesas-xhci: Do not print any log while fw verif success usb: typec: retimer: Add missing id check in match callback USB: xhci: Fix comment typo usb/typec/tcpm: fix repeated words in comments usb/musb: fix repeated words in comments ...
This commit is contained in:
Коммит
9e2e5ea3b2
|
@ -19,7 +19,7 @@ KernelVersion: 3.13
|
|||
Description:
|
||||
The attributes:
|
||||
|
||||
=========== ==============================================
|
||||
============ ==============================================
|
||||
file The path to the backing file for the LUN.
|
||||
Required if LUN is not marked as removable.
|
||||
ro Flag specifying access to the LUN shall be
|
||||
|
@ -32,4 +32,10 @@ Description:
|
|||
being a CD-ROM.
|
||||
nofua Flag specifying that FUA flag
|
||||
in SCSI WRITE(10,12)
|
||||
=========== ==============================================
|
||||
forced_eject This write-only file is useful only when
|
||||
the function is active. It causes the backing
|
||||
file to be forcibly detached from the LUN,
|
||||
regardless of whether the host has allowed it.
|
||||
Any non-zero number of bytes written will
|
||||
result in ejection.
|
||||
============ ==============================================
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
What: /sys/bus/platform/devices/<dev>/always_powered_in_suspend
|
||||
Date: June 2022
|
||||
KernelVersion: 5.20
|
||||
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.
|
|
@ -253,6 +253,17 @@ Description:
|
|||
only if the system firmware is capable of describing the
|
||||
connection between a port and its connector.
|
||||
|
||||
What: /sys/bus/usb/devices/.../<hub_interface>/port<X>/disable
|
||||
Date: June 2022
|
||||
Contact: Michael Grzeschik <m.grzeschik@pengutronix.de>
|
||||
Description:
|
||||
This file controls the state of a USB port, including
|
||||
Vbus power output (but only on hubs that support
|
||||
power switching -- most hubs don't support it). If
|
||||
a port is disabled, the port is unusable: Devices
|
||||
attached to the port will not be detected, initialized,
|
||||
or enumerated.
|
||||
|
||||
What: /sys/bus/usb/devices/.../power/usb2_lpm_l1_timeout
|
||||
Date: May 2013
|
||||
Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
|
||||
|
|
|
@ -141,6 +141,14 @@ Description:
|
|||
- "reverse": CC2 orientation
|
||||
- "unknown": Orientation cannot be determined.
|
||||
|
||||
What: /sys/class/typec/<port>/select_usb_power_delivery
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
Lists the USB Power Delivery Capabilities that the port can
|
||||
advertise to the partner. The currently used capabilities are in
|
||||
brackets. Selection happens by writing to the file.
|
||||
|
||||
USB Type-C partner devices (eg. /sys/class/typec/port0-partner/)
|
||||
|
||||
What: /sys/class/typec/<port>-partner/accessory_mode
|
||||
|
|
|
@ -0,0 +1,240 @@
|
|||
What: /sys/class/usb_power_delivery
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
Directory for USB Power Delivery devices.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../revision
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
File showing the USB Power Delivery Specification Revision used
|
||||
in communication.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../version
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
This is an optional attribute file showing the version of the
|
||||
specific revision of the USB Power Delivery Specification. In
|
||||
most cases the specification version is not known and the file
|
||||
is not available.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../source-capabilities
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
The source capabilities message "Source_Capabilities" contains a
|
||||
set of Power Data Objects (PDO), each representing a type of
|
||||
power supply. The order of the PDO objects is defined in the USB
|
||||
Power Delivery Specification. Each PDO - power supply - will
|
||||
have its own device, and the PDO device name will start with the
|
||||
object position number as the first character followed by the
|
||||
power supply type name (":" as delimiter).
|
||||
|
||||
/sys/class/usb_power_delivery/.../source_capabilities/<position>:<type>
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../sink-capabilities
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
The sink capability message "Sink_Capabilities" contains a set
|
||||
of Power Data Objects (PDO) just like with source capabilities,
|
||||
but instead of describing the power capabilities, these objects
|
||||
describe the power requirements.
|
||||
|
||||
The order of the objects in the sink capability message is the
|
||||
same as with the source capabilities message.
|
||||
|
||||
Fixed Supplies
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../<capability>/<position>:fixed_supply
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
Devices containing the attributes (the bit fields) defined for
|
||||
Fixed Supplies.
|
||||
|
||||
The device "1:fixed_supply" is special. USB Power Delivery
|
||||
Specification dictates that the first PDO (at object position
|
||||
1), and the only mandatory PDO, is always the vSafe5V Fixed
|
||||
Supply Object. vSafe5V Object has additional fields defined for
|
||||
it that the other Fixed Supply Objects do not have and that are
|
||||
related to the USB capabilities rather than power capabilities.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../<capability>/1:fixed_supply/dual_role_power
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
This file contains boolean value that tells does the device
|
||||
support both source and sink power roles.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../<capability>/1:fixed_supply/usb_suspend_supported
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
This file shows the value of the USB Suspend Supported bit in
|
||||
vSafe5V Fixed Supply Object. If the bit is set then the device
|
||||
will follow the USB 2.0 and USB 3.2 rules for suspend and
|
||||
resume.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../<capability>/1:fixed_supply/unconstrained_power
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
This file shows the value of the Unconstrained Power bit in
|
||||
vSafe5V Fixed Supply Object. The bit is set when an external
|
||||
source of power, powerful enough to power the entire system on
|
||||
its own, is available for the device.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../<capability>/1:fixed_supply/usb_communication_capable
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
This file shows the value of the USB Communication Capable bit in
|
||||
vSafe5V Fixed Supply Object.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../<capability>/1:fixed_supply/dual_role_data
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
This file shows the value of the Dual-Role Data bit in vSafe5V
|
||||
Fixed Supply Object. Dual role data means ability act as both
|
||||
USB host and USB device.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../<capability>/1:fixed_supply/unchunked_extended_messages_supported
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
This file shows the value of the Unchunked Extended Messages
|
||||
Supported bit in vSafe5V Fixed Supply Object.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../<capability>/<position>:fixed_supply/voltage
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
The voltage the supply supports in millivolts.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../source-capabilities/<position>:fixed_supply/maximum_current
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
Maximum current of the fixed source supply in milliamperes.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../sink-capabilities/<position>:fixed_supply/operational_current
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
Operational current of the sink in milliamperes.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../sink-capabilities/<position>:fixed_supply/fast_role_swap_current
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
This file contains the value of the "Fast Role Swap USB Type-C
|
||||
Current" field that tells the current level the sink requires
|
||||
after a Fast Role Swap.
|
||||
0 - Fast Swap not supported"
|
||||
1 - Default USB Power"
|
||||
2 - 1.5A@5V"
|
||||
3 - 3.0A@5V"
|
||||
|
||||
Variable Supplies
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../<capability>/<position>:variable_supply
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
Variable Power Supply PDO.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../<capability>/<position>:variable_supply/maximum_voltage
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
Maximum Voltage in millivolts.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../<capability>/<position>:variable_supply/minimum_voltage
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
Minimum Voltage in millivolts.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../source-capabilities/<position>:variable_supply/maximum_current
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
The maximum current in milliamperes that the source can supply
|
||||
at the given Voltage range.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../sink-capabilities/<position>:variable_supply/operational_current
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
The operational current in milliamperes that the sink requires
|
||||
at the given Voltage range.
|
||||
|
||||
Battery Supplies
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../<capability>/<position>:battery
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
Battery PDO.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../<capability>/<position>:battery/maximum_voltage
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
Maximum Voltage in millivolts.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../<capability>/<position>:battery/minimum_voltage
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
Minimum Voltage in millivolts.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../source-capabilities/<position>:battery/maximum_power
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
Maximum allowable Power in milliwatts.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../sink-capabilities/<position>:battery/operational_power
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
The operational power that the sink requires at the given
|
||||
voltage range.
|
||||
|
||||
Standard Power Range (SPR) Programmable Power Supplies
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../<capability>/<position>:programmable_supply
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
Programmable Power Supply (PPS) Augmented PDO (APDO).
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../<capability>/<position>:programmable_supply/maximum_voltage
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
Maximum Voltage in millivolts.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../<capability>/<position>:programmable_supply/minimum_voltage
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
Minimum Voltage in millivolts.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../<capability>/<position>:programmable_supply/maximum_current
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
Maximum Current in milliamperes.
|
||||
|
||||
What: /sys/class/usb_power_delivery/.../source-capabilities/<position>:programmable_supply/pps_power_limited
|
||||
Date: May 2022
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
The PPS Power Limited bit indicates whether or not the source
|
||||
supply will exceed the rated output power if requested.
|
|
@ -0,0 +1,81 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/usb/analogix,anx7411.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analogix ANX7411 Type-C controller bindings
|
||||
|
||||
maintainers:
|
||||
- Xin Ji <xji@analogixsemi.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- analogix,anx7411
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
connector:
|
||||
type: object
|
||||
$ref: ../connector/usb-connector.yaml
|
||||
description:
|
||||
Properties for usb c connector.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: usb-c-connector
|
||||
|
||||
power-role: true
|
||||
|
||||
data-role: true
|
||||
|
||||
try-power-role: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- connector
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
typec@2c {
|
||||
compatible = "analogix,anx7411";
|
||||
reg = <0x2c>;
|
||||
interrupts = <8 IRQ_TYPE_EDGE_FALLING>;
|
||||
interrupt-parent = <&gpio0>;
|
||||
|
||||
typec_con: connector {
|
||||
compatible = "usb-c-connector";
|
||||
power-role = "dual";
|
||||
data-role = "dual";
|
||||
try-power-role = "source";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
typec_con_ep: endpoint {
|
||||
remote-endpoint = <&usbotg_hs_ep>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
|
@ -0,0 +1,52 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (c) 2020 Facebook Inc.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/usb/aspeed,ast2600-udc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ASPEED USB 2.0 Device Controller
|
||||
|
||||
maintainers:
|
||||
- Neal Liu <neal_liu@aspeedtech.com>
|
||||
|
||||
description: |+
|
||||
The ASPEED USB 2.0 Device Controller implements 1 control endpoint and
|
||||
4 generic endpoints for AST260x.
|
||||
|
||||
Supports independent DMA channel for each generic endpoint.
|
||||
Supports 32/256 stages descriptor mode for all generic endpoints.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- aspeed,ast2600-udc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/aspeed-clock.h>
|
||||
udc: usb@1e6a2000 {
|
||||
compatible = "aspeed,ast2600-udc";
|
||||
reg = <0x1e6a2000 0x300>;
|
||||
interrupts = <9>;
|
||||
clocks = <&syscon ASPEED_CLK_GATE_USBPORT2CLK>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_usb2bd_default>;
|
||||
};
|
|
@ -11,6 +11,7 @@ maintainers:
|
|||
|
||||
allOf:
|
||||
- $ref: usb-drd.yaml#
|
||||
- $ref: usb-hcd.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -161,6 +162,8 @@ properties:
|
|||
property is used.
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
|
||||
tpl-support: true
|
||||
|
||||
dependencies:
|
||||
port: [ usb-role-switch ]
|
||||
role-switch-default-mode: [ usb-role-switch ]
|
||||
|
|
|
@ -131,11 +131,6 @@ properties:
|
|||
Set this flag to indicate that the hardware sometimes turns on
|
||||
the OC bit when an over-current isn't actually present.
|
||||
|
||||
companion:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle of a companion.
|
||||
|
||||
phys:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
|
@ -156,7 +151,7 @@ required:
|
|||
- reg
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
|
|
@ -31,6 +31,7 @@ properties:
|
|||
- mediatek,mt8173-xhci
|
||||
- mediatek,mt8183-xhci
|
||||
- mediatek,mt8186-xhci
|
||||
- mediatek,mt8188-xhci
|
||||
- mediatek,mt8192-xhci
|
||||
- mediatek,mt8195-xhci
|
||||
- const: mediatek,mtk-xhci
|
||||
|
@ -57,6 +58,7 @@ properties:
|
|||
- description: optional, wakeup interrupt used to support runtime PM
|
||||
|
||||
interrupt-names:
|
||||
minItems: 1
|
||||
items:
|
||||
- const: host
|
||||
- const: wakeup
|
||||
|
@ -113,6 +115,9 @@ properties:
|
|||
vbus-supply:
|
||||
description: Regulator of USB VBUS5v
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
usb3-lpm-capable: true
|
||||
|
||||
usb2-lpm-disable: true
|
||||
|
|
|
@ -107,6 +107,9 @@ properties:
|
|||
maximum-speed:
|
||||
enum: [super-speed-plus, super-speed, high-speed, full-speed]
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
"#address-cells":
|
||||
enum: [1, 2]
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ properties:
|
|||
- qcom,qcs404-dwc3
|
||||
- qcom,sc7180-dwc3
|
||||
- qcom,sc7280-dwc3
|
||||
- qcom,sc8280xp-dwc3
|
||||
- qcom,sdm660-dwc3
|
||||
- qcom,sdm845-dwc3
|
||||
- qcom,sdx55-dwc3
|
||||
|
@ -66,11 +67,11 @@ properties:
|
|||
- mock_utmi:: Mock utmi clock needed for ITP/SOF generation in host
|
||||
mode. Its frequency should be 19.2MHz.
|
||||
minItems: 1
|
||||
maxItems: 6
|
||||
maxItems: 9
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 6
|
||||
maxItems: 9
|
||||
|
||||
assigned-clocks:
|
||||
items:
|
||||
|
@ -93,20 +94,12 @@ properties:
|
|||
- const: apps-usb
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: The interrupt that is asserted
|
||||
when a wakeup event is received on USB2 bus.
|
||||
- description: The interrupt that is asserted
|
||||
when a wakeup event is received on USB3 bus.
|
||||
- description: Wakeup event on DM line.
|
||||
- description: Wakeup event on DP line.
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: hs_phy_irq
|
||||
- const: ss_phy_irq
|
||||
- const: dm_hs_phy_irq
|
||||
- const: dp_hs_phy_irq
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
|
||||
qcom,select-utmi-as-pipe-clk:
|
||||
description:
|
||||
|
@ -249,6 +242,28 @@ allOf:
|
|||
- const: sleep
|
||||
- const: mock_utmi
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,sc8280xp-dwc3
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 9
|
||||
clock-names:
|
||||
items:
|
||||
- const: cfg_noc
|
||||
- const: core
|
||||
- const: iface
|
||||
- const: sleep
|
||||
- const: mock_utmi
|
||||
- const: noc_aggr
|
||||
- const: noc_aggr_north
|
||||
- const: noc_aggr_south
|
||||
- const: noc_sys
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -311,6 +326,115 @@ allOf:
|
|||
- const: mock_utmi
|
||||
- const: xo
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,ipq4019-dwc3
|
||||
- qcom,ipq6018-dwc3
|
||||
- qcom,ipq8064-dwc3
|
||||
- qcom,ipq8074-dwc3
|
||||
- qcom,msm8994-dwc3
|
||||
- qcom,qcs404-dwc3
|
||||
- qcom,sc7180-dwc3
|
||||
- qcom,sdm845-dwc3
|
||||
- qcom,sdx55-dwc3
|
||||
- qcom,sdx65-dwc3
|
||||
- qcom,sm4250-dwc3
|
||||
- qcom,sm6115-dwc3
|
||||
- qcom,sm6125-dwc3
|
||||
- qcom,sm6350-dwc3
|
||||
- qcom,sm8150-dwc3
|
||||
- qcom,sm8250-dwc3
|
||||
- qcom,sm8350-dwc3
|
||||
- qcom,sm8450-dwc3
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
items:
|
||||
- description: The interrupt that is asserted
|
||||
when a wakeup event is received on USB2 bus.
|
||||
- description: The interrupt that is asserted
|
||||
when a wakeup event is received on USB3 bus.
|
||||
- description: Wakeup event on DM line.
|
||||
- description: Wakeup event on DP line.
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: hs_phy_irq
|
||||
- const: ss_phy_irq
|
||||
- const: dm_hs_phy_irq
|
||||
- const: dp_hs_phy_irq
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,msm8953-dwc3
|
||||
- qcom,msm8996-dwc3
|
||||
- qcom,msm8998-dwc3
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
maxItems: 2
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: hs_phy_irq
|
||||
- const: ss_phy_irq
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,sdm660-dwc3
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
interrupt-names:
|
||||
minItems: 1
|
||||
items:
|
||||
- const: hs_phy_irq
|
||||
- const: ss_phy_irq
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,sc7280-dwc3
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
minItems: 3
|
||||
maxItems: 4
|
||||
interrupt-names:
|
||||
minItems: 3
|
||||
items:
|
||||
- const: hs_phy_irq
|
||||
- const: dp_hs_phy_irq
|
||||
- const: dm_hs_phy_irq
|
||||
- const: ss_phy_irq
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,sc8280xp-dwc3
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
maxItems: 4
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: pwr_event
|
||||
- const: dp_hs_phy_irq
|
||||
- const: dm_hs_phy_irq
|
||||
- const: ss_phy_irq
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
|
|
|
@ -25,13 +25,13 @@ properties:
|
|||
description:
|
||||
phandle to the regulator that provides power to the hub.
|
||||
|
||||
companion-hub:
|
||||
peer-hub:
|
||||
$ref: '/schemas/types.yaml#/definitions/phandle'
|
||||
description:
|
||||
phandle to the companion hub on the controller.
|
||||
phandle to the peer hub on the controller.
|
||||
|
||||
required:
|
||||
- companion-hub
|
||||
- peer-hub
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
|
@ -49,7 +49,7 @@ examples:
|
|||
compatible = "usbbda,5411";
|
||||
reg = <1>;
|
||||
vdd-supply = <&pp3300_hub>;
|
||||
companion-hub = <&hub_3_0>;
|
||||
peer-hub = <&hub_3_0>;
|
||||
};
|
||||
|
||||
/* 3.0 hub on port 2 */
|
||||
|
@ -57,6 +57,6 @@ examples:
|
|||
compatible = "usbbda,411";
|
||||
reg = <2>;
|
||||
vdd-supply = <&pp3300_hub>;
|
||||
companion-hub = <&hub_2_0>;
|
||||
peer-hub = <&hub_2_0>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -343,6 +343,11 @@ properties:
|
|||
This port is used with the 'usb-role-switch' property to connect the
|
||||
dwc3 to type C connector.
|
||||
|
||||
wakeup-source:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Enable USB remote wakeup.
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/usb/st,typec-stm32g0.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: STMicroelectronics STM32G0 USB Type-C PD controller
|
||||
|
||||
description: |
|
||||
The STM32G0 MCU can be programmed to control Type-C connector(s) through I2C
|
||||
typically using the UCSI protocol over I2C, with a dedicated alert
|
||||
(interrupt) pin.
|
||||
|
||||
maintainers:
|
||||
- Fabrice Gasnier <fabrice.gasnier@foss.st.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: st,stm32g0-typec
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
connector:
|
||||
type: object
|
||||
$ref: /schemas/connector/usb-connector.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
firmware-name:
|
||||
description: |
|
||||
Should contain the name of the default firmware image
|
||||
file located on the firmware search path
|
||||
|
||||
wakeup-source: true
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- connector
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
typec@53 {
|
||||
compatible = "st,stm32g0-typec";
|
||||
reg = <0x53>;
|
||||
/* Alert pin on GPIO PE12 */
|
||||
interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
|
||||
interrupt-parent = <&gpioe>;
|
||||
|
||||
/* Example with one type-C connector */
|
||||
connector {
|
||||
compatible = "usb-c-connector";
|
||||
label = "USB-C";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
con_usb_c_ep: endpoint {
|
||||
remote-endpoint = <&usb_ep>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
usb {
|
||||
usb-role-switch;
|
||||
port {
|
||||
usb_ep: endpoint {
|
||||
remote-endpoint = <&con_usb_c_ep>;
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
|
@ -0,0 +1,67 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/usb/ti,usb8041.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Binding for the TI USB8041 USB 3.0 hub controller
|
||||
|
||||
maintainers:
|
||||
- Alexander Stein <alexander.stein@ew.tq-group.com>
|
||||
|
||||
allOf:
|
||||
- $ref: usb-device.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- usb451,8140
|
||||
- usb451,8142
|
||||
|
||||
reg: true
|
||||
|
||||
reset-gpios:
|
||||
items:
|
||||
- description: GPIO specifier for GRST# pin.
|
||||
|
||||
vdd-supply:
|
||||
description:
|
||||
VDD power supply to the hub
|
||||
|
||||
peer-hub:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
phandle to the peer hub on the controller.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- peer-hub
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
usb {
|
||||
dr_mode = "host";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
/* 2.0 hub on port 1 */
|
||||
hub_2_0: hub@1 {
|
||||
compatible = "usb451,8142";
|
||||
reg = <1>;
|
||||
peer-hub = <&hub_3_0>;
|
||||
reset-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
/* 3.0 hub on port 2 */
|
||||
hub_3_0: hub@2 {
|
||||
compatible = "usb451,8140";
|
||||
reg = <2>;
|
||||
peer-hub = <&hub_2_0>;
|
||||
reset-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
|
@ -333,6 +333,12 @@ In each lun directory there are the following attribute files:
|
|||
being a CD-ROM.
|
||||
nofua Flag specifying that FUA flag
|
||||
in SCSI WRITE(10,12)
|
||||
forced_eject This write-only file is useful only when
|
||||
the function is active. It causes the backing
|
||||
file to be forcibly detached from the LUN,
|
||||
regardless of whether the host has allowed it.
|
||||
Any non-zero number of bytes written will
|
||||
result in ejection.
|
||||
=============== ==============================================
|
||||
|
||||
Testing the MASS STORAGE function
|
||||
|
|
|
@ -181,6 +181,15 @@ sysfs entries
|
|||
Reflects the state of nofua flag for given logical unit. It can
|
||||
be read and written.
|
||||
|
||||
- forced_eject
|
||||
|
||||
When written into, it causes the backing file to be forcibly
|
||||
detached from the LUN, regardless of whether the host has allowed
|
||||
it. The content doesn't matter, any non-zero number of bytes
|
||||
written will result in ejection.
|
||||
|
||||
Can not be read.
|
||||
|
||||
Other then those, as usual, the values of module parameters can be
|
||||
read from /sys/module/g_mass_storage/parameters/* files.
|
||||
|
||||
|
|
15
MAINTAINERS
15
MAINTAINERS
|
@ -3179,6 +3179,13 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/media/aspeed-video.txt
|
||||
F: drivers/media/platform/aspeed/
|
||||
|
||||
ASPEED USB UDC DRIVER
|
||||
M: Neal Liu <neal_liu@aspeedtech.com>
|
||||
L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/usb/aspeed,ast2600-udc.yaml
|
||||
F: drivers/usb/gadget/udc/aspeed_udc.c
|
||||
|
||||
ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS
|
||||
M: Corentin Chary <corentin.chary@gmail.com>
|
||||
L: acpi4asus-user@lists.sourceforge.net
|
||||
|
@ -15066,6 +15073,13 @@ S: Maintained
|
|||
T: git git://linuxtv.org/media_tree.git
|
||||
F: drivers/media/i2c/ov9734.c
|
||||
|
||||
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
|
||||
|
||||
ONENAND FLASH DRIVER
|
||||
M: Kyungmin Park <kyungmin.park@samsung.com>
|
||||
L: linux-mtd@lists.infradead.org
|
||||
|
@ -17458,6 +17472,7 @@ F: drivers/mailbox/mailbox-mpfs.c
|
|||
F: drivers/pci/controller/pcie-microchip-host.c
|
||||
F: drivers/soc/microchip/
|
||||
F: drivers/spi/spi-microchip-core.c
|
||||
F: drivers/usb/musb/mpfs.c
|
||||
F: include/soc/microchip/mpfs.h
|
||||
|
||||
RNBD BLOCK DRIVERS
|
||||
|
|
|
@ -677,6 +677,14 @@
|
|||
&usbh_ehci {
|
||||
phys = <&usbphyc_port0>;
|
||||
status = "okay";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
/* onboard HUB */
|
||||
hub@1 {
|
||||
compatible = "usb424,2514";
|
||||
reg = <1>;
|
||||
vdd-supply = <&v3v3>;
|
||||
};
|
||||
};
|
||||
|
||||
&usbotg_hs {
|
||||
|
|
|
@ -865,6 +865,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_AB8500_USB=y
|
||||
CONFIG_KEYSTONE_USB_PHY=m
|
||||
CONFIG_NOP_USB_XCEIV=y
|
||||
|
|
|
@ -134,7 +134,7 @@ CONFIG_RTC_CLASS=y
|
|||
CONFIG_RTC_DRV_DS1307=y
|
||||
CONFIG_STAGING=y
|
||||
CONFIG_OCTEON_ETHERNET=y
|
||||
CONFIG_OCTEON_USB=y
|
||||
CONFIG_USB_OCTEON_HCD=y
|
||||
# CONFIG_IOMMU_SUPPORT is not set
|
||||
CONFIG_RAS=y
|
||||
CONFIG_EXT4_FS=y
|
||||
|
|
|
@ -42,8 +42,6 @@ source "drivers/staging/rts5208/Kconfig"
|
|||
|
||||
source "drivers/staging/octeon/Kconfig"
|
||||
|
||||
source "drivers/staging/octeon-usb/Kconfig"
|
||||
|
||||
source "drivers/staging/vt6655/Kconfig"
|
||||
|
||||
source "drivers/staging/vt6656/Kconfig"
|
||||
|
|
|
@ -11,7 +11,6 @@ obj-$(CONFIG_R8712U) += rtl8712/
|
|||
obj-$(CONFIG_R8188EU) += r8188eu/
|
||||
obj-$(CONFIG_RTS5208) += rts5208/
|
||||
obj-$(CONFIG_OCTEON_ETHERNET) += octeon/
|
||||
obj-$(CONFIG_OCTEON_USB) += octeon-usb/
|
||||
obj-$(CONFIG_VT6655) += vt6655/
|
||||
obj-$(CONFIG_VT6656) += vt6656/
|
||||
obj-$(CONFIG_VME_BUS) += vme_user/
|
||||
|
|
|
@ -17,12 +17,6 @@
|
|||
#define GDM_TTY_MAJOR 0
|
||||
#define GDM_TTY_MINOR 32
|
||||
|
||||
#define ACM_CTRL_DTR 0x01
|
||||
#define ACM_CTRL_RTS 0x02
|
||||
#define ACM_CTRL_DSR 0x02
|
||||
#define ACM_CTRL_RI 0x08
|
||||
#define ACM_CTRL_DCD 0x01
|
||||
|
||||
#define WRITE_SIZE 2048
|
||||
|
||||
#define MUX_TX_MAX_SIZE 2048
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
config OCTEON_USB
|
||||
tristate "Cavium Networks Octeon USB support"
|
||||
depends on CAVIUM_OCTEON_SOC && USB
|
||||
help
|
||||
This driver supports USB host controller on some Cavium
|
||||
Networks' products in the Octeon family.
|
||||
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called octeon-hcd.
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-${CONFIG_OCTEON_USB} := octeon-hcd.o
|
|
@ -1,8 +0,0 @@
|
|||
This driver is functional and has been tested on EdgeRouter Lite,
|
||||
D-Link DSR-1000N and EBH5600 evaluation board with USB mass storage.
|
||||
|
||||
TODO:
|
||||
- kernel coding style
|
||||
- checkpatch warnings
|
||||
|
||||
Contact: Aaro Koskinen <aaro.koskinen@iki.fi>
|
|
@ -694,7 +694,7 @@ void tb_ctl_free(struct tb_ctl *ctl)
|
|||
}
|
||||
|
||||
/**
|
||||
* tb_cfg_start() - start/resume the control channel
|
||||
* tb_ctl_start() - start/resume the control channel
|
||||
* @ctl: Control channel to start
|
||||
*/
|
||||
void tb_ctl_start(struct tb_ctl *ctl)
|
||||
|
@ -710,7 +710,7 @@ void tb_ctl_start(struct tb_ctl *ctl)
|
|||
}
|
||||
|
||||
/**
|
||||
* tb_ctrl_stop() - pause the control channel
|
||||
* tb_ctl_stop() - pause the control channel
|
||||
* @ctl: Control channel to stop
|
||||
*
|
||||
* All invocations of ctl->callback will have finished after this method
|
||||
|
@ -912,7 +912,7 @@ struct tb_cfg_result tb_cfg_read_raw(struct tb_ctl *ctl, void *buffer,
|
|||
}
|
||||
|
||||
/**
|
||||
* tb_cfg_write() - write from buffer into config space
|
||||
* tb_cfg_write_raw() - write from buffer into config space
|
||||
* @ctl: Pointer to the control channel
|
||||
* @buffer: Data to write
|
||||
* @route: Route string of the router
|
||||
|
|
|
@ -35,7 +35,7 @@ struct tb_cfg_result {
|
|||
* If err = 1 then this is the port that send the
|
||||
* error.
|
||||
* If err = 0 and if this was a cfg_read/write then
|
||||
* this is the the upstream port of the responding
|
||||
* this is the upstream port of the responding
|
||||
* switch.
|
||||
* Otherwise the field is set to zero.
|
||||
*/
|
||||
|
|
|
@ -2516,6 +2516,8 @@ struct tb *icm_probe(struct tb_nhi *nhi)
|
|||
case PCI_DEVICE_ID_INTEL_TGL_H_NHI1:
|
||||
case PCI_DEVICE_ID_INTEL_ADL_NHI0:
|
||||
case PCI_DEVICE_ID_INTEL_ADL_NHI1:
|
||||
case PCI_DEVICE_ID_INTEL_RPL_NHI0:
|
||||
case PCI_DEVICE_ID_INTEL_RPL_NHI1:
|
||||
icm->is_supported = icm_tgl_is_supported;
|
||||
icm->driver_ready = icm_icl_driver_ready;
|
||||
icm->set_uuid = icm_icl_set_uuid;
|
||||
|
|
|
@ -1410,6 +1410,10 @@ static struct pci_device_id nhi_ids[] = {
|
|||
.driver_data = (kernel_ulong_t)&icl_nhi_ops },
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL_NHI1),
|
||||
.driver_data = (kernel_ulong_t)&icl_nhi_ops },
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPL_NHI0),
|
||||
.driver_data = (kernel_ulong_t)&icl_nhi_ops },
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPL_NHI1),
|
||||
.driver_data = (kernel_ulong_t)&icl_nhi_ops },
|
||||
|
||||
/* Any USB4 compliant host */
|
||||
{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_USB4, ~0) },
|
||||
|
|
|
@ -80,6 +80,8 @@ extern const struct tb_nhi_ops icl_nhi_ops;
|
|||
#define PCI_DEVICE_ID_INTEL_TGL_NHI1 0x9a1d
|
||||
#define PCI_DEVICE_ID_INTEL_TGL_H_NHI0 0x9a1f
|
||||
#define PCI_DEVICE_ID_INTEL_TGL_H_NHI1 0x9a21
|
||||
#define PCI_DEVICE_ID_INTEL_RPL_NHI0 0xa73e
|
||||
#define PCI_DEVICE_ID_INTEL_RPL_NHI1 0xa76d
|
||||
|
||||
#define PCI_CLASS_SERIAL_USB_USB4 0x0c0340
|
||||
|
||||
|
|
|
@ -3133,9 +3133,13 @@ void tb_switch_suspend(struct tb_switch *sw, bool runtime)
|
|||
/*
|
||||
* Actually only needed for Titan Ridge but for simplicity can be
|
||||
* done for USB4 device too as CLx is re-enabled at resume.
|
||||
* CL0s and CL1 are enabled and supported together.
|
||||
*/
|
||||
if (tb_switch_disable_clx(sw, TB_CL0S))
|
||||
tb_sw_warn(sw, "failed to disable CLx on upstream port\n");
|
||||
if (tb_switch_is_clx_enabled(sw, TB_CL1)) {
|
||||
if (tb_switch_disable_clx(sw, TB_CL1))
|
||||
tb_sw_warn(sw, "failed to disable %s on upstream port\n",
|
||||
tb_switch_clx_name(TB_CL1));
|
||||
}
|
||||
|
||||
err = tb_plug_events_active(sw, false);
|
||||
if (err)
|
||||
|
@ -3426,13 +3430,12 @@ static bool tb_port_clx_supported(struct tb_port *port, enum tb_clx clx)
|
|||
}
|
||||
|
||||
switch (clx) {
|
||||
case TB_CL0S:
|
||||
/* CL0s support requires also CL1 support */
|
||||
case TB_CL1:
|
||||
/* CL0s and CL1 are enabled and supported together */
|
||||
mask = LANE_ADP_CS_0_CL0S_SUPPORT | LANE_ADP_CS_0_CL1_SUPPORT;
|
||||
break;
|
||||
|
||||
/* For now we support only CL0s. Not CL1, CL2 */
|
||||
case TB_CL1:
|
||||
/* For now we support only CL0s and CL1. Not CL2 */
|
||||
case TB_CL2:
|
||||
default:
|
||||
return false;
|
||||
|
@ -3446,18 +3449,18 @@ static bool tb_port_clx_supported(struct tb_port *port, enum tb_clx clx)
|
|||
return !!(val & mask);
|
||||
}
|
||||
|
||||
static inline bool tb_port_cl0s_supported(struct tb_port *port)
|
||||
{
|
||||
return tb_port_clx_supported(port, TB_CL0S);
|
||||
}
|
||||
|
||||
static int __tb_port_cl0s_set(struct tb_port *port, bool enable)
|
||||
static int __tb_port_clx_set(struct tb_port *port, enum tb_clx clx, bool enable)
|
||||
{
|
||||
u32 phy, mask;
|
||||
int ret;
|
||||
|
||||
/* To enable CL0s also required to enable CL1 */
|
||||
mask = LANE_ADP_CS_1_CL0S_ENABLE | LANE_ADP_CS_1_CL1_ENABLE;
|
||||
/* CL0s and CL1 are enabled and supported together */
|
||||
if (clx == TB_CL1)
|
||||
mask = LANE_ADP_CS_1_CL0S_ENABLE | LANE_ADP_CS_1_CL1_ENABLE;
|
||||
else
|
||||
/* For now we support only CL0s and CL1. Not CL2 */
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = tb_port_read(port, &phy, TB_CFG_PORT,
|
||||
port->cap_phy + LANE_ADP_CS_1, 1);
|
||||
if (ret)
|
||||
|
@ -3472,20 +3475,20 @@ static int __tb_port_cl0s_set(struct tb_port *port, bool enable)
|
|||
port->cap_phy + LANE_ADP_CS_1, 1);
|
||||
}
|
||||
|
||||
static int tb_port_cl0s_disable(struct tb_port *port)
|
||||
static int tb_port_clx_disable(struct tb_port *port, enum tb_clx clx)
|
||||
{
|
||||
return __tb_port_cl0s_set(port, false);
|
||||
return __tb_port_clx_set(port, clx, false);
|
||||
}
|
||||
|
||||
static int tb_port_cl0s_enable(struct tb_port *port)
|
||||
static int tb_port_clx_enable(struct tb_port *port, enum tb_clx clx)
|
||||
{
|
||||
return __tb_port_cl0s_set(port, true);
|
||||
return __tb_port_clx_set(port, clx, true);
|
||||
}
|
||||
|
||||
static int tb_switch_enable_cl0s(struct tb_switch *sw)
|
||||
static int __tb_switch_enable_clx(struct tb_switch *sw, enum tb_clx clx)
|
||||
{
|
||||
struct tb_switch *parent = tb_switch_parent(sw);
|
||||
bool up_cl0s_support, down_cl0s_support;
|
||||
bool up_clx_support, down_clx_support;
|
||||
struct tb_port *up, *down;
|
||||
int ret;
|
||||
|
||||
|
@ -3510,37 +3513,37 @@ static int tb_switch_enable_cl0s(struct tb_switch *sw)
|
|||
up = tb_upstream_port(sw);
|
||||
down = tb_port_at(tb_route(sw), parent);
|
||||
|
||||
up_cl0s_support = tb_port_cl0s_supported(up);
|
||||
down_cl0s_support = tb_port_cl0s_supported(down);
|
||||
up_clx_support = tb_port_clx_supported(up, clx);
|
||||
down_clx_support = tb_port_clx_supported(down, clx);
|
||||
|
||||
tb_port_dbg(up, "CL0s %ssupported\n",
|
||||
up_cl0s_support ? "" : "not ");
|
||||
tb_port_dbg(down, "CL0s %ssupported\n",
|
||||
down_cl0s_support ? "" : "not ");
|
||||
tb_port_dbg(up, "%s %ssupported\n", tb_switch_clx_name(clx),
|
||||
up_clx_support ? "" : "not ");
|
||||
tb_port_dbg(down, "%s %ssupported\n", tb_switch_clx_name(clx),
|
||||
down_clx_support ? "" : "not ");
|
||||
|
||||
if (!up_cl0s_support || !down_cl0s_support)
|
||||
if (!up_clx_support || !down_clx_support)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = tb_port_cl0s_enable(up);
|
||||
ret = tb_port_clx_enable(up, clx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tb_port_cl0s_enable(down);
|
||||
ret = tb_port_clx_enable(down, clx);
|
||||
if (ret) {
|
||||
tb_port_cl0s_disable(up);
|
||||
tb_port_clx_disable(up, clx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tb_switch_mask_clx_objections(sw);
|
||||
if (ret) {
|
||||
tb_port_cl0s_disable(up);
|
||||
tb_port_cl0s_disable(down);
|
||||
tb_port_clx_disable(up, clx);
|
||||
tb_port_clx_disable(down, clx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sw->clx = TB_CL0S;
|
||||
sw->clx = clx;
|
||||
|
||||
tb_port_dbg(up, "CL0s enabled\n");
|
||||
tb_port_dbg(up, "%s enabled\n", tb_switch_clx_name(clx));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3554,7 +3557,7 @@ static int tb_switch_enable_cl0s(struct tb_switch *sw)
|
|||
* to improve performance. CLx is enabled only if both sides of the link
|
||||
* support CLx, and if both sides of the link are not configured as two
|
||||
* single lane links and only if the link is not inter-domain link. The
|
||||
* complete set of conditions is descibed in CM Guide 1.0 section 8.1.
|
||||
* complete set of conditions is described in CM Guide 1.0 section 8.1.
|
||||
*
|
||||
* Return: Returns 0 on success or an error code on failure.
|
||||
*/
|
||||
|
@ -3573,15 +3576,16 @@ int tb_switch_enable_clx(struct tb_switch *sw, enum tb_clx clx)
|
|||
return 0;
|
||||
|
||||
switch (clx) {
|
||||
case TB_CL0S:
|
||||
return tb_switch_enable_cl0s(sw);
|
||||
case TB_CL1:
|
||||
/* CL0s and CL1 are enabled and supported together */
|
||||
return __tb_switch_enable_clx(sw, clx);
|
||||
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int tb_switch_disable_cl0s(struct tb_switch *sw)
|
||||
static int __tb_switch_disable_clx(struct tb_switch *sw, enum tb_clx clx)
|
||||
{
|
||||
struct tb_switch *parent = tb_switch_parent(sw);
|
||||
struct tb_port *up, *down;
|
||||
|
@ -3603,17 +3607,17 @@ static int tb_switch_disable_cl0s(struct tb_switch *sw)
|
|||
|
||||
up = tb_upstream_port(sw);
|
||||
down = tb_port_at(tb_route(sw), parent);
|
||||
ret = tb_port_cl0s_disable(up);
|
||||
ret = tb_port_clx_disable(up, clx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tb_port_cl0s_disable(down);
|
||||
ret = tb_port_clx_disable(down, clx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sw->clx = TB_CLX_DISABLE;
|
||||
|
||||
tb_port_dbg(up, "CL0s disabled\n");
|
||||
tb_port_dbg(up, "%s disabled\n", tb_switch_clx_name(clx));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3630,8 +3634,9 @@ int tb_switch_disable_clx(struct tb_switch *sw, enum tb_clx clx)
|
|||
return 0;
|
||||
|
||||
switch (clx) {
|
||||
case TB_CL0S:
|
||||
return tb_switch_disable_cl0s(sw);
|
||||
case TB_CL1:
|
||||
/* CL0s and CL1 are enabled and supported together */
|
||||
return __tb_switch_disable_clx(sw, clx);
|
||||
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
|
|
|
@ -118,6 +118,13 @@ static void tb_switch_discover_tunnels(struct tb_switch *sw,
|
|||
switch (port->config.type) {
|
||||
case TB_TYPE_DP_HDMI_IN:
|
||||
tunnel = tb_tunnel_discover_dp(tb, port, alloc_hopids);
|
||||
/*
|
||||
* In case of DP tunnel exists, change host router's
|
||||
* 1st children TMU mode to HiFi for CL0s to work.
|
||||
*/
|
||||
if (tunnel)
|
||||
tb_switch_enable_tmu_1st_child(tb->root_switch,
|
||||
TB_SWITCH_TMU_RATE_HIFI);
|
||||
break;
|
||||
|
||||
case TB_TYPE_PCIE_DOWN:
|
||||
|
@ -215,7 +222,7 @@ static int tb_enable_tmu(struct tb_switch *sw)
|
|||
int ret;
|
||||
|
||||
/* If it is already enabled in correct mode, don't touch it */
|
||||
if (tb_switch_tmu_hifi_is_enabled(sw, sw->tmu.unidirectional_request))
|
||||
if (tb_switch_tmu_is_enabled(sw, sw->tmu.unidirectional_request))
|
||||
return 0;
|
||||
|
||||
ret = tb_switch_tmu_disable(sw);
|
||||
|
@ -575,6 +582,7 @@ static void tb_scan_port(struct tb_port *port)
|
|||
struct tb_cm *tcm = tb_priv(port->sw->tb);
|
||||
struct tb_port *upstream_port;
|
||||
struct tb_switch *sw;
|
||||
int ret;
|
||||
|
||||
if (tb_is_upstream_port(port))
|
||||
return;
|
||||
|
@ -663,11 +671,24 @@ static void tb_scan_port(struct tb_port *port)
|
|||
tb_switch_lane_bonding_enable(sw);
|
||||
/* Set the link configured */
|
||||
tb_switch_configure_link(sw);
|
||||
if (tb_switch_enable_clx(sw, TB_CL0S))
|
||||
tb_sw_warn(sw, "failed to enable CLx on upstream port\n");
|
||||
/*
|
||||
* CL0s and CL1 are enabled and supported together.
|
||||
* Silently ignore CLx enabling in case CLx is not supported.
|
||||
*/
|
||||
ret = tb_switch_enable_clx(sw, TB_CL1);
|
||||
if (ret && ret != -EOPNOTSUPP)
|
||||
tb_sw_warn(sw, "failed to enable %s on upstream port\n",
|
||||
tb_switch_clx_name(TB_CL1));
|
||||
|
||||
tb_switch_tmu_configure(sw, TB_SWITCH_TMU_RATE_HIFI,
|
||||
tb_switch_is_clx_enabled(sw));
|
||||
if (tb_switch_is_clx_enabled(sw, TB_CL1))
|
||||
/*
|
||||
* To support highest CLx state, we set router's TMU to
|
||||
* Normal-Uni mode.
|
||||
*/
|
||||
tb_switch_tmu_configure(sw, TB_SWITCH_TMU_RATE_NORMAL, true);
|
||||
else
|
||||
/* If CLx disabled, configure router's TMU to HiFi-Bidir mode*/
|
||||
tb_switch_tmu_configure(sw, TB_SWITCH_TMU_RATE_HIFI, false);
|
||||
|
||||
if (tb_enable_tmu(sw))
|
||||
tb_sw_warn(sw, "failed to enable TMU\n");
|
||||
|
@ -965,6 +986,12 @@ static void tb_tunnel_dp(struct tb *tb)
|
|||
|
||||
list_add_tail(&tunnel->list, &tcm->tunnel_list);
|
||||
tb_reclaim_usb3_bandwidth(tb, in, out);
|
||||
/*
|
||||
* In case of DP tunnel exists, change host router's 1st children
|
||||
* TMU mode to HiFi for CL0s to work.
|
||||
*/
|
||||
tb_switch_enable_tmu_1st_child(tb->root_switch, TB_SWITCH_TMU_RATE_HIFI);
|
||||
|
||||
return;
|
||||
|
||||
err_free:
|
||||
|
@ -1407,7 +1434,12 @@ static int tb_start(struct tb *tb)
|
|||
return ret;
|
||||
}
|
||||
|
||||
tb_switch_tmu_configure(tb->root_switch, TB_SWITCH_TMU_RATE_HIFI, false);
|
||||
/*
|
||||
* To support highest CLx state, we set host router's TMU to
|
||||
* Normal mode.
|
||||
*/
|
||||
tb_switch_tmu_configure(tb->root_switch, TB_SWITCH_TMU_RATE_NORMAL,
|
||||
false);
|
||||
/* Enable TMU if it is off */
|
||||
tb_switch_tmu_enable(tb->root_switch);
|
||||
/* Full scan to discover devices added before the driver was loaded. */
|
||||
|
@ -1446,19 +1478,31 @@ static int tb_suspend_noirq(struct tb *tb)
|
|||
static void tb_restore_children(struct tb_switch *sw)
|
||||
{
|
||||
struct tb_port *port;
|
||||
int ret;
|
||||
|
||||
/* No need to restore if the router is already unplugged */
|
||||
if (sw->is_unplugged)
|
||||
return;
|
||||
|
||||
if (tb_switch_enable_clx(sw, TB_CL0S))
|
||||
tb_sw_warn(sw, "failed to re-enable CLx on upstream port\n");
|
||||
|
||||
/*
|
||||
* tb_switch_tmu_configure() was already called when the switch was
|
||||
* added before entering system sleep or runtime suspend,
|
||||
* so no need to call it again before enabling TMU.
|
||||
* CL0s and CL1 are enabled and supported together.
|
||||
* Silently ignore CLx re-enabling in case CLx is not supported.
|
||||
*/
|
||||
ret = tb_switch_enable_clx(sw, TB_CL1);
|
||||
if (ret && ret != -EOPNOTSUPP)
|
||||
tb_sw_warn(sw, "failed to re-enable %s on upstream port\n",
|
||||
tb_switch_clx_name(TB_CL1));
|
||||
|
||||
if (tb_switch_is_clx_enabled(sw, TB_CL1))
|
||||
/*
|
||||
* To support highest CLx state, we set router's TMU to
|
||||
* Normal-Uni mode.
|
||||
*/
|
||||
tb_switch_tmu_configure(sw, TB_SWITCH_TMU_RATE_NORMAL, true);
|
||||
else
|
||||
/* If CLx disabled, configure router's TMU to HiFi-Bidir mode*/
|
||||
tb_switch_tmu_configure(sw, TB_SWITCH_TMU_RATE_HIFI, false);
|
||||
|
||||
if (tb_enable_tmu(sw))
|
||||
tb_sw_warn(sw, "failed to restore TMU configuration\n");
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/thunderbolt.h>
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/bitfield.h>
|
||||
|
||||
#include "tb_regs.h"
|
||||
#include "ctl.h"
|
||||
|
@ -111,7 +112,7 @@ struct tb_switch_tmu {
|
|||
|
||||
enum tb_clx {
|
||||
TB_CLX_DISABLE,
|
||||
TB_CL0S,
|
||||
/* CL0s and CL1 are enabled and supported together */
|
||||
TB_CL1,
|
||||
TB_CL2,
|
||||
};
|
||||
|
@ -933,46 +934,49 @@ int tb_switch_tmu_enable(struct tb_switch *sw);
|
|||
void tb_switch_tmu_configure(struct tb_switch *sw,
|
||||
enum tb_switch_tmu_rate rate,
|
||||
bool unidirectional);
|
||||
void tb_switch_enable_tmu_1st_child(struct tb_switch *sw,
|
||||
enum tb_switch_tmu_rate rate);
|
||||
/**
|
||||
* tb_switch_tmu_hifi_is_enabled() - Checks if the specified TMU mode is enabled
|
||||
* tb_switch_tmu_is_enabled() - Checks if the specified TMU mode is enabled
|
||||
* @sw: Router whose TMU mode to check
|
||||
* @unidirectional: If uni-directional (bi-directional otherwise)
|
||||
*
|
||||
* Return true if hardware TMU configuration matches the one passed in
|
||||
* as parameter. That is HiFi and either uni-directional or bi-directional.
|
||||
* as parameter. That is HiFi/Normal and either uni-directional or bi-directional.
|
||||
*/
|
||||
static inline bool tb_switch_tmu_hifi_is_enabled(const struct tb_switch *sw,
|
||||
bool unidirectional)
|
||||
static inline bool tb_switch_tmu_is_enabled(const struct tb_switch *sw,
|
||||
bool unidirectional)
|
||||
{
|
||||
return sw->tmu.rate == TB_SWITCH_TMU_RATE_HIFI &&
|
||||
return sw->tmu.rate == sw->tmu.rate_request &&
|
||||
sw->tmu.unidirectional == unidirectional;
|
||||
}
|
||||
|
||||
static inline const char *tb_switch_clx_name(enum tb_clx clx)
|
||||
{
|
||||
switch (clx) {
|
||||
/* CL0s and CL1 are enabled and supported together */
|
||||
case TB_CL1:
|
||||
return "CL0s/CL1";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
int tb_switch_enable_clx(struct tb_switch *sw, enum tb_clx clx);
|
||||
int tb_switch_disable_clx(struct tb_switch *sw, enum tb_clx clx);
|
||||
|
||||
/**
|
||||
* tb_switch_is_clx_enabled() - Checks if the CLx is enabled
|
||||
* @sw: Router to check the CLx state for
|
||||
* @sw: Router to check for the CLx
|
||||
* @clx: The CLx state to check for
|
||||
*
|
||||
* Checks if the CLx is enabled on the router upstream link.
|
||||
* Checks if the specified CLx is enabled on the router upstream link.
|
||||
* Not applicable for a host router.
|
||||
*/
|
||||
static inline bool tb_switch_is_clx_enabled(const struct tb_switch *sw)
|
||||
static inline bool tb_switch_is_clx_enabled(const struct tb_switch *sw,
|
||||
enum tb_clx clx)
|
||||
{
|
||||
return sw->clx != TB_CLX_DISABLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* tb_switch_is_cl0s_enabled() - Checks if the CL0s is enabled
|
||||
* @sw: Router to check for the CL0s
|
||||
*
|
||||
* Checks if the CL0s is enabled on the router upstream link.
|
||||
* Not applicable for a host router.
|
||||
*/
|
||||
static inline bool tb_switch_is_cl0s_enabled(const struct tb_switch *sw)
|
||||
{
|
||||
return sw->clx == TB_CL0S;
|
||||
return sw->clx == clx;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -234,6 +234,7 @@ enum usb4_switch_op {
|
|||
|
||||
/* Router TMU configuration */
|
||||
#define TMU_RTR_CS_0 0x00
|
||||
#define TMU_RTR_CS_0_FREQ_WIND_MASK GENMASK(26, 16)
|
||||
#define TMU_RTR_CS_0_TD BIT(27)
|
||||
#define TMU_RTR_CS_0_UCAP BIT(30)
|
||||
#define TMU_RTR_CS_1 0x01
|
||||
|
@ -244,6 +245,11 @@ enum usb4_switch_op {
|
|||
#define TMU_RTR_CS_3_LOCAL_TIME_NS_MASK GENMASK(15, 0)
|
||||
#define TMU_RTR_CS_3_TS_PACKET_INTERVAL_MASK GENMASK(31, 16)
|
||||
#define TMU_RTR_CS_3_TS_PACKET_INTERVAL_SHIFT 16
|
||||
#define TMU_RTR_CS_15 0xf
|
||||
#define TMU_RTR_CS_15_FREQ_AVG_MASK GENMASK(5, 0)
|
||||
#define TMU_RTR_CS_15_DELAY_AVG_MASK GENMASK(11, 6)
|
||||
#define TMU_RTR_CS_15_OFFSET_AVG_MASK GENMASK(17, 12)
|
||||
#define TMU_RTR_CS_15_ERROR_AVG_MASK GENMASK(23, 18)
|
||||
#define TMU_RTR_CS_22 0x16
|
||||
#define TMU_RTR_CS_24 0x18
|
||||
#define TMU_RTR_CS_25 0x19
|
||||
|
|
|
@ -11,6 +11,55 @@
|
|||
|
||||
#include "tb.h"
|
||||
|
||||
static int tb_switch_set_tmu_mode_params(struct tb_switch *sw,
|
||||
enum tb_switch_tmu_rate rate)
|
||||
{
|
||||
u32 freq_meas_wind[2] = { 30, 800 };
|
||||
u32 avg_const[2] = { 4, 8 };
|
||||
u32 freq, avg, val;
|
||||
int ret;
|
||||
|
||||
if (rate == TB_SWITCH_TMU_RATE_NORMAL) {
|
||||
freq = freq_meas_wind[0];
|
||||
avg = avg_const[0];
|
||||
} else if (rate == TB_SWITCH_TMU_RATE_HIFI) {
|
||||
freq = freq_meas_wind[1];
|
||||
avg = avg_const[1];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = tb_sw_read(sw, &val, TB_CFG_SWITCH,
|
||||
sw->tmu.cap + TMU_RTR_CS_0, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val &= ~TMU_RTR_CS_0_FREQ_WIND_MASK;
|
||||
val |= FIELD_PREP(TMU_RTR_CS_0_FREQ_WIND_MASK, freq);
|
||||
|
||||
ret = tb_sw_write(sw, &val, TB_CFG_SWITCH,
|
||||
sw->tmu.cap + TMU_RTR_CS_0, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tb_sw_read(sw, &val, TB_CFG_SWITCH,
|
||||
sw->tmu.cap + TMU_RTR_CS_15, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val &= ~TMU_RTR_CS_15_FREQ_AVG_MASK &
|
||||
~TMU_RTR_CS_15_DELAY_AVG_MASK &
|
||||
~TMU_RTR_CS_15_OFFSET_AVG_MASK &
|
||||
~TMU_RTR_CS_15_ERROR_AVG_MASK;
|
||||
val |= FIELD_PREP(TMU_RTR_CS_15_FREQ_AVG_MASK, avg) |
|
||||
FIELD_PREP(TMU_RTR_CS_15_DELAY_AVG_MASK, avg) |
|
||||
FIELD_PREP(TMU_RTR_CS_15_OFFSET_AVG_MASK, avg) |
|
||||
FIELD_PREP(TMU_RTR_CS_15_ERROR_AVG_MASK, avg);
|
||||
|
||||
return tb_sw_write(sw, &val, TB_CFG_SWITCH,
|
||||
sw->tmu.cap + TMU_RTR_CS_15, 1);
|
||||
}
|
||||
|
||||
static const char *tb_switch_tmu_mode_name(const struct tb_switch *sw)
|
||||
{
|
||||
bool root_switch = !tb_route(sw);
|
||||
|
@ -348,7 +397,7 @@ int tb_switch_tmu_disable(struct tb_switch *sw)
|
|||
|
||||
|
||||
if (tb_route(sw)) {
|
||||
bool unidirectional = tb_switch_tmu_hifi_is_enabled(sw, true);
|
||||
bool unidirectional = sw->tmu.unidirectional;
|
||||
struct tb_switch *parent = tb_switch_parent(sw);
|
||||
struct tb_port *down, *up;
|
||||
int ret;
|
||||
|
@ -359,13 +408,14 @@ int tb_switch_tmu_disable(struct tb_switch *sw)
|
|||
* In case of uni-directional time sync, TMU handshake is
|
||||
* initiated by upstream router. In case of bi-directional
|
||||
* time sync, TMU handshake is initiated by downstream router.
|
||||
* Therefore, we change the rate to off in the respective
|
||||
* router.
|
||||
* We change downstream router's rate to off for both uni/bidir
|
||||
* cases although it is needed only for the bi-directional mode.
|
||||
* We avoid changing upstream router's mode since it might
|
||||
* have another downstream router plugged, that is set to
|
||||
* uni-directional mode and we don't want to change it's TMU
|
||||
* mode.
|
||||
*/
|
||||
if (unidirectional)
|
||||
tb_switch_tmu_rate_write(parent, TB_SWITCH_TMU_RATE_OFF);
|
||||
else
|
||||
tb_switch_tmu_rate_write(sw, TB_SWITCH_TMU_RATE_OFF);
|
||||
tb_switch_tmu_rate_write(sw, TB_SWITCH_TMU_RATE_OFF);
|
||||
|
||||
tb_port_tmu_time_sync_disable(up);
|
||||
ret = tb_port_tmu_time_sync_disable(down);
|
||||
|
@ -411,6 +461,7 @@ static void __tb_switch_tmu_off(struct tb_switch *sw, bool unidirectional)
|
|||
else
|
||||
tb_switch_tmu_rate_write(sw, TB_SWITCH_TMU_RATE_OFF);
|
||||
|
||||
tb_switch_set_tmu_mode_params(sw, sw->tmu.rate);
|
||||
tb_port_tmu_unidirectional_disable(down);
|
||||
tb_port_tmu_unidirectional_disable(up);
|
||||
}
|
||||
|
@ -492,7 +543,11 @@ static int __tb_switch_tmu_enable_unidirectional(struct tb_switch *sw)
|
|||
|
||||
up = tb_upstream_port(sw);
|
||||
down = tb_port_at(tb_route(sw), parent);
|
||||
ret = tb_switch_tmu_rate_write(parent, TB_SWITCH_TMU_RATE_HIFI);
|
||||
ret = tb_switch_tmu_rate_write(parent, sw->tmu.rate_request);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tb_switch_set_tmu_mode_params(sw, sw->tmu.rate_request);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -519,7 +574,83 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int tb_switch_tmu_hifi_enable(struct tb_switch *sw)
|
||||
static void __tb_switch_tmu_change_mode_prev(struct tb_switch *sw)
|
||||
{
|
||||
struct tb_switch *parent = tb_switch_parent(sw);
|
||||
struct tb_port *down, *up;
|
||||
|
||||
down = tb_port_at(tb_route(sw), parent);
|
||||
up = tb_upstream_port(sw);
|
||||
/*
|
||||
* In case of any failure in one of the steps when change mode,
|
||||
* get back to the TMU configurations in previous mode.
|
||||
* In case of additional failures in the functions below,
|
||||
* ignore them since the caller shall already report a failure.
|
||||
*/
|
||||
tb_port_tmu_set_unidirectional(down, sw->tmu.unidirectional);
|
||||
if (sw->tmu.unidirectional_request)
|
||||
tb_switch_tmu_rate_write(parent, sw->tmu.rate);
|
||||
else
|
||||
tb_switch_tmu_rate_write(sw, sw->tmu.rate);
|
||||
|
||||
tb_switch_set_tmu_mode_params(sw, sw->tmu.rate);
|
||||
tb_port_tmu_set_unidirectional(up, sw->tmu.unidirectional);
|
||||
}
|
||||
|
||||
static int __tb_switch_tmu_change_mode(struct tb_switch *sw)
|
||||
{
|
||||
struct tb_switch *parent = tb_switch_parent(sw);
|
||||
struct tb_port *up, *down;
|
||||
int ret;
|
||||
|
||||
up = tb_upstream_port(sw);
|
||||
down = tb_port_at(tb_route(sw), parent);
|
||||
ret = tb_port_tmu_set_unidirectional(down, sw->tmu.unidirectional_request);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (sw->tmu.unidirectional_request)
|
||||
ret = tb_switch_tmu_rate_write(parent, sw->tmu.rate_request);
|
||||
else
|
||||
ret = tb_switch_tmu_rate_write(sw, sw->tmu.rate_request);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tb_switch_set_tmu_mode_params(sw, sw->tmu.rate_request);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tb_port_tmu_set_unidirectional(up, sw->tmu.unidirectional_request);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = tb_port_tmu_time_sync_enable(down);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = tb_port_tmu_time_sync_enable(up);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
__tb_switch_tmu_change_mode_prev(sw);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* tb_switch_tmu_enable() - Enable TMU on a router
|
||||
* @sw: Router whose TMU to enable
|
||||
*
|
||||
* Enables TMU of a router to be in uni-directional Normal/HiFi
|
||||
* or bi-directional HiFi mode. Calling tb_switch_tmu_configure() is required
|
||||
* before calling this function, to select the mode Normal/HiFi and
|
||||
* directionality (uni-directional/bi-directional).
|
||||
* In HiFi mode all tunneling should work. In Normal mode, DP tunneling can't
|
||||
* work. Uni-directional mode is required for CLx (Link Low-Power) to work.
|
||||
*/
|
||||
int tb_switch_tmu_enable(struct tb_switch *sw)
|
||||
{
|
||||
bool unidirectional = sw->tmu.unidirectional_request;
|
||||
int ret;
|
||||
|
@ -535,12 +666,15 @@ static int tb_switch_tmu_hifi_enable(struct tb_switch *sw)
|
|||
if (!tb_switch_is_clx_supported(sw))
|
||||
return 0;
|
||||
|
||||
if (tb_switch_tmu_hifi_is_enabled(sw, sw->tmu.unidirectional_request))
|
||||
if (tb_switch_tmu_is_enabled(sw, sw->tmu.unidirectional_request))
|
||||
return 0;
|
||||
|
||||
if (tb_switch_is_titan_ridge(sw) && unidirectional) {
|
||||
/* Titan Ridge supports only CL0s */
|
||||
if (!tb_switch_is_cl0s_enabled(sw))
|
||||
/*
|
||||
* Titan Ridge supports CL0s and CL1 only. CL0s and CL1 are
|
||||
* enabled and supported together.
|
||||
*/
|
||||
if (!tb_switch_is_clx_enabled(sw, TB_CL1))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = tb_switch_tmu_objection_mask(sw);
|
||||
|
@ -557,7 +691,11 @@ static int tb_switch_tmu_hifi_enable(struct tb_switch *sw)
|
|||
return ret;
|
||||
|
||||
if (tb_route(sw)) {
|
||||
/* The used mode changes are from OFF to HiFi-Uni/HiFi-BiDir */
|
||||
/*
|
||||
* The used mode changes are from OFF to
|
||||
* HiFi-Uni/HiFi-BiDir/Normal-Uni or from Normal-Uni to
|
||||
* HiFi-Uni.
|
||||
*/
|
||||
if (sw->tmu.rate == TB_SWITCH_TMU_RATE_OFF) {
|
||||
if (unidirectional)
|
||||
ret = __tb_switch_tmu_enable_unidirectional(sw);
|
||||
|
@ -565,6 +703,10 @@ static int tb_switch_tmu_hifi_enable(struct tb_switch *sw)
|
|||
ret = __tb_switch_tmu_enable_bidirectional(sw);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else if (sw->tmu.rate == TB_SWITCH_TMU_RATE_NORMAL) {
|
||||
ret = __tb_switch_tmu_change_mode(sw);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
sw->tmu.unidirectional = unidirectional;
|
||||
} else {
|
||||
|
@ -574,39 +716,21 @@ static int tb_switch_tmu_hifi_enable(struct tb_switch *sw)
|
|||
* of the child node - see above.
|
||||
* Here only the host router' rate configuration is written.
|
||||
*/
|
||||
ret = tb_switch_tmu_rate_write(sw, TB_SWITCH_TMU_RATE_HIFI);
|
||||
ret = tb_switch_tmu_rate_write(sw, sw->tmu.rate_request);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
sw->tmu.rate = TB_SWITCH_TMU_RATE_HIFI;
|
||||
sw->tmu.rate = sw->tmu.rate_request;
|
||||
|
||||
tb_sw_dbg(sw, "TMU: mode set to: %s\n", tb_switch_tmu_mode_name(sw));
|
||||
return tb_switch_tmu_set_time_disruption(sw, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* tb_switch_tmu_enable() - Enable TMU on a router
|
||||
* @sw: Router whose TMU to enable
|
||||
*
|
||||
* Enables TMU of a router to be in uni-directional or bi-directional HiFi mode.
|
||||
* Calling tb_switch_tmu_configure() is required before calling this function,
|
||||
* to select the mode HiFi and directionality (uni-directional/bi-directional).
|
||||
* In both modes all tunneling should work. Uni-directional mode is required for
|
||||
* CLx (Link Low-Power) to work.
|
||||
*/
|
||||
int tb_switch_tmu_enable(struct tb_switch *sw)
|
||||
{
|
||||
if (sw->tmu.rate_request == TB_SWITCH_TMU_RATE_NORMAL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return tb_switch_tmu_hifi_enable(sw);
|
||||
}
|
||||
|
||||
/**
|
||||
* tb_switch_tmu_configure() - Configure the TMU rate and directionality
|
||||
* @sw: Router whose mode to change
|
||||
* @rate: Rate to configure Off/LowRes/HiFi
|
||||
* @rate: Rate to configure Off/Normal/HiFi
|
||||
* @unidirectional: If uni-directional (bi-directional otherwise)
|
||||
*
|
||||
* Selects the rate of the TMU and directionality (uni-directional or
|
||||
|
@ -618,3 +742,32 @@ void tb_switch_tmu_configure(struct tb_switch *sw,
|
|||
sw->tmu.unidirectional_request = unidirectional;
|
||||
sw->tmu.rate_request = rate;
|
||||
}
|
||||
|
||||
static int tb_switch_tmu_config_enable(struct device *dev, void *rate)
|
||||
{
|
||||
if (tb_is_switch(dev)) {
|
||||
struct tb_switch *sw = tb_to_switch(dev);
|
||||
|
||||
tb_switch_tmu_configure(sw, *(enum tb_switch_tmu_rate *)rate,
|
||||
tb_switch_is_clx_enabled(sw, TB_CL1));
|
||||
if (tb_switch_tmu_enable(sw))
|
||||
tb_sw_dbg(sw, "fail switching TMU mode for 1st depth router\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tb_switch_enable_tmu_1st_child - Configure and enable TMU for 1st chidren
|
||||
* @sw: The router to configure and enable it's children TMU
|
||||
* @rate: Rate of the TMU to configure the router's chidren to
|
||||
*
|
||||
* Configures and enables the TMU mode of 1st depth children of the specified
|
||||
* router to the specified rate.
|
||||
*/
|
||||
void tb_switch_enable_tmu_1st_child(struct tb_switch *sw,
|
||||
enum tb_switch_tmu_rate rate)
|
||||
{
|
||||
device_for_each_child(&sw->dev, &rate,
|
||||
tb_switch_tmu_config_enable);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
* HISTORY : some part of the code was base on ueagle 1.3 BSD driver,
|
||||
* Damien Bergamini agree to put his code under a DUAL GPL/BSD license.
|
||||
*
|
||||
* The rest of the code was was rewritten from scratch.
|
||||
* The rest of the code was rewritten from scratch.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
|
|
@ -220,7 +220,7 @@ int cdns3_allocate_trb_pool(struct cdns3_endpoint *priv_ep)
|
|||
|
||||
if (!priv_ep->trb_pool) {
|
||||
priv_ep->trb_pool = dma_pool_alloc(priv_dev->eps_dma_pool,
|
||||
GFP_DMA32 | GFP_ATOMIC,
|
||||
GFP_ATOMIC,
|
||||
&priv_ep->trb_pool_dma);
|
||||
|
||||
if (!priv_ep->trb_pool)
|
||||
|
@ -625,9 +625,9 @@ static void cdns3_wa2_remove_old_request(struct cdns3_endpoint *priv_ep)
|
|||
trace_cdns3_wa2(priv_ep, "removes eldest request");
|
||||
|
||||
kfree(priv_req->request.buf);
|
||||
list_del_init(&priv_req->list);
|
||||
cdns3_gadget_ep_free_request(&priv_ep->endpoint,
|
||||
&priv_req->request);
|
||||
list_del_init(&priv_req->list);
|
||||
--priv_ep->wa2_counter;
|
||||
|
||||
if (!chain)
|
||||
|
@ -2285,14 +2285,15 @@ static int cdns3_gadget_ep_enable(struct usb_ep *ep,
|
|||
int val;
|
||||
|
||||
priv_ep = ep_to_cdns3_ep(ep);
|
||||
priv_dev = priv_ep->cdns3_dev;
|
||||
comp_desc = priv_ep->endpoint.comp_desc;
|
||||
|
||||
if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
|
||||
dev_dbg(priv_dev->dev, "usbss: invalid parameters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
comp_desc = priv_ep->endpoint.comp_desc;
|
||||
priv_dev = priv_ep->cdns3_dev;
|
||||
|
||||
if (!desc->wMaxPacketSize) {
|
||||
dev_err(priv_dev->dev, "usbss: missing wMaxPacketSize\n");
|
||||
return -EINVAL;
|
||||
|
@ -2600,7 +2601,7 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
|
|||
struct usb_request *request)
|
||||
{
|
||||
struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep);
|
||||
struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
|
||||
struct cdns3_device *priv_dev;
|
||||
struct usb_request *req, *req_temp;
|
||||
struct cdns3_request *priv_req;
|
||||
struct cdns3_trb *link_trb;
|
||||
|
@ -2611,6 +2612,8 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
|
|||
if (!ep || !request || !ep->desc)
|
||||
return -EINVAL;
|
||||
|
||||
priv_dev = priv_ep->cdns3_dev;
|
||||
|
||||
spin_lock_irqsave(&priv_dev->lock, flags);
|
||||
|
||||
priv_req = to_cdns3_request(request);
|
||||
|
|
|
@ -49,6 +49,7 @@ enum ci_hw_regs {
|
|||
OP_USBCMD,
|
||||
OP_USBSTS,
|
||||
OP_USBINTR,
|
||||
OP_FRINDEX,
|
||||
OP_DEVICEADDR,
|
||||
OP_ENDPTLISTADDR,
|
||||
OP_TTCTRL,
|
||||
|
|
|
@ -348,25 +348,18 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
|
|||
data->pinctrl = devm_pinctrl_get(dev);
|
||||
if (PTR_ERR(data->pinctrl) == -ENODEV)
|
||||
data->pinctrl = NULL;
|
||||
else if (IS_ERR(data->pinctrl)) {
|
||||
if (PTR_ERR(data->pinctrl) != -EPROBE_DEFER)
|
||||
dev_err(dev, "pinctrl get failed, err=%ld\n",
|
||||
PTR_ERR(data->pinctrl));
|
||||
return PTR_ERR(data->pinctrl);
|
||||
}
|
||||
else if (IS_ERR(data->pinctrl))
|
||||
return dev_err_probe(dev, PTR_ERR(data->pinctrl),
|
||||
"pinctrl get failed\n");
|
||||
|
||||
data->hsic_pad_regulator =
|
||||
devm_regulator_get_optional(dev, "hsic");
|
||||
if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) {
|
||||
/* no pad regualator is needed */
|
||||
data->hsic_pad_regulator = NULL;
|
||||
} else if (IS_ERR(data->hsic_pad_regulator)) {
|
||||
if (PTR_ERR(data->hsic_pad_regulator) != -EPROBE_DEFER)
|
||||
dev_err(dev,
|
||||
"Get HSIC pad regulator error: %ld\n",
|
||||
PTR_ERR(data->hsic_pad_regulator));
|
||||
return PTR_ERR(data->hsic_pad_regulator);
|
||||
}
|
||||
} else if (IS_ERR(data->hsic_pad_regulator))
|
||||
return dev_err_probe(dev, PTR_ERR(data->hsic_pad_regulator),
|
||||
"Get HSIC pad regulator error\n");
|
||||
|
||||
if (data->hsic_pad_regulator) {
|
||||
ret = regulator_enable(data->hsic_pad_regulator);
|
||||
|
@ -458,9 +451,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
|
|||
&pdata);
|
||||
if (IS_ERR(data->ci_pdev)) {
|
||||
ret = PTR_ERR(data->ci_pdev);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "ci_hdrc_add_device failed, err=%d\n",
|
||||
ret);
|
||||
dev_err_probe(dev, ret, "ci_hdrc_add_device failed\n");
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ struct imx_usbmisc_data {
|
|||
unsigned int pwr_pol:1; /* power polarity */
|
||||
unsigned int evdo:1; /* set external vbus divider option */
|
||||
unsigned int ulpi:1; /* connected to an ULPI phy */
|
||||
unsigned int hsic:1; /* HSIC controlller */
|
||||
unsigned int hsic:1; /* HSIC controller */
|
||||
unsigned int ext_id:1; /* ID from exteranl event */
|
||||
unsigned int ext_vbus:1; /* Vbus from exteranl event */
|
||||
struct usb_phy *usb_phy;
|
||||
|
|
|
@ -53,6 +53,7 @@ static const u8 ci_regs_nolpm[] = {
|
|||
[OP_USBCMD] = 0x00U,
|
||||
[OP_USBSTS] = 0x04U,
|
||||
[OP_USBINTR] = 0x08U,
|
||||
[OP_FRINDEX] = 0x0CU,
|
||||
[OP_DEVICEADDR] = 0x14U,
|
||||
[OP_ENDPTLISTADDR] = 0x18U,
|
||||
[OP_TTCTRL] = 0x1CU,
|
||||
|
@ -78,6 +79,7 @@ static const u8 ci_regs_lpm[] = {
|
|||
[OP_USBCMD] = 0x00U,
|
||||
[OP_USBSTS] = 0x04U,
|
||||
[OP_USBINTR] = 0x08U,
|
||||
[OP_FRINDEX] = 0x0CU,
|
||||
[OP_DEVICEADDR] = 0x14U,
|
||||
[OP_ENDPTLISTADDR] = 0x18U,
|
||||
[OP_TTCTRL] = 0x1CU,
|
||||
|
|
|
@ -459,7 +459,7 @@ static void ci_otg_drv_vbus(struct otg_fsm *fsm, int on)
|
|||
struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm);
|
||||
|
||||
if (on) {
|
||||
/* Enable power power */
|
||||
/* Enable power */
|
||||
hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP,
|
||||
PORTSC_PP);
|
||||
if (ci->platdata->reg_vbus) {
|
||||
|
|
|
@ -1654,6 +1654,19 @@ static const struct usb_ep_ops usb_ep_ops = {
|
|||
/******************************************************************************
|
||||
* GADGET block
|
||||
*****************************************************************************/
|
||||
|
||||
static int ci_udc_get_frame(struct usb_gadget *_gadget)
|
||||
{
|
||||
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
ret = hw_read(ci, OP_FRINDEX, 0x3fff);
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
return ret >> 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* ci_hdrc_gadget_connect: caller makes sure gadget driver is binded
|
||||
*/
|
||||
|
@ -1810,6 +1823,7 @@ static struct usb_ep *ci_udc_match_ep(struct usb_gadget *gadget,
|
|||
* Check "usb_gadget.h" for details
|
||||
*/
|
||||
static const struct usb_gadget_ops usb_gadget_ops = {
|
||||
.get_frame = ci_udc_get_frame,
|
||||
.vbus_session = ci_udc_vbus_session,
|
||||
.wakeup = ci_udc_wakeup,
|
||||
.set_selfpowered = ci_udc_selfpowered,
|
||||
|
|
|
@ -119,7 +119,7 @@ static int acm_ctrl_msg(struct acm *acm, int request, int value,
|
|||
retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
|
||||
request, USB_RT_ACM, value,
|
||||
acm->control->altsetting[0].desc.bInterfaceNumber,
|
||||
buf, len, 5000);
|
||||
buf, len, USB_CTRL_SET_TIMEOUT);
|
||||
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - rq 0x%02x, val %#x, len %#x, result %d\n",
|
||||
|
@ -311,7 +311,7 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
|
|||
dev_dbg(&acm->control->dev,
|
||||
"%s - serial state: 0x%x\n", __func__, newctrl);
|
||||
|
||||
if (!acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
|
||||
if (!acm->clocal && (acm->ctrlin & ~newctrl & USB_CDC_SERIAL_STATE_DCD)) {
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - calling hangup\n", __func__);
|
||||
tty_port_tty_hangup(&acm->port, false);
|
||||
|
@ -322,25 +322,25 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
|
|||
acm->ctrlin = newctrl;
|
||||
acm->oldcount = acm->iocount;
|
||||
|
||||
if (difference & ACM_CTRL_DSR)
|
||||
if (difference & USB_CDC_SERIAL_STATE_DSR)
|
||||
acm->iocount.dsr++;
|
||||
if (difference & ACM_CTRL_DCD)
|
||||
if (difference & USB_CDC_SERIAL_STATE_DCD)
|
||||
acm->iocount.dcd++;
|
||||
if (newctrl & ACM_CTRL_BRK) {
|
||||
if (newctrl & USB_CDC_SERIAL_STATE_BREAK) {
|
||||
acm->iocount.brk++;
|
||||
tty_insert_flip_char(&acm->port, 0, TTY_BREAK);
|
||||
}
|
||||
if (newctrl & ACM_CTRL_RI)
|
||||
if (newctrl & USB_CDC_SERIAL_STATE_RING_SIGNAL)
|
||||
acm->iocount.rng++;
|
||||
if (newctrl & ACM_CTRL_FRAMING)
|
||||
if (newctrl & USB_CDC_SERIAL_STATE_FRAMING)
|
||||
acm->iocount.frame++;
|
||||
if (newctrl & ACM_CTRL_PARITY)
|
||||
if (newctrl & USB_CDC_SERIAL_STATE_PARITY)
|
||||
acm->iocount.parity++;
|
||||
if (newctrl & ACM_CTRL_OVERRUN)
|
||||
if (newctrl & USB_CDC_SERIAL_STATE_OVERRUN)
|
||||
acm->iocount.overrun++;
|
||||
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||
|
||||
if (newctrl & ACM_CTRL_BRK)
|
||||
if (newctrl & USB_CDC_SERIAL_STATE_BREAK)
|
||||
tty_flip_buffer_push(&acm->port);
|
||||
|
||||
if (difference)
|
||||
|
@ -658,7 +658,7 @@ static void acm_port_dtr_rts(struct tty_port *port, int raise)
|
|||
int res;
|
||||
|
||||
if (raise)
|
||||
val = ACM_CTRL_DTR | ACM_CTRL_RTS;
|
||||
val = USB_CDC_CTRL_DTR | USB_CDC_CTRL_RTS;
|
||||
else
|
||||
val = 0;
|
||||
|
||||
|
@ -903,11 +903,11 @@ static int acm_tty_tiocmget(struct tty_struct *tty)
|
|||
{
|
||||
struct acm *acm = tty->driver_data;
|
||||
|
||||
return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
|
||||
(acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
|
||||
(acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
|
||||
(acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) |
|
||||
(acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) |
|
||||
return (acm->ctrlout & USB_CDC_CTRL_DTR ? TIOCM_DTR : 0) |
|
||||
(acm->ctrlout & USB_CDC_CTRL_RTS ? TIOCM_RTS : 0) |
|
||||
(acm->ctrlin & USB_CDC_SERIAL_STATE_DSR ? TIOCM_DSR : 0) |
|
||||
(acm->ctrlin & USB_CDC_SERIAL_STATE_RING_SIGNAL ? TIOCM_RI : 0) |
|
||||
(acm->ctrlin & USB_CDC_SERIAL_STATE_DCD ? TIOCM_CD : 0) |
|
||||
TIOCM_CTS;
|
||||
}
|
||||
|
||||
|
@ -918,10 +918,10 @@ static int acm_tty_tiocmset(struct tty_struct *tty,
|
|||
unsigned int newctrl;
|
||||
|
||||
newctrl = acm->ctrlout;
|
||||
set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
|
||||
(set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
|
||||
clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
|
||||
(clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
|
||||
set = (set & TIOCM_DTR ? USB_CDC_CTRL_DTR : 0) |
|
||||
(set & TIOCM_RTS ? USB_CDC_CTRL_RTS : 0);
|
||||
clear = (clear & TIOCM_DTR ? USB_CDC_CTRL_DTR : 0) |
|
||||
(clear & TIOCM_RTS ? USB_CDC_CTRL_RTS : 0);
|
||||
|
||||
newctrl = (newctrl & ~clear) | set;
|
||||
|
||||
|
@ -1068,9 +1068,9 @@ static void acm_tty_set_termios(struct tty_struct *tty,
|
|||
|
||||
if (C_BAUD(tty) == B0) {
|
||||
newline.dwDTERate = acm->line.dwDTERate;
|
||||
newctrl &= ~ACM_CTRL_DTR;
|
||||
newctrl &= ~USB_CDC_CTRL_DTR;
|
||||
} else if (termios_old && (termios_old->c_cflag & CBAUD) == B0) {
|
||||
newctrl |= ACM_CTRL_DTR;
|
||||
newctrl |= USB_CDC_CTRL_DTR;
|
||||
}
|
||||
|
||||
if (newctrl != acm->ctrlout)
|
||||
|
|
|
@ -22,26 +22,6 @@
|
|||
|
||||
#define USB_RT_ACM (USB_TYPE_CLASS | USB_RECIP_INTERFACE)
|
||||
|
||||
/*
|
||||
* Output control lines.
|
||||
*/
|
||||
|
||||
#define ACM_CTRL_DTR 0x01
|
||||
#define ACM_CTRL_RTS 0x02
|
||||
|
||||
/*
|
||||
* Input control lines and line errors.
|
||||
*/
|
||||
|
||||
#define ACM_CTRL_DCD 0x01
|
||||
#define ACM_CTRL_DSR 0x02
|
||||
#define ACM_CTRL_BRK 0x04
|
||||
#define ACM_CTRL_RI 0x08
|
||||
|
||||
#define ACM_CTRL_FRAMING 0x10
|
||||
#define ACM_CTRL_PARITY 0x20
|
||||
#define ACM_CTRL_OVERRUN 0x40
|
||||
|
||||
/*
|
||||
* Internal driver structures.
|
||||
*/
|
||||
|
|
|
@ -257,6 +257,7 @@ static int usb_conn_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
device_set_wakeup_capable(&pdev->dev, true);
|
||||
|
||||
/* Perform initial detection */
|
||||
usb_conn_queue_dwork(info, 0);
|
||||
|
@ -286,6 +287,14 @@ static int __maybe_unused usb_conn_suspend(struct device *dev)
|
|||
{
|
||||
struct usb_conn_info *info = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
if (info->id_gpiod)
|
||||
enable_irq_wake(info->id_irq);
|
||||
if (info->vbus_gpiod)
|
||||
enable_irq_wake(info->vbus_irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info->id_gpiod)
|
||||
disable_irq(info->id_irq);
|
||||
if (info->vbus_gpiod)
|
||||
|
@ -300,6 +309,14 @@ static int __maybe_unused usb_conn_resume(struct device *dev)
|
|||
{
|
||||
struct usb_conn_info *info = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
if (info->id_gpiod)
|
||||
disable_irq_wake(info->id_irq);
|
||||
if (info->vbus_gpiod)
|
||||
disable_irq_wake(info->vbus_irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pinctrl_pm_select_default_state(dev);
|
||||
|
||||
if (info->id_gpiod)
|
||||
|
|
|
@ -12,6 +12,10 @@ 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
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_USB) += usbcore.o
|
||||
|
||||
obj-$(CONFIG_USB_LEDS_TRIGGER_USBPORT) += ledtrig-usbport.o
|
||||
|
|
|
@ -1482,7 +1482,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
|
|||
* @msg: Power Management message describing this state transition
|
||||
*
|
||||
* This is the central routine for resuming USB devices. It calls the
|
||||
* the resume method for @udev and then calls the resume methods for all
|
||||
* resume method for @udev and then calls the resume methods for all
|
||||
* the interface drivers in @udev.
|
||||
*
|
||||
* Autoresume requests originating from a child device or an interface
|
||||
|
|
|
@ -1691,7 +1691,6 @@ static void usb_giveback_urb_bh(struct tasklet_struct *t)
|
|||
|
||||
spin_lock_irq(&bh->lock);
|
||||
bh->running = true;
|
||||
restart:
|
||||
list_replace_init(&bh->head, &local_list);
|
||||
spin_unlock_irq(&bh->lock);
|
||||
|
||||
|
@ -1705,10 +1704,17 @@ static void usb_giveback_urb_bh(struct tasklet_struct *t)
|
|||
bh->completing_ep = NULL;
|
||||
}
|
||||
|
||||
/* check if there are new URBs to giveback */
|
||||
/*
|
||||
* giveback new URBs next time to prevent this function
|
||||
* from not exiting for a long time.
|
||||
*/
|
||||
spin_lock_irq(&bh->lock);
|
||||
if (!list_empty(&bh->head))
|
||||
goto restart;
|
||||
if (!list_empty(&bh->head)) {
|
||||
if (bh->high_prio)
|
||||
tasklet_hi_schedule(&bh->bh);
|
||||
else
|
||||
tasklet_schedule(&bh->bh);
|
||||
}
|
||||
bh->running = false;
|
||||
spin_unlock_irq(&bh->lock);
|
||||
}
|
||||
|
@ -1737,7 +1743,7 @@ static void usb_giveback_urb_bh(struct tasklet_struct *t)
|
|||
void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
|
||||
{
|
||||
struct giveback_urb_bh *bh;
|
||||
bool running, high_prio_bh;
|
||||
bool running;
|
||||
|
||||
/* pass status to tasklet via unlinked */
|
||||
if (likely(!urb->unlinked))
|
||||
|
@ -1748,13 +1754,10 @@ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
|
|||
return;
|
||||
}
|
||||
|
||||
if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe)) {
|
||||
if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe))
|
||||
bh = &hcd->high_prio_bh;
|
||||
high_prio_bh = true;
|
||||
} else {
|
||||
else
|
||||
bh = &hcd->low_prio_bh;
|
||||
high_prio_bh = false;
|
||||
}
|
||||
|
||||
spin_lock(&bh->lock);
|
||||
list_add_tail(&urb->urb_list, &bh->head);
|
||||
|
@ -1763,7 +1766,7 @@ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
|
|||
|
||||
if (running)
|
||||
;
|
||||
else if (high_prio_bh)
|
||||
else if (bh->high_prio)
|
||||
tasklet_hi_schedule(&bh->bh);
|
||||
else
|
||||
tasklet_schedule(&bh->bh);
|
||||
|
@ -2959,6 +2962,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
|||
|
||||
/* initialize tasklets */
|
||||
init_giveback_urb_bh(&hcd->high_prio_bh);
|
||||
hcd->high_prio_bh.high_prio = true;
|
||||
init_giveback_urb_bh(&hcd->low_prio_bh);
|
||||
|
||||
/* enable irqs just before we start the controller,
|
||||
|
@ -3033,9 +3037,15 @@ EXPORT_SYMBOL_GPL(usb_add_hcd);
|
|||
*/
|
||||
void usb_remove_hcd(struct usb_hcd *hcd)
|
||||
{
|
||||
struct usb_device *rhdev = hcd->self.root_hub;
|
||||
struct usb_device *rhdev;
|
||||
bool rh_registered;
|
||||
|
||||
if (!hcd) {
|
||||
pr_debug("%s: hcd is NULL\n", __func__);
|
||||
return;
|
||||
}
|
||||
rhdev = hcd->self.root_hub;
|
||||
|
||||
dev_info(hcd->self.controller, "remove, state %x\n", hcd->state);
|
||||
|
||||
usb_get_dev(rhdev);
|
||||
|
|
|
@ -23,6 +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/otg.h>
|
||||
#include <linux/usb/quirks.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
@ -613,7 +614,7 @@ static int hub_ext_port_status(struct usb_hub *hub, int port1, int type,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int hub_port_status(struct usb_hub *hub, int port1,
|
||||
int usb_hub_port_status(struct usb_hub *hub, int port1,
|
||||
u16 *status, u16 *change)
|
||||
{
|
||||
return hub_ext_port_status(hub, port1, HUB_PORT_STATUS,
|
||||
|
@ -1126,7 +1127,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
|
|||
u16 portstatus, portchange;
|
||||
|
||||
portstatus = portchange = 0;
|
||||
status = hub_port_status(hub, port1, &portstatus, &portchange);
|
||||
status = usb_hub_port_status(hub, port1, &portstatus, &portchange);
|
||||
if (status)
|
||||
goto abort;
|
||||
|
||||
|
@ -1752,6 +1753,8 @@ 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);
|
||||
|
||||
kref_put(&hub->kref, hub_release);
|
||||
}
|
||||
|
||||
|
@ -1869,6 +1872,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);
|
||||
spin_lock_init(&hub->irq_urb_lock);
|
||||
timer_setup(&hub->irq_urb_retry, hub_retry_irq_urb, 0);
|
||||
usb_get_intf(intf);
|
||||
|
@ -1889,8 +1893,11 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
|||
usb_autopm_get_interface_no_resume(intf);
|
||||
}
|
||||
|
||||
if (hub_configure(hub, &desc->endpoint[0].desc) >= 0)
|
||||
if (hub_configure(hub, &desc->endpoint[0].desc) >= 0) {
|
||||
onboard_hub_create_pdevs(hdev, &hub->onboard_hub_devs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
hub_disconnect(intf);
|
||||
return -ENODEV;
|
||||
|
@ -2855,7 +2862,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
|
|||
&portstatus, &portchange,
|
||||
&ext_portstatus);
|
||||
else
|
||||
ret = hub_port_status(hub, port1, &portstatus,
|
||||
ret = usb_hub_port_status(hub, port1, &portstatus,
|
||||
&portchange);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -2956,7 +2963,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
|
|||
* If the caller hasn't explicitly requested a warm reset,
|
||||
* double check and see if one is needed.
|
||||
*/
|
||||
if (hub_port_status(hub, port1, &portstatus, &portchange) == 0)
|
||||
if (usb_hub_port_status(hub, port1, &portstatus,
|
||||
&portchange) == 0)
|
||||
if (hub_port_warm_reset_required(hub, port1,
|
||||
portstatus))
|
||||
warm = true;
|
||||
|
@ -3008,7 +3016,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
|
|||
* If a USB 3.0 device migrates from reset to an error
|
||||
* state, re-issue the warm reset.
|
||||
*/
|
||||
if (hub_port_status(hub, port1,
|
||||
if (usb_hub_port_status(hub, port1,
|
||||
&portstatus, &portchange) < 0)
|
||||
goto done;
|
||||
|
||||
|
@ -3074,7 +3082,7 @@ done:
|
|||
}
|
||||
|
||||
/* Check if a port is power on */
|
||||
static int port_is_power_on(struct usb_hub *hub, unsigned portstatus)
|
||||
int usb_port_is_power_on(struct usb_hub *hub, unsigned int portstatus)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
|
@ -3140,13 +3148,13 @@ static int check_port_resume_type(struct usb_device *udev,
|
|||
}
|
||||
/* Is the device still present? */
|
||||
else if (status || port_is_suspended(hub, portstatus) ||
|
||||
!port_is_power_on(hub, portstatus)) {
|
||||
!usb_port_is_power_on(hub, portstatus)) {
|
||||
if (status >= 0)
|
||||
status = -ENODEV;
|
||||
} else if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
|
||||
if (retries--) {
|
||||
usleep_range(200, 300);
|
||||
status = hub_port_status(hub, port1, &portstatus,
|
||||
status = usb_hub_port_status(hub, port1, &portstatus,
|
||||
&portchange);
|
||||
goto retry;
|
||||
}
|
||||
|
@ -3409,7 +3417,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
|
|||
u16 portstatus, portchange;
|
||||
|
||||
portstatus = portchange = 0;
|
||||
ret = hub_port_status(hub, port1, &portstatus,
|
||||
ret = usb_hub_port_status(hub, port1, &portstatus,
|
||||
&portchange);
|
||||
|
||||
dev_dbg(&port_dev->dev,
|
||||
|
@ -3587,13 +3595,13 @@ static int wait_for_connected(struct usb_device *udev,
|
|||
while (delay_ms < 2000) {
|
||||
if (status || *portstatus & USB_PORT_STAT_CONNECTION)
|
||||
break;
|
||||
if (!port_is_power_on(hub, *portstatus)) {
|
||||
if (!usb_port_is_power_on(hub, *portstatus)) {
|
||||
status = -ENODEV;
|
||||
break;
|
||||
}
|
||||
msleep(20);
|
||||
delay_ms += 20;
|
||||
status = hub_port_status(hub, port1, portstatus, portchange);
|
||||
status = usb_hub_port_status(hub, port1, portstatus, portchange);
|
||||
}
|
||||
dev_dbg(&udev->dev, "Waited %dms for CONNECT\n", delay_ms);
|
||||
return status;
|
||||
|
@ -3653,7 +3661,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
|
|||
usb_lock_port(port_dev);
|
||||
|
||||
/* Skip the initial Clear-Suspend step for a remote wakeup */
|
||||
status = hub_port_status(hub, port1, &portstatus, &portchange);
|
||||
status = usb_hub_port_status(hub, port1, &portstatus, &portchange);
|
||||
if (status == 0 && !port_is_suspended(hub, portstatus)) {
|
||||
if (portchange & USB_PORT_STAT_C_SUSPEND)
|
||||
pm_wakeup_event(&udev->dev, 0);
|
||||
|
@ -3678,7 +3686,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
|
|||
* stop resume signaling. Then finish the resume
|
||||
* sequence.
|
||||
*/
|
||||
status = hub_port_status(hub, port1, &portstatus, &portchange);
|
||||
status = usb_hub_port_status(hub, port1, &portstatus, &portchange);
|
||||
}
|
||||
|
||||
SuspendCleared:
|
||||
|
@ -3791,7 +3799,7 @@ static int check_ports_changed(struct usb_hub *hub)
|
|||
u16 portstatus, portchange;
|
||||
int status;
|
||||
|
||||
status = hub_port_status(hub, port1, &portstatus, &portchange);
|
||||
status = usb_hub_port_status(hub, port1, &portstatus, &portchange);
|
||||
if (!status && portchange)
|
||||
return 1;
|
||||
}
|
||||
|
@ -3946,7 +3954,7 @@ static const char * const usb3_lpm_names[] = {
|
|||
* This function will fail if the SEL or PEL values for udev are greater than
|
||||
* the maximum allowed values for the link state to be enabled.
|
||||
*/
|
||||
static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state)
|
||||
static int usb_req_set_sel(struct usb_device *udev)
|
||||
{
|
||||
struct usb_set_sel_req *sel_values;
|
||||
unsigned long long u1_sel;
|
||||
|
@ -3955,7 +3963,7 @@ static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state)
|
|||
unsigned long long u2_pel;
|
||||
int ret;
|
||||
|
||||
if (udev->state != USB_STATE_CONFIGURED)
|
||||
if (!udev->parent || udev->speed < USB_SPEED_SUPER || !udev->lpm_capable)
|
||||
return 0;
|
||||
|
||||
/* Convert SEL and PEL stored in ns to us */
|
||||
|
@ -3972,34 +3980,14 @@ static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state)
|
|||
* latency for the link state, and could start a device-initiated
|
||||
* U1/U2 when the exit latencies are too high.
|
||||
*/
|
||||
if ((state == USB3_LPM_U1 &&
|
||||
(u1_sel > USB3_LPM_MAX_U1_SEL_PEL ||
|
||||
u1_pel > USB3_LPM_MAX_U1_SEL_PEL)) ||
|
||||
(state == USB3_LPM_U2 &&
|
||||
(u2_sel > USB3_LPM_MAX_U2_SEL_PEL ||
|
||||
u2_pel > USB3_LPM_MAX_U2_SEL_PEL))) {
|
||||
dev_dbg(&udev->dev, "Device-initiated %s disabled due to long SEL %llu us or PEL %llu us\n",
|
||||
usb3_lpm_names[state], u1_sel, u1_pel);
|
||||
if (u1_sel > USB3_LPM_MAX_U1_SEL_PEL ||
|
||||
u1_pel > USB3_LPM_MAX_U1_SEL_PEL ||
|
||||
u2_sel > USB3_LPM_MAX_U2_SEL_PEL ||
|
||||
u2_pel > USB3_LPM_MAX_U2_SEL_PEL) {
|
||||
dev_dbg(&udev->dev, "Device-initiated U1/U2 disabled due to long SEL or PEL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're enabling device-initiated LPM for one link state,
|
||||
* but the other link state has a too high SEL or PEL value,
|
||||
* just set those values to the max in the Set SEL request.
|
||||
*/
|
||||
if (u1_sel > USB3_LPM_MAX_U1_SEL_PEL)
|
||||
u1_sel = USB3_LPM_MAX_U1_SEL_PEL;
|
||||
|
||||
if (u1_pel > USB3_LPM_MAX_U1_SEL_PEL)
|
||||
u1_pel = USB3_LPM_MAX_U1_SEL_PEL;
|
||||
|
||||
if (u2_sel > USB3_LPM_MAX_U2_SEL_PEL)
|
||||
u2_sel = USB3_LPM_MAX_U2_SEL_PEL;
|
||||
|
||||
if (u2_pel > USB3_LPM_MAX_U2_SEL_PEL)
|
||||
u2_pel = USB3_LPM_MAX_U2_SEL_PEL;
|
||||
|
||||
/*
|
||||
* usb_enable_lpm() can be called as part of a failed device reset,
|
||||
* which may be initiated by an error path of a mass storage driver.
|
||||
|
@ -4021,6 +4009,10 @@ static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state)
|
|||
sel_values, sizeof *(sel_values),
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
kfree(sel_values);
|
||||
|
||||
if (ret > 0)
|
||||
udev->lpm_devinit_allow = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -4136,6 +4128,9 @@ static bool usb_device_may_initiate_lpm(struct usb_device *udev,
|
|||
unsigned int sel; /* us */
|
||||
int i, j;
|
||||
|
||||
if (!udev->lpm_devinit_allow)
|
||||
return false;
|
||||
|
||||
if (state == USB3_LPM_U1)
|
||||
sel = DIV_ROUND_UP(udev->u1_params.sel, 1000);
|
||||
else if (state == USB3_LPM_U2)
|
||||
|
@ -4184,7 +4179,7 @@ static bool usb_device_may_initiate_lpm(struct usb_device *udev,
|
|||
static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
enum usb3_link_state state)
|
||||
{
|
||||
int timeout, ret;
|
||||
int timeout;
|
||||
__u8 u1_mel = udev->bos->ss_cap->bU1devExitLat;
|
||||
__le16 u2_mel = udev->bos->ss_cap->bU2DevExitLat;
|
||||
|
||||
|
@ -4196,17 +4191,6 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
(state == USB3_LPM_U2 && u2_mel == 0))
|
||||
return;
|
||||
|
||||
/*
|
||||
* First, let the device know about the exit latencies
|
||||
* associated with the link state we're about to enable.
|
||||
*/
|
||||
ret = usb_req_set_sel(udev, state);
|
||||
if (ret < 0) {
|
||||
dev_warn(&udev->dev, "Set SEL for device-initiated %s failed.\n",
|
||||
usb3_lpm_names[state]);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We allow the host controller to set the U1/U2 timeout internally
|
||||
* first, so that it can change its schedule to account for the
|
||||
* additional latency to send data to a device in a lower power
|
||||
|
@ -4486,6 +4470,11 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int usb_req_set_sel(struct usb_device *udev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
/*
|
||||
|
@ -4554,7 +4543,7 @@ int hub_port_debounce(struct usb_hub *hub, int port1, bool must_be_connected)
|
|||
struct usb_port *port_dev = hub->ports[port1 - 1];
|
||||
|
||||
for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) {
|
||||
ret = hub_port_status(hub, port1, &portstatus, &portchange);
|
||||
ret = usb_hub_port_status(hub, port1, &portstatus, &portchange);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -5011,6 +5000,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
|
|||
udev->lpm_capable = usb_device_supports_lpm(udev);
|
||||
udev->lpm_disable_count = 1;
|
||||
usb_set_lpm_parameters(udev);
|
||||
usb_req_set_sel(udev);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5240,7 +5230,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
|
|||
* but only if the port isn't owned by someone else.
|
||||
*/
|
||||
if (hub_is_port_power_switchable(hub)
|
||||
&& !port_is_power_on(hub, portstatus)
|
||||
&& !usb_port_is_power_on(hub, portstatus)
|
||||
&& !port_dev->port_owner)
|
||||
set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
|
||||
|
||||
|
@ -5557,7 +5547,7 @@ static void port_event(struct usb_hub *hub, int port1)
|
|||
clear_bit(port1, hub->event_bits);
|
||||
clear_bit(port1, hub->wakeup_bits);
|
||||
|
||||
if (hub_port_status(hub, port1, &portstatus, &portchange) < 0)
|
||||
if (usb_hub_port_status(hub, port1, &portstatus, &portchange) < 0)
|
||||
return;
|
||||
|
||||
if (portchange & USB_PORT_STAT_C_CONNECTION) {
|
||||
|
@ -5594,7 +5584,7 @@ static void port_event(struct usb_hub *hub, int port1)
|
|||
USB_PORT_FEAT_C_OVER_CURRENT);
|
||||
msleep(100); /* Cool down */
|
||||
hub_power_on(hub, true);
|
||||
hub_port_status(hub, port1, &status, &unused);
|
||||
usb_hub_port_status(hub, port1, &status, &unused);
|
||||
if (status & USB_PORT_STAT_OVERCURRENT)
|
||||
dev_err(&port_dev->dev, "over-current condition\n");
|
||||
}
|
||||
|
@ -5638,7 +5628,7 @@ static void port_event(struct usb_hub *hub, int port1)
|
|||
u16 unused;
|
||||
|
||||
msleep(20);
|
||||
hub_port_status(hub, port1, &portstatus, &unused);
|
||||
usb_hub_port_status(hub, port1, &portstatus, &unused);
|
||||
dev_dbg(&port_dev->dev, "Wait for inactive link disconnect detect\n");
|
||||
continue;
|
||||
} else if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION)
|
||||
|
|
|
@ -73,6 +73,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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -121,6 +122,9 @@ extern int hub_port_debounce(struct usb_hub *hub, int port1,
|
|||
bool must_be_connected);
|
||||
extern int usb_clear_port_feature(struct usb_device *hdev,
|
||||
int port1, int feature);
|
||||
extern int usb_hub_port_status(struct usb_hub *hub, int port1,
|
||||
u16 *status, u16 *change);
|
||||
extern int usb_port_is_power_on(struct usb_hub *hub, unsigned int portstatus);
|
||||
|
||||
static inline bool hub_is_port_power_switchable(struct usb_hub *hub)
|
||||
{
|
||||
|
|
|
@ -17,6 +17,88 @@ static int usb_port_block_power_off;
|
|||
|
||||
static const struct attribute_group *port_dev_group[];
|
||||
|
||||
static ssize_t disable_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_port *port_dev = to_usb_port(dev);
|
||||
struct usb_device *hdev = to_usb_device(dev->parent->parent);
|
||||
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
|
||||
struct usb_interface *intf = to_usb_interface(hub->intfdev);
|
||||
int port1 = port_dev->portnum;
|
||||
u16 portstatus, unused;
|
||||
bool disabled;
|
||||
int rc;
|
||||
|
||||
rc = usb_autopm_get_interface(intf);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
usb_lock_device(hdev);
|
||||
if (hub->disconnected) {
|
||||
rc = -ENODEV;
|
||||
goto out_hdev_lock;
|
||||
}
|
||||
|
||||
usb_hub_port_status(hub, port1, &portstatus, &unused);
|
||||
disabled = !usb_port_is_power_on(hub, portstatus);
|
||||
|
||||
out_hdev_lock:
|
||||
usb_unlock_device(hdev);
|
||||
usb_autopm_put_interface(intf);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return sysfs_emit(buf, "%s\n", disabled ? "1" : "0");
|
||||
}
|
||||
|
||||
static ssize_t disable_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct usb_port *port_dev = to_usb_port(dev);
|
||||
struct usb_device *hdev = to_usb_device(dev->parent->parent);
|
||||
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
|
||||
struct usb_interface *intf = to_usb_interface(hub->intfdev);
|
||||
int port1 = port_dev->portnum;
|
||||
bool disabled;
|
||||
int rc;
|
||||
|
||||
rc = strtobool(buf, &disabled);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = usb_autopm_get_interface(intf);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
usb_lock_device(hdev);
|
||||
if (hub->disconnected) {
|
||||
rc = -ENODEV;
|
||||
goto out_hdev_lock;
|
||||
}
|
||||
|
||||
if (disabled && port_dev->child)
|
||||
usb_disconnect(&port_dev->child);
|
||||
|
||||
rc = usb_hub_set_port_power(hdev, hub, port1, !disabled);
|
||||
|
||||
if (disabled) {
|
||||
usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION);
|
||||
if (!port_dev->is_superspeed)
|
||||
usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
rc = count;
|
||||
|
||||
out_hdev_lock:
|
||||
usb_unlock_device(hdev);
|
||||
usb_autopm_put_interface(intf);
|
||||
|
||||
return rc;
|
||||
}
|
||||
static DEVICE_ATTR_RW(disable);
|
||||
|
||||
static ssize_t location_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
@ -153,6 +235,7 @@ static struct attribute *port_dev_attrs[] = {
|
|||
&dev_attr_location.attr,
|
||||
&dev_attr_quirks.attr,
|
||||
&dev_attr_over_current_count.attr,
|
||||
&dev_attr_disable.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ static ssize_t field##_show(struct device *dev, \
|
|||
return -EINTR; \
|
||||
actconfig = udev->actconfig; \
|
||||
if (actconfig) \
|
||||
rc = sprintf(buf, format_string, \
|
||||
rc = sysfs_emit(buf, format_string, \
|
||||
actconfig->desc.field); \
|
||||
usb_unlock_device(udev); \
|
||||
return rc; \
|
||||
|
@ -61,7 +61,7 @@ static ssize_t bMaxPower_show(struct device *dev,
|
|||
return -EINTR;
|
||||
actconfig = udev->actconfig;
|
||||
if (actconfig)
|
||||
rc = sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig));
|
||||
rc = sysfs_emit(buf, "%dmA\n", usb_get_max_power(udev, actconfig));
|
||||
usb_unlock_device(udev);
|
||||
return rc;
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ static ssize_t configuration_show(struct device *dev,
|
|||
return -EINTR;
|
||||
actconfig = udev->actconfig;
|
||||
if (actconfig && actconfig->string)
|
||||
rc = sprintf(buf, "%s\n", actconfig->string);
|
||||
rc = sysfs_emit(buf, "%s\n", actconfig->string);
|
||||
usb_unlock_device(udev);
|
||||
return rc;
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ static ssize_t devspec_show(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
struct device_node *of_node = dev->of_node;
|
||||
|
||||
return sprintf(buf, "%pOF\n", of_node);
|
||||
return sysfs_emit(buf, "%pOF\n", of_node);
|
||||
}
|
||||
static DEVICE_ATTR_RO(devspec);
|
||||
#endif
|
||||
|
@ -131,7 +131,7 @@ static ssize_t name##_show(struct device *dev, \
|
|||
retval = usb_lock_device_interruptible(udev); \
|
||||
if (retval < 0) \
|
||||
return -EINTR; \
|
||||
retval = sprintf(buf, "%s\n", udev->name); \
|
||||
retval = sysfs_emit(buf, "%s\n", udev->name); \
|
||||
usb_unlock_device(udev); \
|
||||
return retval; \
|
||||
} \
|
||||
|
@ -175,7 +175,7 @@ static ssize_t speed_show(struct device *dev, struct device_attribute *attr,
|
|||
default:
|
||||
speed = "unknown";
|
||||
}
|
||||
return sprintf(buf, "%s\n", speed);
|
||||
return sysfs_emit(buf, "%s\n", speed);
|
||||
}
|
||||
static DEVICE_ATTR_RO(speed);
|
||||
|
||||
|
@ -185,7 +185,7 @@ static ssize_t rx_lanes_show(struct device *dev, struct device_attribute *attr,
|
|||
struct usb_device *udev;
|
||||
|
||||
udev = to_usb_device(dev);
|
||||
return sprintf(buf, "%d\n", udev->rx_lanes);
|
||||
return sysfs_emit(buf, "%d\n", udev->rx_lanes);
|
||||
}
|
||||
static DEVICE_ATTR_RO(rx_lanes);
|
||||
|
||||
|
@ -195,7 +195,7 @@ static ssize_t tx_lanes_show(struct device *dev, struct device_attribute *attr,
|
|||
struct usb_device *udev;
|
||||
|
||||
udev = to_usb_device(dev);
|
||||
return sprintf(buf, "%d\n", udev->tx_lanes);
|
||||
return sysfs_emit(buf, "%d\n", udev->tx_lanes);
|
||||
}
|
||||
static DEVICE_ATTR_RO(tx_lanes);
|
||||
|
||||
|
@ -205,7 +205,7 @@ static ssize_t busnum_show(struct device *dev, struct device_attribute *attr,
|
|||
struct usb_device *udev;
|
||||
|
||||
udev = to_usb_device(dev);
|
||||
return sprintf(buf, "%d\n", udev->bus->busnum);
|
||||
return sysfs_emit(buf, "%d\n", udev->bus->busnum);
|
||||
}
|
||||
static DEVICE_ATTR_RO(busnum);
|
||||
|
||||
|
@ -215,7 +215,7 @@ static ssize_t devnum_show(struct device *dev, struct device_attribute *attr,
|
|||
struct usb_device *udev;
|
||||
|
||||
udev = to_usb_device(dev);
|
||||
return sprintf(buf, "%d\n", udev->devnum);
|
||||
return sysfs_emit(buf, "%d\n", udev->devnum);
|
||||
}
|
||||
static DEVICE_ATTR_RO(devnum);
|
||||
|
||||
|
@ -225,7 +225,7 @@ static ssize_t devpath_show(struct device *dev, struct device_attribute *attr,
|
|||
struct usb_device *udev;
|
||||
|
||||
udev = to_usb_device(dev);
|
||||
return sprintf(buf, "%s\n", udev->devpath);
|
||||
return sysfs_emit(buf, "%s\n", udev->devpath);
|
||||
}
|
||||
static DEVICE_ATTR_RO(devpath);
|
||||
|
||||
|
@ -237,7 +237,7 @@ static ssize_t version_show(struct device *dev, struct device_attribute *attr,
|
|||
|
||||
udev = to_usb_device(dev);
|
||||
bcdUSB = le16_to_cpu(udev->descriptor.bcdUSB);
|
||||
return sprintf(buf, "%2x.%02x\n", bcdUSB >> 8, bcdUSB & 0xff);
|
||||
return sysfs_emit(buf, "%2x.%02x\n", bcdUSB >> 8, bcdUSB & 0xff);
|
||||
}
|
||||
static DEVICE_ATTR_RO(version);
|
||||
|
||||
|
@ -247,7 +247,7 @@ static ssize_t maxchild_show(struct device *dev, struct device_attribute *attr,
|
|||
struct usb_device *udev;
|
||||
|
||||
udev = to_usb_device(dev);
|
||||
return sprintf(buf, "%d\n", udev->maxchild);
|
||||
return sysfs_emit(buf, "%d\n", udev->maxchild);
|
||||
}
|
||||
static DEVICE_ATTR_RO(maxchild);
|
||||
|
||||
|
@ -257,7 +257,7 @@ static ssize_t quirks_show(struct device *dev, struct device_attribute *attr,
|
|||
struct usb_device *udev;
|
||||
|
||||
udev = to_usb_device(dev);
|
||||
return sprintf(buf, "0x%x\n", udev->quirks);
|
||||
return sysfs_emit(buf, "0x%x\n", udev->quirks);
|
||||
}
|
||||
static DEVICE_ATTR_RO(quirks);
|
||||
|
||||
|
@ -267,7 +267,7 @@ static ssize_t avoid_reset_quirk_show(struct device *dev,
|
|||
struct usb_device *udev;
|
||||
|
||||
udev = to_usb_device(dev);
|
||||
return sprintf(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET));
|
||||
return sysfs_emit(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET));
|
||||
}
|
||||
|
||||
static ssize_t avoid_reset_quirk_store(struct device *dev,
|
||||
|
@ -297,7 +297,7 @@ static ssize_t urbnum_show(struct device *dev, struct device_attribute *attr,
|
|||
struct usb_device *udev;
|
||||
|
||||
udev = to_usb_device(dev);
|
||||
return sprintf(buf, "%d\n", atomic_read(&udev->urbnum));
|
||||
return sysfs_emit(buf, "%d\n", atomic_read(&udev->urbnum));
|
||||
}
|
||||
static DEVICE_ATTR_RO(urbnum);
|
||||
|
||||
|
@ -305,8 +305,8 @@ static ssize_t ltm_capable_show(struct device *dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
if (usb_device_supports_ltm(to_usb_device(dev)))
|
||||
return sprintf(buf, "%s\n", "yes");
|
||||
return sprintf(buf, "%s\n", "no");
|
||||
return sysfs_emit(buf, "%s\n", "yes");
|
||||
return sysfs_emit(buf, "%s\n", "no");
|
||||
}
|
||||
static DEVICE_ATTR_RO(ltm_capable);
|
||||
|
||||
|
@ -317,7 +317,7 @@ static ssize_t persist_show(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", udev->persist_enabled);
|
||||
return sysfs_emit(buf, "%d\n", udev->persist_enabled);
|
||||
}
|
||||
|
||||
static ssize_t persist_store(struct device *dev, struct device_attribute *attr,
|
||||
|
@ -372,7 +372,7 @@ static ssize_t connected_duration_show(struct device *dev,
|
|||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
|
||||
return sprintf(buf, "%u\n",
|
||||
return sysfs_emit(buf, "%u\n",
|
||||
jiffies_to_msecs(jiffies - udev->connect_time));
|
||||
}
|
||||
static DEVICE_ATTR_RO(connected_duration);
|
||||
|
@ -394,14 +394,14 @@ static ssize_t active_duration_show(struct device *dev,
|
|||
duration = jiffies_to_msecs(jiffies + udev->active_duration);
|
||||
else
|
||||
duration = jiffies_to_msecs(udev->active_duration);
|
||||
return sprintf(buf, "%u\n", duration);
|
||||
return sysfs_emit(buf, "%u\n", duration);
|
||||
}
|
||||
static DEVICE_ATTR_RO(active_duration);
|
||||
|
||||
static ssize_t autosuspend_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", dev->power.autosuspend_delay / 1000);
|
||||
return sysfs_emit(buf, "%d\n", dev->power.autosuspend_delay / 1000);
|
||||
}
|
||||
|
||||
static ssize_t autosuspend_store(struct device *dev,
|
||||
|
@ -442,7 +442,7 @@ static ssize_t level_show(struct device *dev, struct device_attribute *attr,
|
|||
warn_level();
|
||||
if (udev->state != USB_STATE_SUSPENDED && !udev->dev.power.runtime_auto)
|
||||
p = on_string;
|
||||
return sprintf(buf, "%s\n", p);
|
||||
return sysfs_emit(buf, "%s\n", p);
|
||||
}
|
||||
|
||||
static ssize_t level_store(struct device *dev, struct device_attribute *attr,
|
||||
|
@ -490,7 +490,7 @@ static ssize_t usb2_hardware_lpm_show(struct device *dev,
|
|||
else
|
||||
p = "disabled";
|
||||
|
||||
return sprintf(buf, "%s\n", p);
|
||||
return sysfs_emit(buf, "%s\n", p);
|
||||
}
|
||||
|
||||
static ssize_t usb2_hardware_lpm_store(struct device *dev,
|
||||
|
@ -529,7 +529,7 @@ static ssize_t usb2_lpm_l1_timeout_show(struct device *dev,
|
|||
char *buf)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
return sprintf(buf, "%d\n", udev->l1_params.timeout);
|
||||
return sysfs_emit(buf, "%d\n", udev->l1_params.timeout);
|
||||
}
|
||||
|
||||
static ssize_t usb2_lpm_l1_timeout_store(struct device *dev,
|
||||
|
@ -552,7 +552,7 @@ static ssize_t usb2_lpm_besl_show(struct device *dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
return sprintf(buf, "%d\n", udev->l1_params.besl);
|
||||
return sysfs_emit(buf, "%d\n", udev->l1_params.besl);
|
||||
}
|
||||
|
||||
static ssize_t usb2_lpm_besl_store(struct device *dev,
|
||||
|
@ -589,7 +589,7 @@ static ssize_t usb3_hardware_lpm_u1_show(struct device *dev,
|
|||
|
||||
usb_unlock_device(udev);
|
||||
|
||||
return sprintf(buf, "%s\n", p);
|
||||
return sysfs_emit(buf, "%s\n", p);
|
||||
}
|
||||
static DEVICE_ATTR_RO(usb3_hardware_lpm_u1);
|
||||
|
||||
|
@ -611,7 +611,7 @@ static ssize_t usb3_hardware_lpm_u2_show(struct device *dev,
|
|||
|
||||
usb_unlock_device(udev);
|
||||
|
||||
return sprintf(buf, "%s\n", p);
|
||||
return sysfs_emit(buf, "%s\n", p);
|
||||
}
|
||||
static DEVICE_ATTR_RO(usb3_hardware_lpm_u2);
|
||||
|
||||
|
@ -694,7 +694,7 @@ field##_show(struct device *dev, struct device_attribute *attr, \
|
|||
struct usb_device *udev; \
|
||||
\
|
||||
udev = to_usb_device(dev); \
|
||||
return sprintf(buf, format_string, \
|
||||
return sysfs_emit(buf, format_string, \
|
||||
le16_to_cpu(udev->descriptor.field)); \
|
||||
} \
|
||||
static DEVICE_ATTR_RO(field)
|
||||
|
@ -711,7 +711,7 @@ field##_show(struct device *dev, struct device_attribute *attr, \
|
|||
struct usb_device *udev; \
|
||||
\
|
||||
udev = to_usb_device(dev); \
|
||||
return sprintf(buf, format_string, udev->descriptor.field); \
|
||||
return sysfs_emit(buf, format_string, udev->descriptor.field); \
|
||||
} \
|
||||
static DEVICE_ATTR_RO(field)
|
||||
|
||||
|
@ -727,7 +727,7 @@ static ssize_t authorized_show(struct device *dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_device *usb_dev = to_usb_device(dev);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized);
|
||||
return sysfs_emit(buf, "%u\n", usb_dev->authorized);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -918,7 +918,7 @@ static ssize_t authorized_default_show(struct device *dev,
|
|||
struct usb_hcd *hcd;
|
||||
|
||||
hcd = bus_to_hcd(usb_bus);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", hcd->dev_policy);
|
||||
return sysfs_emit(buf, "%u\n", hcd->dev_policy);
|
||||
}
|
||||
|
||||
static ssize_t authorized_default_store(struct device *dev,
|
||||
|
@ -957,7 +957,7 @@ static ssize_t interface_authorized_default_show(struct device *dev,
|
|||
struct usb_device *usb_dev = to_usb_device(dev);
|
||||
struct usb_hcd *hcd = bus_to_hcd(usb_dev->bus);
|
||||
|
||||
return sprintf(buf, "%u\n", !!HCD_INTF_AUTHORIZED(hcd));
|
||||
return sysfs_emit(buf, "%u\n", !!HCD_INTF_AUTHORIZED(hcd));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1066,7 +1066,7 @@ iad_##field##_show(struct device *dev, struct device_attribute *attr, \
|
|||
{ \
|
||||
struct usb_interface *intf = to_usb_interface(dev); \
|
||||
\
|
||||
return sprintf(buf, format_string, \
|
||||
return sysfs_emit(buf, format_string, \
|
||||
intf->intf_assoc->field); \
|
||||
} \
|
||||
static DEVICE_ATTR_RO(iad_##field)
|
||||
|
@ -1085,7 +1085,7 @@ field##_show(struct device *dev, struct device_attribute *attr, \
|
|||
{ \
|
||||
struct usb_interface *intf = to_usb_interface(dev); \
|
||||
\
|
||||
return sprintf(buf, format_string, \
|
||||
return sysfs_emit(buf, format_string, \
|
||||
intf->cur_altsetting->desc.field); \
|
||||
} \
|
||||
static DEVICE_ATTR_RO(field)
|
||||
|
@ -1107,7 +1107,7 @@ static ssize_t interface_show(struct device *dev, struct device_attribute *attr,
|
|||
string = READ_ONCE(intf->cur_altsetting->string);
|
||||
if (!string)
|
||||
return 0;
|
||||
return sprintf(buf, "%s\n", string);
|
||||
return sysfs_emit(buf, "%s\n", string);
|
||||
}
|
||||
static DEVICE_ATTR_RO(interface);
|
||||
|
||||
|
@ -1122,7 +1122,8 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
|||
udev = interface_to_usbdev(intf);
|
||||
alt = READ_ONCE(intf->cur_altsetting);
|
||||
|
||||
return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"
|
||||
return sysfs_emit(buf,
|
||||
"usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"
|
||||
"ic%02Xisc%02Xip%02Xin%02X\n",
|
||||
le16_to_cpu(udev->descriptor.idVendor),
|
||||
le16_to_cpu(udev->descriptor.idProduct),
|
||||
|
@ -1150,7 +1151,7 @@ static ssize_t supports_autosuspend_show(struct device *dev,
|
|||
s = (!dev->driver || to_usb_driver(dev->driver)->supports_autosuspend);
|
||||
device_unlock(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", s);
|
||||
return sysfs_emit(buf, "%u\n", s);
|
||||
}
|
||||
static DEVICE_ATTR_RO(supports_autosuspend);
|
||||
|
||||
|
@ -1163,7 +1164,7 @@ static ssize_t interface_authorized_show(struct device *dev,
|
|||
{
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", intf->authorized);
|
||||
return sysfs_emit(buf, "%u\n", intf->authorized);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -801,7 +801,7 @@ EXPORT_SYMBOL_GPL(usb_intf_get_dma_device);
|
|||
* is simple:
|
||||
*
|
||||
* When locking both a device and its parent, always lock the
|
||||
* the parent first.
|
||||
* parent first.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
|
@ -3594,7 +3594,8 @@ void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg)
|
|||
void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
/* remove the soft-disconnect and let's go */
|
||||
dwc2_clear_bit(hsotg, DCTL, DCTL_SFTDISCON);
|
||||
if (!hsotg->role_sw || (dwc2_readl(hsotg, GOTGCTL) & GOTGCTL_BSESVLD))
|
||||
dwc2_clear_bit(hsotg, DCTL, DCTL_SFTDISCON);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <linux/usb/ch11.h>
|
||||
#include <linux/usb/of.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "hcd.h"
|
||||
|
@ -999,7 +1000,7 @@ static void dwc2_hc_set_even_odd_frame(struct dwc2_hsotg *hsotg,
|
|||
|
||||
/*
|
||||
* Try to figure out if we're an even or odd frame. If we set
|
||||
* even and the current frame number is even the the transfer
|
||||
* even and the current frame number is even the transfer
|
||||
* will happen immediately. Similar if both are odd. If one is
|
||||
* even and the other is odd then the transfer will happen when
|
||||
* the frame number ticks.
|
||||
|
@ -5339,6 +5340,8 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
|
|||
/* Don't support SG list at this point */
|
||||
hcd->self.sg_tablesize = 0;
|
||||
|
||||
hcd->tpl_support = of_usb_host_tpl_support(hsotg->dev->of_node);
|
||||
|
||||
if (!IS_ERR_OR_NULL(hsotg->uphy))
|
||||
otg_set_host(hsotg->uphy->otg, &hcd->self);
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ config USB_DWC3
|
|||
Say Y or M here if your system has a Dual Role SuperSpeed
|
||||
USB controller based on the DesignWare USB3 IP Core.
|
||||
|
||||
If you choose to build this driver is a dynamically linked
|
||||
If you choose to build this driver as a dynamically linked
|
||||
module, the module will be called dwc3.ko.
|
||||
|
||||
if USB_DWC3
|
||||
|
@ -165,7 +165,7 @@ config USB_DWC3_AM62
|
|||
default USB_DWC3
|
||||
help
|
||||
Support TI's AM62 platforms with DesignWare Core USB3 IP.
|
||||
The Designware Core USB3 IP is progammed to operate in
|
||||
The Designware Core USB3 IP is programmed to operate in
|
||||
in USB 2.0 mode only.
|
||||
Say 'Y' or 'M' here if you have one such device
|
||||
endif
|
||||
|
|
|
@ -158,8 +158,13 @@ static void __dwc3_set_mode(struct work_struct *work)
|
|||
break;
|
||||
}
|
||||
|
||||
/* For DRD host or device mode only */
|
||||
if (dwc->desired_dr_role != DWC3_GCTL_PRTCAP_OTG) {
|
||||
/*
|
||||
* When current_dr_role is not set, there's no role switching.
|
||||
* Only perform GCTL.CoreSoftReset when there's DRD role switching.
|
||||
*/
|
||||
if (dwc->current_dr_role && ((DWC3_IP_IS(DWC3) ||
|
||||
DWC3_VER_IS_PRIOR(DWC31, 190A)) &&
|
||||
dwc->desired_dr_role != DWC3_GCTL_PRTCAP_OTG)) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
reg |= DWC3_GCTL_CORESOFTRESET;
|
||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
|
@ -426,7 +431,7 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
|
|||
* otherwise ERR_PTR(errno).
|
||||
*/
|
||||
static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
|
||||
unsigned length)
|
||||
unsigned int length)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
|
||||
|
@ -469,7 +474,7 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)
|
|||
* Returns 0 on success otherwise negative errno. In the error case, dwc
|
||||
* may contain some buffers allocated but not all which were requested.
|
||||
*/
|
||||
static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
|
||||
static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned int length)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
|
||||
|
@ -1029,6 +1034,37 @@ static void dwc3_set_incr_burst_type(struct dwc3 *dwc)
|
|||
dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, cfg);
|
||||
}
|
||||
|
||||
static void dwc3_set_power_down_clk_scale(struct dwc3 *dwc)
|
||||
{
|
||||
u32 scale;
|
||||
u32 reg;
|
||||
|
||||
if (!dwc->susp_clk)
|
||||
return;
|
||||
|
||||
/*
|
||||
* The power down scale field specifies how many suspend_clk
|
||||
* periods fit into a 16KHz clock period. When performing
|
||||
* the division, round up the remainder.
|
||||
*
|
||||
* The power down scale value is calculated using the fastest
|
||||
* frequency of the suspend_clk. If it isn't fixed (but within
|
||||
* the accuracy requirement), the driver may not know the max
|
||||
* rate of the suspend_clk, so only update the power down scale
|
||||
* if the default is less than the calculated value from
|
||||
* clk_get_rate() or if the default is questionably high
|
||||
* (3x or more) to be within the requirement.
|
||||
*/
|
||||
scale = DIV_ROUND_UP(clk_get_rate(dwc->susp_clk), 16000);
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
if ((reg & DWC3_GCTL_PWRDNSCALE_MASK) < DWC3_GCTL_PWRDNSCALE(scale) ||
|
||||
(reg & DWC3_GCTL_PWRDNSCALE_MASK) > DWC3_GCTL_PWRDNSCALE(scale*3)) {
|
||||
reg &= ~(DWC3_GCTL_PWRDNSCALE_MASK);
|
||||
reg |= DWC3_GCTL_PWRDNSCALE(scale);
|
||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_core_init - Low-level initialization of DWC3 Core
|
||||
* @dwc: Pointer to our controller context structure
|
||||
|
@ -1105,6 +1141,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
|||
if (ret)
|
||||
goto err1;
|
||||
|
||||
/* Set power down scale of suspend_clk */
|
||||
dwc3_set_power_down_clk_scale(dwc);
|
||||
|
||||
/* Adjust Frame Length */
|
||||
dwc3_frame_length_adjustment(dwc);
|
||||
|
||||
|
@ -1782,6 +1821,7 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, dwc);
|
||||
dwc3_cache_hwparams(dwc);
|
||||
device_init_wakeup(&pdev->dev, of_property_read_bool(dev->of_node, "wakeup-source"));
|
||||
|
||||
spin_lock_init(&dwc->lock);
|
||||
mutex_init(&dwc->mutex);
|
||||
|
@ -1943,7 +1983,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
|
|||
dwc3_core_exit(dwc);
|
||||
break;
|
||||
case DWC3_GCTL_PRTCAP_HOST:
|
||||
if (!PMSG_IS_AUTO(msg)) {
|
||||
if (!PMSG_IS_AUTO(msg) && !device_can_wakeup(dwc->dev)) {
|
||||
dwc3_core_exit(dwc);
|
||||
break;
|
||||
}
|
||||
|
@ -2004,7 +2044,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
|
|||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
break;
|
||||
case DWC3_GCTL_PRTCAP_HOST:
|
||||
if (!PMSG_IS_AUTO(msg)) {
|
||||
if (!PMSG_IS_AUTO(msg) && !device_can_wakeup(dwc->dev)) {
|
||||
ret = dwc3_core_init_for_resume(dwc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -2081,8 +2121,6 @@ static int dwc3_runtime_suspend(struct device *dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
device_init_wakeup(dev, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2091,8 +2129,6 @@ static int dwc3_runtime_resume(struct device *dev)
|
|||
struct dwc3 *dwc = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
device_init_wakeup(dev, false);
|
||||
|
||||
ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
@ -231,6 +231,7 @@
|
|||
|
||||
/* Global Configuration Register */
|
||||
#define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19)
|
||||
#define DWC3_GCTL_PWRDNSCALE_MASK GENMASK(31, 19)
|
||||
#define DWC3_GCTL_U2RSTECN BIT(16)
|
||||
#define DWC3_GCTL_RAMCLKSEL(x) (((x) & DWC3_GCTL_CLK_MASK) << 6)
|
||||
#define DWC3_GCTL_CLK_BUS (0)
|
||||
|
@ -1086,6 +1087,8 @@ struct dwc3_scratchpad_array {
|
|||
* @dis_u1_entry_quirk: set if link entering into U1 state needs to be disabled.
|
||||
* @dis_u2_entry_quirk: set if link entering into U2 state needs to be disabled.
|
||||
* @dis_rxdet_inp3_quirk: set if we disable Rx.Detect in P3
|
||||
* @async_callbacks: if set, indicate that async callbacks will be used.
|
||||
*
|
||||
* @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists
|
||||
* in GUSB2PHYCFG, specify that USB2 PHY doesn't
|
||||
* provide a free-running PHY clock.
|
||||
|
|
|
@ -17,10 +17,12 @@
|
|||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/usb/of.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <linux/usb.h>
|
||||
#include "core.h"
|
||||
|
||||
/* USB QSCRATCH Hardware registers */
|
||||
|
@ -76,6 +78,7 @@ struct dwc3_qcom {
|
|||
int dp_hs_phy_irq;
|
||||
int dm_hs_phy_irq;
|
||||
int ss_phy_irq;
|
||||
enum usb_device_speed usb2_speed;
|
||||
|
||||
struct extcon_dev *edev;
|
||||
struct extcon_dev *host_edev;
|
||||
|
@ -296,50 +299,92 @@ static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom)
|
|||
icc_put(qcom->icc_path_apps);
|
||||
}
|
||||
|
||||
static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom)
|
||||
{
|
||||
struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
|
||||
struct usb_hcd *hcd = platform_get_drvdata(dwc->xhci);
|
||||
struct usb_device *udev;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
udev = usb_hub_find_child(hcd->self.root_hub, 1);
|
||||
|
||||
if (!udev)
|
||||
return USB_SPEED_UNKNOWN;
|
||||
|
||||
return udev->speed;
|
||||
}
|
||||
|
||||
static void dwc3_qcom_enable_wakeup_irq(int irq, unsigned int polarity)
|
||||
{
|
||||
if (!irq)
|
||||
return;
|
||||
|
||||
if (polarity)
|
||||
irq_set_irq_type(irq, polarity);
|
||||
|
||||
enable_irq(irq);
|
||||
enable_irq_wake(irq);
|
||||
}
|
||||
|
||||
static void dwc3_qcom_disable_wakeup_irq(int irq)
|
||||
{
|
||||
if (!irq)
|
||||
return;
|
||||
|
||||
disable_irq_wake(irq);
|
||||
disable_irq_nosync(irq);
|
||||
}
|
||||
|
||||
static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom)
|
||||
{
|
||||
if (qcom->hs_phy_irq) {
|
||||
disable_irq_wake(qcom->hs_phy_irq);
|
||||
disable_irq_nosync(qcom->hs_phy_irq);
|
||||
dwc3_qcom_disable_wakeup_irq(qcom->hs_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);
|
||||
} else {
|
||||
dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq);
|
||||
dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq);
|
||||
}
|
||||
|
||||
if (qcom->dp_hs_phy_irq) {
|
||||
disable_irq_wake(qcom->dp_hs_phy_irq);
|
||||
disable_irq_nosync(qcom->dp_hs_phy_irq);
|
||||
}
|
||||
|
||||
if (qcom->dm_hs_phy_irq) {
|
||||
disable_irq_wake(qcom->dm_hs_phy_irq);
|
||||
disable_irq_nosync(qcom->dm_hs_phy_irq);
|
||||
}
|
||||
|
||||
if (qcom->ss_phy_irq) {
|
||||
disable_irq_wake(qcom->ss_phy_irq);
|
||||
disable_irq_nosync(qcom->ss_phy_irq);
|
||||
}
|
||||
dwc3_qcom_disable_wakeup_irq(qcom->ss_phy_irq);
|
||||
}
|
||||
|
||||
static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
|
||||
{
|
||||
if (qcom->hs_phy_irq) {
|
||||
enable_irq(qcom->hs_phy_irq);
|
||||
enable_irq_wake(qcom->hs_phy_irq);
|
||||
dwc3_qcom_enable_wakeup_irq(qcom->hs_phy_irq, 0);
|
||||
|
||||
/*
|
||||
* Configure DP/DM line interrupts based on the USB2 device attached to
|
||||
* the root hub port. When HS/FS device is connected, configure the DP line
|
||||
* as falling edge to detect both disconnect and remote wakeup scenarios. When
|
||||
* LS device is connected, configure DM line as falling edge to detect both
|
||||
* disconnect and remote wakeup. When no device is connected, configure both
|
||||
* 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);
|
||||
} 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);
|
||||
}
|
||||
|
||||
if (qcom->dp_hs_phy_irq) {
|
||||
enable_irq(qcom->dp_hs_phy_irq);
|
||||
enable_irq_wake(qcom->dp_hs_phy_irq);
|
||||
}
|
||||
|
||||
if (qcom->dm_hs_phy_irq) {
|
||||
enable_irq(qcom->dm_hs_phy_irq);
|
||||
enable_irq_wake(qcom->dm_hs_phy_irq);
|
||||
}
|
||||
|
||||
if (qcom->ss_phy_irq) {
|
||||
enable_irq(qcom->ss_phy_irq);
|
||||
enable_irq_wake(qcom->ss_phy_irq);
|
||||
}
|
||||
dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq, 0);
|
||||
}
|
||||
|
||||
static int dwc3_qcom_suspend(struct dwc3_qcom *qcom)
|
||||
|
@ -361,8 +406,10 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom)
|
|||
if (ret)
|
||||
dev_warn(qcom->dev, "failed to disable interconnect: %d\n", ret);
|
||||
|
||||
if (device_may_wakeup(qcom->dev))
|
||||
if (device_may_wakeup(qcom->dev)) {
|
||||
qcom->usb2_speed = dwc3_qcom_read_usb2_speed(qcom);
|
||||
dwc3_qcom_enable_interrupts(qcom);
|
||||
}
|
||||
|
||||
qcom->is_suspended = true;
|
||||
|
||||
|
@ -443,9 +490,9 @@ static int dwc3_qcom_get_irq(struct platform_device *pdev,
|
|||
int ret;
|
||||
|
||||
if (np)
|
||||
ret = platform_get_irq_byname(pdev_irq, name);
|
||||
ret = platform_get_irq_byname_optional(pdev_irq, name);
|
||||
else
|
||||
ret = platform_get_irq(pdev_irq, num);
|
||||
ret = platform_get_irq_optional(pdev_irq, num);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -710,12 +757,13 @@ dwc3_qcom_create_urs_usb_platdev(struct device *dev)
|
|||
|
||||
static int dwc3_qcom_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dwc3_qcom *qcom;
|
||||
struct resource *res, *parent_res = NULL;
|
||||
int ret, i;
|
||||
bool ignore_pipe_clk;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dwc3_qcom *qcom;
|
||||
struct resource *res, *parent_res = NULL;
|
||||
int ret, i;
|
||||
bool ignore_pipe_clk;
|
||||
struct generic_pm_domain *genpd;
|
||||
|
||||
qcom = devm_kzalloc(&pdev->dev, sizeof(*qcom), GFP_KERNEL);
|
||||
if (!qcom)
|
||||
|
@ -724,6 +772,8 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, qcom);
|
||||
qcom->dev = &pdev->dev;
|
||||
|
||||
genpd = pd_to_genpd(qcom->dev->pm_domain);
|
||||
|
||||
if (has_acpi_companion(dev)) {
|
||||
qcom->acpi_pdata = acpi_device_get_match_data(dev);
|
||||
if (!qcom->acpi_pdata) {
|
||||
|
@ -831,7 +881,17 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto interconnect_exit;
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
if (device_can_wakeup(&qcom->dwc3->dev)) {
|
||||
/*
|
||||
* Setting GENPD_FLAG_ALWAYS_ON flag takes care of keeping
|
||||
* genpd on in both runtime suspend and system suspend cases.
|
||||
*/
|
||||
genpd->flags |= GENPD_FLAG_ALWAYS_ON;
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
} else {
|
||||
genpd->flags |= GENPD_FLAG_RPM_ALWAYS_ON;
|
||||
}
|
||||
|
||||
qcom->is_suspended = false;
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
|
|
@ -239,6 +239,8 @@ void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
|
|||
dwc3_gadget_giveback(dep, req, -ECONNRESET);
|
||||
}
|
||||
|
||||
dwc->eps[0]->trb_enqueue = 0;
|
||||
dwc->eps[1]->trb_enqueue = 0;
|
||||
dwc->ep0state = EP0_SETUP_PHASE;
|
||||
dwc3_ep0_out_start(dwc);
|
||||
}
|
||||
|
@ -473,7 +475,7 @@ static int dwc3_ep0_handle_device(struct dwc3 *dwc,
|
|||
case USB_DEVICE_REMOTE_WAKEUP:
|
||||
break;
|
||||
/*
|
||||
* 9.4.1 says only only for SS, in AddressState only for
|
||||
* 9.4.1 says only for SS, in AddressState only for
|
||||
* default control pipe
|
||||
*/
|
||||
case USB_DEVICE_U1_ENABLE:
|
||||
|
@ -1140,6 +1142,11 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
|
|||
if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS)
|
||||
return;
|
||||
|
||||
if (dwc->setup_packet_pending) {
|
||||
dwc3_ep0_stall_and_restart(dwc);
|
||||
return;
|
||||
}
|
||||
|
||||
dwc->ep0state = EP0_STATUS_PHASE;
|
||||
|
||||
if (dwc->delayed_status) {
|
||||
|
|
|
@ -657,6 +657,7 @@ static int dwc3_gadget_set_ep_config(struct dwc3_ep *dep, unsigned int action)
|
|||
/**
|
||||
* dwc3_gadget_calc_tx_fifo_size - calculates the txfifo size value
|
||||
* @dwc: pointer to the DWC3 context
|
||||
* @mult: multiplier to be used when calculating the fifo_size
|
||||
*
|
||||
* Calculates the size value based on the equation below:
|
||||
*
|
||||
|
@ -1182,17 +1183,49 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep)
|
|||
return trbs_left;
|
||||
}
|
||||
|
||||
static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb,
|
||||
dma_addr_t dma, unsigned int length, unsigned int chain,
|
||||
unsigned int node, unsigned int stream_id,
|
||||
unsigned int short_not_ok, unsigned int no_interrupt,
|
||||
unsigned int is_last, bool must_interrupt)
|
||||
/**
|
||||
* dwc3_prepare_one_trb - setup one TRB from one request
|
||||
* @dep: endpoint for which this request is prepared
|
||||
* @req: dwc3_request pointer
|
||||
* @trb_length: buffer size of the TRB
|
||||
* @chain: should this TRB be chained to the next?
|
||||
* @node: only for isochronous endpoints. First TRB needs different type.
|
||||
* @use_bounce_buffer: set to use bounce buffer
|
||||
* @must_interrupt: set to interrupt on TRB completion
|
||||
*/
|
||||
static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
|
||||
struct dwc3_request *req, unsigned int trb_length,
|
||||
unsigned int chain, unsigned int node, bool use_bounce_buffer,
|
||||
bool must_interrupt)
|
||||
{
|
||||
struct dwc3_trb *trb;
|
||||
dma_addr_t dma;
|
||||
unsigned int stream_id = req->request.stream_id;
|
||||
unsigned int short_not_ok = req->request.short_not_ok;
|
||||
unsigned int no_interrupt = req->request.no_interrupt;
|
||||
unsigned int is_last = req->request.is_last;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
struct usb_gadget *gadget = dwc->gadget;
|
||||
enum usb_device_speed speed = gadget->speed;
|
||||
|
||||
trb->size = DWC3_TRB_SIZE_LENGTH(length);
|
||||
if (use_bounce_buffer)
|
||||
dma = dep->dwc->bounce_addr;
|
||||
else if (req->request.num_sgs > 0)
|
||||
dma = sg_dma_address(req->start_sg);
|
||||
else
|
||||
dma = req->request.dma;
|
||||
|
||||
trb = &dep->trb_pool[dep->trb_enqueue];
|
||||
|
||||
if (!req->trb) {
|
||||
dwc3_gadget_move_started_request(req);
|
||||
req->trb = trb;
|
||||
req->trb_dma = dwc3_trb_dma_offset(dep, trb);
|
||||
}
|
||||
|
||||
req->num_trbs++;
|
||||
|
||||
trb->size = DWC3_TRB_SIZE_LENGTH(trb_length);
|
||||
trb->bpl = lower_32_bits(dma);
|
||||
trb->bph = upper_32_bits(dma);
|
||||
|
||||
|
@ -1232,10 +1265,10 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb,
|
|||
unsigned int mult = 2;
|
||||
unsigned int maxp = usb_endpoint_maxp(ep->desc);
|
||||
|
||||
if (length <= (2 * maxp))
|
||||
if (req->request.length <= (2 * maxp))
|
||||
mult--;
|
||||
|
||||
if (length <= maxp)
|
||||
if (req->request.length <= maxp)
|
||||
mult--;
|
||||
|
||||
trb->size |= DWC3_TRB_SIZE_PCM1(mult);
|
||||
|
@ -1309,50 +1342,6 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb,
|
|||
trace_dwc3_prepare_trb(dep, trb);
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_prepare_one_trb - setup one TRB from one request
|
||||
* @dep: endpoint for which this request is prepared
|
||||
* @req: dwc3_request pointer
|
||||
* @trb_length: buffer size of the TRB
|
||||
* @chain: should this TRB be chained to the next?
|
||||
* @node: only for isochronous endpoints. First TRB needs different type.
|
||||
* @use_bounce_buffer: set to use bounce buffer
|
||||
* @must_interrupt: set to interrupt on TRB completion
|
||||
*/
|
||||
static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
|
||||
struct dwc3_request *req, unsigned int trb_length,
|
||||
unsigned int chain, unsigned int node, bool use_bounce_buffer,
|
||||
bool must_interrupt)
|
||||
{
|
||||
struct dwc3_trb *trb;
|
||||
dma_addr_t dma;
|
||||
unsigned int stream_id = req->request.stream_id;
|
||||
unsigned int short_not_ok = req->request.short_not_ok;
|
||||
unsigned int no_interrupt = req->request.no_interrupt;
|
||||
unsigned int is_last = req->request.is_last;
|
||||
|
||||
if (use_bounce_buffer)
|
||||
dma = dep->dwc->bounce_addr;
|
||||
else if (req->request.num_sgs > 0)
|
||||
dma = sg_dma_address(req->start_sg);
|
||||
else
|
||||
dma = req->request.dma;
|
||||
|
||||
trb = &dep->trb_pool[dep->trb_enqueue];
|
||||
|
||||
if (!req->trb) {
|
||||
dwc3_gadget_move_started_request(req);
|
||||
req->trb = trb;
|
||||
req->trb_dma = dwc3_trb_dma_offset(dep, trb);
|
||||
}
|
||||
|
||||
req->num_trbs++;
|
||||
|
||||
__dwc3_prepare_one_trb(dep, trb, dma, trb_length, chain, node,
|
||||
stream_id, short_not_ok, no_interrupt, is_last,
|
||||
must_interrupt);
|
||||
}
|
||||
|
||||
static bool dwc3_needs_extra_trb(struct dwc3_ep *dep, struct dwc3_request *req)
|
||||
{
|
||||
unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
|
||||
|
|
|
@ -57,18 +57,8 @@ struct f_acm {
|
|||
|
||||
/* SetControlLineState request -- CDC 1.1 section 6.2.14 (INPUT) */
|
||||
u16 port_handshake_bits;
|
||||
#define ACM_CTRL_RTS (1 << 1) /* unused with full duplex */
|
||||
#define ACM_CTRL_DTR (1 << 0) /* host is ready for data r/w */
|
||||
|
||||
/* SerialState notification -- CDC 1.1 section 6.3.5 (OUTPUT) */
|
||||
u16 serial_state;
|
||||
#define ACM_CTRL_OVERRUN (1 << 6)
|
||||
#define ACM_CTRL_PARITY (1 << 5)
|
||||
#define ACM_CTRL_FRAMING (1 << 4)
|
||||
#define ACM_CTRL_RI (1 << 3)
|
||||
#define ACM_CTRL_BRK (1 << 2)
|
||||
#define ACM_CTRL_DSR (1 << 1)
|
||||
#define ACM_CTRL_DCD (1 << 0)
|
||||
};
|
||||
|
||||
static inline struct f_acm *func_to_acm(struct usb_function *f)
|
||||
|
@ -387,7 +377,7 @@ static int acm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
|
|||
value = 0;
|
||||
|
||||
/* FIXME we should not allow data to flow until the
|
||||
* host sets the ACM_CTRL_DTR bit; and when it clears
|
||||
* host sets the USB_CDC_CTRL_DTR bit; and when it clears
|
||||
* that bit, we should return to that no-flow state.
|
||||
*/
|
||||
acm->port_handshake_bits = w_value;
|
||||
|
@ -585,7 +575,7 @@ static void acm_connect(struct gserial *port)
|
|||
{
|
||||
struct f_acm *acm = port_to_acm(port);
|
||||
|
||||
acm->serial_state |= ACM_CTRL_DSR | ACM_CTRL_DCD;
|
||||
acm->serial_state |= USB_CDC_SERIAL_STATE_DSR | USB_CDC_SERIAL_STATE_DCD;
|
||||
acm_notify_serial_state(acm);
|
||||
}
|
||||
|
||||
|
@ -593,7 +583,7 @@ static void acm_disconnect(struct gserial *port)
|
|||
{
|
||||
struct f_acm *acm = port_to_acm(port);
|
||||
|
||||
acm->serial_state &= ~(ACM_CTRL_DSR | ACM_CTRL_DCD);
|
||||
acm->serial_state &= ~(USB_CDC_SERIAL_STATE_DSR | USB_CDC_SERIAL_STATE_DCD);
|
||||
acm_notify_serial_state(acm);
|
||||
}
|
||||
|
||||
|
@ -603,9 +593,9 @@ static int acm_send_break(struct gserial *port, int duration)
|
|||
u16 state;
|
||||
|
||||
state = acm->serial_state;
|
||||
state &= ~ACM_CTRL_BRK;
|
||||
state &= ~USB_CDC_SERIAL_STATE_BREAK;
|
||||
if (duration)
|
||||
state |= ACM_CTRL_BRK;
|
||||
state |= USB_CDC_SERIAL_STATE_BREAK;
|
||||
|
||||
acm->serial_state = state;
|
||||
return acm_notify_serial_state(acm);
|
||||
|
|
|
@ -1192,13 +1192,14 @@ static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh)
|
|||
u8 format;
|
||||
int i, len;
|
||||
|
||||
format = common->cmnd[2] & 0xf;
|
||||
|
||||
if ((common->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
|
||||
start_track > 1) {
|
||||
(start_track > 1 && format != 0x1)) {
|
||||
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
format = common->cmnd[2] & 0xf;
|
||||
/*
|
||||
* Check if CDB is old style SFF-8020i
|
||||
* i.e. format is in 2 MSBs of byte 9
|
||||
|
@ -1208,8 +1209,8 @@ static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh)
|
|||
format = (common->cmnd[9] >> 6) & 0x3;
|
||||
|
||||
switch (format) {
|
||||
case 0:
|
||||
/* Formatted TOC */
|
||||
case 0: /* Formatted TOC */
|
||||
case 1: /* Multi-session info */
|
||||
len = 4 + 2*8; /* 4 byte header + 2 descriptors */
|
||||
memset(buf, 0, len);
|
||||
buf[1] = len - 2; /* TOC Length excludes length field */
|
||||
|
@ -1250,7 +1251,7 @@ static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh)
|
|||
return len;
|
||||
|
||||
default:
|
||||
/* Multi-session, PMA, ATIP, CD-TEXT not supported/required */
|
||||
/* PMA, ATIP, CD-TEXT not supported/required */
|
||||
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -2650,10 +2651,21 @@ static ssize_t file_store(struct device *dev, struct device_attribute *attr,
|
|||
return fsg_store_file(curlun, filesem, buf, count);
|
||||
}
|
||||
|
||||
static ssize_t forced_eject_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
|
||||
struct rw_semaphore *filesem = dev_get_drvdata(dev);
|
||||
|
||||
return fsg_store_forced_eject(curlun, filesem, buf, count);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(nofua);
|
||||
/* mode wil be set in fsg_lun_attr_is_visible() */
|
||||
static DEVICE_ATTR(ro, 0, ro_show, ro_store);
|
||||
static DEVICE_ATTR(file, 0, file_show, file_store);
|
||||
static DEVICE_ATTR_WO(forced_eject);
|
||||
|
||||
/****************************** FSG COMMON ******************************/
|
||||
|
||||
|
@ -2807,6 +2819,7 @@ static struct attribute *fsg_lun_dev_attrs[] = {
|
|||
&dev_attr_ro.attr,
|
||||
&dev_attr_file.attr,
|
||||
&dev_attr_nofua.attr,
|
||||
&dev_attr_forced_eject.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -3220,6 +3233,18 @@ static ssize_t fsg_lun_opts_inquiry_string_store(struct config_item *item,
|
|||
|
||||
CONFIGFS_ATTR(fsg_lun_opts_, inquiry_string);
|
||||
|
||||
static ssize_t fsg_lun_opts_forced_eject_store(struct config_item *item,
|
||||
const char *page, size_t len)
|
||||
{
|
||||
struct fsg_lun_opts *opts = to_fsg_lun_opts(item);
|
||||
struct fsg_opts *fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent);
|
||||
|
||||
return fsg_store_forced_eject(opts->lun, &fsg_opts->common->filesem,
|
||||
page, len);
|
||||
}
|
||||
|
||||
CONFIGFS_ATTR_WO(fsg_lun_opts_, forced_eject);
|
||||
|
||||
static struct configfs_attribute *fsg_lun_attrs[] = {
|
||||
&fsg_lun_opts_attr_file,
|
||||
&fsg_lun_opts_attr_ro,
|
||||
|
@ -3227,6 +3252,7 @@ static struct configfs_attribute *fsg_lun_attrs[] = {
|
|||
&fsg_lun_opts_attr_cdrom,
|
||||
&fsg_lun_opts_attr_nofua,
|
||||
&fsg_lun_opts_attr_inquiry_string,
|
||||
&fsg_lun_opts_attr_forced_eject,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
|
|
@ -141,7 +141,8 @@ static struct usb_endpoint_descriptor uvc_fs_streaming_ep = {
|
|||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_SYNC_ASYNC
|
||||
| USB_ENDPOINT_XFER_ISOC,
|
||||
/* The wMaxPacketSize and bInterval values will be initialized from
|
||||
/*
|
||||
* The wMaxPacketSize and bInterval values will be initialized from
|
||||
* module parameters.
|
||||
*/
|
||||
};
|
||||
|
@ -152,7 +153,8 @@ static struct usb_endpoint_descriptor uvc_hs_streaming_ep = {
|
|||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_SYNC_ASYNC
|
||||
| USB_ENDPOINT_XFER_ISOC,
|
||||
/* The wMaxPacketSize and bInterval values will be initialized from
|
||||
/*
|
||||
* The wMaxPacketSize and bInterval values will be initialized from
|
||||
* module parameters.
|
||||
*/
|
||||
};
|
||||
|
@ -164,7 +166,8 @@ static struct usb_endpoint_descriptor uvc_ss_streaming_ep = {
|
|||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_SYNC_ASYNC
|
||||
| USB_ENDPOINT_XFER_ISOC,
|
||||
/* The wMaxPacketSize and bInterval values will be initialized from
|
||||
/*
|
||||
* The wMaxPacketSize and bInterval values will be initialized from
|
||||
* module parameters.
|
||||
*/
|
||||
};
|
||||
|
@ -172,7 +175,8 @@ static struct usb_endpoint_descriptor uvc_ss_streaming_ep = {
|
|||
static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = {
|
||||
.bLength = sizeof(uvc_ss_streaming_comp),
|
||||
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
||||
/* The bMaxBurst, bmAttributes and wBytesPerInterval values will be
|
||||
/*
|
||||
* The bMaxBurst, bmAttributes and wBytesPerInterval values will be
|
||||
* initialized from module parameters.
|
||||
*/
|
||||
};
|
||||
|
@ -234,7 +238,8 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
|
|||
if (le16_to_cpu(ctrl->wLength) > UVC_MAX_REQUEST_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
/* Tell the complete callback to generate an event for the next request
|
||||
/*
|
||||
* Tell the complete callback to generate an event for the next request
|
||||
* that will be enqueued by UVCIOC_SEND_RESPONSE.
|
||||
*/
|
||||
uvc->event_setup_out = !(ctrl->bRequestType & USB_DIR_IN);
|
||||
|
@ -500,7 +505,8 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
|
|||
if (!uvc_control_desc || !uvc_streaming_cls)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
/* Descriptors layout
|
||||
/*
|
||||
* Descriptors layout
|
||||
*
|
||||
* uvc_iad
|
||||
* uvc_control_intf
|
||||
|
@ -597,8 +603,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
uvcg_info(f, "%s()\n", __func__);
|
||||
|
||||
opts = fi_to_f_uvc_opts(f->fi);
|
||||
/* Sanity check the streaming endpoint module parameters.
|
||||
*/
|
||||
/* Sanity check the streaming endpoint module parameters. */
|
||||
opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U);
|
||||
opts->streaming_maxpacket = clamp(opts->streaming_maxpacket, 1U, 3072U);
|
||||
opts->streaming_maxburst = min(opts->streaming_maxburst, 15U);
|
||||
|
@ -611,7 +616,8 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
opts->streaming_maxpacket);
|
||||
}
|
||||
|
||||
/* Fill in the FS/HS/SS Video Streaming specific descriptors from the
|
||||
/*
|
||||
* Fill in the FS/HS/SS Video Streaming specific descriptors from the
|
||||
* module parameters.
|
||||
*
|
||||
* NOTE: We assume that the user knows what they are doing and won't
|
||||
|
@ -895,7 +901,8 @@ static void uvc_function_unbind(struct usb_configuration *c,
|
|||
|
||||
uvcg_info(f, "%s()\n", __func__);
|
||||
|
||||
/* If we know we're connected via v4l2, then there should be a cleanup
|
||||
/*
|
||||
* If we know we're connected via v4l2, then there should be a cleanup
|
||||
* of the device from userspace either via UVC_EVENT_DISCONNECT or
|
||||
* though the video device removal uevent. Allow some time for the
|
||||
* application to close out before things get deleted.
|
||||
|
@ -912,7 +919,8 @@ static void uvc_function_unbind(struct usb_configuration *c,
|
|||
v4l2_device_unregister(&uvc->v4l2_dev);
|
||||
|
||||
if (uvc->func_connected) {
|
||||
/* Wait for the release to occur to ensure there are no longer any
|
||||
/*
|
||||
* Wait for the release to occur to ensure there are no longer any
|
||||
* pending operations that may cause panics when resources are cleaned
|
||||
* up.
|
||||
*/
|
||||
|
|
|
@ -519,4 +519,19 @@ ssize_t fsg_store_inquiry_string(struct fsg_lun *curlun, const char *buf,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(fsg_store_inquiry_string);
|
||||
|
||||
ssize_t fsg_store_forced_eject(struct fsg_lun *curlun, struct rw_semaphore *filesem,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Forcibly detach the backing file from the LUN
|
||||
* regardless of whether the host has allowed it.
|
||||
*/
|
||||
curlun->prevent_medium_removal = 0;
|
||||
ret = fsg_store_file(curlun, filesem, "", 0);
|
||||
return ret < 0 ? ret : count;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fsg_store_forced_eject);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -219,5 +219,7 @@ ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf,
|
|||
size_t count);
|
||||
ssize_t fsg_store_inquiry_string(struct fsg_lun *curlun, const char *buf,
|
||||
size_t count);
|
||||
ssize_t fsg_store_forced_eject(struct fsg_lun *curlun, struct rw_semaphore *filesem,
|
||||
const char *buf, size_t count);
|
||||
|
||||
#endif /* USB_STORAGE_COMMON_H */
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <linux/etherdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include "u_ether.h"
|
||||
|
||||
|
|
|
@ -44,7 +44,8 @@ static int uvc_queue_setup(struct vb2_queue *vq,
|
|||
{
|
||||
struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
|
||||
struct uvc_video *video = container_of(queue, struct uvc_video, queue);
|
||||
struct usb_composite_dev *cdev = video->uvc->func.config->cdev;
|
||||
unsigned int req_size;
|
||||
unsigned int nreq;
|
||||
|
||||
if (*nbuffers > UVC_MAX_VIDEO_BUFFERS)
|
||||
*nbuffers = UVC_MAX_VIDEO_BUFFERS;
|
||||
|
@ -53,10 +54,16 @@ static int uvc_queue_setup(struct vb2_queue *vq,
|
|||
|
||||
sizes[0] = video->imagesize;
|
||||
|
||||
if (cdev->gadget->speed < USB_SPEED_SUPER)
|
||||
video->uvc_num_requests = 4;
|
||||
else
|
||||
video->uvc_num_requests = 64;
|
||||
req_size = video->ep->maxpacket
|
||||
* max_t(unsigned int, video->ep->maxburst, 1)
|
||||
* (video->ep->mult);
|
||||
|
||||
/* We divide by two, to increase the chance to run
|
||||
* into fewer requests for smaller framesizes.
|
||||
*/
|
||||
nreq = DIV_ROUND_UP(DIV_ROUND_UP(sizes[0], 2), req_size);
|
||||
nreq = clamp(nreq, 4U, 64U);
|
||||
video->uvc_num_requests = nreq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -104,7 +111,8 @@ static void uvc_buffer_queue(struct vb2_buffer *vb)
|
|||
if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) {
|
||||
list_add_tail(&buf->queue, &queue->irqqueue);
|
||||
} else {
|
||||
/* If the device is disconnected return the buffer to userspace
|
||||
/*
|
||||
* If the device is disconnected return the buffer to userspace
|
||||
* directly. The next QBUF call will fail with -ENODEV.
|
||||
*/
|
||||
buf->state = UVC_BUF_STATE_ERROR;
|
||||
|
@ -255,7 +263,8 @@ void uvcg_queue_cancel(struct uvc_video_queue *queue, int disconnect)
|
|||
}
|
||||
queue->buf_used = 0;
|
||||
|
||||
/* This must be protected by the irqlock spinlock to avoid race
|
||||
/*
|
||||
* This must be protected by the irqlock spinlock to avoid race
|
||||
* conditions between uvc_queue_buffer and the disconnection event that
|
||||
* could result in an interruptible wait in uvc_dequeue_buffer. Do not
|
||||
* blindly replace this logic by checking for the UVC_DEV_DISCONNECTED
|
||||
|
|
|
@ -261,7 +261,7 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
|
|||
break;
|
||||
|
||||
default:
|
||||
uvcg_info(&video->uvc->func,
|
||||
uvcg_warn(&video->uvc->func,
|
||||
"VS request completed with status %d.\n",
|
||||
req->status);
|
||||
uvcg_queue_cancel(queue, 0);
|
||||
|
@ -378,7 +378,8 @@ static void uvcg_video_pump(struct work_struct *work)
|
|||
int ret;
|
||||
|
||||
while (video->ep->enabled) {
|
||||
/* Retrieve the first available USB request, protected by the
|
||||
/*
|
||||
* Retrieve the first available USB request, protected by the
|
||||
* request lock.
|
||||
*/
|
||||
spin_lock_irqsave(&video->req_lock, flags);
|
||||
|
@ -391,7 +392,8 @@ static void uvcg_video_pump(struct work_struct *work)
|
|||
list_del(&req->list);
|
||||
spin_unlock_irqrestore(&video->req_lock, flags);
|
||||
|
||||
/* Retrieve the first available video buffer and fill the
|
||||
/*
|
||||
* Retrieve the first available video buffer and fill the
|
||||
* request, protected by the video queue irqlock.
|
||||
*/
|
||||
spin_lock_irqsave(&queue->irqlock, flags);
|
||||
|
@ -403,9 +405,11 @@ static void uvcg_video_pump(struct work_struct *work)
|
|||
|
||||
video->encode(req, video, buf);
|
||||
|
||||
/* With usb3 we have more requests. This will decrease the
|
||||
/*
|
||||
* With usb3 we have more requests. This will decrease the
|
||||
* interrupt load to a quarter but also catches the corner
|
||||
* cases, which needs to be handled */
|
||||
* cases, which needs to be handled.
|
||||
*/
|
||||
if (list_empty(&video->req_free) ||
|
||||
buf->state == UVC_BUF_STATE_DONE ||
|
||||
!(video->req_int_count %
|
||||
|
|
|
@ -362,6 +362,7 @@ ep_io (struct ep_data *epdata, void *buf, unsigned len)
|
|||
spin_unlock_irq (&epdata->dev->lock);
|
||||
|
||||
DBG (epdata->dev, "endpoint gone\n");
|
||||
wait_for_completion(&done);
|
||||
epdata->status = -ENODEV;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -311,7 +311,7 @@ source "drivers/usb/gadget/udc/bdc/Kconfig"
|
|||
|
||||
config USB_AMD5536UDC
|
||||
tristate "AMD5536 UDC"
|
||||
depends on USB_PCI
|
||||
depends on USB_PCI && HAS_DMA
|
||||
select USB_SNP_CORE
|
||||
help
|
||||
The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge.
|
||||
|
@ -463,6 +463,19 @@ config USB_TEGRA_XUDC
|
|||
dynamically linked module called "tegra_xudc" and force all
|
||||
gadget drivers to also be dynamically linked.
|
||||
|
||||
config USB_ASPEED_UDC
|
||||
tristate "Aspeed UDC driver support"
|
||||
depends on ARCH_ASPEED || COMPILE_TEST
|
||||
depends on USB_LIBCOMPOSITE
|
||||
help
|
||||
Enables Aspeed USB2.0 Device Controller driver for AST260x
|
||||
family SoCs. The controller supports 1 control endpoint and
|
||||
4 programmable endpoints.
|
||||
|
||||
Say "y" to link the driver statically, or "m" to build a
|
||||
dynamically linked module called "aspeed_udc" and force all
|
||||
gadget drivers to also be dynamically linked.
|
||||
|
||||
source "drivers/usb/gadget/udc/aspeed-vhub/Kconfig"
|
||||
|
||||
#
|
||||
|
|
|
@ -40,5 +40,6 @@ obj-$(CONFIG_USB_GR_UDC) += gr_udc.o
|
|||
obj-$(CONFIG_USB_GADGET_XILINX) += udc-xilinx.o
|
||||
obj-$(CONFIG_USB_SNP_UDC_PLAT) += snps_udc_plat.o
|
||||
obj-$(CONFIG_USB_ASPEED_VHUB) += aspeed-vhub/
|
||||
obj-$(CONFIG_USB_ASPEED_UDC) += aspeed_udc.o
|
||||
obj-$(CONFIG_USB_BDC_UDC) += bdc/
|
||||
obj-$(CONFIG_USB_MAX3420_UDC) += max3420_udc.o
|
||||
|
|
|
@ -1059,8 +1059,10 @@ static int ast_vhub_init_desc(struct ast_vhub *vhub)
|
|||
/* Initialize vhub String Descriptors. */
|
||||
INIT_LIST_HEAD(&vhub->vhub_str_desc);
|
||||
desc_np = of_get_child_by_name(vhub_np, "vhub-strings");
|
||||
if (desc_np)
|
||||
if (desc_np) {
|
||||
ret = ast_vhub_of_parse_str_desc(vhub, desc_np);
|
||||
of_node_put(desc_np);
|
||||
}
|
||||
else
|
||||
ret = ast_vhub_str_alloc_add(vhub, &ast_vhub_strings);
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -2060,7 +2060,7 @@ static const struct usba_udc_errata at91sam9g45_errata = {
|
|||
.pulse_bias = at91sam9g45_pulse_bias,
|
||||
};
|
||||
|
||||
static const struct usba_ep_config ep_config_sam9[] __initconst = {
|
||||
static const struct usba_ep_config ep_config_sam9[] = {
|
||||
{ .nr_banks = 1 }, /* ep 0 */
|
||||
{ .nr_banks = 2, .can_dma = 1, .can_isoc = 1 }, /* ep 1 */
|
||||
{ .nr_banks = 2, .can_dma = 1, .can_isoc = 1 }, /* ep 2 */
|
||||
|
@ -2070,7 +2070,7 @@ static const struct usba_ep_config ep_config_sam9[] __initconst = {
|
|||
{ .nr_banks = 3, .can_dma = 1, .can_isoc = 1 }, /* ep 6 */
|
||||
};
|
||||
|
||||
static const struct usba_ep_config ep_config_sama5[] __initconst = {
|
||||
static const struct usba_ep_config ep_config_sama5[] = {
|
||||
{ .nr_banks = 1 }, /* ep 0 */
|
||||
{ .nr_banks = 3, .can_dma = 1, .can_isoc = 1 }, /* ep 1 */
|
||||
{ .nr_banks = 3, .can_dma = 1, .can_isoc = 1 }, /* ep 2 */
|
||||
|
@ -2165,6 +2165,8 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
|
|||
|
||||
udc->vbus_pin = devm_gpiod_get_optional(&pdev->dev, "atmel,vbus",
|
||||
GPIOD_IN);
|
||||
if (IS_ERR(udc->vbus_pin))
|
||||
return ERR_CAST(udc->vbus_pin);
|
||||
|
||||
if (fifo_mode == 0) {
|
||||
udc->num_ep = udc_config->num_ep;
|
||||
|
@ -2447,6 +2449,7 @@ static int usba_udc_resume(struct device *dev)
|
|||
static SIMPLE_DEV_PM_OPS(usba_udc_pm_ops, usba_udc_suspend, usba_udc_resume);
|
||||
|
||||
static struct platform_driver udc_driver = {
|
||||
.probe = usba_udc_probe,
|
||||
.remove = usba_udc_remove,
|
||||
.driver = {
|
||||
.name = "atmel_usba_udc",
|
||||
|
@ -2454,8 +2457,7 @@ static struct platform_driver udc_driver = {
|
|||
.of_match_table = atmel_udc_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver_probe(udc_driver, usba_udc_probe);
|
||||
module_platform_driver(udc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Atmel USBA UDC driver");
|
||||
MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
|
||||
|
|
|
@ -307,7 +307,7 @@ int bdc_ep_clear_stall(struct bdc *bdc, int epnum)
|
|||
* his will reset the seq number for non EP0.
|
||||
*/
|
||||
if (epnum != 1) {
|
||||
/* if the endpoint it not stallled */
|
||||
/* if the endpoint it not stalled */
|
||||
if (!(ep->flags & BDC_EP_STALL)) {
|
||||
ret = bdc_ep_set_stall(bdc, epnum);
|
||||
if (ret)
|
||||
|
|
|
@ -1728,13 +1728,14 @@ static int usb_udc_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (udc->driver) {
|
||||
mutex_lock(&udc_lock);
|
||||
if (udc->driver)
|
||||
ret = add_uevent_var(env, "USB_UDC_DRIVER=%s",
|
||||
udc->driver->function);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n");
|
||||
return ret;
|
||||
}
|
||||
mutex_unlock(&udc_lock);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -3691,15 +3691,15 @@ static int tegra_xudc_powerdomain_init(struct tegra_xudc *xudc)
|
|||
int err;
|
||||
|
||||
xudc->genpd_dev_device = dev_pm_domain_attach_by_name(dev, "dev");
|
||||
if (IS_ERR(xudc->genpd_dev_device)) {
|
||||
err = PTR_ERR(xudc->genpd_dev_device);
|
||||
if (IS_ERR_OR_NULL(xudc->genpd_dev_device)) {
|
||||
err = PTR_ERR(xudc->genpd_dev_device) ? : -ENODATA;
|
||||
dev_err(dev, "failed to get device power domain: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
xudc->genpd_dev_ss = dev_pm_domain_attach_by_name(dev, "ss");
|
||||
if (IS_ERR(xudc->genpd_dev_ss)) {
|
||||
err = PTR_ERR(xudc->genpd_dev_ss);
|
||||
if (IS_ERR_OR_NULL(xudc->genpd_dev_ss)) {
|
||||
err = PTR_ERR(xudc->genpd_dev_ss) ? : -ENODATA;
|
||||
dev_err(dev, "failed to get SuperSpeed power domain: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ DECLARE_EVENT_CLASS(udc_log_ep,
|
|||
TP_PROTO(struct usb_ep *ep, int ret),
|
||||
TP_ARGS(ep, ret),
|
||||
TP_STRUCT__entry(
|
||||
__dynamic_array(char, name, UDC_TRACE_STR_MAX)
|
||||
__string(name, ep->name)
|
||||
__field(unsigned, maxpacket)
|
||||
__field(unsigned, maxpacket_limit)
|
||||
__field(unsigned, max_streams)
|
||||
|
@ -152,7 +152,7 @@ DECLARE_EVENT_CLASS(udc_log_ep,
|
|||
__field(int, ret)
|
||||
),
|
||||
TP_fast_assign(
|
||||
snprintf(__get_str(name), UDC_TRACE_STR_MAX, "%s", ep->name);
|
||||
__assign_str(name, ep->name);
|
||||
__entry->maxpacket = ep->maxpacket;
|
||||
__entry->maxpacket_limit = ep->maxpacket_limit;
|
||||
__entry->max_streams = ep->max_streams;
|
||||
|
@ -214,7 +214,7 @@ DECLARE_EVENT_CLASS(udc_log_req,
|
|||
TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret),
|
||||
TP_ARGS(ep, req, ret),
|
||||
TP_STRUCT__entry(
|
||||
__dynamic_array(char, name, UDC_TRACE_STR_MAX)
|
||||
__string(name, ep->name)
|
||||
__field(unsigned, length)
|
||||
__field(unsigned, actual)
|
||||
__field(unsigned, num_sgs)
|
||||
|
@ -228,7 +228,7 @@ DECLARE_EVENT_CLASS(udc_log_req,
|
|||
__field(struct usb_request *, req)
|
||||
),
|
||||
TP_fast_assign(
|
||||
snprintf(__get_str(name), UDC_TRACE_STR_MAX, "%s", ep->name);
|
||||
__assign_str(name, ep->name);
|
||||
__entry->length = req->length;
|
||||
__entry->actual = req->actual;
|
||||
__entry->num_sgs = req->num_sgs;
|
||||
|
|
|
@ -306,6 +306,16 @@ config USB_EHCI_MV
|
|||
Dova, Armada 370 and Armada XP. See "Support for Marvell EBU
|
||||
on-chip EHCI USB controller" for those.
|
||||
|
||||
config USB_OCTEON_HCD
|
||||
tristate "Cavium Networks Octeon USB support"
|
||||
depends on CAVIUM_OCTEON_SOC && USB
|
||||
help
|
||||
This driver supports USB host controller on some Cavium
|
||||
Networks' products in the Octeon family.
|
||||
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called octeon-hcd.
|
||||
|
||||
config USB_CNS3XXX_EHCI
|
||||
bool "Cavium CNS3XXX EHCI Module (DEPRECATED)"
|
||||
depends on ARCH_CNS3XXX || COMPILE_TEST
|
||||
|
|
|
@ -63,6 +63,7 @@ obj-$(CONFIG_USB_OHCI_HCD_S3C2410) += ohci-s3c2410.o
|
|||
obj-$(CONFIG_USB_OHCI_HCD_LPC32XX) += ohci-nxp.o
|
||||
obj-$(CONFIG_USB_OHCI_HCD_PXA27X) += ohci-pxa27x.o
|
||||
obj-$(CONFIG_USB_OHCI_HCD_DAVINCI) += ohci-da8xx.o
|
||||
obj-$(CONFIG_USB_OCTEON_HCD) += octeon-hcd.o
|
||||
|
||||
obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
|
||||
obj-$(CONFIG_USB_FHCI_HCD) += fhci.o
|
||||
|
|
|
@ -370,6 +370,8 @@ static int ehci_platform_probe(struct platform_device *dev)
|
|||
hcd->rsrc_start = res_mem->start;
|
||||
hcd->rsrc_len = resource_size(res_mem);
|
||||
|
||||
hcd->tpl_support = of_usb_host_tpl_support(dev->dev.of_node);
|
||||
|
||||
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (err)
|
||||
goto err_power;
|
||||
|
|
|
@ -148,6 +148,7 @@ static int ehci_hcd_ppc_of_probe(struct platform_device *op)
|
|||
} else {
|
||||
ehci->has_amcc_usb23 = 1;
|
||||
}
|
||||
of_node_put(np);
|
||||
}
|
||||
|
||||
if (of_get_property(dn, "big-endian", NULL)) {
|
||||
|
|
|
@ -1162,7 +1162,7 @@ submit_async (
|
|||
* This is done in two parts: first SETUP req for GetDesc is sent then
|
||||
* 15 seconds later, the IN stage for GetDesc starts to req data from dev
|
||||
*
|
||||
* is_setup : i/p arguement decides which of the two stage needs to be
|
||||
* is_setup : i/p argument decides which of the two stage needs to be
|
||||
* performed; TRUE - SETUP and FALSE - IN+STATUS
|
||||
* Returns 0 if success
|
||||
*/
|
||||
|
|
|
@ -312,7 +312,7 @@ static const int hrsl_to_error[] = {
|
|||
|
||||
/*
|
||||
* See https://www.beyondlogic.org/usbnutshell/usb4.shtml#Control for a
|
||||
* reasonable overview of how control transfers use the the IN/OUT
|
||||
* reasonable overview of how control transfers use the IN/OUT
|
||||
* tokens.
|
||||
*/
|
||||
#define MAX3421_HXFR_BULK_IN(ep) (0x00 | (ep)) /* bulk or interrupt */
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
* This file is licenced under the GPL.
|
||||
*/
|
||||
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
@ -55,6 +56,7 @@ struct ohci_at91_priv {
|
|||
bool clocked;
|
||||
bool wakeup; /* Saved wake-up state for resume */
|
||||
struct regmap *sfr_regmap;
|
||||
u32 suspend_smc_id;
|
||||
};
|
||||
/* interface and function clocks; sometimes also an AHB clock */
|
||||
|
||||
|
@ -135,6 +137,19 @@ static void at91_stop_hc(struct platform_device *pdev)
|
|||
|
||||
static void usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *);
|
||||
|
||||
static u32 at91_dt_suspend_smc(struct device *dev)
|
||||
{
|
||||
u32 suspend_smc_id;
|
||||
|
||||
if (!dev->of_node)
|
||||
return 0;
|
||||
|
||||
if (of_property_read_u32(dev->of_node, "microchip,suspend-smc-id", &suspend_smc_id))
|
||||
return 0;
|
||||
|
||||
return suspend_smc_id;
|
||||
}
|
||||
|
||||
static struct regmap *at91_dt_syscon_sfr(void)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
|
@ -215,9 +230,13 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
|
|||
goto err;
|
||||
}
|
||||
|
||||
ohci_at91->sfr_regmap = at91_dt_syscon_sfr();
|
||||
if (!ohci_at91->sfr_regmap)
|
||||
dev_dbg(dev, "failed to find sfr node\n");
|
||||
ohci_at91->suspend_smc_id = at91_dt_suspend_smc(dev);
|
||||
if (!ohci_at91->suspend_smc_id) {
|
||||
dev_dbg(dev, "failed to find sfr suspend smc id, using regmap\n");
|
||||
ohci_at91->sfr_regmap = at91_dt_syscon_sfr();
|
||||
if (!ohci_at91->sfr_regmap)
|
||||
dev_dbg(dev, "failed to find sfr node\n");
|
||||
}
|
||||
|
||||
board = hcd->self.controller->platform_data;
|
||||
ohci = hcd_to_ohci(hcd);
|
||||
|
@ -303,24 +322,30 @@ static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf)
|
|||
return length;
|
||||
}
|
||||
|
||||
static int ohci_at91_port_suspend(struct regmap *regmap, u8 set)
|
||||
static int ohci_at91_port_suspend(struct ohci_at91_priv *ohci_at91, u8 set)
|
||||
{
|
||||
struct regmap *regmap = ohci_at91->sfr_regmap;
|
||||
u32 regval;
|
||||
int ret;
|
||||
|
||||
if (!regmap)
|
||||
return 0;
|
||||
if (ohci_at91->suspend_smc_id) {
|
||||
struct arm_smccc_res res;
|
||||
|
||||
ret = regmap_read(regmap, AT91_SFR_OHCIICR, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
arm_smccc_smc(ohci_at91->suspend_smc_id, set, 0, 0, 0, 0, 0, 0, &res);
|
||||
if (res.a0)
|
||||
return -EINVAL;
|
||||
} else if (regmap) {
|
||||
ret = regmap_read(regmap, AT91_SFR_OHCIICR, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (set)
|
||||
regval |= AT91_OHCIICR_USB_SUSPEND;
|
||||
else
|
||||
regval &= ~AT91_OHCIICR_USB_SUSPEND;
|
||||
if (set)
|
||||
regval |= AT91_OHCIICR_USB_SUSPEND;
|
||||
else
|
||||
regval &= ~AT91_OHCIICR_USB_SUSPEND;
|
||||
|
||||
regmap_write(regmap, AT91_SFR_OHCIICR, regval);
|
||||
regmap_write(regmap, AT91_SFR_OHCIICR, regval);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -357,9 +382,8 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
|
||||
case USB_PORT_FEAT_SUSPEND:
|
||||
dev_dbg(hcd->self.controller, "SetPortFeat: SUSPEND\n");
|
||||
if (valid_port(wIndex) && ohci_at91->sfr_regmap) {
|
||||
ohci_at91_port_suspend(ohci_at91->sfr_regmap,
|
||||
1);
|
||||
if (valid_port(wIndex)) {
|
||||
ohci_at91_port_suspend(ohci_at91, 1);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
@ -400,9 +424,8 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
|
||||
case USB_PORT_FEAT_SUSPEND:
|
||||
dev_dbg(hcd->self.controller, "ClearPortFeature: SUSPEND\n");
|
||||
if (valid_port(wIndex) && ohci_at91->sfr_regmap) {
|
||||
ohci_at91_port_suspend(ohci_at91->sfr_regmap,
|
||||
0);
|
||||
if (valid_port(wIndex)) {
|
||||
ohci_at91_port_suspend(ohci_at91, 0);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
@ -630,10 +653,10 @@ ohci_hcd_at91_drv_suspend(struct device *dev)
|
|||
/* flush the writes */
|
||||
(void) ohci_readl (ohci, &ohci->regs->control);
|
||||
msleep(1);
|
||||
ohci_at91_port_suspend(ohci_at91->sfr_regmap, 1);
|
||||
ohci_at91_port_suspend(ohci_at91, 1);
|
||||
at91_stop_clock(ohci_at91);
|
||||
} else {
|
||||
ohci_at91_port_suspend(ohci_at91->sfr_regmap, 1);
|
||||
ohci_at91_port_suspend(ohci_at91, 1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -645,7 +668,7 @@ ohci_hcd_at91_drv_resume(struct device *dev)
|
|||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
|
||||
|
||||
ohci_at91_port_suspend(ohci_at91->sfr_regmap, 0);
|
||||
ohci_at91_port_suspend(ohci_at91, 0);
|
||||
|
||||
if (ohci_at91->wakeup)
|
||||
disable_irq_wake(hcd->irq);
|
||||
|
|
|
@ -164,6 +164,7 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
isp1301_i2c_client = isp1301_get_client(isp1301_node);
|
||||
of_node_put(isp1301_node);
|
||||
if (!isp1301_i2c_client)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/usb/ohci_pdriver.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <linux/usb/of.h>
|
||||
|
||||
#include "ohci.h"
|
||||
|
||||
|
@ -210,6 +211,8 @@ static int ohci_platform_probe(struct platform_device *dev)
|
|||
hcd->rsrc_start = res_mem->start;
|
||||
hcd->rsrc_len = resource_size(res_mem);
|
||||
|
||||
hcd->tpl_support = of_usb_host_tpl_support(dev->dev.of_node);
|
||||
|
||||
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (err)
|
||||
goto err_power;
|
||||
|
|
|
@ -166,6 +166,7 @@ static int ohci_hcd_ppc_of_probe(struct platform_device *op)
|
|||
release_mem_region(res.start, 0x4);
|
||||
} else
|
||||
pr_debug("%s: cannot get ehci offset from fdt\n", __FILE__);
|
||||
of_node_put(np);
|
||||
}
|
||||
|
||||
irq_dispose_mapping(irq);
|
||||
|
|
|
@ -153,7 +153,7 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev)
|
|||
* fine. This is however not always the case - buffers may be allocated
|
||||
* using kmalloc() - so the usb core needs to be told that it must copy
|
||||
* data into our local memory if the buffers happen to be placed in
|
||||
* regular memory. A non-null hcd->localmem_pool initialized by the
|
||||
* regular memory. A non-null hcd->localmem_pool initialized by
|
||||
* the call to usb_hcd_setup_local_mem() below does just that.
|
||||
*/
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ static int uhci_grlib_init(struct usb_hcd *hcd)
|
|||
|
||||
uhci->rh_numports = uhci_count_ports(hcd);
|
||||
|
||||
/* Set up pointers to to generic functions */
|
||||
/* Set up pointers to generic functions */
|
||||
uhci->reset_hc = uhci_generic_reset_hc;
|
||||
uhci->check_and_reset_hc = uhci_generic_check_and_reset_hc;
|
||||
/* No special actions need to be taken for the functions below */
|
||||
|
|
|
@ -314,7 +314,7 @@ struct uhci_td {
|
|||
*
|
||||
* There's a special skeleton QH for Isochronous QHs which never appears
|
||||
* on the schedule. Isochronous TDs go on the schedule before the
|
||||
* the skeleton QHs. The hardware accesses them directly rather than
|
||||
* skeleton QHs. The hardware accesses them directly rather than
|
||||
* through their QH, which is used only for bookkeeping purposes.
|
||||
* While the UHCI spec doesn't forbid the use of QHs for Isochronous,
|
||||
* it doesn't use them either. And the spec says that queues never
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/pm_wakeirq.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "xhci.h"
|
||||
#include "xhci-mtk.h"
|
||||
|
@ -550,6 +551,12 @@ static int xhci_mtk_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto disable_ldos;
|
||||
|
||||
ret = device_reset_optional(dev);
|
||||
if (ret) {
|
||||
dev_err_probe(dev, ret, "failed to reset controller\n");
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
hcd = usb_create_hcd(driver, dev, dev_name(dev));
|
||||
if (!hcd) {
|
||||
ret = -ENOMEM;
|
||||
|
|
|
@ -120,7 +120,6 @@ static int renesas_fw_verify(const void *fw_data,
|
|||
size_t length)
|
||||
{
|
||||
u16 fw_version_pointer;
|
||||
u16 fw_version;
|
||||
|
||||
/*
|
||||
* The Firmware's Data Format is describe in
|
||||
|
@ -150,9 +149,6 @@ static int renesas_fw_verify(const void *fw_data,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
fw_version = get_unaligned_le16(fw_data + fw_version_pointer);
|
||||
pr_err("got firmware version: %02x.", fw_version);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче