phy-rockchip-usb.c (14443B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Rockchip usb PHY driver 4 * 5 * Copyright (C) 2014 Yunzhi Li <lyz@rock-chips.com> 6 * Copyright (C) 2014 ROCKCHIP, Inc. 7 */ 8 9#include <linux/clk.h> 10#include <linux/clk-provider.h> 11#include <linux/io.h> 12#include <linux/kernel.h> 13#include <linux/module.h> 14#include <linux/mutex.h> 15#include <linux/of.h> 16#include <linux/of_address.h> 17#include <linux/of_platform.h> 18#include <linux/phy/phy.h> 19#include <linux/platform_device.h> 20#include <linux/regulator/consumer.h> 21#include <linux/reset.h> 22#include <linux/regmap.h> 23#include <linux/mfd/syscon.h> 24#include <linux/delay.h> 25 26static int enable_usb_uart; 27 28#define HIWORD_UPDATE(val, mask) \ 29 ((val) | (mask) << 16) 30 31#define UOC_CON0 0x00 32#define UOC_CON0_SIDDQ BIT(13) 33#define UOC_CON0_DISABLE BIT(4) 34#define UOC_CON0_COMMON_ON_N BIT(0) 35 36#define UOC_CON2 0x08 37#define UOC_CON2_SOFT_CON_SEL BIT(2) 38 39#define UOC_CON3 0x0c 40/* bits present on rk3188 and rk3288 phys */ 41#define UOC_CON3_UTMI_TERMSEL_FULLSPEED BIT(5) 42#define UOC_CON3_UTMI_XCVRSEELCT_FSTRANSC (1 << 3) 43#define UOC_CON3_UTMI_XCVRSEELCT_MASK (3 << 3) 44#define UOC_CON3_UTMI_OPMODE_NODRIVING (1 << 1) 45#define UOC_CON3_UTMI_OPMODE_MASK (3 << 1) 46#define UOC_CON3_UTMI_SUSPENDN BIT(0) 47 48struct rockchip_usb_phys { 49 int reg; 50 const char *pll_name; 51}; 52 53struct rockchip_usb_phy_base; 54struct rockchip_usb_phy_pdata { 55 struct rockchip_usb_phys *phys; 56 int (*init_usb_uart)(struct regmap *grf, 57 const struct rockchip_usb_phy_pdata *pdata); 58 int usb_uart_phy; 59}; 60 61struct rockchip_usb_phy_base { 62 struct device *dev; 63 struct regmap *reg_base; 64 const struct rockchip_usb_phy_pdata *pdata; 65}; 66 67struct rockchip_usb_phy { 68 struct rockchip_usb_phy_base *base; 69 struct device_node *np; 70 unsigned int reg_offset; 71 struct clk *clk; 72 struct clk *clk480m; 73 struct clk_hw clk480m_hw; 74 struct phy *phy; 75 bool uart_enabled; 76 struct reset_control *reset; 77 struct regulator *vbus; 78}; 79 80static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy, 81 bool siddq) 82{ 83 u32 val = HIWORD_UPDATE(siddq ? UOC_CON0_SIDDQ : 0, UOC_CON0_SIDDQ); 84 85 return regmap_write(phy->base->reg_base, phy->reg_offset, val); 86} 87 88static unsigned long rockchip_usb_phy480m_recalc_rate(struct clk_hw *hw, 89 unsigned long parent_rate) 90{ 91 return 480000000; 92} 93 94static void rockchip_usb_phy480m_disable(struct clk_hw *hw) 95{ 96 struct rockchip_usb_phy *phy = container_of(hw, 97 struct rockchip_usb_phy, 98 clk480m_hw); 99 100 if (phy->vbus) 101 regulator_disable(phy->vbus); 102 103 /* Power down usb phy analog blocks by set siddq 1 */ 104 rockchip_usb_phy_power(phy, 1); 105} 106 107static int rockchip_usb_phy480m_enable(struct clk_hw *hw) 108{ 109 struct rockchip_usb_phy *phy = container_of(hw, 110 struct rockchip_usb_phy, 111 clk480m_hw); 112 113 /* Power up usb phy analog blocks by set siddq 0 */ 114 return rockchip_usb_phy_power(phy, 0); 115} 116 117static int rockchip_usb_phy480m_is_enabled(struct clk_hw *hw) 118{ 119 struct rockchip_usb_phy *phy = container_of(hw, 120 struct rockchip_usb_phy, 121 clk480m_hw); 122 int ret; 123 u32 val; 124 125 ret = regmap_read(phy->base->reg_base, phy->reg_offset, &val); 126 if (ret < 0) 127 return ret; 128 129 return (val & UOC_CON0_SIDDQ) ? 0 : 1; 130} 131 132static const struct clk_ops rockchip_usb_phy480m_ops = { 133 .enable = rockchip_usb_phy480m_enable, 134 .disable = rockchip_usb_phy480m_disable, 135 .is_enabled = rockchip_usb_phy480m_is_enabled, 136 .recalc_rate = rockchip_usb_phy480m_recalc_rate, 137}; 138 139static int rockchip_usb_phy_power_off(struct phy *_phy) 140{ 141 struct rockchip_usb_phy *phy = phy_get_drvdata(_phy); 142 143 if (phy->uart_enabled) 144 return -EBUSY; 145 146 clk_disable_unprepare(phy->clk480m); 147 148 return 0; 149} 150 151static int rockchip_usb_phy_power_on(struct phy *_phy) 152{ 153 struct rockchip_usb_phy *phy = phy_get_drvdata(_phy); 154 155 if (phy->uart_enabled) 156 return -EBUSY; 157 158 if (phy->vbus) { 159 int ret; 160 161 ret = regulator_enable(phy->vbus); 162 if (ret) 163 return ret; 164 } 165 166 return clk_prepare_enable(phy->clk480m); 167} 168 169static int rockchip_usb_phy_reset(struct phy *_phy) 170{ 171 struct rockchip_usb_phy *phy = phy_get_drvdata(_phy); 172 173 if (phy->reset) { 174 reset_control_assert(phy->reset); 175 udelay(10); 176 reset_control_deassert(phy->reset); 177 } 178 179 return 0; 180} 181 182static const struct phy_ops ops = { 183 .power_on = rockchip_usb_phy_power_on, 184 .power_off = rockchip_usb_phy_power_off, 185 .reset = rockchip_usb_phy_reset, 186 .owner = THIS_MODULE, 187}; 188 189static void rockchip_usb_phy_action(void *data) 190{ 191 struct rockchip_usb_phy *rk_phy = data; 192 193 if (!rk_phy->uart_enabled) { 194 of_clk_del_provider(rk_phy->np); 195 clk_unregister(rk_phy->clk480m); 196 } 197 198 if (rk_phy->clk) 199 clk_put(rk_phy->clk); 200} 201 202static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base, 203 struct device_node *child) 204{ 205 struct rockchip_usb_phy *rk_phy; 206 unsigned int reg_offset; 207 const char *clk_name; 208 struct clk_init_data init; 209 int err, i; 210 211 rk_phy = devm_kzalloc(base->dev, sizeof(*rk_phy), GFP_KERNEL); 212 if (!rk_phy) 213 return -ENOMEM; 214 215 rk_phy->base = base; 216 rk_phy->np = child; 217 218 if (of_property_read_u32(child, "reg", ®_offset)) { 219 dev_err(base->dev, "missing reg property in node %pOFn\n", 220 child); 221 return -EINVAL; 222 } 223 224 rk_phy->reset = of_reset_control_get(child, "phy-reset"); 225 if (IS_ERR(rk_phy->reset)) 226 rk_phy->reset = NULL; 227 228 rk_phy->reg_offset = reg_offset; 229 230 rk_phy->clk = of_clk_get_by_name(child, "phyclk"); 231 if (IS_ERR(rk_phy->clk)) 232 rk_phy->clk = NULL; 233 234 i = 0; 235 init.name = NULL; 236 while (base->pdata->phys[i].reg) { 237 if (base->pdata->phys[i].reg == reg_offset) { 238 init.name = base->pdata->phys[i].pll_name; 239 break; 240 } 241 i++; 242 } 243 244 if (!init.name) { 245 dev_err(base->dev, "phy data not found\n"); 246 return -EINVAL; 247 } 248 249 if (enable_usb_uart && base->pdata->usb_uart_phy == i) { 250 dev_dbg(base->dev, "phy%d used as uart output\n", i); 251 rk_phy->uart_enabled = true; 252 } else { 253 if (rk_phy->clk) { 254 clk_name = __clk_get_name(rk_phy->clk); 255 init.flags = 0; 256 init.parent_names = &clk_name; 257 init.num_parents = 1; 258 } else { 259 init.flags = 0; 260 init.parent_names = NULL; 261 init.num_parents = 0; 262 } 263 264 init.ops = &rockchip_usb_phy480m_ops; 265 rk_phy->clk480m_hw.init = &init; 266 267 rk_phy->clk480m = clk_register(base->dev, &rk_phy->clk480m_hw); 268 if (IS_ERR(rk_phy->clk480m)) { 269 err = PTR_ERR(rk_phy->clk480m); 270 goto err_clk; 271 } 272 273 err = of_clk_add_provider(child, of_clk_src_simple_get, 274 rk_phy->clk480m); 275 if (err < 0) 276 goto err_clk_prov; 277 } 278 279 err = devm_add_action_or_reset(base->dev, rockchip_usb_phy_action, 280 rk_phy); 281 if (err) 282 return err; 283 284 rk_phy->phy = devm_phy_create(base->dev, child, &ops); 285 if (IS_ERR(rk_phy->phy)) { 286 dev_err(base->dev, "failed to create PHY\n"); 287 return PTR_ERR(rk_phy->phy); 288 } 289 phy_set_drvdata(rk_phy->phy, rk_phy); 290 291 rk_phy->vbus = devm_regulator_get_optional(&rk_phy->phy->dev, "vbus"); 292 if (IS_ERR(rk_phy->vbus)) { 293 if (PTR_ERR(rk_phy->vbus) == -EPROBE_DEFER) 294 return PTR_ERR(rk_phy->vbus); 295 rk_phy->vbus = NULL; 296 } 297 298 /* 299 * When acting as uart-pipe, just keep clock on otherwise 300 * only power up usb phy when it use, so disable it when init 301 */ 302 if (rk_phy->uart_enabled) 303 return clk_prepare_enable(rk_phy->clk); 304 else 305 return rockchip_usb_phy_power(rk_phy, 1); 306 307err_clk_prov: 308 if (!rk_phy->uart_enabled) 309 clk_unregister(rk_phy->clk480m); 310err_clk: 311 if (rk_phy->clk) 312 clk_put(rk_phy->clk); 313 return err; 314} 315 316static const struct rockchip_usb_phy_pdata rk3066a_pdata = { 317 .phys = (struct rockchip_usb_phys[]){ 318 { .reg = 0x17c, .pll_name = "sclk_otgphy0_480m" }, 319 { .reg = 0x188, .pll_name = "sclk_otgphy1_480m" }, 320 { /* sentinel */ } 321 }, 322}; 323 324static int __init rockchip_init_usb_uart_common(struct regmap *grf, 325 const struct rockchip_usb_phy_pdata *pdata) 326{ 327 int regoffs = pdata->phys[pdata->usb_uart_phy].reg; 328 int ret; 329 u32 val; 330 331 /* 332 * COMMON_ON and DISABLE settings are described in the TRM, 333 * but were not present in the original code. 334 * Also disable the analog phy components to save power. 335 */ 336 val = HIWORD_UPDATE(UOC_CON0_COMMON_ON_N 337 | UOC_CON0_DISABLE 338 | UOC_CON0_SIDDQ, 339 UOC_CON0_COMMON_ON_N 340 | UOC_CON0_DISABLE 341 | UOC_CON0_SIDDQ); 342 ret = regmap_write(grf, regoffs + UOC_CON0, val); 343 if (ret) 344 return ret; 345 346 val = HIWORD_UPDATE(UOC_CON2_SOFT_CON_SEL, 347 UOC_CON2_SOFT_CON_SEL); 348 ret = regmap_write(grf, regoffs + UOC_CON2, val); 349 if (ret) 350 return ret; 351 352 val = HIWORD_UPDATE(UOC_CON3_UTMI_OPMODE_NODRIVING 353 | UOC_CON3_UTMI_XCVRSEELCT_FSTRANSC 354 | UOC_CON3_UTMI_TERMSEL_FULLSPEED, 355 UOC_CON3_UTMI_SUSPENDN 356 | UOC_CON3_UTMI_OPMODE_MASK 357 | UOC_CON3_UTMI_XCVRSEELCT_MASK 358 | UOC_CON3_UTMI_TERMSEL_FULLSPEED); 359 ret = regmap_write(grf, UOC_CON3, val); 360 if (ret) 361 return ret; 362 363 return 0; 364} 365 366#define RK3188_UOC0_CON0 0x10c 367#define RK3188_UOC0_CON0_BYPASSSEL BIT(9) 368#define RK3188_UOC0_CON0_BYPASSDMEN BIT(8) 369 370/* 371 * Enable the bypass of uart2 data through the otg usb phy. 372 * See description of rk3288-variant for details. 373 */ 374static int __init rk3188_init_usb_uart(struct regmap *grf, 375 const struct rockchip_usb_phy_pdata *pdata) 376{ 377 u32 val; 378 int ret; 379 380 ret = rockchip_init_usb_uart_common(grf, pdata); 381 if (ret) 382 return ret; 383 384 val = HIWORD_UPDATE(RK3188_UOC0_CON0_BYPASSSEL 385 | RK3188_UOC0_CON0_BYPASSDMEN, 386 RK3188_UOC0_CON0_BYPASSSEL 387 | RK3188_UOC0_CON0_BYPASSDMEN); 388 ret = regmap_write(grf, RK3188_UOC0_CON0, val); 389 if (ret) 390 return ret; 391 392 return 0; 393} 394 395static const struct rockchip_usb_phy_pdata rk3188_pdata = { 396 .phys = (struct rockchip_usb_phys[]){ 397 { .reg = 0x10c, .pll_name = "sclk_otgphy0_480m" }, 398 { .reg = 0x11c, .pll_name = "sclk_otgphy1_480m" }, 399 { /* sentinel */ } 400 }, 401 .init_usb_uart = rk3188_init_usb_uart, 402 .usb_uart_phy = 0, 403}; 404 405#define RK3288_UOC0_CON3 0x32c 406#define RK3288_UOC0_CON3_BYPASSDMEN BIT(6) 407#define RK3288_UOC0_CON3_BYPASSSEL BIT(7) 408 409/* 410 * Enable the bypass of uart2 data through the otg usb phy. 411 * Original description in the TRM. 412 * 1. Disable the OTG block by setting OTGDISABLE0 to 1’b1. 413 * 2. Disable the pull-up resistance on the D+ line by setting 414 * OPMODE0[1:0] to 2’b01. 415 * 3. To ensure that the XO, Bias, and PLL blocks are powered down in Suspend 416 * mode, set COMMONONN to 1’b1. 417 * 4. Place the USB PHY in Suspend mode by setting SUSPENDM0 to 1’b0. 418 * 5. Set BYPASSSEL0 to 1’b1. 419 * 6. To transmit data, controls BYPASSDMEN0, and BYPASSDMDATA0. 420 * To receive data, monitor FSVPLUS0. 421 * 422 * The actual code in the vendor kernel does some things differently. 423 */ 424static int __init rk3288_init_usb_uart(struct regmap *grf, 425 const struct rockchip_usb_phy_pdata *pdata) 426{ 427 u32 val; 428 int ret; 429 430 ret = rockchip_init_usb_uart_common(grf, pdata); 431 if (ret) 432 return ret; 433 434 val = HIWORD_UPDATE(RK3288_UOC0_CON3_BYPASSSEL 435 | RK3288_UOC0_CON3_BYPASSDMEN, 436 RK3288_UOC0_CON3_BYPASSSEL 437 | RK3288_UOC0_CON3_BYPASSDMEN); 438 ret = regmap_write(grf, RK3288_UOC0_CON3, val); 439 if (ret) 440 return ret; 441 442 return 0; 443} 444 445static const struct rockchip_usb_phy_pdata rk3288_pdata = { 446 .phys = (struct rockchip_usb_phys[]){ 447 { .reg = 0x320, .pll_name = "sclk_otgphy0_480m" }, 448 { .reg = 0x334, .pll_name = "sclk_otgphy1_480m" }, 449 { .reg = 0x348, .pll_name = "sclk_otgphy2_480m" }, 450 { /* sentinel */ } 451 }, 452 .init_usb_uart = rk3288_init_usb_uart, 453 .usb_uart_phy = 0, 454}; 455 456static int rockchip_usb_phy_probe(struct platform_device *pdev) 457{ 458 struct device *dev = &pdev->dev; 459 struct rockchip_usb_phy_base *phy_base; 460 struct phy_provider *phy_provider; 461 const struct of_device_id *match; 462 struct device_node *child; 463 int err; 464 465 phy_base = devm_kzalloc(dev, sizeof(*phy_base), GFP_KERNEL); 466 if (!phy_base) 467 return -ENOMEM; 468 469 match = of_match_device(dev->driver->of_match_table, dev); 470 if (!match || !match->data) { 471 dev_err(dev, "missing phy data\n"); 472 return -EINVAL; 473 } 474 475 phy_base->pdata = match->data; 476 477 phy_base->dev = dev; 478 phy_base->reg_base = ERR_PTR(-ENODEV); 479 if (dev->parent && dev->parent->of_node) 480 phy_base->reg_base = syscon_node_to_regmap( 481 dev->parent->of_node); 482 if (IS_ERR(phy_base->reg_base)) 483 phy_base->reg_base = syscon_regmap_lookup_by_phandle( 484 dev->of_node, "rockchip,grf"); 485 if (IS_ERR(phy_base->reg_base)) { 486 dev_err(&pdev->dev, "Missing rockchip,grf property\n"); 487 return PTR_ERR(phy_base->reg_base); 488 } 489 490 for_each_available_child_of_node(dev->of_node, child) { 491 err = rockchip_usb_phy_init(phy_base, child); 492 if (err) { 493 of_node_put(child); 494 return err; 495 } 496 } 497 498 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 499 return PTR_ERR_OR_ZERO(phy_provider); 500} 501 502static const struct of_device_id rockchip_usb_phy_dt_ids[] = { 503 { .compatible = "rockchip,rk3066a-usb-phy", .data = &rk3066a_pdata }, 504 { .compatible = "rockchip,rk3188-usb-phy", .data = &rk3188_pdata }, 505 { .compatible = "rockchip,rk3288-usb-phy", .data = &rk3288_pdata }, 506 {} 507}; 508 509MODULE_DEVICE_TABLE(of, rockchip_usb_phy_dt_ids); 510 511static struct platform_driver rockchip_usb_driver = { 512 .probe = rockchip_usb_phy_probe, 513 .driver = { 514 .name = "rockchip-usb-phy", 515 .of_match_table = rockchip_usb_phy_dt_ids, 516 }, 517}; 518 519module_platform_driver(rockchip_usb_driver); 520 521#ifndef MODULE 522static int __init rockchip_init_usb_uart(void) 523{ 524 const struct of_device_id *match; 525 const struct rockchip_usb_phy_pdata *data; 526 struct device_node *np; 527 struct regmap *grf; 528 int ret; 529 530 if (!enable_usb_uart) 531 return 0; 532 533 np = of_find_matching_node_and_match(NULL, rockchip_usb_phy_dt_ids, 534 &match); 535 if (!np) { 536 pr_err("%s: failed to find usbphy node\n", __func__); 537 return -ENOTSUPP; 538 } 539 540 pr_debug("%s: using settings for %s\n", __func__, match->compatible); 541 data = match->data; 542 543 if (!data->init_usb_uart) { 544 pr_err("%s: usb-uart not available on %s\n", 545 __func__, match->compatible); 546 return -ENOTSUPP; 547 } 548 549 grf = ERR_PTR(-ENODEV); 550 if (np->parent) 551 grf = syscon_node_to_regmap(np->parent); 552 if (IS_ERR(grf)) 553 grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); 554 if (IS_ERR(grf)) { 555 pr_err("%s: Missing rockchip,grf property, %lu\n", 556 __func__, PTR_ERR(grf)); 557 return PTR_ERR(grf); 558 } 559 560 ret = data->init_usb_uart(grf, data); 561 if (ret) { 562 pr_err("%s: could not init usb_uart, %d\n", __func__, ret); 563 enable_usb_uart = 0; 564 return ret; 565 } 566 567 return 0; 568} 569early_initcall(rockchip_init_usb_uart); 570 571static int __init rockchip_usb_uart(char *buf) 572{ 573 enable_usb_uart = true; 574 return 0; 575} 576early_param("rockchip.usb_uart", rockchip_usb_uart); 577#endif 578 579MODULE_AUTHOR("Yunzhi Li <lyz@rock-chips.com>"); 580MODULE_DESCRIPTION("Rockchip USB 2.0 PHY driver"); 581MODULE_LICENSE("GPL v2");