USB / PHY patches for 5.3-rc1

Here is the big USB and PHY driver pull request for 5.3-rc1.
 
 Lots of stuff here, all of which has been in linux-next for a while with
 no reported issues.  Nothing is earth-shattering, just constant forward
 progress for more devices supported and cleanups and small fixes:
   - USB gadget driver updates and fixes
   - new USB gadget driver for some hardware, followed by a quick revert
     of those patches as they were not ready to be merged...
   - PHY driver updates
   - Lots of new driver additions and cleanups with a few fixes mixed in.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXSXjYA8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ynMYACgnSRP3GylwMywrkc9paVmDeiIgNwAn0N2sika
 JEW7C3lkBJZJ7R6V/Ynm
 =drla
 -----END PGP SIGNATURE-----

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

Pull USB / PHY updates from Greg KH:
 "Here is the big USB and PHY driver pull request for 5.3-rc1.

  Lots of stuff here, all of which has been in linux-next for a while
  with no reported issues. Nothing is earth-shattering, just constant
  forward progress for more devices supported and cleanups and small
  fixes:

   - USB gadget driver updates and fixes

   - new USB gadget driver for some hardware, followed by a quick revert
     of those patches as they were not ready to be merged...

   - PHY driver updates

   - Lots of new driver additions and cleanups with a few fixes mixed
     in"

* tag 'usb-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (145 commits)
  Revert "usb: gadget: storage: Remove warning message"
  Revert "dt-bindings: add binding for USBSS-DRD controller."
  Revert "usb:gadget Separated decoding functions from dwc3 driver."
  Revert "usb:gadget Patch simplify usb_decode_set_clear_feature function."
  Revert "usb:gadget Simplify usb_decode_get_set_descriptor function."
  Revert "usb:cdns3 Add Cadence USB3 DRD Driver"
  Revert "usb:cdns3 Fix for stuck packets in on-chip OUT buffer."
  usb :fsl: Change string format for errata property
  usb: host: Stops USB controller init if PLL fails to lock
  usb: linux/fsl_device: Add platform member has_fsl_erratum_a006918
  usb: phy: Workaround for USB erratum-A005728
  usb: fsl: Set USB_EN bit to select ULPI phy
  usb: Handle USB3 remote wakeup for LPM enabled devices correctly
  drivers/usb/typec/tps6598x.c: fix 4CC cmd write
  drivers/usb/typec/tps6598x.c: fix portinfo width
  usb: storage: scsiglue: Do not skip VPD if try_vpd_pages is set
  usb: renesas_usbhs: add a workaround for a race condition of workqueue
  usb: gadget: udc: renesas_usb3: remove redundant assignment to ret
  usb: dwc2: use a longer AHB idle timeout in dwc2_core_reset()
  USB: gadget: function: fix issue Unneeded variable: "value"
  ...
This commit is contained in:
Linus Torvalds 2019-07-11 15:40:06 -07:00
commit 17a20acaf1
176 changed files with 2348 additions and 750 deletions

View File

@ -0,0 +1,29 @@
Mixel DSI PHY for i.MX8
The Mixel MIPI-DSI PHY IP block is e.g. found on i.MX8 platforms (along the
MIPI-DSI IP from Northwest Logic). It represents the physical layer for the
electrical signals for DSI.
Required properties:
- compatible: Must be:
- "fsl,imx8mq-mipi-dphy"
- clocks: Must contain an entry for each entry in clock-names.
- clock-names: Must contain the following entries:
- "phy_ref": phandle and specifier referring to the DPHY ref clock
- reg: the register range of the PHY controller
- #phy-cells: number of cells in PHY, as defined in
Documentation/devicetree/bindings/phy/phy-bindings.txt
this must be <0>
Optional properties:
- power-domains: phandle to power domain
Example:
dphy: dphy@30a0030 {
compatible = "fsl,imx8mq-mipi-dphy";
clocks = <&clk IMX8MQ_CLK_DSI_PHY_REF>;
clock-names = "phy_ref";
reg = <0x30a00300 0x100>;
power-domains = <&pd_mipi0>;
#phy-cells = <0>;
};

View File

@ -7,6 +7,7 @@ Required properties:
* "fsl,imx6sl-usbphy" for imx6sl
* "fsl,vf610-usbphy" for Vybrid vf610
* "fsl,imx6sx-usbphy" for imx6sx
* "fsl,imx7ulp-usbphy" for imx7ulp
"fsl,imx23-usbphy" is still a fallback for other strings
- reg: Should contain registers location and length
- interrupts: Should contain phy interrupt
@ -23,7 +24,7 @@ Optional properties:
the 17.78mA TX reference current. Default: 100
Example:
usbphy1: usbphy@20c9000 {
usbphy1: usb-phy@20c9000 {
compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy";
reg = <0x020c9000 0x1000>;
interrupts = <0 44 0x04>;

View File

@ -42,6 +42,18 @@ Required properties:
- reset-names: Must include the following entries:
- "padctl"
For Tegra124:
- avdd-pll-utmip-supply: UTMI PLL power supply. Must supply 1.8 V.
- avdd-pll-erefe-supply: PLLE reference PLL power supply. Must supply 1.05 V.
- avdd-pex-pll-supply: PCIe/USB3 PLL power supply. Must supply 1.05 V.
- hvdd-pex-pll-e-supply: High-voltage PLLE power supply. Must supply 3.3 V.
For Tegra210:
- avdd-pll-utmip-supply: UTMI PLL power supply. Must supply 1.8 V.
- avdd-pll-uerefe-supply: PLLE reference PLL power supply. Must supply 1.05 V.
- dvdd-pex-pll-supply: PCIe/USB3 PLL power supply. Must supply 1.05 V.
- hvdd-pex-pll-e-supply: High-voltage PLLE power supply. Must supply 1.8 V.
For Tegra186:
- avdd-pll-erefeut-supply: UPHY brick and reference clock as well as UTMI PHY
power supply. Must supply 1.8 V.

View File

@ -0,0 +1,18 @@
Marvell PXA USB PHY
-------------------
Required properties:
- compatible: one of: "marvell,mmp2-usb-phy", "marvell,pxa910-usb-phy",
"marvell,pxa168-usb-phy",
- #phy-cells: must be 0
Example:
usb-phy: usbphy@d4207000 {
compatible = "marvell,mmp2-usb-phy";
reg = <0xd4207000 0x40>;
#phy-cells = <0>;
status = "okay";
};
This document explains the device tree binding. For general
information about PHY subsystem refer to Documentation/phy.txt

View File

@ -0,0 +1,42 @@
Qualcomm PCIe2 PHY controller
=============================
The Qualcomm PCIe2 PHY is a Synopsys based phy found in a number of Qualcomm
platforms.
Required properties:
- compatible: compatible list, should be:
"qcom,qcs404-pcie2-phy", "qcom,pcie2-phy"
- reg: offset and length of the PHY register set.
- #phy-cells: must be 0.
- clocks: a clock-specifier pair for the "pipe" clock
- vdda-vp-supply: phandle to low voltage regulator
- vdda-vph-supply: phandle to high voltage regulator
- resets: reset-specifier pairs for the "phy" and "pipe" resets
- reset-names: list of resets, should contain:
"phy" and "pipe"
- clock-output-names: name of the outgoing clock signal from the PHY PLL
- #clock-cells: must be 0
Example:
phy@7786000 {
compatible = "qcom,qcs404-pcie2-phy", "qcom,pcie2-phy";
reg = <0x07786000 0xb8>;
clocks = <&gcc GCC_PCIE_0_PIPE_CLK>;
resets = <&gcc GCC_PCIEPHY_0_PHY_BCR>,
<&gcc GCC_PCIE_0_PIPE_ARES>;
reset-names = "phy", "pipe";
vdda-vp-supply = <&vreg_l3_1p05>;
vdda-vph-supply = <&vreg_l5_1p8>;
clock-output-names = "pcie_0_pipe_clk";
#clock-cells = <0>;
#phy-cells = <0>;
};

View File

@ -1,10 +1,12 @@
* Renesas R-Car generation 3 USB 2.0 PHY
This file provides information on what the device node for the R-Car generation
3, RZ/G1C and RZ/G2 USB 2.0 PHY contain.
3, RZ/G1C, RZ/G2 and RZ/A2 USB 2.0 PHY contain.
Required properties:
- compatible: "renesas,usb2-phy-r8a77470" if the device is a part of an R8A77470
- compatible: "renesas,usb2-phy-r7s9210" if the device is a part of an R7S9210
SoC.
"renesas,usb2-phy-r8a77470" if the device is a part of an R8A77470
SoC.
"renesas,usb2-phy-r8a774a1" if the device is a part of an R8A774A1
SoC.
@ -20,8 +22,8 @@ Required properties:
R8A77990 SoC.
"renesas,usb2-phy-r8a77995" if the device is a part of an
R8A77995 SoC.
"renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 or RZ/G2
compatible device.
"renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3, RZ/G2 or
RZ/A2 compatible device.
When compatible with the generic version, nodes must list the
SoC-specific version corresponding to the platform first
@ -46,6 +48,9 @@ channel as USB OTG:
regulator will be managed during the PHY power on/off sequence.
- renesas,no-otg-pins: boolean, specify when a board does not provide proper
otg pins.
- dr_mode: string, indicates the working mode for the PHY. Can be "host",
"peripheral", or "otg". Should be set if otg controller is not used.
Example (R-Car H3):

View File

@ -42,6 +42,8 @@ Refer to phy/phy-bindings.txt for generic phy consumer properties
- g-rx-fifo-size: size of rx fifo size in gadget mode.
- g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget mode.
- g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) in gadget mode.
- snps,need-phy-for-wake: If present indicates that the phy needs to be left
on for remote wakeup during suspend.
- snps,reset-phy-on-wake: If present indicates that we need to reset the PHY when
we detect a wakeup. This is due to a hardware errata.
@ -58,4 +60,5 @@ Example:
clock-names = "otg";
phys = <&usbphy>;
phy-names = "usb2-phy";
snps,need-phy-for-wake;
};

View File

@ -64,6 +64,8 @@ Optional properties:
- snps,dis_u2_susphy_quirk: when set core will disable USB2 suspend phy.
- snps,dis_enblslpm_quirk: when set clears the enblslpm in GUSB2PHYCFG,
disabling the suspend signal to the PHY.
- snps,dis-u1-entry-quirk: set if link entering into U1 needs to be disabled.
- snps,dis-u2-entry-quirk: set if link entering into U2 needs to be disabled.
- snps,dis_rxdet_inp3_quirk: when set core will disable receiver detection
in PHY P3 power state.
- snps,dis-u2-freeclk-exists-quirk: when set, clear the u2_freeclk_exists

View File

@ -20,9 +20,11 @@ Required properties:
- "renesas,usbhs-r8a77990" for r8a77990 (R-Car E3) compatible device
- "renesas,usbhs-r8a77995" for r8a77995 (R-Car D3) compatible device
- "renesas,usbhs-r7s72100" for r7s72100 (RZ/A1) compatible device
- "renesas,usbhs-r7s9210" for r7s9210 (RZ/A2) compatible device
- "renesas,rcar-gen2-usbhs" for R-Car Gen2 or RZ/G1 compatible devices
- "renesas,rcar-gen3-usbhs" for R-Car Gen3 or RZ/G2 compatible devices
- "renesas,rza1-usbhs" for RZ/A1 compatible device
- "renesas,rza2-usbhs" for RZ/A2 compatible device
When compatible with the generic version, nodes must list the
SoC-specific version corresponding to the platform first followed

View File

@ -101,6 +101,7 @@ needed).
filesystems/index
vm/index
bpf/index
usb/index
misc-devices/index
Architecture-specific documentation

View File

@ -254,7 +254,7 @@ Device:
- connect the gadget to a host, preferably not the one used
to control the gadget
- run a program which writes to /dev/hidg<N>, e.g.
a userspace program found in Documentation/usb/gadget_hid.txt::
a userspace program found in Documentation/usb/gadget_hid.rst::
$ ./hid_gadget_test /dev/hidg0 keyboard
@ -886,7 +886,7 @@ host::
# cat /dev/usb/lp0
More advanced testing can be done with the prn_example
described in Documentation/usb/gadget_printer.txt.
described in Documentation/usb/gadget_printer.rst.
20. UAC1 function (virtual ALSA card, using u_audio API)

View File

@ -0,0 +1,39 @@
===========
USB support
===========
.. toctree::
:maxdepth: 1
acm
authorization
chipidea
dwc3
ehci
functionfs
gadget_configfs
gadget_hid
gadget_multi
gadget_printer
gadget_serial
gadget-testing
iuu_phoenix
mass-storage
misc_usbsevseg
mtouchusb
ohci
rio
usbip_protocol
usbmon
usb-serial
wusb-design-overview
usb-help
text_files
.. only:: subproject and html
Indices
=======
* :ref:`genindex`

View File

@ -0,0 +1,29 @@
Linux CDC ACM inf
-----------------
.. include:: linux-cdc-acm.inf
:literal:
Linux inf
---------
.. include:: linux.inf
:literal:
USB devfs drop permissions source
---------------------------------
.. literalinclude:: usbdevfs-drop-permissions.c
:language: c
WUSB command line script to manipulate auth credentials
-------------------------------------------------------
.. literalinclude:: wusb-cbaf
:language: shell
Credits
-------
.. include:: CREDITS
:literal:

View File

@ -3792,7 +3792,7 @@ F: scripts/extract-cert.c
CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM:
L: linux-usb@vger.kernel.org
S: Orphan
F: Documentation/usb/WUSB-Design-overview.txt
F: Documentation/usb/wusb-design-overview.rst
F: Documentation/usb/wusb-cbaf
F: drivers/usb/host/hwa-hc.c
F: drivers/usb/host/whci/
@ -16422,7 +16422,7 @@ USB ACM DRIVER
M: Oliver Neukum <oneukum@suse.com>
L: linux-usb@vger.kernel.org
S: Maintained
F: Documentation/usb/acm.txt
F: Documentation/usb/acm.rst
F: drivers/usb/class/cdc-acm.*
USB AR5523 WIRELESS DRIVER
@ -16475,7 +16475,7 @@ USB EHCI DRIVER
M: Alan Stern <stern@rowland.harvard.edu>
L: linux-usb@vger.kernel.org
S: Maintained
F: Documentation/usb/ehci.txt
F: Documentation/usb/ehci.rst
F: drivers/usb/host/ehci*
USB GADGET/PERIPHERAL SUBSYSTEM
@ -16549,7 +16549,7 @@ USB OHCI DRIVER
M: Alan Stern <stern@rowland.harvard.edu>
L: linux-usb@vger.kernel.org
S: Maintained
F: Documentation/usb/ohci.txt
F: Documentation/usb/ohci.rst
F: drivers/usb/host/ohci*
USB OTG FSM (Finite State Machine)
@ -16565,7 +16565,7 @@ M: Shuah Khan <shuah@kernel.org>
M: Shuah Khan <skhan@linuxfoundation.org>
L: linux-usb@vger.kernel.org
S: Maintained
F: Documentation/usb/usbip_protocol.txt
F: Documentation/usb/usbip_protocol.rst
F: drivers/usb/usbip/
F: tools/usb/usbip/
F: tools/testing/selftests/drivers/usb/usbip/
@ -16613,7 +16613,7 @@ M: Johan Hovold <johan@kernel.org>
L: linux-usb@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial.git
S: Maintained
F: Documentation/usb/usb-serial.txt
F: Documentation/usb/usb-serial.rst
F: drivers/usb/serial/
F: include/linux/usb/serial.h

View File

@ -424,6 +424,7 @@
&usb_host1 {
status = "okay";
snps,need-phy-for-wake;
};
&usb_otg {
@ -432,6 +433,7 @@
assigned-clocks = <&cru SCLK_USBPHY480M_SRC>;
assigned-clock-parents = <&usbphy0>;
dr_mode = "host";
snps,need-phy-for-wake;
};
&vopb {

View File

@ -1009,3 +1009,4 @@ MODULE_DESCRIPTION("Counter with CBC MAC");
MODULE_ALIAS_CRYPTO("ccm_base");
MODULE_ALIAS_CRYPTO("rfc4309");
MODULE_ALIAS_CRYPTO("ccm");
MODULE_ALIAS_CRYPTO("cbcmac");

View File

@ -188,7 +188,7 @@ static const struct regmap_config phy_g12a_usb3_pcie_cr_regmap_conf = {
.reg_read = phy_g12a_usb3_pcie_cr_bus_read,
.reg_write = phy_g12a_usb3_pcie_cr_bus_write,
.max_register = 0xffff,
.fast_io = true,
.disable_locking = true,
};
static int phy_g12a_usb3_init(struct phy *phy)

View File

@ -368,6 +368,13 @@ static int brcm_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR_OR_ZERO(phy_provider);
}
static int brcm_usb_phy_remove(struct platform_device *pdev)
{
sysfs_remove_group(&pdev->dev.kobj, &brcm_usb_phy_group);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int brcm_usb_phy_suspend(struct device *dev)
{
@ -433,9 +440,9 @@ MODULE_DEVICE_TABLE(of, brcm_usb_dt_ids);
static struct platform_driver brcm_usb_driver = {
.probe = brcm_usb_phy_probe,
.remove = brcm_usb_phy_remove,
.driver = {
.name = "brcmstb-usb-phy",
.owner = THIS_MODULE,
.pm = &brcm_usb_phy_pm_ops,
.of_match_table = brcm_usb_dt_ids,
},

View File

@ -4,3 +4,13 @@ config PHY_FSL_IMX8MQ_USB
depends on OF && HAS_IOMEM
select GENERIC_PHY
default ARCH_MXC && ARM64
config PHY_MIXEL_MIPI_DPHY
tristate "Mixel MIPI DSI PHY support"
depends on OF && HAS_IOMEM
select GENERIC_PHY
select GENERIC_PHY_MIPI_DPHY
select REGMAP_MMIO
help
Enable this to add support for the Mixel DSI PHY as found
on NXP's i.MX8 family of SOCs.

View File

@ -1,2 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_PHY_FSL_IMX8MQ_USB) += phy-fsl-imx8mq-usb.o
obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY) += phy-fsl-imx8-mipi-dphy.o

View File

@ -0,0 +1,497 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2017,2018 NXP
* Copyright 2019 Purism SPC
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
/* DPHY registers */
#define DPHY_PD_DPHY 0x00
#define DPHY_M_PRG_HS_PREPARE 0x04
#define DPHY_MC_PRG_HS_PREPARE 0x08
#define DPHY_M_PRG_HS_ZERO 0x0c
#define DPHY_MC_PRG_HS_ZERO 0x10
#define DPHY_M_PRG_HS_TRAIL 0x14
#define DPHY_MC_PRG_HS_TRAIL 0x18
#define DPHY_PD_PLL 0x1c
#define DPHY_TST 0x20
#define DPHY_CN 0x24
#define DPHY_CM 0x28
#define DPHY_CO 0x2c
#define DPHY_LOCK 0x30
#define DPHY_LOCK_BYP 0x34
#define DPHY_REG_BYPASS_PLL 0x4C
#define MBPS(x) ((x) * 1000000)
#define DATA_RATE_MAX_SPEED MBPS(1500)
#define DATA_RATE_MIN_SPEED MBPS(80)
#define PLL_LOCK_SLEEP 10
#define PLL_LOCK_TIMEOUT 1000
#define CN_BUF 0xcb7a89c0
#define CO_BUF 0x63
#define CM(x) ( \
((x) < 32) ? 0xe0 | ((x) - 16) : \
((x) < 64) ? 0xc0 | ((x) - 32) : \
((x) < 128) ? 0x80 | ((x) - 64) : \
((x) - 128))
#define CN(x) (((x) == 1) ? 0x1f : (((CN_BUF) >> ((x) - 1)) & 0x1f))
#define CO(x) ((CO_BUF) >> (8 - (x)) & 0x03)
/* PHY power on is active low */
#define PWR_ON 0
#define PWR_OFF 1
enum mixel_dphy_devtype {
MIXEL_IMX8MQ,
};
struct mixel_dphy_devdata {
u8 reg_tx_rcal;
u8 reg_auto_pd_en;
u8 reg_rxlprp;
u8 reg_rxcdrp;
u8 reg_rxhs_settle;
};
static const struct mixel_dphy_devdata mixel_dphy_devdata[] = {
[MIXEL_IMX8MQ] = {
.reg_tx_rcal = 0x38,
.reg_auto_pd_en = 0x3c,
.reg_rxlprp = 0x40,
.reg_rxcdrp = 0x44,
.reg_rxhs_settle = 0x48,
},
};
struct mixel_dphy_cfg {
/* DPHY PLL parameters */
u32 cm;
u32 cn;
u32 co;
/* DPHY register values */
u8 mc_prg_hs_prepare;
u8 m_prg_hs_prepare;
u8 mc_prg_hs_zero;
u8 m_prg_hs_zero;
u8 mc_prg_hs_trail;
u8 m_prg_hs_trail;
u8 rxhs_settle;
};
struct mixel_dphy_priv {
struct mixel_dphy_cfg cfg;
struct regmap *regmap;
struct clk *phy_ref_clk;
const struct mixel_dphy_devdata *devdata;
};
static const struct regmap_config mixel_dphy_regmap_config = {
.reg_bits = 8,
.val_bits = 32,
.reg_stride = 4,
.max_register = DPHY_REG_BYPASS_PLL,
.name = "mipi-dphy",
};
static int phy_write(struct phy *phy, u32 value, unsigned int reg)
{
struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
int ret;
ret = regmap_write(priv->regmap, reg, value);
if (ret < 0)
dev_err(&phy->dev, "Failed to write DPHY reg %d: %d\n", reg,
ret);
return ret;
}
/*
* Find a ratio close to the desired one using continued fraction
* approximation ending either at exact match or maximum allowed
* nominator, denominator.
*/
static void get_best_ratio(u32 *pnum, u32 *pdenom, u32 max_n, u32 max_d)
{
u32 a = *pnum;
u32 b = *pdenom;
u32 c;
u32 n[] = {0, 1};
u32 d[] = {1, 0};
u32 whole;
unsigned int i = 1;
while (b) {
i ^= 1;
whole = a / b;
n[i] += (n[i ^ 1] * whole);
d[i] += (d[i ^ 1] * whole);
if ((n[i] > max_n) || (d[i] > max_d)) {
i ^= 1;
break;
}
c = a - (b * whole);
a = b;
b = c;
}
*pnum = n[i];
*pdenom = d[i];
}
static int mixel_dphy_config_from_opts(struct phy *phy,
struct phy_configure_opts_mipi_dphy *dphy_opts,
struct mixel_dphy_cfg *cfg)
{
struct mixel_dphy_priv *priv = dev_get_drvdata(phy->dev.parent);
unsigned long ref_clk = clk_get_rate(priv->phy_ref_clk);
u32 lp_t, numerator, denominator;
unsigned long long tmp;
u32 n;
int i;
if (dphy_opts->hs_clk_rate > DATA_RATE_MAX_SPEED ||
dphy_opts->hs_clk_rate < DATA_RATE_MIN_SPEED)
return -EINVAL;
numerator = dphy_opts->hs_clk_rate;
denominator = ref_clk;
get_best_ratio(&numerator, &denominator, 255, 256);
if (!numerator || !denominator) {
dev_err(&phy->dev, "Invalid %d/%d for %ld/%ld\n",
numerator, denominator,
dphy_opts->hs_clk_rate, ref_clk);
return -EINVAL;
}
while ((numerator < 16) && (denominator <= 128)) {
numerator <<= 1;
denominator <<= 1;
}
/*
* CM ranges between 16 and 255
* CN ranges between 1 and 32
* CO is power of 2: 1, 2, 4, 8
*/
i = __ffs(denominator);
if (i > 3)
i = 3;
cfg->cn = denominator >> i;
cfg->co = 1 << i;
cfg->cm = numerator;
if (cfg->cm < 16 || cfg->cm > 255 ||
cfg->cn < 1 || cfg->cn > 32 ||
cfg->co < 1 || cfg->co > 8) {
dev_err(&phy->dev, "Invalid CM/CN/CO values: %u/%u/%u\n",
cfg->cm, cfg->cn, cfg->co);
dev_err(&phy->dev, "for hs_clk/ref_clk=%ld/%ld ~ %d/%d\n",
dphy_opts->hs_clk_rate, ref_clk,
numerator, denominator);
return -EINVAL;
}
dev_dbg(&phy->dev, "hs_clk/ref_clk=%ld/%ld ~ %d/%d\n",
dphy_opts->hs_clk_rate, ref_clk, numerator, denominator);
/* LP clock period */
tmp = 1000000000000LL;
do_div(tmp, dphy_opts->lp_clk_rate); /* ps */
if (tmp > ULONG_MAX)
return -EINVAL;
lp_t = tmp;
dev_dbg(&phy->dev, "LP clock %lu, period: %u ps\n",
dphy_opts->lp_clk_rate, lp_t);
/* hs_prepare: in lp clock periods */
if (2 * dphy_opts->hs_prepare > 5 * lp_t) {
dev_err(&phy->dev,
"hs_prepare (%u) > 2.5 * lp clock period (%u)\n",
dphy_opts->hs_prepare, lp_t);
return -EINVAL;
}
/* 00: lp_t, 01: 1.5 * lp_t, 10: 2 * lp_t, 11: 2.5 * lp_t */
if (dphy_opts->hs_prepare < lp_t) {
n = 0;
} else {
tmp = 2 * (dphy_opts->hs_prepare - lp_t);
do_div(tmp, lp_t);
n = tmp;
}
cfg->m_prg_hs_prepare = n;
/* clk_prepare: in lp clock periods */
if (2 * dphy_opts->clk_prepare > 3 * lp_t) {
dev_err(&phy->dev,
"clk_prepare (%u) > 1.5 * lp clock period (%u)\n",
dphy_opts->clk_prepare, lp_t);
return -EINVAL;
}
/* 00: lp_t, 01: 1.5 * lp_t */
cfg->mc_prg_hs_prepare = dphy_opts->clk_prepare > lp_t ? 1 : 0;
/* hs_zero: formula from NXP BSP */
n = (144 * (dphy_opts->hs_clk_rate / 1000000) - 47500) / 10000;
cfg->m_prg_hs_zero = n < 1 ? 1 : n;
/* clk_zero: formula from NXP BSP */
n = (34 * (dphy_opts->hs_clk_rate / 1000000) - 2500) / 1000;
cfg->mc_prg_hs_zero = n < 1 ? 1 : n;
/* clk_trail, hs_trail: formula from NXP BSP */
n = (103 * (dphy_opts->hs_clk_rate / 1000000) + 10000) / 10000;
if (n > 15)
n = 15;
if (n < 1)
n = 1;
cfg->m_prg_hs_trail = n;
cfg->mc_prg_hs_trail = n;
/* rxhs_settle: formula from NXP BSP */
if (dphy_opts->hs_clk_rate < MBPS(80))
cfg->rxhs_settle = 0x0d;
else if (dphy_opts->hs_clk_rate < MBPS(90))
cfg->rxhs_settle = 0x0c;
else if (dphy_opts->hs_clk_rate < MBPS(125))
cfg->rxhs_settle = 0x0b;
else if (dphy_opts->hs_clk_rate < MBPS(150))
cfg->rxhs_settle = 0x0a;
else if (dphy_opts->hs_clk_rate < MBPS(225))
cfg->rxhs_settle = 0x09;
else if (dphy_opts->hs_clk_rate < MBPS(500))
cfg->rxhs_settle = 0x08;
else
cfg->rxhs_settle = 0x07;
dev_dbg(&phy->dev, "phy_config: %u %u %u %u %u %u %u\n",
cfg->m_prg_hs_prepare, cfg->mc_prg_hs_prepare,
cfg->m_prg_hs_zero, cfg->mc_prg_hs_zero,
cfg->m_prg_hs_trail, cfg->mc_prg_hs_trail,
cfg->rxhs_settle);
return 0;
}
static void mixel_phy_set_hs_timings(struct phy *phy)
{
struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
phy_write(phy, priv->cfg.m_prg_hs_prepare, DPHY_M_PRG_HS_PREPARE);
phy_write(phy, priv->cfg.mc_prg_hs_prepare, DPHY_MC_PRG_HS_PREPARE);
phy_write(phy, priv->cfg.m_prg_hs_zero, DPHY_M_PRG_HS_ZERO);
phy_write(phy, priv->cfg.mc_prg_hs_zero, DPHY_MC_PRG_HS_ZERO);
phy_write(phy, priv->cfg.m_prg_hs_trail, DPHY_M_PRG_HS_TRAIL);
phy_write(phy, priv->cfg.mc_prg_hs_trail, DPHY_MC_PRG_HS_TRAIL);
phy_write(phy, priv->cfg.rxhs_settle, priv->devdata->reg_rxhs_settle);
}
static int mixel_dphy_set_pll_params(struct phy *phy)
{
struct mixel_dphy_priv *priv = dev_get_drvdata(phy->dev.parent);
if (priv->cfg.cm < 16 || priv->cfg.cm > 255 ||
priv->cfg.cn < 1 || priv->cfg.cn > 32 ||
priv->cfg.co < 1 || priv->cfg.co > 8) {
dev_err(&phy->dev, "Invalid CM/CN/CO values! (%u/%u/%u)\n",
priv->cfg.cm, priv->cfg.cn, priv->cfg.co);
return -EINVAL;
}
dev_dbg(&phy->dev, "Using CM:%u CN:%u CO:%u\n",
priv->cfg.cm, priv->cfg.cn, priv->cfg.co);
phy_write(phy, CM(priv->cfg.cm), DPHY_CM);
phy_write(phy, CN(priv->cfg.cn), DPHY_CN);
phy_write(phy, CO(priv->cfg.co), DPHY_CO);
return 0;
}
static int mixel_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
{
struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
struct mixel_dphy_cfg cfg = { 0 };
int ret;
ret = mixel_dphy_config_from_opts(phy, &opts->mipi_dphy, &cfg);
if (ret)
return ret;
/* Update the configuration */
memcpy(&priv->cfg, &cfg, sizeof(struct mixel_dphy_cfg));
phy_write(phy, 0x00, DPHY_LOCK_BYP);
phy_write(phy, 0x01, priv->devdata->reg_tx_rcal);
phy_write(phy, 0x00, priv->devdata->reg_auto_pd_en);
phy_write(phy, 0x02, priv->devdata->reg_rxlprp);
phy_write(phy, 0x02, priv->devdata->reg_rxcdrp);
phy_write(phy, 0x25, DPHY_TST);
mixel_phy_set_hs_timings(phy);
ret = mixel_dphy_set_pll_params(phy);
if (ret < 0)
return ret;
return 0;
}
static int mixel_dphy_validate(struct phy *phy, enum phy_mode mode, int submode,
union phy_configure_opts *opts)
{
struct mixel_dphy_cfg cfg = { 0 };
if (mode != PHY_MODE_MIPI_DPHY)
return -EINVAL;
return mixel_dphy_config_from_opts(phy, &opts->mipi_dphy, &cfg);
}
static int mixel_dphy_init(struct phy *phy)
{
phy_write(phy, PWR_OFF, DPHY_PD_PLL);
phy_write(phy, PWR_OFF, DPHY_PD_DPHY);
return 0;
}
static int mixel_dphy_exit(struct phy *phy)
{
phy_write(phy, 0, DPHY_CM);
phy_write(phy, 0, DPHY_CN);
phy_write(phy, 0, DPHY_CO);
return 0;
}
static int mixel_dphy_power_on(struct phy *phy)
{
struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
u32 locked;
int ret;
ret = clk_prepare_enable(priv->phy_ref_clk);
if (ret < 0)
return ret;
phy_write(phy, PWR_ON, DPHY_PD_PLL);
ret = regmap_read_poll_timeout(priv->regmap, DPHY_LOCK, locked,
locked, PLL_LOCK_SLEEP,
PLL_LOCK_TIMEOUT);
if (ret < 0) {
dev_err(&phy->dev, "Could not get DPHY lock (%d)!\n", ret);
goto clock_disable;
}
phy_write(phy, PWR_ON, DPHY_PD_DPHY);
return 0;
clock_disable:
clk_disable_unprepare(priv->phy_ref_clk);
return ret;
}
static int mixel_dphy_power_off(struct phy *phy)
{
struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
phy_write(phy, PWR_OFF, DPHY_PD_PLL);
phy_write(phy, PWR_OFF, DPHY_PD_DPHY);
clk_disable_unprepare(priv->phy_ref_clk);
return 0;
}
static const struct phy_ops mixel_dphy_phy_ops = {
.init = mixel_dphy_init,
.exit = mixel_dphy_exit,
.power_on = mixel_dphy_power_on,
.power_off = mixel_dphy_power_off,
.configure = mixel_dphy_configure,
.validate = mixel_dphy_validate,
.owner = THIS_MODULE,
};
static const struct of_device_id mixel_dphy_of_match[] = {
{ .compatible = "fsl,imx8mq-mipi-dphy",
.data = &mixel_dphy_devdata[MIXEL_IMX8MQ] },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, mixel_dphy_of_match);
static int mixel_dphy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct phy_provider *phy_provider;
struct mixel_dphy_priv *priv;
struct resource *res;
struct phy *phy;
void __iomem *base;
if (!np)
return -ENODEV;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->devdata = of_device_get_match_data(&pdev->dev);
if (!priv->devdata)
return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&mixel_dphy_regmap_config);
if (IS_ERR(priv->regmap)) {
dev_err(dev, "Couldn't create the DPHY regmap\n");
return PTR_ERR(priv->regmap);
}
priv->phy_ref_clk = devm_clk_get(&pdev->dev, "phy_ref");
if (IS_ERR(priv->phy_ref_clk)) {
dev_err(dev, "No phy_ref clock found\n");
return PTR_ERR(priv->phy_ref_clk);
}
dev_dbg(dev, "phy_ref clock rate: %lu\n",
clk_get_rate(priv->phy_ref_clk));
dev_set_drvdata(dev, priv);
phy = devm_phy_create(dev, np, &mixel_dphy_phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "Failed to create phy %ld\n", PTR_ERR(phy));
return PTR_ERR(phy);
}
phy_set_drvdata(phy, priv);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
}
static struct platform_driver mixel_dphy_driver = {
.probe = mixel_dphy_probe,
.driver = {
.name = "mixel-mipi-dphy",
.of_match_table = mixel_dphy_of_match,
}
};
module_platform_driver(mixel_dphy_driver);
MODULE_AUTHOR("NXP Semiconductor");
MODULE_DESCRIPTION("Mixel MIPI-DSI PHY driver");
MODULE_LICENSE("GPL");

