linux/drivers/phy/samsung/phy-exynos5-usbdrd.c
<<
>>
Prefs
   1/*
   2 * Samsung EXYNOS5 SoC series USB DRD PHY driver
   3 *
   4 * Phy provider for USB 3.0 DRD controller on Exynos5 SoC series
   5 *
   6 * Copyright (C) 2014 Samsung Electronics Co., Ltd.
   7 * Author: Vivek Gautam <gautam.vivek@samsung.com>
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2 as
  11 * published by the Free Software Foundation.
  12 */
  13
  14#include <linux/clk.h>
  15#include <linux/delay.h>
  16#include <linux/io.h>
  17#include <linux/kernel.h>
  18#include <linux/module.h>
  19#include <linux/of.h>
  20#include <linux/of_address.h>
  21#include <linux/of_device.h>
  22#include <linux/phy/phy.h>
  23#include <linux/platform_device.h>
  24#include <linux/mutex.h>
  25#include <linux/mfd/syscon.h>
  26#include <linux/regmap.h>
  27#include <linux/regulator/consumer.h>
  28#include <linux/soc/samsung/exynos-regs-pmu.h>
  29
  30/* Exynos USB PHY registers */
  31#define EXYNOS5_FSEL_9MHZ6              0x0
  32#define EXYNOS5_FSEL_10MHZ              0x1
  33#define EXYNOS5_FSEL_12MHZ              0x2
  34#define EXYNOS5_FSEL_19MHZ2             0x3
  35#define EXYNOS5_FSEL_20MHZ              0x4
  36#define EXYNOS5_FSEL_24MHZ              0x5
  37#define EXYNOS5_FSEL_50MHZ              0x7
  38
  39/* EXYNOS5: USB 3.0 DRD PHY registers */
  40#define EXYNOS5_DRD_LINKSYSTEM                  0x04
  41
  42#define LINKSYSTEM_FLADJ_MASK                   (0x3f << 1)
  43#define LINKSYSTEM_FLADJ(_x)                    ((_x) << 1)
  44#define LINKSYSTEM_XHCI_VERSION_CONTROL         BIT(27)
  45
  46#define EXYNOS5_DRD_PHYUTMI                     0x08
  47
  48#define PHYUTMI_OTGDISABLE                      BIT(6)
  49#define PHYUTMI_FORCESUSPEND                    BIT(1)
  50#define PHYUTMI_FORCESLEEP                      BIT(0)
  51
  52#define EXYNOS5_DRD_PHYPIPE                     0x0c
  53
  54#define EXYNOS5_DRD_PHYCLKRST                   0x10
  55
  56#define PHYCLKRST_EN_UTMISUSPEND                BIT(31)
  57
  58#define PHYCLKRST_SSC_REFCLKSEL_MASK            (0xff << 23)
  59#define PHYCLKRST_SSC_REFCLKSEL(_x)             ((_x) << 23)
  60
  61#define PHYCLKRST_SSC_RANGE_MASK                (0x03 << 21)
  62#define PHYCLKRST_SSC_RANGE(_x)                 ((_x) << 21)
  63
  64#define PHYCLKRST_SSC_EN                        BIT(20)
  65#define PHYCLKRST_REF_SSP_EN                    BIT(19)
  66#define PHYCLKRST_REF_CLKDIV2                   BIT(18)
  67
  68#define PHYCLKRST_MPLL_MULTIPLIER_MASK          (0x7f << 11)
  69#define PHYCLKRST_MPLL_MULTIPLIER_100MHZ_REF    (0x19 << 11)
  70#define PHYCLKRST_MPLL_MULTIPLIER_50M_REF       (0x32 << 11)
  71#define PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF     (0x68 << 11)
  72#define PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF     (0x7d << 11)
  73#define PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF  (0x02 << 11)
  74
  75#define PHYCLKRST_FSEL_UTMI_MASK                (0x7 << 5)
  76#define PHYCLKRST_FSEL_PIPE_MASK                (0x7 << 8)
  77#define PHYCLKRST_FSEL(_x)                      ((_x) << 5)
  78#define PHYCLKRST_FSEL_PAD_100MHZ               (0x27 << 5)
  79#define PHYCLKRST_FSEL_PAD_24MHZ                (0x2a << 5)
  80#define PHYCLKRST_FSEL_PAD_20MHZ                (0x31 << 5)
  81#define PHYCLKRST_FSEL_PAD_19_2MHZ              (0x38 << 5)
  82
  83#define PHYCLKRST_RETENABLEN                    BIT(4)
  84
  85#define PHYCLKRST_REFCLKSEL_MASK                (0x03 << 2)
  86#define PHYCLKRST_REFCLKSEL_PAD_REFCLK          (0x2 << 2)
  87#define PHYCLKRST_REFCLKSEL_EXT_REFCLK          (0x3 << 2)
  88
  89#define PHYCLKRST_PORTRESET                     BIT(1)
  90#define PHYCLKRST_COMMONONN                     BIT(0)
  91
  92#define EXYNOS5_DRD_PHYREG0                     0x14
  93#define EXYNOS5_DRD_PHYREG1                     0x18
  94
  95#define EXYNOS5_DRD_PHYPARAM0                   0x1c
  96
  97#define PHYPARAM0_REF_USE_PAD                   BIT(31)
  98#define PHYPARAM0_REF_LOSLEVEL_MASK             (0x1f << 26)
  99#define PHYPARAM0_REF_LOSLEVEL                  (0x9 << 26)
 100
 101#define EXYNOS5_DRD_PHYPARAM1                   0x20
 102
 103#define PHYPARAM1_PCS_TXDEEMPH_MASK             (0x1f << 0)
 104#define PHYPARAM1_PCS_TXDEEMPH                  (0x1c)
 105
 106#define EXYNOS5_DRD_PHYTERM                     0x24
 107
 108#define EXYNOS5_DRD_PHYTEST                     0x28
 109
 110#define PHYTEST_POWERDOWN_SSP                   BIT(3)
 111#define PHYTEST_POWERDOWN_HSP                   BIT(2)
 112
 113#define EXYNOS5_DRD_PHYADP                      0x2c
 114
 115#define EXYNOS5_DRD_PHYUTMICLKSEL               0x30
 116
 117#define PHYUTMICLKSEL_UTMI_CLKSEL               BIT(2)
 118
 119#define EXYNOS5_DRD_PHYRESUME                   0x34
 120#define EXYNOS5_DRD_LINKPORT                    0x44
 121
 122#define KHZ     1000
 123#define MHZ     (KHZ * KHZ)
 124
 125enum exynos5_usbdrd_phy_id {
 126        EXYNOS5_DRDPHY_UTMI,
 127        EXYNOS5_DRDPHY_PIPE3,
 128        EXYNOS5_DRDPHYS_NUM,
 129};
 130
 131struct phy_usb_instance;
 132struct exynos5_usbdrd_phy;
 133
 134struct exynos5_usbdrd_phy_config {
 135        u32 id;
 136        void (*phy_isol)(struct phy_usb_instance *inst, u32 on);
 137        void (*phy_init)(struct exynos5_usbdrd_phy *phy_drd);
 138        unsigned int (*set_refclk)(struct phy_usb_instance *inst);
 139};
 140
 141struct exynos5_usbdrd_phy_drvdata {
 142        const struct exynos5_usbdrd_phy_config *phy_cfg;
 143        u32 pmu_offset_usbdrd0_phy;
 144        u32 pmu_offset_usbdrd1_phy;
 145        bool has_common_clk_gate;
 146};
 147
 148/**
 149 * struct exynos5_usbdrd_phy - driver data for USB 3.0 PHY
 150 * @dev: pointer to device instance of this platform device
 151 * @reg_phy: usb phy controller register memory base
 152 * @clk: phy clock for register access
 153 * @pipeclk: clock for pipe3 phy
 154 * @utmiclk: clock for utmi+ phy
 155 * @itpclk: clock for ITP generation
 156 * @drv_data: pointer to SoC level driver data structure
 157 * @phys[]: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY
 158 *          instances each with its 'phy' and 'phy_cfg'.
 159 * @extrefclk: frequency select settings when using 'separate
 160 *             reference clocks' for SS and HS operations
 161 * @ref_clk: reference clock to PHY block from which PHY's
 162 *           operational clocks are derived
 163 * vbus: VBUS regulator for phy
 164 * vbus_boost: Boost regulator for VBUS present on few Exynos boards
 165 */
 166struct exynos5_usbdrd_phy {
 167        struct device *dev;
 168        void __iomem *reg_phy;
 169        struct clk *clk;
 170        struct clk *pipeclk;
 171        struct clk *utmiclk;
 172        struct clk *itpclk;
 173        const struct exynos5_usbdrd_phy_drvdata *drv_data;
 174        struct phy_usb_instance {
 175                struct phy *phy;
 176                u32 index;
 177                struct regmap *reg_pmu;
 178                u32 pmu_offset;
 179                const struct exynos5_usbdrd_phy_config *phy_cfg;
 180        } phys[EXYNOS5_DRDPHYS_NUM];
 181        u32 extrefclk;
 182        struct clk *ref_clk;
 183        struct regulator *vbus;
 184        struct regulator *vbus_boost;
 185};
 186
 187static inline
 188struct exynos5_usbdrd_phy *to_usbdrd_phy(struct phy_usb_instance *inst)
 189{
 190        return container_of((inst), struct exynos5_usbdrd_phy,
 191                            phys[(inst)->index]);
 192}
 193
 194/*
 195 * exynos5_rate_to_clk() converts the supplied clock rate to the value that
 196 * can be written to the phy register.
 197 */
 198static unsigned int exynos5_rate_to_clk(unsigned long rate, u32 *reg)
 199{
 200        /* EXYNOS5_FSEL_MASK */
 201
 202        switch (rate) {
 203        case 9600 * KHZ:
 204                *reg = EXYNOS5_FSEL_9MHZ6;
 205                break;
 206        case 10 * MHZ:
 207                *reg = EXYNOS5_FSEL_10MHZ;
 208                break;
 209        case 12 * MHZ:
 210                *reg = EXYNOS5_FSEL_12MHZ;
 211                break;
 212        case 19200 * KHZ:
 213                *reg = EXYNOS5_FSEL_19MHZ2;
 214                break;
 215        case 20 * MHZ:
 216                *reg = EXYNOS5_FSEL_20MHZ;
 217                break;
 218        case 24 * MHZ:
 219                *reg = EXYNOS5_FSEL_24MHZ;
 220                break;
 221        case 50 * MHZ:
 222                *reg = EXYNOS5_FSEL_50MHZ;
 223                break;
 224        default:
 225                return -EINVAL;
 226        }
 227
 228        return 0;
 229}
 230
 231static void exynos5_usbdrd_phy_isol(struct phy_usb_instance *inst,
 232                                                unsigned int on)
 233{
 234        unsigned int val;
 235
 236        if (!inst->reg_pmu)
 237                return;
 238
 239        val = on ? 0 : EXYNOS4_PHY_ENABLE;
 240
 241        regmap_update_bits(inst->reg_pmu, inst->pmu_offset,
 242                           EXYNOS4_PHY_ENABLE, val);
 243}
 244
 245/*
 246 * Sets the pipe3 phy's clk as EXTREFCLK (XXTI) which is internal clock
 247 * from clock core. Further sets multiplier values and spread spectrum
 248 * clock settings for SuperSpeed operations.
 249 */
 250static unsigned int
 251exynos5_usbdrd_pipe3_set_refclk(struct phy_usb_instance *inst)
 252{
 253        u32 reg;
 254        struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
 255
 256        /* restore any previous reference clock settings */
 257        reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);
 258
 259        /* Use EXTREFCLK as ref clock */
 260        reg &= ~PHYCLKRST_REFCLKSEL_MASK;
 261        reg |=  PHYCLKRST_REFCLKSEL_EXT_REFCLK;
 262
 263        /* FSEL settings corresponding to reference clock */
 264        reg &= ~PHYCLKRST_FSEL_PIPE_MASK |
 265                PHYCLKRST_MPLL_MULTIPLIER_MASK |
 266                PHYCLKRST_SSC_REFCLKSEL_MASK;
 267        switch (phy_drd->extrefclk) {
 268        case EXYNOS5_FSEL_50MHZ:
 269                reg |= (PHYCLKRST_MPLL_MULTIPLIER_50M_REF |
 270                        PHYCLKRST_SSC_REFCLKSEL(0x00));
 271                break;
 272        case EXYNOS5_FSEL_24MHZ:
 273                reg |= (PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF |
 274                        PHYCLKRST_SSC_REFCLKSEL(0x88));
 275                break;
 276        case EXYNOS5_FSEL_20MHZ:
 277                reg |= (PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF |
 278                        PHYCLKRST_SSC_REFCLKSEL(0x00));
 279                break;
 280        case EXYNOS5_FSEL_19MHZ2:
 281                reg |= (PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF |
 282                        PHYCLKRST_SSC_REFCLKSEL(0x88));
 283                break;
 284        default:
 285                dev_dbg(phy_drd->dev, "unsupported ref clk\n");
 286                break;
 287        }
 288
 289        return reg;
 290}
 291
 292/*
 293 * Sets the utmi phy's clk as EXTREFCLK (XXTI) which is internal clock
 294 * from clock core. Further sets the FSEL values for HighSpeed operations.
 295 */
 296static unsigned int
 297exynos5_usbdrd_utmi_set_refclk(struct phy_usb_instance *inst)
 298{
 299        u32 reg;
 300        struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
 301
 302        /* restore any previous reference clock settings */
 303        reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);
 304
 305        reg &= ~PHYCLKRST_REFCLKSEL_MASK;
 306        reg |=  PHYCLKRST_REFCLKSEL_EXT_REFCLK;
 307
 308        reg &= ~PHYCLKRST_FSEL_UTMI_MASK |
 309                PHYCLKRST_MPLL_MULTIPLIER_MASK |
 310                PHYCLKRST_SSC_REFCLKSEL_MASK;
 311        reg |= PHYCLKRST_FSEL(phy_drd->extrefclk);
 312
 313        return reg;
 314}
 315
 316static void exynos5_usbdrd_pipe3_init(struct exynos5_usbdrd_phy *phy_drd)
 317{
 318        u32 reg;
 319
 320        reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1);
 321        /* Set Tx De-Emphasis level */
 322        reg &= ~PHYPARAM1_PCS_TXDEEMPH_MASK;
 323        reg |=  PHYPARAM1_PCS_TXDEEMPH;
 324        writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1);
 325
 326        reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST);
 327        reg &= ~PHYTEST_POWERDOWN_SSP;
 328        writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST);
 329}
 330
 331static void exynos5_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd)
 332{
 333        u32 reg;
 334
 335        reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0);
 336        /* Set Loss-of-Signal Detector sensitivity */
 337        reg &= ~PHYPARAM0_REF_LOSLEVEL_MASK;
 338        reg |=  PHYPARAM0_REF_LOSLEVEL;
 339        writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0);
 340
 341        reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1);
 342        /* Set Tx De-Emphasis level */
 343        reg &= ~PHYPARAM1_PCS_TXDEEMPH_MASK;
 344        reg |=  PHYPARAM1_PCS_TXDEEMPH;
 345        writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1);
 346
 347        /* UTMI Power Control */
 348        writel(PHYUTMI_OTGDISABLE, phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMI);
 349
 350        reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST);
 351        reg &= ~PHYTEST_POWERDOWN_HSP;
 352        writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST);
 353}
 354
 355static int exynos5_usbdrd_phy_init(struct phy *phy)
 356{
 357        int ret;
 358        u32 reg;
 359        struct phy_usb_instance *inst = phy_get_drvdata(phy);
 360        struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
 361
 362        ret = clk_prepare_enable(phy_drd->clk);
 363        if (ret)
 364                return ret;
 365
 366        /* Reset USB 3.0 PHY */
 367        writel(0x0, phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0);
 368        writel(0x0, phy_drd->reg_phy + EXYNOS5_DRD_PHYRESUME);
 369
 370        /*
 371         * Setting the Frame length Adj value[6:1] to default 0x20
 372         * See xHCI 1.0 spec, 5.2.4
 373         */
 374        reg =   LINKSYSTEM_XHCI_VERSION_CONTROL |
 375                LINKSYSTEM_FLADJ(0x20);
 376        writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_LINKSYSTEM);
 377
 378        reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0);
 379        /* Select PHY CLK source */
 380        reg &= ~PHYPARAM0_REF_USE_PAD;
 381        writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0);
 382
 383        /* This bit must be set for both HS and SS operations */
 384        reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMICLKSEL);
 385        reg |= PHYUTMICLKSEL_UTMI_CLKSEL;
 386        writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMICLKSEL);
 387
 388        /* UTMI or PIPE3 specific init */
 389        inst->phy_cfg->phy_init(phy_drd);
 390
 391        /* reference clock settings */
 392        reg = inst->phy_cfg->set_refclk(inst);
 393
 394                /* Digital power supply in normal operating mode */
 395        reg |=  PHYCLKRST_RETENABLEN |
 396                /* Enable ref clock for SS function */
 397                PHYCLKRST_REF_SSP_EN |
 398                /* Enable spread spectrum */
 399                PHYCLKRST_SSC_EN |
 400                /* Power down HS Bias and PLL blocks in suspend mode */
 401                PHYCLKRST_COMMONONN |
 402                /* Reset the port */
 403                PHYCLKRST_PORTRESET;
 404
 405        writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);
 406
 407        udelay(10);
 408
 409        reg &= ~PHYCLKRST_PORTRESET;
 410        writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);
 411
 412        clk_disable_unprepare(phy_drd->clk);
 413
 414        return 0;
 415}
 416
 417static int exynos5_usbdrd_phy_exit(struct phy *phy)
 418{
 419        int ret;
 420        u32 reg;
 421        struct phy_usb_instance *inst = phy_get_drvdata(phy);
 422        struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
 423
 424        ret = clk_prepare_enable(phy_drd->clk);
 425        if (ret)
 426                return ret;
 427
 428        reg =   PHYUTMI_OTGDISABLE |
 429                PHYUTMI_FORCESUSPEND |
 430                PHYUTMI_FORCESLEEP;
 431        writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMI);
 432
 433        /* Resetting the PHYCLKRST enable bits to reduce leakage current */
 434        reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);
 435        reg &= ~(PHYCLKRST_REF_SSP_EN |
 436                 PHYCLKRST_SSC_EN |
 437                 PHYCLKRST_COMMONONN);
 438        writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);
 439
 440        /* Control PHYTEST to remove leakage current */
 441        reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST);
 442        reg |=  PHYTEST_POWERDOWN_SSP |
 443                PHYTEST_POWERDOWN_HSP;
 444        writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST);
 445
 446        clk_disable_unprepare(phy_drd->clk);
 447
 448        return 0;
 449}
 450
 451static int exynos5_usbdrd_phy_power_on(struct phy *phy)
 452{
 453        int ret;
 454        struct phy_usb_instance *inst = phy_get_drvdata(phy);
 455        struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
 456
 457        dev_dbg(phy_drd->dev, "Request to power_on usbdrd_phy phy\n");
 458
 459        clk_prepare_enable(phy_drd->ref_clk);
 460        if (!phy_drd->drv_data->has_common_clk_gate) {
 461                clk_prepare_enable(phy_drd->pipeclk);
 462                clk_prepare_enable(phy_drd->utmiclk);
 463                clk_prepare_enable(phy_drd->itpclk);
 464        }
 465
 466        /* Enable VBUS supply */
 467        if (phy_drd->vbus_boost) {
 468                ret = regulator_enable(phy_drd->vbus_boost);
 469                if (ret) {
 470                        dev_err(phy_drd->dev,
 471                                "Failed to enable VBUS boost supply\n");
 472                        goto fail_vbus;
 473                }
 474        }
 475
 476        if (phy_drd->vbus) {
 477                ret = regulator_enable(phy_drd->vbus);
 478                if (ret) {
 479                        dev_err(phy_drd->dev, "Failed to enable VBUS supply\n");
 480                        goto fail_vbus_boost;
 481                }
 482        }
 483
 484        /* Power-on PHY*/
 485        inst->phy_cfg->phy_isol(inst, 0);
 486
 487        return 0;
 488
 489fail_vbus_boost:
 490        if (phy_drd->vbus_boost)
 491                regulator_disable(phy_drd->vbus_boost);
 492
 493fail_vbus:
 494        clk_disable_unprepare(phy_drd->ref_clk);
 495        if (!phy_drd->drv_data->has_common_clk_gate) {
 496                clk_disable_unprepare(phy_drd->itpclk);
 497                clk_disable_unprepare(phy_drd->utmiclk);
 498                clk_disable_unprepare(phy_drd->pipeclk);
 499        }
 500
 501        return ret;
 502}
 503
 504static int exynos5_usbdrd_phy_power_off(struct phy *phy)
 505{
 506        struct phy_usb_instance *inst = phy_get_drvdata(phy);
 507        struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
 508
 509        dev_dbg(phy_drd->dev, "Request to power_off usbdrd_phy phy\n");
 510
 511        /* Power-off the PHY */
 512        inst->phy_cfg->phy_isol(inst, 1);
 513
 514        /* Disable VBUS supply */
 515        if (phy_drd->vbus)
 516                regulator_disable(phy_drd->vbus);
 517        if (phy_drd->vbus_boost)
 518                regulator_disable(phy_drd->vbus_boost);
 519
 520        clk_disable_unprepare(phy_drd->ref_clk);
 521        if (!phy_drd->drv_data->has_common_clk_gate) {
 522                clk_disable_unprepare(phy_drd->itpclk);
 523                clk_disable_unprepare(phy_drd->pipeclk);
 524                clk_disable_unprepare(phy_drd->utmiclk);
 525        }
 526
 527        return 0;
 528}
 529
 530static struct phy *exynos5_usbdrd_phy_xlate(struct device *dev,
 531                                        struct of_phandle_args *args)
 532{
 533        struct exynos5_usbdrd_phy *phy_drd = dev_get_drvdata(dev);
 534
 535        if (WARN_ON(args->args[0] >= EXYNOS5_DRDPHYS_NUM))
 536                return ERR_PTR(-ENODEV);
 537
 538        return phy_drd->phys[args->args[0]].phy;
 539}
 540
 541static const struct phy_ops exynos5_usbdrd_phy_ops = {
 542        .init           = exynos5_usbdrd_phy_init,
 543        .exit           = exynos5_usbdrd_phy_exit,
 544        .power_on       = exynos5_usbdrd_phy_power_on,
 545        .power_off      = exynos5_usbdrd_phy_power_off,
 546        .owner          = THIS_MODULE,
 547};
 548
 549static int exynos5_usbdrd_phy_clk_handle(struct exynos5_usbdrd_phy *phy_drd)
 550{
 551        unsigned long ref_rate;
 552        int ret;
 553
 554        phy_drd->clk = devm_clk_get(phy_drd->dev, "phy");
 555        if (IS_ERR(phy_drd->clk)) {
 556                dev_err(phy_drd->dev, "Failed to get phy clock\n");
 557                return PTR_ERR(phy_drd->clk);
 558        }
 559
 560        phy_drd->ref_clk = devm_clk_get(phy_drd->dev, "ref");
 561        if (IS_ERR(phy_drd->ref_clk)) {
 562                dev_err(phy_drd->dev, "Failed to get phy reference clock\n");
 563                return PTR_ERR(phy_drd->ref_clk);
 564        }
 565        ref_rate = clk_get_rate(phy_drd->ref_clk);
 566
 567        ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk);
 568        if (ret) {
 569                dev_err(phy_drd->dev, "Clock rate (%ld) not supported\n",
 570                        ref_rate);
 571                return ret;
 572        }
 573
 574        if (!phy_drd->drv_data->has_common_clk_gate) {
 575                phy_drd->pipeclk = devm_clk_get(phy_drd->dev, "phy_pipe");
 576                if (IS_ERR(phy_drd->pipeclk)) {
 577                        dev_info(phy_drd->dev,
 578                                 "PIPE3 phy operational clock not specified\n");
 579                        phy_drd->pipeclk = NULL;
 580                }
 581
 582                phy_drd->utmiclk = devm_clk_get(phy_drd->dev, "phy_utmi");
 583                if (IS_ERR(phy_drd->utmiclk)) {
 584                        dev_info(phy_drd->dev,
 585                                 "UTMI phy operational clock not specified\n");
 586                        phy_drd->utmiclk = NULL;
 587                }
 588
 589                phy_drd->itpclk = devm_clk_get(phy_drd->dev, "itp");
 590                if (IS_ERR(phy_drd->itpclk)) {
 591                        dev_info(phy_drd->dev,
 592                                 "ITP clock from main OSC not specified\n");
 593                        phy_drd->itpclk = NULL;
 594                }
 595        }
 596
 597        return 0;
 598}
 599
 600static const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = {
 601        {
 602                .id             = EXYNOS5_DRDPHY_UTMI,
 603                .phy_isol       = exynos5_usbdrd_phy_isol,
 604                .phy_init       = exynos5_usbdrd_utmi_init,
 605                .set_refclk     = exynos5_usbdrd_utmi_set_refclk,
 606        },
 607        {
 608                .id             = EXYNOS5_DRDPHY_PIPE3,
 609                .phy_isol       = exynos5_usbdrd_phy_isol,
 610                .phy_init       = exynos5_usbdrd_pipe3_init,
 611                .set_refclk     = exynos5_usbdrd_pipe3_set_refclk,
 612        },
 613};
 614
 615static const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = {
 616        .phy_cfg                = phy_cfg_exynos5,
 617        .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
 618        .pmu_offset_usbdrd1_phy = EXYNOS5420_USBDRD1_PHY_CONTROL,
 619        .has_common_clk_gate    = true,
 620};
 621
 622static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = {
 623        .phy_cfg                = phy_cfg_exynos5,
 624        .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
 625        .has_common_clk_gate    = true,
 626};
 627
 628static const struct exynos5_usbdrd_phy_drvdata exynos5433_usbdrd_phy = {
 629        .phy_cfg                = phy_cfg_exynos5,
 630        .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
 631        .pmu_offset_usbdrd1_phy = EXYNOS5433_USBHOST30_PHY_CONTROL,
 632        .has_common_clk_gate    = false,
 633};
 634
 635static const struct exynos5_usbdrd_phy_drvdata exynos7_usbdrd_phy = {
 636        .phy_cfg                = phy_cfg_exynos5,
 637        .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
 638        .has_common_clk_gate    = false,
 639};
 640
 641static const struct of_device_id exynos5_usbdrd_phy_of_match[] = {
 642        {
 643                .compatible = "samsung,exynos5250-usbdrd-phy",
 644                .data = &exynos5250_usbdrd_phy
 645        }, {
 646                .compatible = "samsung,exynos5420-usbdrd-phy",
 647                .data = &exynos5420_usbdrd_phy
 648        }, {
 649                .compatible = "samsung,exynos5433-usbdrd-phy",
 650                .data = &exynos5433_usbdrd_phy
 651        }, {
 652                .compatible = "samsung,exynos7-usbdrd-phy",
 653                .data = &exynos7_usbdrd_phy
 654        },
 655        { },
 656};
 657MODULE_DEVICE_TABLE(of, exynos5_usbdrd_phy_of_match);
 658
 659static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
 660{
 661        struct device *dev = &pdev->dev;
 662        struct device_node *node = dev->of_node;
 663        struct exynos5_usbdrd_phy *phy_drd;
 664        struct phy_provider *phy_provider;
 665        struct resource *res;
 666        const struct exynos5_usbdrd_phy_drvdata *drv_data;
 667        struct regmap *reg_pmu;
 668        u32 pmu_offset;
 669        int i, ret;
 670        int channel;
 671
 672        phy_drd = devm_kzalloc(dev, sizeof(*phy_drd), GFP_KERNEL);
 673        if (!phy_drd)
 674                return -ENOMEM;
 675
 676        dev_set_drvdata(dev, phy_drd);
 677        phy_drd->dev = dev;
 678
 679        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 680        phy_drd->reg_phy = devm_ioremap_resource(dev, res);
 681        if (IS_ERR(phy_drd->reg_phy))
 682                return PTR_ERR(phy_drd->reg_phy);
 683
 684        drv_data = of_device_get_match_data(dev);
 685        if (!drv_data)
 686                return -EINVAL;
 687
 688        phy_drd->drv_data = drv_data;
 689
 690        ret = exynos5_usbdrd_phy_clk_handle(phy_drd);
 691        if (ret) {
 692                dev_err(dev, "Failed to initialize clocks\n");
 693                return ret;
 694        }
 695
 696        reg_pmu = syscon_regmap_lookup_by_phandle(dev->of_node,
 697                                                   "samsung,pmu-syscon");
 698        if (IS_ERR(reg_pmu)) {
 699                dev_err(dev, "Failed to lookup PMU regmap\n");
 700                return PTR_ERR(reg_pmu);
 701        }
 702
 703        /*
 704         * Exynos5420 SoC has multiple channels for USB 3.0 PHY, with
 705         * each having separate power control registers.
 706         * 'channel' facilitates to set such registers.
 707         */
 708        channel = of_alias_get_id(node, "usbdrdphy");
 709        if (channel < 0)
 710                dev_dbg(dev, "Not a multi-controller usbdrd phy\n");
 711
 712        switch (channel) {
 713        case 1:
 714                pmu_offset = phy_drd->drv_data->pmu_offset_usbdrd1_phy;
 715                break;
 716        case 0:
 717        default:
 718                pmu_offset = phy_drd->drv_data->pmu_offset_usbdrd0_phy;
 719                break;
 720        }
 721
 722        /* Get Vbus regulators */
 723        phy_drd->vbus = devm_regulator_get(dev, "vbus");
 724        if (IS_ERR(phy_drd->vbus)) {
 725                ret = PTR_ERR(phy_drd->vbus);
 726                if (ret == -EPROBE_DEFER)
 727                        return ret;
 728
 729                dev_warn(dev, "Failed to get VBUS supply regulator\n");
 730                phy_drd->vbus = NULL;
 731        }
 732
 733        phy_drd->vbus_boost = devm_regulator_get(dev, "vbus-boost");
 734        if (IS_ERR(phy_drd->vbus_boost)) {
 735                ret = PTR_ERR(phy_drd->vbus_boost);
 736                if (ret == -EPROBE_DEFER)
 737                        return ret;
 738
 739                dev_warn(dev, "Failed to get VBUS boost supply regulator\n");
 740                phy_drd->vbus_boost = NULL;
 741        }
 742
 743        dev_vdbg(dev, "Creating usbdrd_phy phy\n");
 744
 745        for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) {
 746                struct phy *phy = devm_phy_create(dev, NULL,
 747                                                  &exynos5_usbdrd_phy_ops);
 748                if (IS_ERR(phy)) {
 749                        dev_err(dev, "Failed to create usbdrd_phy phy\n");
 750                        return PTR_ERR(phy);
 751                }
 752
 753                phy_drd->phys[i].phy = phy;
 754                phy_drd->phys[i].index = i;
 755                phy_drd->phys[i].reg_pmu = reg_pmu;
 756                phy_drd->phys[i].pmu_offset = pmu_offset;
 757                phy_drd->phys[i].phy_cfg = &drv_data->phy_cfg[i];
 758                phy_set_drvdata(phy, &phy_drd->phys[i]);
 759        }
 760
 761        phy_provider = devm_of_phy_provider_register(dev,
 762                                                     exynos5_usbdrd_phy_xlate);
 763        if (IS_ERR(phy_provider)) {
 764                dev_err(phy_drd->dev, "Failed to register phy provider\n");
 765                return PTR_ERR(phy_provider);
 766        }
 767
 768        return 0;
 769}
 770
 771static struct platform_driver exynos5_usb3drd_phy = {
 772        .probe  = exynos5_usbdrd_phy_probe,
 773        .driver = {
 774                .of_match_table = exynos5_usbdrd_phy_of_match,
 775                .name           = "exynos5_usb3drd_phy",
 776        }
 777};
 778
 779module_platform_driver(exynos5_usb3drd_phy);
 780MODULE_DESCRIPTION("Samsung EXYNOS5 SoCs USB 3.0 DRD controller PHY driver");
 781MODULE_AUTHOR("Vivek Gautam <gautam.vivek@samsung.com>");
 782MODULE_LICENSE("GPL v2");
 783MODULE_ALIAS("platform:exynos5_usb3drd_phy");
 784