1 /*
2  * Copyright (c) 2016 Chen-Yu Tsai. 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/clk.h>
15 #include <linux/clk-provider.h>
16 #include <linux/of_address.h>
17 #include <linux/platform_device.h>
18 #include <linux/reset.h>
19 
20 #include "ccu_common.h"
21 #include "ccu_div.h"
22 #include "ccu_gate.h"
23 #include "ccu_reset.h"
24 
25 #include "ccu-sun9i-a80-de.h"
26 
27 static SUNXI_CCU_GATE(fe0_clk,		"fe0",		"fe0-div",
28 		      0x00, BIT(0), 0);
29 static SUNXI_CCU_GATE(fe1_clk,		"fe1",		"fe1-div",
30 		      0x00, BIT(1), 0);
31 static SUNXI_CCU_GATE(fe2_clk,		"fe2",		"fe2-div",
32 		      0x00, BIT(2), 0);
33 static SUNXI_CCU_GATE(iep_deu0_clk,	"iep-deu0",	"de",
34 		      0x00, BIT(4), 0);
35 static SUNXI_CCU_GATE(iep_deu1_clk,	"iep-deu1",	"de",
36 		      0x00, BIT(5), 0);
37 static SUNXI_CCU_GATE(be0_clk,		"be0",		"be0-div",
38 		      0x00, BIT(8), 0);
39 static SUNXI_CCU_GATE(be1_clk,		"be1",		"be1-div",
40 		      0x00, BIT(9), 0);
41 static SUNXI_CCU_GATE(be2_clk,		"be2",		"be2-div",
42 		      0x00, BIT(10), 0);
43 static SUNXI_CCU_GATE(iep_drc0_clk,	"iep-drc0",	"de",
44 		      0x00, BIT(12), 0);
45 static SUNXI_CCU_GATE(iep_drc1_clk,	"iep-drc1",	"de",
46 		      0x00, BIT(13), 0);
47 static SUNXI_CCU_GATE(merge_clk,	"merge",	"de",
48 		      0x00, BIT(20), 0);
49 
50 static SUNXI_CCU_GATE(dram_fe0_clk,	"dram-fe0",	"sdram",
51 		      0x04, BIT(0), 0);
52 static SUNXI_CCU_GATE(dram_fe1_clk,	"dram-fe1",	"sdram",
53 		      0x04, BIT(1), 0);
54 static SUNXI_CCU_GATE(dram_fe2_clk,	"dram-fe2",	"sdram",
55 		      0x04, BIT(2), 0);
56 static SUNXI_CCU_GATE(dram_deu0_clk,	"dram-deu0",	"sdram",
57 		      0x04, BIT(4), 0);
58 static SUNXI_CCU_GATE(dram_deu1_clk,	"dram-deu1",	"sdram",
59 		      0x04, BIT(5), 0);
60 static SUNXI_CCU_GATE(dram_be0_clk,	"dram-be0",	"sdram",
61 		      0x04, BIT(8), 0);
62 static SUNXI_CCU_GATE(dram_be1_clk,	"dram-be1",	"sdram",
63 		      0x04, BIT(9), 0);
64 static SUNXI_CCU_GATE(dram_be2_clk,	"dram-be2",	"sdram",
65 		      0x04, BIT(10), 0);
66 static SUNXI_CCU_GATE(dram_drc0_clk,	"dram-drc0",	"sdram",
67 		      0x04, BIT(12), 0);
68 static SUNXI_CCU_GATE(dram_drc1_clk,	"dram-drc1",	"sdram",
69 		      0x04, BIT(13), 0);
70 
71 static SUNXI_CCU_GATE(bus_fe0_clk,	"bus-fe0",	"bus-de",
72 		      0x08, BIT(0), 0);
73 static SUNXI_CCU_GATE(bus_fe1_clk,	"bus-fe1",	"bus-de",
74 		      0x08, BIT(1), 0);
75 static SUNXI_CCU_GATE(bus_fe2_clk,	"bus-fe2",	"bus-de",
76 		      0x08, BIT(2), 0);
77 static SUNXI_CCU_GATE(bus_deu0_clk,	"bus-deu0",	"bus-de",
78 		      0x08, BIT(4), 0);
79 static SUNXI_CCU_GATE(bus_deu1_clk,	"bus-deu1",	"bus-de",
80 		      0x08, BIT(5), 0);
81 static SUNXI_CCU_GATE(bus_be0_clk,	"bus-be0",	"bus-de",
82 		      0x08, BIT(8), 0);
83 static SUNXI_CCU_GATE(bus_be1_clk,	"bus-be1",	"bus-de",
84 		      0x08, BIT(9), 0);
85 static SUNXI_CCU_GATE(bus_be2_clk,	"bus-be2",	"bus-de",
86 		      0x08, BIT(10), 0);
87 static SUNXI_CCU_GATE(bus_drc0_clk,	"bus-drc0",	"bus-de",
88 		      0x08, BIT(12), 0);
89 static SUNXI_CCU_GATE(bus_drc1_clk,	"bus-drc1",	"bus-de",
90 		      0x08, BIT(13), 0);
91 
92 static SUNXI_CCU_M(fe0_div_clk, "fe0-div", "de", 0x20, 0, 4, 0);
93 static SUNXI_CCU_M(fe1_div_clk, "fe1-div", "de", 0x20, 4, 4, 0);
94 static SUNXI_CCU_M(fe2_div_clk, "fe2-div", "de", 0x20, 8, 4, 0);
95 static SUNXI_CCU_M(be0_div_clk, "be0-div", "de", 0x20, 16, 4, 0);
96 static SUNXI_CCU_M(be1_div_clk, "be1-div", "de", 0x20, 20, 4, 0);
97 static SUNXI_CCU_M(be2_div_clk, "be2-div", "de", 0x20, 24, 4, 0);
98 
99 static struct ccu_common *sun9i_a80_de_clks[] = {
100 	&fe0_clk.common,
101 	&fe1_clk.common,
102 	&fe2_clk.common,
103 	&iep_deu0_clk.common,
104 	&iep_deu1_clk.common,
105 	&be0_clk.common,
106 	&be1_clk.common,
107 	&be2_clk.common,
108 	&iep_drc0_clk.common,
109 	&iep_drc1_clk.common,
110 	&merge_clk.common,
111 
112 	&dram_fe0_clk.common,
113 	&dram_fe1_clk.common,
114 	&dram_fe2_clk.common,
115 	&dram_deu0_clk.common,
116 	&dram_deu1_clk.common,
117 	&dram_be0_clk.common,
118 	&dram_be1_clk.common,
119 	&dram_be2_clk.common,
120 	&dram_drc0_clk.common,
121 	&dram_drc1_clk.common,
122 
123 	&bus_fe0_clk.common,
124 	&bus_fe1_clk.common,
125 	&bus_fe2_clk.common,
126 	&bus_deu0_clk.common,
127 	&bus_deu1_clk.common,
128 	&bus_be0_clk.common,
129 	&bus_be1_clk.common,
130 	&bus_be2_clk.common,
131 	&bus_drc0_clk.common,
132 	&bus_drc1_clk.common,
133 
134 	&fe0_div_clk.common,
135 	&fe1_div_clk.common,
136 	&fe2_div_clk.common,
137 	&be0_div_clk.common,
138 	&be1_div_clk.common,
139 	&be2_div_clk.common,
140 };
141 
142 static struct clk_hw_onecell_data sun9i_a80_de_hw_clks = {
143 	.hws	= {
144 		[CLK_FE0]	= &fe0_clk.common.hw,
145 		[CLK_FE1]	= &fe1_clk.common.hw,
146 		[CLK_FE2]	= &fe2_clk.common.hw,
147 		[CLK_IEP_DEU0]	= &iep_deu0_clk.common.hw,
148 		[CLK_IEP_DEU1]	= &iep_deu1_clk.common.hw,
149 		[CLK_BE0]	= &be0_clk.common.hw,
150 		[CLK_BE1]	= &be1_clk.common.hw,
151 		[CLK_BE2]	= &be2_clk.common.hw,
152 		[CLK_IEP_DRC0]	= &iep_drc0_clk.common.hw,
153 		[CLK_IEP_DRC1]	= &iep_drc1_clk.common.hw,
154 		[CLK_MERGE]	= &merge_clk.common.hw,
155 
156 		[CLK_DRAM_FE0]	= &dram_fe0_clk.common.hw,
157 		[CLK_DRAM_FE1]	= &dram_fe1_clk.common.hw,
158 		[CLK_DRAM_FE2]	= &dram_fe2_clk.common.hw,
159 		[CLK_DRAM_DEU0]	= &dram_deu0_clk.common.hw,
160 		[CLK_DRAM_DEU1]	= &dram_deu1_clk.common.hw,
161 		[CLK_DRAM_BE0]	= &dram_be0_clk.common.hw,
162 		[CLK_DRAM_BE1]	= &dram_be1_clk.common.hw,
163 		[CLK_DRAM_BE2]	= &dram_be2_clk.common.hw,
164 		[CLK_DRAM_DRC0]	= &dram_drc0_clk.common.hw,
165 		[CLK_DRAM_DRC1]	= &dram_drc1_clk.common.hw,
166 
167 		[CLK_BUS_FE0]	= &bus_fe0_clk.common.hw,
168 		[CLK_BUS_FE1]	= &bus_fe1_clk.common.hw,
169 		[CLK_BUS_FE2]	= &bus_fe2_clk.common.hw,
170 		[CLK_BUS_DEU0]	= &bus_deu0_clk.common.hw,
171 		[CLK_BUS_DEU1]	= &bus_deu1_clk.common.hw,
172 		[CLK_BUS_BE0]	= &bus_be0_clk.common.hw,
173 		[CLK_BUS_BE1]	= &bus_be1_clk.common.hw,
174 		[CLK_BUS_BE2]	= &bus_be2_clk.common.hw,
175 		[CLK_BUS_DRC0]	= &bus_drc0_clk.common.hw,
176 		[CLK_BUS_DRC1]	= &bus_drc1_clk.common.hw,
177 
178 		[CLK_FE0_DIV]	= &fe0_div_clk.common.hw,
179 		[CLK_FE1_DIV]	= &fe1_div_clk.common.hw,
180 		[CLK_FE2_DIV]	= &fe2_div_clk.common.hw,
181 		[CLK_BE0_DIV]	= &be0_div_clk.common.hw,
182 		[CLK_BE1_DIV]	= &be1_div_clk.common.hw,
183 		[CLK_BE2_DIV]	= &be2_div_clk.common.hw,
184 	},
185 	.num	= CLK_NUMBER,
186 };
187 
188 static struct ccu_reset_map sun9i_a80_de_resets[] = {
189 	[RST_FE0]	= { 0x0c, BIT(0) },
190 	[RST_FE1]	= { 0x0c, BIT(1) },
191 	[RST_FE2]	= { 0x0c, BIT(2) },
192 	[RST_DEU0]	= { 0x0c, BIT(4) },
193 	[RST_DEU1]	= { 0x0c, BIT(5) },
194 	[RST_BE0]	= { 0x0c, BIT(8) },
195 	[RST_BE1]	= { 0x0c, BIT(9) },
196 	[RST_BE2]	= { 0x0c, BIT(10) },
197 	[RST_DRC0]	= { 0x0c, BIT(12) },
198 	[RST_DRC1]	= { 0x0c, BIT(13) },
199 	[RST_MERGE]	= { 0x0c, BIT(20) },
200 };
201 
202 static const struct sunxi_ccu_desc sun9i_a80_de_clk_desc = {
203 	.ccu_clks	= sun9i_a80_de_clks,
204 	.num_ccu_clks	= ARRAY_SIZE(sun9i_a80_de_clks),
205 
206 	.hw_clks	= &sun9i_a80_de_hw_clks,
207 
208 	.resets		= sun9i_a80_de_resets,
209 	.num_resets	= ARRAY_SIZE(sun9i_a80_de_resets),
210 };
211 
212 static int sun9i_a80_de_clk_probe(struct platform_device *pdev)
213 {
214 	struct resource *res;
215 	struct clk *bus_clk;
216 	struct reset_control *rstc;
217 	void __iomem *reg;
218 	int ret;
219 
220 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
221 	reg = devm_ioremap_resource(&pdev->dev, res);
222 	if (IS_ERR(reg))
223 		return PTR_ERR(reg);
224 
225 	bus_clk = devm_clk_get(&pdev->dev, "bus");
226 	if (IS_ERR(bus_clk)) {
227 		ret = PTR_ERR(bus_clk);
228 		if (ret != -EPROBE_DEFER)
229 			dev_err(&pdev->dev, "Couldn't get bus clk: %d\n", ret);
230 		return ret;
231 	}
232 
233 	rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
234 	if (IS_ERR(rstc)) {
235 		ret = PTR_ERR(rstc);
236 		if (ret != -EPROBE_DEFER)
237 			dev_err(&pdev->dev,
238 				"Couldn't get reset control: %d\n", ret);
239 		return ret;
240 	}
241 
242 	/* The bus clock needs to be enabled for us to access the registers */
243 	ret = clk_prepare_enable(bus_clk);
244 	if (ret) {
245 		dev_err(&pdev->dev, "Couldn't enable bus clk: %d\n", ret);
246 		return ret;
247 	}
248 
249 	/* The reset control needs to be asserted for the controls to work */
250 	ret = reset_control_deassert(rstc);
251 	if (ret) {
252 		dev_err(&pdev->dev,
253 			"Couldn't deassert reset control: %d\n", ret);
254 		goto err_disable_clk;
255 	}
256 
257 	ret = sunxi_ccu_probe(pdev->dev.of_node, reg,
258 			      &sun9i_a80_de_clk_desc);
259 	if (ret)
260 		goto err_assert_reset;
261 
262 	return 0;
263 
264 err_assert_reset:
265 	reset_control_assert(rstc);
266 err_disable_clk:
267 	clk_disable_unprepare(bus_clk);
268 	return ret;
269 }
270 
271 static const struct of_device_id sun9i_a80_de_clk_ids[] = {
272 	{ .compatible = "allwinner,sun9i-a80-de-clks" },
273 	{ }
274 };
275 
276 static struct platform_driver sun9i_a80_de_clk_driver = {
277 	.probe	= sun9i_a80_de_clk_probe,
278 	.driver	= {
279 		.name	= "sun9i-a80-de-clks",
280 		.of_match_table	= sun9i_a80_de_clk_ids,
281 	},
282 };
283 builtin_platform_driver(sun9i_a80_de_clk_driver);
284