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> |
5 | #include <linux/of.h> |
6 | #include <linux/platform_device.h> |
7 | #include <linux/regmap.h> |
8 | |
9 | #include "clk-alpha-pll.h" |
10 | |
11 | /* |
12 | * Even though APSS PLL type is of existing one (like Huayra), its offsets |
13 | * are different from the one mentioned in the clk-alpha-pll.c, since the |
14 | * PLL is specific to APSS, so lets the define the same. |
15 | */ |
16 | static const u8 ipq_pll_offsets[][PLL_OFF_MAX_REGS] = { |
17 | [CLK_ALPHA_PLL_TYPE_HUAYRA] = { |
18 | [PLL_OFF_L_VAL] = 0x08, |
19 | [PLL_OFF_ALPHA_VAL] = 0x10, |
20 | [PLL_OFF_USER_CTL] = 0x18, |
21 | [PLL_OFF_CONFIG_CTL] = 0x20, |
22 | [PLL_OFF_CONFIG_CTL_U] = 0x24, |
23 | [PLL_OFF_STATUS] = 0x28, |
24 | [PLL_OFF_TEST_CTL] = 0x30, |
25 | [PLL_OFF_TEST_CTL_U] = 0x34, |
26 | }, |
27 | [CLK_ALPHA_PLL_TYPE_STROMER_PLUS] = { |
28 | [PLL_OFF_L_VAL] = 0x08, |
29 | [PLL_OFF_ALPHA_VAL] = 0x10, |
30 | [PLL_OFF_ALPHA_VAL_U] = 0x14, |
31 | [PLL_OFF_USER_CTL] = 0x18, |
32 | [PLL_OFF_USER_CTL_U] = 0x1c, |
33 | [PLL_OFF_CONFIG_CTL] = 0x20, |
34 | [PLL_OFF_STATUS] = 0x28, |
35 | [PLL_OFF_TEST_CTL] = 0x30, |
36 | [PLL_OFF_TEST_CTL_U] = 0x34, |
37 | }, |
38 | }; |
39 | |
40 | static struct clk_alpha_pll ipq_pll_huayra = { |
41 | .offset = 0x0, |
42 | .regs = ipq_pll_offsets[CLK_ALPHA_PLL_TYPE_HUAYRA], |
43 | .flags = SUPPORTS_DYNAMIC_UPDATE, |
44 | .clkr = { |
45 | .enable_reg = 0x0, |
46 | .enable_mask = BIT(0), |
47 | .hw.init = &(struct clk_init_data){ |
48 | .name = "a53pll" , |
49 | .parent_data = &(const struct clk_parent_data) { |
50 | .fw_name = "xo" , |
51 | }, |
52 | .num_parents = 1, |
53 | .ops = &clk_alpha_pll_huayra_ops, |
54 | }, |
55 | }, |
56 | }; |
57 | |
58 | static struct clk_alpha_pll ipq_pll_stromer_plus = { |
59 | .offset = 0x0, |
60 | .regs = ipq_pll_offsets[CLK_ALPHA_PLL_TYPE_STROMER_PLUS], |
61 | .flags = SUPPORTS_DYNAMIC_UPDATE, |
62 | .clkr = { |
63 | .enable_reg = 0x0, |
64 | .enable_mask = BIT(0), |
65 | .hw.init = &(struct clk_init_data){ |
66 | .name = "a53pll" , |
67 | .parent_data = &(const struct clk_parent_data) { |
68 | .fw_name = "xo" , |
69 | }, |
70 | .num_parents = 1, |
71 | .ops = &clk_alpha_pll_stromer_plus_ops, |
72 | }, |
73 | }, |
74 | }; |
75 | |
76 | static const struct alpha_pll_config ipq5018_pll_config = { |
77 | .l = 0x32, |
78 | .config_ctl_val = 0x4001075b, |
79 | .config_ctl_hi_val = 0x304, |
80 | .main_output_mask = BIT(0), |
81 | .aux_output_mask = BIT(1), |
82 | .early_output_mask = BIT(3), |
83 | .alpha_en_mask = BIT(24), |
84 | .status_val = 0x3, |
85 | .status_mask = GENMASK(10, 8), |
86 | .lock_det = BIT(2), |
87 | .test_ctl_hi_val = 0x00400003, |
88 | }; |
89 | |
90 | static const struct alpha_pll_config ipq5332_pll_config = { |
91 | .l = 0x2d, |
92 | .config_ctl_val = 0x4001075b, |
93 | .config_ctl_hi_val = 0x304, |
94 | .main_output_mask = BIT(0), |
95 | .aux_output_mask = BIT(1), |
96 | .early_output_mask = BIT(3), |
97 | .alpha_en_mask = BIT(24), |
98 | .status_val = 0x3, |
99 | .status_mask = GENMASK(10, 8), |
100 | .lock_det = BIT(2), |
101 | .test_ctl_hi_val = 0x00400003, |
102 | }; |
103 | |
104 | static const struct alpha_pll_config ipq6018_pll_config = { |
105 | .l = 0x37, |
106 | .config_ctl_val = 0x240d4828, |
107 | .config_ctl_hi_val = 0x6, |
108 | .early_output_mask = BIT(3), |
109 | .aux2_output_mask = BIT(2), |
110 | .aux_output_mask = BIT(1), |
111 | .main_output_mask = BIT(0), |
112 | .test_ctl_val = 0x1c0000C0, |
113 | .test_ctl_hi_val = 0x4000, |
114 | }; |
115 | |
116 | static const struct alpha_pll_config ipq8074_pll_config = { |
117 | .l = 0x48, |
118 | .config_ctl_val = 0x200d4828, |
119 | .config_ctl_hi_val = 0x6, |
120 | .early_output_mask = BIT(3), |
121 | .aux2_output_mask = BIT(2), |
122 | .aux_output_mask = BIT(1), |
123 | .main_output_mask = BIT(0), |
124 | .test_ctl_val = 0x1c000000, |
125 | .test_ctl_hi_val = 0x4000, |
126 | }; |
127 | |
128 | static const struct alpha_pll_config ipq9574_pll_config = { |
129 | .l = 0x3b, |
130 | .config_ctl_val = 0x200d4828, |
131 | .config_ctl_hi_val = 0x6, |
132 | .early_output_mask = BIT(3), |
133 | .aux2_output_mask = BIT(2), |
134 | .aux_output_mask = BIT(1), |
135 | .main_output_mask = BIT(0), |
136 | .test_ctl_val = 0x0, |
137 | .test_ctl_hi_val = 0x4000, |
138 | }; |
139 | |
140 | struct apss_pll_data { |
141 | int pll_type; |
142 | struct clk_alpha_pll *pll; |
143 | const struct alpha_pll_config *pll_config; |
144 | }; |
145 | |
146 | static const struct apss_pll_data ipq5018_pll_data = { |
147 | .pll_type = CLK_ALPHA_PLL_TYPE_STROMER_PLUS, |
148 | .pll = &ipq_pll_stromer_plus, |
149 | .pll_config = &ipq5018_pll_config, |
150 | }; |
151 | |
152 | static struct apss_pll_data ipq5332_pll_data = { |
153 | .pll_type = CLK_ALPHA_PLL_TYPE_STROMER_PLUS, |
154 | .pll = &ipq_pll_stromer_plus, |
155 | .pll_config = &ipq5332_pll_config, |
156 | }; |
157 | |
158 | static struct apss_pll_data ipq8074_pll_data = { |
159 | .pll_type = CLK_ALPHA_PLL_TYPE_HUAYRA, |
160 | .pll = &ipq_pll_huayra, |
161 | .pll_config = &ipq8074_pll_config, |
162 | }; |
163 | |
164 | static struct apss_pll_data ipq6018_pll_data = { |
165 | .pll_type = CLK_ALPHA_PLL_TYPE_HUAYRA, |
166 | .pll = &ipq_pll_huayra, |
167 | .pll_config = &ipq6018_pll_config, |
168 | }; |
169 | |
170 | static struct apss_pll_data ipq9574_pll_data = { |
171 | .pll_type = CLK_ALPHA_PLL_TYPE_HUAYRA, |
172 | .pll = &ipq_pll_huayra, |
173 | .pll_config = &ipq9574_pll_config, |
174 | }; |
175 | |
176 | static const struct regmap_config ipq_pll_regmap_config = { |
177 | .reg_bits = 32, |
178 | .reg_stride = 4, |
179 | .val_bits = 32, |
180 | .max_register = 0x40, |
181 | .fast_io = true, |
182 | }; |
183 | |
184 | static int apss_ipq_pll_probe(struct platform_device *pdev) |
185 | { |
186 | const struct apss_pll_data *data; |
187 | struct device *dev = &pdev->dev; |
188 | struct regmap *regmap; |
189 | void __iomem *base; |
190 | int ret; |
191 | |
192 | base = devm_platform_ioremap_resource(pdev, index: 0); |
193 | if (IS_ERR(ptr: base)) |
194 | return PTR_ERR(ptr: base); |
195 | |
196 | regmap = devm_regmap_init_mmio(dev, base, &ipq_pll_regmap_config); |
197 | if (IS_ERR(ptr: regmap)) |
198 | return PTR_ERR(ptr: regmap); |
199 | |
200 | data = of_device_get_match_data(dev: &pdev->dev); |
201 | if (!data) |
202 | return -ENODEV; |
203 | |
204 | if (data->pll_type == CLK_ALPHA_PLL_TYPE_HUAYRA) |
205 | clk_alpha_pll_configure(pll: data->pll, regmap, config: data->pll_config); |
206 | else if (data->pll_type == CLK_ALPHA_PLL_TYPE_STROMER_PLUS) |
207 | clk_stromer_pll_configure(pll: data->pll, regmap, config: data->pll_config); |
208 | |
209 | ret = devm_clk_register_regmap(dev, rclk: &data->pll->clkr); |
210 | if (ret) |
211 | return ret; |
212 | |
213 | return devm_of_clk_add_hw_provider(dev, get: of_clk_hw_simple_get, |
214 | data: &data->pll->clkr.hw); |
215 | } |
216 | |
217 | static const struct of_device_id apss_ipq_pll_match_table[] = { |
218 | { .compatible = "qcom,ipq5018-a53pll" , .data = &ipq5018_pll_data }, |
219 | { .compatible = "qcom,ipq5332-a53pll" , .data = &ipq5332_pll_data }, |
220 | { .compatible = "qcom,ipq6018-a53pll" , .data = &ipq6018_pll_data }, |
221 | { .compatible = "qcom,ipq8074-a53pll" , .data = &ipq8074_pll_data }, |
222 | { .compatible = "qcom,ipq9574-a73pll" , .data = &ipq9574_pll_data }, |
223 | { } |
224 | }; |
225 | MODULE_DEVICE_TABLE(of, apss_ipq_pll_match_table); |
226 | |
227 | static struct platform_driver apss_ipq_pll_driver = { |
228 | .probe = apss_ipq_pll_probe, |
229 | .driver = { |
230 | .name = "qcom-ipq-apss-pll" , |
231 | .of_match_table = apss_ipq_pll_match_table, |
232 | }, |
233 | }; |
234 | module_platform_driver(apss_ipq_pll_driver); |
235 | |
236 | MODULE_DESCRIPTION("Qualcomm technology Inc APSS ALPHA PLL Driver" ); |
237 | MODULE_LICENSE("GPL v2" ); |
238 | |