1313#include <linux/regulator/consumer.h>
1414#include <linux/reset.h>
1515
16+ #define EXYNOS_USB_PHY_HS_PHY_CTRL_RST (0x0)
17+ #define USB_PHY_RST_MASK GENMASK(1, 0)
18+ #define UTMI_PORT_RST_MASK GENMASK(5, 4)
19+
20+ #define EXYNOS_USB_PHY_HS_PHY_CTRL_COMMON (0x4)
21+ #define RPTR_MODE BIT(10)
22+ #define FSEL_20_MHZ_VAL (0x1)
23+ #define FSEL_24_MHZ_VAL (0x2)
24+ #define FSEL_26_MHZ_VAL (0x3)
25+ #define FSEL_48_MHZ_VAL (0x2)
26+
27+ #define EXYNOS_USB_PHY_CFG_PLLCFG0 (0x8)
28+ #define PHY_CFG_PLL_FB_DIV_19_8_MASK GENMASK(19, 8)
29+ #define DIV_19_8_19_2_MHZ_VAL (0x170)
30+ #define DIV_19_8_20_MHZ_VAL (0x160)
31+ #define DIV_19_8_24_MHZ_VAL (0x120)
32+ #define DIV_19_8_26_MHZ_VAL (0x107)
33+ #define DIV_19_8_48_MHZ_VAL (0x120)
34+
35+ #define EXYNOS_USB_PHY_CFG_PLLCFG1 (0xc)
36+ #define EXYNOS_PHY_CFG_PLL_FB_DIV_11_8_MASK GENMASK(11, 8)
37+ #define EXYNOS_DIV_11_8_19_2_MHZ_VAL (0x0)
38+ #define EXYNOS_DIV_11_8_20_MHZ_VAL (0x0)
39+ #define EXYNOS_DIV_11_8_24_MHZ_VAL (0x0)
40+ #define EXYNOS_DIV_11_8_26_MHZ_VAL (0x0)
41+ #define EXYNOS_DIV_11_8_48_MHZ_VAL (0x1)
42+
43+ #define EXYNOS_PHY_CFG_TX (0x14)
44+ #define EXYNOS_PHY_CFG_TX_FSLS_VREF_TUNE_MASK GENMASK(2, 1)
45+
46+ #define EXYNOS_USB_PHY_UTMI_TESTSE (0x20)
47+ #define TEST_IDDQ BIT(6)
48+
1649#define QCOM_USB_PHY_UTMI_CTRL0 (0x3c)
1750#define SLEEPM BIT(0)
1851#define OPMODE_MASK GENMASK(4, 3)
@@ -123,13 +156,16 @@ static const char * const eusb2_hsphy_vreg_names[] = {
123156
124157struct snps_eusb2_phy_drvdata {
125158 int (* phy_init )(struct phy * p );
159+ const char * const * clk_names ;
160+ int num_clks ;
126161};
127162
128163struct snps_eusb2_hsphy {
129164 struct phy * phy ;
130165 void __iomem * base ;
131166
132167 struct clk * ref_clk ;
168+ struct clk_bulk_data * clks ;
133169 struct reset_control * phy_reset ;
134170
135171 struct regulator_bulk_data vregs [EUSB2_NUM_VREGS ];
@@ -199,6 +235,46 @@ struct snps_eusb2_ref_clk {
199235 u32 div_11_8_val ;
200236};
201237
238+ static const struct snps_eusb2_ref_clk exynos_eusb2_ref_clk [] = {
239+ { 19200000 , FSEL_19_2_MHZ_VAL , DIV_19_8_19_2_MHZ_VAL , EXYNOS_DIV_11_8_19_2_MHZ_VAL },
240+ { 20000000 , FSEL_20_MHZ_VAL , DIV_19_8_20_MHZ_VAL , EXYNOS_DIV_11_8_20_MHZ_VAL },
241+ { 24000000 , FSEL_24_MHZ_VAL , DIV_19_8_24_MHZ_VAL , EXYNOS_DIV_11_8_24_MHZ_VAL },
242+ { 26000000 , FSEL_26_MHZ_VAL , DIV_19_8_26_MHZ_VAL , EXYNOS_DIV_11_8_26_MHZ_VAL },
243+ { 48000000 , FSEL_48_MHZ_VAL , DIV_19_8_48_MHZ_VAL , EXYNOS_DIV_11_8_48_MHZ_VAL },
244+ };
245+
246+ static int exynos_eusb2_ref_clk_init (struct snps_eusb2_hsphy * phy )
247+ {
248+ const struct snps_eusb2_ref_clk * config = NULL ;
249+ unsigned long ref_clk_freq = clk_get_rate (phy -> ref_clk );
250+
251+ for (int i = 0 ; i < ARRAY_SIZE (exynos_eusb2_ref_clk ); i ++ ) {
252+ if (exynos_eusb2_ref_clk [i ].freq == ref_clk_freq ) {
253+ config = & exynos_eusb2_ref_clk [i ];
254+ break ;
255+ }
256+ }
257+
258+ if (!config ) {
259+ dev_err (& phy -> phy -> dev , "unsupported ref_clk_freq:%lu\n" , ref_clk_freq );
260+ return - EINVAL ;
261+ }
262+
263+ snps_eusb2_hsphy_write_mask (phy -> base , EXYNOS_USB_PHY_HS_PHY_CTRL_COMMON ,
264+ FSEL_MASK ,
265+ FIELD_PREP (FSEL_MASK , config -> fsel_val ));
266+
267+ snps_eusb2_hsphy_write_mask (phy -> base , EXYNOS_USB_PHY_CFG_PLLCFG0 ,
268+ PHY_CFG_PLL_FB_DIV_19_8_MASK ,
269+ FIELD_PREP (PHY_CFG_PLL_FB_DIV_19_8_MASK ,
270+ config -> div_7_0_val ));
271+
272+ snps_eusb2_hsphy_write_mask (phy -> base , EXYNOS_USB_PHY_CFG_PLLCFG1 ,
273+ EXYNOS_PHY_CFG_PLL_FB_DIV_11_8_MASK ,
274+ config -> div_11_8_val );
275+ return 0 ;
276+ }
277+
202278static const struct snps_eusb2_ref_clk qcom_eusb2_ref_clk [] = {
203279 { 19200000 , FSEL_19_2_MHZ_VAL , DIV_7_0_19_2_MHZ_VAL , DIV_11_8_19_2_MHZ_VAL },
204280 { 38400000 , FSEL_38_4_MHZ_VAL , DIV_7_0_38_4_MHZ_VAL , DIV_11_8_38_4_MHZ_VAL },
@@ -239,6 +315,55 @@ static int qcom_eusb2_ref_clk_init(struct snps_eusb2_hsphy *phy)
239315 return 0 ;
240316}
241317
318+ static int exynos_snps_eusb2_hsphy_init (struct phy * p )
319+ {
320+ struct snps_eusb2_hsphy * phy = phy_get_drvdata (p );
321+ int ret ;
322+
323+ snps_eusb2_hsphy_write_mask (phy -> base , EXYNOS_USB_PHY_HS_PHY_CTRL_RST ,
324+ USB_PHY_RST_MASK | UTMI_PORT_RST_MASK ,
325+ USB_PHY_RST_MASK | UTMI_PORT_RST_MASK );
326+ fsleep (50 ); /* required after holding phy in reset */
327+
328+ snps_eusb2_hsphy_write_mask (phy -> base , EXYNOS_USB_PHY_HS_PHY_CTRL_COMMON ,
329+ RPTR_MODE , RPTR_MODE );
330+
331+ /* update ref_clk related registers */
332+ ret = exynos_eusb2_ref_clk_init (phy );
333+ if (ret )
334+ return ret ;
335+
336+ /* default parameter: tx fsls-vref */
337+ snps_eusb2_hsphy_write_mask (phy -> base , EXYNOS_PHY_CFG_TX ,
338+ EXYNOS_PHY_CFG_TX_FSLS_VREF_TUNE_MASK ,
339+ FIELD_PREP (EXYNOS_PHY_CFG_TX_FSLS_VREF_TUNE_MASK , 0x0 ));
340+
341+ snps_eusb2_hsphy_write_mask (phy -> base , EXYNOS_USB_PHY_UTMI_TESTSE ,
342+ TEST_IDDQ , 0 );
343+ fsleep (10 ); /* required after releasing test_iddq */
344+
345+ snps_eusb2_hsphy_write_mask (phy -> base , EXYNOS_USB_PHY_HS_PHY_CTRL_RST ,
346+ USB_PHY_RST_MASK , 0 );
347+
348+ snps_eusb2_hsphy_write_mask (phy -> base , EXYNOS_USB_PHY_HS_PHY_CTRL_COMMON ,
349+ PHY_ENABLE , PHY_ENABLE );
350+
351+ snps_eusb2_hsphy_write_mask (phy -> base , EXYNOS_USB_PHY_HS_PHY_CTRL_RST ,
352+ UTMI_PORT_RST_MASK , 0 );
353+
354+ return 0 ;
355+ }
356+
357+ static const char * const exynos_eusb2_hsphy_clock_names [] = {
358+ "ref" , "bus" , "ctrl" ,
359+ };
360+
361+ static const struct snps_eusb2_phy_drvdata exynos2200_snps_eusb2_phy = {
362+ .phy_init = exynos_snps_eusb2_hsphy_init ,
363+ .clk_names = exynos_eusb2_hsphy_clock_names ,
364+ .num_clks = ARRAY_SIZE (exynos_eusb2_hsphy_clock_names ),
365+ };
366+
242367static int qcom_snps_eusb2_hsphy_init (struct phy * p )
243368{
244369 struct snps_eusb2_hsphy * phy = phy_get_drvdata (p );
@@ -315,8 +440,14 @@ static int qcom_snps_eusb2_hsphy_init(struct phy *p)
315440 return 0 ;
316441}
317442
443+ static const char * const qcom_eusb2_hsphy_clock_names [] = {
444+ "ref" ,
445+ };
446+
318447static const struct snps_eusb2_phy_drvdata sm8550_snps_eusb2_phy = {
319448 .phy_init = qcom_snps_eusb2_hsphy_init ,
449+ .clk_names = qcom_eusb2_hsphy_clock_names ,
450+ .num_clks = ARRAY_SIZE (qcom_eusb2_hsphy_clock_names ),
320451};
321452
322453static int snps_eusb2_hsphy_init (struct phy * p )
@@ -334,7 +465,7 @@ static int snps_eusb2_hsphy_init(struct phy *p)
334465 goto disable_vreg ;
335466 }
336467
337- ret = clk_prepare_enable (phy -> ref_clk );
468+ ret = clk_bulk_prepare_enable (phy -> data -> num_clks , phy -> clks );
338469 if (ret ) {
339470 dev_err (& p -> dev , "failed to enable ref clock, %d\n" , ret );
340471 goto disable_vreg ;
@@ -361,7 +492,7 @@ static int snps_eusb2_hsphy_init(struct phy *p)
361492 return 0 ;
362493
363494disable_ref_clk :
364- clk_disable_unprepare (phy -> ref_clk );
495+ clk_bulk_disable_unprepare (phy -> data -> num_clks , phy -> clks );
365496
366497disable_vreg :
367498 regulator_bulk_disable (ARRAY_SIZE (phy -> vregs ), phy -> vregs );
@@ -415,8 +546,28 @@ static int snps_eusb2_hsphy_probe(struct platform_device *pdev)
415546 if (IS_ERR (phy -> phy_reset ))
416547 return PTR_ERR (phy -> phy_reset );
417548
418- phy -> ref_clk = devm_clk_get (dev , "ref" );
419- if (IS_ERR (phy -> ref_clk ))
549+ phy -> clks = devm_kcalloc (dev , phy -> data -> num_clks , sizeof (* phy -> clks ),
550+ GFP_KERNEL );
551+ if (!phy -> clks )
552+ return - ENOMEM ;
553+
554+ for (int i = 0 ; i < phy -> data -> num_clks ; ++ i )
555+ phy -> clks [i ].id = phy -> data -> clk_names [i ];
556+
557+ ret = devm_clk_bulk_get (dev , phy -> data -> num_clks , phy -> clks );
558+ if (ret )
559+ return dev_err_probe (dev , ret ,
560+ "failed to get phy clock(s)\n" );
561+
562+ phy -> ref_clk = NULL ;
563+ for (int i = 0 ; i < phy -> data -> num_clks ; ++ i ) {
564+ if (!strcmp (phy -> clks [i ].id , "ref" )) {
565+ phy -> ref_clk = phy -> clks [i ].clk ;
566+ break ;
567+ }
568+ }
569+
570+ if (IS_ERR_OR_NULL (phy -> ref_clk ))
420571 return dev_err_probe (dev , PTR_ERR (phy -> ref_clk ),
421572 "failed to get ref clk\n" );
422573
@@ -456,6 +607,9 @@ static const struct of_device_id snps_eusb2_hsphy_of_match_table[] = {
456607 {
457608 .compatible = "qcom,sm8550-snps-eusb2-phy" ,
458609 .data = & sm8550_snps_eusb2_phy ,
610+ }, {
611+ .compatible = "samsung,exynos2200-eusb2-phy" ,
612+ .data = & exynos2200_snps_eusb2_phy ,
459613 }, { },
460614};
461615MODULE_DEVICE_TABLE (of , snps_eusb2_hsphy_of_match_table );
0 commit comments