linux/drivers/phy/qualcomm/phy-qcom-ufs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
   4 */
   5
   6#include "phy-qcom-ufs-i.h"
   7
   8#define MAX_PROP_NAME              32
   9#define VDDA_PHY_MIN_UV            1000000
  10#define VDDA_PHY_MAX_UV            1000000
  11#define VDDA_PLL_MIN_UV            1800000
  12#define VDDA_PLL_MAX_UV            1800000
  13#define VDDP_REF_CLK_MIN_UV        1200000
  14#define VDDP_REF_CLK_MAX_UV        1200000
  15
  16int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
  17                           struct ufs_qcom_phy_calibration *tbl_A,
  18                           int tbl_size_A,
  19                           struct ufs_qcom_phy_calibration *tbl_B,
  20                           int tbl_size_B, bool is_rate_B)
  21{
  22        int i;
  23        int ret = 0;
  24
  25        if (!tbl_A) {
  26                dev_err(ufs_qcom_phy->dev, "%s: tbl_A is NULL", __func__);
  27                ret = EINVAL;
  28                goto out;
  29        }
  30
  31        for (i = 0; i < tbl_size_A; i++)
  32                writel_relaxed(tbl_A[i].cfg_value,
  33                               ufs_qcom_phy->mmio + tbl_A[i].reg_offset);
  34
  35        /*
  36         * In case we would like to work in rate B, we need
  37         * to override a registers that were configured in rate A table
  38         * with registers of rate B table.
  39         * table.
  40         */
  41        if (is_rate_B) {
  42                if (!tbl_B) {
  43                        dev_err(ufs_qcom_phy->dev, "%s: tbl_B is NULL",
  44                                __func__);
  45                        ret = EINVAL;
  46                        goto out;
  47                }
  48
  49                for (i = 0; i < tbl_size_B; i++)
  50                        writel_relaxed(tbl_B[i].cfg_value,
  51                                ufs_qcom_phy->mmio + tbl_B[i].reg_offset);
  52        }
  53
  54        /* flush buffered writes */
  55        mb();
  56
  57out:
  58        return ret;
  59}
  60EXPORT_SYMBOL_GPL(ufs_qcom_phy_calibrate);
  61
  62/*
  63 * This assumes the embedded phy structure inside generic_phy is of type
  64 * struct ufs_qcom_phy. In order to function properly it's crucial
  65 * to keep the embedded struct "struct ufs_qcom_phy common_cfg"
  66 * as the first inside generic_phy.
  67 */
  68struct ufs_qcom_phy *get_ufs_qcom_phy(struct phy *generic_phy)
  69{
  70        return (struct ufs_qcom_phy *)phy_get_drvdata(generic_phy);
  71}
  72EXPORT_SYMBOL_GPL(get_ufs_qcom_phy);
  73
  74static
  75int ufs_qcom_phy_base_init(struct platform_device *pdev,
  76                           struct ufs_qcom_phy *phy_common)
  77{
  78        struct device *dev = &pdev->dev;
  79        struct resource *res;
  80        int err = 0;
  81
  82        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_mem");
  83        phy_common->mmio = devm_ioremap_resource(dev, res);
  84        if (IS_ERR((void const *)phy_common->mmio)) {
  85                err = PTR_ERR((void const *)phy_common->mmio);
  86                phy_common->mmio = NULL;
  87                dev_err(dev, "%s: ioremap for phy_mem resource failed %d\n",
  88                        __func__, err);
  89                return err;
  90        }
  91
  92        /* "dev_ref_clk_ctrl_mem" is optional resource */
  93        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
  94                                           "dev_ref_clk_ctrl_mem");
  95        phy_common->dev_ref_clk_ctrl_mmio = devm_ioremap_resource(dev, res);
  96        if (IS_ERR((void const *)phy_common->dev_ref_clk_ctrl_mmio))
  97                phy_common->dev_ref_clk_ctrl_mmio = NULL;
  98
  99        return 0;
 100}
 101
 102struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev,
 103                                struct ufs_qcom_phy *common_cfg,
 104                                const struct phy_ops *ufs_qcom_phy_gen_ops,
 105                                struct ufs_qcom_phy_specific_ops *phy_spec_ops)
 106{
 107        int err;
 108        struct device *dev = &pdev->dev;
 109        struct phy *generic_phy = NULL;
 110        struct phy_provider *phy_provider;
 111
 112        err = ufs_qcom_phy_base_init(pdev, common_cfg);
 113        if (err) {
 114                dev_err(dev, "%s: phy base init failed %d\n", __func__, err);
 115                goto out;
 116        }
 117
 118        phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 119        if (IS_ERR(phy_provider)) {
 120                err = PTR_ERR(phy_provider);
 121                dev_err(dev, "%s: failed to register phy %d\n", __func__, err);
 122                goto out;
 123        }
 124
 125        generic_phy = devm_phy_create(dev, NULL, ufs_qcom_phy_gen_ops);
 126        if (IS_ERR(generic_phy)) {
 127                err =  PTR_ERR(generic_phy);
 128                dev_err(dev, "%s: failed to create phy %d\n", __func__, err);
 129                generic_phy = NULL;
 130                goto out;
 131        }
 132
 133        common_cfg->phy_spec_ops = phy_spec_ops;
 134        common_cfg->dev = dev;
 135
 136out:
 137        return generic_phy;
 138}
 139EXPORT_SYMBOL_GPL(ufs_qcom_phy_generic_probe);
 140
 141static int ufs_qcom_phy_get_reset(struct ufs_qcom_phy *phy_common)
 142{
 143        struct reset_control *reset;
 144
 145        if (phy_common->ufs_reset)
 146                return 0;
 147
 148        reset = devm_reset_control_get_exclusive_by_index(phy_common->dev, 0);
 149        if (IS_ERR(reset))
 150                return PTR_ERR(reset);
 151
 152        phy_common->ufs_reset = reset;
 153        return 0;
 154}
 155
 156static int __ufs_qcom_phy_clk_get(struct device *dev,
 157                         const char *name, struct clk **clk_out, bool err_print)
 158{
 159        struct clk *clk;
 160        int err = 0;
 161
 162        clk = devm_clk_get(dev, name);
 163        if (IS_ERR(clk)) {
 164                err = PTR_ERR(clk);
 165                if (err_print)
 166                        dev_err(dev, "failed to get %s err %d", name, err);
 167        } else {
 168                *clk_out = clk;
 169        }
 170
 171        return err;
 172}
 173
 174static int ufs_qcom_phy_clk_get(struct device *dev,
 175                         const char *name, struct clk **clk_out)
 176{
 177        return __ufs_qcom_phy_clk_get(dev, name, clk_out, true);
 178}
 179
 180int ufs_qcom_phy_init_clks(struct ufs_qcom_phy *phy_common)
 181{
 182        int err;
 183
 184        if (of_device_is_compatible(phy_common->dev->of_node,
 185                                "qcom,msm8996-ufs-phy-qmp-14nm"))
 186                goto skip_txrx_clk;
 187
 188        err = ufs_qcom_phy_clk_get(phy_common->dev, "tx_iface_clk",
 189                                   &phy_common->tx_iface_clk);
 190        if (err)
 191                goto out;
 192
 193        err = ufs_qcom_phy_clk_get(phy_common->dev, "rx_iface_clk",
 194                                   &phy_common->rx_iface_clk);
 195        if (err)
 196                goto out;
 197
 198skip_txrx_clk:
 199        err = ufs_qcom_phy_clk_get(phy_common->dev, "ref_clk_src",
 200                                   &phy_common->ref_clk_src);
 201        if (err)
 202                goto out;
 203
 204        /*
 205         * "ref_clk_parent" is optional hence don't abort init if it's not
 206         * found.
 207         */
 208        __ufs_qcom_phy_clk_get(phy_common->dev, "ref_clk_parent",
 209                                   &phy_common->ref_clk_parent, false);
 210
 211        err = ufs_qcom_phy_clk_get(phy_common->dev, "ref_clk",
 212                                   &phy_common->ref_clk);
 213
 214out:
 215        return err;
 216}
 217EXPORT_SYMBOL_GPL(ufs_qcom_phy_init_clks);
 218
 219static int ufs_qcom_phy_init_vreg(struct device *dev,
 220                                  struct ufs_qcom_phy_vreg *vreg,
 221                                  const char *name)
 222{
 223        int err = 0;
 224
 225        char prop_name[MAX_PROP_NAME];
 226
 227        vreg->name = name;
 228        vreg->reg = devm_regulator_get(dev, name);
 229        if (IS_ERR(vreg->reg)) {
 230                err = PTR_ERR(vreg->reg);
 231                dev_err(dev, "failed to get %s, %d\n", name, err);
 232                goto out;
 233        }
 234
 235        if (dev->of_node) {
 236                snprintf(prop_name, MAX_PROP_NAME, "%s-max-microamp", name);
 237                err = of_property_read_u32(dev->of_node,
 238                                        prop_name, &vreg->max_uA);
 239                if (err && err != -EINVAL) {
 240                        dev_err(dev, "%s: failed to read %s\n",
 241                                        __func__, prop_name);
 242                        goto out;
 243                } else if (err == -EINVAL || !vreg->max_uA) {
 244                        if (regulator_count_voltages(vreg->reg) > 0) {
 245                                dev_err(dev, "%s: %s is mandatory\n",
 246                                                __func__, prop_name);
 247                                goto out;
 248                        }
 249                        err = 0;
 250                }
 251        }
 252
 253        if (!strcmp(name, "vdda-pll")) {
 254                vreg->max_uV = VDDA_PLL_MAX_UV;
 255                vreg->min_uV = VDDA_PLL_MIN_UV;
 256        } else if (!strcmp(name, "vdda-phy")) {
 257                vreg->max_uV = VDDA_PHY_MAX_UV;
 258                vreg->min_uV = VDDA_PHY_MIN_UV;
 259        } else if (!strcmp(name, "vddp-ref-clk")) {
 260                vreg->max_uV = VDDP_REF_CLK_MAX_UV;
 261                vreg->min_uV = VDDP_REF_CLK_MIN_UV;
 262        }
 263
 264out:
 265        return err;
 266}
 267
 268int ufs_qcom_phy_init_vregulators(struct ufs_qcom_phy *phy_common)
 269{
 270        int err;
 271
 272        err = ufs_qcom_phy_init_vreg(phy_common->dev, &phy_common->vdda_pll,
 273                "vdda-pll");
 274        if (err)
 275                goto out;
 276
 277        err = ufs_qcom_phy_init_vreg(phy_common->dev, &phy_common->vdda_phy,
 278                "vdda-phy");
 279
 280        if (err)
 281                goto out;
 282
 283        err = ufs_qcom_phy_init_vreg(phy_common->dev, &phy_common->vddp_ref_clk,
 284                                     "vddp-ref-clk");
 285
 286out:
 287        return err;
 288}
 289EXPORT_SYMBOL_GPL(ufs_qcom_phy_init_vregulators);
 290
 291static int ufs_qcom_phy_cfg_vreg(struct device *dev,
 292                          struct ufs_qcom_phy_vreg *vreg, bool on)
 293{
 294        int ret = 0;
 295        struct regulator *reg = vreg->reg;
 296        const char *name = vreg->name;
 297        int min_uV;
 298        int uA_load;
 299
 300        if (regulator_count_voltages(reg) > 0) {
 301                min_uV = on ? vreg->min_uV : 0;
 302                ret = regulator_set_voltage(reg, min_uV, vreg->max_uV);
 303                if (ret) {
 304                        dev_err(dev, "%s: %s set voltage failed, err=%d\n",
 305                                        __func__, name, ret);
 306                        goto out;
 307                }
 308                uA_load = on ? vreg->max_uA : 0;
 309                ret = regulator_set_load(reg, uA_load);
 310                if (ret >= 0) {
 311                        /*
 312                         * regulator_set_load() returns new regulator
 313                         * mode upon success.
 314                         */
 315                        ret = 0;
 316                } else {
 317                        dev_err(dev, "%s: %s set optimum mode(uA_load=%d) failed, err=%d\n",
 318                                        __func__, name, uA_load, ret);
 319                        goto out;
 320                }
 321        }
 322out:
 323        return ret;
 324}
 325
 326static int ufs_qcom_phy_enable_vreg(struct device *dev,
 327                             struct ufs_qcom_phy_vreg *vreg)
 328{
 329        int ret = 0;
 330
 331        if (!vreg || vreg->enabled)
 332                goto out;
 333
 334        ret = ufs_qcom_phy_cfg_vreg(dev, vreg, true);
 335        if (ret) {
 336                dev_err(dev, "%s: ufs_qcom_phy_cfg_vreg() failed, err=%d\n",
 337                        __func__, ret);
 338                goto out;
 339        }
 340
 341        ret = regulator_enable(vreg->reg);
 342        if (ret) {
 343                dev_err(dev, "%s: enable failed, err=%d\n",
 344                                __func__, ret);
 345                goto out;
 346        }
 347
 348        vreg->enabled = true;
 349out:
 350        return ret;
 351}
 352
 353static int ufs_qcom_phy_enable_ref_clk(struct ufs_qcom_phy *phy)
 354{
 355        int ret = 0;
 356
 357        if (phy->is_ref_clk_enabled)
 358                goto out;
 359
 360        /*
 361         * reference clock is propagated in a daisy-chained manner from
 362         * source to phy, so ungate them at each stage.
 363         */
 364        ret = clk_prepare_enable(phy->ref_clk_src);
 365        if (ret) {
 366                dev_err(phy->dev, "%s: ref_clk_src enable failed %d\n",
 367                                __func__, ret);
 368                goto out;
 369        }
 370
 371        /*
 372         * "ref_clk_parent" is optional clock hence make sure that clk reference
 373         * is available before trying to enable the clock.
 374         */
 375        if (phy->ref_clk_parent) {
 376                ret = clk_prepare_enable(phy->ref_clk_parent);
 377                if (ret) {
 378                        dev_err(phy->dev, "%s: ref_clk_parent enable failed %d\n",
 379                                        __func__, ret);
 380                        goto out_disable_src;
 381                }
 382        }
 383
 384        ret = clk_prepare_enable(phy->ref_clk);
 385        if (ret) {
 386                dev_err(phy->dev, "%s: ref_clk enable failed %d\n",
 387                                __func__, ret);
 388                goto out_disable_parent;
 389        }
 390
 391        phy->is_ref_clk_enabled = true;
 392        goto out;
 393
 394out_disable_parent:
 395        if (phy->ref_clk_parent)
 396                clk_disable_unprepare(phy->ref_clk_parent);
 397out_disable_src:
 398        clk_disable_unprepare(phy->ref_clk_src);
 399out:
 400        return ret;
 401}
 402
 403static int ufs_qcom_phy_disable_vreg(struct device *dev,
 404                              struct ufs_qcom_phy_vreg *vreg)
 405{
 406        int ret = 0;
 407
 408        if (!vreg || !vreg->enabled)
 409                goto out;
 410
 411        ret = regulator_disable(vreg->reg);
 412
 413        if (!ret) {
 414                /* ignore errors on applying disable config */
 415                ufs_qcom_phy_cfg_vreg(dev, vreg, false);
 416                vreg->enabled = false;
 417        } else {
 418                dev_err(dev, "%s: %s disable failed, err=%d\n",
 419                                __func__, vreg->name, ret);
 420        }
 421out:
 422        return ret;
 423}
 424
 425static void ufs_qcom_phy_disable_ref_clk(struct ufs_qcom_phy *phy)
 426{
 427        if (phy->is_ref_clk_enabled) {
 428                clk_disable_unprepare(phy->ref_clk);
 429                /*
 430                 * "ref_clk_parent" is optional clock hence make sure that clk
 431                 * reference is available before trying to disable the clock.
 432                 */
 433                if (phy->ref_clk_parent)
 434                        clk_disable_unprepare(phy->ref_clk_parent);
 435                clk_disable_unprepare(phy->ref_clk_src);
 436                phy->is_ref_clk_enabled = false;
 437        }
 438}
 439
 440/* Turn ON M-PHY RMMI interface clocks */
 441static int ufs_qcom_phy_enable_iface_clk(struct ufs_qcom_phy *phy)
 442{
 443        int ret = 0;
 444
 445        if (phy->is_iface_clk_enabled)
 446                goto out;
 447
 448        ret = clk_prepare_enable(phy->tx_iface_clk);
 449        if (ret) {
 450                dev_err(phy->dev, "%s: tx_iface_clk enable failed %d\n",
 451                                __func__, ret);
 452                goto out;
 453        }
 454        ret = clk_prepare_enable(phy->rx_iface_clk);
 455        if (ret) {
 456                clk_disable_unprepare(phy->tx_iface_clk);
 457                dev_err(phy->dev, "%s: rx_iface_clk enable failed %d. disabling also tx_iface_clk\n",
 458                                __func__, ret);
 459                goto out;
 460        }
 461        phy->is_iface_clk_enabled = true;
 462
 463out:
 464        return ret;
 465}
 466
 467/* Turn OFF M-PHY RMMI interface clocks */
 468static void ufs_qcom_phy_disable_iface_clk(struct ufs_qcom_phy *phy)
 469{
 470        if (phy->is_iface_clk_enabled) {
 471                clk_disable_unprepare(phy->tx_iface_clk);
 472                clk_disable_unprepare(phy->rx_iface_clk);
 473                phy->is_iface_clk_enabled = false;
 474        }
 475}
 476
 477static int ufs_qcom_phy_start_serdes(struct ufs_qcom_phy *ufs_qcom_phy)
 478{
 479        int ret = 0;
 480
 481        if (!ufs_qcom_phy->phy_spec_ops->start_serdes) {
 482                dev_err(ufs_qcom_phy->dev, "%s: start_serdes() callback is not supported\n",
 483                        __func__);
 484                ret = -ENOTSUPP;
 485        } else {
 486                ufs_qcom_phy->phy_spec_ops->start_serdes(ufs_qcom_phy);
 487        }
 488
 489        return ret;
 490}
 491
 492int ufs_qcom_phy_set_tx_lane_enable(struct phy *generic_phy, u32 tx_lanes)
 493{
 494        struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
 495        int ret = 0;
 496
 497        if (!ufs_qcom_phy->phy_spec_ops->set_tx_lane_enable) {
 498                dev_err(ufs_qcom_phy->dev, "%s: set_tx_lane_enable() callback is not supported\n",
 499                        __func__);
 500                ret = -ENOTSUPP;
 501        } else {
 502                ufs_qcom_phy->phy_spec_ops->set_tx_lane_enable(ufs_qcom_phy,
 503                                                               tx_lanes);
 504        }
 505
 506        return ret;
 507}
 508EXPORT_SYMBOL_GPL(ufs_qcom_phy_set_tx_lane_enable);
 509
 510void ufs_qcom_phy_save_controller_version(struct phy *generic_phy,
 511                                          u8 major, u16 minor, u16 step)
 512{
 513        struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
 514
 515        ufs_qcom_phy->host_ctrl_rev_major = major;
 516        ufs_qcom_phy->host_ctrl_rev_minor = minor;
 517        ufs_qcom_phy->host_ctrl_rev_step = step;
 518}
 519EXPORT_SYMBOL_GPL(ufs_qcom_phy_save_controller_version);
 520
 521static int ufs_qcom_phy_is_pcs_ready(struct ufs_qcom_phy *ufs_qcom_phy)
 522{
 523        if (!ufs_qcom_phy->phy_spec_ops->is_physical_coding_sublayer_ready) {
 524                dev_err(ufs_qcom_phy->dev, "%s: is_physical_coding_sublayer_ready() callback is not supported\n",
 525                        __func__);
 526                return -ENOTSUPP;
 527        }
 528
 529        return ufs_qcom_phy->phy_spec_ops->
 530                        is_physical_coding_sublayer_ready(ufs_qcom_phy);
 531}
 532
 533int ufs_qcom_phy_power_on(struct phy *generic_phy)
 534{
 535        struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);
 536        struct device *dev = phy_common->dev;
 537        bool is_rate_B = false;
 538        int err;
 539
 540        err = ufs_qcom_phy_get_reset(phy_common);
 541        if (err)
 542                return err;
 543
 544        err = reset_control_assert(phy_common->ufs_reset);
 545        if (err)
 546                return err;
 547
 548        if (phy_common->mode == PHY_MODE_UFS_HS_B)
 549                is_rate_B = true;
 550
 551        err = phy_common->phy_spec_ops->calibrate(phy_common, is_rate_B);
 552        if (err)
 553                return err;
 554
 555        err = reset_control_deassert(phy_common->ufs_reset);
 556        if (err) {
 557                dev_err(dev, "Failed to assert UFS PHY reset");
 558                return err;
 559        }
 560
 561        err = ufs_qcom_phy_start_serdes(phy_common);
 562        if (err)
 563                return err;
 564
 565        err = ufs_qcom_phy_is_pcs_ready(phy_common);
 566        if (err)
 567                return err;
 568
 569        err = ufs_qcom_phy_enable_vreg(dev, &phy_common->vdda_phy);
 570        if (err) {
 571                dev_err(dev, "%s enable vdda_phy failed, err=%d\n",
 572                        __func__, err);
 573                goto out;
 574        }
 575
 576        phy_common->phy_spec_ops->power_control(phy_common, true);
 577
 578        /* vdda_pll also enables ref clock LDOs so enable it first */
 579        err = ufs_qcom_phy_enable_vreg(dev, &phy_common->vdda_pll);
 580        if (err) {
 581                dev_err(dev, "%s enable vdda_pll failed, err=%d\n",
 582                        __func__, err);
 583                goto out_disable_phy;
 584        }
 585
 586        err = ufs_qcom_phy_enable_iface_clk(phy_common);
 587        if (err) {
 588                dev_err(dev, "%s enable phy iface clock failed, err=%d\n",
 589                        __func__, err);
 590                goto out_disable_pll;
 591        }
 592
 593        err = ufs_qcom_phy_enable_ref_clk(phy_common);
 594        if (err) {
 595                dev_err(dev, "%s enable phy ref clock failed, err=%d\n",
 596                        __func__, err);
 597                goto out_disable_iface_clk;
 598        }
 599
 600        /* enable device PHY ref_clk pad rail */
 601        if (phy_common->vddp_ref_clk.reg) {
 602                err = ufs_qcom_phy_enable_vreg(dev,
 603                                               &phy_common->vddp_ref_clk);
 604                if (err) {
 605                        dev_err(dev, "%s enable vddp_ref_clk failed, err=%d\n",
 606                                __func__, err);
 607                        goto out_disable_ref_clk;
 608                }
 609        }
 610
 611        goto out;
 612
 613out_disable_ref_clk:
 614        ufs_qcom_phy_disable_ref_clk(phy_common);
 615out_disable_iface_clk:
 616        ufs_qcom_phy_disable_iface_clk(phy_common);
 617out_disable_pll:
 618        ufs_qcom_phy_disable_vreg(dev, &phy_common->vdda_pll);
 619out_disable_phy:
 620        ufs_qcom_phy_disable_vreg(dev, &phy_common->vdda_phy);
 621out:
 622        return err;
 623}
 624EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_on);
 625
 626int ufs_qcom_phy_power_off(struct phy *generic_phy)
 627{
 628        struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);
 629
 630        phy_common->phy_spec_ops->power_control(phy_common, false);
 631
 632        if (phy_common->vddp_ref_clk.reg)
 633                ufs_qcom_phy_disable_vreg(phy_common->dev,
 634                                          &phy_common->vddp_ref_clk);
 635        ufs_qcom_phy_disable_ref_clk(phy_common);
 636        ufs_qcom_phy_disable_iface_clk(phy_common);
 637
 638        ufs_qcom_phy_disable_vreg(phy_common->dev, &phy_common->vdda_pll);
 639        ufs_qcom_phy_disable_vreg(phy_common->dev, &phy_common->vdda_phy);
 640        reset_control_assert(phy_common->ufs_reset);
 641        return 0;
 642}
 643EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_off);
 644
 645MODULE_AUTHOR("Yaniv Gardi <ygardi@codeaurora.org>");
 646MODULE_AUTHOR("Vivek Gautam <vivek.gautam@codeaurora.org>");
 647MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY");
 648MODULE_LICENSE("GPL v2");
 649