提交 2c093cdb 编写于 作者: G Greg Kroah-Hartman

Merge tag 'phy-for-4.18' of...

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: NKishon Vijay Abraham I <kishon@ti.com>
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
// 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;
......
#
# 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
......
# 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
......
// 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);
......
/* 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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册