xref: /openbmc/linux/drivers/phy/hisilicon/phy-hi3670-usb3.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
18de6b7edSMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0-only
28de6b7edSMauro Carvalho Chehab /*
38de6b7edSMauro Carvalho Chehab  * Phy provider for USB 3.1 controller on HiSilicon Kirin970 platform
48de6b7edSMauro Carvalho Chehab  *
58de6b7edSMauro Carvalho Chehab  * Copyright (C) 2017-2020 Hilisicon Electronics Co., Ltd.
68de6b7edSMauro Carvalho Chehab  *		http://www.huawei.com
78de6b7edSMauro Carvalho Chehab  *
88de6b7edSMauro Carvalho Chehab  * Authors: Yu Chen <chenyu56@huawei.com>
98de6b7edSMauro Carvalho Chehab  */
108de6b7edSMauro Carvalho Chehab 
118de6b7edSMauro Carvalho Chehab #include <linux/bitfield.h>
128de6b7edSMauro Carvalho Chehab #include <linux/clk.h>
138de6b7edSMauro Carvalho Chehab #include <linux/kernel.h>
148de6b7edSMauro Carvalho Chehab #include <linux/mfd/syscon.h>
158de6b7edSMauro Carvalho Chehab #include <linux/module.h>
16*7559e757SRob Herring #include <linux/of.h>
178de6b7edSMauro Carvalho Chehab #include <linux/phy/phy.h>
188de6b7edSMauro Carvalho Chehab #include <linux/platform_device.h>
198de6b7edSMauro Carvalho Chehab #include <linux/regmap.h>
208de6b7edSMauro Carvalho Chehab 
218de6b7edSMauro Carvalho Chehab #define SCTRL_SCDEEPSLEEPED		(0x0)
228de6b7edSMauro Carvalho Chehab #define USB_CLK_SELECTED		BIT(20)
238de6b7edSMauro Carvalho Chehab 
248de6b7edSMauro Carvalho Chehab #define PERI_CRG_PEREN0			(0x00)
258de6b7edSMauro Carvalho Chehab #define PERI_CRG_PERDIS0		(0x04)
268de6b7edSMauro Carvalho Chehab #define PERI_CRG_PEREN4			(0x40)
278de6b7edSMauro Carvalho Chehab #define PERI_CRG_PERDIS4		(0x44)
288de6b7edSMauro Carvalho Chehab #define PERI_CRG_PERRSTEN4		(0x90)
298de6b7edSMauro Carvalho Chehab #define PERI_CRG_PERRSTDIS4		(0x94)
308de6b7edSMauro Carvalho Chehab #define PERI_CRG_ISODIS			(0x148)
318de6b7edSMauro Carvalho Chehab #define PERI_CRG_PEREN6			(0x410)
328de6b7edSMauro Carvalho Chehab #define PERI_CRG_PERDIS6		(0x414)
338de6b7edSMauro Carvalho Chehab 
348de6b7edSMauro Carvalho Chehab #define USB_REFCLK_ISO_EN		BIT(25)
358de6b7edSMauro Carvalho Chehab 
368de6b7edSMauro Carvalho Chehab #define GT_CLK_USB2PHY_REF		BIT(19)
378de6b7edSMauro Carvalho Chehab 
388de6b7edSMauro Carvalho Chehab #define PCTRL_PERI_CTRL3		(0x10)
398de6b7edSMauro Carvalho Chehab #define PCTRL_PERI_CTRL3_MSK_START	(16)
408de6b7edSMauro Carvalho Chehab #define USB_TCXO_EN			BIT(1)
418de6b7edSMauro Carvalho Chehab 
428de6b7edSMauro Carvalho Chehab #define PCTRL_PERI_CTRL24		(0x64)
438de6b7edSMauro Carvalho Chehab #define SC_CLK_USB3PHY_3MUX1_SEL	BIT(25)
448de6b7edSMauro Carvalho Chehab 
458de6b7edSMauro Carvalho Chehab #define USB3OTG_CTRL0			(0x00)
468de6b7edSMauro Carvalho Chehab #define USB3OTG_CTRL3			(0x0c)
478de6b7edSMauro Carvalho Chehab #define USB3OTG_CTRL4			(0x10)
488de6b7edSMauro Carvalho Chehab #define USB3OTG_CTRL5			(0x14)
498de6b7edSMauro Carvalho Chehab #define USB3OTG_CTRL7			(0x1c)
508de6b7edSMauro Carvalho Chehab #define USB_MISC_CFG50			(0x50)
518de6b7edSMauro Carvalho Chehab #define USB_MISC_CFG54			(0x54)
528de6b7edSMauro Carvalho Chehab #define USB_MISC_CFG58			(0x58)
538de6b7edSMauro Carvalho Chehab #define USB_MISC_CFG5C			(0x5c)
548de6b7edSMauro Carvalho Chehab #define USB_MISC_CFGA0			(0xa0)
558de6b7edSMauro Carvalho Chehab #define TCA_CLK_RST			(0x200)
568de6b7edSMauro Carvalho Chehab #define TCA_INTR_EN			(0x204)
578de6b7edSMauro Carvalho Chehab #define TCA_INTR_STS			(0x208)
588de6b7edSMauro Carvalho Chehab #define TCA_GCFG			(0x210)
598de6b7edSMauro Carvalho Chehab #define TCA_TCPC			(0x214)
608de6b7edSMauro Carvalho Chehab #define TCA_SYSMODE_CFG			(0x218)
618de6b7edSMauro Carvalho Chehab #define TCA_VBUS_CTRL			(0x240)
628de6b7edSMauro Carvalho Chehab 
638de6b7edSMauro Carvalho Chehab #define CTRL0_USB3_VBUSVLD		BIT(7)
648de6b7edSMauro Carvalho Chehab #define CTRL0_USB3_VBUSVLD_SEL		BIT(6)
658de6b7edSMauro Carvalho Chehab 
668de6b7edSMauro Carvalho Chehab #define CTRL3_USB2_VBUSVLDEXT0		BIT(6)
678de6b7edSMauro Carvalho Chehab #define CTRL3_USB2_VBUSVLDEXTSEL0	BIT(5)
688de6b7edSMauro Carvalho Chehab 
698de6b7edSMauro Carvalho Chehab #define CTRL5_USB2_SIDDQ		BIT(0)
708de6b7edSMauro Carvalho Chehab 
718de6b7edSMauro Carvalho Chehab #define CTRL7_USB2_REFCLKSEL_MASK	GENMASK(4, 3)
728de6b7edSMauro Carvalho Chehab #define CTRL7_USB2_REFCLKSEL_ABB	(BIT(4) | BIT(3))
738de6b7edSMauro Carvalho Chehab #define CTRL7_USB2_REFCLKSEL_PAD	BIT(4)
748de6b7edSMauro Carvalho Chehab 
758de6b7edSMauro Carvalho Chehab #define CFG50_USB3_PHY_TEST_POWERDOWN	BIT(23)
768de6b7edSMauro Carvalho Chehab 
778de6b7edSMauro Carvalho Chehab #define CFG54_USB31PHY_CR_ADDR_MASK	GENMASK(31, 16)
788de6b7edSMauro Carvalho Chehab 
798de6b7edSMauro Carvalho Chehab #define CFG54_USB3PHY_REF_USE_PAD	BIT(12)
808de6b7edSMauro Carvalho Chehab #define CFG54_PHY0_PMA_PWR_STABLE	BIT(11)
818de6b7edSMauro Carvalho Chehab #define CFG54_PHY0_PCS_PWR_STABLE	BIT(9)
828de6b7edSMauro Carvalho Chehab #define CFG54_USB31PHY_CR_ACK		BIT(7)
838de6b7edSMauro Carvalho Chehab #define CFG54_USB31PHY_CR_WR_EN		BIT(5)
848de6b7edSMauro Carvalho Chehab #define CFG54_USB31PHY_CR_SEL		BIT(4)
858de6b7edSMauro Carvalho Chehab #define CFG54_USB31PHY_CR_RD_EN		BIT(3)
868de6b7edSMauro Carvalho Chehab #define CFG54_USB31PHY_CR_CLK		BIT(2)
878de6b7edSMauro Carvalho Chehab #define CFG54_USB3_PHY0_ANA_PWR_EN	BIT(1)
888de6b7edSMauro Carvalho Chehab 
898de6b7edSMauro Carvalho Chehab #define CFG58_USB31PHY_CR_DATA_MASK     GENMASK(31, 16)
908de6b7edSMauro Carvalho Chehab 
918de6b7edSMauro Carvalho Chehab #define CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN	BIT(1)
928de6b7edSMauro Carvalho Chehab 
938de6b7edSMauro Carvalho Chehab #define CFGA0_VAUX_RESET		BIT(9)
948de6b7edSMauro Carvalho Chehab #define CFGA0_USB31C_RESET		BIT(8)
958de6b7edSMauro Carvalho Chehab #define CFGA0_USB2PHY_REFCLK_SELECT	BIT(4)
968de6b7edSMauro Carvalho Chehab #define CFGA0_USB3PHY_RESET		BIT(1)
978de6b7edSMauro Carvalho Chehab #define CFGA0_USB2PHY_POR		BIT(0)
988de6b7edSMauro Carvalho Chehab 
998de6b7edSMauro Carvalho Chehab #define INTR_EN_XA_TIMEOUT_EVT_EN	BIT(1)
1008de6b7edSMauro Carvalho Chehab #define INTR_EN_XA_ACK_EVT_EN		BIT(0)
1018de6b7edSMauro Carvalho Chehab 
1028de6b7edSMauro Carvalho Chehab #define CLK_RST_TCA_REF_CLK_EN		BIT(1)
1038de6b7edSMauro Carvalho Chehab #define CLK_RST_SUSPEND_CLK_EN		BIT(0)
1048de6b7edSMauro Carvalho Chehab 
1058de6b7edSMauro Carvalho Chehab #define GCFG_ROLE_HSTDEV		BIT(4)
1068de6b7edSMauro Carvalho Chehab #define GCFG_OP_MODE			GENMASK(1, 0)
1078de6b7edSMauro Carvalho Chehab #define GCFG_OP_MODE_CTRL_SYNC_MODE	BIT(0)
1088de6b7edSMauro Carvalho Chehab 
1098de6b7edSMauro Carvalho Chehab #define TCPC_VALID			BIT(4)
1108de6b7edSMauro Carvalho Chehab #define TCPC_LOW_POWER_EN		BIT(3)
1118de6b7edSMauro Carvalho Chehab #define TCPC_MUX_CONTROL_MASK		GENMASK(1, 0)
1128de6b7edSMauro Carvalho Chehab #define TCPC_MUX_CONTROL_USB31		BIT(0)
1138de6b7edSMauro Carvalho Chehab 
1148de6b7edSMauro Carvalho Chehab #define SYSMODE_CFG_TYPEC_DISABLE	BIT(3)
1158de6b7edSMauro Carvalho Chehab 
1168de6b7edSMauro Carvalho Chehab #define VBUS_CTRL_POWERPRESENT_OVERRD	GENMASK(3, 2)
1178de6b7edSMauro Carvalho Chehab #define VBUS_CTRL_VBUSVALID_OVERRD	GENMASK(1, 0)
1188de6b7edSMauro Carvalho Chehab 
1198de6b7edSMauro Carvalho Chehab #define KIRIN970_USB_DEFAULT_PHY_PARAM	(0xfdfee4)
1208de6b7edSMauro Carvalho Chehab #define KIRIN970_USB_DEFAULT_PHY_VBOOST	(0x5)
1218de6b7edSMauro Carvalho Chehab 
1228de6b7edSMauro Carvalho Chehab #define TX_VBOOST_LVL_REG		(0xf)
1238de6b7edSMauro Carvalho Chehab #define TX_VBOOST_LVL_START		(6)
1248de6b7edSMauro Carvalho Chehab #define TX_VBOOST_LVL_ENABLE		BIT(9)
1258de6b7edSMauro Carvalho Chehab 
1268de6b7edSMauro Carvalho Chehab struct hi3670_priv {
1278de6b7edSMauro Carvalho Chehab 	struct device *dev;
1288de6b7edSMauro Carvalho Chehab 	struct regmap *peri_crg;
1298de6b7edSMauro Carvalho Chehab 	struct regmap *pctrl;
1308de6b7edSMauro Carvalho Chehab 	struct regmap *sctrl;
1318de6b7edSMauro Carvalho Chehab 	struct regmap *usb31misc;
1328de6b7edSMauro Carvalho Chehab 
1338de6b7edSMauro Carvalho Chehab 	u32 eye_diagram_param;
1348de6b7edSMauro Carvalho Chehab 	u32 tx_vboost_lvl;
1358de6b7edSMauro Carvalho Chehab 
1368de6b7edSMauro Carvalho Chehab 	u32 peri_crg_offset;
1378de6b7edSMauro Carvalho Chehab 	u32 pctrl_offset;
1388de6b7edSMauro Carvalho Chehab 	u32 usb31misc_offset;
1398de6b7edSMauro Carvalho Chehab };
1408de6b7edSMauro Carvalho Chehab 
hi3670_phy_cr_clk(struct regmap * usb31misc)1418de6b7edSMauro Carvalho Chehab static int hi3670_phy_cr_clk(struct regmap *usb31misc)
1428de6b7edSMauro Carvalho Chehab {
1438de6b7edSMauro Carvalho Chehab 	int ret;
1448de6b7edSMauro Carvalho Chehab 
1458de6b7edSMauro Carvalho Chehab 	/* Clock up */
1468de6b7edSMauro Carvalho Chehab 	ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
1478de6b7edSMauro Carvalho Chehab 				 CFG54_USB31PHY_CR_CLK, CFG54_USB31PHY_CR_CLK);
1488de6b7edSMauro Carvalho Chehab 	if (ret)
1498de6b7edSMauro Carvalho Chehab 		return ret;
1508de6b7edSMauro Carvalho Chehab 
1518de6b7edSMauro Carvalho Chehab 	/* Clock down */
1528de6b7edSMauro Carvalho Chehab 	return regmap_update_bits(usb31misc, USB_MISC_CFG54,
1538de6b7edSMauro Carvalho Chehab 				  CFG54_USB31PHY_CR_CLK, 0);
1548de6b7edSMauro Carvalho Chehab }
1558de6b7edSMauro Carvalho Chehab 
hi3670_phy_cr_set_sel(struct regmap * usb31misc)1568de6b7edSMauro Carvalho Chehab static int hi3670_phy_cr_set_sel(struct regmap *usb31misc)
1578de6b7edSMauro Carvalho Chehab {
1588de6b7edSMauro Carvalho Chehab 	return regmap_update_bits(usb31misc, USB_MISC_CFG54,
1598de6b7edSMauro Carvalho Chehab 				  CFG54_USB31PHY_CR_SEL, CFG54_USB31PHY_CR_SEL);
1608de6b7edSMauro Carvalho Chehab }
1618de6b7edSMauro Carvalho Chehab 
hi3670_phy_cr_start(struct regmap * usb31misc,int direction)1628de6b7edSMauro Carvalho Chehab static int hi3670_phy_cr_start(struct regmap *usb31misc, int direction)
1638de6b7edSMauro Carvalho Chehab {
1648de6b7edSMauro Carvalho Chehab 	int ret, reg;
1658de6b7edSMauro Carvalho Chehab 
1668de6b7edSMauro Carvalho Chehab 	if (direction)
1678de6b7edSMauro Carvalho Chehab 		reg = CFG54_USB31PHY_CR_WR_EN;
1688de6b7edSMauro Carvalho Chehab 	else
1698de6b7edSMauro Carvalho Chehab 		reg = CFG54_USB31PHY_CR_RD_EN;
1708de6b7edSMauro Carvalho Chehab 
1718de6b7edSMauro Carvalho Chehab 	ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, reg, reg);
1728de6b7edSMauro Carvalho Chehab 
1738de6b7edSMauro Carvalho Chehab 	if (ret)
1748de6b7edSMauro Carvalho Chehab 		return ret;
1758de6b7edSMauro Carvalho Chehab 
1768de6b7edSMauro Carvalho Chehab 	ret = hi3670_phy_cr_clk(usb31misc);
1778de6b7edSMauro Carvalho Chehab 	if (ret)
1788de6b7edSMauro Carvalho Chehab 		return ret;
1798de6b7edSMauro Carvalho Chehab 
1808de6b7edSMauro Carvalho Chehab 	return regmap_update_bits(usb31misc, USB_MISC_CFG54,
1818de6b7edSMauro Carvalho Chehab 				  CFG54_USB31PHY_CR_RD_EN | CFG54_USB31PHY_CR_WR_EN, 0);
1828de6b7edSMauro Carvalho Chehab }
1838de6b7edSMauro Carvalho Chehab 
hi3670_phy_cr_wait_ack(struct regmap * usb31misc)1848de6b7edSMauro Carvalho Chehab static int hi3670_phy_cr_wait_ack(struct regmap *usb31misc)
1858de6b7edSMauro Carvalho Chehab {
1868de6b7edSMauro Carvalho Chehab 	u32 reg;
1878de6b7edSMauro Carvalho Chehab 	int retry = 10;
1888de6b7edSMauro Carvalho Chehab 	int ret;
1898de6b7edSMauro Carvalho Chehab 
1908de6b7edSMauro Carvalho Chehab 	while (retry-- > 0) {
1918de6b7edSMauro Carvalho Chehab 		ret = regmap_read(usb31misc, USB_MISC_CFG54, &reg);
1928de6b7edSMauro Carvalho Chehab 		if (ret)
1938de6b7edSMauro Carvalho Chehab 			return ret;
1948de6b7edSMauro Carvalho Chehab 		if ((reg & CFG54_USB31PHY_CR_ACK) == CFG54_USB31PHY_CR_ACK)
1958de6b7edSMauro Carvalho Chehab 			return 0;
1968de6b7edSMauro Carvalho Chehab 
1978de6b7edSMauro Carvalho Chehab 		ret = hi3670_phy_cr_clk(usb31misc);
1988de6b7edSMauro Carvalho Chehab 		if (ret)
1998de6b7edSMauro Carvalho Chehab 			return ret;
2008de6b7edSMauro Carvalho Chehab 
2018de6b7edSMauro Carvalho Chehab 		usleep_range(10, 20);
2028de6b7edSMauro Carvalho Chehab 	}
2038de6b7edSMauro Carvalho Chehab 
2048de6b7edSMauro Carvalho Chehab 	return -ETIMEDOUT;
2058de6b7edSMauro Carvalho Chehab }
2068de6b7edSMauro Carvalho Chehab 
hi3670_phy_cr_set_addr(struct regmap * usb31misc,u32 addr)2078de6b7edSMauro Carvalho Chehab static int hi3670_phy_cr_set_addr(struct regmap *usb31misc, u32 addr)
2088de6b7edSMauro Carvalho Chehab {
2098de6b7edSMauro Carvalho Chehab 	u32 reg;
2108de6b7edSMauro Carvalho Chehab 	int ret;
2118de6b7edSMauro Carvalho Chehab 
2128de6b7edSMauro Carvalho Chehab 	ret = regmap_read(usb31misc, USB_MISC_CFG54, &reg);
2138de6b7edSMauro Carvalho Chehab 	if (ret)
2148de6b7edSMauro Carvalho Chehab 		return ret;
2158de6b7edSMauro Carvalho Chehab 
2168de6b7edSMauro Carvalho Chehab 	reg = FIELD_PREP(CFG54_USB31PHY_CR_ADDR_MASK, addr);
2178de6b7edSMauro Carvalho Chehab 
2188de6b7edSMauro Carvalho Chehab 	return regmap_update_bits(usb31misc, USB_MISC_CFG54,
2198de6b7edSMauro Carvalho Chehab 				  CFG54_USB31PHY_CR_ADDR_MASK, reg);
2208de6b7edSMauro Carvalho Chehab }
2218de6b7edSMauro Carvalho Chehab 
hi3670_phy_cr_read(struct regmap * usb31misc,u32 addr,u32 * val)2228de6b7edSMauro Carvalho Chehab static int hi3670_phy_cr_read(struct regmap *usb31misc, u32 addr, u32 *val)
2238de6b7edSMauro Carvalho Chehab {
2248de6b7edSMauro Carvalho Chehab 	int reg, i, ret;
2258de6b7edSMauro Carvalho Chehab 
2268de6b7edSMauro Carvalho Chehab 	for (i = 0; i < 100; i++) {
2278de6b7edSMauro Carvalho Chehab 		ret = hi3670_phy_cr_clk(usb31misc);
2288de6b7edSMauro Carvalho Chehab 		if (ret)
2298de6b7edSMauro Carvalho Chehab 			return ret;
2308de6b7edSMauro Carvalho Chehab 	}
2318de6b7edSMauro Carvalho Chehab 
2328de6b7edSMauro Carvalho Chehab 	ret = hi3670_phy_cr_set_sel(usb31misc);
2338de6b7edSMauro Carvalho Chehab 	if (ret)
2348de6b7edSMauro Carvalho Chehab 		return ret;
2358de6b7edSMauro Carvalho Chehab 
2368de6b7edSMauro Carvalho Chehab 	ret = hi3670_phy_cr_set_addr(usb31misc, addr);
2378de6b7edSMauro Carvalho Chehab 	if (ret)
2388de6b7edSMauro Carvalho Chehab 		return ret;
2398de6b7edSMauro Carvalho Chehab 
2408de6b7edSMauro Carvalho Chehab 	ret = hi3670_phy_cr_start(usb31misc, 0);
2418de6b7edSMauro Carvalho Chehab 	if (ret)
2428de6b7edSMauro Carvalho Chehab 		return ret;
2438de6b7edSMauro Carvalho Chehab 
2448de6b7edSMauro Carvalho Chehab 	ret = hi3670_phy_cr_wait_ack(usb31misc);
2458de6b7edSMauro Carvalho Chehab 	if (ret)
2468de6b7edSMauro Carvalho Chehab 		return ret;
2478de6b7edSMauro Carvalho Chehab 
2488de6b7edSMauro Carvalho Chehab 	ret = regmap_read(usb31misc, USB_MISC_CFG58, &reg);
2498de6b7edSMauro Carvalho Chehab 	if (ret)
2508de6b7edSMauro Carvalho Chehab 		return ret;
2518de6b7edSMauro Carvalho Chehab 
2528de6b7edSMauro Carvalho Chehab 	*val = FIELD_GET(CFG58_USB31PHY_CR_DATA_MASK, reg);
2538de6b7edSMauro Carvalho Chehab 
2548de6b7edSMauro Carvalho Chehab 	return 0;
2558de6b7edSMauro Carvalho Chehab }
2568de6b7edSMauro Carvalho Chehab 
hi3670_phy_cr_write(struct regmap * usb31misc,u32 addr,u32 val)2578de6b7edSMauro Carvalho Chehab static int hi3670_phy_cr_write(struct regmap *usb31misc, u32 addr, u32 val)
2588de6b7edSMauro Carvalho Chehab {
2598de6b7edSMauro Carvalho Chehab 	int i;
2608de6b7edSMauro Carvalho Chehab 	int ret;
2618de6b7edSMauro Carvalho Chehab 
2628de6b7edSMauro Carvalho Chehab 	for (i = 0; i < 100; i++) {
2638de6b7edSMauro Carvalho Chehab 		ret = hi3670_phy_cr_clk(usb31misc);
2648de6b7edSMauro Carvalho Chehab 		if (ret)
2658de6b7edSMauro Carvalho Chehab 			return ret;
2668de6b7edSMauro Carvalho Chehab 	}
2678de6b7edSMauro Carvalho Chehab 
2688de6b7edSMauro Carvalho Chehab 	ret = hi3670_phy_cr_set_sel(usb31misc);
2698de6b7edSMauro Carvalho Chehab 	if (ret)
2708de6b7edSMauro Carvalho Chehab 		return ret;
2718de6b7edSMauro Carvalho Chehab 
2728de6b7edSMauro Carvalho Chehab 	ret = hi3670_phy_cr_set_addr(usb31misc, addr);
2738de6b7edSMauro Carvalho Chehab 	if (ret)
2748de6b7edSMauro Carvalho Chehab 		return ret;
2758de6b7edSMauro Carvalho Chehab 
2768de6b7edSMauro Carvalho Chehab 	ret = regmap_write(usb31misc, USB_MISC_CFG58,
2778de6b7edSMauro Carvalho Chehab 			   FIELD_PREP(CFG58_USB31PHY_CR_DATA_MASK, val));
2788de6b7edSMauro Carvalho Chehab 	if (ret)
2798de6b7edSMauro Carvalho Chehab 		return ret;
2808de6b7edSMauro Carvalho Chehab 
2818de6b7edSMauro Carvalho Chehab 	ret = hi3670_phy_cr_start(usb31misc, 1);
2828de6b7edSMauro Carvalho Chehab 	if (ret)
2838de6b7edSMauro Carvalho Chehab 		return ret;
2848de6b7edSMauro Carvalho Chehab 
2858de6b7edSMauro Carvalho Chehab 	return hi3670_phy_cr_wait_ack(usb31misc);
2868de6b7edSMauro Carvalho Chehab }
2878de6b7edSMauro Carvalho Chehab 
hi3670_phy_set_params(struct hi3670_priv * priv)2888de6b7edSMauro Carvalho Chehab static int hi3670_phy_set_params(struct hi3670_priv *priv)
2898de6b7edSMauro Carvalho Chehab {
2908de6b7edSMauro Carvalho Chehab 	u32 reg;
2918de6b7edSMauro Carvalho Chehab 	int ret;
2928de6b7edSMauro Carvalho Chehab 	int retry = 3;
2938de6b7edSMauro Carvalho Chehab 
2948de6b7edSMauro Carvalho Chehab 	ret = regmap_write(priv->usb31misc, USB3OTG_CTRL4,
2958de6b7edSMauro Carvalho Chehab 			   priv->eye_diagram_param);
2968de6b7edSMauro Carvalho Chehab 	if (ret) {
2978de6b7edSMauro Carvalho Chehab 		dev_err(priv->dev, "set USB3OTG_CTRL4 failed\n");
2988de6b7edSMauro Carvalho Chehab 		return ret;
2998de6b7edSMauro Carvalho Chehab 	}
3008de6b7edSMauro Carvalho Chehab 
3018de6b7edSMauro Carvalho Chehab 	while (retry-- > 0) {
3028de6b7edSMauro Carvalho Chehab 		ret = hi3670_phy_cr_read(priv->usb31misc,
3038de6b7edSMauro Carvalho Chehab 					 TX_VBOOST_LVL_REG, &reg);
3048de6b7edSMauro Carvalho Chehab 		if (!ret)
3058de6b7edSMauro Carvalho Chehab 			break;
3068de6b7edSMauro Carvalho Chehab 
3078de6b7edSMauro Carvalho Chehab 		if (ret != -ETIMEDOUT) {
3088de6b7edSMauro Carvalho Chehab 			dev_err(priv->dev, "read TX_VBOOST_LVL_REG failed\n");
3098de6b7edSMauro Carvalho Chehab 			return ret;
3108de6b7edSMauro Carvalho Chehab 		}
3118de6b7edSMauro Carvalho Chehab 	}
3128de6b7edSMauro Carvalho Chehab 	if (ret)
3138de6b7edSMauro Carvalho Chehab 		return ret;
3148de6b7edSMauro Carvalho Chehab 
3158de6b7edSMauro Carvalho Chehab 	reg |= (TX_VBOOST_LVL_ENABLE | (priv->tx_vboost_lvl << TX_VBOOST_LVL_START));
3168de6b7edSMauro Carvalho Chehab 	ret = hi3670_phy_cr_write(priv->usb31misc, TX_VBOOST_LVL_REG, reg);
3178de6b7edSMauro Carvalho Chehab 	if (ret)
3188de6b7edSMauro Carvalho Chehab 		dev_err(priv->dev, "write TX_VBOOST_LVL_REG failed\n");
3198de6b7edSMauro Carvalho Chehab 
3208de6b7edSMauro Carvalho Chehab 	return ret;
3218de6b7edSMauro Carvalho Chehab }
3228de6b7edSMauro Carvalho Chehab 
hi3670_is_abbclk_selected(struct hi3670_priv * priv)3238de6b7edSMauro Carvalho Chehab static bool hi3670_is_abbclk_selected(struct hi3670_priv *priv)
3248de6b7edSMauro Carvalho Chehab {
3258de6b7edSMauro Carvalho Chehab 	u32 reg;
3268de6b7edSMauro Carvalho Chehab 
3278de6b7edSMauro Carvalho Chehab 	if (!priv->sctrl) {
3288de6b7edSMauro Carvalho Chehab 		dev_err(priv->dev, "priv->sctrl is null!\n");
3298de6b7edSMauro Carvalho Chehab 		return false;
3308de6b7edSMauro Carvalho Chehab 	}
3318de6b7edSMauro Carvalho Chehab 
3328de6b7edSMauro Carvalho Chehab 	if (regmap_read(priv->sctrl, SCTRL_SCDEEPSLEEPED, &reg)) {
3338de6b7edSMauro Carvalho Chehab 		dev_err(priv->dev, "SCTRL_SCDEEPSLEEPED read failed!\n");
3348de6b7edSMauro Carvalho Chehab 		return false;
3358de6b7edSMauro Carvalho Chehab 	}
3368de6b7edSMauro Carvalho Chehab 
3378de6b7edSMauro Carvalho Chehab 	if ((reg & USB_CLK_SELECTED) == 0)
3388de6b7edSMauro Carvalho Chehab 		return false;
3398de6b7edSMauro Carvalho Chehab 
3408de6b7edSMauro Carvalho Chehab 	return true;
3418de6b7edSMauro Carvalho Chehab }
3428de6b7edSMauro Carvalho Chehab 
hi3670_config_phy_clock(struct hi3670_priv * priv)3438de6b7edSMauro Carvalho Chehab static int hi3670_config_phy_clock(struct hi3670_priv *priv)
3448de6b7edSMauro Carvalho Chehab {
3458de6b7edSMauro Carvalho Chehab 	u32 val, mask;
3468de6b7edSMauro Carvalho Chehab 	int ret;
3478de6b7edSMauro Carvalho Chehab 
3488de6b7edSMauro Carvalho Chehab 	if (!hi3670_is_abbclk_selected(priv)) {
3498de6b7edSMauro Carvalho Chehab 		/* usb refclk iso disable */
3508de6b7edSMauro Carvalho Chehab 		ret = regmap_write(priv->peri_crg, PERI_CRG_ISODIS,
3518de6b7edSMauro Carvalho Chehab 				   USB_REFCLK_ISO_EN);
3528de6b7edSMauro Carvalho Chehab 		if (ret)
3538de6b7edSMauro Carvalho Chehab 			goto out;
3548de6b7edSMauro Carvalho Chehab 
3558de6b7edSMauro Carvalho Chehab 		/* enable usb_tcxo_en */
3568de6b7edSMauro Carvalho Chehab 		ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3,
3578de6b7edSMauro Carvalho Chehab 				   USB_TCXO_EN |
3588de6b7edSMauro Carvalho Chehab 				   (USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START));
3598de6b7edSMauro Carvalho Chehab 
3608de6b7edSMauro Carvalho Chehab 		/* select usbphy clk from abb */
3618de6b7edSMauro Carvalho Chehab 		mask = SC_CLK_USB3PHY_3MUX1_SEL;
3628de6b7edSMauro Carvalho Chehab 		ret = regmap_update_bits(priv->pctrl,
3638de6b7edSMauro Carvalho Chehab 					 PCTRL_PERI_CTRL24, mask, 0);
3648de6b7edSMauro Carvalho Chehab 		if (ret)
3658de6b7edSMauro Carvalho Chehab 			goto out;
3668de6b7edSMauro Carvalho Chehab 
3678de6b7edSMauro Carvalho Chehab 		ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0,
3688de6b7edSMauro Carvalho Chehab 					 CFGA0_USB2PHY_REFCLK_SELECT, 0);
3698de6b7edSMauro Carvalho Chehab 		if (ret)
3708de6b7edSMauro Carvalho Chehab 			goto out;
3718de6b7edSMauro Carvalho Chehab 
3728de6b7edSMauro Carvalho Chehab 		ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val);
3738de6b7edSMauro Carvalho Chehab 		if (ret)
3748de6b7edSMauro Carvalho Chehab 			goto out;
3758de6b7edSMauro Carvalho Chehab 		val &= ~CTRL7_USB2_REFCLKSEL_MASK;
3768de6b7edSMauro Carvalho Chehab 		val |= CTRL7_USB2_REFCLKSEL_ABB;
3778de6b7edSMauro Carvalho Chehab 		ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val);
3788de6b7edSMauro Carvalho Chehab 		if (ret)
3798de6b7edSMauro Carvalho Chehab 			goto out;
3808de6b7edSMauro Carvalho Chehab 
3818de6b7edSMauro Carvalho Chehab 		return 0;
3828de6b7edSMauro Carvalho Chehab 	}
3838de6b7edSMauro Carvalho Chehab 
3848de6b7edSMauro Carvalho Chehab 	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54,
3858de6b7edSMauro Carvalho Chehab 				 CFG54_USB3PHY_REF_USE_PAD,
3868de6b7edSMauro Carvalho Chehab 				 CFG54_USB3PHY_REF_USE_PAD);
3878de6b7edSMauro Carvalho Chehab 	if (ret)
3888de6b7edSMauro Carvalho Chehab 		goto out;
3898de6b7edSMauro Carvalho Chehab 
3908de6b7edSMauro Carvalho Chehab 	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0,
3918de6b7edSMauro Carvalho Chehab 				 CFGA0_USB2PHY_REFCLK_SELECT,
3928de6b7edSMauro Carvalho Chehab 				 CFGA0_USB2PHY_REFCLK_SELECT);
3938de6b7edSMauro Carvalho Chehab 	if (ret)
3948de6b7edSMauro Carvalho Chehab 		goto out;
3958de6b7edSMauro Carvalho Chehab 
3968de6b7edSMauro Carvalho Chehab 	ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val);
3978de6b7edSMauro Carvalho Chehab 	if (ret)
3988de6b7edSMauro Carvalho Chehab 		goto out;
3998de6b7edSMauro Carvalho Chehab 	val &= ~CTRL7_USB2_REFCLKSEL_MASK;
4008de6b7edSMauro Carvalho Chehab 	val |= CTRL7_USB2_REFCLKSEL_PAD;
4018de6b7edSMauro Carvalho Chehab 	ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val);
4028de6b7edSMauro Carvalho Chehab 	if (ret)
4038de6b7edSMauro Carvalho Chehab 		goto out;
4048de6b7edSMauro Carvalho Chehab 
4058de6b7edSMauro Carvalho Chehab 	ret = regmap_write(priv->peri_crg,
4068de6b7edSMauro Carvalho Chehab 			   PERI_CRG_PEREN6, GT_CLK_USB2PHY_REF);
4078de6b7edSMauro Carvalho Chehab 	if (ret)
4088de6b7edSMauro Carvalho Chehab 		goto out;
4098de6b7edSMauro Carvalho Chehab 
4108de6b7edSMauro Carvalho Chehab 	return 0;
4118de6b7edSMauro Carvalho Chehab out:
4128de6b7edSMauro Carvalho Chehab 	dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret);
4138de6b7edSMauro Carvalho Chehab 	return ret;
4148de6b7edSMauro Carvalho Chehab }
4158de6b7edSMauro Carvalho Chehab 
hi3670_config_tca(struct hi3670_priv * priv)4168de6b7edSMauro Carvalho Chehab static int hi3670_config_tca(struct hi3670_priv *priv)
4178de6b7edSMauro Carvalho Chehab {
4188de6b7edSMauro Carvalho Chehab 	u32 val, mask;
4198de6b7edSMauro Carvalho Chehab 	int ret;
4208de6b7edSMauro Carvalho Chehab 
4218de6b7edSMauro Carvalho Chehab 	ret = regmap_write(priv->usb31misc, TCA_INTR_STS, 0xffff);
4228de6b7edSMauro Carvalho Chehab 	if (ret)
4238de6b7edSMauro Carvalho Chehab 		goto out;
4248de6b7edSMauro Carvalho Chehab 
4258de6b7edSMauro Carvalho Chehab 	ret = regmap_write(priv->usb31misc, TCA_INTR_EN,
4268de6b7edSMauro Carvalho Chehab 			   INTR_EN_XA_TIMEOUT_EVT_EN | INTR_EN_XA_ACK_EVT_EN);
4278de6b7edSMauro Carvalho Chehab 	if (ret)
4288de6b7edSMauro Carvalho Chehab 		goto out;
4298de6b7edSMauro Carvalho Chehab 
4308de6b7edSMauro Carvalho Chehab 	mask = CLK_RST_TCA_REF_CLK_EN | CLK_RST_SUSPEND_CLK_EN;
4318de6b7edSMauro Carvalho Chehab 	ret = regmap_update_bits(priv->usb31misc, TCA_CLK_RST, mask, 0);
4328de6b7edSMauro Carvalho Chehab 	if (ret)
4338de6b7edSMauro Carvalho Chehab 		goto out;
4348de6b7edSMauro Carvalho Chehab 
4358de6b7edSMauro Carvalho Chehab 	ret = regmap_update_bits(priv->usb31misc, TCA_GCFG,
4368de6b7edSMauro Carvalho Chehab 				 GCFG_ROLE_HSTDEV | GCFG_OP_MODE,
4378de6b7edSMauro Carvalho Chehab 				 GCFG_ROLE_HSTDEV | GCFG_OP_MODE_CTRL_SYNC_MODE);
4388de6b7edSMauro Carvalho Chehab 	if (ret)
4398de6b7edSMauro Carvalho Chehab 		goto out;
4408de6b7edSMauro Carvalho Chehab 
4418de6b7edSMauro Carvalho Chehab 	ret = regmap_update_bits(priv->usb31misc, TCA_SYSMODE_CFG,
4428de6b7edSMauro Carvalho Chehab 				 SYSMODE_CFG_TYPEC_DISABLE, 0);
4438de6b7edSMauro Carvalho Chehab 	if (ret)
4448de6b7edSMauro Carvalho Chehab 		goto out;
4458de6b7edSMauro Carvalho Chehab 
4468de6b7edSMauro Carvalho Chehab 	ret = regmap_read(priv->usb31misc, TCA_TCPC, &val);
4478de6b7edSMauro Carvalho Chehab 	if (ret)
4488de6b7edSMauro Carvalho Chehab 		goto out;
4498de6b7edSMauro Carvalho Chehab 	val &= ~(TCPC_VALID | TCPC_LOW_POWER_EN | TCPC_MUX_CONTROL_MASK);
4508de6b7edSMauro Carvalho Chehab 	val |= (TCPC_VALID | TCPC_MUX_CONTROL_USB31);
4518de6b7edSMauro Carvalho Chehab 	ret = regmap_write(priv->usb31misc, TCA_TCPC, val);
4528de6b7edSMauro Carvalho Chehab 	if (ret)
4538de6b7edSMauro Carvalho Chehab 		goto out;
4548de6b7edSMauro Carvalho Chehab 
4558de6b7edSMauro Carvalho Chehab 	ret = regmap_write(priv->usb31misc, TCA_VBUS_CTRL,
4568de6b7edSMauro Carvalho Chehab 			   VBUS_CTRL_POWERPRESENT_OVERRD | VBUS_CTRL_VBUSVALID_OVERRD);
4578de6b7edSMauro Carvalho Chehab 	if (ret)
4588de6b7edSMauro Carvalho Chehab 		goto out;
4598de6b7edSMauro Carvalho Chehab 
4608de6b7edSMauro Carvalho Chehab 	return 0;
4618de6b7edSMauro Carvalho Chehab out:
4628de6b7edSMauro Carvalho Chehab 	dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret);
4638de6b7edSMauro Carvalho Chehab 	return ret;
4648de6b7edSMauro Carvalho Chehab }
4658de6b7edSMauro Carvalho Chehab 
hi3670_phy_init(struct phy * phy)4668de6b7edSMauro Carvalho Chehab static int hi3670_phy_init(struct phy *phy)
4678de6b7edSMauro Carvalho Chehab {
4688de6b7edSMauro Carvalho Chehab 	struct hi3670_priv *priv = phy_get_drvdata(phy);
4698de6b7edSMauro Carvalho Chehab 	u32 val;
4708de6b7edSMauro Carvalho Chehab 	int ret;
4718de6b7edSMauro Carvalho Chehab 
4728de6b7edSMauro Carvalho Chehab 	/* assert controller */
4738de6b7edSMauro Carvalho Chehab 	val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET |
4748de6b7edSMauro Carvalho Chehab 	      CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
4758de6b7edSMauro Carvalho Chehab 	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, 0);
4768de6b7edSMauro Carvalho Chehab 	if (ret)
4778de6b7edSMauro Carvalho Chehab 		goto out;
4788de6b7edSMauro Carvalho Chehab 
4798de6b7edSMauro Carvalho Chehab 	ret = hi3670_config_phy_clock(priv);
4808de6b7edSMauro Carvalho Chehab 	if (ret)
4818de6b7edSMauro Carvalho Chehab 		goto out;
4828de6b7edSMauro Carvalho Chehab 
4838de6b7edSMauro Carvalho Chehab 	/* Exit from IDDQ mode */
4848de6b7edSMauro Carvalho Chehab 	ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL5,
4858de6b7edSMauro Carvalho Chehab 				 CTRL5_USB2_SIDDQ, 0);
4868de6b7edSMauro Carvalho Chehab 	if (ret)
4878de6b7edSMauro Carvalho Chehab 		goto out;
4888de6b7edSMauro Carvalho Chehab 
4898de6b7edSMauro Carvalho Chehab 	/* Release USB31 PHY out of TestPowerDown mode */
4908de6b7edSMauro Carvalho Chehab 	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG50,
4918de6b7edSMauro Carvalho Chehab 				 CFG50_USB3_PHY_TEST_POWERDOWN, 0);
4928de6b7edSMauro Carvalho Chehab 	if (ret)
4938de6b7edSMauro Carvalho Chehab 		goto out;
4948de6b7edSMauro Carvalho Chehab 
4958de6b7edSMauro Carvalho Chehab 	/* Deassert phy */
4968de6b7edSMauro Carvalho Chehab 	val = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
4978de6b7edSMauro Carvalho Chehab 	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val);
4988de6b7edSMauro Carvalho Chehab 	if (ret)
4998de6b7edSMauro Carvalho Chehab 		goto out;
5008de6b7edSMauro Carvalho Chehab 
5018de6b7edSMauro Carvalho Chehab 	usleep_range(100, 120);
5028de6b7edSMauro Carvalho Chehab 
5038de6b7edSMauro Carvalho Chehab 	/* Tell the PHY power is stable */
5048de6b7edSMauro Carvalho Chehab 	val = CFG54_USB3_PHY0_ANA_PWR_EN | CFG54_PHY0_PCS_PWR_STABLE |
5058de6b7edSMauro Carvalho Chehab 	      CFG54_PHY0_PMA_PWR_STABLE;
5068de6b7edSMauro Carvalho Chehab 	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54,
5078de6b7edSMauro Carvalho Chehab 				 val, val);
5088de6b7edSMauro Carvalho Chehab 	if (ret)
5098de6b7edSMauro Carvalho Chehab 		goto out;
5108de6b7edSMauro Carvalho Chehab 
5118de6b7edSMauro Carvalho Chehab 	ret = hi3670_config_tca(priv);
5128de6b7edSMauro Carvalho Chehab 	if (ret)
5138de6b7edSMauro Carvalho Chehab 		goto out;
5148de6b7edSMauro Carvalho Chehab 
5158de6b7edSMauro Carvalho Chehab 	/* Enable SSC */
5168de6b7edSMauro Carvalho Chehab 	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG5C,
5178de6b7edSMauro Carvalho Chehab 				 CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN,
5188de6b7edSMauro Carvalho Chehab 				 CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN);
5198de6b7edSMauro Carvalho Chehab 	if (ret)
5208de6b7edSMauro Carvalho Chehab 		goto out;
5218de6b7edSMauro Carvalho Chehab 
5228de6b7edSMauro Carvalho Chehab 	/* Deassert controller */
5238de6b7edSMauro Carvalho Chehab 	val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET;
5248de6b7edSMauro Carvalho Chehab 	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val);
5258de6b7edSMauro Carvalho Chehab 	if (ret)
5268de6b7edSMauro Carvalho Chehab 		goto out;
5278de6b7edSMauro Carvalho Chehab 
5288de6b7edSMauro Carvalho Chehab 	usleep_range(100, 120);
5298de6b7edSMauro Carvalho Chehab 
5308de6b7edSMauro Carvalho Chehab 	/* Set fake vbus valid signal */
5318de6b7edSMauro Carvalho Chehab 	val = CTRL0_USB3_VBUSVLD | CTRL0_USB3_VBUSVLD_SEL;
5328de6b7edSMauro Carvalho Chehab 	ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL0, val, val);
5338de6b7edSMauro Carvalho Chehab 	if (ret)
5348de6b7edSMauro Carvalho Chehab 		goto out;
5358de6b7edSMauro Carvalho Chehab 
5368de6b7edSMauro Carvalho Chehab 	val = CTRL3_USB2_VBUSVLDEXT0 | CTRL3_USB2_VBUSVLDEXTSEL0;
5378de6b7edSMauro Carvalho Chehab 	ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL3, val, val);
5388de6b7edSMauro Carvalho Chehab 	if (ret)
5398de6b7edSMauro Carvalho Chehab 		goto out;
5408de6b7edSMauro Carvalho Chehab 
5418de6b7edSMauro Carvalho Chehab 	usleep_range(100, 120);
5428de6b7edSMauro Carvalho Chehab 
5438de6b7edSMauro Carvalho Chehab 	ret = hi3670_phy_set_params(priv);
5448de6b7edSMauro Carvalho Chehab 	if (ret)
5458de6b7edSMauro Carvalho Chehab 		goto out;
5468de6b7edSMauro Carvalho Chehab 
5478de6b7edSMauro Carvalho Chehab 	return 0;
5488de6b7edSMauro Carvalho Chehab out:
5498de6b7edSMauro Carvalho Chehab 	dev_err(priv->dev, "failed to init phy ret: %d\n", ret);
5508de6b7edSMauro Carvalho Chehab 	return ret;
5518de6b7edSMauro Carvalho Chehab }
5528de6b7edSMauro Carvalho Chehab 
hi3670_phy_exit(struct phy * phy)5538de6b7edSMauro Carvalho Chehab static int hi3670_phy_exit(struct phy *phy)
5548de6b7edSMauro Carvalho Chehab {
5558de6b7edSMauro Carvalho Chehab 	struct hi3670_priv *priv = phy_get_drvdata(phy);
5568de6b7edSMauro Carvalho Chehab 	u32 mask;
5578de6b7edSMauro Carvalho Chehab 	int ret;
5588de6b7edSMauro Carvalho Chehab 
5598de6b7edSMauro Carvalho Chehab 	/* Assert phy */
5608de6b7edSMauro Carvalho Chehab 	mask = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
5618de6b7edSMauro Carvalho Chehab 	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, mask, 0);
5628de6b7edSMauro Carvalho Chehab 	if (ret)
5638de6b7edSMauro Carvalho Chehab 		goto out;
5648de6b7edSMauro Carvalho Chehab 
5658de6b7edSMauro Carvalho Chehab 	if (!hi3670_is_abbclk_selected(priv)) {
5668de6b7edSMauro Carvalho Chehab 		/* disable usb_tcxo_en */
5678de6b7edSMauro Carvalho Chehab 		ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3,
5688de6b7edSMauro Carvalho Chehab 				   USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START);
5698de6b7edSMauro Carvalho Chehab 	} else {
5708de6b7edSMauro Carvalho Chehab 		ret = regmap_write(priv->peri_crg, PERI_CRG_PERDIS6,
5718de6b7edSMauro Carvalho Chehab 				   GT_CLK_USB2PHY_REF);
5728de6b7edSMauro Carvalho Chehab 		if (ret)
5738de6b7edSMauro Carvalho Chehab 			goto out;
5748de6b7edSMauro Carvalho Chehab 	}
5758de6b7edSMauro Carvalho Chehab 
5768de6b7edSMauro Carvalho Chehab 	return 0;
5778de6b7edSMauro Carvalho Chehab out:
5788de6b7edSMauro Carvalho Chehab 	dev_err(priv->dev, "failed to exit phy ret: %d\n", ret);
5798de6b7edSMauro Carvalho Chehab 	return ret;
5808de6b7edSMauro Carvalho Chehab }
5818de6b7edSMauro Carvalho Chehab 
5828de6b7edSMauro Carvalho Chehab static const struct phy_ops hi3670_phy_ops = {
5838de6b7edSMauro Carvalho Chehab 	.init		= hi3670_phy_init,
5848de6b7edSMauro Carvalho Chehab 	.exit		= hi3670_phy_exit,
5858de6b7edSMauro Carvalho Chehab 	.owner		= THIS_MODULE,
5868de6b7edSMauro Carvalho Chehab };
5878de6b7edSMauro Carvalho Chehab 
hi3670_phy_probe(struct platform_device * pdev)5888de6b7edSMauro Carvalho Chehab static int hi3670_phy_probe(struct platform_device *pdev)
5898de6b7edSMauro Carvalho Chehab {
5908de6b7edSMauro Carvalho Chehab 	struct phy_provider *phy_provider;
5918de6b7edSMauro Carvalho Chehab 	struct device *dev = &pdev->dev;
5928de6b7edSMauro Carvalho Chehab 	struct phy *phy;
5938de6b7edSMauro Carvalho Chehab 	struct hi3670_priv *priv;
5948de6b7edSMauro Carvalho Chehab 
5958de6b7edSMauro Carvalho Chehab 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
5968de6b7edSMauro Carvalho Chehab 	if (!priv)
5978de6b7edSMauro Carvalho Chehab 		return -ENOMEM;
5988de6b7edSMauro Carvalho Chehab 
5998de6b7edSMauro Carvalho Chehab 	priv->dev = dev;
6008de6b7edSMauro Carvalho Chehab 	priv->peri_crg = syscon_regmap_lookup_by_phandle(dev->of_node,
6018de6b7edSMauro Carvalho Chehab 							 "hisilicon,pericrg-syscon");
6028de6b7edSMauro Carvalho Chehab 	if (IS_ERR(priv->peri_crg)) {
6038de6b7edSMauro Carvalho Chehab 		dev_err(dev, "no hisilicon,pericrg-syscon\n");
6048de6b7edSMauro Carvalho Chehab 		return PTR_ERR(priv->peri_crg);
6058de6b7edSMauro Carvalho Chehab 	}
6068de6b7edSMauro Carvalho Chehab 
6078de6b7edSMauro Carvalho Chehab 	priv->pctrl = syscon_regmap_lookup_by_phandle(dev->of_node,
6088de6b7edSMauro Carvalho Chehab 						      "hisilicon,pctrl-syscon");
6098de6b7edSMauro Carvalho Chehab 	if (IS_ERR(priv->pctrl)) {
6108de6b7edSMauro Carvalho Chehab 		dev_err(dev, "no hisilicon,pctrl-syscon\n");
6118de6b7edSMauro Carvalho Chehab 		return PTR_ERR(priv->pctrl);
6128de6b7edSMauro Carvalho Chehab 	}
6138de6b7edSMauro Carvalho Chehab 
6148de6b7edSMauro Carvalho Chehab 	priv->sctrl = syscon_regmap_lookup_by_phandle(dev->of_node,
6158de6b7edSMauro Carvalho Chehab 						      "hisilicon,sctrl-syscon");
6168de6b7edSMauro Carvalho Chehab 	if (IS_ERR(priv->sctrl)) {
6178de6b7edSMauro Carvalho Chehab 		dev_err(dev, "no hisilicon,sctrl-syscon\n");
6188de6b7edSMauro Carvalho Chehab 		return PTR_ERR(priv->sctrl);
6198de6b7edSMauro Carvalho Chehab 	}
6208de6b7edSMauro Carvalho Chehab 
6218de6b7edSMauro Carvalho Chehab 	/* node of hi3670 phy is a sub-node of usb3_otg_bc */
6228de6b7edSMauro Carvalho Chehab 	priv->usb31misc = syscon_node_to_regmap(dev->parent->of_node);
6238de6b7edSMauro Carvalho Chehab 	if (IS_ERR(priv->usb31misc)) {
6248de6b7edSMauro Carvalho Chehab 		dev_err(dev, "no hisilicon,usb3-otg-bc-syscon\n");
6258de6b7edSMauro Carvalho Chehab 		return PTR_ERR(priv->usb31misc);
6268de6b7edSMauro Carvalho Chehab 	}
6278de6b7edSMauro Carvalho Chehab 
6288de6b7edSMauro Carvalho Chehab 	if (of_property_read_u32(dev->of_node, "hisilicon,eye-diagram-param",
6298de6b7edSMauro Carvalho Chehab 				 &priv->eye_diagram_param))
6308de6b7edSMauro Carvalho Chehab 		priv->eye_diagram_param = KIRIN970_USB_DEFAULT_PHY_PARAM;
6318de6b7edSMauro Carvalho Chehab 
6328de6b7edSMauro Carvalho Chehab 	if (of_property_read_u32(dev->of_node, "hisilicon,tx-vboost-lvl",
6338de6b7edSMauro Carvalho Chehab 				 &priv->tx_vboost_lvl))
6348de6b7edSMauro Carvalho Chehab 		priv->tx_vboost_lvl = KIRIN970_USB_DEFAULT_PHY_VBOOST;
6358de6b7edSMauro Carvalho Chehab 
6368de6b7edSMauro Carvalho Chehab 	phy = devm_phy_create(dev, NULL, &hi3670_phy_ops);
6378de6b7edSMauro Carvalho Chehab 	if (IS_ERR(phy))
6388de6b7edSMauro Carvalho Chehab 		return PTR_ERR(phy);
6398de6b7edSMauro Carvalho Chehab 
6408de6b7edSMauro Carvalho Chehab 	phy_set_drvdata(phy, priv);
6418de6b7edSMauro Carvalho Chehab 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
6428de6b7edSMauro Carvalho Chehab 	return PTR_ERR_OR_ZERO(phy_provider);
6438de6b7edSMauro Carvalho Chehab }
6448de6b7edSMauro Carvalho Chehab 
6458de6b7edSMauro Carvalho Chehab static const struct of_device_id hi3670_phy_of_match[] = {
6468de6b7edSMauro Carvalho Chehab 	{ .compatible = "hisilicon,hi3670-usb-phy" },
6478de6b7edSMauro Carvalho Chehab 	{ },
6488de6b7edSMauro Carvalho Chehab };
6498de6b7edSMauro Carvalho Chehab MODULE_DEVICE_TABLE(of, hi3670_phy_of_match);
6508de6b7edSMauro Carvalho Chehab 
6518de6b7edSMauro Carvalho Chehab static struct platform_driver hi3670_phy_driver = {
6528de6b7edSMauro Carvalho Chehab 	.probe	= hi3670_phy_probe,
6538de6b7edSMauro Carvalho Chehab 	.driver = {
6548de6b7edSMauro Carvalho Chehab 		.name	= "hi3670-usb-phy",
6558de6b7edSMauro Carvalho Chehab 		.of_match_table	= hi3670_phy_of_match,
6568de6b7edSMauro Carvalho Chehab 	}
6578de6b7edSMauro Carvalho Chehab };
6588de6b7edSMauro Carvalho Chehab module_platform_driver(hi3670_phy_driver);
6598de6b7edSMauro Carvalho Chehab 
6608de6b7edSMauro Carvalho Chehab MODULE_AUTHOR("Yu Chen <chenyu56@huawei.com>");
6618de6b7edSMauro Carvalho Chehab MODULE_LICENSE("GPL v2");
6628de6b7edSMauro Carvalho Chehab MODULE_DESCRIPTION("Hilisicon Kirin970 USB31 PHY Driver");
663