cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dispcc-qcm2290.c (14559B)


      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
     24enum {
     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
     34static const struct pll_vco spark_vco[] = {
     35	{ 500000000, 1000000000, 2 },
     36};
     37
     38/* 768MHz configuration */
     39static 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
     49static 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
     66static const struct parent_map disp_cc_parent_map_0[] = {
     67	{ P_BI_TCXO, 0 },
     68	{ P_DSI0_PHY_PLL_OUT_BYTECLK, 1 },
     69};
     70
     71static 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
     77static const struct parent_map disp_cc_parent_map_1[] = {
     78	{ P_BI_TCXO, 0 },
     79};
     80
     81static 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
     86static const struct parent_map disp_cc_parent_map_2[] = {
     87	{ P_BI_TCXO, 0 },
     88	{ P_GPLL0_OUT_MAIN, 4 },
     89};
     90
     91static 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
     97static 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
    103static 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
    110static 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
    116static 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
    123static const struct parent_map disp_cc_parent_map_5[] = {
    124	{ P_SLEEP_CLK, 0 },
    125};
    126
    127static 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
    132static 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
    147static 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
    161static 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
    168static 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
    182static const struct freq_tbl ftbl_disp_cc_mdss_esc0_clk_src[] = {
    183	F(19200000, P_BI_TCXO, 1, 0, 0),
    184	{ }
    185};
    186
    187static 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
    201static 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
    210static 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
    225static 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
    240static 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
    255static const struct freq_tbl ftbl_disp_cc_sleep_clk_src[] = {
    256	F(32764, P_SLEEP_CLK, 1, 0, 0),
    257	{ }
    258};
    259
    260static 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
    274static 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
    292static 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
    310static 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
    328static 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
    346static 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
    364static 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
    382static 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
    400static 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
    418static 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
    436static 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
    454static 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
    463static struct gdsc *disp_cc_qcm2290_gdscs[] = {
    464	[MDSS_GDSC] = &mdss_gdsc,
    465};
    466
    467static 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
    489static 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
    497static 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
    505static const struct of_device_id disp_cc_qcm2290_match_table[] = {
    506	{ .compatible = "qcom,qcm2290-dispcc" },
    507	{ }
    508};
    509MODULE_DEVICE_TABLE(of, disp_cc_qcm2290_match_table);
    510
    511static 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
    534static 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
    542static int __init disp_cc_qcm2290_init(void)
    543{
    544	return platform_driver_register(&disp_cc_qcm2290_driver);
    545}
    546subsys_initcall(disp_cc_qcm2290_init);
    547
    548static void __exit disp_cc_qcm2290_exit(void)
    549{
    550	platform_driver_unregister(&disp_cc_qcm2290_driver);
    551}
    552module_exit(disp_cc_qcm2290_exit);
    553
    554MODULE_DESCRIPTION("QTI DISP_CC qcm2290 Driver");
    555MODULE_LICENSE("GPL v2");