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:
commit
17a20acaf1
|
@ -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>;
|
||||
};
|
|
@ -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>;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
|
@ -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>;
|
||||
};
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -101,6 +101,7 @@ needed).
|
|||
filesystems/index
|
||||
vm/index
|
||||
bpf/index
|
||||
usb/index
|
||||
misc-devices/index
|
||||
|
||||
Architecture-specific documentation
|
||||
|
|
|
@ -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)
|
|
@ -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`
|
|
@ -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:
|
12
MAINTAINERS
12
MAINTAINERS
|
@ -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
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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 */
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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--;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue