1// SPDX-License-Identifier: GPL-2.0
2// Copyright (c) 2018, The Linux Foundation. All rights reserved.
3
4#include <linux/kernel.h>
5#include <linux/init.h>
6#include <linux/module.h>
7#include <linux/platform_device.h>
8#include <linux/of.h>
9#include <linux/of_device.h>
10#include <linux/clk.h>
11#include <linux/clk-provider.h>
12#include <linux/regmap.h>
13
14#include "clk-regmap.h"
15#include "clk-hfpll.h"
16
17static const struct hfpll_data hdata = {
18 .mode_reg = 0x00,
19 .l_reg = 0x04,
20 .m_reg = 0x08,
21 .n_reg = 0x0c,
22 .user_reg = 0x10,
23 .config_reg = 0x14,
24 .config_val = 0x430405d,
25 .status_reg = 0x1c,
26 .lock_bit = 16,
27
28 .user_val = 0x8,
29 .user_vco_mask = 0x100000,
30 .low_vco_max_rate = 1248000000,
31 .min_rate = 537600000UL,
32 .max_rate = 2900000000UL,
33};
34
35static const struct hfpll_data msm8976_a53 = {
36 .mode_reg = 0x00,
37 .l_reg = 0x04,
38 .m_reg = 0x08,
39 .n_reg = 0x0c,
40 .user_reg = 0x10,
41 .config_reg = 0x14,
42 .config_val = 0x341600,
43 .status_reg = 0x1c,
44 .lock_bit = 16,
45
46 .l_val = 0x35,
47 .user_val = 0x109,
48 .min_rate = 902400000UL,
49 .max_rate = 1478400000UL,
50};
51
52static const struct hfpll_data msm8976_a72 = {
53 .mode_reg = 0x00,
54 .l_reg = 0x04,
55 .m_reg = 0x08,
56 .n_reg = 0x0c,
57 .user_reg = 0x10,
58 .config_reg = 0x14,
59 .config_val = 0x4e0405d,
60 .status_reg = 0x1c,
61 .lock_bit = 16,
62
63 .l_val = 0x3e,
64 .user_val = 0x100109,
65 .min_rate = 940800000UL,
66 .max_rate = 2016000000UL,
67};
68
69static const struct hfpll_data msm8976_cci = {
70 .mode_reg = 0x00,
71 .l_reg = 0x04,
72 .m_reg = 0x08,
73 .n_reg = 0x0c,
74 .user_reg = 0x10,
75 .config_reg = 0x14,
76 .config_val = 0x141400,
77 .status_reg = 0x1c,
78 .lock_bit = 16,
79
80 .l_val = 0x20,
81 .user_val = 0x100109,
82 .min_rate = 556800000UL,
83 .max_rate = 902400000UL,
84};
85
86static const struct of_device_id qcom_hfpll_match_table[] = {
87 { .compatible = "qcom,hfpll", .data = &hdata },
88 { .compatible = "qcom,msm8976-hfpll-a53", .data = &msm8976_a53 },
89 { .compatible = "qcom,msm8976-hfpll-a72", .data = &msm8976_a72 },
90 { .compatible = "qcom,msm8976-hfpll-cci", .data = &msm8976_cci },
91 { }
92};
93MODULE_DEVICE_TABLE(of, qcom_hfpll_match_table);
94
95static const struct regmap_config hfpll_regmap_config = {
96 .reg_bits = 32,
97 .reg_stride = 4,
98 .val_bits = 32,
99 .max_register = 0x30,
100 .fast_io = true,
101};
102
103static int qcom_hfpll_probe(struct platform_device *pdev)
104{
105 struct device *dev = &pdev->dev;
106 void __iomem *base;
107 struct regmap *regmap;
108 struct clk_hfpll *h;
109 struct clk_init_data init = {
110 .num_parents = 1,
111 .ops = &clk_ops_hfpll,
112 /*
113 * rather than marking the clock critical and forcing the clock
114 * to be always enabled, we make sure that the clock is not
115 * disabled: the firmware remains responsible of enabling this
116 * clock (for more info check the commit log)
117 */
118 .flags = CLK_IGNORE_UNUSED,
119 };
120 int ret;
121 struct clk_parent_data pdata = { .index = 0 };
122
123 h = devm_kzalloc(dev, size: sizeof(*h), GFP_KERNEL);
124 if (!h)
125 return -ENOMEM;
126
127 base = devm_platform_get_and_ioremap_resource(pdev, index: 0, NULL);
128 if (IS_ERR(ptr: base))
129 return PTR_ERR(ptr: base);
130
131 regmap = devm_regmap_init_mmio(&pdev->dev, base, &hfpll_regmap_config);
132 if (IS_ERR(ptr: regmap))
133 return PTR_ERR(ptr: regmap);
134
135 if (of_property_read_string_index(np: dev->of_node, propname: "clock-output-names",
136 index: 0, output: &init.name))
137 return -ENODEV;
138
139 init.parent_data = &pdata;
140
141 h->d = of_device_get_match_data(dev: &pdev->dev);
142 h->clkr.hw.init = &init;
143 spin_lock_init(&h->lock);
144
145 ret = devm_clk_register_regmap(dev, rclk: &h->clkr);
146 if (ret) {
147 dev_err(dev, "failed to register regmap clock: %d\n", ret);
148 return ret;
149 }
150
151 return devm_of_clk_add_hw_provider(dev, get: of_clk_hw_simple_get,
152 data: &h->clkr.hw);
153}
154
155static struct platform_driver qcom_hfpll_driver = {
156 .probe = qcom_hfpll_probe,
157 .driver = {
158 .name = "qcom-hfpll",
159 .of_match_table = qcom_hfpll_match_table,
160 },
161};
162module_platform_driver(qcom_hfpll_driver);
163
164MODULE_DESCRIPTION("QCOM HFPLL Clock Driver");
165MODULE_LICENSE("GPL v2");
166MODULE_ALIAS("platform:qcom-hfpll");
167

source code of linux/drivers/clk/qcom/hfpll.c