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