View File

@ -25,6 +25,14 @@ config PHY_QCOM_IPQ806X_SATA
depends on OF
select GENERIC_PHY
config PHY_QCOM_PCIE2
tristate "Qualcomm PCIe Gen2 PHY Driver"
depends on OF && COMMON_CLK && (ARCH_QCOM || COMPILE_TEST)
select GENERIC_PHY
help
Enable this to support the Qualcomm PCIe PHY, used with the Synopsys
based PCIe controller.
config PHY_QCOM_QMP
tristate "Qualcomm QMP PHY Driver"
depends on OF && COMMON_CLK && (ARCH_QCOM || COMPILE_TEST)

View File

@ -2,6 +2,7 @@
obj-$(CONFIG_PHY_ATH79_USB) += phy-ath79-usb.o
obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o
obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o
obj-$(CONFIG_PHY_QCOM_PCIE2) += phy-qcom-pcie2.o
obj-$(CONFIG_PHY_QCOM_QMP) += phy-qcom-qmp.o
obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o

View File

@ -0,0 +1,331 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
* Copyright (c) 2019, Linaro Ltd.
*/
#include <linux/clk-provider.h>
#include <linux/clk.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/slab.h>
#include <dt-bindings/phy/phy.h>
#define PCIE20_PARF_PHY_STTS 0x3c
#define PCIE2_PHY_RESET_CTRL 0x44
#define PCIE20_PARF_PHY_REFCLK_CTRL2 0xa0
#define PCIE20_PARF_PHY_REFCLK_CTRL3 0xa4
#define PCIE20_PARF_PCS_SWING_CTRL1 0x88
#define PCIE20_PARF_PCS_SWING_CTRL2 0x8c
#define PCIE20_PARF_PCS_DEEMPH1 0x74
#define PCIE20_PARF_PCS_DEEMPH2 0x78
#define PCIE20_PARF_PCS_DEEMPH3 0x7c
#define PCIE20_PARF_CONFIGBITS 0x84
#define PCIE20_PARF_PHY_CTRL3 0x94
#define PCIE20_PARF_PCS_CTRL 0x80
#define TX_AMP_VAL 120
#define PHY_RX0_EQ_GEN1_VAL 0
#define PHY_RX0_EQ_GEN2_VAL 4
#define TX_DEEMPH_GEN1_VAL 24
#define TX_DEEMPH_GEN2_3_5DB_VAL 26
#define TX_DEEMPH_GEN2_6DB_VAL 36
#define PHY_TX0_TERM_OFFST_VAL 0
struct qcom_phy {
struct device *dev;
void __iomem *base;
struct regulator_bulk_data vregs[2];
struct reset_control *phy_reset;
struct reset_control *pipe_reset;
struct clk *pipe_clk;
};
static int qcom_pcie2_phy_init(struct phy *phy)
{
struct qcom_phy *qphy = phy_get_drvdata(phy);
int ret;
ret = reset_control_deassert(qphy->phy_reset);
if (ret) {
dev_err(qphy->dev, "cannot deassert pipe reset\n");
return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
if (ret)
reset_control_assert(qphy->phy_reset);
return ret;
}
static int qcom_pcie2_phy_power_on(struct phy *phy)
{
struct qcom_phy *qphy = phy_get_drvdata(phy);
int ret;
u32 val;
/* Program REF_CLK source */
val = readl(qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);
val &= ~BIT(1);
writel(val, qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);
usleep_range(1000, 2000);
/* Don't use PAD for refclock */
val = readl(qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);
val &= ~BIT(0);
writel(val, qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);
/* Program SSP ENABLE */
val = readl(qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL3);
val |= BIT(0);
writel(val, qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL3);
usleep_range(1000, 2000);
/* Assert Phy SW Reset */
val = readl(qphy->base + PCIE2_PHY_RESET_CTRL);
val |= BIT(0);
writel(val, qphy->base + PCIE2_PHY_RESET_CTRL);
/* Program Tx Amplitude */
val = readl(qphy->base + PCIE20_PARF_PCS_SWING_CTRL1);
val &= ~0x7f;
val |= TX_AMP_VAL;
writel(val, qphy->base + PCIE20_PARF_PCS_SWING_CTRL1);
val = readl(qphy->base + PCIE20_PARF_PCS_SWING_CTRL2);
val &= ~0x7f;
val |= TX_AMP_VAL;
writel(val, qphy->base + PCIE20_PARF_PCS_SWING_CTRL2);
/* Program De-Emphasis */
val = readl(qphy->base + PCIE20_PARF_PCS_DEEMPH1);
val &= ~0x3f;
val |= TX_DEEMPH_GEN2_6DB_VAL;
writel(val, qphy->base + PCIE20_PARF_PCS_DEEMPH1);
val = readl(qphy->base + PCIE20_PARF_PCS_DEEMPH2);
val &= ~0x3f;
val |= TX_DEEMPH_GEN2_3_5DB_VAL;
writel(val, qphy->base + PCIE20_PARF_PCS_DEEMPH2);
val = readl(qphy->base + PCIE20_PARF_PCS_DEEMPH3);
val &= ~0x3f;
val |= TX_DEEMPH_GEN1_VAL;
writel(val, qphy->base + PCIE20_PARF_PCS_DEEMPH3);
/* Program Rx_Eq */
val = readl(qphy->base + PCIE20_PARF_CONFIGBITS);
val &= ~0x7;
val |= PHY_RX0_EQ_GEN2_VAL;
writel(val, qphy->base + PCIE20_PARF_CONFIGBITS);
/* Program Tx0_term_offset */
val = readl(qphy->base + PCIE20_PARF_PHY_CTRL3);
val &= ~0x1f;
val |= PHY_TX0_TERM_OFFST_VAL;
writel(val, qphy->base + PCIE20_PARF_PHY_CTRL3);
/* disable Tx2Rx Loopback */
val = readl(qphy->base + PCIE20_PARF_PCS_CTRL);
val &= ~BIT(1);
writel(val, qphy->base + PCIE20_PARF_PCS_CTRL);
/* De-assert Phy SW Reset */
val = readl(qphy->base + PCIE2_PHY_RESET_CTRL);
val &= ~BIT(0);
writel(val, qphy->base + PCIE2_PHY_RESET_CTRL);
usleep_range(1000, 2000);
ret = reset_control_deassert(qphy->pipe_reset);
if (ret) {
dev_err(qphy->dev, "cannot deassert pipe reset\n");
goto out;
}
clk_set_rate(qphy->pipe_clk, 250000000);
ret = clk_prepare_enable(qphy->pipe_clk);
if (ret) {
dev_err(qphy->dev, "failed to enable pipe clock\n");
goto out;
}
ret = readl_poll_timeout(qphy->base + PCIE20_PARF_PHY_STTS, val,
!(val & BIT(0)), 1000, 10);
if (ret)
dev_err(qphy->dev, "phy initialization failed\n");
out:
return ret;
}
static int qcom_pcie2_phy_power_off(struct phy *phy)
{
struct qcom_phy *qphy = phy_get_drvdata(phy);
u32 val;
val = readl(qphy->base + PCIE2_PHY_RESET_CTRL);
val |= BIT(0);
writel(val, qphy->base + PCIE2_PHY_RESET_CTRL);
clk_disable_unprepare(qphy->pipe_clk);
reset_control_assert(qphy->pipe_reset);
return 0;
}
static int qcom_pcie2_phy_exit(struct phy *phy)
{
struct qcom_phy *qphy = phy_get_drvdata(phy);
regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
reset_control_assert(qphy->phy_reset);
return 0;
}
static const struct phy_ops qcom_pcie2_ops = {
.init = qcom_pcie2_phy_init,
.power_on = qcom_pcie2_phy_power_on,
.power_off = qcom_pcie2_phy_power_off,
.exit = qcom_pcie2_phy_exit,
.owner = THIS_MODULE,
};
/*
* Register a fixed rate pipe clock.
*
* The <s>_pipe_clksrc generated by PHY goes to the GCC that gate
* controls it. The <s>_pipe_clk coming out of the GCC is requested
* by the PHY driver for its operations.
* We register the <s>_pipe_clksrc here. The gcc driver takes care
* of assigning this <s>_pipe_clksrc as parent to <s>_pipe_clk.
* Below picture shows this relationship.
*
* +---------------+
* | PHY block |<<---------------------------------------+
* | | |
* | +-------+ | +-----+ |
* I/P---^-->| PLL |---^--->pipe_clksrc--->| GCC |--->pipe_clk---+
* clk | +-------+ | +-----+
* +---------------+
*/
static int phy_pipe_clksrc_register(struct qcom_phy *qphy)
{
struct device_node *np = qphy->dev->of_node;
struct clk_fixed_rate *fixed;
struct clk_init_data init = { };
int ret;
ret = of_property_read_string(np, "clock-output-names", &init.name);
if (ret) {
dev_err(qphy->dev, "%s: No clock-output-names\n", np->name);
return ret;
}
fixed = devm_kzalloc(qphy->dev, sizeof(*fixed), GFP_KERNEL);
if (!fixed)
return -ENOMEM;
init.ops = &clk_fixed_rate_ops;
/* controllers using QMP phys use 250MHz pipe clock interface */
fixed->fixed_rate = 250000000;
fixed->hw.init = &init;
return devm_clk_hw_register(qphy->dev, &fixed->hw);
}
static int qcom_pcie2_phy_probe(struct platform_device *pdev)
{
struct phy_provider *phy_provider;
struct qcom_phy *qphy;
struct resource *res;
struct device *dev = &pdev->dev;
struct phy *phy;
int ret;
qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
if (!qphy)
return -ENOMEM;
qphy->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
qphy->base = devm_ioremap_resource(dev, res);
if (IS_ERR(qphy->base))
return PTR_ERR(qphy->base);
ret = phy_pipe_clksrc_register(qphy);
if (ret) {
dev_err(dev, "failed to register pipe_clk\n");
return ret;
}
qphy->vregs[0].supply = "vdda-vp";
qphy->vregs[1].supply = "vdda-vph";
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(qphy->vregs), qphy->vregs);
if (ret < 0)
return ret;
qphy->pipe_clk = devm_clk_get(dev, NULL);
if (IS_ERR(qphy->pipe_clk)) {
dev_err(dev, "failed to acquire pipe clock\n");
return PTR_ERR(qphy->pipe_clk);
}
qphy->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
if (IS_ERR(qphy->phy_reset)) {
dev_err(dev, "failed to acquire phy reset\n");
return PTR_ERR(qphy->phy_reset);
}
qphy->pipe_reset = devm_reset_control_get_exclusive(dev, "pipe");
if (IS_ERR(qphy->pipe_reset)) {
dev_err(dev, "failed to acquire pipe reset\n");
return PTR_ERR(qphy->pipe_reset);
}
phy = devm_phy_create(dev, dev->of_node, &qcom_pcie2_ops);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create phy\n");
return PTR_ERR(phy);
}
phy_set_drvdata(phy, qphy);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (IS_ERR(phy_provider))
dev_err(dev, "failed to register phy provider\n");
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id qcom_pcie2_phy_match_table[] = {
{ .compatible = "qcom,pcie2-phy" },
{}
};
MODULE_DEVICE_TABLE(of, qcom_pcie2_phy_match_table);
static struct platform_driver qcom_pcie2_phy_driver = {
.probe = qcom_pcie2_phy_probe,
.driver = {
.name = "phy-qcom-pcie2",
.of_match_table = qcom_pcie2_phy_match_table,
},
};
module_platform_driver(qcom_pcie2_phy_driver);
MODULE_DESCRIPTION("Qualcomm PCIe PHY driver");
MODULE_LICENSE("GPL v2");

