Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

phy: phy-snps-eusb2: add support for exynos2200

The Exynos2200 SoC reuses the Synopsis eUSB2 PHY IP, alongside an
external repeater, for USB 2.0. Add support for it to the existing
driver, while keeping in mind that it requires enabled more than the
reference clock.

Signed-off-by: Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
Acked-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20250504144527.1723980-10-ivo.ivanov.ivanov1@gmail.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Ivaylo Ivanov and committed by
Vinod Koul
c4098f3e e36a5d1e

+159 -5
+1 -1
drivers/phy/Kconfig
··· 45 45 46 46 config PHY_SNPS_EUSB2 47 47 tristate "SNPS eUSB2 PHY Driver" 48 - depends on OF && (ARCH_QCOM || COMPILE_TEST) 48 + depends on OF && (ARCH_EXYNOS || ARCH_QCOM || COMPILE_TEST) 49 49 select GENERIC_PHY 50 50 help 51 51 Enable support for the USB high-speed SNPS eUSB2 phy on select
+158 -4
drivers/phy/phy-snps-eusb2.c
··· 13 13 #include <linux/regulator/consumer.h> 14 14 #include <linux/reset.h> 15 15 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 + 16 49 #define QCOM_USB_PHY_UTMI_CTRL0 (0x3c) 17 50 #define SLEEPM BIT(0) 18 51 #define OPMODE_MASK GENMASK(4, 3) ··· 156 123 157 124 struct snps_eusb2_phy_drvdata { 158 125 int (*phy_init)(struct phy *p); 126 + const char * const *clk_names; 127 + int num_clks; 159 128 }; 160 129 161 130 struct snps_eusb2_hsphy { ··· 165 130 void __iomem *base; 166 131 167 132 struct clk *ref_clk; 133 + struct clk_bulk_data *clks; 168 134 struct reset_control *phy_reset; 169 135 170 136 struct regulator_bulk_data vregs[EUSB2_NUM_VREGS]; ··· 235 199 u32 div_11_8_val; 236 200 }; 237 201 202 + static const struct snps_eusb2_ref_clk exynos_eusb2_ref_clk[] = { 203 + { 19200000, FSEL_19_2_MHZ_VAL, DIV_19_8_19_2_MHZ_VAL, EXYNOS_DIV_11_8_19_2_MHZ_VAL }, 204 + { 20000000, FSEL_20_MHZ_VAL, DIV_19_8_20_MHZ_VAL, EXYNOS_DIV_11_8_20_MHZ_VAL }, 205 + { 24000000, FSEL_24_MHZ_VAL, DIV_19_8_24_MHZ_VAL, EXYNOS_DIV_11_8_24_MHZ_VAL }, 206 + { 26000000, FSEL_26_MHZ_VAL, DIV_19_8_26_MHZ_VAL, EXYNOS_DIV_11_8_26_MHZ_VAL }, 207 + { 48000000, FSEL_48_MHZ_VAL, DIV_19_8_48_MHZ_VAL, EXYNOS_DIV_11_8_48_MHZ_VAL }, 208 + }; 209 + 210 + static int exynos_eusb2_ref_clk_init(struct snps_eusb2_hsphy *phy) 211 + { 212 + const struct snps_eusb2_ref_clk *config = NULL; 213 + unsigned long ref_clk_freq = clk_get_rate(phy->ref_clk); 214 + 215 + for (int i = 0; i < ARRAY_SIZE(exynos_eusb2_ref_clk); i++) { 216 + if (exynos_eusb2_ref_clk[i].freq == ref_clk_freq) { 217 + config = &exynos_eusb2_ref_clk[i]; 218 + break; 219 + } 220 + } 221 + 222 + if (!config) { 223 + dev_err(&phy->phy->dev, "unsupported ref_clk_freq:%lu\n", ref_clk_freq); 224 + return -EINVAL; 225 + } 226 + 227 + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_COMMON, 228 + FSEL_MASK, 229 + FIELD_PREP(FSEL_MASK, config->fsel_val)); 230 + 231 + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_CFG_PLLCFG0, 232 + PHY_CFG_PLL_FB_DIV_19_8_MASK, 233 + FIELD_PREP(PHY_CFG_PLL_FB_DIV_19_8_MASK, 234 + config->div_7_0_val)); 235 + 236 + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_CFG_PLLCFG1, 237 + EXYNOS_PHY_CFG_PLL_FB_DIV_11_8_MASK, 238 + config->div_11_8_val); 239 + return 0; 240 + } 241 + 238 242 static const struct snps_eusb2_ref_clk qcom_eusb2_ref_clk[] = { 239 243 { 19200000, FSEL_19_2_MHZ_VAL, DIV_7_0_19_2_MHZ_VAL, DIV_11_8_19_2_MHZ_VAL }, 240 244 { 38400000, FSEL_38_4_MHZ_VAL, DIV_7_0_38_4_MHZ_VAL, DIV_11_8_38_4_MHZ_VAL }, ··· 314 238 315 239 return 0; 316 240 } 241 + 242 + static int exynos_snps_eusb2_hsphy_init(struct phy *p) 243 + { 244 + struct snps_eusb2_hsphy *phy = phy_get_drvdata(p); 245 + int ret; 246 + 247 + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_RST, 248 + USB_PHY_RST_MASK | UTMI_PORT_RST_MASK, 249 + USB_PHY_RST_MASK | UTMI_PORT_RST_MASK); 250 + fsleep(50); /* required after holding phy in reset */ 251 + 252 + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_COMMON, 253 + RPTR_MODE, RPTR_MODE); 254 + 255 + /* update ref_clk related registers */ 256 + ret = exynos_eusb2_ref_clk_init(phy); 257 + if (ret) 258 + return ret; 259 + 260 + /* default parameter: tx fsls-vref */ 261 + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_PHY_CFG_TX, 262 + EXYNOS_PHY_CFG_TX_FSLS_VREF_TUNE_MASK, 263 + FIELD_PREP(EXYNOS_PHY_CFG_TX_FSLS_VREF_TUNE_MASK, 0x0)); 264 + 265 + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_UTMI_TESTSE, 266 + TEST_IDDQ, 0); 267 + fsleep(10); /* required after releasing test_iddq */ 268 + 269 + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_RST, 270 + USB_PHY_RST_MASK, 0); 271 + 272 + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_COMMON, 273 + PHY_ENABLE, PHY_ENABLE); 274 + 275 + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_RST, 276 + UTMI_PORT_RST_MASK, 0); 277 + 278 + return 0; 279 + } 280 + 281 + static const char * const exynos_eusb2_hsphy_clock_names[] = { 282 + "ref", "bus", "ctrl", 283 + }; 284 + 285 + static const struct snps_eusb2_phy_drvdata exynos2200_snps_eusb2_phy = { 286 + .phy_init = exynos_snps_eusb2_hsphy_init, 287 + .clk_names = exynos_eusb2_hsphy_clock_names, 288 + .num_clks = ARRAY_SIZE(exynos_eusb2_hsphy_clock_names), 289 + }; 317 290 318 291 static int qcom_snps_eusb2_hsphy_init(struct phy *p) 319 292 { ··· 440 315 return 0; 441 316 } 442 317 318 + static const char * const qcom_eusb2_hsphy_clock_names[] = { 319 + "ref", 320 + }; 321 + 443 322 static const struct snps_eusb2_phy_drvdata sm8550_snps_eusb2_phy = { 444 323 .phy_init = qcom_snps_eusb2_hsphy_init, 324 + .clk_names = qcom_eusb2_hsphy_clock_names, 325 + .num_clks = ARRAY_SIZE(qcom_eusb2_hsphy_clock_names), 445 326 }; 446 327 447 328 static int snps_eusb2_hsphy_init(struct phy *p) ··· 465 334 goto disable_vreg; 466 335 } 467 336 468 - ret = clk_prepare_enable(phy->ref_clk); 337 + ret = clk_bulk_prepare_enable(phy->data->num_clks, phy->clks); 469 338 if (ret) { 470 339 dev_err(&p->dev, "failed to enable ref clock, %d\n", ret); 471 340 goto disable_vreg; ··· 492 361 return 0; 493 362 494 363 disable_ref_clk: 495 - clk_disable_unprepare(phy->ref_clk); 364 + clk_bulk_disable_unprepare(phy->data->num_clks, phy->clks); 496 365 497 366 disable_vreg: 498 367 regulator_bulk_disable(ARRAY_SIZE(phy->vregs), phy->vregs); ··· 546 415 if (IS_ERR(phy->phy_reset)) 547 416 return PTR_ERR(phy->phy_reset); 548 417 549 - phy->ref_clk = devm_clk_get(dev, "ref"); 550 - if (IS_ERR(phy->ref_clk)) 418 + phy->clks = devm_kcalloc(dev, phy->data->num_clks, sizeof(*phy->clks), 419 + GFP_KERNEL); 420 + if (!phy->clks) 421 + return -ENOMEM; 422 + 423 + for (int i = 0; i < phy->data->num_clks; ++i) 424 + phy->clks[i].id = phy->data->clk_names[i]; 425 + 426 + ret = devm_clk_bulk_get(dev, phy->data->num_clks, phy->clks); 427 + if (ret) 428 + return dev_err_probe(dev, ret, 429 + "failed to get phy clock(s)\n"); 430 + 431 + phy->ref_clk = NULL; 432 + for (int i = 0; i < phy->data->num_clks; ++i) { 433 + if (!strcmp(phy->clks[i].id, "ref")) { 434 + phy->ref_clk = phy->clks[i].clk; 435 + break; 436 + } 437 + } 438 + 439 + if (IS_ERR_OR_NULL(phy->ref_clk)) 551 440 return dev_err_probe(dev, PTR_ERR(phy->ref_clk), 552 441 "failed to get ref clk\n"); 553 442 ··· 607 456 { 608 457 .compatible = "qcom,sm8550-snps-eusb2-phy", 609 458 .data = &sm8550_snps_eusb2_phy, 459 + }, { 460 + .compatible = "samsung,exynos2200-eusb2-phy", 461 + .data = &exynos2200_snps_eusb2_phy, 610 462 }, { }, 611 463 }; 612 464 MODULE_DEVICE_TABLE(of, snps_eusb2_hsphy_of_match_table);