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