View File

@ -1074,6 +1074,7 @@ static const struct qmp_phy_cfg msm8996_pciephy_cfg = {
.start_ctrl = PCS_START | PLL_READY_GATE_EN,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.mask_pcs_ready = PHYSTATUS,
.mask_com_pcs_ready = PCS_READY,
.has_phy_com_ctrl = true,
@ -1253,7 +1254,7 @@ static const struct qmp_phy_cfg msm8998_pciephy_cfg = {
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.mask_com_pcs_ready = PCS_READY,
.mask_pcs_ready = PHYSTATUS,
};
static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {
@ -1547,7 +1548,7 @@ static int qcom_qmp_phy_enable(struct phy *phy)
status = pcs + cfg->regs[QPHY_PCS_READY_STATUS];
mask = cfg->mask_pcs_ready;
ret = readl_poll_timeout(status, val, !(val & mask), 1,
ret = readl_poll_timeout(status, val, val & mask, 10,
PHY_INIT_COMPLETE_TIMEOUT);
if (ret) {
dev_err(qmp->dev, "phy initialization timed-out\n");

View File

@ -564,7 +564,7 @@ static int __maybe_unused qusb2_phy_runtime_resume(struct device *dev)
}
if (!qphy->has_se_clk_scheme) {
clk_prepare_enable(qphy->ref_clk);
ret = clk_prepare_enable(qphy->ref_clk);
if (ret) {
dev_err(dev, "failed to enable ref clk, %d\n", ret);
goto disable_ahb_clk;

View File

@ -391,6 +391,7 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev)
error = of_property_read_u32(np, "reg", &channel_num);
if (error || channel_num > 2) {
dev_err(dev, "Invalid \"reg\" property\n");
of_node_put(np);
return error;
}
channel->select_mask = select_mask[channel_num];
@ -406,6 +407,7 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev)
data->gen2_phy_ops);
if (IS_ERR(phy->phy)) {
dev_err(dev, "Failed to create PHY\n");
of_node_put(np);
return PTR_ERR(phy->phy);
}
phy_set_drvdata(phy->phy, phy);

View File

@ -13,6 +13,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
@ -106,6 +107,7 @@ struct rcar_gen3_chan {
struct rcar_gen3_phy rphys[NUM_OF_PHYS];
struct regulator *vbus;
struct work_struct work;
struct mutex lock; /* protects rphys[...].powered */
enum usb_dr_mode dr_mode;
bool extcon_host;
bool is_otg_channel;
@ -437,15 +439,16 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
struct rcar_gen3_chan *channel = rphy->ch;
void __iomem *usb2_base = channel->base;
u32 val;
int ret;
int ret = 0;
mutex_lock(&channel->lock);
if (!rcar_gen3_are_all_rphys_power_off(channel))
return 0;
goto out;
if (channel->vbus) {
ret = regulator_enable(channel->vbus);
if (ret)
return ret;
goto out;
}
val = readl(usb2_base + USB2_USBCTR);
@ -454,7 +457,10 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
val &= ~USB2_USBCTR_PLL_RST;
writel(val, usb2_base + USB2_USBCTR);
out:
/* The powered flag should be set for any other phys anyway */
rphy->powered = true;
mutex_unlock(&channel->lock);
return 0;
}
@ -465,14 +471,18 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p)
struct rcar_gen3_chan *channel = rphy->ch;
int ret = 0;
mutex_lock(&channel->lock);
rphy->powered = false;
if (!rcar_gen3_are_all_rphys_power_off(channel))
return 0;
goto out;
if (channel->vbus)
ret = regulator_disable(channel->vbus);
out:
mutex_unlock(&channel->lock);
return ret;
}
@ -639,6 +649,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
if (!phy_usb2_ops)
return -EINVAL;
mutex_init(&channel->lock);
for (i = 0; i < NUM_OF_PHYS; i++) {
channel->rphys[i].phy = devm_phy_create(dev, NULL,
phy_usb2_ops);

View File

@ -156,9 +156,8 @@ static int samsung_usb2_phy_probe(struct platform_device *pdev)
if (!cfg)
return -EINVAL;
drv = devm_kzalloc(dev, sizeof(struct samsung_usb2_phy_driver) +
cfg->num_phys * sizeof(struct samsung_usb2_phy_instance),
GFP_KERNEL);
drv = devm_kzalloc(dev, struct_size(drv, instances, cfg->num_phys),
GFP_KERNEL);
if (!drv)
return -ENOMEM;

View File

@ -1713,6 +1713,13 @@ static const struct tegra_xusb_padctl_ops tegra124_xusb_padctl_ops = {
.hsic_set_idle = tegra124_hsic_set_idle,
};
static const char * const tegra124_xusb_padctl_supply_names[] = {
"avdd-pll-utmip",
"avdd-pll-erefe",
"avdd-pex-pll",
"hvdd-pex-pll-e",
};
const struct tegra_xusb_padctl_soc tegra124_xusb_padctl_soc = {
.num_pads = ARRAY_SIZE(tegra124_pads),
.pads = tegra124_pads,
@ -1735,6 +1742,8 @@ const struct tegra_xusb_padctl_soc tegra124_xusb_padctl_soc = {
},
},
.ops = &tegra124_xusb_padctl_ops,
.supply_names = tegra124_xusb_padctl_supply_names,
.num_supplies = ARRAY_SIZE(tegra124_xusb_padctl_supply_names),
};
EXPORT_SYMBOL_GPL(tegra124_xusb_padctl_soc);

View File

@ -2009,6 +2009,13 @@ static const struct tegra_xusb_padctl_ops tegra210_xusb_padctl_ops = {
.hsic_set_idle = tegra210_hsic_set_idle,
};
static const char * const tegra210_xusb_padctl_supply_names[] = {
"avdd-pll-utmip",
"avdd-pll-uerefe",
"dvdd-pex-pll",
"hvdd-pex-pll-e",
};
const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc = {
.num_pads = ARRAY_SIZE(tegra210_pads),
.pads = tegra210_pads,
@ -2027,6 +2034,8 @@ const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc = {
},
},
.ops = &tegra210_xusb_padctl_ops,
.supply_names = tegra210_xusb_padctl_supply_names,
.num_supplies = ARRAY_SIZE(tegra210_xusb_padctl_supply_names),
};
EXPORT_SYMBOL_GPL(tegra210_xusb_padctl_soc);

View File

