GNU Linux-libre 4.9.308-gnu1
[releases.git] / drivers / clk / qcom / common.c
1 /*
2  * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
3  *
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  */
13
14 #include <linux/export.h>
15 #include <linux/module.h>
16 #include <linux/regmap.h>
17 #include <linux/platform_device.h>
18 #include <linux/clk-provider.h>
19 #include <linux/reset-controller.h>
20 #include <linux/of.h>
21
22 #include "common.h"
23 #include "clk-rcg.h"
24 #include "clk-regmap.h"
25 #include "reset.h"
26 #include "gdsc.h"
27
28 struct qcom_cc {
29         struct qcom_reset_controller reset;
30         struct clk_regmap **rclks;
31         size_t num_rclks;
32 };
33
34 const
35 struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, unsigned long rate)
36 {
37         if (!f)
38                 return NULL;
39
40         if (!f->freq)
41                 return f;
42
43         for (; f->freq; f++)
44                 if (rate <= f->freq)
45                         return f;
46
47         /* Default to our fastest rate */
48         return f - 1;
49 }
50 EXPORT_SYMBOL_GPL(qcom_find_freq);
51
52 int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map, u8 src)
53 {
54         int i, num_parents = clk_hw_get_num_parents(hw);
55
56         for (i = 0; i < num_parents; i++)
57                 if (src == map[i].src)
58                         return i;
59
60         return -ENOENT;
61 }
62 EXPORT_SYMBOL_GPL(qcom_find_src_index);
63
64 struct regmap *
65 qcom_cc_map(struct platform_device *pdev, const struct qcom_cc_desc *desc)
66 {
67         void __iomem *base;
68         struct resource *res;
69         struct device *dev = &pdev->dev;
70
71         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
72         base = devm_ioremap_resource(dev, res);
73         if (IS_ERR(base))
74                 return ERR_CAST(base);
75
76         return devm_regmap_init_mmio(dev, base, desc->config);
77 }
78 EXPORT_SYMBOL_GPL(qcom_cc_map);
79
80 static void qcom_cc_del_clk_provider(void *data)
81 {
82         of_clk_del_provider(data);
83 }
84
85 static void qcom_cc_reset_unregister(void *data)
86 {
87         reset_controller_unregister(data);
88 }
89
90 static void qcom_cc_gdsc_unregister(void *data)
91 {
92         gdsc_unregister(data);
93 }
94
95 /*
96  * Backwards compatibility with old DTs. Register a pass-through factor 1/1
97  * clock to translate 'path' clk into 'name' clk and regsiter the 'path'
98  * clk as a fixed rate clock if it isn't present.
99  */
100 static int _qcom_cc_register_board_clk(struct device *dev, const char *path,
101                                        const char *name, unsigned long rate,
102                                        bool add_factor)
103 {
104         struct device_node *node = NULL;
105         struct device_node *clocks_node;
106         struct clk_fixed_factor *factor;
107         struct clk_fixed_rate *fixed;
108         struct clk_init_data init_data = { };
109         int ret;
110
111         clocks_node = of_find_node_by_path("/clocks");
112         if (clocks_node)
113                 node = of_find_node_by_name(clocks_node, path);
114         of_node_put(clocks_node);
115
116         if (!node) {
117                 fixed = devm_kzalloc(dev, sizeof(*fixed), GFP_KERNEL);
118                 if (!fixed)
119                         return -EINVAL;
120
121                 fixed->fixed_rate = rate;
122                 fixed->hw.init = &init_data;
123
124                 init_data.name = path;
125                 init_data.ops = &clk_fixed_rate_ops;
126
127                 ret = devm_clk_hw_register(dev, &fixed->hw);
128                 if (ret)
129                         return ret;
130         }
131         of_node_put(node);
132
133         if (add_factor) {
134                 factor = devm_kzalloc(dev, sizeof(*factor), GFP_KERNEL);
135                 if (!factor)
136                         return -EINVAL;
137
138                 factor->mult = factor->div = 1;
139                 factor->hw.init = &init_data;
140
141                 init_data.name = name;
142                 init_data.parent_names = &path;
143                 init_data.num_parents = 1;
144                 init_data.flags = 0;
145                 init_data.ops = &clk_fixed_factor_ops;
146
147                 ret = devm_clk_hw_register(dev, &factor->hw);
148                 if (ret)
149                         return ret;
150         }
151
152         return 0;
153 }
154
155 int qcom_cc_register_board_clk(struct device *dev, const char *path,
156                                const char *name, unsigned long rate)
157 {
158         bool add_factor = true;
159         struct device_node *node;
160
161         /* The RPM clock driver will add the factor clock if present */
162         if (IS_ENABLED(CONFIG_QCOM_RPMCC)) {
163                 node = of_find_compatible_node(NULL, NULL, "qcom,rpmcc");
164                 if (of_device_is_available(node))
165                         add_factor = false;
166                 of_node_put(node);
167         }
168
169         return _qcom_cc_register_board_clk(dev, path, name, rate, add_factor);
170 }
171 EXPORT_SYMBOL_GPL(qcom_cc_register_board_clk);
172
173 int qcom_cc_register_sleep_clk(struct device *dev)
174 {
175         return _qcom_cc_register_board_clk(dev, "sleep_clk", "sleep_clk_src",
176                                            32768, true);
177 }
178 EXPORT_SYMBOL_GPL(qcom_cc_register_sleep_clk);
179
180 static struct clk_hw *qcom_cc_clk_hw_get(struct of_phandle_args *clkspec,
181                                          void *data)
182 {
183         struct qcom_cc *cc = data;
184         unsigned int idx = clkspec->args[0];
185
186         if (idx >= cc->num_rclks) {
187                 pr_err("%s: invalid index %u\n", __func__, idx);
188                 return ERR_PTR(-EINVAL);
189         }
190
191         return cc->rclks[idx] ? &cc->rclks[idx]->hw : ERR_PTR(-ENOENT);
192 }
193
194 int qcom_cc_really_probe(struct platform_device *pdev,
195                          const struct qcom_cc_desc *desc, struct regmap *regmap)
196 {
197         int i, ret;
198         struct device *dev = &pdev->dev;
199         struct qcom_reset_controller *reset;
200         struct qcom_cc *cc;
201         struct gdsc_desc *scd;
202         size_t num_clks = desc->num_clks;
203         struct clk_regmap **rclks = desc->clks;
204
205         cc = devm_kzalloc(dev, sizeof(*cc), GFP_KERNEL);
206         if (!cc)
207                 return -ENOMEM;
208
209         cc->rclks = rclks;
210         cc->num_rclks = num_clks;
211
212         for (i = 0; i < num_clks; i++) {
213                 if (!rclks[i])
214                         continue;
215
216                 ret = devm_clk_register_regmap(dev, rclks[i]);
217                 if (ret)
218                         return ret;
219         }
220
221         ret = of_clk_add_hw_provider(dev->of_node, qcom_cc_clk_hw_get, cc);
222         if (ret)
223                 return ret;
224
225         ret = devm_add_action_or_reset(dev, qcom_cc_del_clk_provider,
226                                        pdev->dev.of_node);
227
228         if (ret)
229                 return ret;
230
231         reset = &cc->reset;
232         reset->rcdev.of_node = dev->of_node;
233         reset->rcdev.ops = &qcom_reset_ops;
234         reset->rcdev.owner = dev->driver->owner;
235         reset->rcdev.nr_resets = desc->num_resets;
236         reset->regmap = regmap;
237         reset->reset_map = desc->resets;
238
239         ret = reset_controller_register(&reset->rcdev);
240         if (ret)
241                 return ret;
242
243         ret = devm_add_action_or_reset(dev, qcom_cc_reset_unregister,
244                                        &reset->rcdev);
245
246         if (ret)
247                 return ret;
248
249         if (desc->gdscs && desc->num_gdscs) {
250                 scd = devm_kzalloc(dev, sizeof(*scd), GFP_KERNEL);
251                 if (!scd)
252                         return -ENOMEM;
253                 scd->dev = dev;
254                 scd->scs = desc->gdscs;
255                 scd->num = desc->num_gdscs;
256                 ret = gdsc_register(scd, &reset->rcdev, regmap);
257                 if (ret)
258                         return ret;
259                 ret = devm_add_action_or_reset(dev, qcom_cc_gdsc_unregister,
260                                                scd);
261                 if (ret)
262                         return ret;
263         }
264
265         return 0;
266 }
267 EXPORT_SYMBOL_GPL(qcom_cc_really_probe);
268
269 int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc)
270 {
271         struct regmap *regmap;
272
273         regmap = qcom_cc_map(pdev, desc);
274         if (IS_ERR(regmap))
275                 return PTR_ERR(regmap);
276
277         return qcom_cc_really_probe(pdev, desc, regmap);
278 }
279 EXPORT_SYMBOL_GPL(qcom_cc_probe);
280
281 MODULE_LICENSE("GPL v2");