lcc-mdm9615.c (14225B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (c) 2014, The Linux Foundation. All rights reserved. 4 * Copyright (c) BayLibre, SAS. 5 * Author : Neil Armstrong <narmstrong@baylibre.com> 6 */ 7 8#include <linux/kernel.h> 9#include <linux/bitops.h> 10#include <linux/err.h> 11#include <linux/platform_device.h> 12#include <linux/module.h> 13#include <linux/of.h> 14#include <linux/of_device.h> 15#include <linux/clk-provider.h> 16#include <linux/regmap.h> 17 18#include <dt-bindings/clock/qcom,lcc-mdm9615.h> 19 20#include "common.h" 21#include "clk-regmap.h" 22#include "clk-pll.h" 23#include "clk-rcg.h" 24#include "clk-branch.h" 25#include "clk-regmap-divider.h" 26#include "clk-regmap-mux.h" 27 28static struct clk_pll pll4 = { 29 .l_reg = 0x4, 30 .m_reg = 0x8, 31 .n_reg = 0xc, 32 .config_reg = 0x14, 33 .mode_reg = 0x0, 34 .status_reg = 0x18, 35 .status_bit = 16, 36 .clkr.hw.init = &(struct clk_init_data){ 37 .name = "pll4", 38 .parent_names = (const char *[]){ "cxo" }, 39 .num_parents = 1, 40 .ops = &clk_pll_ops, 41 }, 42}; 43 44enum { 45 P_CXO, 46 P_PLL4, 47}; 48 49static const struct parent_map lcc_cxo_pll4_map[] = { 50 { P_CXO, 0 }, 51 { P_PLL4, 2 } 52}; 53 54static const char * const lcc_cxo_pll4[] = { 55 "cxo", 56 "pll4_vote", 57}; 58 59static struct freq_tbl clk_tbl_aif_osr_492[] = { 60 { 512000, P_PLL4, 4, 1, 240 }, 61 { 768000, P_PLL4, 4, 1, 160 }, 62 { 1024000, P_PLL4, 4, 1, 120 }, 63 { 1536000, P_PLL4, 4, 1, 80 }, 64 { 2048000, P_PLL4, 4, 1, 60 }, 65 { 3072000, P_PLL4, 4, 1, 40 }, 66 { 4096000, P_PLL4, 4, 1, 30 }, 67 { 6144000, P_PLL4, 4, 1, 20 }, 68 { 8192000, P_PLL4, 4, 1, 15 }, 69 { 12288000, P_PLL4, 4, 1, 10 }, 70 { 24576000, P_PLL4, 4, 1, 5 }, 71 { 27000000, P_CXO, 1, 0, 0 }, 72 { } 73}; 74 75static struct freq_tbl clk_tbl_aif_osr_393[] = { 76 { 512000, P_PLL4, 4, 1, 192 }, 77 { 768000, P_PLL4, 4, 1, 128 }, 78 { 1024000, P_PLL4, 4, 1, 96 }, 79 { 1536000, P_PLL4, 4, 1, 64 }, 80 { 2048000, P_PLL4, 4, 1, 48 }, 81 { 3072000, P_PLL4, 4, 1, 32 }, 82 { 4096000, P_PLL4, 4, 1, 24 }, 83 { 6144000, P_PLL4, 4, 1, 16 }, 84 { 8192000, P_PLL4, 4, 1, 12 }, 85 { 12288000, P_PLL4, 4, 1, 8 }, 86 { 24576000, P_PLL4, 4, 1, 4 }, 87 { 27000000, P_CXO, 1, 0, 0 }, 88 { } 89}; 90 91static struct clk_rcg mi2s_osr_src = { 92 .ns_reg = 0x48, 93 .md_reg = 0x4c, 94 .mn = { 95 .mnctr_en_bit = 8, 96 .mnctr_reset_bit = 7, 97 .mnctr_mode_shift = 5, 98 .n_val_shift = 24, 99 .m_val_shift = 8, 100 .width = 8, 101 }, 102 .p = { 103 .pre_div_shift = 3, 104 .pre_div_width = 2, 105 }, 106 .s = { 107 .src_sel_shift = 0, 108 .parent_map = lcc_cxo_pll4_map, 109 }, 110 .freq_tbl = clk_tbl_aif_osr_393, 111 .clkr = { 112 .enable_reg = 0x48, 113 .enable_mask = BIT(9), 114 .hw.init = &(struct clk_init_data){ 115 .name = "mi2s_osr_src", 116 .parent_names = lcc_cxo_pll4, 117 .num_parents = 2, 118 .ops = &clk_rcg_ops, 119 .flags = CLK_SET_RATE_GATE, 120 }, 121 }, 122}; 123 124static const char * const lcc_mi2s_parents[] = { 125 "mi2s_osr_src", 126}; 127 128static struct clk_branch mi2s_osr_clk = { 129 .halt_reg = 0x50, 130 .halt_bit = 1, 131 .halt_check = BRANCH_HALT_ENABLE, 132 .clkr = { 133 .enable_reg = 0x48, 134 .enable_mask = BIT(17), 135 .hw.init = &(struct clk_init_data){ 136 .name = "mi2s_osr_clk", 137 .parent_names = lcc_mi2s_parents, 138 .num_parents = 1, 139 .ops = &clk_branch_ops, 140 .flags = CLK_SET_RATE_PARENT, 141 }, 142 }, 143}; 144 145static struct clk_regmap_div mi2s_div_clk = { 146 .reg = 0x48, 147 .shift = 10, 148 .width = 4, 149 .clkr = { 150 .enable_reg = 0x48, 151 .enable_mask = BIT(15), 152 .hw.init = &(struct clk_init_data){ 153 .name = "mi2s_div_clk", 154 .parent_names = lcc_mi2s_parents, 155 .num_parents = 1, 156 .ops = &clk_regmap_div_ops, 157 }, 158 }, 159}; 160 161static struct clk_branch mi2s_bit_div_clk = { 162 .halt_reg = 0x50, 163 .halt_bit = 0, 164 .halt_check = BRANCH_HALT_ENABLE, 165 .clkr = { 166 .enable_reg = 0x48, 167 .enable_mask = BIT(15), 168 .hw.init = &(struct clk_init_data){ 169 .name = "mi2s_bit_div_clk", 170 .parent_names = (const char *[]){ "mi2s_div_clk" }, 171 .num_parents = 1, 172 .ops = &clk_branch_ops, 173 .flags = CLK_SET_RATE_PARENT, 174 }, 175 }, 176}; 177 178static struct clk_regmap_mux mi2s_bit_clk = { 179 .reg = 0x48, 180 .shift = 14, 181 .width = 1, 182 .clkr = { 183 .hw.init = &(struct clk_init_data){ 184 .name = "mi2s_bit_clk", 185 .parent_names = (const char *[]){ 186 "mi2s_bit_div_clk", 187 "mi2s_codec_clk", 188 }, 189 .num_parents = 2, 190 .ops = &clk_regmap_mux_closest_ops, 191 .flags = CLK_SET_RATE_PARENT, 192 }, 193 }, 194}; 195 196#define CLK_AIF_OSR_DIV(prefix, _ns, _md, hr) \ 197static struct clk_rcg prefix##_osr_src = { \ 198 .ns_reg = _ns, \ 199 .md_reg = _md, \ 200 .mn = { \ 201 .mnctr_en_bit = 8, \ 202 .mnctr_reset_bit = 7, \ 203 .mnctr_mode_shift = 5, \ 204 .n_val_shift = 24, \ 205 .m_val_shift = 8, \ 206 .width = 8, \ 207 }, \ 208 .p = { \ 209 .pre_div_shift = 3, \ 210 .pre_div_width = 2, \ 211 }, \ 212 .s = { \ 213 .src_sel_shift = 0, \ 214 .parent_map = lcc_cxo_pll4_map, \ 215 }, \ 216 .freq_tbl = clk_tbl_aif_osr_393, \ 217 .clkr = { \ 218 .enable_reg = _ns, \ 219 .enable_mask = BIT(9), \ 220 .hw.init = &(struct clk_init_data){ \ 221 .name = #prefix "_osr_src", \ 222 .parent_names = lcc_cxo_pll4, \ 223 .num_parents = 2, \ 224 .ops = &clk_rcg_ops, \ 225 .flags = CLK_SET_RATE_GATE, \ 226 }, \ 227 }, \ 228}; \ 229 \ 230static const char * const lcc_##prefix##_parents[] = { \ 231 #prefix "_osr_src", \ 232}; \ 233 \ 234static struct clk_branch prefix##_osr_clk = { \ 235 .halt_reg = hr, \ 236 .halt_bit = 1, \ 237 .halt_check = BRANCH_HALT_ENABLE, \ 238 .clkr = { \ 239 .enable_reg = _ns, \ 240 .enable_mask = BIT(21), \ 241 .hw.init = &(struct clk_init_data){ \ 242 .name = #prefix "_osr_clk", \ 243 .parent_names = lcc_##prefix##_parents, \ 244 .num_parents = 1, \ 245 .ops = &clk_branch_ops, \ 246 .flags = CLK_SET_RATE_PARENT, \ 247 }, \ 248 }, \ 249}; \ 250 \ 251static struct clk_regmap_div prefix##_div_clk = { \ 252 .reg = _ns, \ 253 .shift = 10, \ 254 .width = 8, \ 255 .clkr = { \ 256 .hw.init = &(struct clk_init_data){ \ 257 .name = #prefix "_div_clk", \ 258 .parent_names = lcc_##prefix##_parents, \ 259 .num_parents = 1, \ 260 .ops = &clk_regmap_div_ops, \ 261 }, \ 262 }, \ 263}; \ 264 \ 265static struct clk_branch prefix##_bit_div_clk = { \ 266 .halt_reg = hr, \ 267 .halt_bit = 0, \ 268 .halt_check = BRANCH_HALT_ENABLE, \ 269 .clkr = { \ 270 .enable_reg = _ns, \ 271 .enable_mask = BIT(19), \ 272 .hw.init = &(struct clk_init_data){ \ 273 .name = #prefix "_bit_div_clk", \ 274 .parent_names = (const char *[]){ \ 275 #prefix "_div_clk" \ 276 }, \ 277 .num_parents = 1, \ 278 .ops = &clk_branch_ops, \ 279 .flags = CLK_SET_RATE_PARENT, \ 280 }, \ 281 }, \ 282}; \ 283 \ 284static struct clk_regmap_mux prefix##_bit_clk = { \ 285 .reg = _ns, \ 286 .shift = 18, \ 287 .width = 1, \ 288 .clkr = { \ 289 .hw.init = &(struct clk_init_data){ \ 290 .name = #prefix "_bit_clk", \ 291 .parent_names = (const char *[]){ \ 292 #prefix "_bit_div_clk", \ 293 #prefix "_codec_clk", \ 294 }, \ 295 .num_parents = 2, \ 296 .ops = &clk_regmap_mux_closest_ops, \ 297 .flags = CLK_SET_RATE_PARENT, \ 298 }, \ 299 }, \ 300} 301 302CLK_AIF_OSR_DIV(codec_i2s_mic, 0x60, 0x64, 0x68); 303CLK_AIF_OSR_DIV(spare_i2s_mic, 0x78, 0x7c, 0x80); 304CLK_AIF_OSR_DIV(codec_i2s_spkr, 0x6c, 0x70, 0x74); 305CLK_AIF_OSR_DIV(spare_i2s_spkr, 0x84, 0x88, 0x8c); 306 307static struct freq_tbl clk_tbl_pcm_492[] = { 308 { 256000, P_PLL4, 4, 1, 480 }, 309 { 512000, P_PLL4, 4, 1, 240 }, 310 { 768000, P_PLL4, 4, 1, 160 }, 311 { 1024000, P_PLL4, 4, 1, 120 }, 312 { 1536000, P_PLL4, 4, 1, 80 }, 313 { 2048000, P_PLL4, 4, 1, 60 }, 314 { 3072000, P_PLL4, 4, 1, 40 }, 315 { 4096000, P_PLL4, 4, 1, 30 }, 316 { 6144000, P_PLL4, 4, 1, 20 }, 317 { 8192000, P_PLL4, 4, 1, 15 }, 318 { 12288000, P_PLL4, 4, 1, 10 }, 319 { 24576000, P_PLL4, 4, 1, 5 }, 320 { 27000000, P_CXO, 1, 0, 0 }, 321 { } 322}; 323 324static struct freq_tbl clk_tbl_pcm_393[] = { 325 { 256000, P_PLL4, 4, 1, 384 }, 326 { 512000, P_PLL4, 4, 1, 192 }, 327 { 768000, P_PLL4, 4, 1, 128 }, 328 { 1024000, P_PLL4, 4, 1, 96 }, 329 { 1536000, P_PLL4, 4, 1, 64 }, 330 { 2048000, P_PLL4, 4, 1, 48 }, 331 { 3072000, P_PLL4, 4, 1, 32 }, 332 { 4096000, P_PLL4, 4, 1, 24 }, 333 { 6144000, P_PLL4, 4, 1, 16 }, 334 { 8192000, P_PLL4, 4, 1, 12 }, 335 { 12288000, P_PLL4, 4, 1, 8 }, 336 { 24576000, P_PLL4, 4, 1, 4 }, 337 { 27000000, P_CXO, 1, 0, 0 }, 338 { } 339}; 340 341static struct clk_rcg pcm_src = { 342 .ns_reg = 0x54, 343 .md_reg = 0x58, 344 .mn = { 345 .mnctr_en_bit = 8, 346 .mnctr_reset_bit = 7, 347 .mnctr_mode_shift = 5, 348 .n_val_shift = 16, 349 .m_val_shift = 16, 350 .width = 16, 351 }, 352 .p = { 353 .pre_div_shift = 3, 354 .pre_div_width = 2, 355 }, 356 .s = { 357 .src_sel_shift = 0, 358 .parent_map = lcc_cxo_pll4_map, 359 }, 360 .freq_tbl = clk_tbl_pcm_393, 361 .clkr = { 362 .enable_reg = 0x54, 363 .enable_mask = BIT(9), 364 .hw.init = &(struct clk_init_data){ 365 .name = "pcm_src", 366 .parent_names = lcc_cxo_pll4, 367 .num_parents = 2, 368 .ops = &clk_rcg_ops, 369 .flags = CLK_SET_RATE_GATE, 370 }, 371 }, 372}; 373 374static struct clk_branch pcm_clk_out = { 375 .halt_reg = 0x5c, 376 .halt_bit = 0, 377 .halt_check = BRANCH_HALT_ENABLE, 378 .clkr = { 379 .enable_reg = 0x54, 380 .enable_mask = BIT(11), 381 .hw.init = &(struct clk_init_data){ 382 .name = "pcm_clk_out", 383 .parent_names = (const char *[]){ "pcm_src" }, 384 .num_parents = 1, 385 .ops = &clk_branch_ops, 386 .flags = CLK_SET_RATE_PARENT, 387 }, 388 }, 389}; 390 391static struct clk_regmap_mux pcm_clk = { 392 .reg = 0x54, 393 .shift = 10, 394 .width = 1, 395 .clkr = { 396 .hw.init = &(struct clk_init_data){ 397 .name = "pcm_clk", 398 .parent_names = (const char *[]){ 399 "pcm_clk_out", 400 "pcm_codec_clk", 401 }, 402 .num_parents = 2, 403 .ops = &clk_regmap_mux_closest_ops, 404 .flags = CLK_SET_RATE_PARENT, 405 }, 406 }, 407}; 408 409static struct clk_rcg slimbus_src = { 410 .ns_reg = 0xcc, 411 .md_reg = 0xd0, 412 .mn = { 413 .mnctr_en_bit = 8, 414 .mnctr_reset_bit = 7, 415 .mnctr_mode_shift = 5, 416 .n_val_shift = 24, 417 .m_val_shift = 8, 418 .width = 8, 419 }, 420 .p = { 421 .pre_div_shift = 3, 422 .pre_div_width = 2, 423 }, 424 .s = { 425 .src_sel_shift = 0, 426 .parent_map = lcc_cxo_pll4_map, 427 }, 428 .freq_tbl = clk_tbl_aif_osr_393, 429 .clkr = { 430 .enable_reg = 0xcc, 431 .enable_mask = BIT(9), 432 .hw.init = &(struct clk_init_data){ 433 .name = "slimbus_src", 434 .parent_names = lcc_cxo_pll4, 435 .num_parents = 2, 436 .ops = &clk_rcg_ops, 437 .flags = CLK_SET_RATE_GATE, 438 }, 439 }, 440}; 441 442static const char * const lcc_slimbus_parents[] = { 443 "slimbus_src", 444}; 445 446static struct clk_branch audio_slimbus_clk = { 447 .halt_reg = 0xd4, 448 .halt_bit = 0, 449 .halt_check = BRANCH_HALT_ENABLE, 450 .clkr = { 451 .enable_reg = 0xcc, 452 .enable_mask = BIT(10), 453 .hw.init = &(struct clk_init_data){ 454 .name = "audio_slimbus_clk", 455 .parent_names = lcc_slimbus_parents, 456 .num_parents = 1, 457 .ops = &clk_branch_ops, 458 .flags = CLK_SET_RATE_PARENT, 459 }, 460 }, 461}; 462 463static struct clk_branch sps_slimbus_clk = { 464 .halt_reg = 0xd4, 465 .halt_bit = 1, 466 .halt_check = BRANCH_HALT_ENABLE, 467 .clkr = { 468 .enable_reg = 0xcc, 469 .enable_mask = BIT(12), 470 .hw.init = &(struct clk_init_data){ 471 .name = "sps_slimbus_clk", 472 .parent_names = lcc_slimbus_parents, 473 .num_parents = 1, 474 .ops = &clk_branch_ops, 475 .flags = CLK_SET_RATE_PARENT, 476 }, 477 }, 478}; 479 480static struct clk_regmap *lcc_mdm9615_clks[] = { 481 [PLL4] = &pll4.clkr, 482 [MI2S_OSR_SRC] = &mi2s_osr_src.clkr, 483 [MI2S_OSR_CLK] = &mi2s_osr_clk.clkr, 484 [MI2S_DIV_CLK] = &mi2s_div_clk.clkr, 485 [MI2S_BIT_DIV_CLK] = &mi2s_bit_div_clk.clkr, 486 [MI2S_BIT_CLK] = &mi2s_bit_clk.clkr, 487 [PCM_SRC] = &pcm_src.clkr, 488 [PCM_CLK_OUT] = &pcm_clk_out.clkr, 489 [PCM_CLK] = &pcm_clk.clkr, 490 [SLIMBUS_SRC] = &slimbus_src.clkr, 491 [AUDIO_SLIMBUS_CLK] = &audio_slimbus_clk.clkr, 492 [SPS_SLIMBUS_CLK] = &sps_slimbus_clk.clkr, 493 [CODEC_I2S_MIC_OSR_SRC] = &codec_i2s_mic_osr_src.clkr, 494 [CODEC_I2S_MIC_OSR_CLK] = &codec_i2s_mic_osr_clk.clkr, 495 [CODEC_I2S_MIC_DIV_CLK] = &codec_i2s_mic_div_clk.clkr, 496 [CODEC_I2S_MIC_BIT_DIV_CLK] = &codec_i2s_mic_bit_div_clk.clkr, 497 [CODEC_I2S_MIC_BIT_CLK] = &codec_i2s_mic_bit_clk.clkr, 498 [SPARE_I2S_MIC_OSR_SRC] = &spare_i2s_mic_osr_src.clkr, 499 [SPARE_I2S_MIC_OSR_CLK] = &spare_i2s_mic_osr_clk.clkr, 500 [SPARE_I2S_MIC_DIV_CLK] = &spare_i2s_mic_div_clk.clkr, 501 [SPARE_I2S_MIC_BIT_DIV_CLK] = &spare_i2s_mic_bit_div_clk.clkr, 502 [SPARE_I2S_MIC_BIT_CLK] = &spare_i2s_mic_bit_clk.clkr, 503 [CODEC_I2S_SPKR_OSR_SRC] = &codec_i2s_spkr_osr_src.clkr, 504 [CODEC_I2S_SPKR_OSR_CLK] = &codec_i2s_spkr_osr_clk.clkr, 505 [CODEC_I2S_SPKR_DIV_CLK] = &codec_i2s_spkr_div_clk.clkr, 506 [CODEC_I2S_SPKR_BIT_DIV_CLK] = &codec_i2s_spkr_bit_div_clk.clkr, 507 [CODEC_I2S_SPKR_BIT_CLK] = &codec_i2s_spkr_bit_clk.clkr, 508 [SPARE_I2S_SPKR_OSR_SRC] = &spare_i2s_spkr_osr_src.clkr, 509 [SPARE_I2S_SPKR_OSR_CLK] = &spare_i2s_spkr_osr_clk.clkr, 510 [SPARE_I2S_SPKR_DIV_CLK] = &spare_i2s_spkr_div_clk.clkr, 511 [SPARE_I2S_SPKR_BIT_DIV_CLK] = &spare_i2s_spkr_bit_div_clk.clkr, 512 [SPARE_I2S_SPKR_BIT_CLK] = &spare_i2s_spkr_bit_clk.clkr, 513}; 514 515static const struct regmap_config lcc_mdm9615_regmap_config = { 516 .reg_bits = 32, 517 .reg_stride = 4, 518 .val_bits = 32, 519 .max_register = 0xfc, 520 .fast_io = true, 521}; 522 523static const struct qcom_cc_desc lcc_mdm9615_desc = { 524 .config = &lcc_mdm9615_regmap_config, 525 .clks = lcc_mdm9615_clks, 526 .num_clks = ARRAY_SIZE(lcc_mdm9615_clks), 527}; 528 529static const struct of_device_id lcc_mdm9615_match_table[] = { 530 { .compatible = "qcom,lcc-mdm9615" }, 531 { } 532}; 533MODULE_DEVICE_TABLE(of, lcc_mdm9615_match_table); 534 535static int lcc_mdm9615_probe(struct platform_device *pdev) 536{ 537 u32 val; 538 struct regmap *regmap; 539 540 regmap = qcom_cc_map(pdev, &lcc_mdm9615_desc); 541 if (IS_ERR(regmap)) 542 return PTR_ERR(regmap); 543 544 /* Use the correct frequency plan depending on speed of PLL4 */ 545 regmap_read(regmap, 0x4, &val); 546 if (val == 0x12) { 547 slimbus_src.freq_tbl = clk_tbl_aif_osr_492; 548 mi2s_osr_src.freq_tbl = clk_tbl_aif_osr_492; 549 codec_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492; 550 spare_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492; 551 codec_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492; 552 spare_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492; 553 pcm_src.freq_tbl = clk_tbl_pcm_492; 554 } 555 /* Enable PLL4 source on the LPASS Primary PLL Mux */ 556 regmap_write(regmap, 0xc4, 0x1); 557 558 return qcom_cc_really_probe(pdev, &lcc_mdm9615_desc, regmap); 559} 560 561static struct platform_driver lcc_mdm9615_driver = { 562 .probe = lcc_mdm9615_probe, 563 .driver = { 564 .name = "lcc-mdm9615", 565 .of_match_table = lcc_mdm9615_match_table, 566 }, 567}; 568module_platform_driver(lcc_mdm9615_driver); 569 570MODULE_DESCRIPTION("QCOM LCC MDM9615 Driver"); 571MODULE_LICENSE("GPL v2"); 572MODULE_ALIAS("platform:lcc-mdm9615");