@ -247,8 +247,8 @@ static void serdes_am654_release(struct phy *x)
mux_control_deselect(phy->control);
}
struct phy *serdes_am654_xlate(struct device *dev, struct of_phandle_args
*args)
static struct phy *serdes_am654_xlate(struct device *dev,
struct of_phandle_args *args)
{
struct serdes_am654 *am654_phy;
struct phy *phy;

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
@ -450,6 +451,9 @@ int geni_se_resources_off(struct geni_se *se)
{
int ret;
if (has_acpi_companion(se->dev))
return 0;
ret = pinctrl_pm_select_sleep_state(se->dev);
if (ret)
return ret;
@ -487,6 +491,9 @@ int geni_se_resources_on(struct geni_se *se)
{
int ret;
if (has_acpi_companion(se->dev))
return 0;
ret = geni_se_clks_on(se);
if (ret)
return ret;
@ -724,12 +731,14 @@ static int geni_se_probe(struct platform_device *pdev)
if (IS_ERR(wrapper->base))
return PTR_ERR(wrapper->base);
wrapper->ahb_clks[0].id = "m-ahb";
wrapper->ahb_clks[1].id = "s-ahb";
ret = devm_clk_bulk_get(dev, NUM_AHB_CLKS, wrapper->ahb_clks);
if (ret) {
dev_err(dev, "Err getting AHB clks %d\n", ret);
return ret;
if (!has_acpi_companion(&pdev->dev)) {
wrapper->ahb_clks[0].id = "m-ahb";
wrapper->ahb_clks[1].id = "s-ahb";
ret = devm_clk_bulk_get(dev, NUM_AHB_CLKS, wrapper->ahb_clks);
if (ret) {
dev_err(dev, "Err getting AHB clks %d\n", ret);
return ret;
}
}
dev_set_drvdata(dev, wrapper);

View File

@ -74,7 +74,7 @@ config USB
After choosing your HCD, then select drivers for the USB peripherals
you'll be using. You may want to check out the information provided
in <file:Documentation/usb/> and especially the links given in
<file:Documentation/usb/usb-help.txt>.
<file:Documentation/usb/usb-help.rst>.
To compile this driver as a module, choose M here: the
module will be called usbcore.

View File

@ -5,6 +5,7 @@
# Object files in subdirectories
obj-$(CONFIG_USB_COMMON) += common/
obj-$(CONFIG_USB) += core/
obj-$(CONFIG_USB_SUPPORT) += phy/
@ -60,8 +61,6 @@ obj-$(CONFIG_USB_CHIPIDEA) += chipidea/
obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/
obj-$(CONFIG_USB_GADGET) += gadget/
obj-$(CONFIG_USB_COMMON) += common/
obj-$(CONFIG_USBIP_CORE) += usbip/
obj-$(CONFIG_TYPEC) += typec/

View File

@ -7,7 +7,6 @@ menuconfig USB_ATM
tristate "USB DSL modem support"
depends on ATM
select CRC32
default n
help
Say Y here if you want to connect a USB Digital Subscriber Line (DSL)
modem to your computer's USB port. You will then need to choose your

View File

@ -1,55 +1,11 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*-
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-2-Clause)
/*
* Copyright (c) 2003, 2004
* Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
*
* Copyright (c) 2005-2007 Matthieu Castet <castet.matthieu@free.fr>
* Copyright (c) 2005-2007 Stanislaw Gruszka <stf_xl@wp.pl>
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* BSD license below:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* GPL license :
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
* HISTORY : some part of the code was base on ueagle 1.3 BSD driver,
* Damien Bergamini agree to put his code under a DUAL GPL/BSD license.
*

View File

@ -13,6 +13,7 @@
#include <linux/usb/of.h>
#include <linux/clk.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_qos.h>
#include "ci.h"
#include "ci_hdrc_imx.h"
@ -63,6 +64,11 @@ static const struct ci_hdrc_imx_platform_flag imx7d_usb_data = {
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM,
};
static const struct ci_hdrc_imx_platform_flag imx7ulp_usb_data = {
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
CI_HDRC_PMQOS,
};
static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
{ .compatible = "fsl,imx23-usb", .data = &imx23_usb_data},
{ .compatible = "fsl,imx28-usb", .data = &imx28_usb_data},
@ -72,6 +78,7 @@ static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
{ .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data},
{ .compatible = "fsl,imx6ul-usb", .data = &imx6ul_usb_data},
{ .compatible = "fsl,imx7d-usb", .data = &imx7d_usb_data},
{ .compatible = "fsl,imx7ulp-usb", .data = &imx7ulp_usb_data},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids);
@ -93,6 +100,8 @@ struct ci_hdrc_imx_data {
struct clk *clk_ahb;
struct clk *clk_per;
/* --------------------------------- */
struct pm_qos_request pm_qos_req;
const struct ci_hdrc_imx_platform_flag *plat_data;
};
/* Common functions shared by usbmisc drivers */
@ -309,6 +318,8 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
if (!data)
return -ENOMEM;
data->plat_data = imx_platform_flag;
pdata.flags |= imx_platform_flag->flags;
platform_set_drvdata(pdev, data);
data->usbmisc_data = usbmisc_get_init_data(dev);
if (IS_ERR(data->usbmisc_data))
@ -369,6 +380,11 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
}
}
}
if (pdata.flags & CI_HDRC_PMQOS)
pm_qos_add_request(&data->pm_qos_req,
PM_QOS_CPU_DMA_LATENCY, 0);
ret = imx_get_clks(dev);
if (ret)
goto disable_hsic_regulator;
@ -382,8 +398,9 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
ret = PTR_ERR(data->phy);
/* Return -EINVAL if no usbphy is available */
if (ret == -ENODEV)
ret = -EINVAL;
goto err_clk;
data->phy = NULL;
else
goto err_clk;
}
pdata.usb_phy = data->phy;
@ -396,7 +413,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
usb_phy_init(pdata.usb_phy);
}
pdata.flags |= imx_platform_flag->flags;
if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM)
data->supports_runtime_pm = true;
@ -439,6 +455,8 @@ err_clk:
disable_hsic_regulator:
if (data->hsic_pad_regulator)
ret = regulator_disable(data->hsic_pad_regulator);
if (pdata.flags & CI_HDRC_PMQOS)
pm_qos_remove_request(&data->pm_qos_req);
return ret;
}
@ -455,6 +473,8 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev)
if (data->override_phy_control)
usb_phy_shutdown(data->phy);
imx_disable_unprepare_clks(&pdev->dev);
if (data->plat_data->flags & CI_HDRC_PMQOS)
pm_qos_remove_request(&data->pm_qos_req);
if (data->hsic_pad_regulator)
regulator_disable(data->hsic_pad_regulator);
@ -480,6 +500,9 @@ static int __maybe_unused imx_controller_suspend(struct device *dev)
}
imx_disable_unprepare_clks(dev);
if (data->plat_data->flags & CI_HDRC_PMQOS)
pm_qos_remove_request(&data->pm_qos_req);
data->in_lpm = true;
return 0;
@ -497,6 +520,10 @@ static int __maybe_unused imx_controller_resume(struct device *dev)
return 0;
}
if (data->plat_data->flags & CI_HDRC_PMQOS)
pm_qos_add_request(&data->pm_qos_req,
PM_QOS_CPU_DMA_LATENCY, 0);
ret = imx_prepare_enable_clks(dev);
if (ret)
return ret;

View File

@ -175,7 +175,6 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev)
struct platform_device *plat_ci;
struct clk *clk;
struct reset_control *reset;
struct resource *res;
int ret;
struct device_node *ulpi_node, *phy_node;
@ -209,8 +208,7 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev)
if (IS_ERR(clk))
return PTR_ERR(clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
ci->base = devm_ioremap_resource(&pdev->dev, res);
ci->base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(ci->base))
return PTR_ERR(ci->base);

View File

@ -523,8 +523,9 @@ int hw_device_reset(struct ci_hdrc *ci)
hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM);
if (hw_read(ci, OP_USBMODE, USBMODE_CM) != USBMODE_CM_DC) {
pr_err("cannot enter in %s device mode", ci_role(ci)->name);
pr_err("lpm = %i", ci->hw_bank.lpm);
dev_err(ci->dev, "cannot enter in %s device mode\n",
ci_role(ci)->name);
dev_err(ci->dev, "lpm = %i\n", ci->hw_bank.lpm);
return -ENODEV;
}

View File

@ -763,13 +763,16 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = {
.compatible = "fsl,imx7d-usbmisc",
.data = &imx7d_usbmisc_ops,
},
{
.compatible = "fsl,imx7ulp-usbmisc",
.data = &imx7d_usbmisc_ops,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
static int usbmisc_imx_probe(struct platform_device *pdev)
{
struct resource *res;
struct imx_usbmisc *data;
const struct of_device_id *of_id;
@ -783,8 +786,7 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
spin_lock_init(&data->lock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
data->base = devm_ioremap_resource(&pdev->dev, res);
data->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(data->base))
return PTR_ERR(data->base);

View File

@ -10,7 +10,7 @@ config USB_ACM
---help---
This driver supports USB modems and ISDN adapters which support the
Communication Device Class Abstract Control Model interface.
Please read <file:Documentation/usb/acm.txt> for details.
Please read <file:Documentation/usb/acm.rst> for details.
If your modem only reports "Cls=ff(vend.)" in the descriptors in
/sys/kernel/debug/usb/devices, then your modem will not work with this

View File

@ -949,7 +949,7 @@ struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf,
int bufsize,
int (*manage_power)(struct usb_interface *, int))
{
int rv = -EINVAL;
int rv;
rv = wdm_create(intf, ep, bufsize, manage_power);
if (rv < 0)

View File

@ -15,6 +15,8 @@
#include <linux/usb/of.h>
#include <linux/usb/otg.h>
#include <linux/of_platform.h>
#include <linux/debugfs.h>
#include "common.h"
static const char *const ep_type_names[] = {
[USB_ENDPOINT_XFER_CONTROL] = "ctrl",
@ -291,4 +293,23 @@ struct device *usb_of_get_companion_dev(struct device *dev)
EXPORT_SYMBOL_GPL(usb_of_get_companion_dev);
#endif
struct dentry *usb_debug_root;
EXPORT_SYMBOL_GPL(usb_debug_root);
static int __init usb_common_init(void)
{
usb_debug_root = debugfs_create_dir("usb", NULL);
ledtrig_usb_init();
return 0;
}
static void __exit usb_common_exit(void)
{
ledtrig_usb_exit();
debugfs_remove_recursive(usb_debug_root);
}
subsys_initcall(usb_common_init);
module_exit(usb_common_exit);
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __LINUX_USB_COMMON_H
#define __LINUX_USB_COMMON_H
#if defined(CONFIG_USB_LED_TRIG)
void ledtrig_usb_init(void);
void ledtrig_usb_exit(void);
#else
static inline void ledtrig_usb_init(void) { }
static inline void ledtrig_usb_exit(void) { }
#endif
#endif /* __LINUX_USB_COMMON_H */

View File

@ -10,6 +10,7 @@
#include <linux/init.h>
#include <linux/leds.h>
#include <linux/usb.h>
#include "common.h"
#define BLINK_DELAY 30
@ -36,18 +37,14 @@ void usb_led_activity(enum usb_led_event ev)
EXPORT_SYMBOL_GPL(usb_led_activity);
static int __init ledtrig_usb_init(void)
void __init ledtrig_usb_init(void)
{
led_trigger_register_simple("usb-gadget", &ledtrig_usb_gadget);
led_trigger_register_simple("usb-host", &ledtrig_usb_host);
return 0;
}
static void __exit ledtrig_usb_exit(void)
void __exit ledtrig_usb_exit(void)
{
led_trigger_unregister_simple(ledtrig_usb_gadget);
led_trigger_unregister_simple(ledtrig_usb_host);
}
module_init(ledtrig_usb_init);
module_exit(ledtrig_usb_exit);

View File

@ -45,7 +45,6 @@ config USB_DYNAMIC_MINORS
config USB_OTG
bool "OTG support"
depends on PM
default n
help
The most notable feature of USB OTG is support for a
"Dual-Role" device, which can act as either a device

View File

@ -48,9 +48,6 @@
#define USB_DEVICE_MAX (USB_MAXBUS * 128)
#define USB_SG_SIZE 16384 /* split-size for large txs */
/* Mutual exclusion for removal, open, and release */
DEFINE_MUTEX(usbfs_mutex);
struct usb_dev_state {
struct list_head list; /* state list */
struct usb_device *dev;
@ -977,15 +974,9 @@ static int usbdev_open(struct inode *inode, struct file *file)
ret = -ENODEV;
/* Protect against simultaneous removal or release */
mutex_lock(&usbfs_mutex);
/* usbdev device-node */
if (imajor(inode) == USB_DEVICE_MAJOR)
dev = usbdev_lookup_by_devt(inode->i_rdev);
mutex_unlock(&usbfs_mutex);
if (!dev)
goto out_free_ps;
@ -1306,6 +1297,39 @@ static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg)
return 0;
}
static int proc_conninfo_ex(struct usb_dev_state *ps,
void __user *arg, size_t size)
{
struct usbdevfs_conninfo_ex ci;
struct usb_device *udev = ps->dev;
if (size < sizeof(ci.size))
return -EINVAL;
memset(&ci, 0, sizeof(ci));
ci.size = sizeof(ci);
ci.busnum = udev->bus->busnum;
ci.devnum = udev->devnum;
ci.speed = udev->speed;
while (udev && udev->portnum != 0) {
if (++ci.num_ports <= ARRAY_SIZE(ci.ports))
ci.ports[ARRAY_SIZE(ci.ports) - ci.num_ports] =
udev->portnum;
udev = udev->parent;
}
if (ci.num_ports < ARRAY_SIZE(ci.ports))
memmove(&ci.ports[0],
&ci.ports[ARRAY_SIZE(ci.ports) - ci.num_ports],
ci.num_ports);
if (copy_to_user(arg, &ci, min(sizeof(ci), size)))
return -EFAULT;
return 0;
}
static int proc_resetdevice(struct usb_dev_state *ps)
{
struct usb_host_config *actconfig = ps->dev->actconfig;
@ -1484,15 +1508,15 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
ret = -EFAULT;
goto error;
}
if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) {
if (uurb->buffer_length < (le16_to_cpu(dr->wLength) + 8)) {
ret = -EINVAL;
goto error;
}
ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest,
le16_to_cpup(&dr->wIndex));
le16_to_cpu(dr->wIndex));
if (ret)
goto error;
uurb->buffer_length = le16_to_cpup(&dr->wLength);
uurb->buffer_length = le16_to_cpu(dr->wLength);
uurb->buffer += 8;
if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
is_in = 1;
@ -1507,9 +1531,9 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
"bRequest=%02x wValue=%04x "
"wIndex=%04x wLength=%04x\n",
dr->bRequestType, dr->bRequest,
__le16_to_cpup(&dr->wValue),
__le16_to_cpup(&dr->wIndex),
__le16_to_cpup(&dr->wLength));
__le16_to_cpu(dr->wValue),
__le16_to_cpu(dr->wIndex),
__le16_to_cpu(dr->wLength));
u = sizeof(struct usb_ctrlrequest);
break;
@ -2137,6 +2161,9 @@ static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl)
if (ps->privileges_dropped)
return -EACCES;
if (!connected(ps))
return -ENODEV;
/* alloc buffer */
size = _IOC_SIZE(ctl->ioctl_code);
if (size > 0) {
@ -2153,11 +2180,6 @@ static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl)
}
}
if (!connected(ps)) {
kfree(buf);
return -ENODEV;
}
if (ps->dev->state != USB_STATE_CONFIGURED)
retval = -EHOSTUNREACH;
else if (!(intf = usb_ifnum_to_if(ps->dev, ctl->ifno)))
@ -2259,7 +2281,7 @@ static int proc_get_capabilities(struct usb_dev_state *ps, void __user *arg)
caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM |
USBDEVFS_CAP_REAP_AFTER_DISCONNECT | USBDEVFS_CAP_MMAP |
USBDEVFS_CAP_DROP_PRIVILEGES;
USBDEVFS_CAP_DROP_PRIVILEGES | USBDEVFS_CAP_CONNINFO_EX;
if (!ps->dev->bus->no_stop_on_short)
caps |= USBDEVFS_CAP_BULK_CONTINUATION;
if (ps->dev->bus->sg_tablesize)
@ -2558,6 +2580,13 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
break;
}
/* Handle variable-length commands */
switch (cmd & ~IOCSIZE_MASK) {
case USBDEVFS_CONNINFO_EX(0):
ret = proc_conninfo_ex(ps, p, _IOC_SIZE(cmd));
break;
}
done:
usb_unlock_device(dev);
if (ret >= 0)

