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