xref: /linux/drivers/phy/phy-snps-eusb2.c (revision d12ed2b7e1fe5c9e4a372a95fb7635a7f81eff6a)
18d3b5f63SIvaylo Ivanov // SPDX-License-Identifier: GPL-2.0
28d3b5f63SIvaylo Ivanov /*
38d3b5f63SIvaylo Ivanov  * Copyright (c) 2023, Linaro Limited
48d3b5f63SIvaylo Ivanov  */
58d3b5f63SIvaylo Ivanov 
68d3b5f63SIvaylo Ivanov #include <linux/bitfield.h>
78d3b5f63SIvaylo Ivanov #include <linux/clk.h>
88d3b5f63SIvaylo Ivanov #include <linux/delay.h>
98d3b5f63SIvaylo Ivanov #include <linux/iopoll.h>
108d3b5f63SIvaylo Ivanov #include <linux/mod_devicetable.h>
118d3b5f63SIvaylo Ivanov #include <linux/phy/phy.h>
128d3b5f63SIvaylo Ivanov #include <linux/platform_device.h>
138d3b5f63SIvaylo Ivanov #include <linux/regulator/consumer.h>
148d3b5f63SIvaylo Ivanov #include <linux/reset.h>
158d3b5f63SIvaylo Ivanov 
16*c4098f3eSIvaylo Ivanov #define EXYNOS_USB_PHY_HS_PHY_CTRL_RST	(0x0)
17*c4098f3eSIvaylo Ivanov #define USB_PHY_RST_MASK		GENMASK(1, 0)
18*c4098f3eSIvaylo Ivanov #define UTMI_PORT_RST_MASK		GENMASK(5, 4)
19*c4098f3eSIvaylo Ivanov 
20*c4098f3eSIvaylo Ivanov #define EXYNOS_USB_PHY_HS_PHY_CTRL_COMMON	(0x4)
21*c4098f3eSIvaylo Ivanov #define RPTR_MODE			BIT(10)
22*c4098f3eSIvaylo Ivanov #define FSEL_20_MHZ_VAL			(0x1)
23*c4098f3eSIvaylo Ivanov #define FSEL_24_MHZ_VAL			(0x2)
24*c4098f3eSIvaylo Ivanov #define FSEL_26_MHZ_VAL			(0x3)
25*c4098f3eSIvaylo Ivanov #define FSEL_48_MHZ_VAL			(0x2)
26*c4098f3eSIvaylo Ivanov 
27*c4098f3eSIvaylo Ivanov #define EXYNOS_USB_PHY_CFG_PLLCFG0	(0x8)
28*c4098f3eSIvaylo Ivanov #define PHY_CFG_PLL_FB_DIV_19_8_MASK	GENMASK(19, 8)
29*c4098f3eSIvaylo Ivanov #define DIV_19_8_19_2_MHZ_VAL		(0x170)
30*c4098f3eSIvaylo Ivanov #define DIV_19_8_20_MHZ_VAL		(0x160)
31*c4098f3eSIvaylo Ivanov #define DIV_19_8_24_MHZ_VAL		(0x120)
32*c4098f3eSIvaylo Ivanov #define DIV_19_8_26_MHZ_VAL		(0x107)
33*c4098f3eSIvaylo Ivanov #define DIV_19_8_48_MHZ_VAL		(0x120)
34*c4098f3eSIvaylo Ivanov 
35*c4098f3eSIvaylo Ivanov #define EXYNOS_USB_PHY_CFG_PLLCFG1	(0xc)
36*c4098f3eSIvaylo Ivanov #define EXYNOS_PHY_CFG_PLL_FB_DIV_11_8_MASK	GENMASK(11, 8)
37*c4098f3eSIvaylo Ivanov #define EXYNOS_DIV_11_8_19_2_MHZ_VAL	(0x0)
38*c4098f3eSIvaylo Ivanov #define EXYNOS_DIV_11_8_20_MHZ_VAL	(0x0)
39*c4098f3eSIvaylo Ivanov #define EXYNOS_DIV_11_8_24_MHZ_VAL	(0x0)
40*c4098f3eSIvaylo Ivanov #define EXYNOS_DIV_11_8_26_MHZ_VAL	(0x0)
41*c4098f3eSIvaylo Ivanov #define EXYNOS_DIV_11_8_48_MHZ_VAL	(0x1)
42*c4098f3eSIvaylo Ivanov 
43*c4098f3eSIvaylo Ivanov #define EXYNOS_PHY_CFG_TX		(0x14)
44*c4098f3eSIvaylo Ivanov #define EXYNOS_PHY_CFG_TX_FSLS_VREF_TUNE_MASK	GENMASK(2, 1)
45*c4098f3eSIvaylo Ivanov 
46*c4098f3eSIvaylo Ivanov #define EXYNOS_USB_PHY_UTMI_TESTSE	(0x20)
47*c4098f3eSIvaylo Ivanov #define TEST_IDDQ			BIT(6)
48*c4098f3eSIvaylo Ivanov 
4993dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_UTMI_CTRL0		(0x3c)
508d3b5f63SIvaylo Ivanov #define SLEEPM				BIT(0)
518d3b5f63SIvaylo Ivanov #define OPMODE_MASK			GENMASK(4, 3)
528d3b5f63SIvaylo Ivanov #define OPMODE_NONDRIVING		BIT(3)
538d3b5f63SIvaylo Ivanov 
5493dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_UTMI_CTRL5		(0x50)
558d3b5f63SIvaylo Ivanov #define POR				BIT(1)
568d3b5f63SIvaylo Ivanov 
5793dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_HS_PHY_CTRL_COMMON0	(0x54)
588d3b5f63SIvaylo Ivanov #define PHY_ENABLE			BIT(0)
598d3b5f63SIvaylo Ivanov #define SIDDQ_SEL			BIT(1)
608d3b5f63SIvaylo Ivanov #define SIDDQ				BIT(2)
618d3b5f63SIvaylo Ivanov #define RETENABLEN			BIT(3)
628d3b5f63SIvaylo Ivanov #define FSEL_MASK			GENMASK(6, 4)
638d3b5f63SIvaylo Ivanov #define FSEL_19_2_MHZ_VAL		(0x0)
648d3b5f63SIvaylo Ivanov #define FSEL_38_4_MHZ_VAL		(0x4)
658d3b5f63SIvaylo Ivanov 
6693dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_CFG_CTRL_1		(0x58)
678d3b5f63SIvaylo Ivanov #define PHY_CFG_PLL_CPBIAS_CNTRL_MASK	GENMASK(7, 1)
688d3b5f63SIvaylo Ivanov 
6993dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_CFG_CTRL_2		(0x5c)
708d3b5f63SIvaylo Ivanov #define PHY_CFG_PLL_FB_DIV_7_0_MASK	GENMASK(7, 0)
718d3b5f63SIvaylo Ivanov #define DIV_7_0_19_2_MHZ_VAL		(0x90)
728d3b5f63SIvaylo Ivanov #define DIV_7_0_38_4_MHZ_VAL		(0xc8)
738d3b5f63SIvaylo Ivanov 
7493dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_CFG_CTRL_3		(0x60)
758d3b5f63SIvaylo Ivanov #define PHY_CFG_PLL_FB_DIV_11_8_MASK	GENMASK(3, 0)
768d3b5f63SIvaylo Ivanov #define DIV_11_8_19_2_MHZ_VAL		(0x1)
778d3b5f63SIvaylo Ivanov #define DIV_11_8_38_4_MHZ_VAL		(0x0)
788d3b5f63SIvaylo Ivanov 
798d3b5f63SIvaylo Ivanov #define PHY_CFG_PLL_REF_DIV		GENMASK(7, 4)
808d3b5f63SIvaylo Ivanov #define PLL_REF_DIV_VAL			(0x0)
818d3b5f63SIvaylo Ivanov 
8293dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_HS_PHY_CTRL2	(0x64)
838d3b5f63SIvaylo Ivanov #define VBUSVLDEXT0			BIT(0)
848d3b5f63SIvaylo Ivanov #define USB2_SUSPEND_N			BIT(2)
858d3b5f63SIvaylo Ivanov #define USB2_SUSPEND_N_SEL		BIT(3)
868d3b5f63SIvaylo Ivanov #define VBUS_DET_EXT_SEL		BIT(4)
878d3b5f63SIvaylo Ivanov 
8893dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_CFG_CTRL_4		(0x68)
898d3b5f63SIvaylo Ivanov #define PHY_CFG_PLL_GMP_CNTRL_MASK	GENMASK(1, 0)
908d3b5f63SIvaylo Ivanov #define PHY_CFG_PLL_INT_CNTRL_MASK	GENMASK(7, 2)
918d3b5f63SIvaylo Ivanov 
9293dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_CFG_CTRL_5		(0x6c)
938d3b5f63SIvaylo Ivanov #define PHY_CFG_PLL_PROP_CNTRL_MASK	GENMASK(4, 0)
948d3b5f63SIvaylo Ivanov #define PHY_CFG_PLL_VREF_TUNE_MASK	GENMASK(7, 6)
958d3b5f63SIvaylo Ivanov 
9693dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_CFG_CTRL_6		(0x70)
978d3b5f63SIvaylo Ivanov #define PHY_CFG_PLL_VCO_CNTRL_MASK	GENMASK(2, 0)
988d3b5f63SIvaylo Ivanov 
9993dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_CFG_CTRL_7		(0x74)
1008d3b5f63SIvaylo Ivanov 
10193dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_CFG_CTRL_8		(0x78)
1028d3b5f63SIvaylo Ivanov #define PHY_CFG_TX_FSLS_VREF_TUNE_MASK	GENMASK(1, 0)
1038d3b5f63SIvaylo Ivanov #define PHY_CFG_TX_FSLS_VREG_BYPASS	BIT(2)
1048d3b5f63SIvaylo Ivanov #define PHY_CFG_TX_HS_VREF_TUNE_MASK	GENMASK(5, 3)
1058d3b5f63SIvaylo Ivanov #define PHY_CFG_TX_HS_XV_TUNE_MASK	GENMASK(7, 6)
1068d3b5f63SIvaylo Ivanov 
10793dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_CFG_CTRL_9		(0x7c)
1088d3b5f63SIvaylo Ivanov #define PHY_CFG_TX_PREEMP_TUNE_MASK	GENMASK(2, 0)
1098d3b5f63SIvaylo Ivanov #define PHY_CFG_TX_RES_TUNE_MASK	GENMASK(4, 3)
1108d3b5f63SIvaylo Ivanov #define PHY_CFG_TX_RISE_TUNE_MASK	GENMASK(6, 5)
1118d3b5f63SIvaylo Ivanov #define PHY_CFG_RCAL_BYPASS		BIT(7)
1128d3b5f63SIvaylo Ivanov 
11393dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_CFG_CTRL_10	(0x80)
1148d3b5f63SIvaylo Ivanov 
11593dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_CFG0		(0x94)
1168d3b5f63SIvaylo Ivanov #define DATAPATH_CTRL_OVERRIDE_EN	BIT(0)
1178d3b5f63SIvaylo Ivanov #define CMN_CTRL_OVERRIDE_EN		BIT(1)
1188d3b5f63SIvaylo Ivanov 
11993dbe9b5SIvaylo Ivanov #define QCOM_UTMI_PHY_CMN_CTRL0		(0x98)
1208d3b5f63SIvaylo Ivanov #define TESTBURNIN			BIT(6)
1218d3b5f63SIvaylo Ivanov 
12293dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_FSEL_SEL		(0xb8)
1238d3b5f63SIvaylo Ivanov #define FSEL_SEL			BIT(0)
1248d3b5f63SIvaylo Ivanov 
12593dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_APB_ACCESS_CMD	(0x130)
1268d3b5f63SIvaylo Ivanov #define RW_ACCESS			BIT(0)
1278d3b5f63SIvaylo Ivanov #define APB_START_CMD			BIT(1)
1288d3b5f63SIvaylo Ivanov #define APB_LOGIC_RESET			BIT(2)
1298d3b5f63SIvaylo Ivanov 
13093dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_APB_ACCESS_STATUS	(0x134)
1318d3b5f63SIvaylo Ivanov #define ACCESS_DONE			BIT(0)
1328d3b5f63SIvaylo Ivanov #define TIMED_OUT			BIT(1)
1338d3b5f63SIvaylo Ivanov #define ACCESS_ERROR			BIT(2)
1348d3b5f63SIvaylo Ivanov #define ACCESS_IN_PROGRESS		BIT(3)
1358d3b5f63SIvaylo Ivanov 
13693dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_APB_ADDRESS	(0x138)
1378d3b5f63SIvaylo Ivanov #define APB_REG_ADDR_MASK		GENMASK(7, 0)
1388d3b5f63SIvaylo Ivanov 
13993dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_APB_WRDATA_LSB	(0x13c)
1408d3b5f63SIvaylo Ivanov #define APB_REG_WRDATA_7_0_MASK		GENMASK(3, 0)
1418d3b5f63SIvaylo Ivanov 
14293dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_APB_WRDATA_MSB	(0x140)
1438d3b5f63SIvaylo Ivanov #define APB_REG_WRDATA_15_8_MASK	GENMASK(7, 4)
1448d3b5f63SIvaylo Ivanov 
14593dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_APB_RDDATA_LSB	(0x144)
1468d3b5f63SIvaylo Ivanov #define APB_REG_RDDATA_7_0_MASK		GENMASK(3, 0)
1478d3b5f63SIvaylo Ivanov 
14893dbe9b5SIvaylo Ivanov #define QCOM_USB_PHY_APB_RDDATA_MSB	(0x148)
1498d3b5f63SIvaylo Ivanov #define APB_REG_RDDATA_15_8_MASK	GENMASK(7, 4)
1508d3b5f63SIvaylo Ivanov 
1518d3b5f63SIvaylo Ivanov static const char * const eusb2_hsphy_vreg_names[] = {
1528d3b5f63SIvaylo Ivanov 	"vdd", "vdda12",
1538d3b5f63SIvaylo Ivanov };
1548d3b5f63SIvaylo Ivanov 
1558d3b5f63SIvaylo Ivanov #define EUSB2_NUM_VREGS		ARRAY_SIZE(eusb2_hsphy_vreg_names)
1568d3b5f63SIvaylo Ivanov 
1573983b4e9SIvaylo Ivanov struct snps_eusb2_phy_drvdata {
1583983b4e9SIvaylo Ivanov 	int (*phy_init)(struct phy *p);
159*c4098f3eSIvaylo Ivanov 	const char * const *clk_names;
160*c4098f3eSIvaylo Ivanov 	int num_clks;
1613983b4e9SIvaylo Ivanov };
1623983b4e9SIvaylo Ivanov 
16393dbe9b5SIvaylo Ivanov struct snps_eusb2_hsphy {
1648d3b5f63SIvaylo Ivanov 	struct phy *phy;
1658d3b5f63SIvaylo Ivanov 	void __iomem *base;
1668d3b5f63SIvaylo Ivanov 
1678d3b5f63SIvaylo Ivanov 	struct clk *ref_clk;
168*c4098f3eSIvaylo Ivanov 	struct clk_bulk_data *clks;
1698d3b5f63SIvaylo Ivanov 	struct reset_control *phy_reset;
1708d3b5f63SIvaylo Ivanov 
1718d3b5f63SIvaylo Ivanov 	struct regulator_bulk_data vregs[EUSB2_NUM_VREGS];
1728d3b5f63SIvaylo Ivanov 
1738d3b5f63SIvaylo Ivanov 	enum phy_mode mode;
1748d3b5f63SIvaylo Ivanov 
1758d3b5f63SIvaylo Ivanov 	struct phy *repeater;
1763983b4e9SIvaylo Ivanov 
1773983b4e9SIvaylo Ivanov 	const struct snps_eusb2_phy_drvdata *data;
1788d3b5f63SIvaylo Ivanov };
1798d3b5f63SIvaylo Ivanov 
snps_eusb2_hsphy_set_mode(struct phy * p,enum phy_mode mode,int submode)18093dbe9b5SIvaylo Ivanov static int snps_eusb2_hsphy_set_mode(struct phy *p, enum phy_mode mode, int submode)
1818d3b5f63SIvaylo Ivanov {
18293dbe9b5SIvaylo Ivanov 	struct snps_eusb2_hsphy *phy = phy_get_drvdata(p);
1838d3b5f63SIvaylo Ivanov 
1848d3b5f63SIvaylo Ivanov 	phy->mode = mode;
1858d3b5f63SIvaylo Ivanov 
1868d3b5f63SIvaylo Ivanov 	return phy_set_mode_ext(phy->repeater, mode, submode);
1878d3b5f63SIvaylo Ivanov }
1888d3b5f63SIvaylo Ivanov 
snps_eusb2_hsphy_write_mask(void __iomem * base,u32 offset,u32 mask,u32 val)18993dbe9b5SIvaylo Ivanov static void snps_eusb2_hsphy_write_mask(void __iomem *base, u32 offset,
1908d3b5f63SIvaylo Ivanov 					u32 mask, u32 val)
1918d3b5f63SIvaylo Ivanov {
1928d3b5f63SIvaylo Ivanov 	u32 reg;
1938d3b5f63SIvaylo Ivanov 
1948d3b5f63SIvaylo Ivanov 	reg = readl_relaxed(base + offset);
1958d3b5f63SIvaylo Ivanov 	reg &= ~mask;
1968d3b5f63SIvaylo Ivanov 	reg |= val & mask;
1978d3b5f63SIvaylo Ivanov 	writel_relaxed(reg, base + offset);
1988d3b5f63SIvaylo Ivanov 
1998d3b5f63SIvaylo Ivanov 	/* Ensure above write is completed */
2008d3b5f63SIvaylo Ivanov 	readl_relaxed(base + offset);
2018d3b5f63SIvaylo Ivanov }
2028d3b5f63SIvaylo Ivanov 
qcom_eusb2_default_parameters(struct snps_eusb2_hsphy * phy)20393dbe9b5SIvaylo Ivanov static void qcom_eusb2_default_parameters(struct snps_eusb2_hsphy *phy)
2048d3b5f63SIvaylo Ivanov {
2058d3b5f63SIvaylo Ivanov 	/* default parameters: tx pre-emphasis */
20693dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_9,
2078d3b5f63SIvaylo Ivanov 				    PHY_CFG_TX_PREEMP_TUNE_MASK,
2088d3b5f63SIvaylo Ivanov 				    FIELD_PREP(PHY_CFG_TX_PREEMP_TUNE_MASK, 0));
2098d3b5f63SIvaylo Ivanov 
2108d3b5f63SIvaylo Ivanov 	/* tx rise/fall time */
21193dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_9,
2128d3b5f63SIvaylo Ivanov 				    PHY_CFG_TX_RISE_TUNE_MASK,
2138d3b5f63SIvaylo Ivanov 				    FIELD_PREP(PHY_CFG_TX_RISE_TUNE_MASK, 0x2));
2148d3b5f63SIvaylo Ivanov 
2158d3b5f63SIvaylo Ivanov 	/* source impedance adjustment */
21693dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_9,
2178d3b5f63SIvaylo Ivanov 				    PHY_CFG_TX_RES_TUNE_MASK,
2188d3b5f63SIvaylo Ivanov 				    FIELD_PREP(PHY_CFG_TX_RES_TUNE_MASK, 0x1));
2198d3b5f63SIvaylo Ivanov 
2208d3b5f63SIvaylo Ivanov 	/* dc voltage level adjustement */
22193dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_8,
2228d3b5f63SIvaylo Ivanov 				    PHY_CFG_TX_HS_VREF_TUNE_MASK,
2238d3b5f63SIvaylo Ivanov 				    FIELD_PREP(PHY_CFG_TX_HS_VREF_TUNE_MASK, 0x3));
2248d3b5f63SIvaylo Ivanov 
2258d3b5f63SIvaylo Ivanov 	/* transmitter HS crossover adjustement */
22693dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_8,
2278d3b5f63SIvaylo Ivanov 				    PHY_CFG_TX_HS_XV_TUNE_MASK,
2288d3b5f63SIvaylo Ivanov 				    FIELD_PREP(PHY_CFG_TX_HS_XV_TUNE_MASK, 0x0));
2298d3b5f63SIvaylo Ivanov }
2308d3b5f63SIvaylo Ivanov 
231e36a5d1eSIvaylo Ivanov struct snps_eusb2_ref_clk {
232e36a5d1eSIvaylo Ivanov 	unsigned long freq;
233e36a5d1eSIvaylo Ivanov 	u32 fsel_val;
234e36a5d1eSIvaylo Ivanov 	u32 div_7_0_val;
235e36a5d1eSIvaylo Ivanov 	u32 div_11_8_val;
236e36a5d1eSIvaylo Ivanov };
237e36a5d1eSIvaylo Ivanov 
238*c4098f3eSIvaylo Ivanov static const struct snps_eusb2_ref_clk exynos_eusb2_ref_clk[] = {
239*c4098f3eSIvaylo Ivanov 	{ 19200000, FSEL_19_2_MHZ_VAL, DIV_19_8_19_2_MHZ_VAL, EXYNOS_DIV_11_8_19_2_MHZ_VAL },
240*c4098f3eSIvaylo Ivanov 	{ 20000000, FSEL_20_MHZ_VAL, DIV_19_8_20_MHZ_VAL, EXYNOS_DIV_11_8_20_MHZ_VAL },
241*c4098f3eSIvaylo Ivanov 	{ 24000000, FSEL_24_MHZ_VAL, DIV_19_8_24_MHZ_VAL, EXYNOS_DIV_11_8_24_MHZ_VAL },
242*c4098f3eSIvaylo Ivanov 	{ 26000000, FSEL_26_MHZ_VAL, DIV_19_8_26_MHZ_VAL, EXYNOS_DIV_11_8_26_MHZ_VAL },
243*c4098f3eSIvaylo Ivanov 	{ 48000000, FSEL_48_MHZ_VAL, DIV_19_8_48_MHZ_VAL, EXYNOS_DIV_11_8_48_MHZ_VAL },
244*c4098f3eSIvaylo Ivanov };
245*c4098f3eSIvaylo Ivanov 
exynos_eusb2_ref_clk_init(struct snps_eusb2_hsphy * phy)246*c4098f3eSIvaylo Ivanov static int exynos_eusb2_ref_clk_init(struct snps_eusb2_hsphy *phy)
247*c4098f3eSIvaylo Ivanov {
248*c4098f3eSIvaylo Ivanov 	const struct snps_eusb2_ref_clk *config = NULL;
249*c4098f3eSIvaylo Ivanov 	unsigned long ref_clk_freq = clk_get_rate(phy->ref_clk);
250*c4098f3eSIvaylo Ivanov 
251*c4098f3eSIvaylo Ivanov 	for (int i = 0; i < ARRAY_SIZE(exynos_eusb2_ref_clk); i++) {
252*c4098f3eSIvaylo Ivanov 		if (exynos_eusb2_ref_clk[i].freq == ref_clk_freq) {
253*c4098f3eSIvaylo Ivanov 			config = &exynos_eusb2_ref_clk[i];
254*c4098f3eSIvaylo Ivanov 			break;
255*c4098f3eSIvaylo Ivanov 		}
256*c4098f3eSIvaylo Ivanov 	}
257*c4098f3eSIvaylo Ivanov 
258*c4098f3eSIvaylo Ivanov 	if (!config) {
259*c4098f3eSIvaylo Ivanov 		dev_err(&phy->phy->dev, "unsupported ref_clk_freq:%lu\n", ref_clk_freq);
260*c4098f3eSIvaylo Ivanov 		return -EINVAL;
261*c4098f3eSIvaylo Ivanov 	}
262*c4098f3eSIvaylo Ivanov 
263*c4098f3eSIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_COMMON,
264*c4098f3eSIvaylo Ivanov 				    FSEL_MASK,
265*c4098f3eSIvaylo Ivanov 				    FIELD_PREP(FSEL_MASK, config->fsel_val));
266*c4098f3eSIvaylo Ivanov 
267*c4098f3eSIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_CFG_PLLCFG0,
268*c4098f3eSIvaylo Ivanov 				    PHY_CFG_PLL_FB_DIV_19_8_MASK,
269*c4098f3eSIvaylo Ivanov 				    FIELD_PREP(PHY_CFG_PLL_FB_DIV_19_8_MASK,
270*c4098f3eSIvaylo Ivanov 					       config->div_7_0_val));
271*c4098f3eSIvaylo Ivanov 
272*c4098f3eSIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_CFG_PLLCFG1,
273*c4098f3eSIvaylo Ivanov 				    EXYNOS_PHY_CFG_PLL_FB_DIV_11_8_MASK,
274*c4098f3eSIvaylo Ivanov 				    config->div_11_8_val);
275*c4098f3eSIvaylo Ivanov 	return 0;
276*c4098f3eSIvaylo Ivanov }
277*c4098f3eSIvaylo Ivanov 
278e36a5d1eSIvaylo Ivanov static const struct snps_eusb2_ref_clk qcom_eusb2_ref_clk[] = {
279e36a5d1eSIvaylo Ivanov 	{ 19200000, FSEL_19_2_MHZ_VAL, DIV_7_0_19_2_MHZ_VAL, DIV_11_8_19_2_MHZ_VAL },
280e36a5d1eSIvaylo Ivanov 	{ 38400000, FSEL_38_4_MHZ_VAL, DIV_7_0_38_4_MHZ_VAL, DIV_11_8_38_4_MHZ_VAL },
281e36a5d1eSIvaylo Ivanov };
282e36a5d1eSIvaylo Ivanov 
qcom_eusb2_ref_clk_init(struct snps_eusb2_hsphy * phy)28393dbe9b5SIvaylo Ivanov static int qcom_eusb2_ref_clk_init(struct snps_eusb2_hsphy *phy)
2848d3b5f63SIvaylo Ivanov {
285e36a5d1eSIvaylo Ivanov 	const struct snps_eusb2_ref_clk *config = NULL;
2868d3b5f63SIvaylo Ivanov 	unsigned long ref_clk_freq = clk_get_rate(phy->ref_clk);
2878d3b5f63SIvaylo Ivanov 
288e36a5d1eSIvaylo Ivanov 	for (int i = 0; i < ARRAY_SIZE(qcom_eusb2_ref_clk); i++) {
289e36a5d1eSIvaylo Ivanov 		if (qcom_eusb2_ref_clk[i].freq == ref_clk_freq) {
290e36a5d1eSIvaylo Ivanov 			config = &qcom_eusb2_ref_clk[i];
2918d3b5f63SIvaylo Ivanov 			break;
292e36a5d1eSIvaylo Ivanov 		}
293e36a5d1eSIvaylo Ivanov 	}
2948d3b5f63SIvaylo Ivanov 
295e36a5d1eSIvaylo Ivanov 	if (!config) {
2968d3b5f63SIvaylo Ivanov 		dev_err(&phy->phy->dev, "unsupported ref_clk_freq:%lu\n", ref_clk_freq);
2978d3b5f63SIvaylo Ivanov 		return -EINVAL;
2988d3b5f63SIvaylo Ivanov 	}
2998d3b5f63SIvaylo Ivanov 
300e36a5d1eSIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL_COMMON0,
301e36a5d1eSIvaylo Ivanov 				    FSEL_MASK,
302e36a5d1eSIvaylo Ivanov 				    FIELD_PREP(FSEL_MASK, config->fsel_val));
303e36a5d1eSIvaylo Ivanov 
304e36a5d1eSIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_2,
305e36a5d1eSIvaylo Ivanov 				    PHY_CFG_PLL_FB_DIV_7_0_MASK,
306e36a5d1eSIvaylo Ivanov 				    config->div_7_0_val);
307e36a5d1eSIvaylo Ivanov 
308e36a5d1eSIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_3,
309e36a5d1eSIvaylo Ivanov 				    PHY_CFG_PLL_FB_DIV_11_8_MASK,
310e36a5d1eSIvaylo Ivanov 				    config->div_11_8_val);
311e36a5d1eSIvaylo Ivanov 
31293dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_3,
3138d3b5f63SIvaylo Ivanov 				    PHY_CFG_PLL_REF_DIV, PLL_REF_DIV_VAL);
3148d3b5f63SIvaylo Ivanov 
3158d3b5f63SIvaylo Ivanov 	return 0;
3168d3b5f63SIvaylo Ivanov }
3178d3b5f63SIvaylo Ivanov 
exynos_snps_eusb2_hsphy_init(struct phy * p)318*c4098f3eSIvaylo Ivanov static int exynos_snps_eusb2_hsphy_init(struct phy *p)
319*c4098f3eSIvaylo Ivanov {
320*c4098f3eSIvaylo Ivanov 	struct snps_eusb2_hsphy *phy = phy_get_drvdata(p);
321*c4098f3eSIvaylo Ivanov 	int ret;
322*c4098f3eSIvaylo Ivanov 
323*c4098f3eSIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_RST,
324*c4098f3eSIvaylo Ivanov 				    USB_PHY_RST_MASK | UTMI_PORT_RST_MASK,
325*c4098f3eSIvaylo Ivanov 				    USB_PHY_RST_MASK | UTMI_PORT_RST_MASK);
326*c4098f3eSIvaylo Ivanov 	fsleep(50); /* required after holding phy in reset */
327*c4098f3eSIvaylo Ivanov 
328*c4098f3eSIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_COMMON,
329*c4098f3eSIvaylo Ivanov 				    RPTR_MODE, RPTR_MODE);
330*c4098f3eSIvaylo Ivanov 
331*c4098f3eSIvaylo Ivanov 	/* update ref_clk related registers */
332*c4098f3eSIvaylo Ivanov 	ret = exynos_eusb2_ref_clk_init(phy);
333*c4098f3eSIvaylo Ivanov 	if (ret)
334*c4098f3eSIvaylo Ivanov 		return ret;
335*c4098f3eSIvaylo Ivanov 
336*c4098f3eSIvaylo Ivanov 	/* default parameter: tx fsls-vref */
337*c4098f3eSIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_PHY_CFG_TX,
338*c4098f3eSIvaylo Ivanov 				    EXYNOS_PHY_CFG_TX_FSLS_VREF_TUNE_MASK,
339*c4098f3eSIvaylo Ivanov 				    FIELD_PREP(EXYNOS_PHY_CFG_TX_FSLS_VREF_TUNE_MASK, 0x0));
340*c4098f3eSIvaylo Ivanov 
341*c4098f3eSIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_UTMI_TESTSE,
342*c4098f3eSIvaylo Ivanov 				    TEST_IDDQ, 0);
343*c4098f3eSIvaylo Ivanov 	fsleep(10); /* required after releasing test_iddq */
344*c4098f3eSIvaylo Ivanov 
345*c4098f3eSIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_RST,
346*c4098f3eSIvaylo Ivanov 				    USB_PHY_RST_MASK, 0);
347*c4098f3eSIvaylo Ivanov 
348*c4098f3eSIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_COMMON,
349*c4098f3eSIvaylo Ivanov 				    PHY_ENABLE, PHY_ENABLE);
350*c4098f3eSIvaylo Ivanov 
351*c4098f3eSIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_RST,
352*c4098f3eSIvaylo Ivanov 				    UTMI_PORT_RST_MASK, 0);
353*c4098f3eSIvaylo Ivanov 
354*c4098f3eSIvaylo Ivanov 	return 0;
355*c4098f3eSIvaylo Ivanov }
356*c4098f3eSIvaylo Ivanov 
357*c4098f3eSIvaylo Ivanov static const char * const exynos_eusb2_hsphy_clock_names[] = {
358*c4098f3eSIvaylo Ivanov 	"ref", "bus", "ctrl",
359*c4098f3eSIvaylo Ivanov };
360*c4098f3eSIvaylo Ivanov 
361*c4098f3eSIvaylo Ivanov static const struct snps_eusb2_phy_drvdata exynos2200_snps_eusb2_phy = {
362*c4098f3eSIvaylo Ivanov 	.phy_init	= exynos_snps_eusb2_hsphy_init,
363*c4098f3eSIvaylo Ivanov 	.clk_names	= exynos_eusb2_hsphy_clock_names,
364*c4098f3eSIvaylo Ivanov 	.num_clks	= ARRAY_SIZE(exynos_eusb2_hsphy_clock_names),
365*c4098f3eSIvaylo Ivanov };
366*c4098f3eSIvaylo Ivanov 
qcom_snps_eusb2_hsphy_init(struct phy * p)3673983b4e9SIvaylo Ivanov static int qcom_snps_eusb2_hsphy_init(struct phy *p)
3688d3b5f63SIvaylo Ivanov {
36993dbe9b5SIvaylo Ivanov 	struct snps_eusb2_hsphy *phy = phy_get_drvdata(p);
3708d3b5f63SIvaylo Ivanov 	int ret;
3718d3b5f63SIvaylo Ivanov 
37293dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG0,
3738d3b5f63SIvaylo Ivanov 				    CMN_CTRL_OVERRIDE_EN, CMN_CTRL_OVERRIDE_EN);
3748d3b5f63SIvaylo Ivanov 
37593dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_UTMI_CTRL5, POR, POR);
3768d3b5f63SIvaylo Ivanov 
37793dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL_COMMON0,
3788d3b5f63SIvaylo Ivanov 				    PHY_ENABLE | RETENABLEN, PHY_ENABLE | RETENABLEN);
3798d3b5f63SIvaylo Ivanov 
38093dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_APB_ACCESS_CMD,
3818d3b5f63SIvaylo Ivanov 				    APB_LOGIC_RESET, APB_LOGIC_RESET);
3828d3b5f63SIvaylo Ivanov 
38393dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_UTMI_PHY_CMN_CTRL0, TESTBURNIN, 0);
3848d3b5f63SIvaylo Ivanov 
38593dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_FSEL_SEL,
3868d3b5f63SIvaylo Ivanov 				    FSEL_SEL, FSEL_SEL);
3878d3b5f63SIvaylo Ivanov 
3888d3b5f63SIvaylo Ivanov 	/* update ref_clk related registers */
3898d3b5f63SIvaylo Ivanov 	ret = qcom_eusb2_ref_clk_init(phy);
3908d3b5f63SIvaylo Ivanov 	if (ret)
39193dbe9b5SIvaylo Ivanov 		return ret;
3928d3b5f63SIvaylo Ivanov 
39393dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_1,
3948d3b5f63SIvaylo Ivanov 				    PHY_CFG_PLL_CPBIAS_CNTRL_MASK,
3958d3b5f63SIvaylo Ivanov 				    FIELD_PREP(PHY_CFG_PLL_CPBIAS_CNTRL_MASK, 0x1));
3968d3b5f63SIvaylo Ivanov 
39793dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_4,
3988d3b5f63SIvaylo Ivanov 				    PHY_CFG_PLL_INT_CNTRL_MASK,
3998d3b5f63SIvaylo Ivanov 				    FIELD_PREP(PHY_CFG_PLL_INT_CNTRL_MASK, 0x8));
4008d3b5f63SIvaylo Ivanov 
40193dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_4,
4028d3b5f63SIvaylo Ivanov 				    PHY_CFG_PLL_GMP_CNTRL_MASK,
4038d3b5f63SIvaylo Ivanov 				    FIELD_PREP(PHY_CFG_PLL_GMP_CNTRL_MASK, 0x1));
4048d3b5f63SIvaylo Ivanov 
40593dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_5,
4068d3b5f63SIvaylo Ivanov 				    PHY_CFG_PLL_PROP_CNTRL_MASK,
4078d3b5f63SIvaylo Ivanov 				    FIELD_PREP(PHY_CFG_PLL_PROP_CNTRL_MASK, 0x10));
4088d3b5f63SIvaylo Ivanov 
40993dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_6,
4108d3b5f63SIvaylo Ivanov 				    PHY_CFG_PLL_VCO_CNTRL_MASK,
4118d3b5f63SIvaylo Ivanov 				    FIELD_PREP(PHY_CFG_PLL_VCO_CNTRL_MASK, 0x0));
4128d3b5f63SIvaylo Ivanov 
41393dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_5,
4148d3b5f63SIvaylo Ivanov 				    PHY_CFG_PLL_VREF_TUNE_MASK,
4158d3b5f63SIvaylo Ivanov 				    FIELD_PREP(PHY_CFG_PLL_VREF_TUNE_MASK, 0x1));
4168d3b5f63SIvaylo Ivanov 
41793dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL2,
4188d3b5f63SIvaylo Ivanov 				    VBUS_DET_EXT_SEL, VBUS_DET_EXT_SEL);
4198d3b5f63SIvaylo Ivanov 
4208d3b5f63SIvaylo Ivanov 	/* set default parameters */
4218d3b5f63SIvaylo Ivanov 	qcom_eusb2_default_parameters(phy);
4228d3b5f63SIvaylo Ivanov 
42393dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL2,
4248d3b5f63SIvaylo Ivanov 				    USB2_SUSPEND_N_SEL | USB2_SUSPEND_N,
4258d3b5f63SIvaylo Ivanov 				    USB2_SUSPEND_N_SEL | USB2_SUSPEND_N);
4268d3b5f63SIvaylo Ivanov 
42793dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_UTMI_CTRL0, SLEEPM, SLEEPM);
4288d3b5f63SIvaylo Ivanov 
42993dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL_COMMON0,
4308d3b5f63SIvaylo Ivanov 				    SIDDQ_SEL, SIDDQ_SEL);
4318d3b5f63SIvaylo Ivanov 
43293dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL_COMMON0,
4338d3b5f63SIvaylo Ivanov 				    SIDDQ, 0);
4348d3b5f63SIvaylo Ivanov 
43593dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_UTMI_CTRL5, POR, 0);
4368d3b5f63SIvaylo Ivanov 
43793dbe9b5SIvaylo Ivanov 	snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL2,
4388d3b5f63SIvaylo Ivanov 				    USB2_SUSPEND_N_SEL, 0);
4398d3b5f63SIvaylo Ivanov 
4408d3b5f63SIvaylo Ivanov 	return 0;
4413983b4e9SIvaylo Ivanov }
4423983b4e9SIvaylo Ivanov 
443*c4098f3eSIvaylo Ivanov static const char * const qcom_eusb2_hsphy_clock_names[] = {
444*c4098f3eSIvaylo Ivanov 	"ref",
445*c4098f3eSIvaylo Ivanov };
446*c4098f3eSIvaylo Ivanov 
4473983b4e9SIvaylo Ivanov static const struct snps_eusb2_phy_drvdata sm8550_snps_eusb2_phy = {
4483983b4e9SIvaylo Ivanov 	.phy_init	= qcom_snps_eusb2_hsphy_init,
449*c4098f3eSIvaylo Ivanov 	.clk_names      = qcom_eusb2_hsphy_clock_names,
450*c4098f3eSIvaylo Ivanov 	.num_clks       = ARRAY_SIZE(qcom_eusb2_hsphy_clock_names),
4513983b4e9SIvaylo Ivanov };
4523983b4e9SIvaylo Ivanov 
snps_eusb2_hsphy_init(struct phy * p)4533983b4e9SIvaylo Ivanov static int snps_eusb2_hsphy_init(struct phy *p)
4543983b4e9SIvaylo Ivanov {
4553983b4e9SIvaylo Ivanov 	struct snps_eusb2_hsphy *phy = phy_get_drvdata(p);
4563983b4e9SIvaylo Ivanov 	int ret;
4573983b4e9SIvaylo Ivanov 
4583983b4e9SIvaylo Ivanov 	ret = regulator_bulk_enable(ARRAY_SIZE(phy->vregs), phy->vregs);
4593983b4e9SIvaylo Ivanov 	if (ret)
4603983b4e9SIvaylo Ivanov 		return ret;
4613983b4e9SIvaylo Ivanov 
4623983b4e9SIvaylo Ivanov 	ret = phy_init(phy->repeater);
4633983b4e9SIvaylo Ivanov 	if (ret) {
4643983b4e9SIvaylo Ivanov 		dev_err(&p->dev, "repeater init failed. %d\n", ret);
4653983b4e9SIvaylo Ivanov 		goto disable_vreg;
4663983b4e9SIvaylo Ivanov 	}
4673983b4e9SIvaylo Ivanov 
468*c4098f3eSIvaylo Ivanov 	ret = clk_bulk_prepare_enable(phy->data->num_clks, phy->clks);
4693983b4e9SIvaylo Ivanov 	if (ret) {
4703983b4e9SIvaylo Ivanov 		dev_err(&p->dev, "failed to enable ref clock, %d\n", ret);
4713983b4e9SIvaylo Ivanov 		goto disable_vreg;
4723983b4e9SIvaylo Ivanov 	}
4733983b4e9SIvaylo Ivanov 
4743983b4e9SIvaylo Ivanov 	ret = reset_control_assert(phy->phy_reset);
4753983b4e9SIvaylo Ivanov 	if (ret) {
4763983b4e9SIvaylo Ivanov 		dev_err(&p->dev, "failed to assert phy_reset, %d\n", ret);
4773983b4e9SIvaylo Ivanov 		goto disable_ref_clk;
4783983b4e9SIvaylo Ivanov 	}
4793983b4e9SIvaylo Ivanov 
4803983b4e9SIvaylo Ivanov 	usleep_range(100, 150);
4813983b4e9SIvaylo Ivanov 
4823983b4e9SIvaylo Ivanov 	ret = reset_control_deassert(phy->phy_reset);
4833983b4e9SIvaylo Ivanov 	if (ret) {
4843983b4e9SIvaylo Ivanov 		dev_err(&p->dev, "failed to de-assert phy_reset, %d\n", ret);
4853983b4e9SIvaylo Ivanov 		goto disable_ref_clk;
4863983b4e9SIvaylo Ivanov 	}
4873983b4e9SIvaylo Ivanov 
4883983b4e9SIvaylo Ivanov 	ret = phy->data->phy_init(p);
4893983b4e9SIvaylo Ivanov 	if (ret)
4903983b4e9SIvaylo Ivanov 		goto disable_ref_clk;
4913983b4e9SIvaylo Ivanov 
4923983b4e9SIvaylo Ivanov 	return 0;
4938d3b5f63SIvaylo Ivanov 
4948d3b5f63SIvaylo Ivanov disable_ref_clk:
495*c4098f3eSIvaylo Ivanov 	clk_bulk_disable_unprepare(phy->data->num_clks, phy->clks);
4968d3b5f63SIvaylo Ivanov 
4978d3b5f63SIvaylo Ivanov disable_vreg:
4988d3b5f63SIvaylo Ivanov 	regulator_bulk_disable(ARRAY_SIZE(phy->vregs), phy->vregs);
4998d3b5f63SIvaylo Ivanov 
5008d3b5f63SIvaylo Ivanov 	return ret;
5018d3b5f63SIvaylo Ivanov }
5028d3b5f63SIvaylo Ivanov 
snps_eusb2_hsphy_exit(struct phy * p)50393dbe9b5SIvaylo Ivanov static int snps_eusb2_hsphy_exit(struct phy *p)
5048d3b5f63SIvaylo Ivanov {
50593dbe9b5SIvaylo Ivanov 	struct snps_eusb2_hsphy *phy = phy_get_drvdata(p);
5068d3b5f63SIvaylo Ivanov 
5078d3b5f63SIvaylo Ivanov 	clk_disable_unprepare(phy->ref_clk);
5088d3b5f63SIvaylo Ivanov 
5098d3b5f63SIvaylo Ivanov 	regulator_bulk_disable(ARRAY_SIZE(phy->vregs), phy->vregs);
5108d3b5f63SIvaylo Ivanov 
5118d3b5f63SIvaylo Ivanov 	phy_exit(phy->repeater);
5128d3b5f63SIvaylo Ivanov 
5138d3b5f63SIvaylo Ivanov 	return 0;
5148d3b5f63SIvaylo Ivanov }
5158d3b5f63SIvaylo Ivanov 
51693dbe9b5SIvaylo Ivanov static const struct phy_ops snps_eusb2_hsphy_ops = {
51793dbe9b5SIvaylo Ivanov 	.init		= snps_eusb2_hsphy_init,
51893dbe9b5SIvaylo Ivanov 	.exit		= snps_eusb2_hsphy_exit,
51993dbe9b5SIvaylo Ivanov 	.set_mode	= snps_eusb2_hsphy_set_mode,
5208d3b5f63SIvaylo Ivanov 	.owner		= THIS_MODULE,
5218d3b5f63SIvaylo Ivanov };
5228d3b5f63SIvaylo Ivanov 
snps_eusb2_hsphy_probe(struct platform_device * pdev)52393dbe9b5SIvaylo Ivanov static int snps_eusb2_hsphy_probe(struct platform_device *pdev)
5248d3b5f63SIvaylo Ivanov {
5258d3b5f63SIvaylo Ivanov 	struct device *dev = &pdev->dev;
5268d3b5f63SIvaylo Ivanov 	struct device_node *np = dev->of_node;
52793dbe9b5SIvaylo Ivanov 	struct snps_eusb2_hsphy *phy;
5288d3b5f63SIvaylo Ivanov 	struct phy_provider *phy_provider;
5298d3b5f63SIvaylo Ivanov 	struct phy *generic_phy;
5308d3b5f63SIvaylo Ivanov 	int ret, i;
5318d3b5f63SIvaylo Ivanov 	int num;
5328d3b5f63SIvaylo Ivanov 
5338d3b5f63SIvaylo Ivanov 	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
5348d3b5f63SIvaylo Ivanov 	if (!phy)
5358d3b5f63SIvaylo Ivanov 		return -ENOMEM;
5368d3b5f63SIvaylo Ivanov 
5373983b4e9SIvaylo Ivanov 	phy->data = device_get_match_data(dev);
5383983b4e9SIvaylo Ivanov 	if (!phy->data)
5393983b4e9SIvaylo Ivanov 		return -EINVAL;
5403983b4e9SIvaylo Ivanov 
5418d3b5f63SIvaylo Ivanov 	phy->base = devm_platform_ioremap_resource(pdev, 0);
5428d3b5f63SIvaylo Ivanov 	if (IS_ERR(phy->base))
5438d3b5f63SIvaylo Ivanov 		return PTR_ERR(phy->base);
5448d3b5f63SIvaylo Ivanov 
545aba7a966SIvaylo Ivanov 	phy->phy_reset = devm_reset_control_get_optional_exclusive(dev, NULL);
5468d3b5f63SIvaylo Ivanov 	if (IS_ERR(phy->phy_reset))
5478d3b5f63SIvaylo Ivanov 		return PTR_ERR(phy->phy_reset);
5488d3b5f63SIvaylo Ivanov 
549*c4098f3eSIvaylo Ivanov 	phy->clks = devm_kcalloc(dev, phy->data->num_clks, sizeof(*phy->clks),
550*c4098f3eSIvaylo Ivanov 				 GFP_KERNEL);
551*c4098f3eSIvaylo Ivanov 	if (!phy->clks)
552*c4098f3eSIvaylo Ivanov 		return -ENOMEM;
553*c4098f3eSIvaylo Ivanov 
554*c4098f3eSIvaylo Ivanov 	for (int i = 0; i < phy->data->num_clks; ++i)
555*c4098f3eSIvaylo Ivanov 		phy->clks[i].id = phy->data->clk_names[i];
556*c4098f3eSIvaylo Ivanov 
557*c4098f3eSIvaylo Ivanov 	ret = devm_clk_bulk_get(dev, phy->data->num_clks, phy->clks);
558*c4098f3eSIvaylo Ivanov 	if (ret)
559*c4098f3eSIvaylo Ivanov 		return dev_err_probe(dev, ret,
560*c4098f3eSIvaylo Ivanov 				     "failed to get phy clock(s)\n");
561*c4098f3eSIvaylo Ivanov 
562*c4098f3eSIvaylo Ivanov 	phy->ref_clk = NULL;
563*c4098f3eSIvaylo Ivanov 	for (int i = 0; i < phy->data->num_clks; ++i) {
564*c4098f3eSIvaylo Ivanov 		if (!strcmp(phy->clks[i].id, "ref")) {
565*c4098f3eSIvaylo Ivanov 			phy->ref_clk = phy->clks[i].clk;
566*c4098f3eSIvaylo Ivanov 			break;
567*c4098f3eSIvaylo Ivanov 		}
568*c4098f3eSIvaylo Ivanov 	}
569*c4098f3eSIvaylo Ivanov 
570*c4098f3eSIvaylo Ivanov 	if (IS_ERR_OR_NULL(phy->ref_clk))
5718d3b5f63SIvaylo Ivanov 		return dev_err_probe(dev, PTR_ERR(phy->ref_clk),
5728d3b5f63SIvaylo Ivanov 				     "failed to get ref clk\n");
5738d3b5f63SIvaylo Ivanov 
5748d3b5f63SIvaylo Ivanov 	num = ARRAY_SIZE(phy->vregs);
5758d3b5f63SIvaylo Ivanov 	for (i = 0; i < num; i++)
5768d3b5f63SIvaylo Ivanov 		phy->vregs[i].supply = eusb2_hsphy_vreg_names[i];
5778d3b5f63SIvaylo Ivanov 
5788d3b5f63SIvaylo Ivanov 	ret = devm_regulator_bulk_get(dev, num, phy->vregs);
5798d3b5f63SIvaylo Ivanov 	if (ret)
5808d3b5f63SIvaylo Ivanov 		return dev_err_probe(dev, ret,
5818d3b5f63SIvaylo Ivanov 				     "failed to get regulator supplies\n");
5828d3b5f63SIvaylo Ivanov 
583d460be70SIvaylo Ivanov 	phy->repeater = devm_of_phy_optional_get(dev, np, 0);
5848d3b5f63SIvaylo Ivanov 	if (IS_ERR(phy->repeater))
5858d3b5f63SIvaylo Ivanov 		return dev_err_probe(dev, PTR_ERR(phy->repeater),
5868d3b5f63SIvaylo Ivanov 				     "failed to get repeater\n");
5878d3b5f63SIvaylo Ivanov 
58893dbe9b5SIvaylo Ivanov 	generic_phy = devm_phy_create(dev, NULL, &snps_eusb2_hsphy_ops);
5898d3b5f63SIvaylo Ivanov 	if (IS_ERR(generic_phy)) {
5908d3b5f63SIvaylo Ivanov 		dev_err(dev, "failed to create phy %d\n", ret);
5918d3b5f63SIvaylo Ivanov 		return PTR_ERR(generic_phy);
5928d3b5f63SIvaylo Ivanov 	}
5938d3b5f63SIvaylo Ivanov 
5948d3b5f63SIvaylo Ivanov 	dev_set_drvdata(dev, phy);
5958d3b5f63SIvaylo Ivanov 	phy_set_drvdata(generic_phy, phy);
5968d3b5f63SIvaylo Ivanov 
5978d3b5f63SIvaylo Ivanov 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
5988d3b5f63SIvaylo Ivanov 	if (IS_ERR(phy_provider))
5998d3b5f63SIvaylo Ivanov 		return PTR_ERR(phy_provider);
6008d3b5f63SIvaylo Ivanov 
60193dbe9b5SIvaylo Ivanov 	dev_info(dev, "Registered Snps-eUSB2 phy\n");
6028d3b5f63SIvaylo Ivanov 
6038d3b5f63SIvaylo Ivanov 	return 0;
6048d3b5f63SIvaylo Ivanov }
6058d3b5f63SIvaylo Ivanov 
60693dbe9b5SIvaylo Ivanov static const struct of_device_id snps_eusb2_hsphy_of_match_table[] = {
6073983b4e9SIvaylo Ivanov 	{
6083983b4e9SIvaylo Ivanov 		.compatible = "qcom,sm8550-snps-eusb2-phy",
6093983b4e9SIvaylo Ivanov 		.data = &sm8550_snps_eusb2_phy,
610*c4098f3eSIvaylo Ivanov 	}, {
611*c4098f3eSIvaylo Ivanov 		.compatible = "samsung,exynos2200-eusb2-phy",
612*c4098f3eSIvaylo Ivanov 		.data = &exynos2200_snps_eusb2_phy,
6133983b4e9SIvaylo Ivanov 	}, { },
6148d3b5f63SIvaylo Ivanov };
61593dbe9b5SIvaylo Ivanov MODULE_DEVICE_TABLE(of, snps_eusb2_hsphy_of_match_table);
6168d3b5f63SIvaylo Ivanov 
61793dbe9b5SIvaylo Ivanov static struct platform_driver snps_eusb2_hsphy_driver = {
61893dbe9b5SIvaylo Ivanov 	.probe		= snps_eusb2_hsphy_probe,
6198d3b5f63SIvaylo Ivanov 	.driver = {
62093dbe9b5SIvaylo Ivanov 		.name	= "snps-eusb2-hsphy",
62193dbe9b5SIvaylo Ivanov 		.of_match_table = snps_eusb2_hsphy_of_match_table,
6228d3b5f63SIvaylo Ivanov 	},
6238d3b5f63SIvaylo Ivanov };
6248d3b5f63SIvaylo Ivanov 
62593dbe9b5SIvaylo Ivanov module_platform_driver(snps_eusb2_hsphy_driver);
62693dbe9b5SIvaylo Ivanov MODULE_DESCRIPTION("Synopsys eUSB2 HS PHY driver");
6278d3b5f63SIvaylo Ivanov MODULE_LICENSE("GPL");
628