View File

@ -873,7 +873,7 @@ int usb_hub_clear_tt_buffer(struct urb *urb)
/* info that CLEAR_TT_BUFFER needs */
clear->tt = tt->multi ? udev->ttport : 1;
clear->devinfo = usb_pipeendpoint (pipe);
clear->devinfo |= udev->devnum << 4;
clear->devinfo |= ((u16)udev->devaddr) << 4;
clear->devinfo |= usb_pipecontrol(pipe)
? (USB_ENDPOINT_XFER_CONTROL << 11)
: (USB_ENDPOINT_XFER_BULK << 11);
@ -2125,6 +2125,8 @@ static void update_devnum(struct usb_device *udev, int devnum)
/* The address for a WUSB device is managed by wusbcore. */
if (!udev->wusb)
udev->devnum = devnum;
if (!udev->devaddr)
udev->devaddr = (u8)devnum;
}
static void hub_free_dev(struct usb_device *udev)
@ -2719,7 +2721,7 @@ static bool use_new_scheme(struct usb_device *udev, int retry,
}
/* Is a USB 3.0 port in the Inactive or Compliance Mode state?
* Port worm reset is required to recover
* Port warm reset is required to recover
*/
static bool hub_port_warm_reset_required(struct usb_hub *hub, int port1,
u16 portstatus)
@ -3617,6 +3619,7 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
struct usb_device *hdev;
struct usb_device *udev;
int connect_change = 0;
u16 link_state;
int ret;
hdev = hub->hdev;
@ -3626,9 +3629,11 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
return 0;
usb_clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND);
} else {
link_state = portstatus & USB_PORT_STAT_LINK_STATE;
if (!udev || udev->state != USB_STATE_SUSPENDED ||
(portstatus & USB_PORT_STAT_LINK_STATE) !=
USB_SS_PORT_LS_U0)
(link_state != USB_SS_PORT_LS_U0 &&
link_state != USB_SS_PORT_LS_U1 &&
link_state != USB_SS_PORT_LS_U2))
return 0;
}
@ -3999,6 +4004,9 @@ static int usb_set_lpm_timeout(struct usb_device *udev,
* control transfers to set the hub timeout or enable device-initiated U1/U2
* will be successful.
*
* If the control transfer to enable device-initiated U1/U2 entry fails, then
* hub-initiated U1/U2 will be disabled.
*
* If we cannot set the parent hub U1/U2 timeout, we attempt to let the xHCI
* driver know about it. If that call fails, it should be harmless, and just
* take up more slightly more bus bandwidth for unnecessary U1/U2 exit latency.
@ -4053,23 +4061,24 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
* host know that this link state won't be enabled.
*/
hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
} else {
/* Only a configured device will accept the Set Feature
* U1/U2_ENABLE
*/
if (udev->actconfig)
usb_set_device_initiated_lpm(udev, state, true);
return;
}
/* As soon as usb_set_lpm_timeout(timeout) returns 0, the
* hub-initiated LPM is enabled. Thus, LPM is enabled no
* matter the result of usb_set_device_initiated_lpm().
* The only difference is whether device is able to initiate
* LPM.
*/
/* Only a configured device will accept the Set Feature
* U1/U2_ENABLE
*/
if (udev->actconfig &&
usb_set_device_initiated_lpm(udev, state, true) == 0) {
if (state == USB3_LPM_U1)
udev->usb3_lpm_u1_enabled = 1;
else if (state == USB3_LPM_U2)
udev->usb3_lpm_u2_enabled = 1;
} else {
/* Don't request U1/U2 entry if the device
* cannot transition to U1/U2.
*/
usb_set_lpm_timeout(udev, state, 0);
hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
}
}
@ -4139,7 +4148,7 @@ int usb_disable_lpm(struct usb_device *udev)
if (!udev || !udev->parent ||
udev->speed < USB_SPEED_SUPER ||
!udev->lpm_capable ||
udev->state < USB_STATE_DEFAULT)
udev->state < USB_STATE_CONFIGURED)
return 0;
hcd = bus_to_hcd(udev->bus);
@ -4198,7 +4207,7 @@ void usb_enable_lpm(struct usb_device *udev)
if (!udev || !udev->parent ||
udev->speed < USB_SPEED_SUPER ||
!udev->lpm_capable ||
udev->state < USB_STATE_DEFAULT)
udev->state < USB_STATE_CONFIGURED)
return;
udev->lpm_disable_count--;

View File

@ -53,11 +53,8 @@ void usb_notify_add_device(struct usb_device *udev)
void usb_notify_remove_device(struct usb_device *udev)
{
/* Protect against simultaneous usbfs open */
mutex_lock(&usbfs_mutex);
blocking_notifier_call_chain(&usb_notifier_list,
USB_DEVICE_REMOVE, udev);
mutex_unlock(&usbfs_mutex);
}
void usb_notify_add_bus(struct usb_bus *ubus)

View File

@ -1185,19 +1185,17 @@ static struct notifier_block usb_bus_nb = {
.notifier_call = usb_bus_notify,
};
struct dentry *usb_debug_root;
EXPORT_SYMBOL_GPL(usb_debug_root);
static struct dentry *usb_devices_root;
static void usb_debugfs_init(void)
{
usb_debug_root = debugfs_create_dir("usb", NULL);
debugfs_create_file("devices", 0444, usb_debug_root, NULL,
&usbfs_devices_fops);
usb_devices_root = debugfs_create_file("devices", 0444, usb_debug_root,
NULL, &usbfs_devices_fops);
}
static void usb_debugfs_cleanup(void)
{
debugfs_remove_recursive(usb_debug_root);
debugfs_remove(usb_devices_root);
}
/*

View File

@ -169,7 +169,6 @@ extern const struct attribute_group *usb_device_groups[];
extern const struct attribute_group *usb_interface_groups[];
/* usbfs stuff */
extern struct mutex usbfs_mutex;
extern struct usb_driver usbfs_driver;
extern const struct file_operations usbfs_devices_fops;
extern const struct file_operations usbdev_file_operations;

View File

@ -58,7 +58,6 @@ config USB_DWC2_PCI
tristate "DWC2 PCI"
depends on USB_PCI
depends on USB_GADGET || !USB_GADGET
default n
select NOP_USB_XCEIV
help
The Designware USB2.0 PCI interface module for controllers

View File

@ -531,7 +531,7 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
}
/* Wait for AHB master IDLE state */
if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 50)) {
if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000)) {
dev_warn(hsotg->dev, "%s: HANG! AHB Idle timeout GRSTCTL GRSTCTL_AHBIDLE\n",
__func__);
return -EBUSY;

View File

@ -861,6 +861,9 @@ struct dwc2_hregs_backup {
* @hibernated: True if core is hibernated
* @reset_phy_on_wake: Quirk saying that we should assert PHY reset on a
* remote wakeup.
* @phy_off_for_suspend: Status of whether we turned the PHY off at suspend.
* @need_phy_for_wake: Quirk saying that we should keep the PHY on at
* suspend if we need USB to wake us up.
* @frame_number: Frame number read from the core. For both device
* and host modes. The value ranges are from 0
* to HFNUM_MAX_FRNUM.
@ -1049,6 +1052,8 @@ struct dwc2_hsotg {
unsigned int ll_hw_enabled:1;
unsigned int hibernated:1;
unsigned int reset_phy_on_wake:1;
unsigned int need_phy_for_wake:1;
unsigned int phy_off_for_suspend:1;
u16 frame_number;
struct phy *phy;
@ -1438,6 +1443,7 @@ int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg);
int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg);
int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
int rem_wakeup, int reset);
bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2);
static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg)
{ schedule_work(&hsotg->phy_reset_work); }
#else
@ -1463,6 +1469,8 @@ static inline int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg)
static inline int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
int rem_wakeup, int reset)
{ return 0; }
static inline bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2)
{ return false; }
static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) {}
#endif

View File

@ -4685,7 +4685,6 @@ fail2:
spin_unlock_irqrestore(&hsotg->lock, flags);
urb->hcpriv = NULL;
kfree(qtd);
qtd = NULL;
fail1:
if (qh_allocated) {
struct dwc2_qtd *qtd2, *qtd2_tmp;
@ -5587,3 +5586,22 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
dev_dbg(hsotg->dev, "Host hibernation restore complete\n");
return ret;
}
bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2)
{
struct usb_device *root_hub = dwc2_hsotg_to_hcd(dwc2)->self.root_hub;
/* If the controller isn't allowed to wakeup then we can power off. */
if (!device_may_wakeup(dwc2->dev))
return true;
/*
* We don't want to power off the PHY if something under the
* root hub has wakeup enabled.
*/
if (usb_wakeup_enabled_descendants(root_hub))
return false;
/* No reason to keep the PHY powered, so allow poweroff */
return true;
}

View File

@ -582,7 +582,6 @@ static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg,
{
list_del(&qtd->qtd_list_entry);
kfree(qtd);
qtd = NULL;
}
/* Descriptor DMA support functions */

View File

@ -76,6 +76,7 @@ static void dwc2_set_s3c6400_params(struct dwc2_hsotg *hsotg)
struct dwc2_core_params *p = &hsotg->params;
p->power_down = 0;
p->phy_utmi_width = 8;
}
static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg)

View File

@ -438,6 +438,10 @@ static int dwc2_driver_probe(struct platform_device *dev)
if (retval)
goto error;
hsotg->need_phy_for_wake =
of_property_read_bool(dev->dev.of_node,
"snps,need-phy-for-wake");
/*
* Reset before dwc2_get_hwparams() then it could get power-on real
* reset value form registers.
@ -469,6 +473,14 @@ static int dwc2_driver_probe(struct platform_device *dev)
hsotg->gadget_enabled = 1;
}
/*
* If we need PHY for wakeup we must be wakeup capable.
* When we have a device that can wake without the PHY we
* can adjust this condition.
*/
if (hsotg->need_phy_for_wake)
device_set_wakeup_capable(&dev->dev, true);
hsotg->reset_phy_on_wake =
of_property_read_bool(dev->dev.of_node,
"snps,reset-phy-on-wake");
@ -507,13 +519,17 @@ error:
static int __maybe_unused dwc2_suspend(struct device *dev)
{
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
bool is_device_mode = dwc2_is_device_mode(dwc2);
int ret = 0;
if (dwc2_is_device_mode(dwc2))
if (is_device_mode)
dwc2_hsotg_suspend(dwc2);
if (dwc2->ll_hw_enabled)
if (dwc2->ll_hw_enabled &&
(is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) {
ret = __dwc2_lowlevel_hw_disable(dwc2);
dwc2->phy_off_for_suspend = true;
}
return ret;
}
@ -523,11 +539,12 @@ static int __maybe_unused dwc2_resume(struct device *dev)
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
int ret = 0;
if (dwc2->ll_hw_enabled) {
if (dwc2->phy_off_for_suspend && dwc2->ll_hw_enabled) {
ret = __dwc2_lowlevel_hw_enable(dwc2);
if (ret)
return ret;
}
dwc2->phy_off_for_suspend = false;
if (dwc2_is_device_mode(dwc2))
ret = dwc2_hsotg_resume(dwc2);

View File

@ -128,7 +128,7 @@ config USB_DWC3_QCOM
tristate "Qualcomm Platform"
depends on ARCH_QCOM || COMPILE_TEST
depends on EXTCON || !EXTCON
depends on OF
depends on (OF || ACPI)
default USB_DWC3
help
Some Qualcomm SoCs use DesignWare Core IP for USB2/3

View File

@ -1282,6 +1282,10 @@ static void dwc3_get_properties(struct dwc3 *dwc)
"snps,dis_u2_susphy_quirk");
dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
"snps,dis_enblslpm_quirk");
dwc->dis_u1_entry_quirk = device_property_read_bool(dev,
"snps,dis-u1-entry-quirk");
dwc->dis_u2_entry_quirk = device_property_read_bool(dev,
"snps,dis-u2-entry-quirk");
dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
"snps,dis_rxdet_inp3_quirk");
dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
@ -1423,11 +1427,6 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->regs = regs;
dwc->regs_size = resource_size(&dwc_res);
if (!dwc3_core_is_valid(dwc)) {
dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
return -ENODEV;
}
dwc3_get_properties(dwc);
dwc->reset = devm_reset_control_get_optional_shared(dev, NULL);
@ -1460,6 +1459,12 @@ static int dwc3_probe(struct platform_device *pdev)
if (ret)
goto unprepare_clks;
if (!dwc3_core_is_valid(dwc)) {
dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
ret = -ENODEV;
goto disable_clks;
}
platform_set_drvdata(pdev, dwc);
dwc3_cache_hwparams(dwc);
@ -1525,6 +1530,7 @@ err1:
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
disable_clks:
clk_bulk_disable(dwc->num_clks, dwc->clks);
unprepare_clks:
clk_bulk_unprepare(dwc->num_clks, dwc->clks);

