linux/drivers/clk/qcom/clk-smd-rpm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2016, Linaro Limited
   4 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
   5 */
   6
   7#include <linux/clk-provider.h>
   8#include <linux/err.h>
   9#include <linux/export.h>
  10#include <linux/init.h>
  11#include <linux/kernel.h>
  12#include <linux/module.h>
  13#include <linux/mutex.h>
  14#include <linux/of.h>
  15#include <linux/of_device.h>
  16#include <linux/platform_device.h>
  17#include <linux/soc/qcom/smd-rpm.h>
  18
  19#include <dt-bindings/clock/qcom,rpmcc.h>
  20#include <dt-bindings/mfd/qcom-rpm.h>
  21
  22#define QCOM_RPM_KEY_SOFTWARE_ENABLE                    0x6e657773
  23#define QCOM_RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY     0x62636370
  24#define QCOM_RPM_SMD_KEY_RATE                           0x007a484b
  25#define QCOM_RPM_SMD_KEY_ENABLE                         0x62616e45
  26#define QCOM_RPM_SMD_KEY_STATE                          0x54415453
  27#define QCOM_RPM_SCALING_ENABLE_ID                      0x2
  28
  29#define __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id, stat_id,  \
  30                             key)                                             \
  31        static struct clk_smd_rpm _platform##_##_active;                      \
  32        static struct clk_smd_rpm _platform##_##_name = {                     \
  33                .rpm_res_type = (type),                                       \
  34                .rpm_clk_id = (r_id),                                         \
  35                .rpm_status_id = (stat_id),                                   \
  36                .rpm_key = (key),                                             \
  37                .peer = &_platform##_##_active,                               \
  38                .rate = INT_MAX,                                              \
  39                .hw.init = &(struct clk_init_data){                           \
  40                        .ops = &clk_smd_rpm_ops,                              \
  41                        .name = #_name,                                       \
  42                        .parent_names = (const char *[]){ "xo_board" },       \
  43                        .num_parents = 1,                                     \
  44                },                                                            \
  45        };                                                                    \
  46        static struct clk_smd_rpm _platform##_##_active = {                   \
  47                .rpm_res_type = (type),                                       \
  48                .rpm_clk_id = (r_id),                                         \
  49                .rpm_status_id = (stat_id),                                   \
  50                .active_only = true,                                          \
  51                .rpm_key = (key),                                             \
  52                .peer = &_platform##_##_name,                                 \
  53                .rate = INT_MAX,                                              \
  54                .hw.init = &(struct clk_init_data){                           \
  55                        .ops = &clk_smd_rpm_ops,                              \
  56                        .name = #_active,                                     \
  57                        .parent_names = (const char *[]){ "xo_board" },       \
  58                        .num_parents = 1,                                     \
  59                },                                                            \
  60        }
  61
  62#define __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type, r_id,    \
  63                                    stat_id, r, key)                          \
  64        static struct clk_smd_rpm _platform##_##_active;                      \
  65        static struct clk_smd_rpm _platform##_##_name = {                     \
  66                .rpm_res_type = (type),                                       \
  67                .rpm_clk_id = (r_id),                                         \
  68                .rpm_status_id = (stat_id),                                   \
  69                .rpm_key = (key),                                             \
  70                .branch = true,                                               \
  71                .peer = &_platform##_##_active,                               \
  72                .rate = (r),                                                  \
  73                .hw.init = &(struct clk_init_data){                           \
  74                        .ops = &clk_smd_rpm_branch_ops,                       \
  75                        .name = #_name,                                       \
  76                        .parent_names = (const char *[]){ "xo_board" },       \
  77                        .num_parents = 1,                                     \
  78                },                                                            \
  79        };                                                                    \
  80        static struct clk_smd_rpm _platform##_##_active = {                   \
  81                .rpm_res_type = (type),                                       \
  82                .rpm_clk_id = (r_id),                                         \
  83                .rpm_status_id = (stat_id),                                   \
  84                .active_only = true,                                          \
  85                .rpm_key = (key),                                             \
  86                .branch = true,                                               \
  87                .peer = &_platform##_##_name,                                 \
  88                .rate = (r),                                                  \
  89                .hw.init = &(struct clk_init_data){                           \
  90                        .ops = &clk_smd_rpm_branch_ops,                       \
  91                        .name = #_active,                                     \
  92                        .parent_names = (const char *[]){ "xo_board" },       \
  93                        .num_parents = 1,                                     \
  94                },                                                            \
  95        }
  96
  97#define DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id)             \
  98                __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id,   \
  99                0, QCOM_RPM_SMD_KEY_RATE)
 100
 101#define DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type, r_id, r)   \
 102                __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type,  \
 103                r_id, 0, r, QCOM_RPM_SMD_KEY_ENABLE)
 104
 105#define DEFINE_CLK_SMD_RPM_QDSS(_platform, _name, _active, type, r_id)        \
 106                __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id,   \
 107                0, QCOM_RPM_SMD_KEY_STATE)
 108
 109#define DEFINE_CLK_SMD_RPM_XO_BUFFER(_platform, _name, _active, r_id)         \
 110                __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active,        \
 111                QCOM_SMD_RPM_CLK_BUF_A, r_id, 0, 1000,                        \
 112                QCOM_RPM_KEY_SOFTWARE_ENABLE)
 113
 114#define DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(_platform, _name, _active, r_id) \
 115                __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active,        \
 116                QCOM_SMD_RPM_CLK_BUF_A, r_id, 0, 1000,                        \
 117                QCOM_RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY)
 118
 119#define to_clk_smd_rpm(_hw) container_of(_hw, struct clk_smd_rpm, hw)
 120
 121struct clk_smd_rpm {
 122        const int rpm_res_type;
 123        const int rpm_key;
 124        const int rpm_clk_id;
 125        const int rpm_status_id;
 126        const bool active_only;
 127        bool enabled;
 128        bool branch;
 129        struct clk_smd_rpm *peer;
 130        struct clk_hw hw;
 131        unsigned long rate;
 132        struct qcom_smd_rpm *rpm;
 133};
 134
 135struct clk_smd_rpm_req {
 136        __le32 key;
 137        __le32 nbytes;
 138        __le32 value;
 139};
 140
 141struct rpm_cc {
 142        struct qcom_rpm *rpm;
 143        struct clk_smd_rpm **clks;
 144        size_t num_clks;
 145};
 146
 147struct rpm_smd_clk_desc {
 148        struct clk_smd_rpm **clks;
 149        size_t num_clks;
 150};
 151
 152static DEFINE_MUTEX(rpm_smd_clk_lock);
 153
 154static int clk_smd_rpm_handoff(struct clk_smd_rpm *r)
 155{
 156        int ret;
 157        struct clk_smd_rpm_req req = {
 158                .key = cpu_to_le32(r->rpm_key),
 159                .nbytes = cpu_to_le32(sizeof(u32)),
 160                .value = cpu_to_le32(r->branch ? 1 : INT_MAX),
 161        };
 162
 163        ret = qcom_rpm_smd_write(r->rpm, QCOM_SMD_RPM_ACTIVE_STATE,
 164                                 r->rpm_res_type, r->rpm_clk_id, &req,
 165                                 sizeof(req));
 166        if (ret)
 167                return ret;
 168        ret = qcom_rpm_smd_write(r->rpm, QCOM_SMD_RPM_SLEEP_STATE,
 169                                 r->rpm_res_type, r->rpm_clk_id, &req,
 170                                 sizeof(req));
 171        if (ret)
 172                return ret;
 173
 174        return 0;
 175}
 176
 177static int clk_smd_rpm_set_rate_active(struct clk_smd_rpm *r,
 178                                       unsigned long rate)
 179{
 180        struct clk_smd_rpm_req req = {
 181                .key = cpu_to_le32(r->rpm_key),
 182                .nbytes = cpu_to_le32(sizeof(u32)),
 183                .value = cpu_to_le32(DIV_ROUND_UP(rate, 1000)), /* to kHz */
 184        };
 185
 186        return qcom_rpm_smd_write(r->rpm, QCOM_SMD_RPM_ACTIVE_STATE,
 187                                  r->rpm_res_type, r->rpm_clk_id, &req,
 188                                  sizeof(req));
 189}
 190
 191static int clk_smd_rpm_set_rate_sleep(struct clk_smd_rpm *r,
 192                                      unsigned long rate)
 193{
 194        struct clk_smd_rpm_req req = {
 195                .key = cpu_to_le32(r->rpm_key),
 196                .nbytes = cpu_to_le32(sizeof(u32)),
 197                .value = cpu_to_le32(DIV_ROUND_UP(rate, 1000)), /* to kHz */
 198        };
 199
 200        return qcom_rpm_smd_write(r->rpm, QCOM_SMD_RPM_SLEEP_STATE,
 201                                  r->rpm_res_type, r->rpm_clk_id, &req,
 202                                  sizeof(req));
 203}
 204
 205static void to_active_sleep(struct clk_smd_rpm *r, unsigned long rate,
 206                            unsigned long *active, unsigned long *sleep)
 207{
 208        *active = rate;
 209
 210        /*
 211         * Active-only clocks don't care what the rate is during sleep. So,
 212         * they vote for zero.
 213         */
 214        if (r->active_only)
 215                *sleep = 0;
 216        else
 217                *sleep = *active;
 218}
 219
 220static int clk_smd_rpm_prepare(struct clk_hw *hw)
 221{
 222        struct clk_smd_rpm *r = to_clk_smd_rpm(hw);
 223        struct clk_smd_rpm *peer = r->peer;
 224        unsigned long this_rate = 0, this_sleep_rate = 0;
 225        unsigned long peer_rate = 0, peer_sleep_rate = 0;
 226        unsigned long active_rate, sleep_rate;
 227        int ret = 0;
 228
 229        mutex_lock(&rpm_smd_clk_lock);
 230
 231        /* Don't send requests to the RPM if the rate has not been set. */
 232        if (!r->rate)
 233                goto out;
 234
 235        to_active_sleep(r, r->rate, &this_rate, &this_sleep_rate);
 236
 237        /* Take peer clock's rate into account only if it's enabled. */
 238        if (peer->enabled)
 239                to_active_sleep(peer, peer->rate,
 240                                &peer_rate, &peer_sleep_rate);
 241
 242        active_rate = max(this_rate, peer_rate);
 243
 244        if (r->branch)
 245                active_rate = !!active_rate;
 246
 247        ret = clk_smd_rpm_set_rate_active(r, active_rate);
 248        if (ret)
 249                goto out;
 250
 251        sleep_rate = max(this_sleep_rate, peer_sleep_rate);
 252        if (r->branch)
 253                sleep_rate = !!sleep_rate;
 254
 255        ret = clk_smd_rpm_set_rate_sleep(r, sleep_rate);
 256        if (ret)
 257                /* Undo the active set vote and restore it */
 258                ret = clk_smd_rpm_set_rate_active(r, peer_rate);
 259
 260out:
 261        if (!ret)
 262                r->enabled = true;
 263
 264        mutex_unlock(&rpm_smd_clk_lock);
 265
 266        return ret;
 267}
 268
 269static void clk_smd_rpm_unprepare(struct clk_hw *hw)
 270{
 271        struct clk_smd_rpm *r = to_clk_smd_rpm(hw);
 272        struct clk_smd_rpm *peer = r->peer;
 273        unsigned long peer_rate = 0, peer_sleep_rate = 0;
 274        unsigned long active_rate, sleep_rate;
 275        int ret;
 276
 277        mutex_lock(&rpm_smd_clk_lock);
 278
 279        if (!r->rate)
 280                goto out;
 281
 282        /* Take peer clock's rate into account only if it's enabled. */
 283        if (peer->enabled)
 284                to_active_sleep(peer, peer->rate, &peer_rate,
 285                                &peer_sleep_rate);
 286
 287        active_rate = r->branch ? !!peer_rate : peer_rate;
 288        ret = clk_smd_rpm_set_rate_active(r, active_rate);
 289        if (ret)
 290                goto out;
 291
 292        sleep_rate = r->branch ? !!peer_sleep_rate : peer_sleep_rate;
 293        ret = clk_smd_rpm_set_rate_sleep(r, sleep_rate);
 294        if (ret)
 295                goto out;
 296
 297        r->enabled = false;
 298
 299out:
 300        mutex_unlock(&rpm_smd_clk_lock);
 301}
 302
 303static int clk_smd_rpm_set_rate(struct clk_hw *hw, unsigned long rate,
 304                                unsigned long parent_rate)
 305{
 306        struct clk_smd_rpm *r = to_clk_smd_rpm(hw);
 307        struct clk_smd_rpm *peer = r->peer;
 308        unsigned long active_rate, sleep_rate;
 309        unsigned long this_rate = 0, this_sleep_rate = 0;
 310        unsigned long peer_rate = 0, peer_sleep_rate = 0;
 311        int ret = 0;
 312
 313        mutex_lock(&rpm_smd_clk_lock);
 314
 315        if (!r->enabled)
 316                goto out;
 317
 318        to_active_sleep(r, rate, &this_rate, &this_sleep_rate);
 319
 320        /* Take peer clock's rate into account only if it's enabled. */
 321        if (peer->enabled)
 322                to_active_sleep(peer, peer->rate,
 323                                &peer_rate, &peer_sleep_rate);
 324
 325        active_rate = max(this_rate, peer_rate);
 326        ret = clk_smd_rpm_set_rate_active(r, active_rate);
 327        if (ret)
 328                goto out;
 329
 330        sleep_rate = max(this_sleep_rate, peer_sleep_rate);
 331        ret = clk_smd_rpm_set_rate_sleep(r, sleep_rate);
 332        if (ret)
 333                goto out;
 334
 335        r->rate = rate;
 336
 337out:
 338        mutex_unlock(&rpm_smd_clk_lock);
 339
 340        return ret;
 341}
 342
 343static long clk_smd_rpm_round_rate(struct clk_hw *hw, unsigned long rate,
 344                                   unsigned long *parent_rate)
 345{
 346        /*
 347         * RPM handles rate rounding and we don't have a way to
 348         * know what the rate will be, so just return whatever
 349         * rate is requested.
 350         */
 351        return rate;
 352}
 353
 354static unsigned long clk_smd_rpm_recalc_rate(struct clk_hw *hw,
 355                                             unsigned long parent_rate)
 356{
 357        struct clk_smd_rpm *r = to_clk_smd_rpm(hw);
 358
 359        /*
 360         * RPM handles rate rounding and we don't have a way to
 361         * know what the rate will be, so just return whatever
 362         * rate was set.
 363         */
 364        return r->rate;
 365}
 366
 367static int clk_smd_rpm_enable_scaling(struct qcom_smd_rpm *rpm)
 368{
 369        int ret;
 370        struct clk_smd_rpm_req req = {
 371                .key = cpu_to_le32(QCOM_RPM_SMD_KEY_ENABLE),
 372                .nbytes = cpu_to_le32(sizeof(u32)),
 373                .value = cpu_to_le32(1),
 374        };
 375
 376        ret = qcom_rpm_smd_write(rpm, QCOM_SMD_RPM_SLEEP_STATE,
 377                                 QCOM_SMD_RPM_MISC_CLK,
 378                                 QCOM_RPM_SCALING_ENABLE_ID, &req, sizeof(req));
 379        if (ret) {
 380                pr_err("RPM clock scaling (sleep set) not enabled!\n");
 381                return ret;
 382        }
 383
 384        ret = qcom_rpm_smd_write(rpm, QCOM_SMD_RPM_ACTIVE_STATE,
 385                                 QCOM_SMD_RPM_MISC_CLK,
 386                                 QCOM_RPM_SCALING_ENABLE_ID, &req, sizeof(req));
 387        if (ret) {
 388                pr_err("RPM clock scaling (active set) not enabled!\n");
 389                return ret;
 390        }
 391
 392        pr_debug("%s: RPM clock scaling is enabled\n", __func__);
 393        return 0;
 394}
 395
 396static const struct clk_ops clk_smd_rpm_ops = {
 397        .prepare        = clk_smd_rpm_prepare,
 398        .unprepare      = clk_smd_rpm_unprepare,
 399        .set_rate       = clk_smd_rpm_set_rate,
 400        .round_rate     = clk_smd_rpm_round_rate,
 401        .recalc_rate    = clk_smd_rpm_recalc_rate,
 402};
 403
 404static const struct clk_ops clk_smd_rpm_branch_ops = {
 405        .prepare        = clk_smd_rpm_prepare,
 406        .unprepare      = clk_smd_rpm_unprepare,
 407};
 408
 409/* msm8916 */
 410DEFINE_CLK_SMD_RPM(msm8916, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
 411DEFINE_CLK_SMD_RPM(msm8916, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
 412DEFINE_CLK_SMD_RPM(msm8916, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
 413DEFINE_CLK_SMD_RPM_QDSS(msm8916, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1);
 414DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, bb_clk1, bb_clk1_a, 1);
 415DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, bb_clk2, bb_clk2_a, 2);
 416DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, rf_clk1, rf_clk1_a, 4);
 417DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, rf_clk2, rf_clk2_a, 5);
 418DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, bb_clk1_pin, bb_clk1_a_pin, 1);
 419DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, bb_clk2_pin, bb_clk2_a_pin, 2);
 420DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, rf_clk1_pin, rf_clk1_a_pin, 4);
 421DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, rf_clk2_pin, rf_clk2_a_pin, 5);
 422
 423static struct clk_smd_rpm *msm8916_clks[] = {
 424        [RPM_SMD_PCNOC_CLK]             = &msm8916_pcnoc_clk,
 425        [RPM_SMD_PCNOC_A_CLK]           = &msm8916_pcnoc_a_clk,
 426        [RPM_SMD_SNOC_CLK]              = &msm8916_snoc_clk,
 427        [RPM_SMD_SNOC_A_CLK]            = &msm8916_snoc_a_clk,
 428        [RPM_SMD_BIMC_CLK]              = &msm8916_bimc_clk,
 429        [RPM_SMD_BIMC_A_CLK]            = &msm8916_bimc_a_clk,
 430        [RPM_SMD_QDSS_CLK]              = &msm8916_qdss_clk,
 431        [RPM_SMD_QDSS_A_CLK]            = &msm8916_qdss_a_clk,
 432        [RPM_SMD_BB_CLK1]               = &msm8916_bb_clk1,
 433        [RPM_SMD_BB_CLK1_A]             = &msm8916_bb_clk1_a,
 434        [RPM_SMD_BB_CLK2]               = &msm8916_bb_clk2,
 435        [RPM_SMD_BB_CLK2_A]             = &msm8916_bb_clk2_a,
 436        [RPM_SMD_RF_CLK1]               = &msm8916_rf_clk1,
 437        [RPM_SMD_RF_CLK1_A]             = &msm8916_rf_clk1_a,
 438        [RPM_SMD_RF_CLK2]               = &msm8916_rf_clk2,
 439        [RPM_SMD_RF_CLK2_A]             = &msm8916_rf_clk2_a,
 440        [RPM_SMD_BB_CLK1_PIN]           = &msm8916_bb_clk1_pin,
 441        [RPM_SMD_BB_CLK1_A_PIN]         = &msm8916_bb_clk1_a_pin,
 442        [RPM_SMD_BB_CLK2_PIN]           = &msm8916_bb_clk2_pin,
 443        [RPM_SMD_BB_CLK2_A_PIN]         = &msm8916_bb_clk2_a_pin,
 444        [RPM_SMD_RF_CLK1_PIN]           = &msm8916_rf_clk1_pin,
 445        [RPM_SMD_RF_CLK1_A_PIN]         = &msm8916_rf_clk1_a_pin,
 446        [RPM_SMD_RF_CLK2_PIN]           = &msm8916_rf_clk2_pin,
 447        [RPM_SMD_RF_CLK2_A_PIN]         = &msm8916_rf_clk2_a_pin,
 448};
 449
 450static const struct rpm_smd_clk_desc rpm_clk_msm8916 = {
 451        .clks = msm8916_clks,
 452        .num_clks = ARRAY_SIZE(msm8916_clks),
 453};
 454
 455/* msm8974 */
 456DEFINE_CLK_SMD_RPM(msm8974, pnoc_clk, pnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
 457DEFINE_CLK_SMD_RPM(msm8974, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
 458DEFINE_CLK_SMD_RPM(msm8974, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
 459DEFINE_CLK_SMD_RPM(msm8974, mmssnoc_ahb_clk, mmssnoc_ahb_a_clk, QCOM_SMD_RPM_BUS_CLK, 3);
 460DEFINE_CLK_SMD_RPM(msm8974, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
 461DEFINE_CLK_SMD_RPM(msm8974, gfx3d_clk_src, gfx3d_a_clk_src, QCOM_SMD_RPM_MEM_CLK, 1);
 462DEFINE_CLK_SMD_RPM(msm8974, ocmemgx_clk, ocmemgx_a_clk, QCOM_SMD_RPM_MEM_CLK, 2);
 463DEFINE_CLK_SMD_RPM_QDSS(msm8974, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1);
 464DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_d0, cxo_d0_a, 1);
 465DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_d1, cxo_d1_a, 2);
 466DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_a0, cxo_a0_a, 4);
 467DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_a1, cxo_a1_a, 5);
 468DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_a2, cxo_a2_a, 6);
 469DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, diff_clk, diff_a_clk, 7);
 470DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, div_clk1, div_a_clk1, 11);
 471DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, div_clk2, div_a_clk2, 12);
 472DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_d0_pin, cxo_d0_a_pin, 1);
 473DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_d1_pin, cxo_d1_a_pin, 2);
 474DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a0_pin, cxo_a0_a_pin, 4);
 475DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a1_pin, cxo_a1_a_pin, 5);
 476DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a2_pin, cxo_a2_a_pin, 6);
 477
 478static struct clk_smd_rpm *msm8974_clks[] = {
 479        [RPM_SMD_PNOC_CLK]              = &msm8974_pnoc_clk,
 480        [RPM_SMD_PNOC_A_CLK]            = &msm8974_pnoc_a_clk,
 481        [RPM_SMD_SNOC_CLK]              = &msm8974_snoc_clk,
 482        [RPM_SMD_SNOC_A_CLK]            = &msm8974_snoc_a_clk,
 483        [RPM_SMD_CNOC_CLK]              = &msm8974_cnoc_clk,
 484        [RPM_SMD_CNOC_A_CLK]            = &msm8974_cnoc_a_clk,
 485        [RPM_SMD_MMSSNOC_AHB_CLK]       = &msm8974_mmssnoc_ahb_clk,
 486        [RPM_SMD_MMSSNOC_AHB_A_CLK]     = &msm8974_mmssnoc_ahb_a_clk,
 487        [RPM_SMD_BIMC_CLK]              = &msm8974_bimc_clk,
 488        [RPM_SMD_BIMC_A_CLK]            = &msm8974_bimc_a_clk,
 489        [RPM_SMD_OCMEMGX_CLK]           = &msm8974_ocmemgx_clk,
 490        [RPM_SMD_OCMEMGX_A_CLK]         = &msm8974_ocmemgx_a_clk,
 491        [RPM_SMD_QDSS_CLK]              = &msm8974_qdss_clk,
 492        [RPM_SMD_QDSS_A_CLK]            = &msm8974_qdss_a_clk,
 493        [RPM_SMD_CXO_D0]                = &msm8974_cxo_d0,
 494        [RPM_SMD_CXO_D0_A]              = &msm8974_cxo_d0_a,
 495        [RPM_SMD_CXO_D1]                = &msm8974_cxo_d1,
 496        [RPM_SMD_CXO_D1_A]              = &msm8974_cxo_d1_a,
 497        [RPM_SMD_CXO_A0]                = &msm8974_cxo_a0,
 498        [RPM_SMD_CXO_A0_A]              = &msm8974_cxo_a0_a,
 499        [RPM_SMD_CXO_A1]                = &msm8974_cxo_a1,
 500        [RPM_SMD_CXO_A1_A]              = &msm8974_cxo_a1_a,
 501        [RPM_SMD_CXO_A2]                = &msm8974_cxo_a2,
 502        [RPM_SMD_CXO_A2_A]              = &msm8974_cxo_a2_a,
 503        [RPM_SMD_DIFF_CLK]              = &msm8974_diff_clk,
 504        [RPM_SMD_DIFF_A_CLK]            = &msm8974_diff_a_clk,
 505        [RPM_SMD_DIV_CLK1]              = &msm8974_div_clk1,
 506        [RPM_SMD_DIV_A_CLK1]            = &msm8974_div_a_clk1,
 507        [RPM_SMD_DIV_CLK2]              = &msm8974_div_clk2,
 508        [RPM_SMD_DIV_A_CLK2]            = &msm8974_div_a_clk2,
 509        [RPM_SMD_CXO_D0_PIN]            = &msm8974_cxo_d0_pin,
 510        [RPM_SMD_CXO_D0_A_PIN]          = &msm8974_cxo_d0_a_pin,
 511        [RPM_SMD_CXO_D1_PIN]            = &msm8974_cxo_d1_pin,
 512        [RPM_SMD_CXO_D1_A_PIN]          = &msm8974_cxo_d1_a_pin,
 513        [RPM_SMD_CXO_A0_PIN]            = &msm8974_cxo_a0_pin,
 514        [RPM_SMD_CXO_A0_A_PIN]          = &msm8974_cxo_a0_a_pin,
 515        [RPM_SMD_CXO_A1_PIN]            = &msm8974_cxo_a1_pin,
 516        [RPM_SMD_CXO_A1_A_PIN]          = &msm8974_cxo_a1_a_pin,
 517        [RPM_SMD_CXO_A2_PIN]            = &msm8974_cxo_a2_pin,
 518        [RPM_SMD_CXO_A2_A_PIN]          = &msm8974_cxo_a2_a_pin,
 519};
 520
 521static const struct rpm_smd_clk_desc rpm_clk_msm8974 = {
 522        .clks = msm8974_clks,
 523        .num_clks = ARRAY_SIZE(msm8974_clks),
 524};
 525
 526/* msm8996 */
 527DEFINE_CLK_SMD_RPM(msm8996, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
 528DEFINE_CLK_SMD_RPM(msm8996, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
 529DEFINE_CLK_SMD_RPM(msm8996, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
 530DEFINE_CLK_SMD_RPM(msm8996, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
 531DEFINE_CLK_SMD_RPM(msm8996, mmssnoc_axi_rpm_clk, mmssnoc_axi_rpm_a_clk,
 532                   QCOM_SMD_RPM_MMAXI_CLK, 0);
 533DEFINE_CLK_SMD_RPM(msm8996, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0);
 534DEFINE_CLK_SMD_RPM(msm8996, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0);
 535DEFINE_CLK_SMD_RPM_BRANCH(msm8996, aggre1_noc_clk, aggre1_noc_a_clk,
 536                          QCOM_SMD_RPM_AGGR_CLK, 1, 1000);
 537DEFINE_CLK_SMD_RPM_BRANCH(msm8996, aggre2_noc_clk, aggre2_noc_a_clk,
 538                          QCOM_SMD_RPM_AGGR_CLK, 2, 1000);
 539DEFINE_CLK_SMD_RPM_QDSS(msm8996, qdss_clk, qdss_a_clk,
 540                        QCOM_SMD_RPM_MISC_CLK, 1);
 541DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, bb_clk1, bb_clk1_a, 1);
 542DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, bb_clk2, bb_clk2_a, 2);
 543DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, rf_clk1, rf_clk1_a, 4);
 544DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, rf_clk2, rf_clk2_a, 5);
 545DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, ln_bb_clk, ln_bb_a_clk, 8);
 546DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk1, div_clk1_a, 0xb);
 547DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk2, div_clk2_a, 0xc);
 548DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk3, div_clk3_a, 0xd);
 549DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, bb_clk1_pin, bb_clk1_a_pin, 1);
 550DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, bb_clk2_pin, bb_clk2_a_pin, 2);
 551DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, rf_clk1_pin, rf_clk1_a_pin, 4);
 552DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, rf_clk2_pin, rf_clk2_a_pin, 5);
 553
 554static struct clk_smd_rpm *msm8996_clks[] = {
 555        [RPM_SMD_PCNOC_CLK] = &msm8996_pcnoc_clk,
 556        [RPM_SMD_PCNOC_A_CLK] = &msm8996_pcnoc_a_clk,
 557        [RPM_SMD_SNOC_CLK] = &msm8996_snoc_clk,
 558        [RPM_SMD_SNOC_A_CLK] = &msm8996_snoc_a_clk,
 559        [RPM_SMD_CNOC_CLK] = &msm8996_cnoc_clk,
 560        [RPM_SMD_CNOC_A_CLK] = &msm8996_cnoc_a_clk,
 561        [RPM_SMD_BIMC_CLK] = &msm8996_bimc_clk,
 562        [RPM_SMD_BIMC_A_CLK] = &msm8996_bimc_a_clk,
 563        [RPM_SMD_MMAXI_CLK] = &msm8996_mmssnoc_axi_rpm_clk,
 564        [RPM_SMD_MMAXI_A_CLK] = &msm8996_mmssnoc_axi_rpm_a_clk,
 565        [RPM_SMD_IPA_CLK] = &msm8996_ipa_clk,
 566        [RPM_SMD_IPA_A_CLK] = &msm8996_ipa_a_clk,
 567        [RPM_SMD_CE1_CLK] = &msm8996_ce1_clk,
 568        [RPM_SMD_CE1_A_CLK] = &msm8996_ce1_a_clk,
 569        [RPM_SMD_AGGR1_NOC_CLK] = &msm8996_aggre1_noc_clk,
 570        [RPM_SMD_AGGR1_NOC_A_CLK] = &msm8996_aggre1_noc_a_clk,
 571        [RPM_SMD_AGGR2_NOC_CLK] = &msm8996_aggre2_noc_clk,
 572        [RPM_SMD_AGGR2_NOC_A_CLK] = &msm8996_aggre2_noc_a_clk,
 573        [RPM_SMD_QDSS_CLK] = &msm8996_qdss_clk,
 574        [RPM_SMD_QDSS_A_CLK] = &msm8996_qdss_a_clk,
 575        [RPM_SMD_BB_CLK1] = &msm8996_bb_clk1,
 576        [RPM_SMD_BB_CLK1_A] = &msm8996_bb_clk1_a,
 577        [RPM_SMD_BB_CLK2] = &msm8996_bb_clk2,
 578        [RPM_SMD_BB_CLK2_A] = &msm8996_bb_clk2_a,
 579        [RPM_SMD_RF_CLK1] = &msm8996_rf_clk1,
 580        [RPM_SMD_RF_CLK1_A] = &msm8996_rf_clk1_a,
 581        [RPM_SMD_RF_CLK2] = &msm8996_rf_clk2,
 582        [RPM_SMD_RF_CLK2_A] = &msm8996_rf_clk2_a,
 583        [RPM_SMD_LN_BB_CLK] = &msm8996_ln_bb_clk,
 584        [RPM_SMD_LN_BB_A_CLK] = &msm8996_ln_bb_a_clk,
 585        [RPM_SMD_DIV_CLK1] = &msm8996_div_clk1,
 586        [RPM_SMD_DIV_A_CLK1] = &msm8996_div_clk1_a,
 587        [RPM_SMD_DIV_CLK2] = &msm8996_div_clk2,
 588        [RPM_SMD_DIV_A_CLK2] = &msm8996_div_clk2_a,
 589        [RPM_SMD_DIV_CLK3] = &msm8996_div_clk3,
 590        [RPM_SMD_DIV_A_CLK3] = &msm8996_div_clk3_a,
 591        [RPM_SMD_BB_CLK1_PIN] = &msm8996_bb_clk1_pin,
 592        [RPM_SMD_BB_CLK1_A_PIN] = &msm8996_bb_clk1_a_pin,
 593        [RPM_SMD_BB_CLK2_PIN] = &msm8996_bb_clk2_pin,
 594        [RPM_SMD_BB_CLK2_A_PIN] = &msm8996_bb_clk2_a_pin,
 595        [RPM_SMD_RF_CLK1_PIN] = &msm8996_rf_clk1_pin,
 596        [RPM_SMD_RF_CLK1_A_PIN] = &msm8996_rf_clk1_a_pin,
 597        [RPM_SMD_RF_CLK2_PIN] = &msm8996_rf_clk2_pin,
 598        [RPM_SMD_RF_CLK2_A_PIN] = &msm8996_rf_clk2_a_pin,
 599};
 600
 601static const struct rpm_smd_clk_desc rpm_clk_msm8996 = {
 602        .clks = msm8996_clks,
 603        .num_clks = ARRAY_SIZE(msm8996_clks),
 604};
 605
 606/* QCS404 */
 607DEFINE_CLK_SMD_RPM_QDSS(qcs404, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1);
 608
 609DEFINE_CLK_SMD_RPM(qcs404, pnoc_clk, pnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
 610DEFINE_CLK_SMD_RPM(qcs404, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
 611
 612DEFINE_CLK_SMD_RPM(qcs404, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
 613DEFINE_CLK_SMD_RPM(qcs404, bimc_gpu_clk, bimc_gpu_a_clk, QCOM_SMD_RPM_MEM_CLK, 2);
 614
 615DEFINE_CLK_SMD_RPM(qcs404, qpic_clk, qpic_a_clk, QCOM_SMD_RPM_QPIC_CLK, 0);
 616DEFINE_CLK_SMD_RPM(qcs404, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0);
 617
 618DEFINE_CLK_SMD_RPM_XO_BUFFER(qcs404, rf_clk1, rf_clk1_a, 4);
 619DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(qcs404, rf_clk1_pin, rf_clk1_a_pin, 4);
 620
 621DEFINE_CLK_SMD_RPM_XO_BUFFER(qcs404, ln_bb_clk, ln_bb_a_clk, 8);
 622DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(qcs404, ln_bb_clk_pin, ln_bb_clk_a_pin, 8);
 623
 624static struct clk_smd_rpm *qcs404_clks[] = {
 625        [RPM_SMD_QDSS_CLK] = &qcs404_qdss_clk,
 626        [RPM_SMD_QDSS_A_CLK] = &qcs404_qdss_a_clk,
 627        [RPM_SMD_PNOC_CLK] = &qcs404_pnoc_clk,
 628        [RPM_SMD_PNOC_A_CLK] = &qcs404_pnoc_a_clk,
 629        [RPM_SMD_SNOC_CLK] = &qcs404_snoc_clk,
 630        [RPM_SMD_SNOC_A_CLK] = &qcs404_snoc_a_clk,
 631        [RPM_SMD_BIMC_CLK] = &qcs404_bimc_clk,
 632        [RPM_SMD_BIMC_A_CLK] = &qcs404_bimc_a_clk,
 633        [RPM_SMD_BIMC_GPU_CLK] = &qcs404_bimc_gpu_clk,
 634        [RPM_SMD_BIMC_GPU_A_CLK] = &qcs404_bimc_gpu_a_clk,
 635        [RPM_SMD_QPIC_CLK] = &qcs404_qpic_clk,
 636        [RPM_SMD_QPIC_CLK_A] = &qcs404_qpic_a_clk,
 637        [RPM_SMD_CE1_CLK] = &qcs404_ce1_clk,
 638        [RPM_SMD_CE1_A_CLK] = &qcs404_ce1_a_clk,
 639        [RPM_SMD_RF_CLK1] = &qcs404_rf_clk1,
 640        [RPM_SMD_RF_CLK1_A] = &qcs404_rf_clk1_a,
 641        [RPM_SMD_LN_BB_CLK] = &qcs404_ln_bb_clk,
 642        [RPM_SMD_LN_BB_A_CLK] = &qcs404_ln_bb_a_clk,
 643};
 644
 645static const struct rpm_smd_clk_desc rpm_clk_qcs404 = {
 646        .clks = qcs404_clks,
 647        .num_clks = ARRAY_SIZE(qcs404_clks),
 648};
 649
 650/* msm8998 */
 651DEFINE_CLK_SMD_RPM(msm8998, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
 652DEFINE_CLK_SMD_RPM(msm8998, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
 653DEFINE_CLK_SMD_RPM(msm8998, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0);
 654DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, div_clk1, div_clk1_a, 0xb);
 655DEFINE_CLK_SMD_RPM(msm8998, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0);
 656DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, ln_bb_clk1, ln_bb_clk1_a, 1);
 657DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, ln_bb_clk2, ln_bb_clk2_a, 2);
 658DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8998, ln_bb_clk3_pin, ln_bb_clk3_a_pin,
 659                                     3);
 660DEFINE_CLK_SMD_RPM(msm8998, mmssnoc_axi_rpm_clk, mmssnoc_axi_rpm_a_clk,
 661                   QCOM_SMD_RPM_MMAXI_CLK, 0);
 662DEFINE_CLK_SMD_RPM(msm8998, aggre1_noc_clk, aggre1_noc_a_clk,
 663                   QCOM_SMD_RPM_AGGR_CLK, 1);
 664DEFINE_CLK_SMD_RPM(msm8998, aggre2_noc_clk, aggre2_noc_a_clk,
 665                   QCOM_SMD_RPM_AGGR_CLK, 2);
 666DEFINE_CLK_SMD_RPM_QDSS(msm8998, qdss_clk, qdss_a_clk,
 667                        QCOM_SMD_RPM_MISC_CLK, 1);
 668DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, rf_clk1, rf_clk1_a, 4);
 669DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8998, rf_clk2_pin, rf_clk2_a_pin, 5);
 670DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, rf_clk3, rf_clk3_a, 6);
 671DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8998, rf_clk3_pin, rf_clk3_a_pin, 6);
 672static struct clk_smd_rpm *msm8998_clks[] = {
 673        [RPM_SMD_SNOC_CLK] = &msm8998_snoc_clk,
 674        [RPM_SMD_SNOC_A_CLK] = &msm8998_snoc_a_clk,
 675        [RPM_SMD_CNOC_CLK] = &msm8998_cnoc_clk,
 676        [RPM_SMD_CNOC_A_CLK] = &msm8998_cnoc_a_clk,
 677        [RPM_SMD_CE1_CLK] = &msm8998_ce1_clk,
 678        [RPM_SMD_CE1_A_CLK] = &msm8998_ce1_a_clk,
 679        [RPM_SMD_DIV_CLK1] = &msm8998_div_clk1,
 680        [RPM_SMD_DIV_A_CLK1] = &msm8998_div_clk1_a,
 681        [RPM_SMD_IPA_CLK] = &msm8998_ipa_clk,
 682        [RPM_SMD_IPA_A_CLK] = &msm8998_ipa_a_clk,
 683        [RPM_SMD_LN_BB_CLK1] = &msm8998_ln_bb_clk1,
 684        [RPM_SMD_LN_BB_CLK1_A] = &msm8998_ln_bb_clk1_a,
 685        [RPM_SMD_LN_BB_CLK2] = &msm8998_ln_bb_clk2,
 686        [RPM_SMD_LN_BB_CLK2_A] = &msm8998_ln_bb_clk2_a,
 687        [RPM_SMD_LN_BB_CLK3_PIN] = &msm8998_ln_bb_clk3_pin,
 688        [RPM_SMD_LN_BB_CLK3_A_PIN] = &msm8998_ln_bb_clk3_a_pin,
 689        [RPM_SMD_MMAXI_CLK] = &msm8998_mmssnoc_axi_rpm_clk,
 690        [RPM_SMD_MMAXI_A_CLK] = &msm8998_mmssnoc_axi_rpm_a_clk,
 691        [RPM_SMD_AGGR1_NOC_CLK] = &msm8998_aggre1_noc_clk,
 692        [RPM_SMD_AGGR1_NOC_A_CLK] = &msm8998_aggre1_noc_a_clk,
 693        [RPM_SMD_AGGR2_NOC_CLK] = &msm8998_aggre2_noc_clk,
 694        [RPM_SMD_AGGR2_NOC_A_CLK] = &msm8998_aggre2_noc_a_clk,
 695        [RPM_SMD_QDSS_CLK] = &msm8998_qdss_clk,
 696        [RPM_SMD_QDSS_A_CLK] = &msm8998_qdss_a_clk,
 697        [RPM_SMD_RF_CLK1] = &msm8998_rf_clk1,
 698        [RPM_SMD_RF_CLK1_A] = &msm8998_rf_clk1_a,
 699        [RPM_SMD_RF_CLK2_PIN] = &msm8998_rf_clk2_pin,
 700        [RPM_SMD_RF_CLK2_A_PIN] = &msm8998_rf_clk2_a_pin,
 701        [RPM_SMD_RF_CLK3] = &msm8998_rf_clk3,
 702        [RPM_SMD_RF_CLK3_A] = &msm8998_rf_clk3_a,
 703        [RPM_SMD_RF_CLK3_PIN] = &msm8998_rf_clk3_pin,
 704        [RPM_SMD_RF_CLK3_A_PIN] = &msm8998_rf_clk3_a_pin,
 705};
 706
 707static const struct rpm_smd_clk_desc rpm_clk_msm8998 = {
 708        .clks = msm8998_clks,
 709        .num_clks = ARRAY_SIZE(msm8998_clks),
 710};
 711
 712static const struct of_device_id rpm_smd_clk_match_table[] = {
 713        { .compatible = "qcom,rpmcc-msm8916", .data = &rpm_clk_msm8916 },
 714        { .compatible = "qcom,rpmcc-msm8974", .data = &rpm_clk_msm8974 },
 715        { .compatible = "qcom,rpmcc-msm8996", .data = &rpm_clk_msm8996 },
 716        { .compatible = "qcom,rpmcc-msm8998", .data = &rpm_clk_msm8998 },
 717        { .compatible = "qcom,rpmcc-qcs404",  .data = &rpm_clk_qcs404  },
 718        { }
 719};
 720MODULE_DEVICE_TABLE(of, rpm_smd_clk_match_table);
 721
 722static struct clk_hw *qcom_smdrpm_clk_hw_get(struct of_phandle_args *clkspec,
 723                                             void *data)
 724{
 725        struct rpm_cc *rcc = data;
 726        unsigned int idx = clkspec->args[0];
 727
 728        if (idx >= rcc->num_clks) {
 729                pr_err("%s: invalid index %u\n", __func__, idx);
 730                return ERR_PTR(-EINVAL);
 731        }
 732
 733        return rcc->clks[idx] ? &rcc->clks[idx]->hw : ERR_PTR(-ENOENT);
 734}
 735
 736static int rpm_smd_clk_probe(struct platform_device *pdev)
 737{
 738        struct rpm_cc *rcc;
 739        int ret;
 740        size_t num_clks, i;
 741        struct qcom_smd_rpm *rpm;
 742        struct clk_smd_rpm **rpm_smd_clks;
 743        const struct rpm_smd_clk_desc *desc;
 744
 745        rpm = dev_get_drvdata(pdev->dev.parent);
 746        if (!rpm) {
 747                dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n");
 748                return -ENODEV;
 749        }
 750
 751        desc = of_device_get_match_data(&pdev->dev);
 752        if (!desc)
 753                return -EINVAL;
 754
 755        rpm_smd_clks = desc->clks;
 756        num_clks = desc->num_clks;
 757
 758        rcc = devm_kzalloc(&pdev->dev, sizeof(*rcc), GFP_KERNEL);
 759        if (!rcc)
 760                return -ENOMEM;
 761
 762        rcc->clks = rpm_smd_clks;
 763        rcc->num_clks = num_clks;
 764
 765        for (i = 0; i < num_clks; i++) {
 766                if (!rpm_smd_clks[i])
 767                        continue;
 768
 769                rpm_smd_clks[i]->rpm = rpm;
 770
 771                ret = clk_smd_rpm_handoff(rpm_smd_clks[i]);
 772                if (ret)
 773                        goto err;
 774        }
 775
 776        ret = clk_smd_rpm_enable_scaling(rpm);
 777        if (ret)
 778                goto err;
 779
 780        for (i = 0; i < num_clks; i++) {
 781                if (!rpm_smd_clks[i])
 782                        continue;
 783
 784                ret = devm_clk_hw_register(&pdev->dev, &rpm_smd_clks[i]->hw);
 785                if (ret)
 786                        goto err;
 787        }
 788
 789        ret = devm_of_clk_add_hw_provider(&pdev->dev, qcom_smdrpm_clk_hw_get,
 790                                     rcc);
 791        if (ret)
 792                goto err;
 793
 794        return 0;
 795err:
 796        dev_err(&pdev->dev, "Error registering SMD clock driver (%d)\n", ret);
 797        return ret;
 798}
 799
 800static struct platform_driver rpm_smd_clk_driver = {
 801        .driver = {
 802                .name = "qcom-clk-smd-rpm",
 803                .of_match_table = rpm_smd_clk_match_table,
 804        },
 805        .probe = rpm_smd_clk_probe,
 806};
 807
 808static int __init rpm_smd_clk_init(void)
 809{
 810        return platform_driver_register(&rpm_smd_clk_driver);
 811}
 812core_initcall(rpm_smd_clk_init);
 813
 814static void __exit rpm_smd_clk_exit(void)
 815{
 816        platform_driver_unregister(&rpm_smd_clk_driver);
 817}
 818module_exit(rpm_smd_clk_exit);
 819
 820MODULE_DESCRIPTION("Qualcomm RPM over SMD Clock Controller Driver");
 821MODULE_LICENSE("GPL v2");
 822MODULE_ALIAS("platform:qcom-clk-smd-rpm");
 823