mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-23 20:24:12 +08:00
USB/Thunderbolt updates for 6.11-rc1
Here is the big set of USB and Thunderbolt changes for 6.11-rc1. Nothing earth-shattering in here, just constant forward progress in adding support for new hardware and better debugging functionalities for thunderbolt devices and the subsystem. Included in here are: - thunderbolt debugging update and driver additions - xhci driver updates - typec driver updates - kselftest device driver changes (acked by the relevant maintainers, depended on other changes in this tree.) - cdns3 driver updates - gadget driver updates - MODULE_DESCRIPTION() additions - dwc3 driver updates and fixes All of these have been in linux-next for a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZppaNA8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ylXZwCgrEtIAQw0x6EF7w/iTWVS5UJj9AEAoLCj5UwO WX978uThyUctuYYKbw+8 =Cm7j -----END PGP SIGNATURE----- Merge tag 'usb-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB / Thunderbolt updates from Greg KH: "Here is the big set of USB and Thunderbolt changes for 6.11-rc1. Nothing earth-shattering in here, just constant forward progress in adding support for new hardware and better debugging functionalities for thunderbolt devices and the subsystem. Included in here are: - thunderbolt debugging update and driver additions - xhci driver updates - typec driver updates - kselftest device driver changes (acked by the relevant maintainers, depended on other changes in this tree.) - cdns3 driver updates - gadget driver updates - MODULE_DESCRIPTION() additions - dwc3 driver updates and fixes All of these have been in linux-next for a while with no reported issues" * tag 'usb-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (112 commits) kselftest: devices: Add test to detect device error logs kselftest: Move ksft helper module to common directory kselftest: devices: Move discoverable devices test to subdirectory usb: gadget: f_uac2: fix non-newline-terminated function name USB: uas: Implement the new shutdown callback USB: core: add 'shutdown' callback to usb_driver usb: typec: Drop explicit initialization of struct i2c_device_id::driver_data to 0 usb: dwc3: enable CCI support for AMD-xilinx DWC3 controller usb: dwc2: add support for other Lantiq SoCs usb: gadget: Use u16 types for 16-bit fields usb: gadget: midi2: Fix incorrect default MIDI2 protocol setup usb: dwc3: core: Check all ports when set phy suspend usb: typec: tcpci: add support to set connector orientation dt-bindings: usb: Convert fsl-usb to yaml usb: typec: ucsi: reorder operations in ucsi_run_command() usb: typec: ucsi: extract common code for command handling usb: typec: ucsi: inline ucsi_read_message_in usb: typec: ucsi: rework command execution functions usb: typec: ucsi: split read operation usb: typec: ucsi: simplify command sending API ...
This commit is contained in:
commit
04d17331ca
@ -75,3 +75,13 @@ Description:
|
||||
The default value is 1 (GNU Remote Debug command).
|
||||
Other permissible value is 0 which is for vendor defined debug
|
||||
target.
|
||||
|
||||
What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_poll_interval_ms
|
||||
Date: February 2024
|
||||
Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
|
||||
Description:
|
||||
This attribute adjust the polling interval used to check for
|
||||
DbC events. Unit is milliseconds. Accepted values range from 0
|
||||
up to 5000. The default value is 64 ms.
|
||||
This polling interval is used while DbC is enabled but has no
|
||||
active data transfers.
|
||||
|
@ -7041,6 +7041,9 @@
|
||||
usb-storage.delay_use=
|
||||
[UMS] The delay in seconds before a new device is
|
||||
scanned for Logical Units (default 1).
|
||||
Optionally the delay in milliseconds if the value has
|
||||
suffix with "ms".
|
||||
Example: delay_use=2567ms
|
||||
|
||||
usb-storage.quirks=
|
||||
[UMS] A list of quirks entries to supplement or
|
||||
|
@ -42,8 +42,11 @@ properties:
|
||||
- const: otg
|
||||
- const: wakeup
|
||||
|
||||
dr_mode:
|
||||
enum: [host, otg, peripheral]
|
||||
port:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
This port is used with the 'usb-role-switch' property to connect the
|
||||
cdns3 to type C connector.
|
||||
|
||||
maximum-speed:
|
||||
enum: [super-speed, high-speed, full-speed]
|
||||
@ -70,6 +73,9 @@ properties:
|
||||
description: Enable resetting of PHY if Rx fail is detected
|
||||
type: boolean
|
||||
|
||||
dependencies:
|
||||
port: [ usb-role-switch ]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@ -77,7 +83,10 @@ required:
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
|
||||
additionalProperties: false
|
||||
allOf:
|
||||
- $ref: usb-drd.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
@ -188,7 +188,7 @@ required:
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
95
Documentation/devicetree/bindings/usb/fsl,usb2.yaml
Normal file
95
Documentation/devicetree/bindings/usb/fsl,usb2.yaml
Normal file
@ -0,0 +1,95 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/usb/fsl,usb2.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Freescale SOC USB controllers
|
||||
|
||||
maintainers:
|
||||
- Frank Li <Frank.Li@nxp.com>
|
||||
|
||||
description: |
|
||||
The device node for a USB controller that is part of a Freescale
|
||||
SOC is as described in the document "Open Firmware Recommended
|
||||
Practice: Universal Serial Bus" with the following modifications
|
||||
and additions.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- fsl-usb2-mph
|
||||
- fsl-usb2-dr
|
||||
- items:
|
||||
- enum:
|
||||
- fsl-usb2-dr-v2.2
|
||||
- fsl-usb2-dr-v2.5
|
||||
- const: fsl-usb2-dr
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
phy_type:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
enum: [ulpi, serial, utmi, utmi_wide]
|
||||
|
||||
port0:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Indicates port0 is connected for fsl-usb2-mph compatible controllers.
|
||||
|
||||
port1:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Indicates port1 is connected for "fsl-usb2-mph" compatible controllers.
|
||||
|
||||
fsl,invert-drvvbus:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
for MPC5121 USB0 only. Indicates the
|
||||
port power polarity of internal PHY signal DRVVBUS is inverted.
|
||||
|
||||
fsl,invert-pwr-fault:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
for MPC5121 USB0 only. Indicates
|
||||
the PWR_FAULT signal polarity is inverted.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- phy_type
|
||||
|
||||
allOf:
|
||||
- $ref: usb-drd.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
usb@22000 {
|
||||
compatible = "fsl-usb2-mph";
|
||||
reg = <22000 1000>;
|
||||
interrupts = <27 IRQ_TYPE_EDGE_RISING>;
|
||||
phy_type = "ulpi";
|
||||
port0;
|
||||
port1;
|
||||
};
|
||||
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
usb@23000 {
|
||||
compatible = "fsl-usb2-dr";
|
||||
reg = <23000 1000>;
|
||||
interrupts = <26 IRQ_TYPE_EDGE_RISING>;
|
||||
dr_mode = "otg";
|
||||
phy_type = "ulpi";
|
||||
};
|
@ -1,81 +0,0 @@
|
||||
Freescale SOC USB controllers
|
||||
|
||||
The device node for a USB controller that is part of a Freescale
|
||||
SOC is as described in the document "Open Firmware Recommended
|
||||
Practice : Universal Serial Bus" with the following modifications
|
||||
and additions :
|
||||
|
||||
Required properties :
|
||||
- compatible : Should be "fsl-usb2-mph" for multi port host USB
|
||||
controllers, or "fsl-usb2-dr" for dual role USB controllers
|
||||
or "fsl,mpc5121-usb2-dr" for dual role USB controllers of MPC5121.
|
||||
Wherever applicable, the IP version of the USB controller should
|
||||
also be mentioned (for eg. fsl-usb2-dr-v2.2 for bsc9132).
|
||||
- phy_type : For multi port host USB controllers, should be one of
|
||||
"ulpi", or "serial". For dual role USB controllers, should be
|
||||
one of "ulpi", "utmi", "utmi_wide", or "serial".
|
||||
- reg : Offset and length of the register set for the device
|
||||
- port0 : boolean; if defined, indicates port0 is connected for
|
||||
fsl-usb2-mph compatible controllers. Either this property or
|
||||
"port1" (or both) must be defined for "fsl-usb2-mph" compatible
|
||||
controllers.
|
||||
- port1 : boolean; if defined, indicates port1 is connected for
|
||||
fsl-usb2-mph compatible controllers. Either this property or
|
||||
"port0" (or both) must be defined for "fsl-usb2-mph" compatible
|
||||
controllers.
|
||||
- dr_mode : indicates the working mode for "fsl-usb2-dr" compatible
|
||||
controllers. Can be "host", "peripheral", or "otg". Default to
|
||||
"host" if not defined for backward compatibility.
|
||||
|
||||
Recommended properties :
|
||||
- interrupts : <a b> where a is the interrupt number and b is a
|
||||
field that represents an encoding of the sense and level
|
||||
information for the interrupt. This should be encoded based on
|
||||
the information in section 2) depending on the type of interrupt
|
||||
controller you have.
|
||||
|
||||
Optional properties :
|
||||
- fsl,invert-drvvbus : boolean; for MPC5121 USB0 only. Indicates the
|
||||
port power polarity of internal PHY signal DRVVBUS is inverted.
|
||||
- fsl,invert-pwr-fault : boolean; for MPC5121 USB0 only. Indicates
|
||||
the PWR_FAULT signal polarity is inverted.
|
||||
|
||||
Example multi port host USB controller device node :
|
||||
usb@22000 {
|
||||
compatible = "fsl-usb2-mph";
|
||||
reg = <22000 1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupt-parent = <700>;
|
||||
interrupts = <27 1>;
|
||||
phy_type = "ulpi";
|
||||
port0;
|
||||
port1;
|
||||
};
|
||||
|
||||
Example dual role USB controller device node :
|
||||
usb@23000 {
|
||||
compatible = "fsl-usb2-dr";
|
||||
reg = <23000 1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupt-parent = <700>;
|
||||
interrupts = <26 1>;
|
||||
dr_mode = "otg";
|
||||
phy = "ulpi";
|
||||
};
|
||||
|
||||
Example dual role USB controller device node for MPC5121ADS:
|
||||
|
||||
usb@4000 {
|
||||
compatible = "fsl,mpc5121-usb2-dr";
|
||||
reg = <0x4000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupt-parent = < &ipic >;
|
||||
interrupts = <44 0x8>;
|
||||
dr_mode = "otg";
|
||||
phy_type = "utmi_wide";
|
||||
fsl,invert-drvvbus;
|
||||
fsl,invert-pwr-fault;
|
||||
};
|
@ -9,9 +9,6 @@ title: Genesys Logic USB hub controller
|
||||
maintainers:
|
||||
- Icenowy Zheng <uwu@icenowy.me>
|
||||
|
||||
allOf:
|
||||
- $ref: usb-device.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
@ -27,17 +24,44 @@ properties:
|
||||
|
||||
vdd-supply:
|
||||
description:
|
||||
the regulator that provides 3.3V core power to the hub.
|
||||
The regulator that provides 3.3V or 5.0V core power to the hub.
|
||||
|
||||
peer-hub:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
phandle to the peer hub on the controller.
|
||||
For onboard hub controllers that support USB 3.x and USB 2.0 hubs
|
||||
with shared resets and power supplies, this property is used to identify
|
||||
the hubs with which these are shared.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
allOf:
|
||||
- $ref: usb-device.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- usb5e3,608
|
||||
then:
|
||||
properties:
|
||||
peer-hub: false
|
||||
vdd-supply: false
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- usb5e3,610
|
||||
- usb5e3,620
|
||||
then:
|
||||
properties:
|
||||
peer-hub: true
|
||||
vdd-supply: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
@ -54,3 +78,29 @@ examples:
|
||||
reset-gpios = <&pio 7 2 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
|
||||
- |
|
||||
#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 = "usb5e3,610";
|
||||
reg = <1>;
|
||||
peer-hub = <&hub_3_0>;
|
||||
reset-gpios = <&gpio 20 GPIO_ACTIVE_LOW>;
|
||||
vdd-supply = <&vcc_5v>;
|
||||
};
|
||||
|
||||
/* 3.1 hub on port 4 */
|
||||
hub_3_0: hub@2 {
|
||||
compatible = "usb5e3,620";
|
||||
reg = <2>;
|
||||
peer-hub = <&hub_2_0>;
|
||||
reset-gpios = <&gpio 20 GPIO_ACTIVE_LOW>;
|
||||
vdd-supply = <&vcc_5v>;
|
||||
};
|
||||
};
|
||||
|
@ -22,6 +22,7 @@ properties:
|
||||
- nxp,cbdtu02043
|
||||
- onnn,fsusb43l10x
|
||||
- pericom,pi3usb102
|
||||
- ti,tmuxhs4212
|
||||
- const: gpio-sbu-mux
|
||||
|
||||
enable-gpios:
|
||||
@ -44,13 +45,18 @@ properties:
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- enable-gpios
|
||||
- select-gpios
|
||||
- orientation-switch
|
||||
- port
|
||||
|
||||
allOf:
|
||||
- $ref: usb-switch.yaml#
|
||||
- if:
|
||||
required:
|
||||
- mode-switch
|
||||
then:
|
||||
required:
|
||||
- enable-gpios
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
|
@ -34,6 +34,13 @@ properties:
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
microchip,ext-vbus-drv:
|
||||
description:
|
||||
Some ULPI USB PHYs do not support an internal VBUS supply and driving
|
||||
the CPEN pin requires the configuration of the UPLI_USE__EXTVBUS
|
||||
bit in ULPI_BUSCONTROL.
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -30,6 +30,8 @@ properties:
|
||||
- qcom,sa8775p-dwc3
|
||||
- qcom,sc7180-dwc3
|
||||
- qcom,sc7280-dwc3
|
||||
- qcom,sc8180x-dwc3
|
||||
- qcom,sc8180x-dwc3-mp
|
||||
- qcom,sc8280xp-dwc3
|
||||
- qcom,sc8280xp-dwc3-mp
|
||||
- qcom,sdm660-dwc3
|
||||
@ -334,6 +336,8 @@ allOf:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,qcm2290-dwc3
|
||||
- qcom,sc8180x-dwc3
|
||||
- qcom,sc8180x-dwc3-mp
|
||||
- qcom,sm6115-dwc3
|
||||
- qcom,sm6125-dwc3
|
||||
- qcom,sm8150-dwc3
|
||||
@ -448,6 +452,7 @@ allOf:
|
||||
- qcom,sa8775p-dwc3
|
||||
- qcom,sc7180-dwc3
|
||||
- qcom,sc7280-dwc3
|
||||
- qcom,sc8180x-dwc3
|
||||
- qcom,sc8280xp-dwc3
|
||||
- qcom,sdm670-dwc3
|
||||
- qcom,sdm845-dwc3
|
||||
@ -475,6 +480,30 @@ allOf:
|
||||
- const: dm_hs_phy_irq
|
||||
- const: ss_phy_irq
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,sc8180x-dwc3-mp
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
minItems: 10
|
||||
maxItems: 10
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: pwr_event_1
|
||||
- const: pwr_event_2
|
||||
- const: hs_phy_1
|
||||
- const: hs_phy_2
|
||||
- const: dp_hs_phy_1
|
||||
- const: dm_hs_phy_1
|
||||
- const: dp_hs_phy_2
|
||||
- const: dm_hs_phy_2
|
||||
- const: ss_phy_1
|
||||
- const: ss_phy_2
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -31,6 +31,30 @@
|
||||
enable-active-high;
|
||||
};
|
||||
|
||||
/* USB hub supports both USB 2.0 and USB 3.0 root hub */
|
||||
usb-hub {
|
||||
dr_mode = "host";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
/* 2.0 hub on port 1 */
|
||||
hub_2_0: hub@1 {
|
||||
compatible = "usb5e3,610";
|
||||
reg = <1>;
|
||||
peer-hub = <&hub_3_0>;
|
||||
vdd-supply = <&usb_pwr_en>;
|
||||
};
|
||||
|
||||
/* 3.0 hub on port 4 */
|
||||
hub_3_0: hub@2 {
|
||||
compatible = "usb5e3,620";
|
||||
reg = <2>;
|
||||
peer-hub = <&hub_2_0>;
|
||||
reset-gpios = <&gpio GPIOH_4 GPIO_ACTIVE_LOW>;
|
||||
vdd-supply = <&vcc_5v>;
|
||||
};
|
||||
};
|
||||
|
||||
sound {
|
||||
compatible = "amlogic,axg-sound-card";
|
||||
model = "ODROID-N2";
|
||||
@ -234,18 +258,6 @@
|
||||
"PIN_3", /* GPIOX_17 */
|
||||
"PIN_5", /* GPIOX_18 */
|
||||
"PIN_36"; /* GPIOX_19 */
|
||||
/*
|
||||
* WARNING: The USB Hub on the Odroid-N2 needs a reset signal
|
||||
* to be turned high in order to be detected by the USB Controller
|
||||
* This signal should be handled by a USB specific power sequence
|
||||
* in order to reset the Hub when USB bus is powered down.
|
||||
*/
|
||||
usb-hub-hog {
|
||||
gpio-hog;
|
||||
gpios = <GPIOH_4 GPIO_ACTIVE_HIGH>;
|
||||
output-high;
|
||||
line-name = "usb-hub-reset";
|
||||
};
|
||||
};
|
||||
|
||||
&i2c3 {
|
||||
|
@ -14,11 +14,13 @@
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_data/phy-da8xx-usb.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define PHY_INIT_BITS (CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN)
|
||||
|
||||
struct da8xx_usb_phy {
|
||||
struct device *dev;
|
||||
struct phy_provider *phy_provider;
|
||||
struct phy *usb11_phy;
|
||||
struct phy *usb20_phy;
|
||||
@ -39,6 +41,12 @@ static int da8xx_usb11_phy_power_on(struct phy *phy)
|
||||
regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_USB1SUSPENDM,
|
||||
CFGCHIP2_USB1SUSPENDM);
|
||||
|
||||
/*
|
||||
* USB1.1 can used USB2.0 output clock as reference clock so this is here to prevent USB2.0
|
||||
* from shutting PHY's power when USB1.1 might use it
|
||||
*/
|
||||
pm_runtime_get_sync(d_phy->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -49,6 +57,7 @@ static int da8xx_usb11_phy_power_off(struct phy *phy)
|
||||
regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_USB1SUSPENDM, 0);
|
||||
|
||||
clk_disable_unprepare(d_phy->usb11_clk);
|
||||
pm_runtime_put_sync(d_phy->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -118,6 +127,35 @@ static const struct phy_ops da8xx_usb20_phy_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __maybe_unused da8xx_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct da8xx_usb_phy *d_phy = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(dev, "Suspending ...\n");
|
||||
|
||||
regmap_set_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused da8xx_runtime_resume(struct device *dev)
|
||||
{
|
||||
u32 mask = CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN | CFGCHIP2_PHY_PLLON;
|
||||
struct da8xx_usb_phy *d_phy = dev_get_drvdata(dev);
|
||||
u32 pll_status;
|
||||
|
||||
regmap_update_bits(d_phy->regmap, CFGCHIP(2), mask, CFGCHIP2_PHY_PLLON);
|
||||
|
||||
dev_dbg(dev, "Resuming ...\n");
|
||||
|
||||
return regmap_read_poll_timeout(d_phy->regmap, CFGCHIP(2), pll_status,
|
||||
pll_status & CFGCHIP2_PHYCLKGD, 1000, 500000);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops da8xx_usb_phy_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(da8xx_runtime_suspend, da8xx_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct phy *da8xx_usb_phy_of_xlate(struct device *dev,
|
||||
const struct of_phandle_args *args)
|
||||
{
|
||||
@ -147,6 +185,8 @@ static int da8xx_usb_phy_probe(struct platform_device *pdev)
|
||||
if (!d_phy)
|
||||
return -ENOMEM;
|
||||
|
||||
d_phy->dev = dev;
|
||||
|
||||
if (pdata)
|
||||
d_phy->regmap = pdata->cfgchip;
|
||||
else
|
||||
@ -208,6 +248,14 @@ static int da8xx_usb_phy_probe(struct platform_device *pdev)
|
||||
regmap_write_bits(d_phy->regmap, CFGCHIP(2),
|
||||
PHY_INIT_BITS, PHY_INIT_BITS);
|
||||
|
||||
pm_runtime_set_active(dev);
|
||||
devm_pm_runtime_enable(dev);
|
||||
/*
|
||||
* Prevent runtime pm from being ON by default. Users can enable
|
||||
* it using power/control in sysfs.
|
||||
*/
|
||||
pm_runtime_forbid(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -232,6 +280,7 @@ static struct platform_driver da8xx_usb_phy_driver = {
|
||||
.remove_new = da8xx_usb_phy_remove,
|
||||
.driver = {
|
||||
.name = "da8xx-usb-phy",
|
||||
.pm = &da8xx_usb_phy_pm_ops,
|
||||
.of_match_table = da8xx_usb_phy_ids,
|
||||
},
|
||||
};
|
||||
|
@ -22,20 +22,25 @@ config USB4_DEBUGFS_WRITE
|
||||
bool "Enable write by debugfs to configuration spaces (DANGEROUS)"
|
||||
help
|
||||
Enables writing to device configuration registers through
|
||||
debugfs interface.
|
||||
debugfs interface. You can use tools such as Thunderbolt/USB4
|
||||
debugging tools to access these registers. For more
|
||||
information see:
|
||||
|
||||
https://github.com/intel/tbtools
|
||||
|
||||
Only enable this if you know what you are doing! Never enable
|
||||
this for production systems or distro kernels.
|
||||
|
||||
config USB4_DEBUGFS_MARGINING
|
||||
bool "Expose receiver lane margining operations under USB4 ports (DANGEROUS)"
|
||||
bool "Expose receiver lane margining operations under USB4 ports and retimers (DANGEROUS)"
|
||||
depends on DEBUG_FS
|
||||
depends on USB4_DEBUGFS_WRITE
|
||||
help
|
||||
Enables hardware and software based receiver lane margining support
|
||||
under each USB4 port. Used for electrical quality and robustness
|
||||
validation during manufacturing. Should not be enabled by distro
|
||||
kernels.
|
||||
Enables hardware and software based receiver lane margining
|
||||
support under each USB4 port and retimer, including retimers
|
||||
on the other side of the cable. Used for electrical quality
|
||||
and robustness validation during manufacturing. Should not be
|
||||
enabled by distro kernels.
|
||||
|
||||
config USB4_KUNIT_TEST
|
||||
bool "KUnit tests" if !KUNIT_ALL_TESTS
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -14,7 +14,11 @@
|
||||
#include "sb_regs.h"
|
||||
#include "tb.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB4_DEBUGFS_MARGINING)
|
||||
#define TB_MAX_RETIMER_INDEX 6
|
||||
#else
|
||||
#define TB_MAX_RETIMER_INDEX 2
|
||||
#endif
|
||||
|
||||
/**
|
||||
* tb_retimer_nvm_read() - Read contents of retimer NVM
|
||||
@ -319,6 +323,8 @@ static ssize_t nvm_version_show(struct device *dev,
|
||||
|
||||
if (!rt->nvm)
|
||||
ret = -EAGAIN;
|
||||
else if (rt->no_nvm_upgrade)
|
||||
ret = -EOPNOTSUPP;
|
||||
else
|
||||
ret = sysfs_emit(buf, "%x.%x\n", rt->nvm->major, rt->nvm->minor);
|
||||
|
||||
@ -366,35 +372,29 @@ const struct device_type tb_retimer_type = {
|
||||
.release = tb_retimer_release,
|
||||
};
|
||||
|
||||
static int tb_retimer_add(struct tb_port *port, u8 index, u32 auth_status)
|
||||
static int tb_retimer_add(struct tb_port *port, u8 index, u32 auth_status,
|
||||
bool on_board)
|
||||
{
|
||||
struct tb_retimer *rt;
|
||||
u32 vendor, device;
|
||||
int ret;
|
||||
|
||||
ret = usb4_port_retimer_read(port, index, USB4_SB_VENDOR_ID, &vendor,
|
||||
sizeof(vendor));
|
||||
ret = usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index,
|
||||
USB4_SB_VENDOR_ID, &vendor, sizeof(vendor));
|
||||
if (ret) {
|
||||
if (ret != -ENODEV)
|
||||
tb_port_warn(port, "failed read retimer VendorId: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = usb4_port_retimer_read(port, index, USB4_SB_PRODUCT_ID, &device,
|
||||
sizeof(device));
|
||||
ret = usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index,
|
||||
USB4_SB_PRODUCT_ID, &device, sizeof(device));
|
||||
if (ret) {
|
||||
if (ret != -ENODEV)
|
||||
tb_port_warn(port, "failed read retimer ProductId: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that it supports NVM operations. If not then don't add
|
||||
* the device at all.
|
||||
*/
|
||||
ret = usb4_port_retimer_nvm_sector_size(port, index);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
rt = kzalloc(sizeof(*rt), GFP_KERNEL);
|
||||
if (!rt)
|
||||
@ -407,6 +407,13 @@ static int tb_retimer_add(struct tb_port *port, u8 index, u32 auth_status)
|
||||
rt->port = port;
|
||||
rt->tb = port->sw->tb;
|
||||
|
||||
/*
|
||||
* Only support NVM upgrade for on-board retimers. The retimers
|
||||
* on the other side of the connection.
|
||||
*/
|
||||
if (!on_board || usb4_port_retimer_nvm_sector_size(port, index) <= 0)
|
||||
rt->no_nvm_upgrade = true;
|
||||
|
||||
rt->dev.parent = &port->usb4->dev;
|
||||
rt->dev.bus = &tb_bus_type;
|
||||
rt->dev.type = &tb_retimer_type;
|
||||
@ -437,12 +444,14 @@ static int tb_retimer_add(struct tb_port *port, u8 index, u32 auth_status)
|
||||
pm_runtime_mark_last_busy(&rt->dev);
|
||||
pm_runtime_use_autosuspend(&rt->dev);
|
||||
|
||||
tb_retimer_debugfs_init(rt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tb_retimer_remove(struct tb_retimer *rt)
|
||||
{
|
||||
dev_info(&rt->dev, "retimer disconnected\n");
|
||||
tb_retimer_debugfs_remove(rt);
|
||||
tb_nvm_free(rt->nvm);
|
||||
device_unregister(&rt->dev);
|
||||
}
|
||||
@ -485,7 +494,7 @@ static struct tb_retimer *tb_port_find_retimer(struct tb_port *port, u8 index)
|
||||
int tb_retimer_scan(struct tb_port *port, bool add)
|
||||
{
|
||||
u32 status[TB_MAX_RETIMER_INDEX + 1] = {};
|
||||
int ret, i, last_idx = 0;
|
||||
int ret, i, max, last_idx = 0;
|
||||
|
||||
/*
|
||||
* Send broadcast RT to make sure retimer indices facing this
|
||||
@ -520,26 +529,28 @@ int tb_retimer_scan(struct tb_port *port, bool add)
|
||||
break;
|
||||
}
|
||||
|
||||
tb_retimer_unset_inbound_sbtx(port);
|
||||
|
||||
if (!last_idx)
|
||||
return 0;
|
||||
|
||||
/* Add on-board retimers if they do not exist already */
|
||||
max = i;
|
||||
ret = 0;
|
||||
for (i = 1; i <= last_idx; i++) {
|
||||
|
||||
/* Add retimers if they do not exist already */
|
||||
for (i = 1; i <= max; i++) {
|
||||
struct tb_retimer *rt;
|
||||
|
||||
/* Skip cable retimers */
|
||||
if (usb4_port_retimer_is_cable(port, i))
|
||||
continue;
|
||||
|
||||
rt = tb_port_find_retimer(port, i);
|
||||
if (rt) {
|
||||
put_device(&rt->dev);
|
||||
} else if (add) {
|
||||
ret = tb_retimer_add(port, i, status[i]);
|
||||
ret = tb_retimer_add(port, i, status[i], i <= last_idx);
|
||||
if (ret && ret != -EOPNOTSUPP)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tb_retimer_unset_inbound_sbtx(port);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,10 @@
|
||||
|
||||
#define USB4_SB_VENDOR_ID 0x00
|
||||
#define USB4_SB_PRODUCT_ID 0x01
|
||||
#define USB4_SB_FW_VERSION 0x02
|
||||
#define USB4_SB_DEBUG_CONF 0x05
|
||||
#define USB4_SB_DEBUG 0x06
|
||||
#define USB4_SB_LRD_TUNING 0x07
|
||||
#define USB4_SB_OPCODE 0x08
|
||||
|
||||
enum usb4_sb_opcode {
|
||||
@ -22,6 +26,7 @@ enum usb4_sb_opcode {
|
||||
USB4_SB_OPCODE_SET_INBOUND_SBTX = 0x5055534c, /* "LSUP" */
|
||||
USB4_SB_OPCODE_UNSET_INBOUND_SBTX = 0x50555355, /* "USUP" */
|
||||
USB4_SB_OPCODE_QUERY_LAST_RETIMER = 0x5453414c, /* "LAST" */
|
||||
USB4_SB_OPCODE_QUERY_CABLE_RETIMER = 0x524c4243, /* "CBLR" */
|
||||
USB4_SB_OPCODE_GET_NVM_SECTOR_SIZE = 0x53534e47, /* "GNSS" */
|
||||
USB4_SB_OPCODE_NVM_SET_OFFSET = 0x53504f42, /* "BOPS" */
|
||||
USB4_SB_OPCODE_NVM_BLOCK_WRITE = 0x574b4c42, /* "BLKW" */
|
||||
@ -35,6 +40,10 @@ enum usb4_sb_opcode {
|
||||
|
||||
#define USB4_SB_METADATA 0x09
|
||||
#define USB4_SB_METADATA_NVM_AUTH_WRITE_MASK GENMASK(5, 0)
|
||||
#define USB4_SB_LINK_CONF 0x0c
|
||||
#define USB4_SB_GEN23_TXFFE 0x0d
|
||||
#define USB4_SB_GEN4_TXFFE 0x0e
|
||||
#define USB4_SB_VERSION 0x0f
|
||||
#define USB4_SB_DATA 0x12
|
||||
|
||||
/* USB4_SB_OPCODE_READ_LANE_MARGINING_CAP */
|
||||
@ -42,30 +51,21 @@ enum usb4_sb_opcode {
|
||||
#define USB4_MARGIN_CAP_0_MODES_SW BIT(1)
|
||||
#define USB4_MARGIN_CAP_0_2_LANES BIT(2)
|
||||
#define USB4_MARGIN_CAP_0_VOLTAGE_INDP_MASK GENMASK(4, 3)
|
||||
#define USB4_MARGIN_CAP_0_VOLTAGE_INDP_SHIFT 3
|
||||
#define USB4_MARGIN_CAP_0_VOLTAGE_MIN 0x0
|
||||
#define USB4_MARGIN_CAP_0_VOLTAGE_HL 0x1
|
||||
#define USB4_MARGIN_CAP_0_VOLTAGE_BOTH 0x2
|
||||
#define USB4_MARGIN_CAP_0_TIME BIT(5)
|
||||
#define USB4_MARGIN_CAP_0_VOLTAGE_STEPS_MASK GENMASK(12, 6)
|
||||
#define USB4_MARGIN_CAP_0_VOLTAGE_STEPS_SHIFT 6
|
||||
#define USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_MASK GENMASK(18, 13)
|
||||
#define USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_SHIFT 13
|
||||
#define USB4_MARGIN_CAP_1_TIME_DESTR BIT(8)
|
||||
#define USB4_MARGIN_CAP_1_TIME_INDP_MASK GENMASK(10, 9)
|
||||
#define USB4_MARGIN_CAP_1_TIME_INDP_SHIFT 9
|
||||
#define USB4_MARGIN_CAP_1_TIME_MIN 0x0
|
||||
#define USB4_MARGIN_CAP_1_TIME_LR 0x1
|
||||
#define USB4_MARGIN_CAP_1_TIME_BOTH 0x2
|
||||
#define USB4_MARGIN_CAP_1_TIME_STEPS_MASK GENMASK(15, 11)
|
||||
#define USB4_MARGIN_CAP_1_TIME_STEPS_SHIFT 11
|
||||
#define USB4_MARGIN_CAP_1_TIME_OFFSET_MASK GENMASK(20, 16)
|
||||
#define USB4_MARGIN_CAP_1_TIME_OFFSET_SHIFT 16
|
||||
#define USB4_MARGIN_CAP_1_MIN_BER_MASK GENMASK(25, 21)
|
||||
#define USB4_MARGIN_CAP_1_MIN_BER_SHIFT 21
|
||||
#define USB4_MARGIN_CAP_1_MAX_BER_MASK GENMASK(30, 26)
|
||||
#define USB4_MARGIN_CAP_1_MAX_BER_SHIFT 26
|
||||
#define USB4_MARGIN_CAP_1_MAX_BER_SHIFT 26
|
||||
|
||||
/* USB4_SB_OPCODE_RUN_HW_LANE_MARGINING */
|
||||
#define USB4_MARGIN_HW_TIME BIT(3)
|
||||
|
@ -329,6 +329,7 @@ struct usb4_port {
|
||||
* @nvm: Pointer to the NVM if the retimer has one (%NULL otherwise)
|
||||
* @no_nvm_upgrade: Prevent NVM upgrade of this retimer
|
||||
* @auth_status: Status of last NVM authentication
|
||||
* @margining: Pointer to margining structure if enabled
|
||||
*/
|
||||
struct tb_retimer {
|
||||
struct device dev;
|
||||
@ -340,6 +341,9 @@ struct tb_retimer {
|
||||
struct tb_nvm *nvm;
|
||||
bool no_nvm_upgrade;
|
||||
u32 auth_status;
|
||||
#ifdef CONFIG_USB4_DEBUGFS_MARGINING
|
||||
struct tb_margining *margining;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1327,26 +1331,43 @@ int usb4_port_router_offline(struct tb_port *port);
|
||||
int usb4_port_router_online(struct tb_port *port);
|
||||
int usb4_port_enumerate_retimers(struct tb_port *port);
|
||||
bool usb4_port_clx_supported(struct tb_port *port);
|
||||
int usb4_port_margining_caps(struct tb_port *port, u32 *caps);
|
||||
|
||||
bool usb4_port_asym_supported(struct tb_port *port);
|
||||
int usb4_port_asym_set_link_width(struct tb_port *port, enum tb_link_width width);
|
||||
int usb4_port_asym_start(struct tb_port *port);
|
||||
|
||||
int usb4_port_hw_margin(struct tb_port *port, unsigned int lanes,
|
||||
unsigned int ber_level, bool timing, bool right_high,
|
||||
u32 *results);
|
||||
int usb4_port_sw_margin(struct tb_port *port, unsigned int lanes, bool timing,
|
||||
/**
|
||||
* enum tb_sb_target - Sideband transaction target
|
||||
* @USB4_SB_TARGET_ROUTER: Target is the router itself
|
||||
* @USB4_SB_TARGET_PARTNER: Target is partner
|
||||
* @USB4_SB_TARGET_RETIMER: Target is retimer
|
||||
*/
|
||||
enum usb4_sb_target {
|
||||
USB4_SB_TARGET_ROUTER,
|
||||
USB4_SB_TARGET_PARTNER,
|
||||
USB4_SB_TARGET_RETIMER,
|
||||
};
|
||||
|
||||
int usb4_port_sb_read(struct tb_port *port, enum usb4_sb_target target, u8 index,
|
||||
u8 reg, void *buf, u8 size);
|
||||
int usb4_port_sb_write(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, u8 reg, const void *buf, u8 size);
|
||||
|
||||
int usb4_port_margining_caps(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, u32 *caps);
|
||||
int usb4_port_hw_margin(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, unsigned int lanes, unsigned int ber_level,
|
||||
bool timing, bool right_high, u32 *results);
|
||||
int usb4_port_sw_margin(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, unsigned int lanes, bool timing,
|
||||
bool right_high, u32 counter);
|
||||
int usb4_port_sw_margin_errors(struct tb_port *port, u32 *errors);
|
||||
int usb4_port_sw_margin_errors(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, u32 *errors);
|
||||
|
||||
int usb4_port_retimer_set_inbound_sbtx(struct tb_port *port, u8 index);
|
||||
int usb4_port_retimer_unset_inbound_sbtx(struct tb_port *port, u8 index);
|
||||
int usb4_port_retimer_read(struct tb_port *port, u8 index, u8 reg, void *buf,
|
||||
u8 size);
|
||||
int usb4_port_retimer_write(struct tb_port *port, u8 index, u8 reg,
|
||||
const void *buf, u8 size);
|
||||
int usb4_port_retimer_is_last(struct tb_port *port, u8 index);
|
||||
int usb4_port_retimer_is_cable(struct tb_port *port, u8 index);
|
||||
int usb4_port_retimer_nvm_sector_size(struct tb_port *port, u8 index);
|
||||
int usb4_port_retimer_nvm_set_offset(struct tb_port *port, u8 index,
|
||||
unsigned int address);
|
||||
@ -1445,6 +1466,8 @@ void tb_xdomain_debugfs_init(struct tb_xdomain *xd);
|
||||
void tb_xdomain_debugfs_remove(struct tb_xdomain *xd);
|
||||
void tb_service_debugfs_init(struct tb_service *svc);
|
||||
void tb_service_debugfs_remove(struct tb_service *svc);
|
||||
void tb_retimer_debugfs_init(struct tb_retimer *rt);
|
||||
void tb_retimer_debugfs_remove(struct tb_retimer *rt);
|
||||
#else
|
||||
static inline void tb_debugfs_init(void) { }
|
||||
static inline void tb_debugfs_exit(void) { }
|
||||
@ -1454,6 +1477,8 @@ static inline void tb_xdomain_debugfs_init(struct tb_xdomain *xd) { }
|
||||
static inline void tb_xdomain_debugfs_remove(struct tb_xdomain *xd) { }
|
||||
static inline void tb_service_debugfs_init(struct tb_service *svc) { }
|
||||
static inline void tb_service_debugfs_remove(struct tb_service *svc) { }
|
||||
static inline void tb_retimer_debugfs_init(struct tb_retimer *rt) { }
|
||||
static inline void tb_retimer_debugfs_remove(struct tb_retimer *rt) { }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -17,12 +17,6 @@
|
||||
#define USB4_DATA_RETRIES 3
|
||||
#define USB4_DATA_DWORDS 16
|
||||
|
||||
enum usb4_sb_target {
|
||||
USB4_SB_TARGET_ROUTER,
|
||||
USB4_SB_TARGET_PARTNER,
|
||||
USB4_SB_TARGET_RETIMER,
|
||||
};
|
||||
|
||||
#define USB4_NVM_READ_OFFSET_MASK GENMASK(23, 2)
|
||||
#define USB4_NVM_READ_OFFSET_SHIFT 2
|
||||
#define USB4_NVM_READ_LENGTH_MASK GENMASK(27, 24)
|
||||
@ -1289,8 +1283,20 @@ static int usb4_port_write_data(struct tb_port *port, const void *data,
|
||||
dwords);
|
||||
}
|
||||
|
||||
static int usb4_port_sb_read(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, u8 reg, void *buf, u8 size)
|
||||
/**
|
||||
* usb4_port_sb_read() - Read from sideband register
|
||||
* @port: USB4 port to read
|
||||
* @target: Sideband target
|
||||
* @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER
|
||||
* @reg: Sideband register index
|
||||
* @buf: Buffer where the sideband data is copied
|
||||
* @size: Size of @buf
|
||||
*
|
||||
* Reads data from sideband register @reg and copies it into @buf.
|
||||
* Returns %0 in case of success and negative errno in case of failure.
|
||||
*/
|
||||
int usb4_port_sb_read(struct tb_port *port, enum usb4_sb_target target, u8 index,
|
||||
u8 reg, void *buf, u8 size)
|
||||
{
|
||||
size_t dwords = DIV_ROUND_UP(size, 4);
|
||||
int ret;
|
||||
@ -1329,8 +1335,20 @@ static int usb4_port_sb_read(struct tb_port *port, enum usb4_sb_target target,
|
||||
return buf ? usb4_port_read_data(port, buf, dwords) : 0;
|
||||
}
|
||||
|
||||
static int usb4_port_sb_write(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, u8 reg, const void *buf, u8 size)
|
||||
/**
|
||||
* usb4_port_sb_write() - Write to sideband register
|
||||
* @port: USB4 port to write
|
||||
* @target: Sideband target
|
||||
* @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER
|
||||
* @reg: Sideband register index
|
||||
* @buf: Data to write
|
||||
* @size: Size of @buf
|
||||
*
|
||||
* Writes @buf to sideband register @reg. Returns %0 in case of success
|
||||
* and negative errno in case of failure.
|
||||
*/
|
||||
int usb4_port_sb_write(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, u8 reg, const void *buf, u8 size)
|
||||
{
|
||||
size_t dwords = DIV_ROUND_UP(size, 4);
|
||||
int ret;
|
||||
@ -1610,26 +1628,31 @@ int usb4_port_asym_start(struct tb_port *port)
|
||||
/**
|
||||
* usb4_port_margining_caps() - Read USB4 port marginig capabilities
|
||||
* @port: USB4 port
|
||||
* @target: Sideband target
|
||||
* @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER
|
||||
* @caps: Array with at least two elements to hold the results
|
||||
*
|
||||
* Reads the USB4 port lane margining capabilities into @caps.
|
||||
*/
|
||||
int usb4_port_margining_caps(struct tb_port *port, u32 *caps)
|
||||
int usb4_port_margining_caps(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, u32 *caps)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0,
|
||||
ret = usb4_port_sb_op(port, target, index,
|
||||
USB4_SB_OPCODE_READ_LANE_MARGINING_CAP, 500);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return usb4_port_sb_read(port, USB4_SB_TARGET_ROUTER, 0,
|
||||
USB4_SB_DATA, caps, sizeof(*caps) * 2);
|
||||
return usb4_port_sb_read(port, target, index, USB4_SB_DATA, caps,
|
||||
sizeof(*caps) * 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb4_port_hw_margin() - Run hardware lane margining on port
|
||||
* @port: USB4 port
|
||||
* @target: Sideband target
|
||||
* @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER
|
||||
* @lanes: Which lanes to run (must match the port capabilities). Can be
|
||||
* %0, %1 or %7.
|
||||
* @ber_level: BER level contour value
|
||||
@ -1640,9 +1663,9 @@ int usb4_port_margining_caps(struct tb_port *port, u32 *caps)
|
||||
* Runs hardware lane margining on USB4 port and returns the result in
|
||||
* @results.
|
||||
*/
|
||||
int usb4_port_hw_margin(struct tb_port *port, unsigned int lanes,
|
||||
unsigned int ber_level, bool timing, bool right_high,
|
||||
u32 *results)
|
||||
int usb4_port_hw_margin(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, unsigned int lanes, unsigned int ber_level,
|
||||
bool timing, bool right_high, u32 *results)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
@ -1656,23 +1679,25 @@ int usb4_port_hw_margin(struct tb_port *port, unsigned int lanes,
|
||||
val |= (ber_level << USB4_MARGIN_HW_BER_SHIFT) &
|
||||
USB4_MARGIN_HW_BER_MASK;
|
||||
|
||||
ret = usb4_port_sb_write(port, USB4_SB_TARGET_ROUTER, 0,
|
||||
USB4_SB_METADATA, &val, sizeof(val));
|
||||
ret = usb4_port_sb_write(port, target, index, USB4_SB_METADATA, &val,
|
||||
sizeof(val));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0,
|
||||
ret = usb4_port_sb_op(port, target, index,
|
||||
USB4_SB_OPCODE_RUN_HW_LANE_MARGINING, 2500);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return usb4_port_sb_read(port, USB4_SB_TARGET_ROUTER, 0,
|
||||
USB4_SB_DATA, results, sizeof(*results) * 2);
|
||||
return usb4_port_sb_read(port, target, index, USB4_SB_DATA, results,
|
||||
sizeof(*results) * 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb4_port_sw_margin() - Run software lane margining on port
|
||||
* @port: USB4 port
|
||||
* @target: Sideband target
|
||||
* @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER
|
||||
* @lanes: Which lanes to run (must match the port capabilities). Can be
|
||||
* %0, %1 or %7.
|
||||
* @timing: Perform timing margining instead of voltage
|
||||
@ -1683,7 +1708,8 @@ int usb4_port_hw_margin(struct tb_port *port, unsigned int lanes,
|
||||
* counters by calling usb4_port_sw_margin_errors(). Returns %0 in
|
||||
* success and negative errno otherwise.
|
||||
*/
|
||||
int usb4_port_sw_margin(struct tb_port *port, unsigned int lanes, bool timing,
|
||||
int usb4_port_sw_margin(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, unsigned int lanes, bool timing,
|
||||
bool right_high, u32 counter)
|
||||
{
|
||||
u32 val;
|
||||
@ -1697,34 +1723,37 @@ int usb4_port_sw_margin(struct tb_port *port, unsigned int lanes, bool timing,
|
||||
val |= (counter << USB4_MARGIN_SW_COUNTER_SHIFT) &
|
||||
USB4_MARGIN_SW_COUNTER_MASK;
|
||||
|
||||
ret = usb4_port_sb_write(port, USB4_SB_TARGET_ROUTER, 0,
|
||||
USB4_SB_METADATA, &val, sizeof(val));
|
||||
ret = usb4_port_sb_write(port, target, index, USB4_SB_METADATA, &val,
|
||||
sizeof(val));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0,
|
||||
return usb4_port_sb_op(port, target, index,
|
||||
USB4_SB_OPCODE_RUN_SW_LANE_MARGINING, 2500);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb4_port_sw_margin_errors() - Read the software margining error counters
|
||||
* @port: USB4 port
|
||||
* @target: Sideband target
|
||||
* @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER
|
||||
* @errors: Error metadata is copied here.
|
||||
*
|
||||
* This reads back the software margining error counters from the port.
|
||||
* Returns %0 in success and negative errno otherwise.
|
||||
*/
|
||||
int usb4_port_sw_margin_errors(struct tb_port *port, u32 *errors)
|
||||
int usb4_port_sw_margin_errors(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, u32 *errors)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0,
|
||||
ret = usb4_port_sb_op(port, target, index,
|
||||
USB4_SB_OPCODE_READ_SW_MARGIN_ERR, 150);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return usb4_port_sb_read(port, USB4_SB_TARGET_ROUTER, 0,
|
||||
USB4_SB_METADATA, errors, sizeof(*errors));
|
||||
return usb4_port_sb_read(port, target, index, USB4_SB_METADATA, errors,
|
||||
sizeof(*errors));
|
||||
}
|
||||
|
||||
static inline int usb4_port_retimer_op(struct tb_port *port, u8 index,
|
||||
@ -1776,47 +1805,6 @@ int usb4_port_retimer_unset_inbound_sbtx(struct tb_port *port, u8 index)
|
||||
USB4_SB_OPCODE_UNSET_INBOUND_SBTX, 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb4_port_retimer_read() - Read from retimer sideband registers
|
||||
* @port: USB4 port
|
||||
* @index: Retimer index
|
||||
* @reg: Sideband register to read
|
||||
* @buf: Data from @reg is stored here
|
||||
* @size: Number of bytes to read
|
||||
*
|
||||
* Function reads retimer sideband registers starting from @reg. The
|
||||
* retimer is connected to @port at @index. Returns %0 in case of
|
||||
* success, and read data is copied to @buf. If there is no retimer
|
||||
* present at given @index returns %-ENODEV. In any other failure
|
||||
* returns negative errno.
|
||||
*/
|
||||
int usb4_port_retimer_read(struct tb_port *port, u8 index, u8 reg, void *buf,
|
||||
u8 size)
|
||||
{
|
||||
return usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index, reg, buf,
|
||||
size);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb4_port_retimer_write() - Write to retimer sideband registers
|
||||
* @port: USB4 port
|
||||
* @index: Retimer index
|
||||
* @reg: Sideband register to write
|
||||
* @buf: Data that is written starting from @reg
|
||||
* @size: Number of bytes to write
|
||||
*
|
||||
* Writes retimer sideband registers starting from @reg. The retimer is
|
||||
* connected to @port at @index. Returns %0 in case of success. If there
|
||||
* is no retimer present at given @index returns %-ENODEV. In any other
|
||||
* failure returns negative errno.
|
||||
*/
|
||||
int usb4_port_retimer_write(struct tb_port *port, u8 index, u8 reg,
|
||||
const void *buf, u8 size)
|
||||
{
|
||||
return usb4_port_sb_write(port, USB4_SB_TARGET_RETIMER, index, reg, buf,
|
||||
size);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb4_port_retimer_is_last() - Is the retimer last on-board retimer
|
||||
* @port: USB4 port
|
||||
@ -1837,8 +1825,32 @@ int usb4_port_retimer_is_last(struct tb_port *port, u8 index)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = usb4_port_retimer_read(port, index, USB4_SB_METADATA, &metadata,
|
||||
sizeof(metadata));
|
||||
ret = usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index,
|
||||
USB4_SB_METADATA, &metadata, sizeof(metadata));
|
||||
return ret ? ret : metadata & 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* usb4_port_retimer_is_cable() - Is the retimer cable retimer
|
||||
* @port: USB4 port
|
||||
* @index: Retimer index
|
||||
*
|
||||
* If the retimer at @index is last cable retimer this function returns
|
||||
* %1 and %0 if it is on-board retimer. In case a retimer is not present
|
||||
* at @index returns %-ENODEV. Otherwise returns negative errno.
|
||||
*/
|
||||
int usb4_port_retimer_is_cable(struct tb_port *port, u8 index)
|
||||
{
|
||||
u32 metadata;
|
||||
int ret;
|
||||
|
||||
ret = usb4_port_retimer_op(port, index, USB4_SB_OPCODE_QUERY_CABLE_RETIMER,
|
||||
500);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index,
|
||||
USB4_SB_METADATA, &metadata, sizeof(metadata));
|
||||
return ret ? ret : metadata & 1;
|
||||
}
|
||||
|
||||
@ -1863,8 +1875,8 @@ int usb4_port_retimer_nvm_sector_size(struct tb_port *port, u8 index)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = usb4_port_retimer_read(port, index, USB4_SB_METADATA, &metadata,
|
||||
sizeof(metadata));
|
||||
ret = usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index,
|
||||
USB4_SB_METADATA, &metadata, sizeof(metadata));
|
||||
return ret ? ret : metadata & USB4_NVM_SECTOR_SIZE_MASK;
|
||||
}
|
||||
|
||||
@ -1889,8 +1901,8 @@ int usb4_port_retimer_nvm_set_offset(struct tb_port *port, u8 index,
|
||||
metadata = (dwaddress << USB4_NVM_SET_OFFSET_SHIFT) &
|
||||
USB4_NVM_SET_OFFSET_MASK;
|
||||
|
||||
ret = usb4_port_retimer_write(port, index, USB4_SB_METADATA, &metadata,
|
||||
sizeof(metadata));
|
||||
ret = usb4_port_sb_write(port, USB4_SB_TARGET_RETIMER, index,
|
||||
USB4_SB_METADATA, &metadata, sizeof(metadata));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1912,8 +1924,8 @@ static int usb4_port_retimer_nvm_write_next_block(void *data,
|
||||
u8 index = info->index;
|
||||
int ret;
|
||||
|
||||
ret = usb4_port_retimer_write(port, index, USB4_SB_DATA,
|
||||
buf, dwords * 4);
|
||||
ret = usb4_port_sb_write(port, USB4_SB_TARGET_RETIMER, index,
|
||||
USB4_SB_DATA, buf, dwords * 4);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1992,8 +2004,8 @@ int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index,
|
||||
u32 metadata, val;
|
||||
int ret;
|
||||
|
||||
ret = usb4_port_retimer_read(port, index, USB4_SB_OPCODE, &val,
|
||||
sizeof(val));
|
||||
ret = usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index,
|
||||
USB4_SB_OPCODE, &val, sizeof(val));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -2004,8 +2016,9 @@ int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index,
|
||||
return 0;
|
||||
|
||||
case -EAGAIN:
|
||||
ret = usb4_port_retimer_read(port, index, USB4_SB_METADATA,
|
||||
&metadata, sizeof(metadata));
|
||||
ret = usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index,
|
||||
USB4_SB_METADATA, &metadata,
|
||||
sizeof(metadata));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -2030,8 +2043,8 @@ static int usb4_port_retimer_nvm_read_block(void *data, unsigned int dwaddress,
|
||||
if (dwords < USB4_DATA_DWORDS)
|
||||
metadata |= dwords << USB4_NVM_READ_LENGTH_SHIFT;
|
||||
|
||||
ret = usb4_port_retimer_write(port, index, USB4_SB_METADATA, &metadata,
|
||||
sizeof(metadata));
|
||||
ret = usb4_port_sb_write(port, USB4_SB_TARGET_RETIMER, index,
|
||||
USB4_SB_METADATA, &metadata, sizeof(metadata));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -2039,8 +2052,8 @@ static int usb4_port_retimer_nvm_read_block(void *data, unsigned int dwaddress,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return usb4_port_retimer_read(port, index, USB4_SB_DATA, buf,
|
||||
dwords * 4);
|
||||
return usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index,
|
||||
USB4_SB_DATA, buf, dwords * 4);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
#include "core.h"
|
||||
|
||||
/* USB Wrapper register offsets */
|
||||
#define USBSS_PID 0x0
|
||||
@ -85,6 +86,18 @@ static inline void cdns_ti_writel(struct cdns_ti *data, u32 offset, u32 value)
|
||||
writel(value, data->usbss + offset);
|
||||
}
|
||||
|
||||
static struct cdns3_platform_data cdns_ti_pdata = {
|
||||
.quirks = CDNS3_DRD_SUSPEND_RESIDENCY_ENABLE, /* Errata i2409 */
|
||||
};
|
||||
|
||||
static const struct of_dev_auxdata cdns_ti_auxdata[] = {
|
||||
{
|
||||
.compatible = "cdns,usb3",
|
||||
.platform_data = &cdns_ti_pdata,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
static int cdns_ti_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -176,7 +189,7 @@ static int cdns_ti_probe(struct platform_device *pdev)
|
||||
reg |= USBSS_W1_PWRUP_RST;
|
||||
cdns_ti_writel(data, USBSS_W1, reg);
|
||||
|
||||
error = of_platform_populate(node, NULL, NULL, dev);
|
||||
error = of_platform_populate(node, NULL, cdns_ti_auxdata, dev);
|
||||
if (error) {
|
||||
dev_err(dev, "failed to create children: %d\n", error);
|
||||
goto err;
|
||||
|
@ -44,6 +44,7 @@ struct cdns3_platform_data {
|
||||
bool suspend, bool wakeup);
|
||||
unsigned long quirks;
|
||||
#define CDNS3_DEFAULT_PM_RUNTIME_ALLOW BIT(0)
|
||||
#define CDNS3_DRD_SUSPEND_RESIDENCY_ENABLE BIT(1)
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -389,7 +389,7 @@ static irqreturn_t cdns_drd_irq(int irq, void *data)
|
||||
int cdns_drd_init(struct cdns *cdns)
|
||||
{
|
||||
void __iomem *regs;
|
||||
u32 state;
|
||||
u32 state, reg;
|
||||
int ret;
|
||||
|
||||
regs = devm_ioremap_resource(cdns->dev, &cdns->otg_res);
|
||||
@ -433,6 +433,14 @@ int cdns_drd_init(struct cdns *cdns)
|
||||
cdns->otg_irq_regs = (struct cdns_otg_irq_regs __iomem *)
|
||||
&cdns->otg_v1_regs->ien;
|
||||
writel(1, &cdns->otg_v1_regs->simulate);
|
||||
|
||||
if (cdns->pdata &&
|
||||
(cdns->pdata->quirks & CDNS3_DRD_SUSPEND_RESIDENCY_ENABLE)) {
|
||||
reg = readl(&cdns->otg_v1_regs->susp_ctrl);
|
||||
reg |= SUSP_CTRL_SUSPEND_RESIDENCY_ENABLE;
|
||||
writel(reg, &cdns->otg_v1_regs->susp_ctrl);
|
||||
}
|
||||
|
||||
cdns->version = CDNS3_CONTROLLER_V1;
|
||||
} else {
|
||||
dev_err(cdns->dev, "not supported DID=0x%08x\n", state);
|
||||
|
@ -193,6 +193,9 @@ struct cdns_otg_irq_regs {
|
||||
/* OTGREFCLK - bitmasks */
|
||||
#define OTGREFCLK_STB_CLK_SWITCH_EN BIT(31)
|
||||
|
||||
/* SUPS_CTRL - bitmasks */
|
||||
#define SUSP_CTRL_SUSPEND_RESIDENCY_ENABLE BIT(17)
|
||||
|
||||
/* OVERRIDE - bitmasks */
|
||||
#define OVERRIDE_IDPULLUP BIT(0)
|
||||
/* Only for CDNS3_CONTROLLER_V0 version */
|
||||
|
@ -557,7 +557,7 @@ static void ci_hdrc_imx_shutdown(struct platform_device *pdev)
|
||||
ci_hdrc_imx_remove(pdev);
|
||||
}
|
||||
|
||||
static int __maybe_unused imx_controller_suspend(struct device *dev,
|
||||
static int imx_controller_suspend(struct device *dev,
|
||||
pm_message_t msg)
|
||||
{
|
||||
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
|
||||
@ -582,7 +582,7 @@ static int __maybe_unused imx_controller_suspend(struct device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused imx_controller_resume(struct device *dev,
|
||||
static int imx_controller_resume(struct device *dev,
|
||||
pm_message_t msg)
|
||||
{
|
||||
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
|
||||
@ -618,7 +618,7 @@ clk_disable:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused ci_hdrc_imx_suspend(struct device *dev)
|
||||
static int ci_hdrc_imx_suspend(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -636,7 +636,7 @@ static int __maybe_unused ci_hdrc_imx_suspend(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused ci_hdrc_imx_resume(struct device *dev)
|
||||
static int ci_hdrc_imx_resume(struct device *dev)
|
||||
{
|
||||
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
@ -652,7 +652,7 @@ static int __maybe_unused ci_hdrc_imx_resume(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused ci_hdrc_imx_runtime_suspend(struct device *dev)
|
||||
static int ci_hdrc_imx_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
|
||||
|
||||
@ -664,15 +664,14 @@ static int __maybe_unused ci_hdrc_imx_runtime_suspend(struct device *dev)
|
||||
return imx_controller_suspend(dev, PMSG_AUTO_SUSPEND);
|
||||
}
|
||||
|
||||
static int __maybe_unused ci_hdrc_imx_runtime_resume(struct device *dev)
|
||||
static int ci_hdrc_imx_runtime_resume(struct device *dev)
|
||||
{
|
||||
return imx_controller_resume(dev, PMSG_AUTO_RESUME);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops ci_hdrc_imx_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume)
|
||||
SET_RUNTIME_PM_OPS(ci_hdrc_imx_runtime_suspend,
|
||||
ci_hdrc_imx_runtime_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume)
|
||||
RUNTIME_PM_OPS(ci_hdrc_imx_runtime_suspend, ci_hdrc_imx_runtime_resume, NULL)
|
||||
};
|
||||
static struct platform_driver ci_hdrc_imx_driver = {
|
||||
.probe = ci_hdrc_imx_probe,
|
||||
@ -681,7 +680,7 @@ static struct platform_driver ci_hdrc_imx_driver = {
|
||||
.driver = {
|
||||
.name = "imx_usb",
|
||||
.of_match_table = ci_hdrc_imx_dt_ids,
|
||||
.pm = &ci_hdrc_imx_pm_ops,
|
||||
.pm = pm_ptr(&ci_hdrc_imx_pm_ops),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -303,4 +303,5 @@ module_platform_driver(ci_hdrc_msm_driver);
|
||||
|
||||
MODULE_ALIAS("platform:msm_hsusb");
|
||||
MODULE_ALIAS("platform:ci13xxx_msm");
|
||||
MODULE_DESCRIPTION("ChipIdea Highspeed Dual Role Controller");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -372,7 +372,7 @@ static void tegra_usb_remove(struct platform_device *pdev)
|
||||
pm_runtime_force_suspend(&pdev->dev);
|
||||
}
|
||||
|
||||
static int __maybe_unused tegra_usb_runtime_resume(struct device *dev)
|
||||
static int tegra_usb_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct tegra_usb *usb = dev_get_drvdata(dev);
|
||||
int err;
|
||||
@ -386,7 +386,7 @@ static int __maybe_unused tegra_usb_runtime_resume(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused tegra_usb_runtime_suspend(struct device *dev)
|
||||
static int tegra_usb_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct tegra_usb *usb = dev_get_drvdata(dev);
|
||||
|
||||
@ -396,15 +396,14 @@ static int __maybe_unused tegra_usb_runtime_suspend(struct device *dev)
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops tegra_usb_pm = {
|
||||
SET_RUNTIME_PM_OPS(tegra_usb_runtime_suspend, tegra_usb_runtime_resume,
|
||||
NULL)
|
||||
RUNTIME_PM_OPS(tegra_usb_runtime_suspend, tegra_usb_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver tegra_usb_driver = {
|
||||
.driver = {
|
||||
.name = "tegra-usb",
|
||||
.of_match_table = tegra_usb_of_match,
|
||||
.pm = &tegra_usb_pm,
|
||||
.pm = pm_ptr(&tegra_usb_pm),
|
||||
},
|
||||
.probe = tegra_usb_probe,
|
||||
.remove_new = tegra_usb_remove,
|
||||
|
@ -2592,4 +2592,5 @@ static struct usb_driver usbtmc_driver = {
|
||||
|
||||
module_usb_driver(usbtmc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("USB Test & Measurement class driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -433,4 +433,5 @@ static void __exit usb_common_exit(void)
|
||||
subsys_initcall(usb_common_init);
|
||||
module_exit(usb_common_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Common code for host and device side USB");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -449,4 +449,5 @@ int otg_statemachine(struct otg_fsm *fsm)
|
||||
return fsm->state_changed;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(otg_statemachine);
|
||||
MODULE_DESCRIPTION("OTG Finite State Machine");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -517,6 +517,19 @@ static int usb_unbind_interface(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usb_shutdown_interface(struct device *dev)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct usb_driver *driver;
|
||||
|
||||
if (!dev->driver)
|
||||
return;
|
||||
|
||||
driver = to_usb_driver(dev->driver);
|
||||
if (driver->shutdown)
|
||||
driver->shutdown(intf);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_driver_claim_interface - bind a driver to an interface
|
||||
* @driver: the driver to be bound
|
||||
@ -1059,6 +1072,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
|
||||
new_driver->driver.bus = &usb_bus_type;
|
||||
new_driver->driver.probe = usb_probe_interface;
|
||||
new_driver->driver.remove = usb_unbind_interface;
|
||||
new_driver->driver.shutdown = usb_shutdown_interface;
|
||||
new_driver->driver.owner = owner;
|
||||
new_driver->driver.mod_name = mod_name;
|
||||
new_driver->driver.dev_groups = new_driver->dev_groups;
|
||||
|
@ -1150,4 +1150,5 @@ static void __exit usb_exit(void)
|
||||
|
||||
subsys_initcall(usb_init);
|
||||
module_exit(usb_exit);
|
||||
MODULE_DESCRIPTION("USB core host-side support");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -885,10 +885,10 @@ static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep,
|
||||
}
|
||||
|
||||
/* DMA sg buffer */
|
||||
for_each_sg(ureq->sg, sg, ureq->num_sgs, i) {
|
||||
for_each_sg(ureq->sg, sg, ureq->num_mapped_sgs, i) {
|
||||
dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &desc,
|
||||
sg_dma_address(sg) + sg->offset, sg_dma_len(sg),
|
||||
sg_is_last(sg));
|
||||
(i == (ureq->num_mapped_sgs - 1)));
|
||||
desc_count += hs_ep->desc_count;
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,15 @@ static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg)
|
||||
p->no_clock_gating = true;
|
||||
}
|
||||
|
||||
static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg)
|
||||
static void dwc2_set_ltq_danube_params(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_core_params *p = &hsotg->params;
|
||||
|
||||
p->otg_caps.hnp_support = false;
|
||||
p->otg_caps.srp_support = false;
|
||||
}
|
||||
|
||||
static void dwc2_set_ltq_ase_params(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_core_params *p = &hsotg->params;
|
||||
|
||||
@ -142,12 +150,21 @@ static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg)
|
||||
p->host_rx_fifo_size = 288;
|
||||
p->host_nperio_tx_fifo_size = 128;
|
||||
p->host_perio_tx_fifo_size = 96;
|
||||
p->max_transfer_size = 65535;
|
||||
p->max_packet_count = 511;
|
||||
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
|
||||
GAHBCFG_HBSTLEN_SHIFT;
|
||||
}
|
||||
|
||||
static void dwc2_set_ltq_xrx200_params(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_core_params *p = &hsotg->params;
|
||||
|
||||
p->otg_caps.hnp_support = false;
|
||||
p->otg_caps.srp_support = false;
|
||||
p->host_rx_fifo_size = 288;
|
||||
p->host_nperio_tx_fifo_size = 128;
|
||||
p->host_perio_tx_fifo_size = 136;
|
||||
}
|
||||
|
||||
static void dwc2_set_amlogic_params(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_core_params *p = &hsotg->params;
|
||||
@ -297,8 +314,11 @@ const struct of_device_id dwc2_of_match_table[] = {
|
||||
{ .compatible = "ingenic,x1830-otg", .data = dwc2_set_x1600_params },
|
||||
{ .compatible = "ingenic,x2000-otg", .data = dwc2_set_x2000_params },
|
||||
{ .compatible = "rockchip,rk3066-usb", .data = dwc2_set_rk_params },
|
||||
{ .compatible = "lantiq,arx100-usb", .data = dwc2_set_ltq_params },
|
||||
{ .compatible = "lantiq,xrx200-usb", .data = dwc2_set_ltq_params },
|
||||
{ .compatible = "lantiq,danube-usb", .data = &dwc2_set_ltq_danube_params },
|
||||
{ .compatible = "lantiq,ase-usb", .data = &dwc2_set_ltq_ase_params },
|
||||
{ .compatible = "lantiq,arx100-usb", .data = &dwc2_set_ltq_ase_params },
|
||||
{ .compatible = "lantiq,xrx200-usb", .data = &dwc2_set_ltq_xrx200_params },
|
||||
{ .compatible = "lantiq,xrx300-usb", .data = &dwc2_set_ltq_xrx200_params },
|
||||
{ .compatible = "snps,dwc2" },
|
||||
{ .compatible = "samsung,s3c6400-hsotg",
|
||||
.data = dwc2_set_s3c6400_params },
|
||||
|
@ -108,22 +108,27 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
|
||||
void dwc3_enable_susphy(struct dwc3 *dwc, bool enable)
|
||||
{
|
||||
u32 reg;
|
||||
int i;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
|
||||
if (enable && !dwc->dis_u3_susphy_quirk)
|
||||
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
else
|
||||
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
for (i = 0; i < dwc->num_usb3_ports; i++) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(i));
|
||||
if (enable && !dwc->dis_u3_susphy_quirk)
|
||||
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
else
|
||||
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(i), reg);
|
||||
}
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||||
if (enable && !dwc->dis_u2_susphy_quirk)
|
||||
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
else
|
||||
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
for (i = 0; i < dwc->num_usb2_ports; i++) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i));
|
||||
if (enable && !dwc->dis_u2_susphy_quirk)
|
||||
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
else
|
||||
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg);
|
||||
}
|
||||
}
|
||||
|
||||
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
|
||||
@ -599,6 +604,18 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
|
||||
parms->hwparams9 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS9);
|
||||
}
|
||||
|
||||
static void dwc3_config_soc_bus(struct dwc3 *dwc)
|
||||
{
|
||||
if (dwc->gsbuscfg0_reqinfo != DWC3_GSBUSCFG0_REQINFO_UNSPECIFIED) {
|
||||
u32 reg;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG0);
|
||||
reg &= ~DWC3_GSBUSCFG0_REQINFO(~0);
|
||||
reg |= DWC3_GSBUSCFG0_REQINFO(dwc->gsbuscfg0_reqinfo);
|
||||
dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, reg);
|
||||
}
|
||||
}
|
||||
|
||||
static int dwc3_core_ulpi_init(struct dwc3 *dwc)
|
||||
{
|
||||
int intf;
|
||||
@ -1338,6 +1355,8 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
||||
|
||||
dwc3_set_incr_burst_type(dwc);
|
||||
|
||||
dwc3_config_soc_bus(dwc);
|
||||
|
||||
ret = dwc3_phy_power_on(dwc);
|
||||
if (ret)
|
||||
goto err_exit_phy;
|
||||
@ -1576,6 +1595,27 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
|
||||
}
|
||||
|
||||
static void dwc3_get_software_properties(struct dwc3 *dwc)
|
||||
{
|
||||
struct device *tmpdev;
|
||||
u16 gsbuscfg0_reqinfo;
|
||||
int ret;
|
||||
|
||||
dwc->gsbuscfg0_reqinfo = DWC3_GSBUSCFG0_REQINFO_UNSPECIFIED;
|
||||
|
||||
/*
|
||||
* Iterate over all parent nodes for finding swnode properties
|
||||
* and non-DT (non-ABI) properties.
|
||||
*/
|
||||
for (tmpdev = dwc->dev; tmpdev; tmpdev = tmpdev->parent) {
|
||||
ret = device_property_read_u16(tmpdev,
|
||||
"snps,gsbuscfg0-reqinfo",
|
||||
&gsbuscfg0_reqinfo);
|
||||
if (!ret)
|
||||
dwc->gsbuscfg0_reqinfo = gsbuscfg0_reqinfo;
|
||||
}
|
||||
}
|
||||
|
||||
static void dwc3_get_properties(struct dwc3 *dwc)
|
||||
{
|
||||
struct device *dev = dwc->dev;
|
||||
@ -2090,6 +2130,8 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
|
||||
dwc3_get_properties(dwc);
|
||||
|
||||
dwc3_get_software_properties(dwc);
|
||||
|
||||
dwc->reset = devm_reset_control_array_get_optional_shared(dev);
|
||||
if (IS_ERR(dwc->reset)) {
|
||||
ret = PTR_ERR(dwc->reset);
|
||||
|
@ -194,6 +194,10 @@
|
||||
#define DWC3_GSBUSCFG0_INCRBRSTENA (1 << 0) /* undefined length enable */
|
||||
#define DWC3_GSBUSCFG0_INCRBRST_MASK 0xff
|
||||
|
||||
/* Global SoC Bus Configuration Register: AHB-prot/AXI-cache/OCP-ReqInfo */
|
||||
#define DWC3_GSBUSCFG0_REQINFO(n) (((n) & 0xffff) << 16)
|
||||
#define DWC3_GSBUSCFG0_REQINFO_UNSPECIFIED 0xffffffff
|
||||
|
||||
/* Global Debug LSP MUX Select */
|
||||
#define DWC3_GDBGLSPMUX_ENDBC BIT(15) /* Host only */
|
||||
#define DWC3_GDBGLSPMUX_HOSTSELECT(n) ((n) & 0x3fff)
|
||||
@ -1153,6 +1157,9 @@ struct dwc3_scratchpad_array {
|
||||
* @num_ep_resized: carries the current number endpoints which have had its tx
|
||||
* fifo resized.
|
||||
* @debug_root: root debugfs directory for this device to put its files in.
|
||||
* @gsbuscfg0_reqinfo: store GSBUSCFG0.DATRDREQINFO, DESRDREQINFO,
|
||||
* DATWRREQINFO, and DESWRREQINFO value passed from
|
||||
* glue driver.
|
||||
*/
|
||||
struct dwc3 {
|
||||
struct work_struct drd_work;
|
||||
@ -1380,6 +1387,7 @@ struct dwc3 {
|
||||
int last_fifo_depth;
|
||||
int num_ep_resized;
|
||||
struct dentry *debug_root;
|
||||
u32 gsbuscfg0_reqinfo;
|
||||
};
|
||||
|
||||
#define INCRX_BURST_MODE 0
|
||||
|
@ -246,6 +246,31 @@ static const struct of_device_id dwc3_xlnx_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dwc3_xlnx_of_match);
|
||||
|
||||
static int dwc3_set_swnode(struct device *dev)
|
||||
{
|
||||
struct device_node *np = dev->of_node, *dwc3_np;
|
||||
struct property_entry props[2];
|
||||
int prop_idx = 0, ret = 0;
|
||||
|
||||
dwc3_np = of_get_compatible_child(np, "snps,dwc3");
|
||||
if (!dwc3_np) {
|
||||
ret = -ENODEV;
|
||||
dev_err(dev, "failed to find dwc3 core child\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props));
|
||||
if (of_dma_is_coherent(dwc3_np))
|
||||
props[prop_idx++] = PROPERTY_ENTRY_U16("snps,gsbuscfg0-reqinfo",
|
||||
0xffff);
|
||||
of_node_put(dwc3_np);
|
||||
|
||||
if (prop_idx)
|
||||
ret = device_create_managed_software_node(dev, props, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwc3_xlnx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct dwc3_xlnx *priv_data;
|
||||
@ -288,6 +313,10 @@ static int dwc3_xlnx_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto err_clk_put;
|
||||
|
||||
ret = dwc3_set_swnode(dev);
|
||||
if (ret)
|
||||
goto err_clk_put;
|
||||
|
||||
ret = of_platform_populate(np, NULL, NULL, dev);
|
||||
if (ret)
|
||||
goto err_clk_put;
|
||||
|
@ -126,7 +126,7 @@ out:
|
||||
|
||||
int dwc3_host_init(struct dwc3 *dwc)
|
||||
{
|
||||
struct property_entry props[5];
|
||||
struct property_entry props[6];
|
||||
struct platform_device *xhci;
|
||||
int ret, irq;
|
||||
int prop_idx = 0;
|
||||
@ -162,6 +162,8 @@ int dwc3_host_init(struct dwc3 *dwc)
|
||||
|
||||
props[prop_idx++] = PROPERTY_ENTRY_BOOL("xhci-sg-trb-cache-size-quirk");
|
||||
|
||||
props[prop_idx++] = PROPERTY_ENTRY_BOOL("write-64-hi-lo-quirk");
|
||||
|
||||
if (dwc->usb3_lpm_capable)
|
||||
props[prop_idx++] = PROPERTY_ENTRY_BOOL("usb3-lpm-capable");
|
||||
|
||||
|
@ -2799,5 +2799,6 @@ void usb_composite_overwrite_options(struct usb_composite_dev *cdev,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_composite_overwrite_options);
|
||||
|
||||
MODULE_DESCRIPTION("infrastructure for Composite USB Gadgets");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("David Brownell");
|
||||
|
@ -854,4 +854,5 @@ static struct usb_function_instance *acm_alloc_instance(void)
|
||||
return &opts->func_inst;
|
||||
}
|
||||
DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func);
|
||||
MODULE_DESCRIPTION("USB CDC serial (ACM) function driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -966,5 +966,6 @@ static struct usb_function *ecm_alloc(struct usb_function_instance *fi)
|
||||
}
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(ecm, ecm_alloc_inst, ecm_alloc);
|
||||
MODULE_DESCRIPTION("USB CDC Ethernet (ECM) link function driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("David Brownell");
|
||||
|
@ -674,5 +674,6 @@ static struct usb_function *eem_alloc(struct usb_function_instance *fi)
|
||||
}
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(eem, eem_alloc_inst, eem_alloc);
|
||||
MODULE_DESCRIPTION("USB CDC Ethernet (EEM) link function driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("David Brownell");
|
||||
|
@ -4316,5 +4316,6 @@ static char *ffs_prepare_buffer(const char __user *buf, size_t len)
|
||||
}
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(ffs, ffs_alloc_inst, ffs_alloc);
|
||||
MODULE_DESCRIPTION("user mode file system API for USB composite function controllers");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Michal Nazarewicz");
|
||||
|
@ -1322,6 +1322,7 @@ err_unlock:
|
||||
}
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(hid, hidg_alloc_inst, hidg_alloc);
|
||||
MODULE_DESCRIPTION("USB HID function driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Fabien Chouteau");
|
||||
|
||||
|
@ -593,4 +593,5 @@ void __exit lb_modexit(void)
|
||||
usb_function_unregister(&Loopbackusb_func);
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("USB peripheral loopback configuration driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -3577,6 +3577,7 @@ static struct usb_function *fsg_alloc(struct usb_function_instance *fi)
|
||||
}
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(mass_storage, fsg_alloc_inst, fsg_alloc);
|
||||
MODULE_DESCRIPTION("Mass Storage USB Composite Function");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Michal Nazarewicz");
|
||||
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "u_midi.h"
|
||||
|
||||
MODULE_AUTHOR("Ben Williamson");
|
||||
MODULE_DESCRIPTION("USB MIDI class function driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
static const char f_midi_shortname[] = "f_midi";
|
||||
|
@ -150,6 +150,9 @@ struct f_midi2 {
|
||||
|
||||
#define func_to_midi2(f) container_of(f, struct f_midi2, func)
|
||||
|
||||
/* convert from MIDI protocol number (1 or 2) to SNDRV_UMP_EP_INFO_PROTO_* */
|
||||
#define to_ump_protocol(v) (((v) & 3) << 8)
|
||||
|
||||
/* get EP name string */
|
||||
static const char *ump_ep_name(const struct f_midi2_ep *ep)
|
||||
{
|
||||
@ -564,8 +567,7 @@ static void reply_ump_stream_ep_config(struct f_midi2_ep *ep)
|
||||
.status = UMP_STREAM_MSG_STATUS_STREAM_CFG,
|
||||
};
|
||||
|
||||
if ((ep->info.protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI_MASK) ==
|
||||
SNDRV_UMP_EP_INFO_PROTO_MIDI2)
|
||||
if (ep->info.protocol == 2)
|
||||
rep.protocol = UMP_STREAM_MSG_EP_INFO_CAP_MIDI2 >> 8;
|
||||
else
|
||||
rep.protocol = UMP_STREAM_MSG_EP_INFO_CAP_MIDI1 >> 8;
|
||||
@ -627,13 +629,13 @@ static void process_ump_stream_msg(struct f_midi2_ep *ep, const u32 *data)
|
||||
return;
|
||||
case UMP_STREAM_MSG_STATUS_STREAM_CFG_REQUEST:
|
||||
if (*data & UMP_STREAM_MSG_EP_INFO_CAP_MIDI2) {
|
||||
ep->info.protocol = SNDRV_UMP_EP_INFO_PROTO_MIDI2;
|
||||
ep->info.protocol = 2;
|
||||
DBG(midi2, "Switching Protocol to MIDI2\n");
|
||||
} else {
|
||||
ep->info.protocol = SNDRV_UMP_EP_INFO_PROTO_MIDI1;
|
||||
ep->info.protocol = 1;
|
||||
DBG(midi2, "Switching Protocol to MIDI1\n");
|
||||
}
|
||||
snd_ump_switch_protocol(ep->ump, ep->info.protocol);
|
||||
snd_ump_switch_protocol(ep->ump, to_ump_protocol(ep->info.protocol));
|
||||
reply_ump_stream_ep_config(ep);
|
||||
return;
|
||||
case UMP_STREAM_MSG_STATUS_FB_DISCOVERY:
|
||||
@ -1065,7 +1067,8 @@ static void f_midi2_midi1_ep_out_complete(struct usb_ep *usb_ep,
|
||||
group = midi2->out_cable_mapping[cable].group;
|
||||
bytes = midi1_packet_bytes[*buf & 0x0f];
|
||||
for (c = 0; c < bytes; c++) {
|
||||
snd_ump_convert_to_ump(cvt, group, ep->info.protocol,
|
||||
snd_ump_convert_to_ump(cvt, group,
|
||||
to_ump_protocol(ep->info.protocol),
|
||||
buf[c + 1]);
|
||||
if (cvt->ump_bytes) {
|
||||
snd_ump_receive(ep->ump, cvt->ump,
|
||||
@ -1375,7 +1378,7 @@ static void assign_block_descriptors(struct f_midi2 *midi2,
|
||||
desc->nNumGroupTrm = b->num_groups;
|
||||
desc->iBlockItem = ep->blks[blk].string_id;
|
||||
|
||||
if (ep->info.protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI2)
|
||||
if (ep->info.protocol == 2)
|
||||
desc->bMIDIProtocol = USB_MS_MIDI_PROTO_2_0;
|
||||
else
|
||||
desc->bMIDIProtocol = USB_MS_MIDI_PROTO_1_0_128;
|
||||
@ -1552,7 +1555,7 @@ static int f_midi2_create_card(struct f_midi2 *midi2)
|
||||
if (midi2->info.static_block)
|
||||
ump->info.flags |= SNDRV_UMP_EP_INFO_STATIC_BLOCKS;
|
||||
ump->info.protocol_caps = (ep->info.protocol_caps & 3) << 8;
|
||||
ump->info.protocol = (ep->info.protocol & 3) << 8;
|
||||
ump->info.protocol = to_ump_protocol(ep->info.protocol);
|
||||
ump->info.version = 0x0101;
|
||||
ump->info.family_id = ep->info.family;
|
||||
ump->info.model_id = ep->info.model;
|
||||
@ -2868,4 +2871,5 @@ static struct usb_function *f_midi2_alloc(struct usb_function_instance *fi)
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(midi2, f_midi2_alloc_inst, f_midi2_alloc);
|
||||
|
||||
MODULE_DESCRIPTION("USB MIDI 2.0 class function driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -1797,5 +1797,6 @@ static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
|
||||
}
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(ncm, ncm_alloc_inst, ncm_alloc);
|
||||
MODULE_DESCRIPTION("USB CDC Network (NCM) link function driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Yauheni Kaliuta");
|
||||
|
@ -487,4 +487,5 @@ static struct usb_function *obex_alloc(struct usb_function_instance *fi)
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(obex, obex_alloc_inst, obex_alloc);
|
||||
MODULE_AUTHOR("Felipe Balbi");
|
||||
MODULE_DESCRIPTION("USB CDC OBEX function driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -729,4 +729,5 @@ void gphonet_cleanup(struct net_device *dev)
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(phonet, phonet_alloc_inst, phonet_alloc);
|
||||
MODULE_AUTHOR("Rémi Denis-Courmont");
|
||||
MODULE_DESCRIPTION("USB CDC Phonet function");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -1527,6 +1527,7 @@ static struct usb_function *gprinter_alloc(struct usb_function_instance *fi)
|
||||
}
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(printer, gprinter_alloc_inst, gprinter_alloc);
|
||||
MODULE_DESCRIPTION("USB printer function driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Craig Nadler");
|
||||
|
||||
|
@ -1013,5 +1013,6 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
|
||||
}
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(rndis, rndis_alloc_inst, rndis_alloc);
|
||||
MODULE_DESCRIPTION("RNDIS link function driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("David Brownell");
|
||||
|
@ -392,6 +392,7 @@ static struct usb_function *gser_alloc(struct usb_function_instance *fi)
|
||||
}
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(gser, gser_alloc_inst, gser_alloc);
|
||||
MODULE_DESCRIPTION("generic USB serial function driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Al Borchers");
|
||||
MODULE_AUTHOR("David Brownell");
|
||||
|
@ -1284,4 +1284,5 @@ static void __exit sslb_modexit(void)
|
||||
module_init(sslb_modinit);
|
||||
module_exit(sslb_modexit);
|
||||
|
||||
MODULE_DESCRIPTION("USB peripheral source/sink configuration driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -500,5 +500,6 @@ static struct usb_function *geth_alloc(struct usb_function_instance *fi)
|
||||
}
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(geth, geth_alloc_inst, geth_alloc);
|
||||
MODULE_DESCRIPTION("\"CDC Subset\" Ethernet link function driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("David Brownell");
|
||||
|
@ -2301,5 +2301,6 @@ static void __exit tcm_exit(void)
|
||||
}
|
||||
module_exit(tcm_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Target based USB-Gadget");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Sebastian Andrzej Siewior");
|
||||
|
@ -1823,5 +1823,6 @@ static struct usb_function *f_audio_alloc(struct usb_function_instance *fi)
|
||||
}
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(uac1, f_audio_alloc_inst, f_audio_alloc);
|
||||
MODULE_DESCRIPTION("USB Audio Class 1.0 Function (using u_audio API)");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Ruslan Bilovol");
|
||||
|
@ -1014,5 +1014,6 @@ static struct usb_function *f_audio_alloc(struct usb_function_instance *fi)
|
||||
}
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(uac1_legacy, f_audio_alloc_inst, f_audio_alloc);
|
||||
MODULE_DESCRIPTION("USB Audio class function driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Bryan Wu");
|
||||
|
@ -2063,7 +2063,10 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \
|
||||
goto end; \
|
||||
} \
|
||||
\
|
||||
ret = scnprintf(opts->name, min(sizeof(opts->name), len), \
|
||||
if (len && page[len - 1] == '\n') \
|
||||
len--; \
|
||||
\
|
||||
ret = scnprintf(opts->name, min(sizeof(opts->name), len + 1), \
|
||||
"%s", page); \
|
||||
\
|
||||
end: \
|
||||
@ -2251,6 +2254,7 @@ static struct usb_function *afunc_alloc(struct usb_function_instance *fi)
|
||||
}
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(uac2, afunc_alloc_inst, afunc_alloc);
|
||||
MODULE_DESCRIPTION("USB Audio Class 2.0 Function");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Yadwinder Singh");
|
||||
MODULE_AUTHOR("Jaswinder Singh");
|
||||
|
@ -1118,5 +1118,6 @@ err_config:
|
||||
}
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(uvc, uvc_alloc_inst, uvc_alloc);
|
||||
MODULE_DESCRIPTION("USB Video Class Gadget driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Laurent Pinchart");
|
||||
|
@ -537,4 +537,5 @@ ssize_t fsg_store_forced_eject(struct fsg_lun *curlun, struct rw_semaphore *file
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fsg_store_forced_eject);
|
||||
|
||||
MODULE_DESCRIPTION("Common definitions for mass storage functionality");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -1245,5 +1245,6 @@ void gether_disconnect(struct gether *link)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gether_disconnect);
|
||||
|
||||
MODULE_DESCRIPTION("Ethernet-over-USB link layer utilities for Gadget stack");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("David Brownell");
|
||||
|
@ -1536,4 +1536,5 @@ static void __exit userial_cleanup(void)
|
||||
}
|
||||
module_exit(userial_cleanup);
|
||||
|
||||
MODULE_DESCRIPTION("utilities for USB gadget \"serial port\"/TTY support");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -434,6 +434,7 @@ static void __exit dbgp_exit(void)
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Stephane Duverger");
|
||||
MODULE_DESCRIPTION("EHCI Debug Port device gadget");
|
||||
MODULE_LICENSE("GPL");
|
||||
module_init(dbgp_init);
|
||||
module_exit(dbgp_exit);
|
||||
|
@ -31,6 +31,7 @@
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
MODULE_AUTHOR("Ben Williamson");
|
||||
MODULE_DESCRIPTION("USB MIDI Gadget Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
static const char longname[] = "MIDI Gadget";
|
||||
|
@ -425,4 +425,5 @@ static struct usb_composite_driver zero_driver = {
|
||||
module_usb_composite_driver(zero_driver);
|
||||
|
||||
MODULE_AUTHOR("David Brownell");
|
||||
MODULE_DESCRIPTION("Gadget Zero, for USB development");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -1009,6 +1009,8 @@ static void ast_udc_getstatus(struct ast_udc_dev *udc)
|
||||
break;
|
||||
case USB_RECIP_ENDPOINT:
|
||||
epnum = crq.wIndex & USB_ENDPOINT_NUMBER_MASK;
|
||||
if (epnum >= AST_UDC_NUM_ENDPOINTS)
|
||||
goto stall;
|
||||
status = udc->ep[epnum].stopped;
|
||||
break;
|
||||
default:
|
||||
|
@ -293,4 +293,5 @@ module_exit(ohci_exynos_cleanup);
|
||||
|
||||
MODULE_ALIAS("platform:exynos-ohci");
|
||||
MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
|
||||
MODULE_DESCRIPTION("OHCI support for Samsung S5P/Exynos SoC Series");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -196,31 +196,6 @@ struct ehci_regs {
|
||||
#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
|
||||
} __packed;
|
||||
|
||||
/* Appendix C, Debug port ... intended for use with special "debug devices"
|
||||
* that can help if there's no serial console. (nonstandard enumeration.)
|
||||
*/
|
||||
struct ehci_dbg_port {
|
||||
u32 control;
|
||||
#define DBGP_OWNER (1<<30)
|
||||
#define DBGP_ENABLED (1<<28)
|
||||
#define DBGP_DONE (1<<16)
|
||||
#define DBGP_INUSE (1<<10)
|
||||
#define DBGP_ERRCODE(x) (((x)>>7)&0x07)
|
||||
# define DBGP_ERR_BAD 1
|
||||
# define DBGP_ERR_SIGNAL 2
|
||||
#define DBGP_ERROR (1<<6)
|
||||
#define DBGP_GO (1<<5)
|
||||
#define DBGP_OUT (1<<4)
|
||||
#define DBGP_LEN(x) (((x)>>0)&0x0f)
|
||||
u32 pids;
|
||||
#define DBGP_PID_GET(x) (((x)>>16)&0xff)
|
||||
#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok))
|
||||
u32 data03;
|
||||
u32 data47;
|
||||
u32 address;
|
||||
#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep))
|
||||
} __packed;
|
||||
|
||||
#define QTD_NEXT(dma) cpu_to_le32((u32)dma)
|
||||
|
||||
/*
|
||||
|
@ -1150,11 +1150,48 @@ static ssize_t dbc_bInterfaceProtocol_store(struct device *dev,
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t dbc_poll_interval_ms_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct xhci_dbc *dbc;
|
||||
struct xhci_hcd *xhci;
|
||||
|
||||
xhci = hcd_to_xhci(dev_get_drvdata(dev));
|
||||
dbc = xhci->dbc;
|
||||
|
||||
return sysfs_emit(buf, "%u\n", dbc->poll_interval);
|
||||
}
|
||||
|
||||
static ssize_t dbc_poll_interval_ms_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct xhci_dbc *dbc;
|
||||
struct xhci_hcd *xhci;
|
||||
u32 value;
|
||||
int ret;
|
||||
|
||||
ret = kstrtou32(buf, 0, &value);
|
||||
if (ret || value > DBC_POLL_INTERVAL_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
xhci = hcd_to_xhci(dev_get_drvdata(dev));
|
||||
dbc = xhci->dbc;
|
||||
|
||||
dbc->poll_interval = value;
|
||||
|
||||
mod_delayed_work(system_wq, &dbc->event_work, 0);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(dbc);
|
||||
static DEVICE_ATTR_RW(dbc_idVendor);
|
||||
static DEVICE_ATTR_RW(dbc_idProduct);
|
||||
static DEVICE_ATTR_RW(dbc_bcdDevice);
|
||||
static DEVICE_ATTR_RW(dbc_bInterfaceProtocol);
|
||||
static DEVICE_ATTR_RW(dbc_poll_interval_ms);
|
||||
|
||||
static struct attribute *dbc_dev_attrs[] = {
|
||||
&dev_attr_dbc.attr,
|
||||
@ -1162,6 +1199,7 @@ static struct attribute *dbc_dev_attrs[] = {
|
||||
&dev_attr_dbc_idProduct.attr,
|
||||
&dev_attr_dbc_bcdDevice.attr,
|
||||
&dev_attr_dbc_bInterfaceProtocol.attr,
|
||||
&dev_attr_dbc_poll_interval_ms.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(dbc_dev);
|
||||
|
@ -95,7 +95,7 @@ struct dbc_ep {
|
||||
#define DBC_QUEUE_SIZE 16
|
||||
#define DBC_WRITE_BUF_SIZE 8192
|
||||
#define DBC_POLL_INTERVAL_DEFAULT 64 /* milliseconds */
|
||||
|
||||
#define DBC_POLL_INTERVAL_MAX 5000 /* milliseconds */
|
||||
/*
|
||||
* Private structure for DbC hardware state:
|
||||
*/
|
||||
|
@ -136,10 +136,7 @@ static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||||
if (!ring || !first || !last)
|
||||
return;
|
||||
|
||||
/* Set chain bit for 0.95 hosts, and for isoc rings on AMD 0.96 host */
|
||||
chain_links = !!(xhci_link_trb_quirk(xhci) ||
|
||||
(ring->type == TYPE_ISOC &&
|
||||
(xhci->quirks & XHCI_AMD_0x96_HOST)));
|
||||
chain_links = xhci_link_chain_quirk(xhci, ring->type);
|
||||
|
||||
next = ring->enq_seg->next;
|
||||
xhci_link_segments(ring->enq_seg, first, ring->type, chain_links);
|
||||
@ -156,7 +153,7 @@ static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||||
ring->last_seg = last;
|
||||
}
|
||||
|
||||
for (seg = last; seg != ring->last_seg; seg = seg->next)
|
||||
for (seg = ring->enq_seg; seg != ring->last_seg; seg = seg->next)
|
||||
seg->next->num = seg->num + 1;
|
||||
}
|
||||
|
||||
@ -327,18 +324,19 @@ EXPORT_SYMBOL_GPL(xhci_initialize_ring_info);
|
||||
|
||||
/* Allocate segments and link them for a ring */
|
||||
static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
|
||||
struct xhci_segment **first, struct xhci_segment **last,
|
||||
unsigned int num_segs, unsigned int num,
|
||||
unsigned int cycle_state, enum xhci_ring_type type,
|
||||
unsigned int max_packet, gfp_t flags)
|
||||
struct xhci_segment **first,
|
||||
struct xhci_segment **last,
|
||||
unsigned int num_segs,
|
||||
unsigned int cycle_state,
|
||||
enum xhci_ring_type type,
|
||||
unsigned int max_packet,
|
||||
gfp_t flags)
|
||||
{
|
||||
struct xhci_segment *prev;
|
||||
unsigned int num = 0;
|
||||
bool chain_links;
|
||||
|
||||
/* Set chain bit for 0.95 hosts, and for isoc rings on AMD 0.96 host */
|
||||
chain_links = !!(xhci_link_trb_quirk(xhci) ||
|
||||
(type == TYPE_ISOC &&
|
||||
(xhci->quirks & XHCI_AMD_0x96_HOST)));
|
||||
chain_links = xhci_link_chain_quirk(xhci, type);
|
||||
|
||||
prev = xhci_segment_alloc(xhci, cycle_state, max_packet, num, flags);
|
||||
if (!prev)
|
||||
@ -394,9 +392,8 @@ struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
|
||||
if (num_segs == 0)
|
||||
return ring;
|
||||
|
||||
ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg,
|
||||
&ring->last_seg, num_segs, 0, cycle_state, type,
|
||||
max_packet, flags);
|
||||
ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg, &ring->last_seg, num_segs,
|
||||
cycle_state, type, max_packet, flags);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
@ -434,10 +431,8 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||||
struct xhci_segment *last;
|
||||
int ret;
|
||||
|
||||
ret = xhci_alloc_segments_for_ring(xhci, &first, &last,
|
||||
num_new_segs, ring->enq_seg->num + 1,
|
||||
ring->cycle_state, ring->type,
|
||||
ring->bounce_buf_len, flags);
|
||||
ret = xhci_alloc_segments_for_ring(xhci, &first, &last, num_new_segs, ring->cycle_state,
|
||||
ring->type, ring->bounce_buf_len, flags);
|
||||
if (ret)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -2325,7 +2320,10 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
|
||||
erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
|
||||
erst_base &= ERST_BASE_RSVDP;
|
||||
erst_base |= ir->erst.erst_dma_addr & ~ERST_BASE_RSVDP;
|
||||
xhci_write_64(xhci, erst_base, &ir->ir_set->erst_base);
|
||||
if (xhci->quirks & XHCI_WRITE_64_HI_LO)
|
||||
hi_lo_writeq(erst_base, &ir->ir_set->erst_base);
|
||||
else
|
||||
xhci_write_64(xhci, erst_base, &ir->ir_set->erst_base);
|
||||
|
||||
/* Set the event ring dequeue address of this interrupter */
|
||||
xhci_set_hc_event_deq(xhci, ir);
|
||||
|
@ -627,4 +627,5 @@ exit:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(renesas_xhci_check_request_fw);
|
||||
|
||||
MODULE_DESCRIPTION("Support for Renesas xHCI controller with firmware");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -50,6 +50,7 @@
|
||||
#define PCI_DEVICE_ID_INTEL_DENVERTON_XHCI 0x19d0
|
||||
#define PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI 0x8a13
|
||||
#define PCI_DEVICE_ID_INTEL_TIGER_LAKE_XHCI 0x9a13
|
||||
#define PCI_DEVICE_ID_INTEL_TIGER_LAKE_PCH_XHCI 0xa0ed
|
||||
#define PCI_DEVICE_ID_INTEL_COMET_LAKE_XHCI 0xa3af
|
||||
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI 0x51ed
|
||||
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_N_PCH_XHCI 0x54ed
|
||||
@ -373,7 +374,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
||||
xhci->quirks |= XHCI_MISSING_CAS;
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
|
||||
(pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI ||
|
||||
(pdev->device == PCI_DEVICE_ID_INTEL_TIGER_LAKE_PCH_XHCI ||
|
||||
pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI ||
|
||||
pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_N_PCH_XHCI))
|
||||
xhci->quirks |= XHCI_RESET_TO_DEFAULT;
|
||||
|
||||
|
@ -256,6 +256,9 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s
|
||||
if (device_property_read_bool(tmpdev, "xhci-sg-trb-cache-size-quirk"))
|
||||
xhci->quirks |= XHCI_SG_TRB_CACHE_SIZE_QUIRK;
|
||||
|
||||
if (device_property_read_bool(tmpdev, "write-64-hi-lo-quirk"))
|
||||
xhci->quirks |= XHCI_WRITE_64_HI_LO;
|
||||
|
||||
device_property_read_u32(tmpdev, "imod-interval-ns",
|
||||
&xhci->imod_interval);
|
||||
}
|
||||
|
@ -250,9 +250,7 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||||
* AMD 0.96 host, carry over the chain bit of the previous TRB
|
||||
* (which may mean the chain bit is cleared).
|
||||
*/
|
||||
if (!(ring->type == TYPE_ISOC &&
|
||||
(xhci->quirks & XHCI_AMD_0x96_HOST)) &&
|
||||
!xhci_link_trb_quirk(xhci)) {
|
||||
if (!xhci_link_chain_quirk(xhci, ring->type)) {
|
||||
next->link.control &= cpu_to_le32(~TRB_CHAIN);
|
||||
next->link.control |= cpu_to_le32(chain);
|
||||
}
|
||||
@ -283,7 +281,7 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||||
* Only for transfer and command rings where driver is the producer, not for
|
||||
* event rings.
|
||||
*/
|
||||
static unsigned int xhci_num_trbs_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
|
||||
static unsigned int xhci_num_trbs_free(struct xhci_ring *ring)
|
||||
{
|
||||
struct xhci_segment *enq_seg = ring->enq_seg;
|
||||
union xhci_trb *enq = ring->enqueue;
|
||||
@ -654,25 +652,6 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci,
|
||||
stream_id);
|
||||
return -ENODEV;
|
||||
}
|
||||
/*
|
||||
* A cancelled TD can complete with a stall if HW cached the trb.
|
||||
* In this case driver can't find td, but if the ring is empty we
|
||||
* can move the dequeue pointer to the current enqueue position.
|
||||
* We shouldn't hit this anymore as cached cancelled TRBs are given back
|
||||
* after clearing the cache, but be on the safe side and keep it anyway
|
||||
*/
|
||||
if (!td) {
|
||||
if (list_empty(&ep_ring->td_list)) {
|
||||
new_seg = ep_ring->enq_seg;
|
||||
new_deq = ep_ring->enqueue;
|
||||
new_cycle = ep_ring->cycle_state;
|
||||
xhci_dbg(xhci, "ep ring empty, Set new dequeue = enqueue");
|
||||
goto deq_found;
|
||||
} else {
|
||||
xhci_warn(xhci, "Can't find new dequeue state, missing td\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id);
|
||||
new_seg = ep_ring->deq_seg;
|
||||
@ -709,8 +688,6 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci,
|
||||
|
||||
} while (!cycle_found || !td_last_trb_found);
|
||||
|
||||
deq_found:
|
||||
|
||||
/* Don't update the ring cycle state for the producer (us). */
|
||||
addr = xhci_trb_virt_to_dma(new_seg, new_deq);
|
||||
if (addr == 0) {
|
||||
@ -738,7 +715,7 @@ deq_found:
|
||||
lower_32_bits(addr) | trb_sct | new_cycle,
|
||||
upper_32_bits(addr),
|
||||
STREAM_ID_FOR_TRB(stream_id), SLOT_ID_FOR_TRB(slot_id) |
|
||||
EP_ID_FOR_TRB(ep_index) | TRB_TYPE(TRB_SET_DEQ), false);
|
||||
EP_INDEX_FOR_TRB(ep_index) | TRB_TYPE(TRB_SET_DEQ), false);
|
||||
if (ret < 0) {
|
||||
xhci_free_command(xhci, cmd);
|
||||
return ret;
|
||||
@ -783,10 +760,6 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be called with xhci->lock held in interrupt context,
|
||||
* releases and re-acquires xhci->lock
|
||||
*/
|
||||
static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci,
|
||||
struct xhci_td *cur_td, int status)
|
||||
{
|
||||
@ -1511,8 +1484,8 @@ static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id,
|
||||
ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
|
||||
}
|
||||
|
||||
static void xhci_handle_cmd_enable_slot(struct xhci_hcd *xhci, int slot_id,
|
||||
struct xhci_command *command, u32 cmd_comp_code)
|
||||
static void xhci_handle_cmd_enable_slot(int slot_id, struct xhci_command *command,
|
||||
u32 cmd_comp_code)
|
||||
{
|
||||
if (cmd_comp_code == COMP_SUCCESS)
|
||||
command->slot_id = slot_id;
|
||||
@ -1537,8 +1510,7 @@ static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id)
|
||||
xhci_free_device_endpoint_resources(xhci, virt_dev, true);
|
||||
}
|
||||
|
||||
static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id,
|
||||
u32 cmd_comp_code)
|
||||
static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id)
|
||||
{
|
||||
struct xhci_virt_device *virt_dev;
|
||||
struct xhci_input_control_ctx *ctrl_ctx;
|
||||
@ -1780,14 +1752,14 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
|
||||
cmd_type = TRB_FIELD_TO_TYPE(le32_to_cpu(cmd_trb->generic.field[3]));
|
||||
switch (cmd_type) {
|
||||
case TRB_ENABLE_SLOT:
|
||||
xhci_handle_cmd_enable_slot(xhci, slot_id, cmd, cmd_comp_code);
|
||||
xhci_handle_cmd_enable_slot(slot_id, cmd, cmd_comp_code);
|
||||
break;
|
||||
case TRB_DISABLE_SLOT:
|
||||
xhci_handle_cmd_disable_slot(xhci, slot_id);
|
||||
break;
|
||||
case TRB_CONFIG_EP:
|
||||
if (!cmd->completion)
|
||||
xhci_handle_cmd_config_ep(xhci, slot_id, cmd_comp_code);
|
||||
xhci_handle_cmd_config_ep(xhci, slot_id);
|
||||
break;
|
||||
case TRB_EVAL_CONTEXT:
|
||||
break;
|
||||
@ -1905,9 +1877,7 @@ static void xhci_cavium_reset_phy_quirk(struct xhci_hcd *xhci)
|
||||
} while (!(pll_lock_check & 0x1) && --retry_count);
|
||||
}
|
||||
|
||||
static void handle_port_status(struct xhci_hcd *xhci,
|
||||
struct xhci_interrupter *ir,
|
||||
union xhci_trb *event)
|
||||
static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
u32 port_id;
|
||||
@ -2156,30 +2126,34 @@ static void xhci_clear_hub_tt_buffer(struct xhci_hcd *xhci, struct xhci_td *td,
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if an error has halted the endpoint ring. The class driver will
|
||||
* cleanup the halt for a non-default control endpoint if we indicate a stall.
|
||||
* However, a babble and other errors also halt the endpoint ring, and the class
|
||||
* driver won't clear the halt in that case, so we need to issue a Set Transfer
|
||||
* Ring Dequeue Pointer command manually.
|
||||
/*
|
||||
* Check if xhci internal endpoint state has gone to a "halt" state due to an
|
||||
* error or stall, including default control pipe protocol stall.
|
||||
* The internal halt needs to be cleared with a reset endpoint command.
|
||||
*
|
||||
* External device side is also halted in functional stall cases. Class driver
|
||||
* will clear the device halt with a CLEAR_FEATURE(ENDPOINT_HALT) request later.
|
||||
*/
|
||||
static int xhci_requires_manual_halt_cleanup(struct xhci_hcd *xhci,
|
||||
struct xhci_ep_ctx *ep_ctx,
|
||||
unsigned int trb_comp_code)
|
||||
static bool xhci_halted_host_endpoint(struct xhci_ep_ctx *ep_ctx, unsigned int comp_code)
|
||||
{
|
||||
/* TRB completion codes that may require a manual halt cleanup */
|
||||
if (trb_comp_code == COMP_USB_TRANSACTION_ERROR ||
|
||||
trb_comp_code == COMP_BABBLE_DETECTED_ERROR ||
|
||||
trb_comp_code == COMP_SPLIT_TRANSACTION_ERROR)
|
||||
/* The 0.95 spec says a babbling control endpoint
|
||||
* is not halted. The 0.96 spec says it is. Some HW
|
||||
* claims to be 0.95 compliant, but it halts the control
|
||||
* endpoint anyway. Check if a babble halted the
|
||||
* endpoint.
|
||||
/* Stall halts both internal and device side endpoint */
|
||||
if (comp_code == COMP_STALL_ERROR)
|
||||
return true;
|
||||
|
||||
/* TRB completion codes that may require internal halt cleanup */
|
||||
if (comp_code == COMP_USB_TRANSACTION_ERROR ||
|
||||
comp_code == COMP_BABBLE_DETECTED_ERROR ||
|
||||
comp_code == COMP_SPLIT_TRANSACTION_ERROR)
|
||||
/*
|
||||
* The 0.95 spec says a babbling control endpoint is not halted.
|
||||
* The 0.96 spec says it is. Some HW claims to be 0.95
|
||||
* compliant, but it halts the control endpoint anyway.
|
||||
* Check endpoint context if endpoint is halted.
|
||||
*/
|
||||
if (GET_EP_CTX_STATE(ep_ctx) == EP_STATE_HALTED)
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code)
|
||||
@ -2349,8 +2323,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
|
||||
case COMP_STOPPED_LENGTH_INVALID:
|
||||
goto finish_td;
|
||||
default:
|
||||
if (!xhci_requires_manual_halt_cleanup(xhci,
|
||||
ep_ctx, trb_comp_code))
|
||||
if (!xhci_halted_host_endpoint(ep_ctx, trb_comp_code))
|
||||
break;
|
||||
xhci_dbg(xhci, "TRB error %u, halted endpoint index = %u\n",
|
||||
trb_comp_code, ep->ep_index);
|
||||
@ -2460,7 +2433,9 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
|
||||
requested = remaining;
|
||||
break;
|
||||
case COMP_STOPPED_LENGTH_INVALID:
|
||||
requested = 0;
|
||||
/* exclude stopped trb with invalid length from length sum */
|
||||
sum_trbs_for_length = true;
|
||||
ep_trb_len = 0;
|
||||
remaining = 0;
|
||||
break;
|
||||
default:
|
||||
@ -2589,6 +2564,33 @@ finish_td:
|
||||
return finish_td(xhci, ep, ep_ring, td, trb_comp_code);
|
||||
}
|
||||
|
||||
/* Transfer events which don't point to a transfer TRB, see xhci 4.17.4 */
|
||||
static int handle_transferless_tx_event(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
|
||||
u32 trb_comp_code)
|
||||
{
|
||||
switch (trb_comp_code) {
|
||||
case COMP_STALL_ERROR:
|
||||
case COMP_USB_TRANSACTION_ERROR:
|
||||
case COMP_INVALID_STREAM_TYPE_ERROR:
|
||||
case COMP_INVALID_STREAM_ID_ERROR:
|
||||
xhci_dbg(xhci, "Stream transaction error ep %u no id\n", ep->ep_index);
|
||||
if (ep->err_count++ > MAX_SOFT_RETRY)
|
||||
xhci_handle_halted_endpoint(xhci, ep, NULL, EP_HARD_RESET);
|
||||
else
|
||||
xhci_handle_halted_endpoint(xhci, ep, NULL, EP_SOFT_RESET);
|
||||
break;
|
||||
case COMP_RING_UNDERRUN:
|
||||
case COMP_RING_OVERRUN:
|
||||
case COMP_STOPPED_LENGTH_INVALID:
|
||||
break;
|
||||
default:
|
||||
xhci_err(xhci, "Transfer event %u for unknown stream ring slot %u ep %u\n",
|
||||
trb_comp_code, ep->vdev->slot_id, ep->ep_index);
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this function returns an error condition, it means it got a Transfer
|
||||
* event with a corrupted Slot ID, Endpoint ID, or TRB DMA address.
|
||||
@ -2609,7 +2611,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||
int status = -EINPROGRESS;
|
||||
struct xhci_ep_ctx *ep_ctx;
|
||||
u32 trb_comp_code;
|
||||
int td_num = 0;
|
||||
|
||||
slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
|
||||
ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1;
|
||||
@ -2632,37 +2633,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* Some transfer events don't always point to a trb, see xhci 4.17.4 */
|
||||
if (!ep_ring) {
|
||||
switch (trb_comp_code) {
|
||||
case COMP_STALL_ERROR:
|
||||
case COMP_USB_TRANSACTION_ERROR:
|
||||
case COMP_INVALID_STREAM_TYPE_ERROR:
|
||||
case COMP_INVALID_STREAM_ID_ERROR:
|
||||
xhci_dbg(xhci, "Stream transaction error ep %u no id\n",
|
||||
ep_index);
|
||||
if (ep->err_count++ > MAX_SOFT_RETRY)
|
||||
xhci_handle_halted_endpoint(xhci, ep, NULL,
|
||||
EP_HARD_RESET);
|
||||
else
|
||||
xhci_handle_halted_endpoint(xhci, ep, NULL,
|
||||
EP_SOFT_RESET);
|
||||
break;
|
||||
case COMP_RING_UNDERRUN:
|
||||
case COMP_RING_OVERRUN:
|
||||
case COMP_STOPPED_LENGTH_INVALID:
|
||||
break;
|
||||
default:
|
||||
xhci_err(xhci, "ERROR Transfer event for unknown stream ring slot %u ep %u\n",
|
||||
slot_id, ep_index);
|
||||
goto err_out;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Count current td numbers if ep->skip is set */
|
||||
if (ep->skip)
|
||||
td_num += list_count_nodes(&ep_ring->td_list);
|
||||
if (!ep_ring)
|
||||
return handle_transferless_tx_event(xhci, ep, trb_comp_code);
|
||||
|
||||
/* Look for common error cases */
|
||||
switch (trb_comp_code) {
|
||||
@ -2744,18 +2716,12 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||
* a Ring Overrun Event for IN Isoch endpoint or Ring
|
||||
* Underrun Event for OUT Isoch endpoint.
|
||||
*/
|
||||
xhci_dbg(xhci, "underrun event on endpoint\n");
|
||||
if (!list_empty(&ep_ring->td_list))
|
||||
xhci_dbg(xhci, "Underrun Event for slot %u ep %d still with TDs queued?\n",
|
||||
slot_id, ep_index);
|
||||
xhci_dbg(xhci, "Underrun event on slot %u ep %u\n", slot_id, ep_index);
|
||||
if (ep->skip)
|
||||
break;
|
||||
return 0;
|
||||
case COMP_RING_OVERRUN:
|
||||
xhci_dbg(xhci, "overrun event on endpoint\n");
|
||||
if (!list_empty(&ep_ring->td_list))
|
||||
xhci_dbg(xhci, "Overrun Event for slot %u ep %d still with TDs queued?\n",
|
||||
slot_id, ep_index);
|
||||
xhci_dbg(xhci, "Overrun event on slot %u ep %u\n", slot_id, ep_index);
|
||||
if (ep->skip)
|
||||
break;
|
||||
return 0;
|
||||
@ -2822,44 +2788,17 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||
xhci_dbg(xhci, "td_list is empty while skip flag set. Clear skip flag for slot %u ep %u.\n",
|
||||
slot_id, ep_index);
|
||||
}
|
||||
if (trb_comp_code == COMP_STALL_ERROR ||
|
||||
xhci_requires_manual_halt_cleanup(xhci, ep_ctx,
|
||||
trb_comp_code)) {
|
||||
xhci_handle_halted_endpoint(xhci, ep, NULL,
|
||||
EP_HARD_RESET);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We've skipped all the TDs on the ep ring when ep->skip set */
|
||||
if (ep->skip && td_num == 0) {
|
||||
ep->skip = false;
|
||||
xhci_dbg(xhci, "All tds on the ep_ring skipped. Clear skip flag for slot %u ep %u.\n",
|
||||
slot_id, ep_index);
|
||||
return 0;
|
||||
td = NULL;
|
||||
goto check_endpoint_halted;
|
||||
}
|
||||
|
||||
td = list_first_entry(&ep_ring->td_list, struct xhci_td,
|
||||
td_list);
|
||||
if (ep->skip)
|
||||
td_num--;
|
||||
|
||||
/* Is this a TRB in the currently executing TD? */
|
||||
ep_seg = trb_in_td(xhci, td, ep_trb_dma, false);
|
||||
|
||||
/*
|
||||
* Skip the Force Stopped Event. The event_trb(event_dma) of FSE
|
||||
* is not in the current TD pointed by ep_ring->dequeue because
|
||||
* that the hardware dequeue pointer still at the previous TRB
|
||||
* of the current TD. The previous TRB maybe a Link TD or the
|
||||
* last TRB of the previous TD. The command completion handle
|
||||
* will take care the rest.
|
||||
*/
|
||||
if (!ep_seg && (trb_comp_code == COMP_STOPPED ||
|
||||
trb_comp_code == COMP_STOPPED_LENGTH_INVALID)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ep_seg) {
|
||||
|
||||
if (ep->skip && usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
|
||||
@ -2867,6 +2806,18 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip the Force Stopped Event. The 'ep_trb' of FSE is not in the current
|
||||
* TD pointed by 'ep_ring->dequeue' because that the hardware dequeue
|
||||
* pointer still at the previous TRB of the current TD. The previous TRB
|
||||
* maybe a Link TD or the last TRB of the previous TD. The command
|
||||
* completion handle will take care the rest.
|
||||
*/
|
||||
if (trb_comp_code == COMP_STOPPED ||
|
||||
trb_comp_code == COMP_STOPPED_LENGTH_INVALID) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some hosts give a spurious success event after a short
|
||||
* transfer. Ignore it.
|
||||
@ -2916,10 +2867,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||
return -ESHUTDOWN;
|
||||
}
|
||||
}
|
||||
if (trb_comp_code == COMP_SHORT_PACKET)
|
||||
ep_ring->last_td_was_short = true;
|
||||
else
|
||||
ep_ring->last_td_was_short = false;
|
||||
|
||||
if (ep->skip) {
|
||||
xhci_dbg(xhci,
|
||||
@ -2928,37 +2875,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||
ep->skip = false;
|
||||
}
|
||||
|
||||
ep_trb = &ep_seg->trbs[(ep_trb_dma - ep_seg->dma) /
|
||||
sizeof(*ep_trb)];
|
||||
|
||||
trace_xhci_handle_transfer(ep_ring,
|
||||
(struct xhci_generic_trb *) ep_trb);
|
||||
|
||||
/*
|
||||
* No-op TRB could trigger interrupts in a case where
|
||||
* a URB was killed and a STALL_ERROR happens right
|
||||
* after the endpoint ring stopped. Reset the halted
|
||||
* endpoint. Otherwise, the endpoint remains stalled
|
||||
* indefinitely.
|
||||
*/
|
||||
|
||||
if (trb_is_noop(ep_trb)) {
|
||||
if (trb_comp_code == COMP_STALL_ERROR ||
|
||||
xhci_requires_manual_halt_cleanup(xhci, ep_ctx,
|
||||
trb_comp_code))
|
||||
xhci_handle_halted_endpoint(xhci, ep, td,
|
||||
EP_HARD_RESET);
|
||||
} else {
|
||||
td->status = status;
|
||||
|
||||
/* update the urb's actual_length and give back to the core */
|
||||
if (usb_endpoint_xfer_control(&td->urb->ep->desc))
|
||||
process_ctrl_td(xhci, ep, ep_ring, td, ep_trb, event);
|
||||
else if (usb_endpoint_xfer_isoc(&td->urb->ep->desc))
|
||||
process_isoc_td(xhci, ep, ep_ring, td, ep_trb, event);
|
||||
else
|
||||
process_bulk_intr_td(xhci, ep, ep_ring, td, ep_trb, event);
|
||||
}
|
||||
/*
|
||||
* If ep->skip is set, it means there are missed tds on the
|
||||
* endpoint ring need to take care of.
|
||||
@ -2967,6 +2883,38 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||
*/
|
||||
} while (ep->skip);
|
||||
|
||||
if (trb_comp_code == COMP_SHORT_PACKET)
|
||||
ep_ring->last_td_was_short = true;
|
||||
else
|
||||
ep_ring->last_td_was_short = false;
|
||||
|
||||
ep_trb = &ep_seg->trbs[(ep_trb_dma - ep_seg->dma) / sizeof(*ep_trb)];
|
||||
trace_xhci_handle_transfer(ep_ring, (struct xhci_generic_trb *) ep_trb);
|
||||
|
||||
/*
|
||||
* No-op TRB could trigger interrupts in a case where a URB was killed
|
||||
* and a STALL_ERROR happens right after the endpoint ring stopped.
|
||||
* Reset the halted endpoint. Otherwise, the endpoint remains stalled
|
||||
* indefinitely.
|
||||
*/
|
||||
|
||||
if (trb_is_noop(ep_trb))
|
||||
goto check_endpoint_halted;
|
||||
|
||||
td->status = status;
|
||||
|
||||
/* update the urb's actual_length and give back to the core */
|
||||
if (usb_endpoint_xfer_control(&td->urb->ep->desc))
|
||||
process_ctrl_td(xhci, ep, ep_ring, td, ep_trb, event);
|
||||
else if (usb_endpoint_xfer_isoc(&td->urb->ep->desc))
|
||||
process_isoc_td(xhci, ep, ep_ring, td, ep_trb, event);
|
||||
else
|
||||
process_bulk_intr_td(xhci, ep, ep_ring, td, ep_trb, event);
|
||||
|
||||
check_endpoint_halted:
|
||||
if (xhci_halted_host_endpoint(ep_ctx, trb_comp_code))
|
||||
xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
@ -3005,7 +2953,7 @@ static int xhci_handle_event_trb(struct xhci_hcd *xhci, struct xhci_interrupter
|
||||
handle_cmd_completion(xhci, &event->event_cmd);
|
||||
break;
|
||||
case TRB_PORT_STATUS:
|
||||
handle_port_status(xhci, ir, event);
|
||||
handle_port_status(xhci, event);
|
||||
break;
|
||||
case TRB_TRANSFER:
|
||||
handle_tx_event(xhci, ir, &event->trans_event);
|
||||
@ -3065,8 +3013,7 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
|
||||
}
|
||||
|
||||
/* Clear the interrupt pending bit for a specific interrupter. */
|
||||
static void xhci_clear_interrupt_pending(struct xhci_hcd *xhci,
|
||||
struct xhci_interrupter *ir)
|
||||
static void xhci_clear_interrupt_pending(struct xhci_interrupter *ir)
|
||||
{
|
||||
if (!ir->ip_autoclear) {
|
||||
u32 irq_pending;
|
||||
@ -3087,7 +3034,7 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir
|
||||
int err;
|
||||
u64 temp;
|
||||
|
||||
xhci_clear_interrupt_pending(xhci, ir);
|
||||
xhci_clear_interrupt_pending(ir);
|
||||
|
||||
/* Event ring hasn't been allocated yet. */
|
||||
if (!ir->event_ring || !ir->event_ring->dequeue) {
|
||||
@ -3260,7 +3207,7 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
|
||||
|
||||
if (ep_ring != xhci->cmd_ring) {
|
||||
new_segs = xhci_ring_expansion_needed(xhci, ep_ring, num_trbs);
|
||||
} else if (xhci_num_trbs_free(xhci, ep_ring) <= num_trbs) {
|
||||
} else if (xhci_num_trbs_free(ep_ring) <= num_trbs) {
|
||||
xhci_err(xhci, "Do not support expand command ring\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -3278,9 +3225,7 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
|
||||
/* If we're not dealing with 0.95 hardware or isoc rings
|
||||
* on AMD 0.96 host, clear the chain bit.
|
||||
*/
|
||||
if (!xhci_link_trb_quirk(xhci) &&
|
||||
!(ep_ring->type == TYPE_ISOC &&
|
||||
(xhci->quirks & XHCI_AMD_0x96_HOST)))
|
||||
if (!xhci_link_chain_quirk(xhci, ep_ring->type))
|
||||
ep_ring->enqueue->link.control &=
|
||||
cpu_to_le32(~TRB_CHAIN);
|
||||
else
|
||||
@ -3435,8 +3380,7 @@ static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id,
|
||||
xhci_ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
|
||||
}
|
||||
|
||||
static void check_interval(struct xhci_hcd *xhci, struct urb *urb,
|
||||
struct xhci_ep_ctx *ep_ctx)
|
||||
static void check_interval(struct urb *urb, struct xhci_ep_ctx *ep_ctx)
|
||||
{
|
||||
int xhci_interval;
|
||||
int ep_interval;
|
||||
@ -3477,7 +3421,7 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
struct xhci_ep_ctx *ep_ctx;
|
||||
|
||||
ep_ctx = xhci_get_ep_ctx(xhci, xhci->devs[slot_id]->out_ctx, ep_index);
|
||||
check_interval(xhci, urb, ep_ctx);
|
||||
check_interval(urb, ep_ctx);
|
||||
|
||||
return xhci_queue_bulk_tx(xhci, mem_flags, urb, slot_id, ep_index);
|
||||
}
|
||||
@ -3723,7 +3667,6 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
upper_32_bits(send_addr),
|
||||
length_field,
|
||||
field);
|
||||
td->num_trbs++;
|
||||
addr += trb_buff_len;
|
||||
sent_len = trb_buff_len;
|
||||
|
||||
@ -3750,7 +3693,6 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
urb_priv->td[1].last_trb_seg = ring->enq_seg;
|
||||
field = TRB_TYPE(TRB_NORMAL) | ring->cycle_state | TRB_IOC;
|
||||
queue_trb(xhci, ring, 0, 0, 0, TRB_INTR_TARGET(0), field);
|
||||
urb_priv->td[1].num_trbs++;
|
||||
}
|
||||
|
||||
check_trb_math(urb, enqd_len);
|
||||
@ -3801,7 +3743,6 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
|
||||
urb_priv = urb->hcpriv;
|
||||
td = &urb_priv->td[0];
|
||||
td->num_trbs = num_trbs;
|
||||
|
||||
/*
|
||||
* Don't give the first TRB to the hardware (by toggling the cycle bit)
|
||||
@ -4122,7 +4063,6 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
goto cleanup;
|
||||
}
|
||||
td = &urb_priv->td[i];
|
||||
td->num_trbs = trbs_per_td;
|
||||
/* use SIA as default, if frame id is used overwrite it */
|
||||
sia_frame_id = TRB_SIA;
|
||||
if (!(urb->transfer_flags & URB_ISO_ASAP) &&
|
||||
@ -4286,7 +4226,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
* Check interval value. This should be done before we start to
|
||||
* calculate the start frame value.
|
||||
*/
|
||||
check_interval(xhci, urb, ep_ctx);
|
||||
check_interval(urb, ep_ctx);
|
||||
|
||||
/* Calculate the start frame and put it in urb->start_frame. */
|
||||
if (HCC_CFC(xhci->hcc_params) && !list_empty(&ep_ring->td_list)) {
|
||||
@ -4439,7 +4379,7 @@ int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, struct xhci_command *cmd,
|
||||
int slot_id, unsigned int ep_index, int suspend)
|
||||
{
|
||||
u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id);
|
||||
u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);
|
||||
u32 trb_ep_index = EP_INDEX_FOR_TRB(ep_index);
|
||||
u32 type = TRB_TYPE(TRB_STOP_RING);
|
||||
u32 trb_suspend = SUSPEND_PORT_FOR_TRB(suspend);
|
||||
|
||||
@ -4452,7 +4392,7 @@ int xhci_queue_reset_ep(struct xhci_hcd *xhci, struct xhci_command *cmd,
|
||||
enum xhci_ep_reset_type reset_type)
|
||||
{
|
||||
u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id);
|
||||
u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);
|
||||
u32 trb_ep_index = EP_INDEX_FOR_TRB(ep_index);
|
||||
u32 type = TRB_TYPE(TRB_RESET_EP);
|
||||
|
||||
if (reset_type == EP_SOFT_RESET)
|
||||
|
@ -250,6 +250,7 @@ DECLARE_EVENT_CLASS(xhci_log_urb,
|
||||
TP_PROTO(struct urb *urb),
|
||||
TP_ARGS(urb),
|
||||
TP_STRUCT__entry(
|
||||
__string(devname, dev_name(&urb->dev->dev))
|
||||
__field(void *, urb)
|
||||
__field(unsigned int, pipe)
|
||||
__field(unsigned int, stream)
|
||||
@ -265,6 +266,7 @@ DECLARE_EVENT_CLASS(xhci_log_urb,
|
||||
__field(int, slot_id)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__assign_str(devname);
|
||||
__entry->urb = urb;
|
||||
__entry->pipe = urb->pipe;
|
||||
__entry->stream = urb->stream_id;
|
||||
@ -279,7 +281,8 @@ DECLARE_EVENT_CLASS(xhci_log_urb,
|
||||
__entry->type = usb_endpoint_type(&urb->ep->desc);
|
||||
__entry->slot_id = urb->dev->slot_id;
|
||||
),
|
||||
TP_printk("ep%d%s-%s: urb %p pipe %u slot %d length %d/%d sgs %d/%d stream %d flags %08x",
|
||||
TP_printk("%s ep%d%s-%s: urb %p pipe %u slot %d length %d/%d sgs %d/%d stream %d flags %08x",
|
||||
__get_str(devname),
|
||||
__entry->epnum, __entry->dir_in ? "in" : "out",
|
||||
__print_symbolic(__entry->type,
|
||||
{ USB_ENDPOINT_XFER_INT, "intr" },
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||
#include <linux/io-64-nonatomic-hi-lo.h>
|
||||
|
||||
/* Code sharing between pci-quirks and xhci hcd */
|
||||
#include "xhci-ext-caps.h"
|
||||
@ -805,12 +806,18 @@ struct xhci_transfer_event {
|
||||
__le32 flags;
|
||||
};
|
||||
|
||||
/* Transfer event TRB length bit mask */
|
||||
/* bits 0:23 */
|
||||
#define EVENT_TRB_LEN(p) ((p) & 0xffffff)
|
||||
/* Transfer event flags bitfield, also for select command completion events */
|
||||
#define TRB_TO_SLOT_ID(p) (((p) >> 24) & 0xff)
|
||||
#define SLOT_ID_FOR_TRB(p) (((p) & 0xff) << 24)
|
||||
|
||||
/** Transfer Event bit fields **/
|
||||
#define TRB_TO_EP_ID(p) (((p) >> 16) & 0x1f)
|
||||
#define TRB_TO_EP_ID(p) (((p) >> 16) & 0x1f) /* Endpoint ID 1 - 31 */
|
||||
#define EP_ID_FOR_TRB(p) (((p) & 0x1f) << 16)
|
||||
|
||||
#define TRB_TO_EP_INDEX(p) (TRB_TO_EP_ID(p) - 1) /* Endpoint index 0 - 30 */
|
||||
#define EP_INDEX_FOR_TRB(p) ((((p) + 1) & 0x1f) << 16)
|
||||
|
||||
/* Transfer event TRB length bit mask */
|
||||
#define EVENT_TRB_LEN(p) ((p) & 0xffffff)
|
||||
|
||||
/* Completion Code - only applicable for some types of TRBs */
|
||||
#define COMP_CODE_MASK (0xff << 24)
|
||||
@ -950,8 +957,6 @@ struct xhci_event_cmd {
|
||||
__le32 flags;
|
||||
};
|
||||
|
||||
/* flags bitmasks */
|
||||
|
||||
/* Address device - disable SetAddress */
|
||||
#define TRB_BSR (1<<9)
|
||||
|
||||
@ -987,13 +992,8 @@ enum xhci_setup_dev {
|
||||
|
||||
/* bits 16:23 are the virtual function ID */
|
||||
/* bits 24:31 are the slot ID */
|
||||
#define TRB_TO_SLOT_ID(p) (((p) & (0xff<<24)) >> 24)
|
||||
#define SLOT_ID_FOR_TRB(p) (((p) & 0xff) << 24)
|
||||
|
||||
/* Stop Endpoint TRB - ep_index to endpoint ID for this TRB */
|
||||
#define TRB_TO_EP_INDEX(p) ((((p) & (0x1f << 16)) >> 16) - 1)
|
||||
#define EP_ID_FOR_TRB(p) ((((p) + 1) & 0x1f) << 16)
|
||||
|
||||
#define SUSPEND_PORT_FOR_TRB(p) (((p) & 1) << 23)
|
||||
#define TRB_TO_SUSPEND_PORT(p) (((p) & (1 << 23)) >> 23)
|
||||
#define LAST_EP_INDEX 30
|
||||
@ -1294,7 +1294,6 @@ struct xhci_td {
|
||||
/* actual_length of the URB has already been set */
|
||||
bool urb_length_set;
|
||||
bool error_mid_td;
|
||||
unsigned int num_trbs;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1628,6 +1627,7 @@ struct xhci_hcd {
|
||||
#define XHCI_RESET_TO_DEFAULT BIT_ULL(44)
|
||||
#define XHCI_ZHAOXIN_TRB_FETCH BIT_ULL(45)
|
||||
#define XHCI_ZHAOXIN_HOST BIT_ULL(46)
|
||||
#define XHCI_WRITE_64_HI_LO BIT_ULL(47)
|
||||
|
||||
unsigned int num_active_eps;
|
||||
unsigned int limit_active_eps;
|
||||
@ -1749,9 +1749,12 @@ static inline void xhci_write_64(struct xhci_hcd *xhci,
|
||||
lo_hi_writeq(val, regs);
|
||||
}
|
||||
|
||||
static inline int xhci_link_trb_quirk(struct xhci_hcd *xhci)
|
||||
|
||||
/* Link TRB chain should always be set on 0.95 hosts, and AMD 0.96 ISOC rings */
|
||||
static inline bool xhci_link_chain_quirk(struct xhci_hcd *xhci, enum xhci_ring_type type)
|
||||
{
|
||||
return xhci->quirks & XHCI_LINK_TRB_QUIRK;
|
||||
return (xhci->quirks & XHCI_LINK_TRB_QUIRK) ||
|
||||
(type == TYPE_ISOC && (xhci->quirks & XHCI_AMD_0x96_HOST));
|
||||
}
|
||||
|
||||
/* xHCI debugging */
|
||||
@ -2021,8 +2024,7 @@ static inline const char *xhci_decode_trb(char *str, size_t size,
|
||||
field1, field0,
|
||||
xhci_trb_comp_code_string(GET_COMP_CODE(field2)),
|
||||
EVENT_TRB_LEN(field2), TRB_TO_SLOT_ID(field3),
|
||||
/* Macro decrements 1, maybe it shouldn't?!? */
|
||||
TRB_TO_EP_INDEX(field3) + 1,
|
||||
TRB_TO_EP_ID(field3),
|
||||
xhci_trb_type_string(type),
|
||||
field3 & EVENT_DATA ? 'E' : 'e',
|
||||
field3 & TRB_CYCLE ? 'C' : 'c');
|
||||
@ -2137,8 +2139,7 @@ static inline const char *xhci_decode_trb(char *str, size_t size,
|
||||
xhci_trb_type_string(type),
|
||||
field1, field0,
|
||||
TRB_TO_SLOT_ID(field3),
|
||||
/* Macro decrements 1, maybe it shouldn't?!? */
|
||||
TRB_TO_EP_INDEX(field3) + 1,
|
||||
TRB_TO_EP_ID(field3),
|
||||
field3 & TRB_TSP ? 'T' : 't',
|
||||
field3 & TRB_CYCLE ? 'C' : 'c');
|
||||
break;
|
||||
@ -2148,8 +2149,7 @@ static inline const char *xhci_decode_trb(char *str, size_t size,
|
||||
xhci_trb_type_string(type),
|
||||
TRB_TO_SLOT_ID(field3),
|
||||
TRB_TO_SUSPEND_PORT(field3),
|
||||
/* Macro decrements 1, maybe it shouldn't?!? */
|
||||
TRB_TO_EP_INDEX(field3) + 1,
|
||||
TRB_TO_EP_ID(field3),
|
||||
field3 & TRB_CYCLE ? 'C' : 'c');
|
||||
break;
|
||||
case TRB_SET_DEQ:
|
||||
@ -2159,8 +2159,7 @@ static inline const char *xhci_decode_trb(char *str, size_t size,
|
||||
field1, field0,
|
||||
TRB_TO_STREAM_ID(field2),
|
||||
TRB_TO_SLOT_ID(field3),
|
||||
/* Macro decrements 1, maybe it shouldn't?!? */
|
||||
TRB_TO_EP_INDEX(field3) + 1,
|
||||
TRB_TO_EP_ID(field3),
|
||||
field3 & TRB_CYCLE ? 'C' : 'c');
|
||||
break;
|
||||
case TRB_RESET_DEV:
|
||||
|
@ -148,4 +148,5 @@ int ezusb_fx2_ihex_firmware_download(struct usb_device *dev,
|
||||
EXPORT_SYMBOL_GPL(ezusb_fx2_ihex_firmware_download);
|
||||
#endif
|
||||
|
||||
MODULE_DESCRIPTION("EZUSB device support");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -127,5 +127,6 @@ static struct usb_driver isight_firmware_driver = {
|
||||
|
||||
module_usb_driver(isight_firmware_driver);
|
||||
|
||||
MODULE_DESCRIPTION("iSight firmware loading support");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
|
||||
|
@ -454,16 +454,18 @@ static struct onboard_dev *_find_onboard_dev(struct device *dev)
|
||||
return onboard_dev;
|
||||
}
|
||||
|
||||
static bool onboard_dev_usbdev_match(struct usb_device *udev)
|
||||
{
|
||||
/* Onboard devices using this driver must have a device tree node */
|
||||
return !!udev->dev.of_node;
|
||||
}
|
||||
|
||||
static int onboard_dev_usbdev_probe(struct usb_device *udev)
|
||||
{
|
||||
struct device *dev = &udev->dev;
|
||||
struct onboard_dev *onboard_dev;
|
||||
int err;
|
||||
|
||||
/* ignore supported devices without device tree node */
|
||||
if (!dev->of_node)
|
||||
return -ENODEV;
|
||||
|
||||
onboard_dev = _find_onboard_dev(dev);
|
||||
if (IS_ERR(onboard_dev))
|
||||
return PTR_ERR(onboard_dev);
|
||||
@ -513,6 +515,7 @@ MODULE_DEVICE_TABLE(usb, onboard_dev_id_table);
|
||||
|
||||
static struct usb_device_driver onboard_dev_usbdev_driver = {
|
||||
.name = "onboard-usb-dev",
|
||||
.match = onboard_dev_usbdev_match,
|
||||
.probe = onboard_dev_usbdev_probe,
|
||||
.disconnect = onboard_dev_usbdev_disconnect,
|
||||
.generic_subclass = 1,
|
||||
|
@ -726,15 +726,15 @@ static int __maybe_unused usb251xb_resume(struct device *dev)
|
||||
static SIMPLE_DEV_PM_OPS(usb251xb_pm_ops, usb251xb_suspend, usb251xb_resume);
|
||||
|
||||
static const struct i2c_device_id usb251xb_id[] = {
|
||||
{ "usb2422", 0 },
|
||||
{ "usb2512b", 0 },
|
||||
{ "usb2512bi", 0 },
|
||||
{ "usb2513b", 0 },
|
||||
{ "usb2513bi", 0 },
|
||||
{ "usb2514b", 0 },
|
||||
{ "usb2514bi", 0 },
|
||||
{ "usb2517", 0 },
|
||||
{ "usb2517i", 0 },
|
||||
{ "usb2422" },
|
||||
{ "usb2512b" },
|
||||
{ "usb2512bi" },
|
||||
{ "usb2513b" },
|
||||
{ "usb2513bi" },
|
||||
{ "usb2514b" },
|
||||
{ "usb2514bi" },
|
||||
{ "usb2517" },
|
||||
{ "usb2517i" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, usb251xb_id);
|
||||
|
@ -390,7 +390,7 @@ static SIMPLE_DEV_PM_OPS(usb3503_platform_pm_ops, usb3503_platform_suspend,
|
||||
usb3503_platform_resume);
|
||||
|
||||
static const struct i2c_device_id usb3503_id[] = {
|
||||
{ USB3503_I2C_NAME, 0 },
|
||||
{ USB3503_I2C_NAME },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, usb3503_id);
|
||||
|
@ -135,7 +135,7 @@ static SIMPLE_DEV_PM_OPS(usb4604_i2c_pm_ops, usb4604_i2c_suspend,
|
||||
usb4604_i2c_resume);
|
||||
|
||||
static const struct i2c_device_id usb4604_id[] = {
|
||||
{ "usb4604", 0 },
|
||||
{ "usb4604" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, usb4604_id);
|
||||
|
@ -531,4 +531,5 @@ static const struct file_operations yurex_fops = {
|
||||
|
||||
module_usb_driver(yurex_driver);
|
||||
|
||||
MODULE_DESCRIPTION("USB YUREX driver support");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -419,4 +419,5 @@ static void __exit mon_exit(void)
|
||||
module_init(mon_init);
|
||||
module_exit(mon_exit);
|
||||
|
||||
MODULE_DESCRIPTION("USB Monitor");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -191,7 +191,7 @@ static void otg_timer(struct timer_list *t)
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
}
|
||||
|
||||
static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
|
||||
static void __maybe_unused da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
|
||||
{
|
||||
static unsigned long last_timer;
|
||||
|
||||
@ -220,6 +220,13 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
|
||||
mod_timer(&musb->dev_timer, timeout);
|
||||
}
|
||||
|
||||
static int da8xx_babble_recover(struct musb *musb)
|
||||
{
|
||||
dev_dbg(musb->controller, "resetting controller to recover from babble\n");
|
||||
musb_writel(musb->ctrl_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
|
||||
{
|
||||
struct musb *musb = hci;
|
||||
@ -328,13 +335,6 @@ static int da8xx_musb_set_mode(struct musb *musb, u8 musb_mode)
|
||||
struct da8xx_glue *glue = dev_get_drvdata(musb->controller->parent);
|
||||
enum phy_mode phy_mode;
|
||||
|
||||
/*
|
||||
* The PHY has some issues when it is forced in device or host mode.
|
||||
* Unless the user request another mode, configure the PHY in OTG mode.
|
||||
*/
|
||||
if (!musb->is_initialized)
|
||||
return phy_set_mode(glue->phy, PHY_MODE_USB_OTG);
|
||||
|
||||
switch (musb_mode) {
|
||||
case MUSB_HOST: /* Force VBUS valid, ID = 0 */
|
||||
phy_mode = PHY_MODE_USB_HOST;
|
||||
@ -483,7 +483,11 @@ static const struct musb_platform_ops da8xx_ops = {
|
||||
.disable = da8xx_musb_disable,
|
||||
|
||||
.set_mode = da8xx_musb_set_mode,
|
||||
|
||||
#ifndef CONFIG_USB_MUSB_HOST
|
||||
.try_idle = da8xx_musb_try_idle,
|
||||
#endif
|
||||
.recover = da8xx_babble_recover,
|
||||
|
||||
.set_vbus = da8xx_musb_set_vbus,
|
||||
};
|
||||
|
@ -190,6 +190,8 @@ static int mpfs_probe(struct platform_device *pdev)
|
||||
pdata->config = &mpfs_musb_hdrc_config;
|
||||
pdata->platform_ops = &mpfs_ops;
|
||||
|
||||
pdata->extvbus = device_property_read_bool(dev, "microchip,ext-vbus-drv");
|
||||
|
||||
pdata->mode = usb_get_dr_mode(dev);
|
||||
if (pdata->mode == USB_DR_MODE_UNKNOWN) {
|
||||
dev_info(dev, "No dr_mode property found, defaulting to otg\n");
|
||||
|
@ -189,4 +189,5 @@ static struct platform_driver am335x_control_driver = {
|
||||
};
|
||||
|
||||
module_platform_driver(am335x_control_driver);
|
||||
MODULE_DESCRIPTION("AM335x USB PHY Control Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -142,4 +142,5 @@ static struct platform_driver am335x_phy_driver = {
|
||||
};
|
||||
|
||||
module_platform_driver(am335x_phy_driver);
|
||||
MODULE_DESCRIPTION("AM335x USB PHY Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -423,6 +423,7 @@ static void uas_data_cmplt(struct urb *urb)
|
||||
uas_log_cmd_state(cmnd, "data cmplt err", status);
|
||||
/* error: no data transfered */
|
||||
scsi_set_resid(cmnd, sdb->length);
|
||||
set_host_byte(cmnd, DID_ERROR);
|
||||
} else {
|
||||
scsi_set_resid(cmnd, sdb->length - urb->actual_length);
|
||||
}
|
||||
@ -1232,9 +1233,8 @@ static void uas_disconnect(struct usb_interface *intf)
|
||||
* hang on reboot when the device is still in uas mode. Note the reset is
|
||||
* necessary as some devices won't revert to usb-storage mode without it.
|
||||
*/
|
||||
static void uas_shutdown(struct device *dev)
|
||||
static void uas_shutdown(struct usb_interface *intf)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
struct Scsi_Host *shost = usb_get_intfdata(intf);
|
||||
struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
|
||||
@ -1257,7 +1257,7 @@ static struct usb_driver uas_driver = {
|
||||
.suspend = uas_suspend,
|
||||
.resume = uas_resume,
|
||||
.reset_resume = uas_reset_resume,
|
||||
.driver.shutdown = uas_shutdown,
|
||||
.shutdown = uas_shutdown,
|
||||
.id_table = uas_usb_ids,
|
||||
};
|
||||
|
||||
@ -1287,6 +1287,7 @@ static void __exit uas_exit(void)
|
||||
module_init(uas_init);
|
||||
module_exit(uas_exit);
|
||||
|
||||
MODULE_DESCRIPTION("USB Attached SCSI driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(USB_STORAGE);
|
||||
MODULE_AUTHOR(
|
||||
|
@ -68,9 +68,102 @@ MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
|
||||
MODULE_DESCRIPTION("USB Mass Storage driver for Linux");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static unsigned int delay_use = 1;
|
||||
module_param(delay_use, uint, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
|
||||
static unsigned int delay_use = 1 * MSEC_PER_SEC;
|
||||
|
||||
/**
|
||||
* parse_delay_str - parse an unsigned decimal integer delay
|
||||
* @str: String to parse.
|
||||
* @ndecimals: Number of decimal to scale up.
|
||||
* @suffix: Suffix string to parse.
|
||||
* @val: Where to store the parsed value.
|
||||
*
|
||||
* Parse an unsigned decimal value in @str, optionally end with @suffix.
|
||||
* Stores the parsed value in @val just as it is if @str ends with @suffix.
|
||||
* Otherwise store the value scale up by 10^(@ndecimal).
|
||||
*
|
||||
* Returns 0 on success, a negative error code otherwise.
|
||||
*/
|
||||
static int parse_delay_str(const char *str, int ndecimals, const char *suffix,
|
||||
unsigned int *val)
|
||||
{
|
||||
int n, n2, l;
|
||||
char buf[16];
|
||||
|
||||
l = strlen(suffix);
|
||||
n = strlen(str);
|
||||
if (n > 0 && str[n - 1] == '\n')
|
||||
--n;
|
||||
if (n >= l && !strncmp(&str[n - l], suffix, l)) {
|
||||
n -= l;
|
||||
n2 = 0;
|
||||
} else
|
||||
n2 = ndecimals;
|
||||
|
||||
if (n + n2 > sizeof(buf) - 1)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(buf, str, n);
|
||||
while (n2-- > 0)
|
||||
buf[n++] = '0';
|
||||
buf[n] = 0;
|
||||
|
||||
return kstrtouint(buf, 10, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* format_delay_ms - format an integer value into a delay string
|
||||
* @val: The integer value to format, scaled by 10^(@ndecimals).
|
||||
* @ndecimals: Number of decimal to scale down.
|
||||
* @suffix: Suffix string to format.
|
||||
* @str: Where to store the formatted string.
|
||||
* @size: The size of buffer for @str.
|
||||
*
|
||||
* Format an integer value in @val scale down by 10^(@ndecimals) without @suffix
|
||||
* if @val is divisible by 10^(@ndecimals).
|
||||
* Otherwise format a value in @val just as it is with @suffix
|
||||
*
|
||||
* Returns the number of characters written into @str.
|
||||
*/
|
||||
static int format_delay_ms(unsigned int val, int ndecimals, const char *suffix,
|
||||
char *str, int size)
|
||||
{
|
||||
u64 delay_ms = val;
|
||||
unsigned int rem = do_div(delay_ms, int_pow(10, ndecimals));
|
||||
int ret;
|
||||
|
||||
if (rem)
|
||||
ret = scnprintf(str, size, "%u%s\n", val, suffix);
|
||||
else
|
||||
ret = scnprintf(str, size, "%u\n", (unsigned int)delay_ms);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int delay_use_set(const char *s, const struct kernel_param *kp)
|
||||
{
|
||||
unsigned int delay_ms;
|
||||
int ret;
|
||||
|
||||
ret = parse_delay_str(skip_spaces(s), 3, "ms", &delay_ms);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*((unsigned int *)kp->arg) = delay_ms;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int delay_use_get(char *s, const struct kernel_param *kp)
|
||||
{
|
||||
unsigned int delay_ms = *((unsigned int *)kp->arg);
|
||||
|
||||
return format_delay_ms(delay_ms, 3, "ms", s, PAGE_SIZE);
|
||||
}
|
||||
|
||||
static const struct kernel_param_ops delay_use_ops = {
|
||||
.set = delay_use_set,
|
||||
.get = delay_use_get,
|
||||
};
|
||||
module_param_cb(delay_use, &delay_use_ops, &delay_use, 0644);
|
||||
MODULE_PARM_DESC(delay_use, "time to delay before using a new device");
|
||||
|
||||
static char quirks[128];
|
||||
module_param_string(quirks, quirks, sizeof(quirks), S_IRUGO | S_IWUSR);
|
||||
@ -1064,7 +1157,7 @@ int usb_stor_probe2(struct us_data *us)
|
||||
if (delay_use > 0)
|
||||
dev_dbg(dev, "waiting for device to settle before scanning\n");
|
||||
queue_delayed_work(system_freezable_wq, &us->scan_dwork,
|
||||
delay_use * HZ);
|
||||
msecs_to_jiffies(delay_use));
|
||||
return 0;
|
||||
|
||||
/* We come here if there are any problems */
|
||||
|
@ -746,7 +746,7 @@ int dp_altmode_probe(struct typec_altmode *alt)
|
||||
dp->alt = alt;
|
||||
|
||||
alt->desc = "DisplayPort";
|
||||
alt->ops = &dp_altmode_ops;
|
||||
typec_altmode_set_ops(alt, &dp_altmode_ops);
|
||||
|
||||
if (plug) {
|
||||
plug->desc = "Displayport";
|
||||
|
@ -1566,7 +1566,7 @@ static void anx7411_i2c_remove(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id anx7411_id[] = {
|
||||
{"anx7411", 0},
|
||||
{ "anx7411" },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -467,6 +467,22 @@ static const struct attribute_group *typec_altmode_groups[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* typec_altmode_set_ops - Set ops for altmode
|
||||
* @adev: Handle to the alternate mode
|
||||
* @ops: Ops for the alternate mode
|
||||
*
|
||||
* After setting ops, attribute visiblity needs to be refreshed if the alternate
|
||||
* mode can be activated.
|
||||
*/
|
||||
void typec_altmode_set_ops(struct typec_altmode *adev,
|
||||
const struct typec_altmode_ops *ops)
|
||||
{
|
||||
adev->ops = ops;
|
||||
sysfs_update_group(&adev->dev.kobj, &typec_altmode_group);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(typec_altmode_set_ops);
|
||||
|
||||
static int altmode_id_get(struct device *dev)
|
||||
{
|
||||
struct ida *ids;
|
||||
@ -2317,7 +2333,7 @@ void typec_port_register_altmodes(struct typec_port *port,
|
||||
continue;
|
||||
}
|
||||
|
||||
alt->ops = ops;
|
||||
typec_altmode_set_ops(alt, ops);
|
||||
typec_altmode_set_drvdata(alt, drvdata);
|
||||
altmodes[index] = alt;
|
||||
index++;
|
||||
|
@ -66,6 +66,9 @@ static int gpio_sbu_mux_set(struct typec_mux_dev *mux,
|
||||
{
|
||||
struct gpio_sbu_mux *sbu_mux = typec_mux_get_drvdata(mux);
|
||||
|
||||
if (!sbu_mux->enable_gpio)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mutex_lock(&sbu_mux->lock);
|
||||
|
||||
switch (state->mode) {
|
||||
@ -102,7 +105,8 @@ static int gpio_sbu_mux_probe(struct platform_device *pdev)
|
||||
|
||||
mutex_init(&sbu_mux->lock);
|
||||
|
||||
sbu_mux->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
|
||||
sbu_mux->enable_gpio = devm_gpiod_get_optional(dev, "enable",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(sbu_mux->enable_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(sbu_mux->enable_gpio),
|
||||
"unable to acquire enable gpio\n");
|
||||
|
@ -69,6 +69,7 @@ struct nb7vpq904m {
|
||||
|
||||
bool swap_data_lanes;
|
||||
struct typec_switch *typec_switch;
|
||||
struct typec_mux *typec_mux;
|
||||
|
||||
struct mutex lock; /* protect non-concurrent retimer & switch */
|
||||
|
||||
@ -275,6 +276,7 @@ static int nb7vpq904m_sw_set(struct typec_switch_dev *sw, enum typec_orientation
|
||||
static int nb7vpq904m_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state)
|
||||
{
|
||||
struct nb7vpq904m *nb7 = typec_retimer_get_drvdata(retimer);
|
||||
struct typec_mux_state mux_state;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&nb7->lock);
|
||||
@ -292,7 +294,14 @@ static int nb7vpq904m_retimer_set(struct typec_retimer *retimer, struct typec_re
|
||||
|
||||
mutex_unlock(&nb7->lock);
|
||||
|
||||
return ret;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mux_state.alt = state->alt;
|
||||
mux_state.data = state->data;
|
||||
mux_state.mode = state->mode;
|
||||
|
||||
return typec_mux_set(nb7->typec_mux, &mux_state);
|
||||
}
|
||||
|
||||
static const struct regmap_config nb7_regmap = {
|
||||
@ -321,46 +330,48 @@ static int nb7vpq904m_parse_data_lanes_mapping(struct nb7vpq904m *nb7)
|
||||
|
||||
ep = of_graph_get_endpoint_by_regs(nb7->client->dev.of_node, 1, 0);
|
||||
|
||||
if (ep) {
|
||||
ret = of_property_count_u32_elems(ep, "data-lanes");
|
||||
if (ret == -EINVAL)
|
||||
/* Property isn't here, consider default mapping */
|
||||
goto out_done;
|
||||
if (ret < 0)
|
||||
goto out_error;
|
||||
if (!ep)
|
||||
return 0;
|
||||
|
||||
if (ret != DATA_LANES_COUNT) {
|
||||
dev_err(&nb7->client->dev, "expected 4 data lanes\n");
|
||||
ret = -EINVAL;
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32_array(ep, "data-lanes", data_lanes, DATA_LANES_COUNT);
|
||||
if (ret)
|
||||
goto out_error;
|
||||
ret = of_property_count_u32_elems(ep, "data-lanes");
|
||||
if (ret == -EINVAL)
|
||||
/* Property isn't here, consider default mapping */
|
||||
goto out_done;
|
||||
if (ret < 0)
|
||||
goto out_error;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(supported_data_lane_mapping); i++) {
|
||||
for (j = 0; j < DATA_LANES_COUNT; j++) {
|
||||
if (data_lanes[j] != supported_data_lane_mapping[i][j])
|
||||
break;
|
||||
}
|
||||
if (ret != DATA_LANES_COUNT) {
|
||||
dev_err(&nb7->client->dev, "expected 4 data lanes\n");
|
||||
ret = -EINVAL;
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
if (j == DATA_LANES_COUNT)
|
||||
ret = of_property_read_u32_array(ep, "data-lanes", data_lanes, DATA_LANES_COUNT);
|
||||
if (ret)
|
||||
goto out_error;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(supported_data_lane_mapping); i++) {
|
||||
for (j = 0; j < DATA_LANES_COUNT; j++) {
|
||||
if (data_lanes[j] != supported_data_lane_mapping[i][j])
|
||||
break;
|
||||
}
|
||||
|
||||
switch (i) {
|
||||
case NORMAL_LANE_MAPPING:
|
||||
if (j == DATA_LANES_COUNT)
|
||||
break;
|
||||
case INVERT_LANE_MAPPING:
|
||||
nb7->swap_data_lanes = true;
|
||||
dev_info(&nb7->client->dev, "using inverted data lanes mapping\n");
|
||||
break;
|
||||
default:
|
||||
dev_err(&nb7->client->dev, "invalid data lanes mapping\n");
|
||||
ret = -EINVAL;
|
||||
goto out_error;
|
||||
}
|
||||
}
|
||||
|
||||
switch (i) {
|
||||
case NORMAL_LANE_MAPPING:
|
||||
break;
|
||||
case INVERT_LANE_MAPPING:
|
||||
nb7->swap_data_lanes = true;
|
||||
dev_info(&nb7->client->dev, "using inverted data lanes mapping\n");
|
||||
break;
|
||||
default:
|
||||
dev_err(&nb7->client->dev, "invalid data lanes mapping\n");
|
||||
ret = -EINVAL;
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
out_done:
|
||||
@ -411,9 +422,16 @@ static int nb7vpq904m_probe(struct i2c_client *client)
|
||||
return dev_err_probe(dev, PTR_ERR(nb7->typec_switch),
|
||||
"failed to acquire orientation-switch\n");
|
||||
|
||||
nb7->typec_mux = fwnode_typec_mux_get(dev->fwnode);
|
||||
if (IS_ERR(nb7->typec_mux)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(nb7->typec_mux),
|
||||
"Failed to acquire mode-switch\n");
|
||||
goto err_switch_put;
|
||||
}
|
||||
|
||||
ret = nb7vpq904m_parse_data_lanes_mapping(nb7);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_mux_put;
|
||||
|
||||
ret = regulator_enable(nb7->vcc_supply);
|
||||
if (ret)
|
||||
@ -456,6 +474,12 @@ err_disable_gpio:
|
||||
gpiod_set_value(nb7->enable_gpio, 0);
|
||||
regulator_disable(nb7->vcc_supply);
|
||||
|
||||
err_mux_put:
|
||||
typec_mux_put(nb7->typec_mux);
|
||||
|
||||
err_switch_put:
|
||||
typec_switch_put(nb7->typec_switch);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -469,6 +493,9 @@ static void nb7vpq904m_remove(struct i2c_client *client)
|
||||
gpiod_set_value(nb7->enable_gpio, 0);
|
||||
|
||||
regulator_disable(nb7->vcc_supply);
|
||||
|
||||
typec_mux_put(nb7->typec_mux);
|
||||
typec_switch_put(nb7->typec_switch);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id nb7vpq904m_table[] = {
|
||||
|
@ -67,6 +67,7 @@ struct ptn36502 {
|
||||
struct typec_retimer *retimer;
|
||||
|
||||
struct typec_switch *typec_switch;
|
||||
struct typec_mux *typec_mux;
|
||||
|
||||
struct mutex lock; /* protect non-concurrent retimer & switch */
|
||||
|
||||
@ -235,6 +236,7 @@ static int ptn36502_sw_set(struct typec_switch_dev *sw, enum typec_orientation o
|
||||
static int ptn36502_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state)
|
||||
{
|
||||
struct ptn36502 *ptn = typec_retimer_get_drvdata(retimer);
|
||||
struct typec_mux_state mux_state;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&ptn->lock);
|
||||
@ -252,7 +254,14 @@ static int ptn36502_retimer_set(struct typec_retimer *retimer, struct typec_reti
|
||||
|
||||
mutex_unlock(&ptn->lock);
|
||||
|
||||
return ret;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mux_state.alt = state->alt;
|
||||
mux_state.data = state->data;
|
||||
mux_state.mode = state->mode;
|
||||
|
||||
return typec_mux_set(ptn->typec_mux, &mux_state);
|
||||
}
|
||||
|
||||
static int ptn36502_detect(struct ptn36502 *ptn)
|
||||
@ -321,9 +330,18 @@ static int ptn36502_probe(struct i2c_client *client)
|
||||
return dev_err_probe(dev, PTR_ERR(ptn->typec_switch),
|
||||
"Failed to acquire orientation-switch\n");
|
||||
|
||||
ptn->typec_mux = fwnode_typec_mux_get(dev->fwnode);
|
||||
if (IS_ERR(ptn->typec_mux)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(ptn->typec_mux),
|
||||
"Failed to acquire mode-switch\n");
|
||||
goto err_switch_put;
|
||||
}
|
||||
|
||||
ret = regulator_enable(ptn->vdd18_supply);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to enable vdd18\n");
|
||||
if (ret) {
|
||||
ret = dev_err_probe(dev, ret, "Failed to enable vdd18\n");
|
||||
goto err_mux_put;
|
||||
}
|
||||
|
||||
ret = ptn36502_detect(ptn);
|
||||
if (ret)
|
||||
@ -363,6 +381,12 @@ err_switch_unregister:
|
||||
err_disable_regulator:
|
||||
regulator_disable(ptn->vdd18_supply);
|
||||
|
||||
err_mux_put:
|
||||
typec_mux_put(ptn->typec_mux);
|
||||
|
||||
err_switch_put:
|
||||
typec_switch_put(ptn->typec_switch);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -374,6 +398,9 @@ static void ptn36502_remove(struct i2c_client *client)
|
||||
typec_switch_unregister(ptn->sw);
|
||||
|
||||
regulator_disable(ptn->vdd18_supply);
|
||||
|
||||
typec_mux_put(ptn->typec_mux);
|
||||
typec_switch_put(ptn->typec_switch);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ptn36502_table[] = {
|
||||
|
@ -1820,8 +1820,8 @@ static const struct of_device_id fusb302_dt_match[] __maybe_unused = {
|
||||
MODULE_DEVICE_TABLE(of, fusb302_dt_match);
|
||||
|
||||
static const struct i2c_device_id fusb302_i2c_device_id[] = {
|
||||
{"typec_fusb302", 0},
|
||||
{},
|
||||
{ "typec_fusb302" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, fusb302_i2c_device_id);
|
||||
|
||||
|
@ -67,6 +67,18 @@ static int tcpci_write16(struct tcpci *tcpci, unsigned int reg, u16 val)
|
||||
return regmap_raw_write(tcpci->regmap, reg, &val, sizeof(u16));
|
||||
}
|
||||
|
||||
static bool tcpci_check_std_output_cap(struct regmap *regmap, u8 mask)
|
||||
{
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(regmap, TCPC_STD_OUTPUT_CAP, ®);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return (reg & mask) == mask;
|
||||
}
|
||||
|
||||
static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
|
||||
{
|
||||
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
|
||||
@ -301,6 +313,28 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
|
||||
TCPC_TCPC_CTRL_ORIENTATION : 0);
|
||||
}
|
||||
|
||||
static int tcpci_set_orientation(struct tcpc_dev *tcpc,
|
||||
enum typec_orientation orientation)
|
||||
{
|
||||
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
|
||||
unsigned int reg;
|
||||
|
||||
switch (orientation) {
|
||||
case TYPEC_ORIENTATION_NONE:
|
||||
/* We can't put a single output into high impedance */
|
||||
fallthrough;
|
||||
case TYPEC_ORIENTATION_NORMAL:
|
||||
reg = TCPC_CONFIG_STD_OUTPUT_ORIENTATION_NORMAL;
|
||||
break;
|
||||
case TYPEC_ORIENTATION_REVERSE:
|
||||
reg = TCPC_CONFIG_STD_OUTPUT_ORIENTATION_FLIPPED;
|
||||
break;
|
||||
}
|
||||
|
||||
return regmap_update_bits(tcpci->regmap, TCPC_CONFIG_STD_OUTPUT,
|
||||
TCPC_CONFIG_STD_OUTPUT_ORIENTATION_MASK, reg);
|
||||
}
|
||||
|
||||
static void tcpci_set_partner_usb_comm_capable(struct tcpc_dev *tcpc, bool capable)
|
||||
{
|
||||
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
|
||||
@ -830,6 +864,9 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
|
||||
if (tcpci->data->vbus_vsafe0v)
|
||||
tcpci->tcpc.is_vbus_vsafe0v = tcpci_is_vbus_vsafe0v;
|
||||
|
||||
if (tcpci->data->set_orientation)
|
||||
tcpci->tcpc.set_orientation = tcpci_set_orientation;
|
||||
|
||||
err = tcpci_parse_config(tcpci);
|
||||
if (err < 0)
|
||||
return ERR_PTR(err);
|
||||
@ -873,6 +910,13 @@ static int tcpci_probe(struct i2c_client *client)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = tcpci_check_std_output_cap(chip->data.regmap,
|
||||
TCPC_STD_OUTPUT_CAP_ORIENTATION);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
chip->data.set_orientation = err;
|
||||
|
||||
chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
|
||||
if (IS_ERR(chip->tcpci))
|
||||
return PTR_ERR(chip->tcpci);
|
||||
@ -903,7 +947,7 @@ static void tcpci_remove(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tcpci_id[] = {
|
||||
{ "tcpci", 0 },
|
||||
{ "tcpci" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tcpci_id);
|
||||
|
@ -538,7 +538,7 @@ static void max_tcpci_remove(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max_tcpci_id[] = {
|
||||
{ "maxtcpc", 0 },
|
||||
{ "maxtcpc" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max_tcpci_id);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user