View File

@ -649,7 +649,6 @@ struct dwc3_event_buffer {
* @cancelled_list: list of cancelled requests for this endpoint
* @pending_list: list of pending requests for this endpoint
* @started_list: list of started requests on this endpoint
* @lock: spinlock for endpoint request queue traversal
* @regs: pointer to first endpoint register
* @trb_pool: array of transaction buffers
* @trb_pool_dma: dma address of @trb_pool
@ -677,7 +676,6 @@ struct dwc3_ep {
struct list_head pending_list;
struct list_head started_list;
spinlock_t lock;
void __iomem *regs;
struct dwc3_trb *trb_pool;
@ -1014,6 +1012,8 @@ struct dwc3_scratchpad_array {
* @dis_u2_susphy_quirk: set if we disable usb2 suspend phy
* @dis_enblslpm_quirk: set if we clear enblslpm in GUSB2PHYCFG,
* disabling the suspend signal to the PHY.
* @dis_u1_entry_quirk: set if link entering into U1 state needs to be disabled.
* @dis_u2_entry_quirk: set if link entering into U2 state needs to be disabled.
* @dis_rxdet_inp3_quirk: set if we disable Rx.Detect in P3
* @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists
* in GUSB2PHYCFG, specify that USB2 PHY doesn't
@ -1205,6 +1205,8 @@ struct dwc3 {
unsigned dis_u3_susphy_quirk:1;
unsigned dis_u2_susphy_quirk:1;
unsigned dis_enblslpm_quirk:1;
unsigned dis_u1_entry_quirk:1;
unsigned dis_u2_entry_quirk:1;
unsigned dis_rxdet_inp3_quirk:1;
unsigned dis_u2_freeclk_exists_quirk:1;
unsigned dis_del_phy_power_chg_quirk:1;

View File

@ -11,9 +11,7 @@
* - Control registers for each USB2 Ports
* - Control registers for the USB PHY layer
* - SuperSpeed PHY can be enabled only if port is used
*
* TOFIX:
* - Add dynamic OTG switching with ID change interrupt
* - Dynamic OTG switching with ID change interrupt
*/
#include <linux/module.h>
@ -348,6 +346,22 @@ static enum usb_role dwc3_meson_g12a_role_get(struct device *dev)
USB_ROLE_HOST : USB_ROLE_DEVICE;
}
static irqreturn_t dwc3_meson_g12a_irq_thread(int irq, void *data)
{
struct dwc3_meson_g12a *priv = data;
enum phy_mode otg_id;
otg_id = dwc3_meson_g12a_get_id(priv);
if (otg_id != priv->otg_phy_mode) {
if (dwc3_meson_g12a_otg_mode_set(priv, otg_id))
dev_warn(priv->dev, "Failed to switch OTG mode\n");
}
regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_IRQ, 0);
return IRQ_HANDLED;
}
static struct device *dwc3_meson_g12_find_child(struct device *dev,
const char *compatible)
{
@ -374,7 +388,7 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
void __iomem *base;
struct resource *res;
enum phy_mode otg_id;
int ret, i;
int ret, i, irq;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@ -436,6 +450,19 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
/* Get dr_mode */
priv->otg_mode = usb_get_dr_mode(dev);
if (priv->otg_mode == USB_DR_MODE_OTG) {
/* Ack irq before registering */
regmap_update_bits(priv->regmap, USB_R5,
USB_R5_ID_DIG_IRQ, 0);
irq = platform_get_irq(pdev, 0);
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
dwc3_meson_g12a_irq_thread,
IRQF_ONESHOT, pdev->name, priv);
if (ret)
return ret;
}
dwc3_meson_g12a_usb_init(priv);
/* Init PHYs */
@ -460,7 +487,6 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
/* Setup OTG mode corresponding to the ID pin */
if (priv->otg_mode == USB_DR_MODE_OTG) {
/* TOFIX Handle ID mode toggling via IRQ */
otg_id = dwc3_meson_g12a_get_id(priv);
if (otg_id != priv->otg_phy_mode) {
if (dwc3_meson_g12a_otg_mode_set(priv, otg_id))

View File

@ -34,6 +34,8 @@
#define PCI_DEVICE_ID_INTEL_CNPLP 0x9dee
#define PCI_DEVICE_ID_INTEL_CNPH 0xa36e
#define PCI_DEVICE_ID_INTEL_ICLLP 0x34ee
#define PCI_DEVICE_ID_INTEL_EHLLP 0x4b7e
#define PCI_DEVICE_ID_INTEL_TGPLP 0xa0ee
#define PCI_INTEL_BXT_DSM_GUID "732b85d5-b7a7-4a1b-9ba0-4bbd00ffd511"
#define PCI_INTEL_BXT_FUNC_PMU_PWR 4
@ -339,6 +341,12 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP),
(kernel_ulong_t) &dwc3_pci_intel_properties, },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHLLP),
(kernel_ulong_t) &dwc3_pci_intel_properties, },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPLP),
(kernel_ulong_t) &dwc3_pci_intel_properties, },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_NL_USB),
(kernel_ulong_t) &dwc3_pci_amd_properties, },
{ } /* Terminating Entry */

View File

@ -4,6 +4,7 @@
* Inspired by dwc3-of-simple.c
*/
#include <linux/acpi.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/clk.h>
@ -38,6 +39,20 @@
#define PWR_EVNT_LPM_IN_L2_MASK BIT(4)
#define PWR_EVNT_LPM_OUT_L2_MASK BIT(5)
#define SDM845_QSCRATCH_BASE_OFFSET 0xf8800
#define SDM845_QSCRATCH_SIZE 0x400
#define SDM845_DWC3_CORE_SIZE 0xcd00
struct dwc3_acpi_pdata {
u32 qscratch_base_offset;
u32 qscratch_base_size;
u32 dwc3_core_base_size;
int hs_phy_irq_index;
int dp_hs_phy_irq_index;
int dm_hs_phy_irq_index;
int ss_phy_irq_index;
};
struct dwc3_qcom {
struct device *dev;
void __iomem *qscratch_base;
@ -56,6 +71,8 @@ struct dwc3_qcom {
struct notifier_block vbus_nb;
struct notifier_block host_nb;
const struct dwc3_acpi_pdata *acpi_pdata;
enum usb_dr_mode mode;
bool is_suspended;
bool pm_suspended;
@ -300,12 +317,27 @@ static void dwc3_qcom_select_utmi_clk(struct dwc3_qcom *qcom)
PIPE_UTMI_CLK_DIS);
}
static int dwc3_qcom_get_irq(struct platform_device *pdev,
const char *name, int num)
{
struct device_node *np = pdev->dev.of_node;
int ret;
if (np)
ret = platform_get_irq_byname(pdev, name);
else
ret = platform_get_irq(pdev, num);
return ret;
}
static int dwc3_qcom_setup_irq(struct platform_device *pdev)
{
struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
const struct dwc3_acpi_pdata *pdata = qcom->acpi_pdata;
int irq, ret;
irq = platform_get_irq_byname(pdev, "hs_phy_irq");
irq = dwc3_qcom_get_irq(pdev, "hs_phy_irq",
pdata ? pdata->hs_phy_irq_index : -1);
if (irq > 0) {
/* Keep wakeup interrupts disabled until suspend */
irq_set_status_flags(irq, IRQ_NOAUTOEN);
@ -320,7 +352,8 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
qcom->hs_phy_irq = irq;
}
irq = platform_get_irq_byname(pdev, "dp_hs_phy_irq");
irq = dwc3_qcom_get_irq(pdev, "dp_hs_phy_irq",
pdata ? pdata->dp_hs_phy_irq_index : -1);
if (irq > 0) {
irq_set_status_flags(irq, IRQ_NOAUTOEN);
ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
@ -334,7 +367,8 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
qcom->dp_hs_phy_irq = irq;
}
irq = platform_get_irq_byname(pdev, "dm_hs_phy_irq");
irq = dwc3_qcom_get_irq(pdev, "dm_hs_phy_irq",
pdata ? pdata->dm_hs_phy_irq_index : -1);
if (irq > 0) {
irq_set_status_flags(irq, IRQ_NOAUTOEN);
ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
@ -348,7 +382,8 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
qcom->dm_hs_phy_irq = irq;
}
irq = platform_get_irq_byname(pdev, "ss_phy_irq");
irq = dwc3_qcom_get_irq(pdev, "ss_phy_irq",
pdata ? pdata->ss_phy_irq_index : -1);
if (irq > 0) {
irq_set_status_flags(irq, IRQ_NOAUTOEN);
ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
@ -371,11 +406,14 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
struct device_node *np = dev->of_node;
int i;
qcom->num_clocks = count;
if (!count)
if (!np || !count)
return 0;
if (count < 0)
return count;
qcom->num_clocks = count;
qcom->clks = devm_kcalloc(dev, qcom->num_clocks,
sizeof(struct clk *), GFP_KERNEL);
if (!qcom->clks)
@ -409,12 +447,115 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
return 0;
}
static int dwc3_qcom_probe(struct platform_device *pdev)
static const struct property_entry dwc3_qcom_acpi_properties[] = {
PROPERTY_ENTRY_STRING("dr_mode", "host"),
{}
};
static int dwc3_qcom_acpi_register_core(struct platform_device *pdev)
{
struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
struct resource *res, *child_res = NULL;
int irq;
int ret;
qcom->dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
if (!qcom->dwc3)
return -ENOMEM;
qcom->dwc3->dev.parent = dev;
qcom->dwc3->dev.type = dev->type;
qcom->dwc3->dev.dma_mask = dev->dma_mask;
qcom->dwc3->dev.dma_parms = dev->dma_parms;
qcom->dwc3->dev.coherent_dma_mask = dev->coherent_dma_mask;
child_res = kcalloc(2, sizeof(*child_res), GFP_KERNEL);
if (!child_res)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to get memory resource\n");
ret = -ENODEV;
goto out;
}
child_res[0].flags = res->flags;
child_res[0].start = res->start;
child_res[0].end = child_res[0].start +
qcom->acpi_pdata->dwc3_core_base_size;
irq = platform_get_irq(pdev, 0);
child_res[1].flags = IORESOURCE_IRQ;
child_res[1].start = child_res[1].end = irq;
ret = platform_device_add_resources(qcom->dwc3, child_res, 2);
if (ret) {
dev_err(&pdev->dev, "failed to add resources\n");
goto out;
}
ret = platform_device_add_properties(qcom->dwc3,
dwc3_qcom_acpi_properties);
if (ret < 0) {
dev_err(&pdev->dev, "failed to add properties\n");
goto out;
}
ret = platform_device_add(qcom->dwc3);
if (ret)
dev_err(&pdev->dev, "failed to add device\n");
out:
kfree(child_res);
return ret;
}
static int dwc3_qcom_of_register_core(struct platform_device *pdev)
{
struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
struct device_node *np = pdev->dev.of_node, *dwc3_np;
struct device *dev = &pdev->dev;
int ret;
dwc3_np = of_get_child_by_name(np, "dwc3");
if (!dwc3_np) {
dev_err(dev, "failed to find dwc3 core child\n");
return -ENODEV;
}
ret = of_platform_populate(np, NULL, NULL, dev);
if (ret) {
dev_err(dev, "failed to register dwc3 core - %d\n", ret);
return ret;
}
qcom->dwc3 = of_find_device_by_node(dwc3_np);
if (!qcom->dwc3) {
dev_err(dev, "failed to get dwc3 platform device\n");
return -ENODEV;
}
return 0;
}
static const struct dwc3_acpi_pdata sdm845_acpi_pdata = {
.qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET,
.qscratch_base_size = SDM845_QSCRATCH_SIZE,
.dwc3_core_base_size = SDM845_DWC3_CORE_SIZE,
.hs_phy_irq_index = 1,
.dp_hs_phy_irq_index = 4,
.dm_hs_phy_irq_index = 3,
.ss_phy_irq_index = 2
};
static int dwc3_qcom_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct dwc3_qcom *qcom;
struct resource *res;
struct resource *res, *parent_res = NULL;
int ret, i;
bool ignore_pipe_clk;
@ -425,6 +566,14 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, qcom);
qcom->dev = &pdev->dev;
if (has_acpi_companion(dev)) {
qcom->acpi_pdata = acpi_device_get_match_data(dev);
if (!qcom->acpi_pdata) {
dev_err(&pdev->dev, "no supporting ACPI device data\n");
return -EINVAL;
}
}
qcom->resets = devm_reset_control_array_get_optional_exclusive(dev);
if (IS_ERR(qcom->resets)) {
ret = PTR_ERR(qcom->resets);
@ -446,15 +595,28 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
goto reset_assert;
}
ret = dwc3_qcom_clk_init(qcom, of_count_phandle_with_args(np,
"clocks", "#clock-cells"));
ret = dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np));
if (ret) {
dev_err(dev, "failed to get clocks\n");
goto reset_assert;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
qcom->qscratch_base = devm_ioremap_resource(dev, res);
if (np) {
parent_res = res;
} else {
parent_res = kmemdup(res, sizeof(struct resource), GFP_KERNEL);
if (!parent_res)
return -ENOMEM;
parent_res->start = res->start +
qcom->acpi_pdata->qscratch_base_offset;
parent_res->end = parent_res->start +
qcom->acpi_pdata->qscratch_base_size;
}
qcom->qscratch_base = devm_ioremap_resource(dev, parent_res);
if (IS_ERR(qcom->qscratch_base)) {
dev_err(dev, "failed to map qscratch, err=%d\n", ret);
ret = PTR_ERR(qcom->qscratch_base);
@ -462,13 +624,8 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
}
ret = dwc3_qcom_setup_irq(pdev);
if (ret)
goto clk_disable;
dwc3_np = of_get_child_by_name(np, "dwc3");
if (!dwc3_np) {
dev_err(dev, "failed to find dwc3 core child\n");
ret = -ENODEV;
if (ret) {
dev_err(dev, "failed to setup IRQs, err=%d\n", ret);
goto clk_disable;
}
@ -481,16 +638,13 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
if (ignore_pipe_clk)
dwc3_qcom_select_utmi_clk(qcom);
ret = of_platform_populate(np, NULL, NULL, dev);
if (ret) {
dev_err(dev, "failed to register dwc3 core - %d\n", ret);
goto clk_disable;
}
if (np)
ret = dwc3_qcom_of_register_core(pdev);
else
ret = dwc3_qcom_acpi_register_core(pdev);
qcom->dwc3 = of_find_device_by_node(dwc3_np);
if (!qcom->dwc3) {
dev_err(&pdev->dev, "failed to get dwc3 platform device\n");
ret = -ENODEV;
if (ret) {
dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret);
goto depopulate;
}
@ -514,7 +668,10 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
return 0;
depopulate:
of_platform_depopulate(&pdev->dev);
if (np)
of_platform_depopulate(&pdev->dev);
else
platform_device_put(pdev);
clk_disable:
for (i = qcom->num_clocks - 1; i >= 0; i--) {
clk_disable_unprepare(qcom->clks[i]);
@ -601,6 +758,12 @@ static const struct of_device_id dwc3_qcom_of_match[] = {
};
MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match);
static const struct acpi_device_id dwc3_qcom_acpi_match[] = {
{ "QCOM2430", (unsigned long)&sdm845_acpi_pdata },
{ },
};
MODULE_DEVICE_TABLE(acpi, dwc3_qcom_acpi_match);
static struct platform_driver dwc3_qcom_driver = {
.probe = dwc3_qcom_probe,
.remove = dwc3_qcom_remove,
@ -608,6 +771,7 @@ static struct platform_driver dwc3_qcom_driver = {
.name = "dwc3-qcom",
.pm = &dwc3_qcom_dev_pm_ops,
.of_match_table = dwc3_qcom_of_match,
.acpi_match_table = ACPI_PTR(dwc3_qcom_acpi_match),
},
};

View File

@ -379,6 +379,8 @@ static int dwc3_ep0_handle_u1(struct dwc3 *dwc, enum usb_device_state state,
if ((dwc->speed != DWC3_DSTS_SUPERSPEED) &&
(dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS))
return -EINVAL;
if (set && dwc->dis_u1_entry_quirk)
return -EINVAL;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (set)
@ -401,6 +403,8 @@ static int dwc3_ep0_handle_u2(struct dwc3 *dwc, enum usb_device_state state,
if ((dwc->speed != DWC3_DSTS_SUPERSPEED) &&
(dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS))
return -EINVAL;
if (set && dwc->dis_u2_entry_quirk)
return -EINVAL;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (set)
@ -626,7 +630,10 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
* nothing is pending from application.
*/
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA);
if (!dwc->dis_u1_entry_quirk)
reg |= DWC3_DCTL_ACCEPTU1ENA;
if (!dwc->dis_u2_entry_quirk)
reg |= DWC3_DCTL_ACCEPTU2ENA;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
}
break;

View File

@ -2073,6 +2073,25 @@ out:
return 0;
}
static void dwc3_gadget_config_params(struct usb_gadget *g,
struct usb_dcd_config_params *params)
{
struct dwc3 *dwc = gadget_to_dwc(g);
/* U1 Device exit Latency */
if (dwc->dis_u1_entry_quirk)
params->bU1devExitLat = 0;
else
params->bU1devExitLat = DWC3_DEFAULT_U1_DEV_EXIT_LAT;
/* U2 Device exit Latency */
if (dwc->dis_u2_entry_quirk)
params->bU2DevExitLat = 0;
else
params->bU2DevExitLat =
cpu_to_le16(DWC3_DEFAULT_U2_DEV_EXIT_LAT);
}
static void dwc3_gadget_set_speed(struct usb_gadget *g,
enum usb_device_speed speed)
{
@ -2142,6 +2161,7 @@ static const struct usb_gadget_ops dwc3_gadget_ops = {
.udc_start = dwc3_gadget_start,
.udc_stop = dwc3_gadget_stop,
.udc_set_speed = dwc3_gadget_set_speed,
.get_config_params = dwc3_gadget_config_params,
};
/* -------------------------------------------------------------------------- */
@ -2251,8 +2271,6 @@ static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum)
dep->endpoint.comp_desc = NULL;
}
spin_lock_init(&dep->lock);
if (num == 0)
ret = dwc3_gadget_init_control_endpoint(dep);
else if (direction)

