1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2018, The Linux Foundation. All rights reserved.
3 #include <linux/clk-provider.h>
4 #include <linux/module.h>
6 #include <linux/platform_device.h>
7 #include <linux/regmap.h>
9 #include "clk-alpha-pll.h"
11 static struct clk_alpha_pll ipq_pll_huayra
= {
13 .regs
= clk_alpha_pll_regs
[CLK_ALPHA_PLL_TYPE_HUAYRA_APSS
],
14 .flags
= SUPPORTS_DYNAMIC_UPDATE
,
17 .enable_mask
= BIT(0),
18 .hw
.init
= &(const struct clk_init_data
) {
20 .parent_data
= &(const struct clk_parent_data
) {
24 .ops
= &clk_alpha_pll_huayra_ops
,
29 static struct clk_alpha_pll ipq_pll_stromer
= {
31 .regs
= clk_alpha_pll_regs
[CLK_ALPHA_PLL_TYPE_STROMER
],
32 .flags
= SUPPORTS_DYNAMIC_UPDATE
,
35 .enable_mask
= BIT(0),
36 .hw
.init
= &(const struct clk_init_data
) {
38 .parent_data
= &(const struct clk_parent_data
) {
42 .ops
= &clk_alpha_pll_stromer_ops
,
47 static struct clk_alpha_pll ipq_pll_stromer_plus
= {
50 * The register offsets of the Stromer Plus PLL used in IPQ5332
51 * are the same as the Stromer PLL's offsets.
53 .regs
= clk_alpha_pll_regs
[CLK_ALPHA_PLL_TYPE_STROMER
],
54 .flags
= SUPPORTS_DYNAMIC_UPDATE
,
57 .enable_mask
= BIT(0),
58 .hw
.init
= &(const struct clk_init_data
) {
60 .parent_data
= &(const struct clk_parent_data
) {
64 .ops
= &clk_alpha_pll_stromer_plus_ops
,
69 /* 1.008 GHz configuration */
70 static const struct alpha_pll_config ipq5018_pll_config
= {
72 .config_ctl_val
= 0x4001075b,
73 .main_output_mask
= BIT(0),
74 .aux_output_mask
= BIT(1),
75 .early_output_mask
= BIT(3),
76 .alpha_en_mask
= BIT(24),
78 .status_mask
= GENMASK(10, 8),
80 .test_ctl_hi_val
= 0x00400003,
83 static const struct alpha_pll_config ipq5332_pll_config
= {
85 .config_ctl_val
= 0x4001075b,
86 .main_output_mask
= BIT(0),
87 .aux_output_mask
= BIT(1),
88 .early_output_mask
= BIT(3),
89 .alpha_en_mask
= BIT(24),
91 .status_mask
= GENMASK(10, 8),
93 .test_ctl_hi_val
= 0x00400003,
96 static const struct alpha_pll_config ipq6018_pll_config
= {
98 .config_ctl_val
= 0x240d4828,
99 .config_ctl_hi_val
= 0x6,
100 .early_output_mask
= BIT(3),
101 .aux2_output_mask
= BIT(2),
102 .aux_output_mask
= BIT(1),
103 .main_output_mask
= BIT(0),
104 .test_ctl_val
= 0x1c0000C0,
105 .test_ctl_hi_val
= 0x4000,
108 static const struct alpha_pll_config ipq8074_pll_config
= {
110 .config_ctl_val
= 0x200d4828,
111 .config_ctl_hi_val
= 0x6,
112 .early_output_mask
= BIT(3),
113 .aux2_output_mask
= BIT(2),
114 .aux_output_mask
= BIT(1),
115 .main_output_mask
= BIT(0),
116 .test_ctl_val
= 0x1c000000,
117 .test_ctl_hi_val
= 0x4000,
120 static const struct alpha_pll_config ipq9574_pll_config
= {
122 .config_ctl_val
= 0x200d4828,
123 .config_ctl_hi_val
= 0x6,
124 .early_output_mask
= BIT(3),
125 .aux2_output_mask
= BIT(2),
126 .aux_output_mask
= BIT(1),
127 .main_output_mask
= BIT(0),
129 .test_ctl_hi_val
= 0x4000,
132 struct apss_pll_data
{
134 struct clk_alpha_pll
*pll
;
135 const struct alpha_pll_config
*pll_config
;
138 static const struct apss_pll_data ipq5018_pll_data
= {
139 .pll_type
= CLK_ALPHA_PLL_TYPE_STROMER
,
140 .pll
= &ipq_pll_stromer
,
141 .pll_config
= &ipq5018_pll_config
,
144 static const struct apss_pll_data ipq5332_pll_data
= {
145 .pll_type
= CLK_ALPHA_PLL_TYPE_STROMER_PLUS
,
146 .pll
= &ipq_pll_stromer_plus
,
147 .pll_config
= &ipq5332_pll_config
,
150 static const struct apss_pll_data ipq8074_pll_data
= {
151 .pll_type
= CLK_ALPHA_PLL_TYPE_HUAYRA
,
152 .pll
= &ipq_pll_huayra
,
153 .pll_config
= &ipq8074_pll_config
,
156 static const struct apss_pll_data ipq6018_pll_data
= {
157 .pll_type
= CLK_ALPHA_PLL_TYPE_HUAYRA
,
158 .pll
= &ipq_pll_huayra
,
159 .pll_config
= &ipq6018_pll_config
,
162 static const struct apss_pll_data ipq9574_pll_data
= {
163 .pll_type
= CLK_ALPHA_PLL_TYPE_HUAYRA
,
164 .pll
= &ipq_pll_huayra
,
165 .pll_config
= &ipq9574_pll_config
,
168 static const struct regmap_config ipq_pll_regmap_config
= {
172 .max_register
= 0x40,
176 static int apss_ipq_pll_probe(struct platform_device
*pdev
)
178 const struct apss_pll_data
*data
;
179 struct device
*dev
= &pdev
->dev
;
180 struct regmap
*regmap
;
184 base
= devm_platform_ioremap_resource(pdev
, 0);
186 return PTR_ERR(base
);
188 regmap
= devm_regmap_init_mmio(dev
, base
, &ipq_pll_regmap_config
);
190 return PTR_ERR(regmap
);
192 data
= of_device_get_match_data(&pdev
->dev
);
196 if (data
->pll_type
== CLK_ALPHA_PLL_TYPE_HUAYRA
)
197 clk_alpha_pll_configure(data
->pll
, regmap
, data
->pll_config
);
198 else if (data
->pll_type
== CLK_ALPHA_PLL_TYPE_STROMER
||
199 data
->pll_type
== CLK_ALPHA_PLL_TYPE_STROMER_PLUS
)
200 clk_stromer_pll_configure(data
->pll
, regmap
, data
->pll_config
);
202 ret
= devm_clk_register_regmap(dev
, &data
->pll
->clkr
);
206 return devm_of_clk_add_hw_provider(dev
, of_clk_hw_simple_get
,
207 &data
->pll
->clkr
.hw
);
210 static const struct of_device_id apss_ipq_pll_match_table
[] = {
211 { .compatible
= "qcom,ipq5018-a53pll", .data
= &ipq5018_pll_data
},
212 { .compatible
= "qcom,ipq5332-a53pll", .data
= &ipq5332_pll_data
},
213 { .compatible
= "qcom,ipq6018-a53pll", .data
= &ipq6018_pll_data
},
214 { .compatible
= "qcom,ipq8074-a53pll", .data
= &ipq8074_pll_data
},
215 { .compatible
= "qcom,ipq9574-a73pll", .data
= &ipq9574_pll_data
},
218 MODULE_DEVICE_TABLE(of
, apss_ipq_pll_match_table
);
220 static struct platform_driver apss_ipq_pll_driver
= {
221 .probe
= apss_ipq_pll_probe
,
223 .name
= "qcom-ipq-apss-pll",
224 .of_match_table
= apss_ipq_pll_match_table
,
227 module_platform_driver(apss_ipq_pll_driver
);
229 MODULE_DESCRIPTION("Qualcomm technology Inc APSS ALPHA PLL Driver");
230 MODULE_LICENSE("GPL v2");