Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: qcom: Add display clock controller driver for QCM2290

Add support for the display clock controller found in QCM2290
based devices. This clock controller feeds the Multimedia Display
SubSystem (MDSS).

It's a porting of dispcc-scuba GPL-2.0 driver from CAF msm-4.19 kernel:
https://source.codeaurora.org/quic/la/kernel/msm-4.19/tree/drivers/clk/qcom/dispcc-scuba.c?h=LE.UM.4.4.1.r3

Global clock name references (parent_names) have been replaced by
parent_data and parent_hws.

Clocks marked enable_safe_config have their clk_rcg2_ops moved to
clk_rcg2_shared_ops.

Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Link: https://lore.kernel.org/r/1644432308-21099-2-git-send-email-loic.poulain@linaro.org

authored by

Loic Poulain and committed by
Bjorn Andersson
cc517ea3 85cedb4e

+565
+9
drivers/clk/qcom/Kconfig
··· 340 340 Say Y if you want to use multimedia devices or peripheral 341 341 devices such as UART, SPI, I2C, USB, SD/eMMC etc. 342 342 343 + config QCM_DISPCC_2290 344 + tristate "QCM2290 Display Clock Controller" 345 + select QCM_GCC_2290 346 + help 347 + Support for the display clock controller on Qualcomm Technologies, Inc 348 + QCM2290 devices. 349 + Say Y if you want to support display devices and functionality such as 350 + splash screen. 351 + 343 352 config QCS_GCC_404 344 353 tristate "QCS404 Global Clock Controller" 345 354 help
+1
drivers/clk/qcom/Makefile
··· 56 56 obj-$(CONFIG_QCOM_CLK_RPMH) += clk-rpmh.o 57 57 obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o 58 58 obj-$(CONFIG_QCM_GCC_2290) += gcc-qcm2290.o 59 + obj-$(CONFIG_QCM_DISPCC_2290) += dispcc-qcm2290.o 59 60 obj-$(CONFIG_QCS_GCC_404) += gcc-qcs404.o 60 61 obj-$(CONFIG_QCS_Q6SSTOP_404) += q6sstop-qcs404.o 61 62 obj-$(CONFIG_QCS_TURING_404) += turingcc-qcs404.o
+555
drivers/clk/qcom/dispcc-qcm2290.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) 2020, The Linux Foundation. All rights reserved. 4 + * Copyright (c) 2021, Linaro Ltd. 5 + */ 6 + 7 + #include <linux/err.h> 8 + #include <linux/kernel.h> 9 + #include <linux/module.h> 10 + #include <linux/of_device.h> 11 + #include <linux/of.h> 12 + #include <linux/regmap.h> 13 + 14 + #include <dt-bindings/clock/qcom,dispcc-qcm2290.h> 15 + 16 + #include "clk-alpha-pll.h" 17 + #include "clk-branch.h" 18 + #include "clk-rcg.h" 19 + #include "clk-regmap.h" 20 + #include "clk-regmap-divider.h" 21 + #include "common.h" 22 + #include "gdsc.h" 23 + 24 + enum { 25 + P_BI_TCXO, 26 + P_DISP_CC_PLL0_OUT_MAIN, 27 + P_DSI0_PHY_PLL_OUT_BYTECLK, 28 + P_DSI0_PHY_PLL_OUT_DSICLK, 29 + P_DSI1_PHY_PLL_OUT_DSICLK, 30 + P_GPLL0_OUT_MAIN, 31 + P_SLEEP_CLK, 32 + }; 33 + 34 + static const struct pll_vco spark_vco[] = { 35 + { 500000000, 1000000000, 2 }, 36 + }; 37 + 38 + /* 768MHz configuration */ 39 + static const struct alpha_pll_config disp_cc_pll0_config = { 40 + .l = 0x28, 41 + .alpha = 0x0, 42 + .alpha_en_mask = BIT(24), 43 + .vco_val = 0x2 << 20, 44 + .vco_mask = GENMASK(21, 20), 45 + .main_output_mask = BIT(0), 46 + .config_ctl_val = 0x4001055B, 47 + }; 48 + 49 + static struct clk_alpha_pll disp_cc_pll0 = { 50 + .offset = 0x0, 51 + .vco_table = spark_vco, 52 + .num_vco = ARRAY_SIZE(spark_vco), 53 + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], 54 + .clkr = { 55 + .hw.init = &(struct clk_init_data){ 56 + .name = "disp_cc_pll0", 57 + .parent_data = &(const struct clk_parent_data){ 58 + .fw_name = "bi_tcxo", 59 + }, 60 + .num_parents = 1, 61 + .ops = &clk_alpha_pll_ops, 62 + }, 63 + }, 64 + }; 65 + 66 + static const struct parent_map disp_cc_parent_map_0[] = { 67 + { P_BI_TCXO, 0 }, 68 + { P_DSI0_PHY_PLL_OUT_BYTECLK, 1 }, 69 + }; 70 + 71 + static const struct clk_parent_data disp_cc_parent_data_0[] = { 72 + { .fw_name = "bi_tcxo" }, 73 + { .fw_name = "dsi0_phy_pll_out_byteclk" }, 74 + { .fw_name = "core_bi_pll_test_se" }, 75 + }; 76 + 77 + static const struct parent_map disp_cc_parent_map_1[] = { 78 + { P_BI_TCXO, 0 }, 79 + }; 80 + 81 + static const struct clk_parent_data disp_cc_parent_data_1[] = { 82 + { .fw_name = "bi_tcxo" }, 83 + { .fw_name = "core_bi_pll_test_se" }, 84 + }; 85 + 86 + static const struct parent_map disp_cc_parent_map_2[] = { 87 + { P_BI_TCXO, 0 }, 88 + { P_GPLL0_OUT_MAIN, 4 }, 89 + }; 90 + 91 + static const struct clk_parent_data disp_cc_parent_data_2[] = { 92 + { .fw_name = "bi_tcxo_ao" }, 93 + { .fw_name = "gcc_disp_gpll0_div_clk_src" }, 94 + { .fw_name = "core_bi_pll_test_se" }, 95 + }; 96 + 97 + static const struct parent_map disp_cc_parent_map_3[] = { 98 + { P_BI_TCXO, 0 }, 99 + { P_DISP_CC_PLL0_OUT_MAIN, 1 }, 100 + { P_GPLL0_OUT_MAIN, 4 }, 101 + }; 102 + 103 + static const struct clk_parent_data disp_cc_parent_data_3[] = { 104 + { .fw_name = "bi_tcxo" }, 105 + { .hw = &disp_cc_pll0.clkr.hw }, 106 + { .fw_name = "gcc_disp_gpll0_clk_src" }, 107 + { .fw_name = "core_bi_pll_test_se" }, 108 + }; 109 + 110 + static const struct parent_map disp_cc_parent_map_4[] = { 111 + { P_BI_TCXO, 0 }, 112 + { P_DSI0_PHY_PLL_OUT_DSICLK, 1 }, 113 + { P_DSI1_PHY_PLL_OUT_DSICLK, 2 }, 114 + }; 115 + 116 + static const struct clk_parent_data disp_cc_parent_data_4[] = { 117 + { .fw_name = "bi_tcxo" }, 118 + { .fw_name = "dsi0_phy_pll_out_dsiclk" }, 119 + { .fw_name = "dsi1_phy_pll_out_dsiclk" }, 120 + { .fw_name = "core_bi_pll_test_se" }, 121 + }; 122 + 123 + static const struct parent_map disp_cc_parent_map_5[] = { 124 + { P_SLEEP_CLK, 0 }, 125 + }; 126 + 127 + static const struct clk_parent_data disp_cc_parent_data_5[] = { 128 + { .fw_name = "sleep_clk" }, 129 + { .fw_name = "core_bi_pll_test_se" }, 130 + }; 131 + 132 + static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = { 133 + .cmd_rcgr = 0x20a4, 134 + .mnd_width = 0, 135 + .hid_width = 5, 136 + .parent_map = disp_cc_parent_map_0, 137 + .clkr.hw.init = &(struct clk_init_data){ 138 + .name = "disp_cc_mdss_byte0_clk_src", 139 + .parent_data = disp_cc_parent_data_0, 140 + .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), 141 + /* For set_rate and set_parent to succeed, parent(s) must be enabled */ 142 + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, 143 + .ops = &clk_byte2_ops, 144 + }, 145 + }; 146 + 147 + static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = { 148 + .reg = 0x20bc, 149 + .shift = 0, 150 + .width = 2, 151 + .clkr.hw.init = &(struct clk_init_data) { 152 + .name = "disp_cc_mdss_byte0_div_clk_src", 153 + .parent_hws = (const struct clk_hw*[]){ 154 + &disp_cc_mdss_byte0_clk_src.clkr.hw, 155 + }, 156 + .num_parents = 1, 157 + .ops = &clk_regmap_div_ops, 158 + }, 159 + }; 160 + 161 + static const struct freq_tbl ftbl_disp_cc_mdss_ahb_clk_src[] = { 162 + F(19200000, P_BI_TCXO, 1, 0, 0), 163 + F(37500000, P_GPLL0_OUT_MAIN, 8, 0, 0), 164 + F(75000000, P_GPLL0_OUT_MAIN, 4, 0, 0), 165 + { } 166 + }; 167 + 168 + static struct clk_rcg2 disp_cc_mdss_ahb_clk_src = { 169 + .cmd_rcgr = 0x2154, 170 + .mnd_width = 0, 171 + .hid_width = 5, 172 + .parent_map = disp_cc_parent_map_2, 173 + .freq_tbl = ftbl_disp_cc_mdss_ahb_clk_src, 174 + .clkr.hw.init = &(struct clk_init_data){ 175 + .name = "disp_cc_mdss_ahb_clk_src", 176 + .parent_data = disp_cc_parent_data_2, 177 + .num_parents = ARRAY_SIZE(disp_cc_parent_data_2), 178 + .ops = &clk_rcg2_shared_ops, 179 + }, 180 + }; 181 + 182 + static const struct freq_tbl ftbl_disp_cc_mdss_esc0_clk_src[] = { 183 + F(19200000, P_BI_TCXO, 1, 0, 0), 184 + { } 185 + }; 186 + 187 + static struct clk_rcg2 disp_cc_mdss_esc0_clk_src = { 188 + .cmd_rcgr = 0x20c0, 189 + .mnd_width = 0, 190 + .hid_width = 5, 191 + .parent_map = disp_cc_parent_map_0, 192 + .freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src, 193 + .clkr.hw.init = &(struct clk_init_data){ 194 + .name = "disp_cc_mdss_esc0_clk_src", 195 + .parent_data = disp_cc_parent_data_0, 196 + .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), 197 + .ops = &clk_rcg2_ops, 198 + }, 199 + }; 200 + 201 + static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src[] = { 202 + F(19200000, P_BI_TCXO, 1, 0, 0), 203 + F(192000000, P_DISP_CC_PLL0_OUT_MAIN, 4, 0, 0), 204 + F(256000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), 205 + F(307200000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0), 206 + F(384000000, P_DISP_CC_PLL0_OUT_MAIN, 2, 0, 0), 207 + { } 208 + }; 209 + 210 + static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = { 211 + .cmd_rcgr = 0x2074, 212 + .mnd_width = 0, 213 + .hid_width = 5, 214 + .parent_map = disp_cc_parent_map_3, 215 + .freq_tbl = ftbl_disp_cc_mdss_mdp_clk_src, 216 + .clkr.hw.init = &(struct clk_init_data){ 217 + .name = "disp_cc_mdss_mdp_clk_src", 218 + .parent_data = disp_cc_parent_data_3, 219 + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), 220 + .flags = CLK_SET_RATE_PARENT, 221 + .ops = &clk_rcg2_shared_ops, 222 + }, 223 + }; 224 + 225 + static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { 226 + .cmd_rcgr = 0x205c, 227 + .mnd_width = 8, 228 + .hid_width = 5, 229 + .parent_map = disp_cc_parent_map_4, 230 + .clkr.hw.init = &(struct clk_init_data){ 231 + .name = "disp_cc_mdss_pclk0_clk_src", 232 + .parent_data = disp_cc_parent_data_4, 233 + .num_parents = ARRAY_SIZE(disp_cc_parent_data_4), 234 + /* For set_rate and set_parent to succeed, parent(s) must be enabled */ 235 + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, 236 + .ops = &clk_pixel_ops, 237 + }, 238 + }; 239 + 240 + static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = { 241 + .cmd_rcgr = 0x208c, 242 + .mnd_width = 0, 243 + .hid_width = 5, 244 + .parent_map = disp_cc_parent_map_1, 245 + .freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src, 246 + .clkr.hw.init = &(struct clk_init_data){ 247 + .name = "disp_cc_mdss_vsync_clk_src", 248 + .parent_data = disp_cc_parent_data_1, 249 + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), 250 + .flags = CLK_SET_RATE_PARENT, 251 + .ops = &clk_rcg2_shared_ops, 252 + }, 253 + }; 254 + 255 + static const struct freq_tbl ftbl_disp_cc_sleep_clk_src[] = { 256 + F(32764, P_SLEEP_CLK, 1, 0, 0), 257 + { } 258 + }; 259 + 260 + static struct clk_rcg2 disp_cc_sleep_clk_src = { 261 + .cmd_rcgr = 0x6050, 262 + .mnd_width = 0, 263 + .hid_width = 5, 264 + .parent_map = disp_cc_parent_map_5, 265 + .freq_tbl = ftbl_disp_cc_sleep_clk_src, 266 + .clkr.hw.init = &(struct clk_init_data){ 267 + .name = "disp_cc_sleep_clk_src", 268 + .parent_data = disp_cc_parent_data_5, 269 + .num_parents = ARRAY_SIZE(disp_cc_parent_data_5), 270 + .ops = &clk_rcg2_ops, 271 + }, 272 + }; 273 + 274 + static struct clk_branch disp_cc_mdss_ahb_clk = { 275 + .halt_reg = 0x2044, 276 + .halt_check = BRANCH_HALT, 277 + .clkr = { 278 + .enable_reg = 0x2044, 279 + .enable_mask = BIT(0), 280 + .hw.init = &(struct clk_init_data){ 281 + .name = "disp_cc_mdss_ahb_clk", 282 + .parent_hws = (const struct clk_hw*[]){ 283 + &disp_cc_mdss_ahb_clk_src.clkr.hw, 284 + }, 285 + .num_parents = 1, 286 + .flags = CLK_SET_RATE_PARENT, 287 + .ops = &clk_branch2_ops, 288 + }, 289 + }, 290 + }; 291 + 292 + static struct clk_branch disp_cc_mdss_byte0_clk = { 293 + .halt_reg = 0x201c, 294 + .halt_check = BRANCH_HALT, 295 + .clkr = { 296 + .enable_reg = 0x201c, 297 + .enable_mask = BIT(0), 298 + .hw.init = &(struct clk_init_data){ 299 + .name = "disp_cc_mdss_byte0_clk", 300 + .parent_hws = (const struct clk_hw*[]){ 301 + &disp_cc_mdss_byte0_clk_src.clkr.hw, 302 + }, 303 + .num_parents = 1, 304 + .flags = CLK_SET_RATE_PARENT, 305 + .ops = &clk_branch2_ops, 306 + }, 307 + }, 308 + }; 309 + 310 + static struct clk_branch disp_cc_mdss_byte0_intf_clk = { 311 + .halt_reg = 0x2020, 312 + .halt_check = BRANCH_HALT, 313 + .clkr = { 314 + .enable_reg = 0x2020, 315 + .enable_mask = BIT(0), 316 + .hw.init = &(struct clk_init_data){ 317 + .name = "disp_cc_mdss_byte0_intf_clk", 318 + .parent_hws = (const struct clk_hw*[]){ 319 + &disp_cc_mdss_byte0_div_clk_src.clkr.hw, 320 + }, 321 + .num_parents = 1, 322 + .flags = CLK_SET_RATE_PARENT, 323 + .ops = &clk_branch2_ops, 324 + }, 325 + }, 326 + }; 327 + 328 + static struct clk_branch disp_cc_mdss_esc0_clk = { 329 + .halt_reg = 0x2024, 330 + .halt_check = BRANCH_HALT, 331 + .clkr = { 332 + .enable_reg = 0x2024, 333 + .enable_mask = BIT(0), 334 + .hw.init = &(struct clk_init_data){ 335 + .name = "disp_cc_mdss_esc0_clk", 336 + .parent_hws = (const struct clk_hw*[]){ 337 + &disp_cc_mdss_esc0_clk_src.clkr.hw, 338 + }, 339 + .num_parents = 1, 340 + .flags = CLK_SET_RATE_PARENT, 341 + .ops = &clk_branch2_ops, 342 + }, 343 + }, 344 + }; 345 + 346 + static struct clk_branch disp_cc_mdss_mdp_clk = { 347 + .halt_reg = 0x2008, 348 + .halt_check = BRANCH_HALT, 349 + .clkr = { 350 + .enable_reg = 0x2008, 351 + .enable_mask = BIT(0), 352 + .hw.init = &(struct clk_init_data){ 353 + .name = "disp_cc_mdss_mdp_clk", 354 + .parent_hws = (const struct clk_hw*[]){ 355 + &disp_cc_mdss_mdp_clk_src.clkr.hw, 356 + }, 357 + .num_parents = 1, 358 + .flags = CLK_SET_RATE_PARENT, 359 + .ops = &clk_branch2_ops, 360 + }, 361 + }, 362 + }; 363 + 364 + static struct clk_branch disp_cc_mdss_mdp_lut_clk = { 365 + .halt_reg = 0x2010, 366 + .halt_check = BRANCH_HALT_VOTED, 367 + .clkr = { 368 + .enable_reg = 0x2010, 369 + .enable_mask = BIT(0), 370 + .hw.init = &(struct clk_init_data){ 371 + .name = "disp_cc_mdss_mdp_lut_clk", 372 + .parent_hws = (const struct clk_hw*[]){ 373 + &disp_cc_mdss_mdp_clk_src.clkr.hw, 374 + }, 375 + .num_parents = 1, 376 + .flags = CLK_SET_RATE_PARENT, 377 + .ops = &clk_branch2_ops, 378 + }, 379 + }, 380 + }; 381 + 382 + static struct clk_branch disp_cc_mdss_non_gdsc_ahb_clk = { 383 + .halt_reg = 0x4004, 384 + .halt_check = BRANCH_HALT_VOTED, 385 + .clkr = { 386 + .enable_reg = 0x4004, 387 + .enable_mask = BIT(0), 388 + .hw.init = &(struct clk_init_data){ 389 + .name = "disp_cc_mdss_non_gdsc_ahb_clk", 390 + .parent_hws = (const struct clk_hw*[]){ 391 + &disp_cc_mdss_ahb_clk_src.clkr.hw, 392 + }, 393 + .num_parents = 1, 394 + .flags = CLK_SET_RATE_PARENT, 395 + .ops = &clk_branch2_ops, 396 + }, 397 + }, 398 + }; 399 + 400 + static struct clk_branch disp_cc_mdss_pclk0_clk = { 401 + .halt_reg = 0x2004, 402 + .halt_check = BRANCH_HALT, 403 + .clkr = { 404 + .enable_reg = 0x2004, 405 + .enable_mask = BIT(0), 406 + .hw.init = &(struct clk_init_data){ 407 + .name = "disp_cc_mdss_pclk0_clk", 408 + .parent_hws = (const struct clk_hw*[]){ 409 + &disp_cc_mdss_pclk0_clk_src.clkr.hw, 410 + }, 411 + .num_parents = 1, 412 + .flags = CLK_SET_RATE_PARENT, 413 + .ops = &clk_branch2_ops, 414 + }, 415 + }, 416 + }; 417 + 418 + static struct clk_branch disp_cc_mdss_vsync_clk = { 419 + .halt_reg = 0x2018, 420 + .halt_check = BRANCH_HALT, 421 + .clkr = { 422 + .enable_reg = 0x2018, 423 + .enable_mask = BIT(0), 424 + .hw.init = &(struct clk_init_data){ 425 + .name = "disp_cc_mdss_vsync_clk", 426 + .parent_hws = (const struct clk_hw*[]){ 427 + &disp_cc_mdss_vsync_clk_src.clkr.hw, 428 + }, 429 + .num_parents = 1, 430 + .flags = CLK_SET_RATE_PARENT, 431 + .ops = &clk_branch2_ops, 432 + }, 433 + }, 434 + }; 435 + 436 + static struct clk_branch disp_cc_sleep_clk = { 437 + .halt_reg = 0x6068, 438 + .halt_check = BRANCH_HALT, 439 + .clkr = { 440 + .enable_reg = 0x6068, 441 + .enable_mask = BIT(0), 442 + .hw.init = &(struct clk_init_data){ 443 + .name = "disp_cc_sleep_clk", 444 + .parent_hws = (const struct clk_hw*[]){ 445 + &disp_cc_sleep_clk_src.clkr.hw, 446 + }, 447 + .num_parents = 1, 448 + .flags = CLK_SET_RATE_PARENT, 449 + .ops = &clk_branch2_ops, 450 + }, 451 + }, 452 + }; 453 + 454 + static struct gdsc mdss_gdsc = { 455 + .gdscr = 0x3000, 456 + .pd = { 457 + .name = "mdss_gdsc", 458 + }, 459 + .pwrsts = PWRSTS_OFF_ON, 460 + .flags = HW_CTRL, 461 + }; 462 + 463 + static struct gdsc *disp_cc_qcm2290_gdscs[] = { 464 + [MDSS_GDSC] = &mdss_gdsc, 465 + }; 466 + 467 + static struct clk_regmap *disp_cc_qcm2290_clocks[] = { 468 + [DISP_CC_MDSS_AHB_CLK] = &disp_cc_mdss_ahb_clk.clkr, 469 + [DISP_CC_MDSS_AHB_CLK_SRC] = &disp_cc_mdss_ahb_clk_src.clkr, 470 + [DISP_CC_MDSS_BYTE0_CLK] = &disp_cc_mdss_byte0_clk.clkr, 471 + [DISP_CC_MDSS_BYTE0_CLK_SRC] = &disp_cc_mdss_byte0_clk_src.clkr, 472 + [DISP_CC_MDSS_BYTE0_DIV_CLK_SRC] = &disp_cc_mdss_byte0_div_clk_src.clkr, 473 + [DISP_CC_MDSS_BYTE0_INTF_CLK] = &disp_cc_mdss_byte0_intf_clk.clkr, 474 + [DISP_CC_MDSS_ESC0_CLK] = &disp_cc_mdss_esc0_clk.clkr, 475 + [DISP_CC_MDSS_ESC0_CLK_SRC] = &disp_cc_mdss_esc0_clk_src.clkr, 476 + [DISP_CC_MDSS_MDP_CLK] = &disp_cc_mdss_mdp_clk.clkr, 477 + [DISP_CC_MDSS_MDP_CLK_SRC] = &disp_cc_mdss_mdp_clk_src.clkr, 478 + [DISP_CC_MDSS_MDP_LUT_CLK] = &disp_cc_mdss_mdp_lut_clk.clkr, 479 + [DISP_CC_MDSS_NON_GDSC_AHB_CLK] = &disp_cc_mdss_non_gdsc_ahb_clk.clkr, 480 + [DISP_CC_MDSS_PCLK0_CLK] = &disp_cc_mdss_pclk0_clk.clkr, 481 + [DISP_CC_MDSS_PCLK0_CLK_SRC] = &disp_cc_mdss_pclk0_clk_src.clkr, 482 + [DISP_CC_MDSS_VSYNC_CLK] = &disp_cc_mdss_vsync_clk.clkr, 483 + [DISP_CC_MDSS_VSYNC_CLK_SRC] = &disp_cc_mdss_vsync_clk_src.clkr, 484 + [DISP_CC_PLL0] = &disp_cc_pll0.clkr, 485 + [DISP_CC_SLEEP_CLK] = &disp_cc_sleep_clk.clkr, 486 + [DISP_CC_SLEEP_CLK_SRC] = &disp_cc_sleep_clk_src.clkr, 487 + }; 488 + 489 + static const struct regmap_config disp_cc_qcm2290_regmap_config = { 490 + .reg_bits = 32, 491 + .reg_stride = 4, 492 + .val_bits = 32, 493 + .max_register = 0x10000, 494 + .fast_io = true, 495 + }; 496 + 497 + static const struct qcom_cc_desc disp_cc_qcm2290_desc = { 498 + .config = &disp_cc_qcm2290_regmap_config, 499 + .clks = disp_cc_qcm2290_clocks, 500 + .num_clks = ARRAY_SIZE(disp_cc_qcm2290_clocks), 501 + .gdscs = disp_cc_qcm2290_gdscs, 502 + .num_gdscs = ARRAY_SIZE(disp_cc_qcm2290_gdscs), 503 + }; 504 + 505 + static const struct of_device_id disp_cc_qcm2290_match_table[] = { 506 + { .compatible = "qcom,qcm2290-dispcc" }, 507 + { } 508 + }; 509 + MODULE_DEVICE_TABLE(of, disp_cc_qcm2290_match_table); 510 + 511 + static int disp_cc_qcm2290_probe(struct platform_device *pdev) 512 + { 513 + struct regmap *regmap; 514 + int ret; 515 + 516 + regmap = qcom_cc_map(pdev, &disp_cc_qcm2290_desc); 517 + if (IS_ERR(regmap)) 518 + return PTR_ERR(regmap); 519 + 520 + clk_alpha_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); 521 + 522 + /* Keep DISP_CC_XO_CLK always-ON */ 523 + regmap_update_bits(regmap, 0x604c, BIT(0), BIT(0)); 524 + 525 + ret = qcom_cc_really_probe(pdev, &disp_cc_qcm2290_desc, regmap); 526 + if (ret) { 527 + dev_err(&pdev->dev, "Failed to register DISP CC clocks\n"); 528 + return ret; 529 + } 530 + 531 + return ret; 532 + } 533 + 534 + static struct platform_driver disp_cc_qcm2290_driver = { 535 + .probe = disp_cc_qcm2290_probe, 536 + .driver = { 537 + .name = "dispcc-qcm2290", 538 + .of_match_table = disp_cc_qcm2290_match_table, 539 + }, 540 + }; 541 + 542 + static int __init disp_cc_qcm2290_init(void) 543 + { 544 + return platform_driver_register(&disp_cc_qcm2290_driver); 545 + } 546 + subsys_initcall(disp_cc_qcm2290_init); 547 + 548 + static void __exit disp_cc_qcm2290_exit(void) 549 + { 550 + platform_driver_unregister(&disp_cc_qcm2290_driver); 551 + } 552 + module_exit(disp_cc_qcm2290_exit); 553 + 554 + MODULE_DESCRIPTION("QTI DISP_CC qcm2290 Driver"); 555 + MODULE_LICENSE("GPL v2");