162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Phy provider for USB 3.1 controller on HiSilicon Kirin970 platform
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2017-2020 Hilisicon Electronics Co., Ltd.
662306a36Sopenharmony_ci *		http://www.huawei.com
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Authors: Yu Chen <chenyu56@huawei.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/bitfield.h>
1262306a36Sopenharmony_ci#include <linux/clk.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/of.h>
1762306a36Sopenharmony_ci#include <linux/phy/phy.h>
1862306a36Sopenharmony_ci#include <linux/platform_device.h>
1962306a36Sopenharmony_ci#include <linux/regmap.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define SCTRL_SCDEEPSLEEPED		(0x0)
2262306a36Sopenharmony_ci#define USB_CLK_SELECTED		BIT(20)
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define PERI_CRG_PEREN0			(0x00)
2562306a36Sopenharmony_ci#define PERI_CRG_PERDIS0		(0x04)
2662306a36Sopenharmony_ci#define PERI_CRG_PEREN4			(0x40)
2762306a36Sopenharmony_ci#define PERI_CRG_PERDIS4		(0x44)
2862306a36Sopenharmony_ci#define PERI_CRG_PERRSTEN4		(0x90)
2962306a36Sopenharmony_ci#define PERI_CRG_PERRSTDIS4		(0x94)
3062306a36Sopenharmony_ci#define PERI_CRG_ISODIS			(0x148)
3162306a36Sopenharmony_ci#define PERI_CRG_PEREN6			(0x410)
3262306a36Sopenharmony_ci#define PERI_CRG_PERDIS6		(0x414)
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define USB_REFCLK_ISO_EN		BIT(25)
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define GT_CLK_USB2PHY_REF		BIT(19)
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define PCTRL_PERI_CTRL3		(0x10)
3962306a36Sopenharmony_ci#define PCTRL_PERI_CTRL3_MSK_START	(16)
4062306a36Sopenharmony_ci#define USB_TCXO_EN			BIT(1)
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define PCTRL_PERI_CTRL24		(0x64)
4362306a36Sopenharmony_ci#define SC_CLK_USB3PHY_3MUX1_SEL	BIT(25)
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define USB3OTG_CTRL0			(0x00)
4662306a36Sopenharmony_ci#define USB3OTG_CTRL3			(0x0c)
4762306a36Sopenharmony_ci#define USB3OTG_CTRL4			(0x10)
4862306a36Sopenharmony_ci#define USB3OTG_CTRL5			(0x14)
4962306a36Sopenharmony_ci#define USB3OTG_CTRL7			(0x1c)
5062306a36Sopenharmony_ci#define USB_MISC_CFG50			(0x50)
5162306a36Sopenharmony_ci#define USB_MISC_CFG54			(0x54)
5262306a36Sopenharmony_ci#define USB_MISC_CFG58			(0x58)
5362306a36Sopenharmony_ci#define USB_MISC_CFG5C			(0x5c)
5462306a36Sopenharmony_ci#define USB_MISC_CFGA0			(0xa0)
5562306a36Sopenharmony_ci#define TCA_CLK_RST			(0x200)
5662306a36Sopenharmony_ci#define TCA_INTR_EN			(0x204)
5762306a36Sopenharmony_ci#define TCA_INTR_STS			(0x208)
5862306a36Sopenharmony_ci#define TCA_GCFG			(0x210)
5962306a36Sopenharmony_ci#define TCA_TCPC			(0x214)
6062306a36Sopenharmony_ci#define TCA_SYSMODE_CFG			(0x218)
6162306a36Sopenharmony_ci#define TCA_VBUS_CTRL			(0x240)
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define CTRL0_USB3_VBUSVLD		BIT(7)
6462306a36Sopenharmony_ci#define CTRL0_USB3_VBUSVLD_SEL		BIT(6)
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define CTRL3_USB2_VBUSVLDEXT0		BIT(6)
6762306a36Sopenharmony_ci#define CTRL3_USB2_VBUSVLDEXTSEL0	BIT(5)
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#define CTRL5_USB2_SIDDQ		BIT(0)
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#define CTRL7_USB2_REFCLKSEL_MASK	GENMASK(4, 3)
7262306a36Sopenharmony_ci#define CTRL7_USB2_REFCLKSEL_ABB	(BIT(4) | BIT(3))
7362306a36Sopenharmony_ci#define CTRL7_USB2_REFCLKSEL_PAD	BIT(4)
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci#define CFG50_USB3_PHY_TEST_POWERDOWN	BIT(23)
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define CFG54_USB31PHY_CR_ADDR_MASK	GENMASK(31, 16)
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci#define CFG54_USB3PHY_REF_USE_PAD	BIT(12)
8062306a36Sopenharmony_ci#define CFG54_PHY0_PMA_PWR_STABLE	BIT(11)
8162306a36Sopenharmony_ci#define CFG54_PHY0_PCS_PWR_STABLE	BIT(9)
8262306a36Sopenharmony_ci#define CFG54_USB31PHY_CR_ACK		BIT(7)
8362306a36Sopenharmony_ci#define CFG54_USB31PHY_CR_WR_EN		BIT(5)
8462306a36Sopenharmony_ci#define CFG54_USB31PHY_CR_SEL		BIT(4)
8562306a36Sopenharmony_ci#define CFG54_USB31PHY_CR_RD_EN		BIT(3)
8662306a36Sopenharmony_ci#define CFG54_USB31PHY_CR_CLK		BIT(2)
8762306a36Sopenharmony_ci#define CFG54_USB3_PHY0_ANA_PWR_EN	BIT(1)
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#define CFG58_USB31PHY_CR_DATA_MASK     GENMASK(31, 16)
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#define CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN	BIT(1)
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci#define CFGA0_VAUX_RESET		BIT(9)
9462306a36Sopenharmony_ci#define CFGA0_USB31C_RESET		BIT(8)
9562306a36Sopenharmony_ci#define CFGA0_USB2PHY_REFCLK_SELECT	BIT(4)
9662306a36Sopenharmony_ci#define CFGA0_USB3PHY_RESET		BIT(1)
9762306a36Sopenharmony_ci#define CFGA0_USB2PHY_POR		BIT(0)
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#define INTR_EN_XA_TIMEOUT_EVT_EN	BIT(1)
10062306a36Sopenharmony_ci#define INTR_EN_XA_ACK_EVT_EN		BIT(0)
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci#define CLK_RST_TCA_REF_CLK_EN		BIT(1)
10362306a36Sopenharmony_ci#define CLK_RST_SUSPEND_CLK_EN		BIT(0)
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci#define GCFG_ROLE_HSTDEV		BIT(4)
10662306a36Sopenharmony_ci#define GCFG_OP_MODE			GENMASK(1, 0)
10762306a36Sopenharmony_ci#define GCFG_OP_MODE_CTRL_SYNC_MODE	BIT(0)
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci#define TCPC_VALID			BIT(4)
11062306a36Sopenharmony_ci#define TCPC_LOW_POWER_EN		BIT(3)
11162306a36Sopenharmony_ci#define TCPC_MUX_CONTROL_MASK		GENMASK(1, 0)
11262306a36Sopenharmony_ci#define TCPC_MUX_CONTROL_USB31		BIT(0)
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#define SYSMODE_CFG_TYPEC_DISABLE	BIT(3)
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci#define VBUS_CTRL_POWERPRESENT_OVERRD	GENMASK(3, 2)
11762306a36Sopenharmony_ci#define VBUS_CTRL_VBUSVALID_OVERRD	GENMASK(1, 0)
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci#define KIRIN970_USB_DEFAULT_PHY_PARAM	(0xfdfee4)
12062306a36Sopenharmony_ci#define KIRIN970_USB_DEFAULT_PHY_VBOOST	(0x5)
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci#define TX_VBOOST_LVL_REG		(0xf)
12362306a36Sopenharmony_ci#define TX_VBOOST_LVL_START		(6)
12462306a36Sopenharmony_ci#define TX_VBOOST_LVL_ENABLE		BIT(9)
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistruct hi3670_priv {
12762306a36Sopenharmony_ci	struct device *dev;
12862306a36Sopenharmony_ci	struct regmap *peri_crg;
12962306a36Sopenharmony_ci	struct regmap *pctrl;
13062306a36Sopenharmony_ci	struct regmap *sctrl;
13162306a36Sopenharmony_ci	struct regmap *usb31misc;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	u32 eye_diagram_param;
13462306a36Sopenharmony_ci	u32 tx_vboost_lvl;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	u32 peri_crg_offset;
13762306a36Sopenharmony_ci	u32 pctrl_offset;
13862306a36Sopenharmony_ci	u32 usb31misc_offset;
13962306a36Sopenharmony_ci};
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic int hi3670_phy_cr_clk(struct regmap *usb31misc)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	int ret;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	/* Clock up */
14662306a36Sopenharmony_ci	ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
14762306a36Sopenharmony_ci				 CFG54_USB31PHY_CR_CLK, CFG54_USB31PHY_CR_CLK);
14862306a36Sopenharmony_ci	if (ret)
14962306a36Sopenharmony_ci		return ret;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	/* Clock down */
15262306a36Sopenharmony_ci	return regmap_update_bits(usb31misc, USB_MISC_CFG54,
15362306a36Sopenharmony_ci				  CFG54_USB31PHY_CR_CLK, 0);
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic int hi3670_phy_cr_set_sel(struct regmap *usb31misc)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	return regmap_update_bits(usb31misc, USB_MISC_CFG54,
15962306a36Sopenharmony_ci				  CFG54_USB31PHY_CR_SEL, CFG54_USB31PHY_CR_SEL);
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic int hi3670_phy_cr_start(struct regmap *usb31misc, int direction)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	int ret, reg;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	if (direction)
16762306a36Sopenharmony_ci		reg = CFG54_USB31PHY_CR_WR_EN;
16862306a36Sopenharmony_ci	else
16962306a36Sopenharmony_ci		reg = CFG54_USB31PHY_CR_RD_EN;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, reg, reg);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	if (ret)
17462306a36Sopenharmony_ci		return ret;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	ret = hi3670_phy_cr_clk(usb31misc);
17762306a36Sopenharmony_ci	if (ret)
17862306a36Sopenharmony_ci		return ret;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	return regmap_update_bits(usb31misc, USB_MISC_CFG54,
18162306a36Sopenharmony_ci				  CFG54_USB31PHY_CR_RD_EN | CFG54_USB31PHY_CR_WR_EN, 0);
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic int hi3670_phy_cr_wait_ack(struct regmap *usb31misc)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	u32 reg;
18762306a36Sopenharmony_ci	int retry = 10;
18862306a36Sopenharmony_ci	int ret;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	while (retry-- > 0) {
19162306a36Sopenharmony_ci		ret = regmap_read(usb31misc, USB_MISC_CFG54, &reg);
19262306a36Sopenharmony_ci		if (ret)
19362306a36Sopenharmony_ci			return ret;
19462306a36Sopenharmony_ci		if ((reg & CFG54_USB31PHY_CR_ACK) == CFG54_USB31PHY_CR_ACK)
19562306a36Sopenharmony_ci			return 0;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci		ret = hi3670_phy_cr_clk(usb31misc);
19862306a36Sopenharmony_ci		if (ret)
19962306a36Sopenharmony_ci			return ret;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci		usleep_range(10, 20);
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return -ETIMEDOUT;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic int hi3670_phy_cr_set_addr(struct regmap *usb31misc, u32 addr)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	u32 reg;
21062306a36Sopenharmony_ci	int ret;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	ret = regmap_read(usb31misc, USB_MISC_CFG54, &reg);
21362306a36Sopenharmony_ci	if (ret)
21462306a36Sopenharmony_ci		return ret;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	reg = FIELD_PREP(CFG54_USB31PHY_CR_ADDR_MASK, addr);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	return regmap_update_bits(usb31misc, USB_MISC_CFG54,
21962306a36Sopenharmony_ci				  CFG54_USB31PHY_CR_ADDR_MASK, reg);
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistatic int hi3670_phy_cr_read(struct regmap *usb31misc, u32 addr, u32 *val)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	int reg, i, ret;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	for (i = 0; i < 100; i++) {
22762306a36Sopenharmony_ci		ret = hi3670_phy_cr_clk(usb31misc);
22862306a36Sopenharmony_ci		if (ret)
22962306a36Sopenharmony_ci			return ret;
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	ret = hi3670_phy_cr_set_sel(usb31misc);
23362306a36Sopenharmony_ci	if (ret)
23462306a36Sopenharmony_ci		return ret;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	ret = hi3670_phy_cr_set_addr(usb31misc, addr);
23762306a36Sopenharmony_ci	if (ret)
23862306a36Sopenharmony_ci		return ret;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	ret = hi3670_phy_cr_start(usb31misc, 0);
24162306a36Sopenharmony_ci	if (ret)
24262306a36Sopenharmony_ci		return ret;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	ret = hi3670_phy_cr_wait_ack(usb31misc);
24562306a36Sopenharmony_ci	if (ret)
24662306a36Sopenharmony_ci		return ret;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	ret = regmap_read(usb31misc, USB_MISC_CFG58, &reg);
24962306a36Sopenharmony_ci	if (ret)
25062306a36Sopenharmony_ci		return ret;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	*val = FIELD_GET(CFG58_USB31PHY_CR_DATA_MASK, reg);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	return 0;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic int hi3670_phy_cr_write(struct regmap *usb31misc, u32 addr, u32 val)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	int i;
26062306a36Sopenharmony_ci	int ret;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	for (i = 0; i < 100; i++) {
26362306a36Sopenharmony_ci		ret = hi3670_phy_cr_clk(usb31misc);
26462306a36Sopenharmony_ci		if (ret)
26562306a36Sopenharmony_ci			return ret;
26662306a36Sopenharmony_ci	}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	ret = hi3670_phy_cr_set_sel(usb31misc);
26962306a36Sopenharmony_ci	if (ret)
27062306a36Sopenharmony_ci		return ret;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	ret = hi3670_phy_cr_set_addr(usb31misc, addr);
27362306a36Sopenharmony_ci	if (ret)
27462306a36Sopenharmony_ci		return ret;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	ret = regmap_write(usb31misc, USB_MISC_CFG58,
27762306a36Sopenharmony_ci			   FIELD_PREP(CFG58_USB31PHY_CR_DATA_MASK, val));
27862306a36Sopenharmony_ci	if (ret)
27962306a36Sopenharmony_ci		return ret;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	ret = hi3670_phy_cr_start(usb31misc, 1);
28262306a36Sopenharmony_ci	if (ret)
28362306a36Sopenharmony_ci		return ret;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	return hi3670_phy_cr_wait_ack(usb31misc);
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic int hi3670_phy_set_params(struct hi3670_priv *priv)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	u32 reg;
29162306a36Sopenharmony_ci	int ret;
29262306a36Sopenharmony_ci	int retry = 3;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	ret = regmap_write(priv->usb31misc, USB3OTG_CTRL4,
29562306a36Sopenharmony_ci			   priv->eye_diagram_param);
29662306a36Sopenharmony_ci	if (ret) {
29762306a36Sopenharmony_ci		dev_err(priv->dev, "set USB3OTG_CTRL4 failed\n");
29862306a36Sopenharmony_ci		return ret;
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	while (retry-- > 0) {
30262306a36Sopenharmony_ci		ret = hi3670_phy_cr_read(priv->usb31misc,
30362306a36Sopenharmony_ci					 TX_VBOOST_LVL_REG, &reg);
30462306a36Sopenharmony_ci		if (!ret)
30562306a36Sopenharmony_ci			break;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci		if (ret != -ETIMEDOUT) {
30862306a36Sopenharmony_ci			dev_err(priv->dev, "read TX_VBOOST_LVL_REG failed\n");
30962306a36Sopenharmony_ci			return ret;
31062306a36Sopenharmony_ci		}
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci	if (ret)
31362306a36Sopenharmony_ci		return ret;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	reg |= (TX_VBOOST_LVL_ENABLE | (priv->tx_vboost_lvl << TX_VBOOST_LVL_START));
31662306a36Sopenharmony_ci	ret = hi3670_phy_cr_write(priv->usb31misc, TX_VBOOST_LVL_REG, reg);
31762306a36Sopenharmony_ci	if (ret)
31862306a36Sopenharmony_ci		dev_err(priv->dev, "write TX_VBOOST_LVL_REG failed\n");
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	return ret;
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic bool hi3670_is_abbclk_selected(struct hi3670_priv *priv)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	u32 reg;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	if (!priv->sctrl) {
32862306a36Sopenharmony_ci		dev_err(priv->dev, "priv->sctrl is null!\n");
32962306a36Sopenharmony_ci		return false;
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (regmap_read(priv->sctrl, SCTRL_SCDEEPSLEEPED, &reg)) {
33362306a36Sopenharmony_ci		dev_err(priv->dev, "SCTRL_SCDEEPSLEEPED read failed!\n");
33462306a36Sopenharmony_ci		return false;
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	if ((reg & USB_CLK_SELECTED) == 0)
33862306a36Sopenharmony_ci		return false;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	return true;
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic int hi3670_config_phy_clock(struct hi3670_priv *priv)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	u32 val, mask;
34662306a36Sopenharmony_ci	int ret;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	if (!hi3670_is_abbclk_selected(priv)) {
34962306a36Sopenharmony_ci		/* usb refclk iso disable */
35062306a36Sopenharmony_ci		ret = regmap_write(priv->peri_crg, PERI_CRG_ISODIS,
35162306a36Sopenharmony_ci				   USB_REFCLK_ISO_EN);
35262306a36Sopenharmony_ci		if (ret)
35362306a36Sopenharmony_ci			goto out;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci		/* enable usb_tcxo_en */
35662306a36Sopenharmony_ci		ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3,
35762306a36Sopenharmony_ci				   USB_TCXO_EN |
35862306a36Sopenharmony_ci				   (USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START));
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci		/* select usbphy clk from abb */
36162306a36Sopenharmony_ci		mask = SC_CLK_USB3PHY_3MUX1_SEL;
36262306a36Sopenharmony_ci		ret = regmap_update_bits(priv->pctrl,
36362306a36Sopenharmony_ci					 PCTRL_PERI_CTRL24, mask, 0);
36462306a36Sopenharmony_ci		if (ret)
36562306a36Sopenharmony_ci			goto out;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci		ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0,
36862306a36Sopenharmony_ci					 CFGA0_USB2PHY_REFCLK_SELECT, 0);
36962306a36Sopenharmony_ci		if (ret)
37062306a36Sopenharmony_ci			goto out;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci		ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val);
37362306a36Sopenharmony_ci		if (ret)
37462306a36Sopenharmony_ci			goto out;
37562306a36Sopenharmony_ci		val &= ~CTRL7_USB2_REFCLKSEL_MASK;
37662306a36Sopenharmony_ci		val |= CTRL7_USB2_REFCLKSEL_ABB;
37762306a36Sopenharmony_ci		ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val);
37862306a36Sopenharmony_ci		if (ret)
37962306a36Sopenharmony_ci			goto out;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci		return 0;
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54,
38562306a36Sopenharmony_ci				 CFG54_USB3PHY_REF_USE_PAD,
38662306a36Sopenharmony_ci				 CFG54_USB3PHY_REF_USE_PAD);
38762306a36Sopenharmony_ci	if (ret)
38862306a36Sopenharmony_ci		goto out;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0,
39162306a36Sopenharmony_ci				 CFGA0_USB2PHY_REFCLK_SELECT,
39262306a36Sopenharmony_ci				 CFGA0_USB2PHY_REFCLK_SELECT);
39362306a36Sopenharmony_ci	if (ret)
39462306a36Sopenharmony_ci		goto out;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val);
39762306a36Sopenharmony_ci	if (ret)
39862306a36Sopenharmony_ci		goto out;
39962306a36Sopenharmony_ci	val &= ~CTRL7_USB2_REFCLKSEL_MASK;
40062306a36Sopenharmony_ci	val |= CTRL7_USB2_REFCLKSEL_PAD;
40162306a36Sopenharmony_ci	ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val);
40262306a36Sopenharmony_ci	if (ret)
40362306a36Sopenharmony_ci		goto out;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	ret = regmap_write(priv->peri_crg,
40662306a36Sopenharmony_ci			   PERI_CRG_PEREN6, GT_CLK_USB2PHY_REF);
40762306a36Sopenharmony_ci	if (ret)
40862306a36Sopenharmony_ci		goto out;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	return 0;
41162306a36Sopenharmony_ciout:
41262306a36Sopenharmony_ci	dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret);
41362306a36Sopenharmony_ci	return ret;
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic int hi3670_config_tca(struct hi3670_priv *priv)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	u32 val, mask;
41962306a36Sopenharmony_ci	int ret;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	ret = regmap_write(priv->usb31misc, TCA_INTR_STS, 0xffff);
42262306a36Sopenharmony_ci	if (ret)
42362306a36Sopenharmony_ci		goto out;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	ret = regmap_write(priv->usb31misc, TCA_INTR_EN,
42662306a36Sopenharmony_ci			   INTR_EN_XA_TIMEOUT_EVT_EN | INTR_EN_XA_ACK_EVT_EN);
42762306a36Sopenharmony_ci	if (ret)
42862306a36Sopenharmony_ci		goto out;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	mask = CLK_RST_TCA_REF_CLK_EN | CLK_RST_SUSPEND_CLK_EN;
43162306a36Sopenharmony_ci	ret = regmap_update_bits(priv->usb31misc, TCA_CLK_RST, mask, 0);
43262306a36Sopenharmony_ci	if (ret)
43362306a36Sopenharmony_ci		goto out;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	ret = regmap_update_bits(priv->usb31misc, TCA_GCFG,
43662306a36Sopenharmony_ci				 GCFG_ROLE_HSTDEV | GCFG_OP_MODE,
43762306a36Sopenharmony_ci				 GCFG_ROLE_HSTDEV | GCFG_OP_MODE_CTRL_SYNC_MODE);
43862306a36Sopenharmony_ci	if (ret)
43962306a36Sopenharmony_ci		goto out;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	ret = regmap_update_bits(priv->usb31misc, TCA_SYSMODE_CFG,
44262306a36Sopenharmony_ci				 SYSMODE_CFG_TYPEC_DISABLE, 0);
44362306a36Sopenharmony_ci	if (ret)
44462306a36Sopenharmony_ci		goto out;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	ret = regmap_read(priv->usb31misc, TCA_TCPC, &val);
44762306a36Sopenharmony_ci	if (ret)
44862306a36Sopenharmony_ci		goto out;
44962306a36Sopenharmony_ci	val &= ~(TCPC_VALID | TCPC_LOW_POWER_EN | TCPC_MUX_CONTROL_MASK);
45062306a36Sopenharmony_ci	val |= (TCPC_VALID | TCPC_MUX_CONTROL_USB31);
45162306a36Sopenharmony_ci	ret = regmap_write(priv->usb31misc, TCA_TCPC, val);
45262306a36Sopenharmony_ci	if (ret)
45362306a36Sopenharmony_ci		goto out;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	ret = regmap_write(priv->usb31misc, TCA_VBUS_CTRL,
45662306a36Sopenharmony_ci			   VBUS_CTRL_POWERPRESENT_OVERRD | VBUS_CTRL_VBUSVALID_OVERRD);
45762306a36Sopenharmony_ci	if (ret)
45862306a36Sopenharmony_ci		goto out;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	return 0;
46162306a36Sopenharmony_ciout:
46262306a36Sopenharmony_ci	dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret);
46362306a36Sopenharmony_ci	return ret;
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic int hi3670_phy_init(struct phy *phy)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	struct hi3670_priv *priv = phy_get_drvdata(phy);
46962306a36Sopenharmony_ci	u32 val;
47062306a36Sopenharmony_ci	int ret;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/* assert controller */
47362306a36Sopenharmony_ci	val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET |
47462306a36Sopenharmony_ci	      CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
47562306a36Sopenharmony_ci	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, 0);
47662306a36Sopenharmony_ci	if (ret)
47762306a36Sopenharmony_ci		goto out;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	ret = hi3670_config_phy_clock(priv);
48062306a36Sopenharmony_ci	if (ret)
48162306a36Sopenharmony_ci		goto out;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	/* Exit from IDDQ mode */
48462306a36Sopenharmony_ci	ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL5,
48562306a36Sopenharmony_ci				 CTRL5_USB2_SIDDQ, 0);
48662306a36Sopenharmony_ci	if (ret)
48762306a36Sopenharmony_ci		goto out;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	/* Release USB31 PHY out of TestPowerDown mode */
49062306a36Sopenharmony_ci	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG50,
49162306a36Sopenharmony_ci				 CFG50_USB3_PHY_TEST_POWERDOWN, 0);
49262306a36Sopenharmony_ci	if (ret)
49362306a36Sopenharmony_ci		goto out;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	/* Deassert phy */
49662306a36Sopenharmony_ci	val = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
49762306a36Sopenharmony_ci	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val);
49862306a36Sopenharmony_ci	if (ret)
49962306a36Sopenharmony_ci		goto out;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	usleep_range(100, 120);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	/* Tell the PHY power is stable */
50462306a36Sopenharmony_ci	val = CFG54_USB3_PHY0_ANA_PWR_EN | CFG54_PHY0_PCS_PWR_STABLE |
50562306a36Sopenharmony_ci	      CFG54_PHY0_PMA_PWR_STABLE;
50662306a36Sopenharmony_ci	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54,
50762306a36Sopenharmony_ci				 val, val);
50862306a36Sopenharmony_ci	if (ret)
50962306a36Sopenharmony_ci		goto out;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	ret = hi3670_config_tca(priv);
51262306a36Sopenharmony_ci	if (ret)
51362306a36Sopenharmony_ci		goto out;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	/* Enable SSC */
51662306a36Sopenharmony_ci	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG5C,
51762306a36Sopenharmony_ci				 CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN,
51862306a36Sopenharmony_ci				 CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN);
51962306a36Sopenharmony_ci	if (ret)
52062306a36Sopenharmony_ci		goto out;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	/* Deassert controller */
52362306a36Sopenharmony_ci	val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET;
52462306a36Sopenharmony_ci	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val);
52562306a36Sopenharmony_ci	if (ret)
52662306a36Sopenharmony_ci		goto out;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	usleep_range(100, 120);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	/* Set fake vbus valid signal */
53162306a36Sopenharmony_ci	val = CTRL0_USB3_VBUSVLD | CTRL0_USB3_VBUSVLD_SEL;
53262306a36Sopenharmony_ci	ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL0, val, val);
53362306a36Sopenharmony_ci	if (ret)
53462306a36Sopenharmony_ci		goto out;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	val = CTRL3_USB2_VBUSVLDEXT0 | CTRL3_USB2_VBUSVLDEXTSEL0;
53762306a36Sopenharmony_ci	ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL3, val, val);
53862306a36Sopenharmony_ci	if (ret)
53962306a36Sopenharmony_ci		goto out;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	usleep_range(100, 120);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	ret = hi3670_phy_set_params(priv);
54462306a36Sopenharmony_ci	if (ret)
54562306a36Sopenharmony_ci		goto out;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	return 0;
54862306a36Sopenharmony_ciout:
54962306a36Sopenharmony_ci	dev_err(priv->dev, "failed to init phy ret: %d\n", ret);
55062306a36Sopenharmony_ci	return ret;
55162306a36Sopenharmony_ci}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_cistatic int hi3670_phy_exit(struct phy *phy)
55462306a36Sopenharmony_ci{
55562306a36Sopenharmony_ci	struct hi3670_priv *priv = phy_get_drvdata(phy);
55662306a36Sopenharmony_ci	u32 mask;
55762306a36Sopenharmony_ci	int ret;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	/* Assert phy */
56062306a36Sopenharmony_ci	mask = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
56162306a36Sopenharmony_ci	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, mask, 0);
56262306a36Sopenharmony_ci	if (ret)
56362306a36Sopenharmony_ci		goto out;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	if (!hi3670_is_abbclk_selected(priv)) {
56662306a36Sopenharmony_ci		/* disable usb_tcxo_en */
56762306a36Sopenharmony_ci		ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3,
56862306a36Sopenharmony_ci				   USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START);
56962306a36Sopenharmony_ci	} else {
57062306a36Sopenharmony_ci		ret = regmap_write(priv->peri_crg, PERI_CRG_PERDIS6,
57162306a36Sopenharmony_ci				   GT_CLK_USB2PHY_REF);
57262306a36Sopenharmony_ci		if (ret)
57362306a36Sopenharmony_ci			goto out;
57462306a36Sopenharmony_ci	}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	return 0;
57762306a36Sopenharmony_ciout:
57862306a36Sopenharmony_ci	dev_err(priv->dev, "failed to exit phy ret: %d\n", ret);
57962306a36Sopenharmony_ci	return ret;
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic const struct phy_ops hi3670_phy_ops = {
58362306a36Sopenharmony_ci	.init		= hi3670_phy_init,
58462306a36Sopenharmony_ci	.exit		= hi3670_phy_exit,
58562306a36Sopenharmony_ci	.owner		= THIS_MODULE,
58662306a36Sopenharmony_ci};
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_cistatic int hi3670_phy_probe(struct platform_device *pdev)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	struct phy_provider *phy_provider;
59162306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
59262306a36Sopenharmony_ci	struct phy *phy;
59362306a36Sopenharmony_ci	struct hi3670_priv *priv;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
59662306a36Sopenharmony_ci	if (!priv)
59762306a36Sopenharmony_ci		return -ENOMEM;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	priv->dev = dev;
60062306a36Sopenharmony_ci	priv->peri_crg = syscon_regmap_lookup_by_phandle(dev->of_node,
60162306a36Sopenharmony_ci							 "hisilicon,pericrg-syscon");
60262306a36Sopenharmony_ci	if (IS_ERR(priv->peri_crg)) {
60362306a36Sopenharmony_ci		dev_err(dev, "no hisilicon,pericrg-syscon\n");
60462306a36Sopenharmony_ci		return PTR_ERR(priv->peri_crg);
60562306a36Sopenharmony_ci	}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	priv->pctrl = syscon_regmap_lookup_by_phandle(dev->of_node,
60862306a36Sopenharmony_ci						      "hisilicon,pctrl-syscon");
60962306a36Sopenharmony_ci	if (IS_ERR(priv->pctrl)) {
61062306a36Sopenharmony_ci		dev_err(dev, "no hisilicon,pctrl-syscon\n");
61162306a36Sopenharmony_ci		return PTR_ERR(priv->pctrl);
61262306a36Sopenharmony_ci	}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	priv->sctrl = syscon_regmap_lookup_by_phandle(dev->of_node,
61562306a36Sopenharmony_ci						      "hisilicon,sctrl-syscon");
61662306a36Sopenharmony_ci	if (IS_ERR(priv->sctrl)) {
61762306a36Sopenharmony_ci		dev_err(dev, "no hisilicon,sctrl-syscon\n");
61862306a36Sopenharmony_ci		return PTR_ERR(priv->sctrl);
61962306a36Sopenharmony_ci	}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	/* node of hi3670 phy is a sub-node of usb3_otg_bc */
62262306a36Sopenharmony_ci	priv->usb31misc = syscon_node_to_regmap(dev->parent->of_node);
62362306a36Sopenharmony_ci	if (IS_ERR(priv->usb31misc)) {
62462306a36Sopenharmony_ci		dev_err(dev, "no hisilicon,usb3-otg-bc-syscon\n");
62562306a36Sopenharmony_ci		return PTR_ERR(priv->usb31misc);
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (of_property_read_u32(dev->of_node, "hisilicon,eye-diagram-param",
62962306a36Sopenharmony_ci				 &priv->eye_diagram_param))
63062306a36Sopenharmony_ci		priv->eye_diagram_param = KIRIN970_USB_DEFAULT_PHY_PARAM;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	if (of_property_read_u32(dev->of_node, "hisilicon,tx-vboost-lvl",
63362306a36Sopenharmony_ci				 &priv->tx_vboost_lvl))
63462306a36Sopenharmony_ci		priv->tx_vboost_lvl = KIRIN970_USB_DEFAULT_PHY_VBOOST;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	phy = devm_phy_create(dev, NULL, &hi3670_phy_ops);
63762306a36Sopenharmony_ci	if (IS_ERR(phy))
63862306a36Sopenharmony_ci		return PTR_ERR(phy);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	phy_set_drvdata(phy, priv);
64162306a36Sopenharmony_ci	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
64262306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(phy_provider);
64362306a36Sopenharmony_ci}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_cistatic const struct of_device_id hi3670_phy_of_match[] = {
64662306a36Sopenharmony_ci	{ .compatible = "hisilicon,hi3670-usb-phy" },
64762306a36Sopenharmony_ci	{ },
64862306a36Sopenharmony_ci};
64962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, hi3670_phy_of_match);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_cistatic struct platform_driver hi3670_phy_driver = {
65262306a36Sopenharmony_ci	.probe	= hi3670_phy_probe,
65362306a36Sopenharmony_ci	.driver = {
65462306a36Sopenharmony_ci		.name	= "hi3670-usb-phy",
65562306a36Sopenharmony_ci		.of_match_table	= hi3670_phy_of_match,
65662306a36Sopenharmony_ci	}
65762306a36Sopenharmony_ci};
65862306a36Sopenharmony_cimodule_platform_driver(hi3670_phy_driver);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ciMODULE_AUTHOR("Yu Chen <chenyu56@huawei.com>");
66162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
66262306a36Sopenharmony_ciMODULE_DESCRIPTION("Hilisicon Kirin970 USB31 PHY Driver");
663