phy: for 4.18
*) Add PHY driver for the ATH79 USB PHY *) Add USB3 PHY driver for Mediatek XS-PHY *) Add QUSB/QMP V3 USB3 PHY Support for Qualcomm's SDM845 *) Add runtime PM support for mapphone PHY driver *) Allow phy_pm_runtime_xxx API calls to accept NULL *) Other minor cleanups and fixes Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJbAysjAAoJEA5ceFyATYLZEaAP/jBBQvrUKt0mxOCS7rg/Xv1X 0LDuLTu//qkib+XvlGlMcFW8dgzuSglxvqE/sQqDO35gJl8spmq3rP/VzwbNuahJ 6YOHHLYuQoqgj5urtm7uc+8/MK0B/gRhp4eqESmvL8gdPNujqZeedT2fjBFZJvm+ wm/vUKojWoATOAaKCFC83ShD/6+U+BPTHCfZ3zQZ8ifUZJagOAZuUgr3df1eEz8E IyhKOXU92nnP4mi7g6gtHHPhpBmHu1QqvsjKMkjJ8NM5OWSySGHw5C0Otvytj3tL Y/Hbjc33q4YSsjiU6ZP8wdG7+dgGcrA9Foy4QDdNqFt+NiFT5hY0xmRTOAjpUx2F IyR3AYXGGRqXSxE2DotWQwL1V3zuw/1cjJazO/i+ceQZ9RtVm5IS3aZ4TSx0T6Fh Y55s1Eck8k4H29CxxOJjqrWwzYj1Y/4xnzUf4LpeXpXSr1pStF5rbytiE4G2awqM A9PMqK1WzLvCExhT3BElWn/BllhzeBQGyTeRrIJou6FFjZ0oJysuWip8S2jkM9r0 9SXVO1IfBgysxVXW+xu2iVa2xZeAVgSoEMvF9/AC93di2HPPfMnTqkV7c60B5jgO ELCsxx1HGp0S68Oh7q7K8EhqTx3d3mafCuCS7SxpEJsMR5RqJrY1dJ9/sp89j9IB 6a0Q+bhm/tiPkCb4W/Oc =5D63 -----END PGP SIGNATURE----- Merge tag 'phy-for-4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy into usb-next Kishon writes: phy: for 4.18 *) Add PHY driver for the ATH79 USB PHY *) Add USB3 PHY driver for Mediatek XS-PHY *) Add QUSB/QMP V3 USB3 PHY Support for Qualcomm's SDM845 *) Add runtime PM support for mapphone PHY driver *) Allow phy_pm_runtime_xxx API calls to accept NULL *) Other minor cleanups and fixes Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
This commit is contained in:
commit
2c093cdb0a
|
@ -0,0 +1,109 @@
|
|||
MediaTek XS-PHY binding
|
||||
--------------------------
|
||||
|
||||
The XS-PHY controller supports physical layer functionality for USB3.1
|
||||
GEN2 controller on MediaTek SoCs.
|
||||
|
||||
Required properties (controller (parent) node):
|
||||
- compatible : should be "mediatek,<soc-model>-xsphy", "mediatek,xsphy",
|
||||
soc-model is the name of SoC, such as mt3611 etc;
|
||||
when using "mediatek,xsphy" compatible string, you need SoC specific
|
||||
ones in addition, one of:
|
||||
- "mediatek,mt3611-xsphy"
|
||||
|
||||
- #address-cells, #size-cells : should use the same values as the root node
|
||||
- ranges: must be present
|
||||
|
||||
Optional properties (controller (parent) node):
|
||||
- reg : offset and length of register shared by multiple U3 ports,
|
||||
exclude port's private register, if only U2 ports provided,
|
||||
shouldn't use the property.
|
||||
- mediatek,src-ref-clk-mhz : u32, frequency of reference clock for slew rate
|
||||
calibrate
|
||||
- mediatek,src-coef : u32, coefficient for slew rate calibrate, depends on
|
||||
SoC process
|
||||
|
||||
Required nodes : a sub-node is required for each port the controller
|
||||
provides. Address range information including the usual
|
||||
'reg' property is used inside these nodes to describe
|
||||
the controller's topology.
|
||||
|
||||
Required properties (port (child) node):
|
||||
- reg : address and length of the register set for the port.
|
||||
- clocks : a list of phandle + clock-specifier pairs, one for each
|
||||
entry in clock-names
|
||||
- clock-names : must contain
|
||||
"ref": 48M reference clock for HighSpeed analog phy; and 26M
|
||||
reference clock for SuperSpeedPlus analog phy, sometimes is
|
||||
24M, 25M or 27M, depended on platform.
|
||||
- #phy-cells : should be 1
|
||||
cell after port phandle is phy type from:
|
||||
- PHY_TYPE_USB2
|
||||
- PHY_TYPE_USB3
|
||||
|
||||
The following optional properties are only for debug or HQA test
|
||||
Optional properties (PHY_TYPE_USB2 port (child) node):
|
||||
- mediatek,eye-src : u32, the value of slew rate calibrate
|
||||
- mediatek,eye-vrt : u32, the selection of VRT reference voltage
|
||||
- mediatek,eye-term : u32, the selection of HS_TX TERM reference voltage
|
||||
- mediatek,efuse-intr : u32, the selection of Internal Resistor
|
||||
|
||||
Optional properties (PHY_TYPE_USB3 port (child) node):
|
||||
- mediatek,efuse-intr : u32, the selection of Internal Resistor
|
||||
- mediatek,efuse-tx-imp : u32, the selection of TX Impedance
|
||||
- mediatek,efuse-rx-imp : u32, the selection of RX Impedance
|
||||
|
||||
Banks layout of xsphy
|
||||
-------------------------------------------------------------
|
||||
port offset bank
|
||||
u2 port0 0x0000 MISC
|
||||
0x0100 FMREG
|
||||
0x0300 U2PHY_COM
|
||||
u2 port1 0x1000 MISC
|
||||
0x1100 FMREG
|
||||
0x1300 U2PHY_COM
|
||||
u2 port2 0x2000 MISC
|
||||
...
|
||||
u31 common 0x3000 DIG_GLB
|
||||
0x3100 PHYA_GLB
|
||||
u31 port0 0x3400 DIG_LN_TOP
|
||||
0x3500 DIG_LN_TX0
|
||||
0x3600 DIG_LN_RX0
|
||||
0x3700 DIG_LN_DAIF
|
||||
0x3800 PHYA_LN
|
||||
u31 port1 0x3a00 DIG_LN_TOP
|
||||
0x3b00 DIG_LN_TX0
|
||||
0x3c00 DIG_LN_RX0
|
||||
0x3d00 DIG_LN_DAIF
|
||||
0x3e00 PHYA_LN
|
||||
...
|
||||
|
||||
DIG_GLB & PHYA_GLB are shared by U31 ports.
|
||||
|
||||
Example:
|
||||
|
||||
u3phy: usb-phy@11c40000 {
|
||||
compatible = "mediatek,mt3611-xsphy", "mediatek,xsphy";
|
||||
reg = <0 0x11c43000 0 0x0200>;
|
||||
mediatek,src-ref-clk-mhz = <26>;
|
||||
mediatek,src-coef = <17>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
|
||||
u2port0: usb-phy@11c40000 {
|
||||
reg = <0 0x11c40000 0 0x0400>;
|
||||
clocks = <&clk48m>;
|
||||
clock-names = "ref";
|
||||
mediatek,eye-src = <4>;
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
|
||||
u3port0: usb-phy@11c43000 {
|
||||
reg = <0 0x11c43400 0 0x0500>;
|
||||
clocks = <&clk26m>;
|
||||
clock-names = "ref";
|
||||
mediatek,efuse-intr = <28>;
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
};
|
|
@ -9,7 +9,8 @@ Required properties:
|
|||
"qcom,ipq8074-qmp-pcie-phy" for PCIe phy on IPQ8074
|
||||
"qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996,
|
||||
"qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996,
|
||||
"qcom,qmp-v3-usb3-phy" for USB3 QMP V3 phy.
|
||||
"qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845,
|
||||
"qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845.
|
||||
|
||||
- reg: offset and length of register set for PHY's common serdes block.
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ QUSB2 controller supports LS/FS/HS usb connectivity on Qualcomm chipsets.
|
|||
Required properties:
|
||||
- compatible: compatible list, contains
|
||||
"qcom,msm8996-qusb2-phy" for 14nm PHY on msm8996,
|
||||
"qcom,qusb2-v2-phy" for QUSB2 V2 PHY.
|
||||
"qcom,sdm845-qusb2-phy" for 10nm PHY on sdm845.
|
||||
|
||||
- reg: offset and length of the PHY register set.
|
||||
- #phy-cells: must be 0.
|
||||
|
@ -27,6 +27,27 @@ Optional properties:
|
|||
tuning parameter value for qusb2 phy.
|
||||
|
||||
- qcom,tcsr-syscon: Phandle to TCSR syscon register region.
|
||||
- qcom,imp-res-offset-value: It is a 6 bit value that specifies offset to be
|
||||
added to PHY refgen RESCODE via IMP_CTRL1 register. It is a PHY
|
||||
tuning parameter that may vary for different boards of same SOC.
|
||||
This property is applicable to only QUSB2 v2 PHY (sdm845).
|
||||
- qcom,hstx-trim-value: It is a 4 bit value that specifies tuning for HSTX
|
||||
output current.
|
||||
Possible range is - 15mA to 24mA (stepsize of 600 uA).
|
||||
See dt-bindings/phy/phy-qcom-qusb2.h for applicable values.
|
||||
This property is applicable to only QUSB2 v2 PHY (sdm845).
|
||||
Default value is 22.2mA for sdm845.
|
||||
- qcom,preemphasis-level: It is a 2 bit value that specifies pre-emphasis level.
|
||||
Possible range is 0 to 15% (stepsize of 5%).
|
||||
See dt-bindings/phy/phy-qcom-qusb2.h for applicable values.
|
||||
This property is applicable to only QUSB2 v2 PHY (sdm845).
|
||||
Default value is 10% for sdm845.
|
||||
- qcom,preemphasis-width: It is a 1 bit value that specifies how long the HSTX
|
||||
pre-emphasis (specified using qcom,preemphasis-level) must be in
|
||||
effect. Duration could be half-bit of full-bit.
|
||||
See dt-bindings/phy/phy-qcom-qusb2.h for applicable values.
|
||||
This property is applicable to only QUSB2 v2 PHY (sdm845).
|
||||
Default value is full-bit width for sdm845.
|
||||
|
||||
Example:
|
||||
hsusb_phy: phy@7411000 {
|
||||
|
|
|
@ -2331,6 +2331,14 @@ S: Maintained
|
|||
F: drivers/gpio/gpio-ath79.c
|
||||
F: Documentation/devicetree/bindings/gpio/gpio-ath79.txt
|
||||
|
||||
ATHEROS 71XX/9XXX USB PHY DRIVER
|
||||
M: Alban Bedel <albeu@free.fr>
|
||||
W: https://github.com/AlbanBedel/linux
|
||||
T: git git://github.com/AlbanBedel/linux
|
||||
S: Maintained
|
||||
F: drivers/phy/qualcomm/phy-ath79-usb.c
|
||||
F: Documentation/devicetree/bindings/phy/phy-ath79-usb.txt
|
||||
|
||||
ATHEROS ATH GENERIC UTILITIES
|
||||
M: "Luis R. Rodriguez" <mcgrof@do-not-panic.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
|
|
|
@ -12,3 +12,12 @@ config PHY_MTK_TPHY
|
|||
different banks layout, the T-PHY with shared banks between
|
||||
multi-ports is first version, otherwise is second veriosn,
|
||||
so you can easily distinguish them by banks layout.
|
||||
|
||||
config PHY_MTK_XSPHY
|
||||
tristate "MediaTek XS-PHY Driver"
|
||||
depends on ARCH_MEDIATEK && OF
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support the SuperSpeedPlus XS-PHY transceiver for
|
||||
USB3.1 GEN2 controllers on MediaTek chips. The driver supports
|
||||
multiple USB2.0, USB3.1 GEN2 ports.
|
||||
|
|
|
@ -3,3 +3,4 @@
|
|||
#
|
||||
|
||||
obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o
|
||||
obj-$(CONFIG_PHY_MTK_XSPHY) += phy-mtk-xsphy.o
|
||||
|
|
|
@ -0,0 +1,600 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* MediaTek USB3.1 gen2 xsphy Driver
|
||||
*
|
||||
* Copyright (c) 2018 MediaTek Inc.
|
||||
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <dt-bindings/phy/phy.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/* u2 phy banks */
|
||||
#define SSUSB_SIFSLV_MISC 0x000
|
||||
#define SSUSB_SIFSLV_U2FREQ 0x100
|
||||
#define SSUSB_SIFSLV_U2PHY_COM 0x300
|
||||
|
||||
/* u3 phy shared banks */
|
||||
#define SSPXTP_SIFSLV_DIG_GLB 0x000
|
||||
#define SSPXTP_SIFSLV_PHYA_GLB 0x100
|
||||
|
||||
/* u3 phy banks */
|
||||
#define SSPXTP_SIFSLV_DIG_LN_TOP 0x000
|
||||
#define SSPXTP_SIFSLV_DIG_LN_TX0 0x100
|
||||
#define SSPXTP_SIFSLV_DIG_LN_RX0 0x200
|
||||
#define SSPXTP_SIFSLV_DIG_LN_DAIF 0x300
|
||||
#define SSPXTP_SIFSLV_PHYA_LN 0x400
|
||||
|
||||
#define XSP_U2FREQ_FMCR0 ((SSUSB_SIFSLV_U2FREQ) + 0x00)
|
||||
#define P2F_RG_FREQDET_EN BIT(24)
|
||||
#define P2F_RG_CYCLECNT GENMASK(23, 0)
|
||||
#define P2F_RG_CYCLECNT_VAL(x) ((P2F_RG_CYCLECNT) & (x))
|
||||
|
||||
#define XSP_U2FREQ_MMONR0 ((SSUSB_SIFSLV_U2FREQ) + 0x0c)
|
||||
|
||||
#define XSP_U2FREQ_FMMONR1 ((SSUSB_SIFSLV_U2FREQ) + 0x10)
|
||||
#define P2F_RG_FRCK_EN BIT(8)
|
||||
#define P2F_USB_FM_VALID BIT(0)
|
||||
|
||||
#define XSP_USBPHYACR0 ((SSUSB_SIFSLV_U2PHY_COM) + 0x00)
|
||||
#define P2A0_RG_INTR_EN BIT(5)
|
||||
|
||||
#define XSP_USBPHYACR1 ((SSUSB_SIFSLV_U2PHY_COM) + 0x04)
|
||||
#define P2A1_RG_INTR_CAL GENMASK(23, 19)
|
||||
#define P2A1_RG_INTR_CAL_VAL(x) ((0x1f & (x)) << 19)
|
||||
#define P2A1_RG_VRT_SEL GENMASK(14, 12)
|
||||
#define P2A1_RG_VRT_SEL_VAL(x) ((0x7 & (x)) << 12)
|
||||
#define P2A1_RG_TERM_SEL GENMASK(10, 8)
|
||||
#define P2A1_RG_TERM_SEL_VAL(x) ((0x7 & (x)) << 8)
|
||||
|
||||
#define XSP_USBPHYACR5 ((SSUSB_SIFSLV_U2PHY_COM) + 0x014)
|
||||
#define P2A5_RG_HSTX_SRCAL_EN BIT(15)
|
||||
#define P2A5_RG_HSTX_SRCTRL GENMASK(14, 12)
|
||||
#define P2A5_RG_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12)
|
||||
|
||||
#define XSP_USBPHYACR6 ((SSUSB_SIFSLV_U2PHY_COM) + 0x018)
|
||||
#define P2A6_RG_BC11_SW_EN BIT(23)
|
||||
#define P2A6_RG_OTG_VBUSCMP_EN BIT(20)
|
||||
|
||||
#define XSP_U2PHYDTM1 ((SSUSB_SIFSLV_U2PHY_COM) + 0x06C)
|
||||
#define P2D_FORCE_IDDIG BIT(9)
|
||||
#define P2D_RG_VBUSVALID BIT(5)
|
||||
#define P2D_RG_SESSEND BIT(4)
|
||||
#define P2D_RG_AVALID BIT(2)
|
||||
#define P2D_RG_IDDIG BIT(1)
|
||||
|
||||
#define SSPXTP_PHYA_GLB_00 ((SSPXTP_SIFSLV_PHYA_GLB) + 0x00)
|
||||
#define RG_XTP_GLB_BIAS_INTR_CTRL GENMASK(21, 16)
|
||||
#define RG_XTP_GLB_BIAS_INTR_CTRL_VAL(x) ((0x3f & (x)) << 16)
|
||||
|
||||
#define SSPXTP_PHYA_LN_04 ((SSPXTP_SIFSLV_PHYA_LN) + 0x04)
|
||||
#define RG_XTP_LN0_TX_IMPSEL GENMASK(4, 0)
|
||||
#define RG_XTP_LN0_TX_IMPSEL_VAL(x) (0x1f & (x))
|
||||
|
||||
#define SSPXTP_PHYA_LN_14 ((SSPXTP_SIFSLV_PHYA_LN) + 0x014)
|
||||
#define RG_XTP_LN0_RX_IMPSEL GENMASK(4, 0)
|
||||
#define RG_XTP_LN0_RX_IMPSEL_VAL(x) (0x1f & (x))
|
||||
|
||||
#define XSP_REF_CLK 26 /* MHZ */
|
||||
#define XSP_SLEW_RATE_COEF 17
|
||||
#define XSP_SR_COEF_DIVISOR 1000
|
||||
#define XSP_FM_DET_CYCLE_CNT 1024
|
||||
|
||||
struct xsphy_instance {
|
||||
struct phy *phy;
|
||||
void __iomem *port_base;
|
||||
struct clk *ref_clk; /* reference clock of anolog phy */
|
||||
u32 index;
|
||||
u32 type;
|
||||
/* only for HQA test */
|
||||
int efuse_intr;
|
||||
int efuse_tx_imp;
|
||||
int efuse_rx_imp;
|
||||
/* u2 eye diagram */
|
||||
int eye_src;
|
||||
int eye_vrt;
|
||||
int eye_term;
|
||||
};
|
||||
|
||||
struct mtk_xsphy {
|
||||
struct device *dev;
|
||||
void __iomem *glb_base; /* only shared u3 sif */
|
||||
struct xsphy_instance **phys;
|
||||
int nphys;
|
||||
int src_ref_clk; /* MHZ, reference clock for slew rate calibrate */
|
||||
int src_coef; /* coefficient for slew rate calibrate */
|
||||
};
|
||||
|
||||
static void u2_phy_slew_rate_calibrate(struct mtk_xsphy *xsphy,
|
||||
struct xsphy_instance *inst)
|
||||
{
|
||||
void __iomem *pbase = inst->port_base;
|
||||
int calib_val;
|
||||
int fm_out;
|
||||
u32 tmp;
|
||||
|
||||
/* use force value */
|
||||
if (inst->eye_src)
|
||||
return;
|
||||
|
||||
/* enable USB ring oscillator */
|
||||
tmp = readl(pbase + XSP_USBPHYACR5);
|
||||
tmp |= P2A5_RG_HSTX_SRCAL_EN;
|
||||
writel(tmp, pbase + XSP_USBPHYACR5);
|
||||
udelay(1); /* wait clock stable */
|
||||
|
||||
/* enable free run clock */
|
||||
tmp = readl(pbase + XSP_U2FREQ_FMMONR1);
|
||||
tmp |= P2F_RG_FRCK_EN;
|
||||
writel(tmp, pbase + XSP_U2FREQ_FMMONR1);
|
||||
|
||||
/* set cycle count as 1024 */
|
||||
tmp = readl(pbase + XSP_U2FREQ_FMCR0);
|
||||
tmp &= ~(P2F_RG_CYCLECNT);
|
||||
tmp |= P2F_RG_CYCLECNT_VAL(XSP_FM_DET_CYCLE_CNT);
|
||||
writel(tmp, pbase + XSP_U2FREQ_FMCR0);
|
||||
|
||||
/* enable frequency meter */
|
||||
tmp = readl(pbase + XSP_U2FREQ_FMCR0);
|
||||
tmp |= P2F_RG_FREQDET_EN;
|
||||
writel(tmp, pbase + XSP_U2FREQ_FMCR0);
|
||||
|
||||
/* ignore return value */
|
||||
readl_poll_timeout(pbase + XSP_U2FREQ_FMMONR1, tmp,
|
||||
(tmp & P2F_USB_FM_VALID), 10, 200);
|
||||
|
||||
fm_out = readl(pbase + XSP_U2FREQ_MMONR0);
|
||||
|
||||
/* disable frequency meter */
|
||||
tmp = readl(pbase + XSP_U2FREQ_FMCR0);
|
||||
tmp &= ~P2F_RG_FREQDET_EN;
|
||||
writel(tmp, pbase + XSP_U2FREQ_FMCR0);
|
||||
|
||||
/* disable free run clock */
|
||||
tmp = readl(pbase + XSP_U2FREQ_FMMONR1);
|
||||
tmp &= ~P2F_RG_FRCK_EN;
|
||||
writel(tmp, pbase + XSP_U2FREQ_FMMONR1);
|
||||
|
||||
if (fm_out) {
|
||||
/* (1024 / FM_OUT) x reference clock frequency x coefficient */
|
||||
tmp = xsphy->src_ref_clk * xsphy->src_coef;
|
||||
tmp = (tmp * XSP_FM_DET_CYCLE_CNT) / fm_out;
|
||||
calib_val = DIV_ROUND_CLOSEST(tmp, XSP_SR_COEF_DIVISOR);
|
||||
} else {
|
||||
/* if FM detection fail, set default value */
|
||||
calib_val = 3;
|
||||
}
|
||||
dev_dbg(xsphy->dev, "phy.%d, fm_out:%d, calib:%d (clk:%d, coef:%d)\n",
|
||||
inst->index, fm_out, calib_val,
|
||||
xsphy->src_ref_clk, xsphy->src_coef);
|
||||
|
||||
/* set HS slew rate */
|
||||
tmp = readl(pbase + XSP_USBPHYACR5);
|
||||
tmp &= ~P2A5_RG_HSTX_SRCTRL;
|
||||
tmp |= P2A5_RG_HSTX_SRCTRL_VAL(calib_val);
|
||||
writel(tmp, pbase + XSP_USBPHYACR5);
|
||||
|
||||
/* disable USB ring oscillator */
|
||||
tmp = readl(pbase + XSP_USBPHYACR5);
|
||||
tmp &= ~P2A5_RG_HSTX_SRCAL_EN;
|
||||
writel(tmp, pbase + XSP_USBPHYACR5);
|
||||
}
|
||||
|
||||
static void u2_phy_instance_init(struct mtk_xsphy *xsphy,
|
||||
struct xsphy_instance *inst)
|
||||
{
|
||||
void __iomem *pbase = inst->port_base;
|
||||
u32 tmp;
|
||||
|
||||
/* DP/DM BC1.1 path Disable */
|
||||
tmp = readl(pbase + XSP_USBPHYACR6);
|
||||
tmp &= ~P2A6_RG_BC11_SW_EN;
|
||||
writel(tmp, pbase + XSP_USBPHYACR6);
|
||||
|
||||
tmp = readl(pbase + XSP_USBPHYACR0);
|
||||
tmp |= P2A0_RG_INTR_EN;
|
||||
writel(tmp, pbase + XSP_USBPHYACR0);
|
||||
}
|
||||
|
||||
static void u2_phy_instance_power_on(struct mtk_xsphy *xsphy,
|
||||
struct xsphy_instance *inst)
|
||||
{
|
||||
void __iomem *pbase = inst->port_base;
|
||||
u32 index = inst->index;
|
||||
u32 tmp;
|
||||
|
||||
tmp = readl(pbase + XSP_USBPHYACR6);
|
||||
tmp |= P2A6_RG_OTG_VBUSCMP_EN;
|
||||
writel(tmp, pbase + XSP_USBPHYACR6);
|
||||
|
||||
tmp = readl(pbase + XSP_U2PHYDTM1);
|
||||
tmp |= P2D_RG_VBUSVALID | P2D_RG_AVALID;
|
||||
tmp &= ~P2D_RG_SESSEND;
|
||||
writel(tmp, pbase + XSP_U2PHYDTM1);
|
||||
|
||||
dev_dbg(xsphy->dev, "%s(%d)\n", __func__, index);
|
||||
}
|
||||
|
||||
static void u2_phy_instance_power_off(struct mtk_xsphy *xsphy,
|
||||
struct xsphy_instance *inst)
|
||||
{
|
||||
void __iomem *pbase = inst->port_base;
|
||||
u32 index = inst->index;
|
||||
u32 tmp;
|
||||
|
||||
tmp = readl(pbase + XSP_USBPHYACR6);
|
||||
tmp &= ~P2A6_RG_OTG_VBUSCMP_EN;
|
||||
writel(tmp, pbase + XSP_USBPHYACR6);
|
||||
|
||||
tmp = readl(pbase + XSP_U2PHYDTM1);
|
||||
tmp &= ~(P2D_RG_VBUSVALID | P2D_RG_AVALID);
|
||||
tmp |= P2D_RG_SESSEND;
|
||||
writel(tmp, pbase + XSP_U2PHYDTM1);
|
||||
|
||||
dev_dbg(xsphy->dev, "%s(%d)\n", __func__, index);
|
||||
}
|
||||
|
||||
static void u2_phy_instance_set_mode(struct mtk_xsphy *xsphy,
|
||||
struct xsphy_instance *inst,
|
||||
enum phy_mode mode)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
tmp = readl(inst->port_base + XSP_U2PHYDTM1);
|
||||
switch (mode) {
|
||||
case PHY_MODE_USB_DEVICE:
|
||||
tmp |= P2D_FORCE_IDDIG | P2D_RG_IDDIG;
|
||||
break;
|
||||
case PHY_MODE_USB_HOST:
|
||||
tmp |= P2D_FORCE_IDDIG;
|
||||
tmp &= ~P2D_RG_IDDIG;
|
||||
break;
|
||||
case PHY_MODE_USB_OTG:
|
||||
tmp &= ~(P2D_FORCE_IDDIG | P2D_RG_IDDIG);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
writel(tmp, inst->port_base + XSP_U2PHYDTM1);
|
||||
}
|
||||
|
||||
static void phy_parse_property(struct mtk_xsphy *xsphy,
|
||||
struct xsphy_instance *inst)
|
||||
{
|
||||
struct device *dev = &inst->phy->dev;
|
||||
|
||||
switch (inst->type) {
|
||||
case PHY_TYPE_USB2:
|
||||
device_property_read_u32(dev, "mediatek,efuse-intr",
|
||||
&inst->efuse_intr);
|
||||
device_property_read_u32(dev, "mediatek,eye-src",
|
||||
&inst->eye_src);
|
||||
device_property_read_u32(dev, "mediatek,eye-vrt",
|
||||
&inst->eye_vrt);
|
||||
device_property_read_u32(dev, "mediatek,eye-term",
|
||||
&inst->eye_term);
|
||||
dev_dbg(dev, "intr:%d, src:%d, vrt:%d, term:%d\n",
|
||||
inst->efuse_intr, inst->eye_src,
|
||||
inst->eye_vrt, inst->eye_term);
|
||||
break;
|
||||
case PHY_TYPE_USB3:
|
||||
device_property_read_u32(dev, "mediatek,efuse-intr",
|
||||
&inst->efuse_intr);
|
||||
device_property_read_u32(dev, "mediatek,efuse-tx-imp",
|
||||
&inst->efuse_tx_imp);
|
||||
device_property_read_u32(dev, "mediatek,efuse-rx-imp",
|
||||
&inst->efuse_rx_imp);
|
||||
dev_dbg(dev, "intr:%d, tx-imp:%d, rx-imp:%d\n",
|
||||
inst->efuse_intr, inst->efuse_tx_imp,
|
||||
inst->efuse_rx_imp);
|
||||
break;
|
||||
default:
|
||||
dev_err(xsphy->dev, "incompatible phy type\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void u2_phy_props_set(struct mtk_xsphy *xsphy,
|
||||
struct xsphy_instance *inst)
|
||||
{
|
||||
void __iomem *pbase = inst->port_base;
|
||||
u32 tmp;
|
||||
|
||||
if (inst->efuse_intr) {
|
||||
tmp = readl(pbase + XSP_USBPHYACR1);
|
||||
tmp &= ~P2A1_RG_INTR_CAL;
|
||||
tmp |= P2A1_RG_INTR_CAL_VAL(inst->efuse_intr);
|
||||
writel(tmp, pbase + XSP_USBPHYACR1);
|
||||
}
|
||||
|
||||
if (inst->eye_src) {
|
||||
tmp = readl(pbase + XSP_USBPHYACR5);
|
||||
tmp &= ~P2A5_RG_HSTX_SRCTRL;
|
||||
tmp |= P2A5_RG_HSTX_SRCTRL_VAL(inst->eye_src);
|
||||
writel(tmp, pbase + XSP_USBPHYACR5);
|
||||
}
|
||||
|
||||
if (inst->eye_vrt) {
|
||||
tmp = readl(pbase + XSP_USBPHYACR1);
|
||||
tmp &= ~P2A1_RG_VRT_SEL;
|
||||
tmp |= P2A1_RG_VRT_SEL_VAL(inst->eye_vrt);
|
||||
writel(tmp, pbase + XSP_USBPHYACR1);
|
||||
}
|
||||
|
||||
if (inst->eye_term) {
|
||||
tmp = readl(pbase + XSP_USBPHYACR1);
|
||||
tmp &= ~P2A1_RG_TERM_SEL;
|
||||
tmp |= P2A1_RG_TERM_SEL_VAL(inst->eye_term);
|
||||
writel(tmp, pbase + XSP_USBPHYACR1);
|
||||
}
|
||||
}
|
||||
|
||||
static void u3_phy_props_set(struct mtk_xsphy *xsphy,
|
||||
struct xsphy_instance *inst)
|
||||
{
|
||||
void __iomem *pbase = inst->port_base;
|
||||
u32 tmp;
|
||||
|
||||
if (inst->efuse_intr) {
|
||||
tmp = readl(xsphy->glb_base + SSPXTP_PHYA_GLB_00);
|
||||
tmp &= ~RG_XTP_GLB_BIAS_INTR_CTRL;
|
||||
tmp |= RG_XTP_GLB_BIAS_INTR_CTRL_VAL(inst->efuse_intr);
|
||||
writel(tmp, xsphy->glb_base + SSPXTP_PHYA_GLB_00);
|
||||
}
|
||||
|
||||
if (inst->efuse_tx_imp) {
|
||||
tmp = readl(pbase + SSPXTP_PHYA_LN_04);
|
||||
tmp &= ~RG_XTP_LN0_TX_IMPSEL;
|
||||
tmp |= RG_XTP_LN0_TX_IMPSEL_VAL(inst->efuse_tx_imp);
|
||||
writel(tmp, pbase + SSPXTP_PHYA_LN_04);
|
||||
}
|
||||
|
||||
if (inst->efuse_rx_imp) {
|
||||
tmp = readl(pbase + SSPXTP_PHYA_LN_14);
|
||||
tmp &= ~RG_XTP_LN0_RX_IMPSEL;
|
||||
tmp |= RG_XTP_LN0_RX_IMPSEL_VAL(inst->efuse_rx_imp);
|
||||
writel(tmp, pbase + SSPXTP_PHYA_LN_14);
|
||||
}
|
||||
}
|
||||
|
||||
static int mtk_phy_init(struct phy *phy)
|
||||
{
|
||||
struct xsphy_instance *inst = phy_get_drvdata(phy);
|
||||
struct mtk_xsphy *xsphy = dev_get_drvdata(phy->dev.parent);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(inst->ref_clk);
|
||||
if (ret) {
|
||||
dev_err(xsphy->dev, "failed to enable ref_clk\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (inst->type) {
|
||||
case PHY_TYPE_USB2:
|
||||
u2_phy_instance_init(xsphy, inst);
|
||||
u2_phy_props_set(xsphy, inst);
|
||||
break;
|
||||
case PHY_TYPE_USB3:
|
||||
u3_phy_props_set(xsphy, inst);
|
||||
break;
|
||||
default:
|
||||
dev_err(xsphy->dev, "incompatible phy type\n");
|
||||
clk_disable_unprepare(inst->ref_clk);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_phy_power_on(struct phy *phy)
|
||||
{
|
||||
struct xsphy_instance *inst = phy_get_drvdata(phy);
|
||||
struct mtk_xsphy *xsphy = dev_get_drvdata(phy->dev.parent);
|
||||
|
||||
if (inst->type == PHY_TYPE_USB2) {
|
||||
u2_phy_instance_power_on(xsphy, inst);
|
||||
u2_phy_slew_rate_calibrate(xsphy, inst);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_phy_power_off(struct phy *phy)
|
||||
{
|
||||
struct xsphy_instance *inst = phy_get_drvdata(phy);
|
||||
struct mtk_xsphy *xsphy = dev_get_drvdata(phy->dev.parent);
|
||||
|
||||
if (inst->type == PHY_TYPE_USB2)
|
||||
u2_phy_instance_power_off(xsphy, inst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_phy_exit(struct phy *phy)
|
||||
{
|
||||
struct xsphy_instance *inst = phy_get_drvdata(phy);
|
||||
|
||||
clk_disable_unprepare(inst->ref_clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_phy_set_mode(struct phy *phy, enum phy_mode mode)
|
||||
{
|
||||
struct xsphy_instance *inst = phy_get_drvdata(phy);
|
||||
struct mtk_xsphy *xsphy = dev_get_drvdata(phy->dev.parent);
|
||||
|
||||
if (inst->type == PHY_TYPE_USB2)
|
||||
u2_phy_instance_set_mode(xsphy, inst, mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy *mtk_phy_xlate(struct device *dev,
|
||||
struct of_phandle_args *args)
|
||||
{
|
||||
struct mtk_xsphy *xsphy = dev_get_drvdata(dev);
|
||||
struct xsphy_instance *inst = NULL;
|
||||
struct device_node *phy_np = args->np;
|
||||
int index;
|
||||
|
||||
if (args->args_count != 1) {
|
||||
dev_err(dev, "invalid number of cells in 'phy' property\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
for (index = 0; index < xsphy->nphys; index++)
|
||||
if (phy_np == xsphy->phys[index]->phy->dev.of_node) {
|
||||
inst = xsphy->phys[index];
|
||||
break;
|
||||
}
|
||||
|
||||
if (!inst) {
|
||||
dev_err(dev, "failed to find appropriate phy\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
inst->type = args->args[0];
|
||||
if (!(inst->type == PHY_TYPE_USB2 ||
|
||||
inst->type == PHY_TYPE_USB3)) {
|
||||
dev_err(dev, "unsupported phy type: %d\n", inst->type);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
phy_parse_property(xsphy, inst);
|
||||
|
||||
return inst->phy;
|
||||
}
|
||||
|
||||
static const struct phy_ops mtk_xsphy_ops = {
|
||||
.init = mtk_phy_init,
|
||||
.exit = mtk_phy_exit,
|
||||
.power_on = mtk_phy_power_on,
|
||||
.power_off = mtk_phy_power_off,
|
||||
.set_mode = mtk_phy_set_mode,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct of_device_id mtk_xsphy_id_table[] = {
|
||||
{ .compatible = "mediatek,xsphy", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mtk_xsphy_id_table);
|
||||
|
||||
static int mtk_xsphy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct device_node *child_np;
|
||||
struct phy_provider *provider;
|
||||
struct resource *glb_res;
|
||||
struct mtk_xsphy *xsphy;
|
||||
struct resource res;
|
||||
int port, retval;
|
||||
|
||||
xsphy = devm_kzalloc(dev, sizeof(*xsphy), GFP_KERNEL);
|
||||
if (!xsphy)
|
||||
return -ENOMEM;
|
||||
|
||||
xsphy->nphys = of_get_child_count(np);
|
||||
xsphy->phys = devm_kcalloc(dev, xsphy->nphys,
|
||||
sizeof(*xsphy->phys), GFP_KERNEL);
|
||||
if (!xsphy->phys)
|
||||
return -ENOMEM;
|
||||
|
||||
xsphy->dev = dev;
|
||||
platform_set_drvdata(pdev, xsphy);
|
||||
|
||||
glb_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
/* optional, may not exist if no u3 phys */
|
||||
if (glb_res) {
|
||||
/* get banks shared by multiple u3 phys */
|
||||
xsphy->glb_base = devm_ioremap_resource(dev, glb_res);
|
||||
if (IS_ERR(xsphy->glb_base)) {
|
||||
dev_err(dev, "failed to remap glb regs\n");
|
||||
return PTR_ERR(xsphy->glb_base);
|
||||
}
|
||||
}
|
||||
|
||||
xsphy->src_ref_clk = XSP_REF_CLK;
|
||||
xsphy->src_coef = XSP_SLEW_RATE_COEF;
|
||||
/* update parameters of slew rate calibrate if exist */
|
||||
device_property_read_u32(dev, "mediatek,src-ref-clk-mhz",
|
||||
&xsphy->src_ref_clk);
|
||||
device_property_read_u32(dev, "mediatek,src-coef", &xsphy->src_coef);
|
||||
|
||||
port = 0;
|
||||
for_each_child_of_node(np, child_np) {
|
||||
struct xsphy_instance *inst;
|
||||
struct phy *phy;
|
||||
|
||||
inst = devm_kzalloc(dev, sizeof(*inst), GFP_KERNEL);
|
||||
if (!inst) {
|
||||
retval = -ENOMEM;
|
||||
goto put_child;
|
||||
}
|
||||
|
||||
xsphy->phys[port] = inst;
|
||||
|
||||
phy = devm_phy_create(dev, child_np, &mtk_xsphy_ops);
|
||||
if (IS_ERR(phy)) {
|
||||
dev_err(dev, "failed to create phy\n");
|
||||
retval = PTR_ERR(phy);
|
||||
goto put_child;
|
||||
}
|
||||
|
||||
retval = of_address_to_resource(child_np, 0, &res);
|
||||
if (retval) {
|
||||
dev_err(dev, "failed to get address resource(id-%d)\n",
|
||||
port);
|
||||
goto put_child;
|
||||
}
|
||||
|
||||
inst->port_base = devm_ioremap_resource(&phy->dev, &res);
|
||||
if (IS_ERR(inst->port_base)) {
|
||||
dev_err(dev, "failed to remap phy regs\n");
|
||||
retval = PTR_ERR(inst->port_base);
|
||||
goto put_child;
|
||||
}
|
||||
|
||||
inst->phy = phy;
|
||||
inst->index = port;
|
||||
phy_set_drvdata(phy, inst);
|
||||
port++;
|
||||
|
||||
inst->ref_clk = devm_clk_get(&phy->dev, "ref");
|
||||
if (IS_ERR(inst->ref_clk)) {
|
||||
dev_err(dev, "failed to get ref_clk(id-%d)\n", port);
|
||||
retval = PTR_ERR(inst->ref_clk);
|
||||
goto put_child;
|
||||
}
|
||||
}
|
||||
|
||||
provider = devm_of_phy_provider_register(dev, mtk_phy_xlate);
|
||||
return PTR_ERR_OR_ZERO(provider);
|
||||
|
||||
put_child:
|
||||
of_node_put(child_np);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static struct platform_driver mtk_xsphy_driver = {
|
||||
.probe = mtk_xsphy_probe,
|
||||
.driver = {
|
||||
.name = "mtk-xsphy",
|
||||
.of_match_table = mtk_xsphy_id_table,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(mtk_xsphy_driver);
|
||||
|
||||
MODULE_AUTHOR("Chunfeng Yun <chunfeng.yun@mediatek.com>");
|
||||
MODULE_DESCRIPTION("MediaTek USB XS-PHY driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
#define PHY_MDM6600_PHY_DELAY_MS 4000 /* PHY enable 2.2s to 3.5s */
|
||||
#define PHY_MDM6600_ENABLED_DELAY_MS 8000 /* 8s more total for MDM6600 */
|
||||
#define MDM6600_MODEM_IDLE_DELAY_MS 1000 /* modem after USB suspend */
|
||||
#define MDM6600_MODEM_WAKE_DELAY_MS 200 /* modem response after idle */
|
||||
|
||||
enum phy_mdm6600_ctrl_lines {
|
||||
PHY_MDM6600_ENABLE, /* USB PHY enable */
|
||||
|
@ -93,9 +95,11 @@ struct phy_mdm6600 {
|
|||
struct gpio_descs *cmd_gpios;
|
||||
struct delayed_work bootup_work;
|
||||
struct delayed_work status_work;
|
||||
struct delayed_work modem_wake_work;
|
||||
struct completion ack;
|
||||
bool enabled; /* mdm6600 phy enabled */
|
||||
bool running; /* mdm6600 boot done */
|
||||
bool awake; /* mdm6600 respnds on n_gsm */
|
||||
int status;
|
||||
};
|
||||
|
||||
|
@ -446,6 +450,62 @@ static void phy_mdm6600_deferred_power_on(struct work_struct *work)
|
|||
dev_err(ddata->dev, "Device not functional\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* USB suspend puts mdm6600 into low power mode. For any n_gsm using apps,
|
||||
* we need to keep the modem awake by kicking it's mode0 GPIO. This will
|
||||
* keep the modem awake for about 1.2 seconds. When no n_gsm apps are using
|
||||
* the modem, runtime PM auto mode can be enabled so modem can enter low
|
||||
* power mode.
|
||||
*/
|
||||
static void phy_mdm6600_wake_modem(struct phy_mdm6600 *ddata)
|
||||
{
|
||||
struct gpio_desc *mode_gpio0;
|
||||
|
||||
mode_gpio0 = ddata->mode_gpios->desc[PHY_MDM6600_MODE0];
|
||||
gpiod_set_value_cansleep(mode_gpio0, 1);
|
||||
usleep_range(5, 15);
|
||||
gpiod_set_value_cansleep(mode_gpio0, 0);
|
||||
if (ddata->awake)
|
||||
usleep_range(5, 15);
|
||||
else
|
||||
msleep(MDM6600_MODEM_WAKE_DELAY_MS);
|
||||
}
|
||||
|
||||
static void phy_mdm6600_modem_wake(struct work_struct *work)
|
||||
{
|
||||
struct phy_mdm6600 *ddata;
|
||||
|
||||
ddata = container_of(work, struct phy_mdm6600, modem_wake_work.work);
|
||||
phy_mdm6600_wake_modem(ddata);
|
||||
schedule_delayed_work(&ddata->modem_wake_work,
|
||||
msecs_to_jiffies(MDM6600_MODEM_IDLE_DELAY_MS));
|
||||
}
|
||||
|
||||
static int __maybe_unused phy_mdm6600_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct phy_mdm6600 *ddata = dev_get_drvdata(dev);
|
||||
|
||||
cancel_delayed_work_sync(&ddata->modem_wake_work);
|
||||
ddata->awake = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused phy_mdm6600_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct phy_mdm6600 *ddata = dev_get_drvdata(dev);
|
||||
|
||||
phy_mdm6600_modem_wake(&ddata->modem_wake_work.work);
|
||||
ddata->awake = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops phy_mdm6600_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(phy_mdm6600_runtime_suspend,
|
||||
phy_mdm6600_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct of_device_id phy_mdm6600_id_table[] = {
|
||||
{ .compatible = "motorola,mapphone-mdm6600", },
|
||||
{},
|
||||
|
@ -464,6 +524,7 @@ static int phy_mdm6600_probe(struct platform_device *pdev)
|
|||
INIT_DELAYED_WORK(&ddata->bootup_work,
|
||||
phy_mdm6600_deferred_power_on);
|
||||
INIT_DELAYED_WORK(&ddata->status_work, phy_mdm6600_status);
|
||||
INIT_DELAYED_WORK(&ddata->modem_wake_work, phy_mdm6600_modem_wake);
|
||||
init_completion(&ddata->ack);
|
||||
|
||||
ddata->dev = &pdev->dev;
|
||||
|
@ -500,6 +561,24 @@ static int phy_mdm6600_probe(struct platform_device *pdev)
|
|||
*/
|
||||
msleep(PHY_MDM6600_PHY_DELAY_MS + 500);
|
||||
|
||||
/*
|
||||
* Enable PM runtime only after PHY has been powered up properly.
|
||||
* It is currently only needed after USB suspends mdm6600 and n_gsm
|
||||
* needs to access the device. We don't want to do this earlier as
|
||||
* gpio mode0 pin doubles as mdm6600 wake-up gpio.
|
||||
*/
|
||||
pm_runtime_use_autosuspend(ddata->dev);
|
||||
pm_runtime_set_autosuspend_delay(ddata->dev,
|
||||
MDM6600_MODEM_IDLE_DELAY_MS);
|
||||
pm_runtime_enable(ddata->dev);
|
||||
error = pm_runtime_get_sync(ddata->dev);
|
||||
if (error < 0) {
|
||||
dev_warn(ddata->dev, "failed to wake modem: %i\n", error);
|
||||
pm_runtime_put_noidle(ddata->dev);
|
||||
}
|
||||
pm_runtime_mark_last_busy(ddata->dev);
|
||||
pm_runtime_put_autosuspend(ddata->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
|
@ -512,6 +591,10 @@ static int phy_mdm6600_remove(struct platform_device *pdev)
|
|||
struct phy_mdm6600 *ddata = platform_get_drvdata(pdev);
|
||||
struct gpio_desc *reset_gpio = ddata->ctrl_gpios[PHY_MDM6600_RESET];
|
||||
|
||||
pm_runtime_dont_use_autosuspend(ddata->dev);
|
||||
pm_runtime_put_sync(ddata->dev);
|
||||
pm_runtime_disable(ddata->dev);
|
||||
|
||||
if (!ddata->running)
|
||||
wait_for_completion_timeout(&ddata->ack,
|
||||
msecs_to_jiffies(PHY_MDM6600_ENABLED_DELAY_MS));
|
||||
|
@ -519,6 +602,7 @@ static int phy_mdm6600_remove(struct platform_device *pdev)
|
|||
gpiod_set_value_cansleep(reset_gpio, 1);
|
||||
phy_mdm6600_device_power_off(ddata);
|
||||
|
||||
cancel_delayed_work_sync(&ddata->modem_wake_work);
|
||||
cancel_delayed_work_sync(&ddata->bootup_work);
|
||||
cancel_delayed_work_sync(&ddata->status_work);
|
||||
|
||||
|
@ -530,6 +614,7 @@ static struct platform_driver phy_mdm6600_driver = {
|
|||
.remove = phy_mdm6600_remove,
|
||||
.driver = {
|
||||
.name = "phy-mapphone-mdm6600",
|
||||
.pm = &phy_mdm6600_pm_ops,
|
||||
.of_match_table = of_match_ptr(phy_mdm6600_id_table),
|
||||
},
|
||||
};
|
||||
|
|
|
@ -153,6 +153,9 @@ int phy_pm_runtime_get(struct phy *phy)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (!phy)
|
||||
return 0;
|
||||
|
||||
if (!pm_runtime_enabled(&phy->dev))
|
||||
return -ENOTSUPP;
|
||||
|
||||
|
@ -168,6 +171,9 @@ int phy_pm_runtime_get_sync(struct phy *phy)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (!phy)
|
||||
return 0;
|
||||
|
||||
if (!pm_runtime_enabled(&phy->dev))
|
||||
return -ENOTSUPP;
|
||||
|
||||
|
@ -181,6 +187,9 @@ EXPORT_SYMBOL_GPL(phy_pm_runtime_get_sync);
|
|||
|
||||
int phy_pm_runtime_put(struct phy *phy)
|
||||
{
|
||||
if (!phy)
|
||||
return 0;
|
||||
|
||||
if (!pm_runtime_enabled(&phy->dev))
|
||||
return -ENOTSUPP;
|
||||
|
||||
|
@ -190,6 +199,9 @@ EXPORT_SYMBOL_GPL(phy_pm_runtime_put);
|
|||
|
||||
int phy_pm_runtime_put_sync(struct phy *phy)
|
||||
{
|
||||
if (!phy)
|
||||
return 0;
|
||||
|
||||
if (!pm_runtime_enabled(&phy->dev))
|
||||
return -ENOTSUPP;
|
||||
|
||||
|
@ -199,6 +211,9 @@ EXPORT_SYMBOL_GPL(phy_pm_runtime_put_sync);
|
|||
|
||||
void phy_pm_runtime_allow(struct phy *phy)
|
||||
{
|
||||
if (!phy)
|
||||
return;
|
||||
|
||||
if (!pm_runtime_enabled(&phy->dev))
|
||||
return;
|
||||
|
||||
|
@ -208,6 +223,9 @@ EXPORT_SYMBOL_GPL(phy_pm_runtime_allow);
|
|||
|
||||
void phy_pm_runtime_forbid(struct phy *phy)
|
||||
{
|
||||
if (!phy)
|
||||
return;
|
||||
|
||||
if (!pm_runtime_enabled(&phy->dev))
|
||||
return;
|
||||
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
#
|
||||
# Phy drivers for Qualcomm platforms
|
||||
# Phy drivers for Qualcomm and Atheros platforms
|
||||
#
|
||||
config PHY_ATH79_USB
|
||||
tristate "Atheros AR71XX/9XXX USB PHY driver"
|
||||
depends on OF && (ATH79 || COMPILE_TEST)
|
||||
default y if USB_EHCI_HCD_PLATFORM || USB_OHCI_HCD_PLATFORM
|
||||
select RESET_CONTROLLER
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support the USB PHY on Atheros AR71XX/9XXX SoCs.
|
||||
|
||||
config PHY_QCOM_APQ8064_SATA
|
||||
tristate "Qualcomm APQ8064 SATA SerDes/PHY driver"
|
||||
depends on ARCH_QCOM
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
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_QMP) += phy-qcom-qmp.o
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Atheros AR71XX/9XXX USB PHY driver
|
||||
*
|
||||
* Copyright (C) 2015-2018 Alban Bedel <albeu@free.fr>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
struct ath79_usb_phy {
|
||||
struct reset_control *reset;
|
||||
/* The suspend override logic is inverted, hence the no prefix
|
||||
* to make the code a bit easier to understand.
|
||||
*/
|
||||
struct reset_control *no_suspend_override;
|
||||
};
|
||||
|
||||
static int ath79_usb_phy_power_on(struct phy *phy)
|
||||
{
|
||||
struct ath79_usb_phy *priv = phy_get_drvdata(phy);
|
||||
int err = 0;
|
||||
|
||||
if (priv->no_suspend_override) {
|
||||
err = reset_control_assert(priv->no_suspend_override);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = reset_control_deassert(priv->reset);
|
||||
if (err && priv->no_suspend_override)
|
||||
reset_control_assert(priv->no_suspend_override);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ath79_usb_phy_power_off(struct phy *phy)
|
||||
{
|
||||
struct ath79_usb_phy *priv = phy_get_drvdata(phy);
|
||||
int err = 0;
|
||||
|
||||
err = reset_control_assert(priv->reset);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (priv->no_suspend_override) {
|
||||
err = reset_control_deassert(priv->no_suspend_override);
|
||||
if (err)
|
||||
reset_control_deassert(priv->reset);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct phy_ops ath79_usb_phy_ops = {
|
||||
.power_on = ath79_usb_phy_power_on,
|
||||
.power_off = ath79_usb_phy_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ath79_usb_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ath79_usb_phy *priv;
|
||||
struct phy *phy;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->reset = devm_reset_control_get(&pdev->dev, "usb-phy");
|
||||
if (IS_ERR(priv->reset))
|
||||
return PTR_ERR(priv->reset);
|
||||
|
||||
priv->no_suspend_override = devm_reset_control_get_optional(
|
||||
&pdev->dev, "usb-suspend-override");
|
||||
if (IS_ERR(priv->no_suspend_override))
|
||||
return PTR_ERR(priv->no_suspend_override);
|
||||
|
||||
phy = devm_phy_create(&pdev->dev, NULL, &ath79_usb_phy_ops);
|
||||
if (IS_ERR(phy))
|
||||
return PTR_ERR(phy);
|
||||
|
||||
phy_set_drvdata(phy, priv);
|
||||
|
||||
return PTR_ERR_OR_ZERO(devm_of_phy_provider_register(
|
||||
&pdev->dev, of_phy_simple_xlate));
|
||||
}
|
||||
|
||||
static const struct of_device_id ath79_usb_phy_of_match[] = {
|
||||
{ .compatible = "qca,ar7100-usb-phy" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ath79_usb_phy_of_match);
|
||||
|
||||
static struct platform_driver ath79_usb_phy_driver = {
|
||||
.probe = ath79_usb_phy_probe,
|
||||
.driver = {
|
||||
.of_match_table = ath79_usb_phy_of_match,
|
||||
.name = "ath79-usb-phy",
|
||||
}
|
||||
};
|
||||
module_platform_driver(ath79_usb_phy_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ATH79 USB PHY driver");
|
||||
MODULE_AUTHOR("Alban Bedel <albeu@free.fr>");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -490,6 +490,118 @@ static const struct qmp_phy_init_tbl qmp_v3_usb3_pcs_tbl[] = {
|
|||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_serdes_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL2, 0x08),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x80),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0xab),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0xea),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x02),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xc9),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x34),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x15),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x04),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_CFG, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_BUF_ENABLE, 0x0a),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x31),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x85),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x07),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_tx_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0xc6),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x06),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_rx_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x0c),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x50),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0e),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x03),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1c),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_pcs_tbl[] = {
|
||||
/* FLL settings */
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x40),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02),
|
||||
|
||||
/* Lock Det settings */
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_POWER_STATE_CONFIG2, 0x1b),
|
||||
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0xba),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V1, 0x9f),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V2, 0xb5),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V3, 0x4c),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V4, 0x64),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_LS, 0x6a),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x15),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0d),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V1, 0x15),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V1, 0x0d),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V2, 0x15),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V2, 0x0d),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V3, 0x15),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V3, 0x1d),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V4, 0x15),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V4, 0x0d),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_LS, 0x15),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_LS, 0x0d),
|
||||
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RATE_SLEW_CNTRL, 0x02),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13),
|
||||
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG1, 0x21),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG2, 0x60),
|
||||
};
|
||||
|
||||
|
||||
/* struct qmp_phy_cfg - per-PHY initialization config */
|
||||
struct qmp_phy_cfg {
|
||||
/* phy-type - PCIE/UFS/USB */
|
||||
|
@ -766,6 +878,7 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = {
|
|||
.pwrdn_ctrl = SW_PWRDN,
|
||||
.mask_pcs_ready = PHYSTATUS,
|
||||
|
||||
.has_pwrdn_delay = true,
|
||||
.pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN,
|
||||
.pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX,
|
||||
|
||||
|
@ -774,6 +887,35 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = {
|
|||
.rx_b_lane_offset = 0x400,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = {
|
||||
.type = PHY_TYPE_USB3,
|
||||
.nlanes = 1,
|
||||
|
||||
.serdes_tbl = qmp_v3_usb3_uniphy_serdes_tbl,
|
||||
.serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_uniphy_serdes_tbl),
|
||||
.tx_tbl = qmp_v3_usb3_uniphy_tx_tbl,
|
||||
.tx_tbl_num = ARRAY_SIZE(qmp_v3_usb3_uniphy_tx_tbl),
|
||||
.rx_tbl = qmp_v3_usb3_uniphy_rx_tbl,
|
||||
.rx_tbl_num = ARRAY_SIZE(qmp_v3_usb3_uniphy_rx_tbl),
|
||||
.pcs_tbl = qmp_v3_usb3_uniphy_pcs_tbl,
|
||||
.pcs_tbl_num = ARRAY_SIZE(qmp_v3_usb3_uniphy_pcs_tbl),
|
||||
.clk_list = qmp_v3_phy_clk_l,
|
||||
.num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l),
|
||||
.reset_list = msm8996_usb3phy_reset_l,
|
||||
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
|
||||
.vreg_list = msm8996_phy_vreg_l,
|
||||
.num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l),
|
||||
.regs = qmp_v3_usb3phy_regs_layout,
|
||||
|
||||
.start_ctrl = SERDES_START | PCS_START,
|
||||
.pwrdn_ctrl = SW_PWRDN,
|
||||
.mask_pcs_ready = PHYSTATUS,
|
||||
|
||||
.has_pwrdn_delay = true,
|
||||
.pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN,
|
||||
.pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX,
|
||||
};
|
||||
|
||||
static void qcom_qmp_phy_configure(void __iomem *base,
|
||||
const unsigned int *regs,
|
||||
const struct qmp_phy_init_tbl tbl[],
|
||||
|
@ -793,19 +935,6 @@ static void qcom_qmp_phy_configure(void __iomem *base,
|
|||
}
|
||||
}
|
||||
|
||||
static int qcom_qmp_phy_poweron(struct phy *phy)
|
||||
{
|
||||
struct qmp_phy *qphy = phy_get_drvdata(phy);
|
||||
struct qcom_qmp *qmp = qphy->qmp;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(qphy->pipe_clk);
|
||||
if (ret)
|
||||
dev_err(qmp->dev, "pipe_clk enable failed, err=%d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
|
||||
{
|
||||
const struct qmp_phy_cfg *cfg = qmp->cfg;
|
||||
|
@ -974,6 +1103,12 @@ static int qcom_qmp_phy_init(struct phy *phy)
|
|||
}
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(qphy->pipe_clk);
|
||||
if (ret) {
|
||||
dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret);
|
||||
goto err_clk_enable;
|
||||
}
|
||||
|
||||
/* Tx, Rx, and PCS configurations */
|
||||
qcom_qmp_phy_configure(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num);
|
||||
/* Configuration for other LANE for USB-DP combo PHY */
|
||||
|
@ -1019,6 +1154,8 @@ static int qcom_qmp_phy_init(struct phy *phy)
|
|||
return ret;
|
||||
|
||||
err_pcs_ready:
|
||||
clk_disable_unprepare(qphy->pipe_clk);
|
||||
err_clk_enable:
|
||||
if (cfg->has_lane_rst)
|
||||
reset_control_assert(qphy->lane_rst);
|
||||
err_lane_rst:
|
||||
|
@ -1283,7 +1420,6 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np)
|
|||
static const struct phy_ops qcom_qmp_phy_gen_ops = {
|
||||
.init = qcom_qmp_phy_init,
|
||||
.exit = qcom_qmp_phy_exit,
|
||||
.power_on = qcom_qmp_phy_poweron,
|
||||
.set_mode = qcom_qmp_phy_set_mode,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
@ -1381,8 +1517,11 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
|
|||
.compatible = "qcom,ipq8074-qmp-pcie-phy",
|
||||
.data = &ipq8074_pciephy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,qmp-v3-usb3-phy",
|
||||
.compatible = "qcom,sdm845-qmp-usb3-phy",
|
||||
.data = &qmp_v3_usb3phy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,sdm845-qmp-usb3-uni-phy",
|
||||
.data = &qmp_v3_usb3_uniphy_cfg,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
|
|
@ -214,6 +214,8 @@
|
|||
#define QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN 0x030
|
||||
#define QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034
|
||||
#define QSERDES_V3_RX_RX_TERM_BW 0x07c
|
||||
#define QSERDES_V3_RX_VGA_CAL_CNTRL1 0x0bc
|
||||
#define QSERDES_V3_RX_VGA_CAL_CNTRL2 0x0c0
|
||||
#define QSERDES_V3_RX_RX_EQ_GAIN2_LSB 0x0c8
|
||||
#define QSERDES_V3_RX_RX_EQ_GAIN2_MSB 0x0cc
|
||||
#define QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2 0x0d4
|
||||
|
@ -227,6 +229,7 @@
|
|||
#define QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL 0x10c
|
||||
#define QSERDES_V3_RX_RX_BAND 0x110
|
||||
#define QSERDES_V3_RX_RX_INTERFACE_MODE 0x11c
|
||||
#define QSERDES_V3_RX_RX_MODE_00 0x164
|
||||
|
||||
/* Only for QMP V3 PHY - PCS registers */
|
||||
#define QPHY_V3_PCS_POWER_DOWN_CONTROL 0x004
|
||||
|
@ -273,6 +276,8 @@
|
|||
#define QPHY_V3_PCS_FLL_CNT_VAL_H_TOL 0x0d0
|
||||
#define QPHY_V3_PCS_FLL_MAN_CODE 0x0d4
|
||||
#define QPHY_V3_PCS_RX_SIGDET_LVL 0x1d8
|
||||
#define QPHY_V3_PCS_REFGEN_REQ_CONFIG1 0x20c
|
||||
#define QPHY_V3_PCS_REFGEN_REQ_CONFIG2 0x210
|
||||
|
||||
/* Only for QMP V3 PHY - PCS_MISC registers */
|
||||
#define QPHY_V3_PCS_MISC_CLAMP_ENABLE 0x0c
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include <linux/reset.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <dt-bindings/phy/phy-qcom-qusb2.h>
|
||||
|
||||
#define QUSB2PHY_PLL_TEST 0x04
|
||||
#define CLK_REF_SEL BIT(7)
|
||||
|
||||
|
@ -60,6 +62,17 @@
|
|||
#define CORE_RESET BIT(5)
|
||||
#define CORE_RESET_MUX BIT(6)
|
||||
|
||||
/* QUSB2PHY_IMP_CTRL1 register bits */
|
||||
#define IMP_RES_OFFSET_MASK GENMASK(5, 0)
|
||||
#define IMP_RES_OFFSET_SHIFT 0x0
|
||||
|
||||
/* QUSB2PHY_PORT_TUNE1 register bits */
|
||||
#define HSTX_TRIM_MASK GENMASK(7, 4)
|
||||
#define HSTX_TRIM_SHIFT 0x4
|
||||
#define PREEMPH_WIDTH_HALF_BIT BIT(2)
|
||||
#define PREEMPHASIS_EN_MASK GENMASK(1, 0)
|
||||
#define PREEMPHASIS_EN_SHIFT 0x0
|
||||
|
||||
#define QUSB2PHY_PLL_ANALOG_CONTROLS_TWO 0x04
|
||||
#define QUSB2PHY_PLL_CLOCK_INVERTERS 0x18c
|
||||
#define QUSB2PHY_PLL_CMODE 0x2c
|
||||
|
@ -139,7 +152,7 @@ static const struct qusb2_phy_init_tbl msm8996_init_tbl[] = {
|
|||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
|
||||
};
|
||||
|
||||
static const unsigned int qusb2_v2_regs_layout[] = {
|
||||
static const unsigned int sdm845_regs_layout[] = {
|
||||
[QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8,
|
||||
[QUSB2PHY_PLL_STATUS] = 0x1a0,
|
||||
[QUSB2PHY_PORT_TUNE1] = 0x240,
|
||||
|
@ -153,7 +166,7 @@ static const unsigned int qusb2_v2_regs_layout[] = {
|
|||
[QUSB2PHY_INTR_CTRL] = 0x230,
|
||||
};
|
||||
|
||||
static const struct qusb2_phy_init_tbl qusb2_v2_init_tbl[] = {
|
||||
static const struct qusb2_phy_init_tbl sdm845_init_tbl[] = {
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_ANALOG_CONTROLS_TWO, 0x03),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CLOCK_INVERTERS, 0x7c),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CMODE, 0x80),
|
||||
|
@ -208,10 +221,10 @@ static const struct qusb2_phy_cfg msm8996_phy_cfg = {
|
|||
.autoresume_en = BIT(3),
|
||||
};
|
||||
|
||||
static const struct qusb2_phy_cfg qusb2_v2_phy_cfg = {
|
||||
.tbl = qusb2_v2_init_tbl,
|
||||
.tbl_num = ARRAY_SIZE(qusb2_v2_init_tbl),
|
||||
.regs = qusb2_v2_regs_layout,
|
||||
static const struct qusb2_phy_cfg sdm845_phy_cfg = {
|
||||
.tbl = sdm845_init_tbl,
|
||||
.tbl_num = ARRAY_SIZE(sdm845_init_tbl),
|
||||
.regs = sdm845_regs_layout,
|
||||
|
||||
.disable_ctrl = (PWR_CTRL1_VREF_SUPPLY_TRIM | PWR_CTRL1_CLAMP_N_EN |
|
||||
POWER_DOWN),
|
||||
|
@ -241,6 +254,15 @@ static const char * const qusb2_phy_vreg_names[] = {
|
|||
* @tcsr: TCSR syscon register map
|
||||
* @cell: nvmem cell containing phy tuning value
|
||||
*
|
||||
* @override_imp_res_offset: PHY should use different rescode offset
|
||||
* @imp_res_offset_value: rescode offset to be updated in IMP_CTRL1 register
|
||||
* @override_hstx_trim: PHY should use different HSTX o/p current value
|
||||
* @hstx_trim_value: HSTX_TRIM value to be updated in TUNE1 register
|
||||
* @override_preemphasis: PHY should use different pre-amphasis amplitude
|
||||
* @preemphasis_level: Amplitude Pre-Emphasis to be updated in TUNE1 register
|
||||
* @override_preemphasis_width: PHY should use different pre-emphasis duration
|
||||
* @preemphasis_width: half/full-width Pre-Emphasis updated via TUNE1
|
||||
*
|
||||
* @cfg: phy config data
|
||||
* @has_se_clk_scheme: indicate if PHY has single-ended ref clock scheme
|
||||
* @phy_initialized: indicate if PHY has been initialized
|
||||
|
@ -259,12 +281,35 @@ struct qusb2_phy {
|
|||
struct regmap *tcsr;
|
||||
struct nvmem_cell *cell;
|
||||
|
||||
bool override_imp_res_offset;
|
||||
u8 imp_res_offset_value;
|
||||
bool override_hstx_trim;
|
||||
u8 hstx_trim_value;
|
||||
bool override_preemphasis;
|
||||
u8 preemphasis_level;
|
||||
bool override_preemphasis_width;
|
||||
u8 preemphasis_width;
|
||||
|
||||
const struct qusb2_phy_cfg *cfg;
|
||||
bool has_se_clk_scheme;
|
||||
bool phy_initialized;
|
||||
enum phy_mode mode;
|
||||
};
|
||||
|
||||
static inline void qusb2_write_mask(void __iomem *base, u32 offset,
|
||||
u32 val, u32 mask)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = readl(base + offset);
|
||||
reg &= ~mask;
|
||||
reg |= val & mask;
|
||||
writel(reg, base + offset);
|
||||
|
||||
/* Ensure above write is completed */
|
||||
readl(base + offset);
|
||||
}
|
||||
|
||||
static inline void qusb2_setbits(void __iomem *base, u32 offset, u32 val)
|
||||
{
|
||||
u32 reg;
|
||||
|
@ -304,6 +349,42 @@ void qcom_qusb2_phy_configure(void __iomem *base,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update board specific PHY tuning override values if specified from
|
||||
* device tree.
|
||||
*/
|
||||
static void qusb2_phy_override_phy_params(struct qusb2_phy *qphy)
|
||||
{
|
||||
const struct qusb2_phy_cfg *cfg = qphy->cfg;
|
||||
|
||||
if (qphy->override_imp_res_offset)
|
||||
qusb2_write_mask(qphy->base, QUSB2PHY_IMP_CTRL1,
|
||||
qphy->imp_res_offset_value << IMP_RES_OFFSET_SHIFT,
|
||||
IMP_RES_OFFSET_MASK);
|
||||
|
||||
if (qphy->override_hstx_trim)
|
||||
qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1],
|
||||
qphy->hstx_trim_value << HSTX_TRIM_SHIFT,
|
||||
HSTX_TRIM_MASK);
|
||||
|
||||
if (qphy->override_preemphasis)
|
||||
qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1],
|
||||
qphy->preemphasis_level << PREEMPHASIS_EN_SHIFT,
|
||||
PREEMPHASIS_EN_MASK);
|
||||
|
||||
if (qphy->override_preemphasis_width) {
|
||||
if (qphy->preemphasis_width ==
|
||||
QUSB2_V2_PREEMPHASIS_WIDTH_HALF_BIT)
|
||||
qusb2_setbits(qphy->base,
|
||||
cfg->regs[QUSB2PHY_PORT_TUNE1],
|
||||
PREEMPH_WIDTH_HALF_BIT);
|
||||
else
|
||||
qusb2_clrbits(qphy->base,
|
||||
cfg->regs[QUSB2PHY_PORT_TUNE1],
|
||||
PREEMPH_WIDTH_HALF_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetches HS Tx tuning value from nvmem and sets the
|
||||
* QUSB2PHY_PORT_TUNE1/2 register.
|
||||
|
@ -315,6 +396,10 @@ static void qusb2_phy_set_tune2_param(struct qusb2_phy *qphy)
|
|||
const struct qusb2_phy_cfg *cfg = qphy->cfg;
|
||||
u8 *val;
|
||||
|
||||
/* efuse register is optional */
|
||||
if (!qphy->cell)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Read efuse register having TUNE2/1 parameter's high nibble.
|
||||
* If efuse register shows value as 0x0, or if we fail to find
|
||||
|
@ -521,6 +606,9 @@ static int qusb2_phy_init(struct phy *phy)
|
|||
qcom_qusb2_phy_configure(qphy->base, cfg->regs, cfg->tbl,
|
||||
cfg->tbl_num);
|
||||
|
||||
/* Override board specific PHY tuning values */
|
||||
qusb2_phy_override_phy_params(qphy);
|
||||
|
||||
/* Set efuse value for tuning the PHY */
|
||||
qusb2_phy_set_tune2_param(qphy);
|
||||
|
||||
|
@ -643,8 +731,8 @@ static const struct of_device_id qusb2_phy_of_match_table[] = {
|
|||
.compatible = "qcom,msm8996-qusb2-phy",
|
||||
.data = &msm8996_phy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,qusb2-v2-phy",
|
||||
.data = &qusb2_v2_phy_cfg,
|
||||
.compatible = "qcom,sdm845-qusb2-phy",
|
||||
.data = &sdm845_phy_cfg,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
@ -664,6 +752,7 @@ static int qusb2_phy_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
int ret, i;
|
||||
int num;
|
||||
u32 value;
|
||||
|
||||
qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
|
||||
if (!qphy)
|
||||
|
@ -732,6 +821,31 @@ static int qusb2_phy_probe(struct platform_device *pdev)
|
|||
qphy->cell = NULL;
|
||||
dev_dbg(dev, "failed to lookup tune2 hstx trim value\n");
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(dev->of_node, "qcom,imp-res-offset-value",
|
||||
&value)) {
|
||||
qphy->imp_res_offset_value = (u8)value;
|
||||
qphy->override_imp_res_offset = true;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(dev->of_node, "qcom,hstx-trim-value",
|
||||
&value)) {
|
||||
qphy->hstx_trim_value = (u8)value;
|
||||
qphy->override_hstx_trim = true;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-level",
|
||||
&value)) {
|
||||
qphy->preemphasis_level = (u8)value;
|
||||
qphy->override_preemphasis = true;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-width",
|
||||
&value)) {
|
||||
qphy->preemphasis_width = (u8)value;
|
||||
qphy->override_preemphasis_width = true;
|
||||
}
|
||||
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
/*
|
||||
|
|
|
@ -231,33 +231,27 @@ struct exynos_mipi_video_phy {
|
|||
static int __set_phy_state(const struct exynos_mipi_phy_desc *data,
|
||||
struct exynos_mipi_video_phy *state, unsigned int on)
|
||||
{
|
||||
u32 val;
|
||||
struct regmap *enable_map = state->regmaps[data->enable_map];
|
||||
struct regmap *resetn_map = state->regmaps[data->resetn_map];
|
||||
|
||||
spin_lock(&state->slock);
|
||||
|
||||
/* disable in PMU sysreg */
|
||||
if (!on && data->coupled_phy_id >= 0 &&
|
||||
state->phys[data->coupled_phy_id].phy->power_count == 0) {
|
||||
regmap_read(state->regmaps[data->enable_map], data->enable_reg,
|
||||
&val);
|
||||
val &= ~data->enable_val;
|
||||
regmap_write(state->regmaps[data->enable_map], data->enable_reg,
|
||||
val);
|
||||
}
|
||||
|
||||
state->phys[data->coupled_phy_id].phy->power_count == 0)
|
||||
regmap_update_bits(enable_map, data->enable_reg,
|
||||
data->enable_val, 0);
|
||||
/* PHY reset */
|
||||
regmap_read(state->regmaps[data->resetn_map], data->resetn_reg, &val);
|
||||
val = on ? (val | data->resetn_val) : (val & ~data->resetn_val);
|
||||
regmap_write(state->regmaps[data->resetn_map], data->resetn_reg, val);
|
||||
|
||||
if (on)
|
||||
regmap_update_bits(resetn_map, data->resetn_reg,
|
||||
data->resetn_val, data->resetn_val);
|
||||
else
|
||||
regmap_update_bits(resetn_map, data->resetn_reg,
|
||||
data->resetn_val, 0);
|
||||
/* enable in PMU sysreg */
|
||||
if (on) {
|
||||
regmap_read(state->regmaps[data->enable_map], data->enable_reg,
|
||||
&val);
|
||||
val |= data->enable_val;
|
||||
regmap_write(state->regmaps[data->enable_map], data->enable_reg,
|
||||
val);
|
||||
}
|
||||
if (on)
|
||||
regmap_update_bits(enable_map, data->enable_reg,
|
||||
data->enable_val, data->enable_val);
|
||||
|
||||
spin_unlock(&state->slock);
|
||||
|
||||
|
|
|
@ -71,7 +71,6 @@ struct stm32_usbphyc {
|
|||
struct stm32_usbphyc_phy **phys;
|
||||
int nphys;
|
||||
int switch_setup;
|
||||
bool pll_enabled;
|
||||
};
|
||||
|
||||
static inline void stm32_usbphyc_set_bits(void __iomem *reg, u32 bits)
|
||||
|
@ -84,7 +83,8 @@ static inline void stm32_usbphyc_clr_bits(void __iomem *reg, u32 bits)
|
|||
writel_relaxed(readl_relaxed(reg) & ~bits, reg);
|
||||
}
|
||||
|
||||
static void stm32_usbphyc_get_pll_params(u32 clk_rate, struct pll_params *pll_params)
|
||||
static void stm32_usbphyc_get_pll_params(u32 clk_rate,
|
||||
struct pll_params *pll_params)
|
||||
{
|
||||
unsigned long long fvco, ndiv, frac;
|
||||
|
||||
|
@ -271,7 +271,6 @@ static struct phy *stm32_usbphyc_of_xlate(struct device *dev,
|
|||
struct stm32_usbphyc *usbphyc = dev_get_drvdata(dev);
|
||||
struct stm32_usbphyc_phy *usbphyc_phy = NULL;
|
||||
struct device_node *phynode = args->np;
|
||||
|
||||
int port = 0;
|
||||
|
||||
for (port = 0; port < usbphyc->nphys; port++) {
|
||||
|
@ -367,8 +366,8 @@ static int stm32_usbphyc_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(phy)) {
|
||||
ret = PTR_ERR(phy);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev,
|
||||
"failed to create phy%d: %d\n", i, ret);
|
||||
dev_err(dev, "failed to create phy%d: %d\n",
|
||||
port, ret);
|
||||
goto put_child;
|
||||
}
|
||||
|
||||
|
|
|
@ -102,19 +102,6 @@ tegra_xusb_pad_find_phy_node(struct tegra_xusb_pad *pad, unsigned int index)
|
|||
return np;
|
||||
}
|
||||
|
||||
static int
|
||||
tegra_xusb_lane_lookup_function(struct tegra_xusb_lane *lane,
|
||||
const char *function)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < lane->soc->num_funcs; i++)
|
||||
if (strcmp(function, lane->soc->funcs[i]) == 0)
|
||||
return i;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int tegra_xusb_lane_parse_dt(struct tegra_xusb_lane *lane,
|
||||
struct device_node *np)
|
||||
{
|
||||
|
@ -126,7 +113,7 @@ int tegra_xusb_lane_parse_dt(struct tegra_xusb_lane *lane,
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = tegra_xusb_lane_lookup_function(lane, function);
|
||||
err = match_string(lane->soc->funcs, lane->soc->num_funcs, function);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "invalid function \"%s\" for lane \"%s\"\n",
|
||||
function, np->name);
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DT_BINDINGS_QCOM_PHY_QUSB2_H_
|
||||
#define _DT_BINDINGS_QCOM_PHY_QUSB2_H_
|
||||
|
||||
/* PHY HSTX TRIM bit values (24mA to 15mA) */
|
||||
#define QUSB2_V2_HSTX_TRIM_24_0_MA 0x0
|
||||
#define QUSB2_V2_HSTX_TRIM_23_4_MA 0x1
|
||||
#define QUSB2_V2_HSTX_TRIM_22_8_MA 0x2
|
||||
#define QUSB2_V2_HSTX_TRIM_22_2_MA 0x3
|
||||
#define QUSB2_V2_HSTX_TRIM_21_6_MA 0x4
|
||||
#define QUSB2_V2_HSTX_TRIM_21_0_MA 0x5
|
||||
#define QUSB2_V2_HSTX_TRIM_20_4_MA 0x6
|
||||
#define QUSB2_V2_HSTX_TRIM_19_8_MA 0x7
|
||||
#define QUSB2_V2_HSTX_TRIM_19_2_MA 0x8
|
||||
#define QUSB2_V2_HSTX_TRIM_18_6_MA 0x9
|
||||
#define QUSB2_V2_HSTX_TRIM_18_0_MA 0xa
|
||||
#define QUSB2_V2_HSTX_TRIM_17_4_MA 0xb
|
||||
#define QUSB2_V2_HSTX_TRIM_16_8_MA 0xc
|
||||
#define QUSB2_V2_HSTX_TRIM_16_2_MA 0xd
|
||||
#define QUSB2_V2_HSTX_TRIM_15_6_MA 0xe
|
||||
#define QUSB2_V2_HSTX_TRIM_15_0_MA 0xf
|
||||
|
||||
/* PHY PREEMPHASIS bit values */
|
||||
#define QUSB2_V2_PREEMPHASIS_NONE 0
|
||||
#define QUSB2_V2_PREEMPHASIS_5_PERCENT 1
|
||||
#define QUSB2_V2_PREEMPHASIS_10_PERCENT 2
|
||||
#define QUSB2_V2_PREEMPHASIS_15_PERCENT 3
|
||||
|
||||
/* PHY PREEMPHASIS-WIDTH bit values */
|
||||
#define QUSB2_V2_PREEMPHASIS_WIDTH_FULL_BIT 0
|
||||
#define QUSB2_V2_PREEMPHASIS_WIDTH_HALF_BIT 1
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue