diff options
Diffstat (limited to 'drivers/clk/qcom/common.c')
-rw-r--r-- | drivers/clk/qcom/common.c | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c new file mode 100644 index 000000000000..9b5a1cfc6b91 --- /dev/null +++ b/drivers/clk/qcom/common.c | |||
@@ -0,0 +1,101 @@ | |||
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/regmap.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/clk-provider.h> | ||
18 | #include <linux/reset-controller.h> | ||
19 | |||
20 | #include "common.h" | ||
21 | #include "clk-regmap.h" | ||
22 | #include "reset.h" | ||
23 | |||
24 | struct qcom_cc { | ||
25 | struct qcom_reset_controller reset; | ||
26 | struct clk_onecell_data data; | ||
27 | struct clk *clks[]; | ||
28 | }; | ||
29 | |||
30 | int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc) | ||
31 | { | ||
32 | void __iomem *base; | ||
33 | struct resource *res; | ||
34 | int i, ret; | ||
35 | struct device *dev = &pdev->dev; | ||
36 | struct clk *clk; | ||
37 | struct clk_onecell_data *data; | ||
38 | struct clk **clks; | ||
39 | struct regmap *regmap; | ||
40 | struct qcom_reset_controller *reset; | ||
41 | struct qcom_cc *cc; | ||
42 | size_t num_clks = desc->num_clks; | ||
43 | struct clk_regmap **rclks = desc->clks; | ||
44 | |||
45 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
46 | base = devm_ioremap_resource(dev, res); | ||
47 | if (IS_ERR(base)) | ||
48 | return PTR_ERR(base); | ||
49 | |||
50 | regmap = devm_regmap_init_mmio(dev, base, desc->config); | ||
51 | if (IS_ERR(regmap)) | ||
52 | return PTR_ERR(regmap); | ||
53 | |||
54 | cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, | ||
55 | GFP_KERNEL); | ||
56 | if (!cc) | ||
57 | return -ENOMEM; | ||
58 | |||
59 | clks = cc->clks; | ||
60 | data = &cc->data; | ||
61 | data->clks = clks; | ||
62 | data->clk_num = num_clks; | ||
63 | |||
64 | for (i = 0; i < num_clks; i++) { | ||
65 | if (!rclks[i]) { | ||
66 | clks[i] = ERR_PTR(-ENOENT); | ||
67 | continue; | ||
68 | } | ||
69 | clk = devm_clk_register_regmap(dev, rclks[i]); | ||
70 | if (IS_ERR(clk)) | ||
71 | return PTR_ERR(clk); | ||
72 | clks[i] = clk; | ||
73 | } | ||
74 | |||
75 | ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); | ||
76 | if (ret) | ||
77 | return ret; | ||
78 | |||
79 | reset = &cc->reset; | ||
80 | reset->rcdev.of_node = dev->of_node; | ||
81 | reset->rcdev.ops = &qcom_reset_ops; | ||
82 | reset->rcdev.owner = dev->driver->owner; | ||
83 | reset->rcdev.nr_resets = desc->num_resets; | ||
84 | reset->regmap = regmap; | ||
85 | reset->reset_map = desc->resets; | ||
86 | platform_set_drvdata(pdev, &reset->rcdev); | ||
87 | |||
88 | ret = reset_controller_register(&reset->rcdev); | ||
89 | if (ret) | ||
90 | of_clk_del_provider(dev->of_node); | ||
91 | |||
92 | return ret; | ||
93 | } | ||
94 | EXPORT_SYMBOL_GPL(qcom_cc_probe); | ||
95 | |||
96 | void qcom_cc_remove(struct platform_device *pdev) | ||
97 | { | ||
98 | of_clk_del_provider(pdev->dev.of_node); | ||
99 | reset_controller_unregister(platform_get_drvdata(pdev)); | ||
100 | } | ||
101 | EXPORT_SYMBOL_GPL(qcom_cc_remove); | ||