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