View File

@ -48,6 +48,12 @@ struct dwc3;
/* DEPXFERCFG parameter 0 */
#define DWC3_DEPXFERCFG_NUM_XFER_RES(n) ((n) & 0xffff)
/* U1 Device exit Latency */
#define DWC3_DEFAULT_U1_DEV_EXIT_LAT 0x0A /* Less then 10 microsec */
/* U2 Device exit Latency */
#define DWC3_DEFAULT_U2_DEV_EXIT_LAT 0x1FF /* Less then 511 microsec */
/* -------------------------------------------------------------------------- */
#define to_dwc3_request(r) (container_of(r, struct dwc3_request, request))

View File

@ -228,7 +228,7 @@ config USB_CONFIGFS
specified simply by creating appropriate directories in configfs.
Associating functions with configurations is done by creating
appropriate symbolic links.
For more information see Documentation/usb/gadget_configfs.txt.
For more information see Documentation/usb/gadget_configfs.rst.
config USB_CONFIGFS_SERIAL
bool "Generic serial bulk in/out"
@ -441,7 +441,7 @@ config USB_CONFIGFS_F_HID
The HID function driver provides generic emulation of USB
Human Interface Devices (HID).
For more information, see Documentation/usb/gadget_hid.txt.
For more information, see Documentation/usb/gadget_hid.rst.
config USB_CONFIGFS_F_UVC
bool "USB Webcam function"
@ -466,7 +466,7 @@ config USB_CONFIGFS_F_PRINTER
receive or send printer data. It can use ioctl calls to
the device file to get or set printer status.
For more information, see Documentation/usb/gadget_printer.txt
For more information, see Documentation/usb/gadget_printer.rst
which includes sample code for accessing the device file.
config USB_CONFIGFS_F_TCM

View File

@ -653,7 +653,7 @@ static int bos_desc(struct usb_composite_dev *cdev)
/* Get Controller configuration */
if (cdev->gadget->ops->get_config_params) {
cdev->gadget->ops->get_config_params(
cdev->gadget->ops->get_config_params(cdev->gadget,
&dcd_config_params);
} else {
dcd_config_params.bU1devExitLat =

View File

@ -166,7 +166,6 @@ static struct usb_gadget_strings *eem_strings[] = {
static int eem_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
{
struct usb_composite_dev *cdev = f->config->cdev;
int value = -EOPNOTSUPP;
u16 w_index = le16_to_cpu(ctrl->wIndex);
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
@ -176,7 +175,7 @@ static int eem_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
w_value, w_index, w_length);
/* device either stalls (value < 0) or reports success */
return value;
return -EOPNOTSUPP;
}

View File

@ -997,7 +997,6 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
* earlier
*/
gadget = epfile->ffs->gadget;
io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE;
spin_lock_irq(&epfile->ffs->eps_lock);
/* In the meantime, endpoint got disabled or changed. */
@ -1012,6 +1011,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
*/
if (io_data->read)
data_len = usb_ep_align_maybe(gadget, ep->ep, data_len);
io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE;
spin_unlock_irq(&epfile->ffs->eps_lock);
data = ffs_alloc_buffer(io_data, data_len);
@ -1182,11 +1183,12 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
ENTER();
if (!is_sync_kiocb(kiocb)) {
p = kmalloc(sizeof(io_data), GFP_KERNEL);
p = kzalloc(sizeof(io_data), GFP_KERNEL);
if (unlikely(!p))
return -ENOMEM;
p->aio = true;
} else {
memset(p, 0, sizeof(*p));
p->aio = false;
}
@ -1218,11 +1220,12 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
ENTER();
if (!is_sync_kiocb(kiocb)) {
p = kmalloc(sizeof(io_data), GFP_KERNEL);
p = kzalloc(sizeof(io_data), GFP_KERNEL);
if (unlikely(!p))
return -ENOMEM;
p->aio = true;
} else {
memset(p, 0, sizeof(*p));
p->aio = false;
}

View File

@ -47,7 +47,7 @@
*
* For more information about MSF and in particular its module
* parameters and sysfs interface read the
* <Documentation/usb/mass-storage.txt> file.
* <Documentation/usb/mass-storage.rst> file.
*/
/*

View File

@ -40,7 +40,7 @@ struct uac_rtd_params {
void *rbuf;
unsigned max_psize; /* MaxPacketSize of endpoint */
unsigned int max_psize; /* MaxPacketSize of endpoint */
struct uac_req *ureq;
spinlock_t lock;
@ -78,7 +78,7 @@ static const struct snd_pcm_hardware uac_pcm_hardware = {
static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req)
{
unsigned pending;
unsigned int pending;
unsigned long flags, flags2;
unsigned int hw_ptr;
int status = req->status;

View File

@ -186,11 +186,12 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
out = dev->port_usb->out_ep;
else
out = NULL;
spin_unlock_irqrestore(&dev->lock, flags);
if (!out)
{
spin_unlock_irqrestore(&dev->lock, flags);
return -ENOTCONN;
}
/* Padding up to RX_EXTRA handles minor disagreements with host.
* Normally we use the USB "terminate on short read" convention;
@ -214,6 +215,7 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
if (dev->port_usb->is_fixed)
size = max_t(size_t, size, dev->port_usb->fixed_out_len);
spin_unlock_irqrestore(&dev->lock, flags);
skb = __netdev_alloc_skb(dev->net, size + NET_IP_ALIGN, gfp_flags);
if (skb == NULL) {
@ -1004,9 +1006,9 @@ int gether_get_ifname(struct net_device *net, char *name, int len)
int ret;
rtnl_lock();
ret = snprintf(name, len, "%s\n", netdev_name(net));
ret = scnprintf(name, len, "%s\n", netdev_name(net));
rtnl_unlock();
return ret < len ? ret : len;
return ret;
}
EXPORT_SYMBOL_GPL(gether_get_ifname);

View File

@ -153,7 +153,6 @@ config USB_ETH_EEM
depends on USB_ETH
select USB_LIBCOMPOSITE
select USB_F_EEM
default n
help
CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM
and therefore can be supported by more hardware. Technically ECM and
@ -288,7 +287,7 @@ config USB_G_SERIAL
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "g_serial".
For more information, see Documentation/usb/gadget_serial.txt
For more information, see Documentation/usb/gadget_serial.rst
which includes instructions and a "driver info file" needed to
make MS-Windows work with CDC ACM.
@ -322,7 +321,7 @@ config USB_G_PRINTER
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "g_printer".
For more information, see Documentation/usb/gadget_printer.txt
For more information, see Documentation/usb/gadget_printer.rst
which includes sample code for accessing the device file.
if TTY
@ -419,7 +418,6 @@ config USB_G_MULTI_RNDIS
config USB_G_MULTI_CDC
bool "CDC Ethernet + CDC Serial + Storage configuration"
depends on USB_G_MULTI
default n
select USB_F_ECM
help
This option enables a configuration with CDC Ethernet (ECM), CDC
@ -438,7 +436,7 @@ config USB_G_HID
The HID gadget driver provides generic emulation of USB
Human Interface Devices (HID).
For more information, see Documentation/usb/gadget_hid.txt which
For more information, see Documentation/usb/gadget_hid.rst which
includes sample code for accessing the device files.
Say "y" to link the driver statically, or "m" to build a

View File

@ -799,7 +799,6 @@ static int at91_wakeup(struct usb_gadget *gadget)
{
struct at91_udc *udc = to_udc(gadget);
u32 glbstate;
int status = -EINVAL;
unsigned long flags;
DBG("%s\n", __func__ );
@ -818,7 +817,7 @@ static int at91_wakeup(struct usb_gadget *gadget)
done:
spin_unlock_irqrestore(&udc->lock, flags);
return status;
return 0;
}
/* reinit == restore initial software state */

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