GNU Linux-libre 4.14.290-gnu1
[releases.git] / drivers / clk / mvebu / ap806-system-controller.c
1 /*
2  * Marvell Armada AP806 System Controller
3  *
4  * Copyright (C) 2016 Marvell
5  *
6  * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
7  *
8  * This file is licensed under the terms of the GNU General Public
9  * License version 2.  This program is licensed "as is" without any
10  * warranty of any kind, whether express or implied.
11  */
12
13 #define pr_fmt(fmt) "ap806-system-controller: " fmt
14
15 #include <linux/clk-provider.h>
16 #include <linux/mfd/syscon.h>
17 #include <linux/init.h>
18 #include <linux/of.h>
19 #include <linux/of_address.h>
20 #include <linux/platform_device.h>
21 #include <linux/regmap.h>
22
23 #define AP806_SAR_REG                   0x400
24 #define AP806_SAR_CLKFREQ_MODE_MASK     0x1f
25
26 #define AP806_CLK_NUM                   5
27
28 static struct clk *ap806_clks[AP806_CLK_NUM];
29
30 static struct clk_onecell_data ap806_clk_data = {
31         .clks = ap806_clks,
32         .clk_num = AP806_CLK_NUM,
33 };
34
35 static char *ap806_unique_name(struct device *dev, struct device_node *np,
36                                char *name)
37 {
38         const __be32 *reg;
39         u64 addr;
40
41         reg = of_get_property(np, "reg", NULL);
42         addr = of_translate_address(np, reg);
43         return devm_kasprintf(dev, GFP_KERNEL, "%llx-%s",
44                         (unsigned long long)addr, name);
45 }
46
47 static int ap806_syscon_common_probe(struct platform_device *pdev,
48                                      struct device_node *syscon_node)
49 {
50         unsigned int freq_mode, cpuclk_freq;
51         const char *name, *fixedclk_name;
52         struct device *dev = &pdev->dev;
53         struct device_node *np = dev->of_node;
54         struct regmap *regmap;
55         u32 reg;
56         int ret;
57
58         regmap = syscon_node_to_regmap(syscon_node);
59         if (IS_ERR(regmap)) {
60                 dev_err(dev, "cannot get regmap\n");
61                 return PTR_ERR(regmap);
62         }
63
64         ret = regmap_read(regmap, AP806_SAR_REG, &reg);
65         if (ret) {
66                 dev_err(dev, "cannot read from regmap\n");
67                 return ret;
68         }
69
70         freq_mode = reg & AP806_SAR_CLKFREQ_MODE_MASK;
71         switch (freq_mode) {
72         case 0x0:
73         case 0x1:
74                 cpuclk_freq = 2000;
75                 break;
76         case 0x6:
77         case 0x7:
78                 cpuclk_freq = 1800;
79                 break;
80         case 0x4:
81         case 0xB:
82         case 0xD:
83                 cpuclk_freq = 1600;
84                 break;
85         case 0x1a:
86                 cpuclk_freq = 1400;
87                 break;
88         case 0x14:
89         case 0x17:
90                 cpuclk_freq = 1300;
91                 break;
92         case 0x19:
93                 cpuclk_freq = 1200;
94                 break;
95         case 0x13:
96         case 0x1d:
97                 cpuclk_freq = 1000;
98                 break;
99         case 0x1c:
100                 cpuclk_freq = 800;
101                 break;
102         case 0x1b:
103                 cpuclk_freq = 600;
104                 break;
105         default:
106                 dev_err(dev, "invalid SAR value\n");
107                 return -EINVAL;
108         }
109
110         /* Convert to hertz */
111         cpuclk_freq *= 1000 * 1000;
112
113         /* CPU clocks depend on the Sample At Reset configuration */
114         name = ap806_unique_name(dev, syscon_node, "cpu-cluster-0");
115         ap806_clks[0] = clk_register_fixed_rate(dev, name, NULL,
116                                                 0, cpuclk_freq);
117         if (IS_ERR(ap806_clks[0])) {
118                 ret = PTR_ERR(ap806_clks[0]);
119                 goto fail0;
120         }
121
122         name = ap806_unique_name(dev, syscon_node, "cpu-cluster-1");
123         ap806_clks[1] = clk_register_fixed_rate(dev, name, NULL, 0,
124                                                 cpuclk_freq);
125         if (IS_ERR(ap806_clks[1])) {
126                 ret = PTR_ERR(ap806_clks[1]);
127                 goto fail1;
128         }
129
130         /* Fixed clock is always 1200 Mhz */
131         fixedclk_name = ap806_unique_name(dev, syscon_node, "fixed");
132         ap806_clks[2] = clk_register_fixed_rate(dev, fixedclk_name, NULL,
133                                                 0, 1200 * 1000 * 1000);
134         if (IS_ERR(ap806_clks[2])) {
135                 ret = PTR_ERR(ap806_clks[2]);
136                 goto fail2;
137         }
138
139         /* MSS Clock is fixed clock divided by 6 */
140         name = ap806_unique_name(dev, syscon_node, "mss");
141         ap806_clks[3] = clk_register_fixed_factor(NULL, name, fixedclk_name,
142                                                   0, 1, 6);
143         if (IS_ERR(ap806_clks[3])) {
144                 ret = PTR_ERR(ap806_clks[3]);
145                 goto fail3;
146         }
147
148         /* SDIO(/eMMC) Clock is fixed clock divided by 3 */
149         name = ap806_unique_name(dev, syscon_node, "sdio");
150         ap806_clks[4] = clk_register_fixed_factor(NULL, name,
151                                                   fixedclk_name,
152                                                   0, 1, 3);
153         if (IS_ERR(ap806_clks[4])) {
154                 ret = PTR_ERR(ap806_clks[4]);
155                 goto fail4;
156         }
157
158         of_clk_add_provider(np, of_clk_src_onecell_get, &ap806_clk_data);
159         ret = of_clk_add_provider(np, of_clk_src_onecell_get, &ap806_clk_data);
160         if (ret)
161                 goto fail_clk_add;
162
163         return 0;
164
165 fail_clk_add:
166         clk_unregister_fixed_factor(ap806_clks[4]);
167 fail4:
168         clk_unregister_fixed_factor(ap806_clks[3]);
169 fail3:
170         clk_unregister_fixed_rate(ap806_clks[2]);
171 fail2:
172         clk_unregister_fixed_rate(ap806_clks[1]);
173 fail1:
174         clk_unregister_fixed_rate(ap806_clks[0]);
175 fail0:
176         return ret;
177 }
178
179 static int ap806_syscon_legacy_probe(struct platform_device *pdev)
180 {
181         dev_warn(&pdev->dev, FW_WARN "Using legacy device tree binding\n");
182         dev_warn(&pdev->dev, FW_WARN "Update your device tree:\n");
183         dev_warn(&pdev->dev, FW_WARN
184                  "This binding won't be supported in future kernel\n");
185
186         return ap806_syscon_common_probe(pdev, pdev->dev.of_node);
187
188 }
189
190 static int ap806_clock_probe(struct platform_device *pdev)
191 {
192         return ap806_syscon_common_probe(pdev, pdev->dev.of_node->parent);
193 }
194
195 static const struct of_device_id ap806_syscon_legacy_of_match[] = {
196         { .compatible = "marvell,ap806-system-controller", },
197         { }
198 };
199
200 static struct platform_driver ap806_syscon_legacy_driver = {
201         .probe = ap806_syscon_legacy_probe,
202         .driver         = {
203                 .name   = "marvell-ap806-system-controller",
204                 .of_match_table = ap806_syscon_legacy_of_match,
205                 .suppress_bind_attrs = true,
206         },
207 };
208 builtin_platform_driver(ap806_syscon_legacy_driver);
209
210 static const struct of_device_id ap806_clock_of_match[] = {
211         { .compatible = "marvell,ap806-clock", },
212         { }
213 };
214
215 static struct platform_driver ap806_clock_driver = {
216         .probe = ap806_clock_probe,
217         .driver         = {
218                 .name   = "marvell-ap806-clock",
219                 .of_match_table = ap806_clock_of_match,
220                 .suppress_bind_attrs = true,
221         },
222 };
223 builtin_platform_driver(ap806_clock_driver);