aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Turquette <mturquette@baylibre.com>2016-07-08 21:08:56 -0400
committerMichael Turquette <mturquette@baylibre.com>2016-07-08 21:08:56 -0400
commit7adb76956189d10fd77f00b41b4d413480e94715 (patch)
treec15068fb36576a29846788bea9d15a327f970fd1
parenta06498297d233fd5074da14f25e72c2f104561d3 (diff)
parent0577e4853bfb4c65f620fa56d3157692df7f766e (diff)
Merge branch 'clk-sunxi-ng' into clk-next
-rw-r--r--Documentation/devicetree/bindings/clock/sunxi-ccu.txt24
-rw-r--r--drivers/clk/Kconfig1
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/sunxi-ng/Kconfig65
-rw-r--r--drivers/clk/sunxi-ng/Makefile20
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun8i-h3.c826
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun8i-h3.h62
-rw-r--r--drivers/clk/sunxi-ng/ccu_common.c90
-rw-r--r--drivers/clk/sunxi-ng/ccu_common.h85
-rw-r--r--drivers/clk/sunxi-ng/ccu_div.c136
-rw-r--r--drivers/clk/sunxi-ng/ccu_div.h133
-rw-r--r--drivers/clk/sunxi-ng/ccu_frac.c110
-rw-r--r--drivers/clk/sunxi-ng/ccu_frac.h53
-rw-r--r--drivers/clk/sunxi-ng/ccu_gate.c82
-rw-r--r--drivers/clk/sunxi-ng/ccu_gate.h52
-rw-r--r--drivers/clk/sunxi-ng/ccu_mp.c158
-rw-r--r--drivers/clk/sunxi-ng/ccu_mp.h77
-rw-r--r--drivers/clk/sunxi-ng/ccu_mult.h15
-rw-r--r--drivers/clk/sunxi-ng/ccu_mux.c187
-rw-r--r--drivers/clk/sunxi-ng/ccu_mux.h91
-rw-r--r--drivers/clk/sunxi-ng/ccu_nk.c147
-rw-r--r--drivers/clk/sunxi-ng/ccu_nk.h71
-rw-r--r--drivers/clk/sunxi-ng/ccu_nkm.c153
-rw-r--r--drivers/clk/sunxi-ng/ccu_nkm.h68
-rw-r--r--drivers/clk/sunxi-ng/ccu_nkmp.c167
-rw-r--r--drivers/clk/sunxi-ng/ccu_nkmp.h71
-rw-r--r--drivers/clk/sunxi-ng/ccu_nm.c114
-rw-r--r--drivers/clk/sunxi-ng/ccu_nm.h91
-rw-r--r--drivers/clk/sunxi-ng/ccu_phase.c126
-rw-r--r--drivers/clk/sunxi-ng/ccu_phase.h50
-rw-r--r--drivers/clk/sunxi-ng/ccu_reset.c55
-rw-r--r--drivers/clk/sunxi-ng/ccu_reset.h40
-rw-r--r--include/dt-bindings/clock/sun8i-h3-ccu.h145
-rw-r--r--include/dt-bindings/reset/sun8i-h3-ccu.h103
34 files changed, 3669 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt
new file mode 100644
index 000000000000..cb91507ffb1e
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt
@@ -0,0 +1,24 @@
1Allwinner Clock Control Unit Binding
2------------------------------------
3
4Required properties :
5- compatible: must contain one of the following compatible:
6 - "allwinner,sun8i-h3-ccu"
7
8- reg: Must contain the registers base address and length
9- clocks: phandle to the oscillators feeding the CCU. Two are needed:
10 - "hosc": the high frequency oscillator (usually at 24MHz)
11 - "losc": the low frequency oscillator (usually at 32kHz)
12- clock-names: Must contain the clock names described just above
13- #clock-cells : must contain 1
14- #reset-cells : must contain 1
15
16Example:
17ccu: clock@01c20000 {
18 compatible = "allwinner,sun8i-h3-ccu";
19 reg = <0x01c20000 0x400>;
20 clocks = <&osc24M>, <&osc32k>;
21 clock-names = "hosc", "losc";
22 #clock-cells = <1>;
23 #reset-cells = <1>;
24};
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 7cef0503429a..4d84be999f55 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -214,6 +214,7 @@ source "drivers/clk/mvebu/Kconfig"
214source "drivers/clk/qcom/Kconfig" 214source "drivers/clk/qcom/Kconfig"
215source "drivers/clk/renesas/Kconfig" 215source "drivers/clk/renesas/Kconfig"
216source "drivers/clk/samsung/Kconfig" 216source "drivers/clk/samsung/Kconfig"
217source "drivers/clk/sunxi-ng/Kconfig"
217source "drivers/clk/tegra/Kconfig" 218source "drivers/clk/tegra/Kconfig"
218source "drivers/clk/ti/Kconfig" 219source "drivers/clk/ti/Kconfig"
219 220
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index af03eb2f6c05..afbf1ad64cc2 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -79,6 +79,7 @@ obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
79obj-$(CONFIG_PLAT_SPEAR) += spear/ 79obj-$(CONFIG_PLAT_SPEAR) += spear/
80obj-$(CONFIG_ARCH_STI) += st/ 80obj-$(CONFIG_ARCH_STI) += st/
81obj-$(CONFIG_ARCH_SUNXI) += sunxi/ 81obj-$(CONFIG_ARCH_SUNXI) += sunxi/
82obj-$(CONFIG_ARCH_SUNXI) += sunxi-ng/
82obj-$(CONFIG_ARCH_TEGRA) += tegra/ 83obj-$(CONFIG_ARCH_TEGRA) += tegra/
83obj-y += ti/ 84obj-y += ti/
84obj-$(CONFIG_ARCH_U8500) += ux500/ 85obj-$(CONFIG_ARCH_U8500) += ux500/
diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig
new file mode 100644
index 000000000000..41e53e8d4d41
--- /dev/null
+++ b/drivers/clk/sunxi-ng/Kconfig
@@ -0,0 +1,65 @@
1config SUNXI_CCU
2 bool "Clock support for Allwinner SoCs"
3 default ARCH_SUNXI
4
5if SUNXI_CCU
6
7# Base clock types
8
9config SUNXI_CCU_DIV
10 bool
11 select SUNXI_CCU_MUX
12
13config SUNXI_CCU_FRAC
14 bool
15
16config SUNXI_CCU_GATE
17 bool
18
19config SUNXI_CCU_MUX
20 bool
21
22config SUNXI_CCU_PHASE
23 bool
24
25# Multi-factor clocks
26
27config SUNXI_CCU_NK
28 bool
29 select SUNXI_CCU_GATE
30
31config SUNXI_CCU_NKM
32 bool
33 select RATIONAL
34 select SUNXI_CCU_GATE
35
36config SUNXI_CCU_NKMP
37 bool
38 select RATIONAL
39 select SUNXI_CCU_GATE
40
41config SUNXI_CCU_NM
42 bool
43 select RATIONAL
44 select SUNXI_CCU_FRAC
45 select SUNXI_CCU_GATE
46
47config SUNXI_CCU_MP
48 bool
49 select SUNXI_CCU_GATE
50 select SUNXI_CCU_MUX
51
52# SoC Drivers
53
54config SUN8I_H3_CCU
55 bool "Support for the Allwinner H3 CCU"
56 select SUNXI_CCU_DIV
57 select SUNXI_CCU_NK
58 select SUNXI_CCU_NKM
59 select SUNXI_CCU_NKMP
60 select SUNXI_CCU_NM
61 select SUNXI_CCU_MP
62 select SUNXI_CCU_PHASE
63 default ARCH_SUN8I
64
65endif
diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile
new file mode 100644
index 000000000000..633ce642ffae
--- /dev/null
+++ b/drivers/clk/sunxi-ng/Makefile
@@ -0,0 +1,20 @@
1# Common objects
2obj-$(CONFIG_SUNXI_CCU) += ccu_common.o
3obj-$(CONFIG_SUNXI_CCU) += ccu_reset.o
4
5# Base clock types
6obj-$(CONFIG_SUNXI_CCU_DIV) += ccu_div.o
7obj-$(CONFIG_SUNXI_CCU_FRAC) += ccu_frac.o
8obj-$(CONFIG_SUNXI_CCU_GATE) += ccu_gate.o
9obj-$(CONFIG_SUNXI_CCU_MUX) += ccu_mux.o
10obj-$(CONFIG_SUNXI_CCU_PHASE) += ccu_phase.o
11
12# Multi-factor clocks
13obj-$(CONFIG_SUNXI_CCU_NK) += ccu_nk.o
14obj-$(CONFIG_SUNXI_CCU_NKM) += ccu_nkm.o
15obj-$(CONFIG_SUNXI_CCU_NKMP) += ccu_nkmp.o
16obj-$(CONFIG_SUNXI_CCU_NM) += ccu_nm.o
17obj-$(CONFIG_SUNXI_CCU_MP) += ccu_mp.o
18
19# SoC support
20obj-$(CONFIG_SUN8I_H3_CCU) += ccu-sun8i-h3.o
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
new file mode 100644
index 000000000000..bcc0a95549d3
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
@@ -0,0 +1,826 @@
1/*
2 * Copyright (c) 2016 Maxime Ripard. 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-provider.h>
15#include <linux/of_address.h>
16
17#include "ccu_common.h"
18#include "ccu_reset.h"
19
20#include "ccu_div.h"
21#include "ccu_gate.h"
22#include "ccu_mp.h"
23#include "ccu_mult.h"
24#include "ccu_nk.h"
25#include "ccu_nkm.h"
26#include "ccu_nkmp.h"
27#include "ccu_nm.h"
28#include "ccu_phase.h"
29
30#include "ccu-sun8i-h3.h"
31
32static SUNXI_CCU_NKMP_WITH_GATE_LOCK(pll_cpux_clk, "pll-cpux",
33 "osc24M", 0x000,
34 8, 5, /* N */
35 4, 2, /* K */
36 0, 2, /* M */
37 16, 2, /* P */
38 BIT(31), /* gate */
39 BIT(28), /* lock */
40 0);
41
42/*
43 * The Audio PLL is supposed to have 4 outputs: 3 fixed factors from
44 * the base (2x, 4x and 8x), and one variable divider (the one true
45 * pll audio).
46 *
47 * We don't have any need for the variable divider for now, so we just
48 * hardcode it to match with the clock names
49 */
50#define SUN8I_H3_PLL_AUDIO_REG 0x008
51
52static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base",
53 "osc24M", 0x008,
54 8, 7, /* N */
55 0, 5, /* M */
56 BIT(31), /* gate */
57 BIT(28), /* lock */
58 0);
59
60static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video_clk, "pll-video",
61 "osc24M", 0x0010,
62 8, 7, /* N */
63 0, 4, /* M */
64 BIT(24), /* frac enable */
65 BIT(25), /* frac select */
66 270000000, /* frac rate 0 */
67 297000000, /* frac rate 1 */
68 BIT(31), /* gate */
69 BIT(28), /* lock */
70 0);
71
72static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve",
73 "osc24M", 0x0018,
74 8, 7, /* N */
75 0, 4, /* M */
76 BIT(24), /* frac enable */
77 BIT(25), /* frac select */
78 270000000, /* frac rate 0 */
79 297000000, /* frac rate 1 */
80 BIT(31), /* gate */
81 BIT(28), /* lock */
82 0);
83
84static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_ddr_clk, "pll-ddr",
85 "osc24M", 0x020,
86 8, 5, /* N */
87 4, 2, /* K */
88 0, 2, /* M */
89 BIT(31), /* gate */
90 BIT(28), /* lock */
91 0);
92
93static SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV(pll_periph0_clk, "pll-periph0",
94 "osc24M", 0x028,
95 8, 5, /* N */
96 4, 2, /* K */
97 BIT(31), /* gate */
98 BIT(28), /* lock */
99 2, /* post-div */
100 0);
101
102static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_gpu_clk, "pll-gpu",
103 "osc24M", 0x0038,
104 8, 7, /* N */
105 0, 4, /* M */
106 BIT(24), /* frac enable */
107 BIT(25), /* frac select */
108 270000000, /* frac rate 0 */
109 297000000, /* frac rate 1 */
110 BIT(31), /* gate */
111 BIT(28), /* lock */
112 0);
113
114static SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV(pll_periph1_clk, "pll-periph1",
115 "osc24M", 0x044,
116 8, 5, /* N */
117 4, 2, /* K */
118 BIT(31), /* gate */
119 BIT(28), /* lock */
120 2, /* post-div */
121 0);
122
123static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_de_clk, "pll-de",
124 "osc24M", 0x0048,
125 8, 7, /* N */
126 0, 4, /* M */
127 BIT(24), /* frac enable */
128 BIT(25), /* frac select */
129 270000000, /* frac rate 0 */
130 297000000, /* frac rate 1 */
131 BIT(31), /* gate */
132 BIT(28), /* lock */
133 0);
134
135static const char * const cpux_parents[] = { "osc32k", "osc24M",
136 "pll-cpux" , "pll-cpux" };
137static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents,
138 0x050, 16, 2, CLK_IS_CRITICAL);
139
140static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x050, 0, 2, 0);
141
142static const char * const ahb1_parents[] = { "osc32k", "osc24M",
143 "axi" , "pll-periph0" };
144static struct ccu_div ahb1_clk = {
145 .div = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO),
146
147 .mux = {
148 .shift = 12,
149 .width = 2,
150
151 .variable_prediv = {
152 .index = 3,
153 .shift = 6,
154 .width = 2,
155 },
156 },
157
158 .common = {
159 .reg = 0x054,
160 .features = CCU_FEATURE_VARIABLE_PREDIV,
161 .hw.init = CLK_HW_INIT_PARENTS("ahb1",
162 ahb1_parents,
163 &ccu_div_ops,
164 0),
165 },
166};
167
168static struct clk_div_table apb1_div_table[] = {
169 { .val = 0, .div = 2 },
170 { .val = 1, .div = 2 },
171 { .val = 2, .div = 4 },
172 { .val = 3, .div = 8 },
173 { /* Sentinel */ },
174};
175static SUNXI_CCU_DIV_TABLE(apb1_clk, "apb1", "ahb1",
176 0x054, 8, 2, apb1_div_table, 0);
177
178static const char * const apb2_parents[] = { "osc32k", "osc24M",
179 "pll-periph0" , "pll-periph0" };
180static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", apb2_parents, 0x058,
181 0, 5, /* M */
182 16, 2, /* P */
183 24, 2, /* mux */
184 0);
185
186static const char * const ahb2_parents[] = { "ahb1" , "pll-periph0" };
187static struct ccu_mux ahb2_clk = {
188 .mux = {
189 .shift = 0,
190 .width = 1,
191
192 .fixed_prediv = {
193 .index = 1,
194 .div = 2,
195 },
196 },
197
198 .common = {
199 .reg = 0x05c,
200 .features = CCU_FEATURE_FIXED_PREDIV,
201 .hw.init = CLK_HW_INIT_PARENTS("ahb2",
202 ahb2_parents,
203 &ccu_mux_ops,
204 0),
205 },
206};
207
208static SUNXI_CCU_GATE(bus_ce_clk, "bus-ce", "ahb1",
209 0x060, BIT(5), 0);
210static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "ahb1",
211 0x060, BIT(6), 0);
212static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb1",
213 0x060, BIT(8), 0);
214static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb1",
215 0x060, BIT(9), 0);
216static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb1",
217 0x060, BIT(10), 0);
218static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb1",
219 0x060, BIT(13), 0);
220static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "ahb1",
221 0x060, BIT(14), 0);
222static SUNXI_CCU_GATE(bus_emac_clk, "bus-emac", "ahb2",
223 0x060, BIT(17), 0);
224static SUNXI_CCU_GATE(bus_ts_clk, "bus-ts", "ahb1",
225 0x060, BIT(18), 0);
226static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "ahb1",
227 0x060, BIT(19), 0);
228static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb1",
229 0x060, BIT(20), 0);
230static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb1",
231 0x060, BIT(21), 0);
232static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb1",
233 0x060, BIT(23), 0);
234static SUNXI_CCU_GATE(bus_ehci0_clk, "bus-ehci0", "ahb1",
235 0x060, BIT(24), 0);
236static SUNXI_CCU_GATE(bus_ehci1_clk, "bus-ehci1", "ahb2",
237 0x060, BIT(25), 0);
238static SUNXI_CCU_GATE(bus_ehci2_clk, "bus-ehci2", "ahb2",
239 0x060, BIT(26), 0);
240static SUNXI_CCU_GATE(bus_ehci3_clk, "bus-ehci3", "ahb2",
241 0x060, BIT(27), 0);
242static SUNXI_CCU_GATE(bus_ohci0_clk, "bus-ohci0", "ahb1",
243 0x060, BIT(28), 0);
244static SUNXI_CCU_GATE(bus_ohci1_clk, "bus-ohci1", "ahb2",
245 0x060, BIT(29), 0);
246static SUNXI_CCU_GATE(bus_ohci2_clk, "bus-ohci2", "ahb2",
247 0x060, BIT(30), 0);
248static SUNXI_CCU_GATE(bus_ohci3_clk, "bus-ohci3", "ahb2",
249 0x060, BIT(31), 0);
250
251static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "ahb1",
252 0x064, BIT(0), 0);
253static SUNXI_CCU_GATE(bus_tcon0_clk, "bus-tcon0", "ahb1",
254 0x064, BIT(3), 0);
255static SUNXI_CCU_GATE(bus_tcon1_clk, "bus-tcon1", "ahb1",
256 0x064, BIT(4), 0);
257static SUNXI_CCU_GATE(bus_deinterlace_clk, "bus-deinterlace", "ahb1",
258 0x064, BIT(5), 0);
259static SUNXI_CCU_GATE(bus_csi_clk, "bus-csi", "ahb1",
260 0x064, BIT(8), 0);
261static SUNXI_CCU_GATE(bus_tve_clk, "bus-tve", "ahb1",
262 0x064, BIT(9), 0);
263static SUNXI_CCU_GATE(bus_hdmi_clk, "bus-hdmi", "ahb1",
264 0x064, BIT(11), 0);
265static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "ahb1",
266 0x064, BIT(12), 0);
267static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "ahb1",
268 0x064, BIT(20), 0);
269static SUNXI_CCU_GATE(bus_msgbox_clk, "bus-msgbox", "ahb1",
270 0x064, BIT(21), 0);
271static SUNXI_CCU_GATE(bus_spinlock_clk, "bus-spinlock", "ahb1",
272 0x064, BIT(22), 0);
273
274static SUNXI_CCU_GATE(bus_codec_clk, "bus-codec", "apb1",
275 0x068, BIT(0), 0);
276static SUNXI_CCU_GATE(bus_spdif_clk, "bus-spdif", "apb1",
277 0x068, BIT(1), 0);
278static SUNXI_CCU_GATE(bus_pio_clk, "bus-pio", "apb1",
279 0x068, BIT(5), 0);
280static SUNXI_CCU_GATE(bus_ths_clk, "bus-ths", "apb1",
281 0x068, BIT(8), 0);
282static SUNXI_CCU_GATE(bus_i2s0_clk, "bus-i2s0", "apb1",
283 0x068, BIT(12), 0);
284static SUNXI_CCU_GATE(bus_i2s1_clk, "bus-i2s1", "apb1",
285 0x068, BIT(13), 0);
286static SUNXI_CCU_GATE(bus_i2s2_clk, "bus-i2s2", "apb1",
287 0x068, BIT(14), 0);
288
289static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2",
290 0x06c, BIT(0), 0);
291static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2",
292 0x06c, BIT(1), 0);
293static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2",
294 0x06c, BIT(2), 0);
295static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2",
296 0x06c, BIT(16), 0);
297static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2",
298 0x06c, BIT(17), 0);
299static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2",
300 0x06c, BIT(18), 0);
301static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", "apb2",
302 0x06c, BIT(19), 0);
303static SUNXI_CCU_GATE(bus_scr_clk, "bus-scr", "apb2",
304 0x06c, BIT(20), 0);
305
306static SUNXI_CCU_GATE(bus_ephy_clk, "bus-ephy", "ahb1",
307 0x070, BIT(0), 0);
308static SUNXI_CCU_GATE(bus_dbg_clk, "bus-dbg", "ahb1",
309 0x070, BIT(7), 0);
310
311static struct clk_div_table ths_div_table[] = {
312 { .val = 0, .div = 1 },
313 { .val = 1, .div = 2 },
314 { .val = 2, .div = 4 },
315 { .val = 3, .div = 6 },
316};
317static SUNXI_CCU_DIV_TABLE_WITH_GATE(ths_clk, "ths", "osc24M",
318 0x074, 0, 2, ths_div_table, BIT(31), 0);
319
320static const char * const mod0_default_parents[] = { "osc24M", "pll-periph0",
321 "pll-periph1" };
322static SUNXI_CCU_MP_WITH_MUX_GATE(nand_clk, "nand", mod0_default_parents, 0x080,
323 0, 4, /* M */
324 16, 2, /* P */
325 24, 2, /* mux */
326 BIT(31), /* gate */
327 0);
328
329static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mod0_default_parents, 0x088,
330 0, 4, /* M */
331 16, 2, /* P */
332 24, 2, /* mux */
333 BIT(31), /* gate */
334 0);
335
336static SUNXI_CCU_PHASE(mmc0_sample_clk, "mmc0_sample", "mmc0",
337 0x088, 20, 3, 0);
338static SUNXI_CCU_PHASE(mmc0_output_clk, "mmc0_output", "mmc0",
339 0x088, 8, 3, 0);
340
341static SUNXI_CCU_MP_WITH_MUX_GATE(mmc1_clk, "mmc1", mod0_default_parents, 0x08c,
342 0, 4, /* M */
343 16, 2, /* P */
344 24, 2, /* mux */
345 BIT(31), /* gate */
346 0);
347
348static SUNXI_CCU_PHASE(mmc1_sample_clk, "mmc1_sample", "mmc1",
349 0x08c, 20, 3, 0);
350static SUNXI_CCU_PHASE(mmc1_output_clk, "mmc1_output", "mmc1",
351 0x08c, 8, 3, 0);
352
353static SUNXI_CCU_MP_WITH_MUX_GATE(mmc2_clk, "mmc2", mod0_default_parents, 0x090,
354 0, 4, /* M */
355 16, 2, /* P */
356 24, 2, /* mux */
357 BIT(31), /* gate */
358 0);
359
360static SUNXI_CCU_PHASE(mmc2_sample_clk, "mmc2_sample", "mmc2",
361 0x090, 20, 3, 0);
362static SUNXI_CCU_PHASE(mmc2_output_clk, "mmc2_output", "mmc2",
363 0x090, 8, 3, 0);
364
365static const char * const ts_parents[] = { "osc24M", "pll-periph0", };
366static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", ts_parents, 0x098,
367 0, 4, /* M */
368 16, 2, /* P */
369 24, 2, /* mux */
370 BIT(31), /* gate */
371 0);
372
373static SUNXI_CCU_MP_WITH_MUX_GATE(ce_clk, "ce", mod0_default_parents, 0x09c,
374 0, 4, /* M */
375 16, 2, /* P */
376 24, 2, /* mux */
377 BIT(31), /* gate */
378 0);
379
380static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", mod0_default_parents, 0x0a0,
381 0, 4, /* M */
382 16, 2, /* P */
383 24, 2, /* mux */
384 BIT(31), /* gate */
385 0);
386
387static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", mod0_default_parents, 0x0a4,
388 0, 4, /* M */
389 16, 2, /* P */
390 24, 2, /* mux */
391 BIT(31), /* gate */
392 0);
393
394static const char * const i2s_parents[] = { "pll-audio-8x", "pll-audio-4x",
395 "pll-audio-2x", "pll-audio" };
396static SUNXI_CCU_MUX_WITH_GATE(i2s0_clk, "i2s0", i2s_parents,
397 0x0b0, 16, 2, BIT(31), 0);
398
399static SUNXI_CCU_MUX_WITH_GATE(i2s1_clk, "i2s1", i2s_parents,
400 0x0b4, 16, 2, BIT(31), 0);
401
402static SUNXI_CCU_MUX_WITH_GATE(i2s2_clk, "i2s2", i2s_parents,
403 0x0b8, 16, 2, BIT(31), 0);
404
405static SUNXI_CCU_M_WITH_GATE(spdif_clk, "spdif", "pll-audio",
406 0x0c0, 0, 4, BIT(31), 0);
407
408static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M",
409 0x0cc, BIT(8), 0);
410static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "osc24M",
411 0x0cc, BIT(9), 0);
412static SUNXI_CCU_GATE(usb_phy2_clk, "usb-phy2", "osc24M",
413 0x0cc, BIT(10), 0);
414static SUNXI_CCU_GATE(usb_phy3_clk, "usb-phy3", "osc24M",
415 0x0cc, BIT(11), 0);
416static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc24M",
417 0x0cc, BIT(16), 0);
418static SUNXI_CCU_GATE(usb_ohci1_clk, "usb-ohci1", "osc24M",
419 0x0cc, BIT(17), 0);
420static SUNXI_CCU_GATE(usb_ohci2_clk, "usb-ohci2", "osc24M",
421 0x0cc, BIT(18), 0);
422static SUNXI_CCU_GATE(usb_ohci3_clk, "usb-ohci3", "osc24M",
423 0x0cc, BIT(19), 0);
424
425static const char * const dram_parents[] = { "pll-ddr", "pll-periph0-2x" };
426static SUNXI_CCU_M_WITH_MUX(dram_clk, "dram", dram_parents,
427 0x0f4, 0, 4, 20, 2, CLK_IS_CRITICAL);
428
429static SUNXI_CCU_GATE(dram_ve_clk, "dram-ve", "dram",
430 0x100, BIT(0), 0);
431static SUNXI_CCU_GATE(dram_csi_clk, "dram-csi", "dram",
432 0x100, BIT(1), 0);
433static SUNXI_CCU_GATE(dram_deinterlace_clk, "dram-deinterlace", "dram",
434 0x100, BIT(2), 0);
435static SUNXI_CCU_GATE(dram_ts_clk, "dram-ts", "dram",
436 0x100, BIT(3), 0);
437
438static const char * const de_parents[] = { "pll-periph0-2x", "pll-de" };
439static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents,
440 0x104, 0, 4, 24, 3, BIT(31), 0);
441
442static const char * const tcon_parents[] = { "pll-video" };
443static SUNXI_CCU_M_WITH_MUX_GATE(tcon_clk, "tcon", tcon_parents,
444 0x118, 0, 4, 24, 3, BIT(31), 0);
445
446static const char * const tve_parents[] = { "pll-de", "pll-periph1" };
447static SUNXI_CCU_M_WITH_MUX_GATE(tve_clk, "tve", tve_parents,
448 0x120, 0, 4, 24, 3, BIT(31), 0);
449
450static const char * const deinterlace_parents[] = { "pll-periph0", "pll-periph1" };
451static SUNXI_CCU_M_WITH_MUX_GATE(deinterlace_clk, "deinterlace", deinterlace_parents,
452 0x124, 0, 4, 24, 3, BIT(31), 0);
453
454static SUNXI_CCU_GATE(csi_misc_clk, "csi-misc", "osc24M",
455 0x130, BIT(31), 0);
456
457static const char * const csi_sclk_parents[] = { "pll-periph0", "pll-periph1" };
458static SUNXI_CCU_M_WITH_MUX_GATE(csi_sclk_clk, "csi-sclk", csi_sclk_parents,
459 0x134, 16, 4, 24, 3, BIT(31), 0);
460
461static const char * const csi_mclk_parents[] = { "osc24M", "pll-video", "pll-periph0" };
462static SUNXI_CCU_M_WITH_MUX_GATE(csi_mclk_clk, "csi-mclk", csi_mclk_parents,
463 0x134, 0, 5, 8, 3, BIT(15), 0);
464
465static SUNXI_CCU_M_WITH_GATE(ve_clk, "ve", "pll-ve",
466 0x13c, 16, 3, BIT(31), 0);
467
468static SUNXI_CCU_GATE(ac_dig_clk, "ac-dig", "pll-audio",
469 0x140, BIT(31), 0);
470static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M",
471 0x144, BIT(31), 0);
472
473static const char * const hdmi_parents[] = { "pll-video" };
474static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents,
475 0x150, 0, 4, 24, 2, BIT(31), 0);
476
477static SUNXI_CCU_GATE(hdmi_ddc_clk, "hdmi-ddc", "osc24M",
478 0x154, BIT(31), 0);
479
480static const char * const mbus_parents[] = { "osc24M", "pll-periph0-2x", "pll-ddr" };
481static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents,
482 0x15c, 0, 3, 24, 2, BIT(31), CLK_IS_CRITICAL);
483
484static SUNXI_CCU_M_WITH_GATE(gpu_clk, "gpu", "pll-gpu",
485 0x1a0, 0, 3, BIT(31), 0);
486
487static struct ccu_common *sun8i_h3_ccu_clks[] = {
488 &pll_cpux_clk.common,
489 &pll_audio_base_clk.common,
490 &pll_video_clk.common,
491 &pll_ve_clk.common,
492 &pll_ddr_clk.common,
493 &pll_periph0_clk.common,
494 &pll_gpu_clk.common,
495 &pll_periph1_clk.common,
496 &pll_de_clk.common,
497 &cpux_clk.common,
498 &axi_clk.common,
499 &ahb1_clk.common,
500 &apb1_clk.common,
501 &apb2_clk.common,
502 &ahb2_clk.common,
503 &bus_ce_clk.common,
504 &bus_dma_clk.common,
505 &bus_mmc0_clk.common,
506 &bus_mmc1_clk.common,
507 &bus_mmc2_clk.common,
508 &bus_nand_clk.common,
509 &bus_dram_clk.common,
510 &bus_emac_clk.common,
511 &bus_ts_clk.common,
512 &bus_hstimer_clk.common,
513 &bus_spi0_clk.common,
514 &bus_spi1_clk.common,
515 &bus_otg_clk.common,
516 &bus_ehci0_clk.common,
517 &bus_ehci1_clk.common,
518 &bus_ehci2_clk.common,
519 &bus_ehci3_clk.common,
520 &bus_ohci0_clk.common,
521 &bus_ohci1_clk.common,
522 &bus_ohci2_clk.common,
523 &bus_ohci3_clk.common,
524 &bus_ve_clk.common,
525 &bus_tcon0_clk.common,
526 &bus_tcon1_clk.common,
527 &bus_deinterlace_clk.common,
528 &bus_csi_clk.common,
529 &bus_tve_clk.common,
530 &bus_hdmi_clk.common,
531 &bus_de_clk.common,
532 &bus_gpu_clk.common,
533 &bus_msgbox_clk.common,
534 &bus_spinlock_clk.common,
535 &bus_codec_clk.common,
536 &bus_spdif_clk.common,
537 &bus_pio_clk.common,
538 &bus_ths_clk.common,
539 &bus_i2s0_clk.common,
540 &bus_i2s1_clk.common,
541 &bus_i2s2_clk.common,
542 &bus_i2c0_clk.common,
543 &bus_i2c1_clk.common,
544 &bus_i2c2_clk.common,
545 &bus_uart0_clk.common,
546 &bus_uart1_clk.common,
547 &bus_uart2_clk.common,
548 &bus_uart3_clk.common,
549 &bus_scr_clk.common,
550 &bus_ephy_clk.common,
551 &bus_dbg_clk.common,
552 &ths_clk.common,
553 &nand_clk.common,
554 &mmc0_clk.common,
555 &mmc0_sample_clk.common,
556 &mmc0_output_clk.common,
557 &mmc1_clk.common,
558 &mmc1_sample_clk.common,
559 &mmc1_output_clk.common,
560 &mmc2_clk.common,
561 &mmc2_sample_clk.common,
562 &mmc2_output_clk.common,
563 &ts_clk.common,
564 &ce_clk.common,
565 &spi0_clk.common,
566 &spi1_clk.common,
567 &i2s0_clk.common,
568 &i2s1_clk.common,
569 &i2s2_clk.common,
570 &spdif_clk.common,
571 &usb_phy0_clk.common,
572 &usb_phy1_clk.common,
573 &usb_phy2_clk.common,
574 &usb_phy3_clk.common,
575 &usb_ohci0_clk.common,
576 &usb_ohci1_clk.common,
577 &usb_ohci2_clk.common,
578 &usb_ohci3_clk.common,
579 &dram_clk.common,
580 &dram_ve_clk.common,
581 &dram_csi_clk.common,
582 &dram_deinterlace_clk.common,
583 &dram_ts_clk.common,
584 &de_clk.common,
585 &tcon_clk.common,
586 &tve_clk.common,
587 &deinterlace_clk.common,
588 &csi_misc_clk.common,
589 &csi_sclk_clk.common,
590 &csi_mclk_clk.common,
591 &ve_clk.common,
592 &ac_dig_clk.common,
593 &avs_clk.common,
594 &hdmi_clk.common,
595 &hdmi_ddc_clk.common,
596 &mbus_clk.common,
597 &gpu_clk.common,
598};
599
600/* We hardcode the divider to 4 for now */
601static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
602 "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT);
603static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
604 "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
605static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
606 "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
607static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
608 "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
609static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x",
610 "pll-periph0", 1, 2, 0);
611
612static struct clk_hw_onecell_data sun8i_h3_hw_clks = {
613 .hws = {
614 [CLK_PLL_CPUX] = &pll_cpux_clk.common.hw,
615 [CLK_PLL_AUDIO_BASE] = &pll_audio_base_clk.common.hw,
616 [CLK_PLL_AUDIO] = &pll_audio_clk.hw,
617 [CLK_PLL_AUDIO_2X] = &pll_audio_2x_clk.hw,
618 [CLK_PLL_AUDIO_4X] = &pll_audio_4x_clk.hw,
619 [CLK_PLL_AUDIO_8X] = &pll_audio_8x_clk.hw,
620 [CLK_PLL_VIDEO] = &pll_video_clk.common.hw,
621 [CLK_PLL_VE] = &pll_ve_clk.common.hw,
622 [CLK_PLL_DDR] = &pll_ddr_clk.common.hw,
623 [CLK_PLL_PERIPH0] = &pll_periph0_clk.common.hw,
624 [CLK_PLL_PERIPH0_2X] = &pll_periph0_2x_clk.hw,
625 [CLK_PLL_GPU] = &pll_gpu_clk.common.hw,
626 [CLK_PLL_PERIPH1] = &pll_periph1_clk.common.hw,
627 [CLK_PLL_DE] = &pll_de_clk.common.hw,
628 [CLK_CPUX] = &cpux_clk.common.hw,
629 [CLK_AXI] = &axi_clk.common.hw,
630 [CLK_AHB1] = &ahb1_clk.common.hw,
631 [CLK_APB1] = &apb1_clk.common.hw,
632 [CLK_APB2] = &apb2_clk.common.hw,
633 [CLK_AHB2] = &ahb2_clk.common.hw,
634 [CLK_BUS_CE] = &bus_ce_clk.common.hw,
635 [CLK_BUS_DMA] = &bus_dma_clk.common.hw,
636 [CLK_BUS_MMC0] = &bus_mmc0_clk.common.hw,
637 [CLK_BUS_MMC1] = &bus_mmc1_clk.common.hw,
638 [CLK_BUS_MMC2] = &bus_mmc2_clk.common.hw,
639 [CLK_BUS_NAND] = &bus_nand_clk.common.hw,
640 [CLK_BUS_DRAM] = &bus_dram_clk.common.hw,
641 [CLK_BUS_EMAC] = &bus_emac_clk.common.hw,
642 [CLK_BUS_TS] = &bus_ts_clk.common.hw,
643 [CLK_BUS_HSTIMER] = &bus_hstimer_clk.common.hw,
644 [CLK_BUS_SPI0] = &bus_spi0_clk.common.hw,
645 [CLK_BUS_SPI1] = &bus_spi1_clk.common.hw,
646 [CLK_BUS_OTG] = &bus_otg_clk.common.hw,
647 [CLK_BUS_EHCI0] = &bus_ehci0_clk.common.hw,
648 [CLK_BUS_EHCI1] = &bus_ehci1_clk.common.hw,
649 [CLK_BUS_EHCI2] = &bus_ehci2_clk.common.hw,
650 [CLK_BUS_EHCI3] = &bus_ehci3_clk.common.hw,
651 [CLK_BUS_OHCI0] = &bus_ohci0_clk.common.hw,
652 [CLK_BUS_OHCI1] = &bus_ohci1_clk.common.hw,
653 [CLK_BUS_OHCI2] = &bus_ohci2_clk.common.hw,
654 [CLK_BUS_OHCI3] = &bus_ohci3_clk.common.hw,
655 [CLK_BUS_VE] = &bus_ve_clk.common.hw,
656 [CLK_BUS_TCON0] = &bus_tcon0_clk.common.hw,
657 [CLK_BUS_TCON1] = &bus_tcon1_clk.common.hw,
658 [CLK_BUS_DEINTERLACE] = &bus_deinterlace_clk.common.hw,
659 [CLK_BUS_CSI] = &bus_csi_clk.common.hw,
660 [CLK_BUS_TVE] = &bus_tve_clk.common.hw,
661 [CLK_BUS_HDMI] = &bus_hdmi_clk.common.hw,
662 [CLK_BUS_DE] = &bus_de_clk.common.hw,
663 [CLK_BUS_GPU] = &bus_gpu_clk.common.hw,
664 [CLK_BUS_MSGBOX] = &bus_msgbox_clk.common.hw,
665 [CLK_BUS_SPINLOCK] = &bus_spinlock_clk.common.hw,
666 [CLK_BUS_CODEC] = &bus_codec_clk.common.hw,
667 [CLK_BUS_SPDIF] = &bus_spdif_clk.common.hw,
668 [CLK_BUS_PIO] = &bus_pio_clk.common.hw,
669 [CLK_BUS_THS] = &bus_ths_clk.common.hw,
670 [CLK_BUS_I2S0] = &bus_i2s0_clk.common.hw,
671 [CLK_BUS_I2S1] = &bus_i2s1_clk.common.hw,
672 [CLK_BUS_I2S2] = &bus_i2s2_clk.common.hw,
673 [CLK_BUS_I2C0] = &bus_i2c0_clk.common.hw,
674 [CLK_BUS_I2C1] = &bus_i2c1_clk.common.hw,
675 [CLK_BUS_I2C2] = &bus_i2c2_clk.common.hw,
676 [CLK_BUS_UART0] = &bus_uart0_clk.common.hw,
677 [CLK_BUS_UART1] = &bus_uart1_clk.common.hw,
678 [CLK_BUS_UART2] = &bus_uart2_clk.common.hw,
679 [CLK_BUS_UART3] = &bus_uart3_clk.common.hw,
680 [CLK_BUS_SCR] = &bus_scr_clk.common.hw,
681 [CLK_BUS_EPHY] = &bus_ephy_clk.common.hw,
682 [CLK_BUS_DBG] = &bus_dbg_clk.common.hw,
683 [CLK_THS] = &ths_clk.common.hw,
684 [CLK_NAND] = &nand_clk.common.hw,
685 [CLK_MMC0] = &mmc0_clk.common.hw,
686 [CLK_MMC0_SAMPLE] = &mmc0_sample_clk.common.hw,
687 [CLK_MMC0_OUTPUT] = &mmc0_output_clk.common.hw,
688 [CLK_MMC1] = &mmc1_clk.common.hw,
689 [CLK_MMC1_SAMPLE] = &mmc1_sample_clk.common.hw,
690 [CLK_MMC1_OUTPUT] = &mmc1_output_clk.common.hw,
691 [CLK_MMC2] = &mmc2_clk.common.hw,
692 [CLK_MMC2_SAMPLE] = &mmc2_sample_clk.common.hw,
693 [CLK_MMC2_OUTPUT] = &mmc2_output_clk.common.hw,
694 [CLK_TS] = &ts_clk.common.hw,
695 [CLK_CE] = &ce_clk.common.hw,
696 [CLK_SPI0] = &spi0_clk.common.hw,
697 [CLK_SPI1] = &spi1_clk.common.hw,
698 [CLK_I2S0] = &i2s0_clk.common.hw,
699 [CLK_I2S1] = &i2s1_clk.common.hw,
700 [CLK_I2S2] = &i2s2_clk.common.hw,
701 [CLK_SPDIF] = &spdif_clk.common.hw,
702 [CLK_USB_PHY0] = &usb_phy0_clk.common.hw,
703 [CLK_USB_PHY1] = &usb_phy1_clk.common.hw,
704 [CLK_USB_PHY2] = &usb_phy2_clk.common.hw,
705 [CLK_USB_PHY3] = &usb_phy3_clk.common.hw,
706 [CLK_USB_OHCI0] = &usb_ohci0_clk.common.hw,
707 [CLK_USB_OHCI1] = &usb_ohci1_clk.common.hw,
708 [CLK_USB_OHCI2] = &usb_ohci2_clk.common.hw,
709 [CLK_USB_OHCI3] = &usb_ohci3_clk.common.hw,
710 [CLK_DRAM] = &dram_clk.common.hw,
711 [CLK_DRAM_VE] = &dram_ve_clk.common.hw,
712 [CLK_DRAM_CSI] = &dram_csi_clk.common.hw,
713 [CLK_DRAM_DEINTERLACE] = &dram_deinterlace_clk.common.hw,
714 [CLK_DRAM_TS] = &dram_ts_clk.common.hw,
715 [CLK_DE] = &de_clk.common.hw,
716 [CLK_TCON0] = &tcon_clk.common.hw,
717 [CLK_TVE] = &tve_clk.common.hw,
718 [CLK_DEINTERLACE] = &deinterlace_clk.common.hw,
719 [CLK_CSI_MISC] = &csi_misc_clk.common.hw,
720 [CLK_CSI_SCLK] = &csi_sclk_clk.common.hw,
721 [CLK_CSI_MCLK] = &csi_mclk_clk.common.hw,
722 [CLK_VE] = &ve_clk.common.hw,
723 [CLK_AC_DIG] = &ac_dig_clk.common.hw,
724 [CLK_AVS] = &avs_clk.common.hw,
725 [CLK_HDMI] = &hdmi_clk.common.hw,
726 [CLK_HDMI_DDC] = &hdmi_ddc_clk.common.hw,
727 [CLK_MBUS] = &mbus_clk.common.hw,
728 [CLK_GPU] = &gpu_clk.common.hw,
729 },
730 .num = CLK_NUMBER,
731};
732
733static struct ccu_reset_map sun8i_h3_ccu_resets[] = {
734 [RST_USB_PHY0] = { 0x0cc, BIT(0) },
735 [RST_USB_PHY1] = { 0x0cc, BIT(1) },
736 [RST_USB_PHY2] = { 0x0cc, BIT(2) },
737 [RST_USB_PHY3] = { 0x0cc, BIT(3) },
738
739 [RST_MBUS] = { 0x0fc, BIT(31) },
740
741 [RST_BUS_CE] = { 0x2c0, BIT(5) },
742 [RST_BUS_DMA] = { 0x2c0, BIT(6) },
743 [RST_BUS_MMC0] = { 0x2c0, BIT(8) },
744 [RST_BUS_MMC1] = { 0x2c0, BIT(9) },
745 [RST_BUS_MMC2] = { 0x2c0, BIT(10) },
746 [RST_BUS_NAND] = { 0x2c0, BIT(13) },
747 [RST_BUS_DRAM] = { 0x2c0, BIT(14) },
748 [RST_BUS_EMAC] = { 0x2c0, BIT(17) },
749 [RST_BUS_TS] = { 0x2c0, BIT(18) },
750 [RST_BUS_HSTIMER] = { 0x2c0, BIT(19) },
751 [RST_BUS_SPI0] = { 0x2c0, BIT(20) },
752 [RST_BUS_SPI1] = { 0x2c0, BIT(21) },
753 [RST_BUS_OTG] = { 0x2c0, BIT(23) },
754 [RST_BUS_EHCI0] = { 0x2c0, BIT(24) },
755 [RST_BUS_EHCI1] = { 0x2c0, BIT(25) },
756 [RST_BUS_EHCI2] = { 0x2c0, BIT(26) },
757 [RST_BUS_EHCI3] = { 0x2c0, BIT(27) },
758 [RST_BUS_OHCI0] = { 0x2c0, BIT(28) },
759 [RST_BUS_OHCI1] = { 0x2c0, BIT(29) },
760 [RST_BUS_OHCI2] = { 0x2c0, BIT(30) },
761 [RST_BUS_OHCI3] = { 0x2c0, BIT(31) },
762
763 [RST_BUS_VE] = { 0x2c4, BIT(0) },
764 [RST_BUS_TCON0] = { 0x2c4, BIT(3) },
765 [RST_BUS_TCON1] = { 0x2c4, BIT(4) },
766 [RST_BUS_DEINTERLACE] = { 0x2c4, BIT(5) },
767 [RST_BUS_CSI] = { 0x2c4, BIT(8) },
768 [RST_BUS_TVE] = { 0x2c4, BIT(9) },
769 [RST_BUS_HDMI0] = { 0x2c4, BIT(10) },
770 [RST_BUS_HDMI1] = { 0x2c4, BIT(11) },
771 [RST_BUS_DE] = { 0x2c4, BIT(12) },
772 [RST_BUS_GPU] = { 0x2c4, BIT(20) },
773 [RST_BUS_MSGBOX] = { 0x2c4, BIT(21) },
774 [RST_BUS_SPINLOCK] = { 0x2c4, BIT(22) },
775 [RST_BUS_DBG] = { 0x2c4, BIT(31) },
776
777 [RST_BUS_EPHY] = { 0x2c8, BIT(2) },
778
779 [RST_BUS_CODEC] = { 0x2d0, BIT(0) },
780 [RST_BUS_SPDIF] = { 0x2d0, BIT(1) },
781 [RST_BUS_THS] = { 0x2d0, BIT(8) },
782 [RST_BUS_I2S0] = { 0x2d0, BIT(12) },
783 [RST_BUS_I2S1] = { 0x2d0, BIT(13) },
784 [RST_BUS_I2S2] = { 0x2d0, BIT(14) },
785
786 [RST_BUS_I2C0] = { 0x2d4, BIT(0) },
787 [RST_BUS_I2C1] = { 0x2d4, BIT(1) },
788 [RST_BUS_I2C2] = { 0x2d4, BIT(2) },
789 [RST_BUS_UART0] = { 0x2d4, BIT(16) },
790 [RST_BUS_UART1] = { 0x2d4, BIT(17) },
791 [RST_BUS_UART2] = { 0x2d4, BIT(18) },
792 [RST_BUS_UART3] = { 0x2d4, BIT(19) },
793 [RST_BUS_SCR] = { 0x2d4, BIT(20) },
794};
795
796static const struct sunxi_ccu_desc sun8i_h3_ccu_desc = {
797 .ccu_clks = sun8i_h3_ccu_clks,
798 .num_ccu_clks = ARRAY_SIZE(sun8i_h3_ccu_clks),
799
800 .hw_clks = &sun8i_h3_hw_clks,
801
802 .resets = sun8i_h3_ccu_resets,
803 .num_resets = ARRAY_SIZE(sun8i_h3_ccu_resets),
804};
805
806static void __init sun8i_h3_ccu_setup(struct device_node *node)
807{
808 void __iomem *reg;
809 u32 val;
810
811 reg = of_io_request_and_map(node, 0, of_node_full_name(node));
812 if (IS_ERR(reg)) {
813 pr_err("%s: Could not map the clock registers\n",
814 of_node_full_name(node));
815 return;
816 }
817
818 /* Force the PLL-Audio-1x divider to 4 */
819 val = readl(reg + SUN8I_H3_PLL_AUDIO_REG);
820 val &= ~GENMASK(4, 0);
821 writel(val | 3, reg + SUN8I_H3_PLL_AUDIO_REG);
822
823 sunxi_ccu_probe(node, reg, &sun8i_h3_ccu_desc);
824}
825CLK_OF_DECLARE(sun8i_h3_ccu, "allwinner,sun8i-h3-ccu",
826 sun8i_h3_ccu_setup);
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.h b/drivers/clk/sunxi-ng/ccu-sun8i-h3.h
new file mode 100644
index 000000000000..78be712c7487
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.h
@@ -0,0 +1,62 @@
1/*
2 * Copyright 2016 Maxime Ripard
3 *
4 * Maxime Ripard <maxime.ripard@free-electrons.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#ifndef _CCU_SUN8I_H3_H_
18#define _CCU_SUN8I_H3_H_
19
20#include <dt-bindings/clock/sun8i-h3-ccu.h>
21#include <dt-bindings/reset/sun8i-h3-ccu.h>
22
23#define CLK_PLL_CPUX 0
24#define CLK_PLL_AUDIO_BASE 1
25#define CLK_PLL_AUDIO 2
26#define CLK_PLL_AUDIO_2X 3
27#define CLK_PLL_AUDIO_4X 4
28#define CLK_PLL_AUDIO_8X 5
29#define CLK_PLL_VIDEO 6
30#define CLK_PLL_VE 7
31#define CLK_PLL_DDR 8
32#define CLK_PLL_PERIPH0 9
33#define CLK_PLL_PERIPH0_2X 10
34#define CLK_PLL_GPU 11
35#define CLK_PLL_PERIPH1 12
36#define CLK_PLL_DE 13
37
38/* The CPUX clock is exported */
39
40#define CLK_AXI 15
41#define CLK_AHB1 16
42#define CLK_APB1 17
43#define CLK_APB2 18
44#define CLK_AHB2 19
45
46/* All the bus gates are exported */
47
48/* The first bunch of module clocks are exported */
49
50#define CLK_DRAM 96
51
52/* All the DRAM gates are exported */
53
54/* Some more module clocks are exported */
55
56#define CLK_MBUS 113
57
58/* And the GPU module clock is exported */
59
60#define CLK_NUMBER (CLK_GPU + 1)
61
62#endif /* _CCU_SUN8I_H3_H_ */
diff --git a/drivers/clk/sunxi-ng/ccu_common.c b/drivers/clk/sunxi-ng/ccu_common.c
new file mode 100644
index 000000000000..fc17b5295e16
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_common.c
@@ -0,0 +1,90 @@
1/*
2 * Copyright 2016 Maxime Ripard
3 *
4 * Maxime Ripard <maxime.ripard@free-electrons.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/clk-provider.h>
18#include <linux/iopoll.h>
19#include <linux/slab.h>
20
21#include "ccu_common.h"
22#include "ccu_reset.h"
23
24static DEFINE_SPINLOCK(ccu_lock);
25
26void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock)
27{
28 u32 reg;
29
30 if (!lock)
31 return;
32
33 WARN_ON(readl_relaxed_poll_timeout(common->base + common->reg, reg,
34 !(reg & lock), 100, 70000));
35}
36
37int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
38 const struct sunxi_ccu_desc *desc)
39{
40 struct ccu_reset *reset;
41 int i, ret;
42
43 for (i = 0; i < desc->num_ccu_clks; i++) {
44 struct ccu_common *cclk = desc->ccu_clks[i];
45
46 if (!cclk)
47 continue;
48
49 cclk->base = reg;
50 cclk->lock = &ccu_lock;
51 }
52
53 for (i = 0; i < desc->hw_clks->num ; i++) {
54 struct clk_hw *hw = desc->hw_clks->hws[i];
55
56 if (!hw)
57 continue;
58
59 ret = clk_hw_register(NULL, hw);
60 if (ret) {
61 pr_err("Couldn't register clock %s\n",
62 clk_hw_get_name(hw));
63 goto err_clk_unreg;
64 }
65 }
66
67 ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
68 desc->hw_clks);
69 if (ret)
70 goto err_clk_unreg;
71
72 reset = kzalloc(sizeof(*reset), GFP_KERNEL);
73 reset->rcdev.of_node = node;
74 reset->rcdev.ops = &ccu_reset_ops;
75 reset->rcdev.owner = THIS_MODULE;
76 reset->rcdev.nr_resets = desc->num_resets;
77 reset->base = reg;
78 reset->lock = &ccu_lock;
79 reset->reset_map = desc->resets;
80
81 ret = reset_controller_register(&reset->rcdev);
82 if (ret)
83 goto err_of_clk_unreg;
84
85 return 0;
86
87err_of_clk_unreg:
88err_clk_unreg:
89 return ret;
90}
diff --git a/drivers/clk/sunxi-ng/ccu_common.h b/drivers/clk/sunxi-ng/ccu_common.h
new file mode 100644
index 000000000000..b3d9abfbd721
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_common.h
@@ -0,0 +1,85 @@
1/*
2 * Copyright (c) 2016 Maxime Ripard. 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#ifndef _COMMON_H_
15#define _COMMON_H_
16
17#include <linux/compiler.h>
18#include <linux/clk-provider.h>
19
20#define CCU_FEATURE_FRACTIONAL BIT(0)
21#define CCU_FEATURE_VARIABLE_PREDIV BIT(1)
22#define CCU_FEATURE_FIXED_PREDIV BIT(2)
23#define CCU_FEATURE_FIXED_POSTDIV BIT(3)
24
25struct device_node;
26
27#define CLK_HW_INIT(_name, _parent, _ops, _flags) \
28 &(struct clk_init_data) { \
29 .flags = _flags, \
30 .name = _name, \
31 .parent_names = (const char *[]) { _parent }, \
32 .num_parents = 1, \
33 .ops = _ops, \
34 }
35
36#define CLK_HW_INIT_PARENTS(_name, _parents, _ops, _flags) \
37 &(struct clk_init_data) { \
38 .flags = _flags, \
39 .name = _name, \
40 .parent_names = _parents, \
41 .num_parents = ARRAY_SIZE(_parents), \
42 .ops = _ops, \
43 }
44
45#define CLK_FIXED_FACTOR(_struct, _name, _parent, \
46 _div, _mult, _flags) \
47 struct clk_fixed_factor _struct = { \
48 .div = _div, \
49 .mult = _mult, \
50 .hw.init = CLK_HW_INIT(_name, \
51 _parent, \
52 &clk_fixed_factor_ops, \
53 _flags), \
54 }
55
56struct ccu_common {
57 void __iomem *base;
58 u16 reg;
59
60 unsigned long features;
61 spinlock_t *lock;
62 struct clk_hw hw;
63};
64
65static inline struct ccu_common *hw_to_ccu_common(struct clk_hw *hw)
66{
67 return container_of(hw, struct ccu_common, hw);
68}
69
70struct sunxi_ccu_desc {
71 struct ccu_common **ccu_clks;
72 unsigned long num_ccu_clks;
73
74 struct clk_hw_onecell_data *hw_clks;
75
76 struct ccu_reset_map *resets;
77 unsigned long num_resets;
78};
79
80void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock);
81
82int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
83 const struct sunxi_ccu_desc *desc);
84
85#endif /* _COMMON_H_ */
diff --git a/drivers/clk/sunxi-ng/ccu_div.c b/drivers/clk/sunxi-ng/ccu_div.c
new file mode 100644
index 000000000000..8659b4cb6c20
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_div.c
@@ -0,0 +1,136 @@
1/*
2 * Copyright (C) 2016 Maxime Ripard
3 * Maxime Ripard <maxime.ripard@free-electrons.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 */
10
11#include <linux/clk-provider.h>
12
13#include "ccu_gate.h"
14#include "ccu_div.h"
15
16static unsigned long ccu_div_round_rate(struct ccu_mux_internal *mux,
17 unsigned long parent_rate,
18 unsigned long rate,
19 void *data)
20{
21 struct ccu_div *cd = data;
22 unsigned long val;
23
24 /*
25 * We can't use divider_round_rate that assumes that there's
26 * several parents, while we might be called to evaluate
27 * several different parents.
28 */
29 val = divider_get_val(rate, parent_rate, cd->div.table, cd->div.width,
30 cd->div.flags);
31
32 return divider_recalc_rate(&cd->common.hw, parent_rate, val,
33 cd->div.table, cd->div.flags);
34}
35
36static void ccu_div_disable(struct clk_hw *hw)
37{
38 struct ccu_div *cd = hw_to_ccu_div(hw);
39
40 return ccu_gate_helper_disable(&cd->common, cd->enable);
41}
42
43static int ccu_div_enable(struct clk_hw *hw)
44{
45 struct ccu_div *cd = hw_to_ccu_div(hw);
46
47 return ccu_gate_helper_enable(&cd->common, cd->enable);
48}
49
50static int ccu_div_is_enabled(struct clk_hw *hw)
51{
52 struct ccu_div *cd = hw_to_ccu_div(hw);
53
54 return ccu_gate_helper_is_enabled(&cd->common, cd->enable);
55}
56
57static unsigned long ccu_div_recalc_rate(struct clk_hw *hw,
58 unsigned long parent_rate)
59{
60 struct ccu_div *cd = hw_to_ccu_div(hw);
61 unsigned long val;
62 u32 reg;
63
64 reg = readl(cd->common.base + cd->common.reg);
65 val = reg >> cd->div.shift;
66 val &= (1 << cd->div.width) - 1;
67
68 ccu_mux_helper_adjust_parent_for_prediv(&cd->common, &cd->mux, -1,
69 &parent_rate);
70
71 return divider_recalc_rate(hw, parent_rate, val, cd->div.table,
72 cd->div.flags);
73}
74
75static int ccu_div_determine_rate(struct clk_hw *hw,
76 struct clk_rate_request *req)
77{
78 struct ccu_div *cd = hw_to_ccu_div(hw);
79
80 return ccu_mux_helper_determine_rate(&cd->common, &cd->mux,
81 req, ccu_div_round_rate, cd);
82}
83
84static int ccu_div_set_rate(struct clk_hw *hw, unsigned long rate,
85 unsigned long parent_rate)
86{
87 struct ccu_div *cd = hw_to_ccu_div(hw);
88 unsigned long flags;
89 unsigned long val;
90 u32 reg;
91
92 ccu_mux_helper_adjust_parent_for_prediv(&cd->common, &cd->mux, -1,
93 &parent_rate);
94
95 val = divider_get_val(rate, parent_rate, cd->div.table, cd->div.width,
96 cd->div.flags);
97
98 spin_lock_irqsave(cd->common.lock, flags);
99
100 reg = readl(cd->common.base + cd->common.reg);
101 reg &= ~GENMASK(cd->div.width + cd->div.shift - 1, cd->div.shift);
102
103 writel(reg | (val << cd->div.shift),
104 cd->common.base + cd->common.reg);
105
106 spin_unlock_irqrestore(cd->common.lock, flags);
107
108 return 0;
109}
110
111static u8 ccu_div_get_parent(struct clk_hw *hw)
112{
113 struct ccu_div *cd = hw_to_ccu_div(hw);
114
115 return ccu_mux_helper_get_parent(&cd->common, &cd->mux);
116}
117
118static int ccu_div_set_parent(struct clk_hw *hw, u8 index)
119{
120 struct ccu_div *cd = hw_to_ccu_div(hw);
121
122 return ccu_mux_helper_set_parent(&cd->common, &cd->mux, index);
123}
124
125const struct clk_ops ccu_div_ops = {
126 .disable = ccu_div_disable,
127 .enable = ccu_div_enable,
128 .is_enabled = ccu_div_is_enabled,
129
130 .get_parent = ccu_div_get_parent,
131 .set_parent = ccu_div_set_parent,
132
133 .determine_rate = ccu_div_determine_rate,
134 .recalc_rate = ccu_div_recalc_rate,
135 .set_rate = ccu_div_set_rate,
136};
diff --git a/drivers/clk/sunxi-ng/ccu_div.h b/drivers/clk/sunxi-ng/ccu_div.h
new file mode 100644
index 000000000000..653ade5769b3
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_div.h
@@ -0,0 +1,133 @@
1/*
2 * Copyright (c) 2016 Maxime Ripard. 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#ifndef _CCU_DIV_H_
15#define _CCU_DIV_H_
16
17#include <linux/clk-provider.h>
18
19#include "ccu_common.h"
20#include "ccu_mux.h"
21
22struct _ccu_div {
23 u8 shift;
24 u8 width;
25
26 u32 flags;
27
28 struct clk_div_table *table;
29};
30
31#define _SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, _table, _flags) \
32 { \
33 .shift = _shift, \
34 .width = _width, \
35 .flags = _flags, \
36 .table = _table, \
37 }
38
39#define _SUNXI_CCU_DIV_FLAGS(_shift, _width, _flags) \
40 _SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, NULL, _flags)
41
42#define _SUNXI_CCU_DIV_TABLE(_shift, _width, _table) \
43 _SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, _table, 0)
44
45#define _SUNXI_CCU_DIV(_shift, _width) \
46 _SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, NULL, 0)
47
48struct ccu_div {
49 u32 enable;
50
51 struct _ccu_div div;
52 struct ccu_mux_internal mux;
53 struct ccu_common common;
54};
55
56#define SUNXI_CCU_DIV_TABLE_WITH_GATE(_struct, _name, _parent, _reg, \
57 _shift, _width, \
58 _table, _gate, _flags) \
59 struct ccu_div _struct = { \
60 .div = _SUNXI_CCU_DIV_TABLE(_shift, _width, \
61 _table), \
62 .enable = _gate, \
63 .common = { \
64 .reg = _reg, \
65 .hw.init = CLK_HW_INIT(_name, \
66 _parent, \
67 &ccu_div_ops, \
68 _flags), \
69 } \
70 }
71
72
73#define SUNXI_CCU_DIV_TABLE(_struct, _name, _parent, _reg, \
74 _shift, _width, \
75 _table, _flags) \
76 SUNXI_CCU_DIV_TABLE_WITH_GATE(_struct, _name, _parent, _reg, \
77 _shift, _width, _table, 0, \
78 _flags)
79
80#define SUNXI_CCU_M_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
81 _mshift, _mwidth, _muxshift, _muxwidth, \
82 _gate, _flags) \
83 struct ccu_div _struct = { \
84 .enable = _gate, \
85 .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \
86 .mux = SUNXI_CLK_MUX(_muxshift, _muxwidth), \
87 .common = { \
88 .reg = _reg, \
89 .hw.init = CLK_HW_INIT_PARENTS(_name, \
90 _parents, \
91 &ccu_div_ops, \
92 _flags), \
93 }, \
94 }
95
96#define SUNXI_CCU_M_WITH_MUX(_struct, _name, _parents, _reg, \
97 _mshift, _mwidth, _muxshift, _muxwidth, \
98 _flags) \
99 SUNXI_CCU_M_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
100 _mshift, _mwidth, _muxshift, _muxwidth, \
101 0, _flags)
102
103
104#define SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg, \
105 _mshift, _mwidth, _gate, \
106 _flags) \
107 struct ccu_div _struct = { \
108 .enable = _gate, \
109 .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \
110 .common = { \
111 .reg = _reg, \
112 .hw.init = CLK_HW_INIT(_name, \
113 _parent, \
114 &ccu_div_ops, \
115 _flags), \
116 }, \
117 }
118
119#define SUNXI_CCU_M(_struct, _name, _parent, _reg, _mshift, _mwidth, \
120 _flags) \
121 SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg, \
122 _mshift, _mwidth, 0, _flags)
123
124static inline struct ccu_div *hw_to_ccu_div(struct clk_hw *hw)
125{
126 struct ccu_common *common = hw_to_ccu_common(hw);
127
128 return container_of(common, struct ccu_div, common);
129}
130
131extern const struct clk_ops ccu_div_ops;
132
133#endif /* _CCU_DIV_H_ */
diff --git a/drivers/clk/sunxi-ng/ccu_frac.c b/drivers/clk/sunxi-ng/ccu_frac.c
new file mode 100644
index 000000000000..5c4b10cd15b5
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_frac.c
@@ -0,0 +1,110 @@
1/*
2 * Copyright (C) 2016 Maxime Ripard
3 * Maxime Ripard <maxime.ripard@free-electrons.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 */
10
11#include <linux/clk-provider.h>
12#include <linux/spinlock.h>
13
14#include "ccu_frac.h"
15
16bool ccu_frac_helper_is_enabled(struct ccu_common *common,
17 struct _ccu_frac *cf)
18{
19 if (!(common->features & CCU_FEATURE_FRACTIONAL))
20 return false;
21
22 return !(readl(common->base + common->reg) & cf->enable);
23}
24
25void ccu_frac_helper_enable(struct ccu_common *common,
26 struct _ccu_frac *cf)
27{
28 unsigned long flags;
29 u32 reg;
30
31 if (!(common->features & CCU_FEATURE_FRACTIONAL))
32 return;
33
34 spin_lock_irqsave(common->lock, flags);
35 reg = readl(common->base + common->reg);
36 writel(reg & ~cf->enable, common->base + common->reg);
37 spin_unlock_irqrestore(common->lock, flags);
38}
39
40void ccu_frac_helper_disable(struct ccu_common *common,
41 struct _ccu_frac *cf)
42{
43 unsigned long flags;
44 u32 reg;
45
46 if (!(common->features & CCU_FEATURE_FRACTIONAL))
47 return;
48
49 spin_lock_irqsave(common->lock, flags);
50 reg = readl(common->base + common->reg);
51 writel(reg | cf->enable, common->base + common->reg);
52 spin_unlock_irqrestore(common->lock, flags);
53}
54
55bool ccu_frac_helper_has_rate(struct ccu_common *common,
56 struct _ccu_frac *cf,
57 unsigned long rate)
58{
59 if (!(common->features & CCU_FEATURE_FRACTIONAL))
60 return false;
61
62 return (cf->rates[0] == rate) || (cf->rates[1] == rate);
63}
64
65unsigned long ccu_frac_helper_read_rate(struct ccu_common *common,
66 struct _ccu_frac *cf)
67{
68 u32 reg;
69
70 printk("%s: Read fractional\n", clk_hw_get_name(&common->hw));
71
72 if (!(common->features & CCU_FEATURE_FRACTIONAL))
73 return 0;
74
75 printk("%s: clock is fractional (rates %lu and %lu)\n",
76 clk_hw_get_name(&common->hw), cf->rates[0], cf->rates[1]);
77
78 reg = readl(common->base + common->reg);
79
80 printk("%s: clock reg is 0x%x (select is 0x%x)\n",
81 clk_hw_get_name(&common->hw), reg, cf->select);
82
83 return (reg & cf->select) ? cf->rates[1] : cf->rates[0];
84}
85
86int ccu_frac_helper_set_rate(struct ccu_common *common,
87 struct _ccu_frac *cf,
88 unsigned long rate)
89{
90 unsigned long flags;
91 u32 reg, sel;
92
93 if (!(common->features & CCU_FEATURE_FRACTIONAL))
94 return -EINVAL;
95
96 if (cf->rates[0] == rate)
97 sel = 0;
98 else if (cf->rates[1] == rate)
99 sel = cf->select;
100 else
101 return -EINVAL;
102
103 spin_lock_irqsave(common->lock, flags);
104 reg = readl(common->base + common->reg);
105 reg &= ~cf->select;
106 writel(reg | sel, common->base + common->reg);
107 spin_unlock_irqrestore(common->lock, flags);
108
109 return 0;
110}
diff --git a/drivers/clk/sunxi-ng/ccu_frac.h b/drivers/clk/sunxi-ng/ccu_frac.h
new file mode 100644
index 000000000000..e4c670b1cdfe
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_frac.h
@@ -0,0 +1,53 @@
1/*
2 * Copyright (c) 2016 Maxime Ripard. 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#ifndef _CCU_FRAC_H_
15#define _CCU_FRAC_H_
16
17#include <linux/clk-provider.h>
18
19#include "ccu_common.h"
20
21struct _ccu_frac {
22 u32 enable;
23 u32 select;
24
25 unsigned long rates[2];
26};
27
28#define _SUNXI_CCU_FRAC(_enable, _select, _rate1, _rate2) \
29 { \
30 .enable = _enable, \
31 .select = _select, \
32 .rates = { _rate1, _rate2 }, \
33 }
34
35bool ccu_frac_helper_is_enabled(struct ccu_common *common,
36 struct _ccu_frac *cf);
37void ccu_frac_helper_enable(struct ccu_common *common,
38 struct _ccu_frac *cf);
39void ccu_frac_helper_disable(struct ccu_common *common,
40 struct _ccu_frac *cf);
41
42bool ccu_frac_helper_has_rate(struct ccu_common *common,
43 struct _ccu_frac *cf,
44 unsigned long rate);
45
46unsigned long ccu_frac_helper_read_rate(struct ccu_common *common,
47 struct _ccu_frac *cf);
48
49int ccu_frac_helper_set_rate(struct ccu_common *common,
50 struct _ccu_frac *cf,
51 unsigned long rate);
52
53#endif /* _CCU_FRAC_H_ */
diff --git a/drivers/clk/sunxi-ng/ccu_gate.c b/drivers/clk/sunxi-ng/ccu_gate.c
new file mode 100644
index 000000000000..8a81f9d4a89f
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_gate.c
@@ -0,0 +1,82 @@
1/*
2 * Copyright (C) 2016 Maxime Ripard
3 * Maxime Ripard <maxime.ripard@free-electrons.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 */
10
11#include <linux/clk-provider.h>
12
13#include "ccu_gate.h"
14
15void ccu_gate_helper_disable(struct ccu_common *common, u32 gate)
16{
17 unsigned long flags;
18 u32 reg;
19
20 if (!gate)
21 return;
22
23 spin_lock_irqsave(common->lock, flags);
24
25 reg = readl(common->base + common->reg);
26 writel(reg & ~gate, common->base + common->reg);
27
28 spin_unlock_irqrestore(common->lock, flags);
29}
30
31static void ccu_gate_disable(struct clk_hw *hw)
32{
33 struct ccu_gate *cg = hw_to_ccu_gate(hw);
34
35 return ccu_gate_helper_disable(&cg->common, cg->enable);
36}
37
38int ccu_gate_helper_enable(struct ccu_common *common, u32 gate)
39{
40 unsigned long flags;
41 u32 reg;
42
43 if (!gate)
44 return 0;
45
46 spin_lock_irqsave(common->lock, flags);
47
48 reg = readl(common->base + common->reg);
49 writel(reg | gate, common->base + common->reg);
50
51 spin_unlock_irqrestore(common->lock, flags);
52
53 return 0;
54}
55
56static int ccu_gate_enable(struct clk_hw *hw)
57{
58 struct ccu_gate *cg = hw_to_ccu_gate(hw);
59
60 return ccu_gate_helper_enable(&cg->common, cg->enable);
61}
62
63int ccu_gate_helper_is_enabled(struct ccu_common *common, u32 gate)
64{
65 if (!gate)
66 return 1;
67
68 return readl(common->base + common->reg) & gate;
69}
70
71static int ccu_gate_is_enabled(struct clk_hw *hw)
72{
73 struct ccu_gate *cg = hw_to_ccu_gate(hw);
74
75 return ccu_gate_helper_is_enabled(&cg->common, cg->enable);
76}
77
78const struct clk_ops ccu_gate_ops = {
79 .disable = ccu_gate_disable,
80 .enable = ccu_gate_enable,
81 .is_enabled = ccu_gate_is_enabled,
82};
diff --git a/drivers/clk/sunxi-ng/ccu_gate.h b/drivers/clk/sunxi-ng/ccu_gate.h
new file mode 100644
index 000000000000..4466169bd2d7
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_gate.h
@@ -0,0 +1,52 @@
1/*
2 * Copyright (c) 2016 Maxime Ripard. 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#ifndef _CCU_GATE_H_
15#define _CCU_GATE_H_
16
17#include <linux/clk-provider.h>
18
19#include "ccu_common.h"
20
21struct ccu_gate {
22 u32 enable;
23
24 struct ccu_common common;
25};
26
27#define SUNXI_CCU_GATE(_struct, _name, _parent, _reg, _gate, _flags) \
28 struct ccu_gate _struct = { \
29 .enable = _gate, \
30 .common = { \
31 .reg = _reg, \
32 .hw.init = CLK_HW_INIT(_name, \
33 _parent, \
34 &ccu_gate_ops, \
35 _flags), \
36 } \
37 }
38
39static inline struct ccu_gate *hw_to_ccu_gate(struct clk_hw *hw)
40{
41 struct ccu_common *common = hw_to_ccu_common(hw);
42
43 return container_of(common, struct ccu_gate, common);
44}
45
46void ccu_gate_helper_disable(struct ccu_common *common, u32 gate);
47int ccu_gate_helper_enable(struct ccu_common *common, u32 gate);
48int ccu_gate_helper_is_enabled(struct ccu_common *common, u32 gate);
49
50extern const struct clk_ops ccu_gate_ops;
51
52#endif /* _CCU_GATE_H_ */
diff --git a/drivers/clk/sunxi-ng/ccu_mp.c b/drivers/clk/sunxi-ng/ccu_mp.c
new file mode 100644
index 000000000000..cbf33ef5faa9
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_mp.c
@@ -0,0 +1,158 @@
1/*
2 * Copyright (C) 2016 Maxime Ripard
3 * Maxime Ripard <maxime.ripard@free-electrons.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 */
10
11#include <linux/clk-provider.h>
12
13#include "ccu_gate.h"
14#include "ccu_mp.h"
15
16static void ccu_mp_find_best(unsigned long parent, unsigned long rate,
17 unsigned int max_m, unsigned int max_p,
18 unsigned int *m, unsigned int *p)
19{
20 unsigned long best_rate = 0;
21 unsigned int best_m = 0, best_p = 0;
22 unsigned int _m, _p;
23
24 for (_p = 0; _p <= max_p; _p++) {
25 for (_m = 1; _m <= max_m; _m++) {
26 unsigned long tmp_rate = (parent >> _p) / _m;
27
28 if (tmp_rate > rate)
29 continue;
30
31 if ((rate - tmp_rate) < (rate - best_rate)) {
32 best_rate = tmp_rate;
33 best_m = _m;
34 best_p = _p;
35 }
36 }
37 }
38
39 *m = best_m;
40 *p = best_p;
41}
42
43static unsigned long ccu_mp_round_rate(struct ccu_mux_internal *mux,
44 unsigned long parent_rate,
45 unsigned long rate,
46 void *data)
47{
48 struct ccu_mp *cmp = data;
49 unsigned int m, p;
50
51 ccu_mp_find_best(parent_rate, rate,
52 1 << cmp->m.width, (1 << cmp->p.width) - 1,
53 &m, &p);
54
55 return (parent_rate >> p) / m;
56}
57
58static void ccu_mp_disable(struct clk_hw *hw)
59{
60 struct ccu_mp *cmp = hw_to_ccu_mp(hw);
61
62 return ccu_gate_helper_disable(&cmp->common, cmp->enable);
63}
64
65static int ccu_mp_enable(struct clk_hw *hw)
66{
67 struct ccu_mp *cmp = hw_to_ccu_mp(hw);
68
69 return ccu_gate_helper_enable(&cmp->common, cmp->enable);
70}
71
72static int ccu_mp_is_enabled(struct clk_hw *hw)
73{
74 struct ccu_mp *cmp = hw_to_ccu_mp(hw);
75
76 return ccu_gate_helper_is_enabled(&cmp->common, cmp->enable);
77}
78
79static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw,
80 unsigned long parent_rate)
81{
82 struct ccu_mp *cmp = hw_to_ccu_mp(hw);
83 unsigned int m, p;
84 u32 reg;
85
86 reg = readl(cmp->common.base + cmp->common.reg);
87
88 m = reg >> cmp->m.shift;
89 m &= (1 << cmp->m.width) - 1;
90
91 p = reg >> cmp->p.shift;
92 p &= (1 << cmp->p.width) - 1;
93
94 return (parent_rate >> p) / (m + 1);
95}
96
97static int ccu_mp_determine_rate(struct clk_hw *hw,
98 struct clk_rate_request *req)
99{
100 struct ccu_mp *cmp = hw_to_ccu_mp(hw);
101
102 return ccu_mux_helper_determine_rate(&cmp->common, &cmp->mux,
103 req, ccu_mp_round_rate, cmp);
104}
105
106static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate,
107 unsigned long parent_rate)
108{
109 struct ccu_mp *cmp = hw_to_ccu_mp(hw);
110 unsigned long flags;
111 unsigned int m, p;
112 u32 reg;
113
114 ccu_mp_find_best(parent_rate, rate,
115 1 << cmp->m.width, (1 << cmp->p.width) - 1,
116 &m, &p);
117
118
119 spin_lock_irqsave(cmp->common.lock, flags);
120
121 reg = readl(cmp->common.base + cmp->common.reg);
122 reg &= ~GENMASK(cmp->m.width + cmp->m.shift - 1, cmp->m.shift);
123 reg &= ~GENMASK(cmp->p.width + cmp->p.shift - 1, cmp->p.shift);
124
125 writel(reg | (p << cmp->p.shift) | ((m - 1) << cmp->m.shift),
126 cmp->common.base + cmp->common.reg);
127
128 spin_unlock_irqrestore(cmp->common.lock, flags);
129
130 return 0;
131}
132
133static u8 ccu_mp_get_parent(struct clk_hw *hw)
134{
135 struct ccu_mp *cmp = hw_to_ccu_mp(hw);
136
137 return ccu_mux_helper_get_parent(&cmp->common, &cmp->mux);
138}
139
140static int ccu_mp_set_parent(struct clk_hw *hw, u8 index)
141{
142 struct ccu_mp *cmp = hw_to_ccu_mp(hw);
143
144 return ccu_mux_helper_set_parent(&cmp->common, &cmp->mux, index);
145}
146
147const struct clk_ops ccu_mp_ops = {
148 .disable = ccu_mp_disable,
149 .enable = ccu_mp_enable,
150 .is_enabled = ccu_mp_is_enabled,
151
152 .get_parent = ccu_mp_get_parent,
153 .set_parent = ccu_mp_set_parent,
154
155 .determine_rate = ccu_mp_determine_rate,
156 .recalc_rate = ccu_mp_recalc_rate,
157 .set_rate = ccu_mp_set_rate,
158};
diff --git a/drivers/clk/sunxi-ng/ccu_mp.h b/drivers/clk/sunxi-ng/ccu_mp.h
new file mode 100644
index 000000000000..3cf12bf95962
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_mp.h
@@ -0,0 +1,77 @@
1/*
2 * Copyright (c) 2016 Maxime Ripard. 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#ifndef _CCU_MP_H_
15#define _CCU_MP_H_
16
17#include <linux/clk-provider.h>
18
19#include "ccu_common.h"
20#include "ccu_div.h"
21#include "ccu_mult.h"
22#include "ccu_mux.h"
23
24/*
25 * struct ccu_mp - Definition of an M-P clock
26 *
27 * Clocks based on the formula parent >> P / M
28 */
29struct ccu_mp {
30 u32 enable;
31
32 struct _ccu_div m;
33 struct _ccu_div p;
34 struct ccu_mux_internal mux;
35 struct ccu_common common;
36};
37
38#define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
39 _mshift, _mwidth, \
40 _pshift, _pwidth, \
41 _muxshift, _muxwidth, \
42 _gate, _flags) \
43 struct ccu_mp _struct = { \
44 .enable = _gate, \
45 .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
46 .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \
47 .mux = SUNXI_CLK_MUX(_muxshift, _muxwidth), \
48 .common = { \
49 .reg = _reg, \
50 .hw.init = CLK_HW_INIT_PARENTS(_name, \
51 _parents, \
52 &ccu_mp_ops, \
53 _flags), \
54 } \
55 }
56
57#define SUNXI_CCU_MP_WITH_MUX(_struct, _name, _parents, _reg, \
58 _mshift, _mwidth, \
59 _pshift, _pwidth, \
60 _muxshift, _muxwidth, \
61 _flags) \
62 SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
63 _mshift, _mwidth, \
64 _pshift, _pwidth, \
65 _muxshift, _muxwidth, \
66 0, _flags)
67
68static inline struct ccu_mp *hw_to_ccu_mp(struct clk_hw *hw)
69{
70 struct ccu_common *common = hw_to_ccu_common(hw);
71
72 return container_of(common, struct ccu_mp, common);
73}
74
75extern const struct clk_ops ccu_mp_ops;
76
77#endif /* _CCU_MP_H_ */
diff --git a/drivers/clk/sunxi-ng/ccu_mult.h b/drivers/clk/sunxi-ng/ccu_mult.h
new file mode 100644
index 000000000000..609db6610880
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_mult.h
@@ -0,0 +1,15 @@
1#ifndef _CCU_MULT_H_
2#define _CCU_MULT_H_
3
4struct _ccu_mult {
5 u8 shift;
6 u8 width;
7};
8
9#define _SUNXI_CCU_MULT(_shift, _width) \
10 { \
11 .shift = _shift, \
12 .width = _width, \
13 }
14
15#endif /* _CCU_MULT_H_ */
diff --git a/drivers/clk/sunxi-ng/ccu_mux.c b/drivers/clk/sunxi-ng/ccu_mux.c
new file mode 100644
index 000000000000..58fc36e7dcce
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_mux.c
@@ -0,0 +1,187 @@
1/*
2 * Copyright (C) 2016 Maxime Ripard
3 * Maxime Ripard <maxime.ripard@free-electrons.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 */
10
11#include <linux/clk-provider.h>
12
13#include "ccu_gate.h"
14#include "ccu_mux.h"
15
16void ccu_mux_helper_adjust_parent_for_prediv(struct ccu_common *common,
17 struct ccu_mux_internal *cm,
18 int parent_index,
19 unsigned long *parent_rate)
20{
21 u8 prediv = 1;
22 u32 reg;
23
24 if (!((common->features & CCU_FEATURE_FIXED_PREDIV) ||
25 (common->features & CCU_FEATURE_VARIABLE_PREDIV)))
26 return;
27
28 reg = readl(common->base + common->reg);
29 if (parent_index < 0) {
30 parent_index = reg >> cm->shift;
31 parent_index &= (1 << cm->width) - 1;
32 }
33
34 if (common->features & CCU_FEATURE_FIXED_PREDIV)
35 if (parent_index == cm->fixed_prediv.index)
36 prediv = cm->fixed_prediv.div;
37
38 if (common->features & CCU_FEATURE_VARIABLE_PREDIV)
39 if (parent_index == cm->variable_prediv.index) {
40 u8 div;
41
42 div = reg >> cm->variable_prediv.shift;
43 div &= (1 << cm->variable_prediv.width) - 1;
44 prediv = div + 1;
45 }
46
47 *parent_rate = *parent_rate / prediv;
48}
49
50int ccu_mux_helper_determine_rate(struct ccu_common *common,
51 struct ccu_mux_internal *cm,
52 struct clk_rate_request *req,
53 unsigned long (*round)(struct ccu_mux_internal *,
54 unsigned long,
55 unsigned long,
56 void *),
57 void *data)
58{
59 unsigned long best_parent_rate = 0, best_rate = 0;
60 struct clk_hw *best_parent, *hw = &common->hw;
61 unsigned int i;
62
63 for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
64 unsigned long tmp_rate, parent_rate;
65 struct clk_hw *parent;
66
67 parent = clk_hw_get_parent_by_index(hw, i);
68 if (!parent)
69 continue;
70
71 parent_rate = clk_hw_get_rate(parent);
72 ccu_mux_helper_adjust_parent_for_prediv(common, cm, i,
73 &parent_rate);
74
75 tmp_rate = round(cm, clk_hw_get_rate(parent), req->rate, data);
76 if (tmp_rate == req->rate) {
77 best_parent = parent;
78 best_parent_rate = parent_rate;
79 best_rate = tmp_rate;
80 goto out;
81 }
82
83 if ((req->rate - tmp_rate) < (req->rate - best_rate)) {
84 best_rate = tmp_rate;
85 best_parent_rate = parent_rate;
86 best_parent = parent;
87 }
88 }
89
90 if (best_rate == 0)
91 return -EINVAL;
92
93out:
94 req->best_parent_hw = best_parent;
95 req->best_parent_rate = best_parent_rate;
96 req->rate = best_rate;
97 return 0;
98}
99
100u8 ccu_mux_helper_get_parent(struct ccu_common *common,
101 struct ccu_mux_internal *cm)
102{
103 u32 reg;
104 u8 parent;
105
106 reg = readl(common->base + common->reg);
107 parent = reg >> cm->shift;
108 parent &= (1 << cm->width) - 1;
109
110 return parent;
111}
112
113int ccu_mux_helper_set_parent(struct ccu_common *common,
114 struct ccu_mux_internal *cm,
115 u8 index)
116{
117 unsigned long flags;
118 u32 reg;
119
120 spin_lock_irqsave(common->lock, flags);
121
122 reg = readl(common->base + common->reg);
123 reg &= ~GENMASK(cm->width + cm->shift - 1, cm->shift);
124 writel(reg | (index << cm->shift), common->base + common->reg);
125
126 spin_unlock_irqrestore(common->lock, flags);
127
128 return 0;
129}
130
131static void ccu_mux_disable(struct clk_hw *hw)
132{
133 struct ccu_mux *cm = hw_to_ccu_mux(hw);
134
135 return ccu_gate_helper_disable(&cm->common, cm->enable);
136}
137
138static int ccu_mux_enable(struct clk_hw *hw)
139{
140 struct ccu_mux *cm = hw_to_ccu_mux(hw);
141
142 return ccu_gate_helper_enable(&cm->common, cm->enable);
143}
144
145static int ccu_mux_is_enabled(struct clk_hw *hw)
146{
147 struct ccu_mux *cm = hw_to_ccu_mux(hw);
148
149 return ccu_gate_helper_is_enabled(&cm->common, cm->enable);
150}
151
152static u8 ccu_mux_get_parent(struct clk_hw *hw)
153{
154 struct ccu_mux *cm = hw_to_ccu_mux(hw);
155
156 return ccu_mux_helper_get_parent(&cm->common, &cm->mux);
157}
158
159static int ccu_mux_set_parent(struct clk_hw *hw, u8 index)
160{
161 struct ccu_mux *cm = hw_to_ccu_mux(hw);
162
163 return ccu_mux_helper_set_parent(&cm->common, &cm->mux, index);
164}
165
166static unsigned long ccu_mux_recalc_rate(struct clk_hw *hw,
167 unsigned long parent_rate)
168{
169 struct ccu_mux *cm = hw_to_ccu_mux(hw);
170
171 ccu_mux_helper_adjust_parent_for_prediv(&cm->common, &cm->mux, -1,
172 &parent_rate);
173
174 return parent_rate;
175}
176
177const struct clk_ops ccu_mux_ops = {
178 .disable = ccu_mux_disable,
179 .enable = ccu_mux_enable,
180 .is_enabled = ccu_mux_is_enabled,
181
182 .get_parent = ccu_mux_get_parent,
183 .set_parent = ccu_mux_set_parent,
184
185 .determine_rate = __clk_mux_determine_rate,
186 .recalc_rate = ccu_mux_recalc_rate,
187};
diff --git a/drivers/clk/sunxi-ng/ccu_mux.h b/drivers/clk/sunxi-ng/ccu_mux.h
new file mode 100644
index 000000000000..945082631e7d
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_mux.h
@@ -0,0 +1,91 @@
1#ifndef _CCU_MUX_H_
2#define _CCU_MUX_H_
3
4#include <linux/clk-provider.h>
5
6#include "ccu_common.h"
7
8struct ccu_mux_internal {
9 u8 shift;
10 u8 width;
11
12 struct {
13 u8 index;
14 u8 div;
15 } fixed_prediv;
16
17 struct {
18 u8 index;
19 u8 shift;
20 u8 width;
21 } variable_prediv;
22};
23
24#define SUNXI_CLK_MUX(_shift, _width) \
25 { \
26 .shift = _shift, \
27 .width = _width, \
28 }
29
30struct ccu_mux {
31 u16 reg;
32 u32 enable;
33
34 struct ccu_mux_internal mux;
35 struct ccu_common common;
36};
37
38#define SUNXI_CCU_MUX(_struct, _name, _parents, _reg, _shift, _width, _flags) \
39 struct ccu_mux _struct = { \
40 .mux = SUNXI_CLK_MUX(_shift, _width), \
41 .common = { \
42 .reg = _reg, \
43 .hw.init = CLK_HW_INIT_PARENTS(_name, \
44 _parents, \
45 &ccu_mux_ops, \
46 _flags), \
47 } \
48 }
49
50#define SUNXI_CCU_MUX_WITH_GATE(_struct, _name, _parents, _reg, \
51 _shift, _width, _gate, _flags) \
52 struct ccu_mux _struct = { \
53 .enable = _gate, \
54 .mux = SUNXI_CLK_MUX(_shift, _width), \
55 .common = { \
56 .reg = _reg, \
57 .hw.init = CLK_HW_INIT_PARENTS(_name, \
58 _parents, \
59 &ccu_mux_ops, \
60 _flags), \
61 } \
62 }
63
64static inline struct ccu_mux *hw_to_ccu_mux(struct clk_hw *hw)
65{
66 struct ccu_common *common = hw_to_ccu_common(hw);
67
68 return container_of(common, struct ccu_mux, common);
69}
70
71extern const struct clk_ops ccu_mux_ops;
72
73void ccu_mux_helper_adjust_parent_for_prediv(struct ccu_common *common,
74 struct ccu_mux_internal *cm,
75 int parent_index,
76 unsigned long *parent_rate);
77int ccu_mux_helper_determine_rate(struct ccu_common *common,
78 struct ccu_mux_internal *cm,
79 struct clk_rate_request *req,
80 unsigned long (*round)(struct ccu_mux_internal *,
81 unsigned long,
82 unsigned long,
83 void *),
84 void *data);
85u8 ccu_mux_helper_get_parent(struct ccu_common *common,
86 struct ccu_mux_internal *cm);
87int ccu_mux_helper_set_parent(struct ccu_common *common,
88 struct ccu_mux_internal *cm,
89 u8 index);
90
91#endif /* _CCU_MUX_H_ */
diff --git a/drivers/clk/sunxi-ng/ccu_nk.c b/drivers/clk/sunxi-ng/ccu_nk.c
new file mode 100644
index 000000000000..4470ffc8cf0d
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_nk.c
@@ -0,0 +1,147 @@
1/*
2 * Copyright (C) 2016 Maxime Ripard
3 * Maxime Ripard <maxime.ripard@free-electrons.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 */
10
11#include <linux/clk-provider.h>
12#include <linux/rational.h>
13
14#include "ccu_gate.h"
15#include "ccu_nk.h"
16
17void ccu_nk_find_best(unsigned long parent, unsigned long rate,
18 unsigned int max_n, unsigned int max_k,
19 unsigned int *n, unsigned int *k)
20{
21 unsigned long best_rate = 0;
22 unsigned int best_k = 0, best_n = 0;
23 unsigned int _k, _n;
24
25 for (_k = 1; _k <= max_k; _k++) {
26 for (_n = 1; _n <= max_n; _n++) {
27 unsigned long tmp_rate = parent * _n * _k;
28
29 if (tmp_rate > rate)
30 continue;
31
32 if ((rate - tmp_rate) < (rate - best_rate)) {
33 best_rate = tmp_rate;
34 best_k = _k;
35 best_n = _n;
36 }
37 }
38 }
39
40 *k = best_k;
41 *n = best_n;
42}
43
44static void ccu_nk_disable(struct clk_hw *hw)
45{
46 struct ccu_nk *nk = hw_to_ccu_nk(hw);
47
48 return ccu_gate_helper_disable(&nk->common, nk->enable);
49}
50
51static int ccu_nk_enable(struct clk_hw *hw)
52{
53 struct ccu_nk *nk = hw_to_ccu_nk(hw);
54
55 return ccu_gate_helper_enable(&nk->common, nk->enable);
56}
57
58static int ccu_nk_is_enabled(struct clk_hw *hw)
59{
60 struct ccu_nk *nk = hw_to_ccu_nk(hw);
61
62 return ccu_gate_helper_is_enabled(&nk->common, nk->enable);
63}
64
65static unsigned long ccu_nk_recalc_rate(struct clk_hw *hw,
66 unsigned long parent_rate)
67{
68 struct ccu_nk *nk = hw_to_ccu_nk(hw);
69 unsigned long rate, n, k;
70 u32 reg;
71
72 reg = readl(nk->common.base + nk->common.reg);
73
74 n = reg >> nk->n.shift;
75 n &= (1 << nk->n.width) - 1;
76
77 k = reg >> nk->k.shift;
78 k &= (1 << nk->k.width) - 1;
79
80 rate = parent_rate * (n + 1) * (k + 1);
81
82 if (nk->common.features & CCU_FEATURE_FIXED_POSTDIV)
83 rate /= nk->fixed_post_div;
84
85 return rate;
86}
87
88static long ccu_nk_round_rate(struct clk_hw *hw, unsigned long rate,
89 unsigned long *parent_rate)
90{
91 struct ccu_nk *nk = hw_to_ccu_nk(hw);
92 unsigned int n, k;
93
94 if (nk->common.features & CCU_FEATURE_FIXED_POSTDIV)
95 rate *= nk->fixed_post_div;
96
97 ccu_nk_find_best(*parent_rate, rate,
98 1 << nk->n.width, 1 << nk->k.width,
99 &n, &k);
100
101 rate = *parent_rate * n * k;
102 if (nk->common.features & CCU_FEATURE_FIXED_POSTDIV)
103 rate = rate / nk->fixed_post_div;
104
105 return rate;
106}
107
108static int ccu_nk_set_rate(struct clk_hw *hw, unsigned long rate,
109 unsigned long parent_rate)
110{
111 struct ccu_nk *nk = hw_to_ccu_nk(hw);
112 unsigned long flags;
113 unsigned int n, k;
114 u32 reg;
115
116 if (nk->common.features & CCU_FEATURE_FIXED_POSTDIV)
117 rate = rate * nk->fixed_post_div;
118
119 ccu_nk_find_best(parent_rate, rate,
120 1 << nk->n.width, 1 << nk->k.width,
121 &n, &k);
122
123 spin_lock_irqsave(nk->common.lock, flags);
124
125 reg = readl(nk->common.base + nk->common.reg);
126 reg &= ~GENMASK(nk->n.width + nk->n.shift - 1, nk->n.shift);
127 reg &= ~GENMASK(nk->k.width + nk->k.shift - 1, nk->k.shift);
128
129 writel(reg | ((k - 1) << nk->k.shift) | ((n - 1) << nk->n.shift),
130 nk->common.base + nk->common.reg);
131
132 spin_unlock_irqrestore(nk->common.lock, flags);
133
134 ccu_helper_wait_for_lock(&nk->common, nk->lock);
135
136 return 0;
137}
138
139const struct clk_ops ccu_nk_ops = {
140 .disable = ccu_nk_disable,
141 .enable = ccu_nk_enable,
142 .is_enabled = ccu_nk_is_enabled,
143
144 .recalc_rate = ccu_nk_recalc_rate,
145 .round_rate = ccu_nk_round_rate,
146 .set_rate = ccu_nk_set_rate,
147};
diff --git a/drivers/clk/sunxi-ng/ccu_nk.h b/drivers/clk/sunxi-ng/ccu_nk.h
new file mode 100644
index 000000000000..4b52da0c29fe
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_nk.h
@@ -0,0 +1,71 @@
1/*
2 * Copyright (c) 2016 Maxime Ripard. 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#ifndef _CCU_NK_H_
15#define _CCU_NK_H_
16
17#include <linux/clk-provider.h>
18
19#include "ccu_common.h"
20#include "ccu_div.h"
21#include "ccu_mult.h"
22
23/*
24 * struct ccu_nk - Definition of an N-K clock
25 *
26 * Clocks based on the formula parent * N * K
27 */
28struct ccu_nk {
29 u16 reg;
30 u32 enable;
31 u32 lock;
32
33 struct _ccu_mult n;
34 struct _ccu_mult k;
35
36 unsigned int fixed_post_div;
37
38 struct ccu_common common;
39};
40
41#define SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV(_struct, _name, _parent, _reg, \
42 _nshift, _nwidth, \
43 _kshift, _kwidth, \
44 _gate, _lock, _postdiv, \
45 _flags) \
46 struct ccu_nk _struct = { \
47 .enable = _gate, \
48 .lock = _lock, \
49 .k = _SUNXI_CCU_MULT(_kshift, _kwidth), \
50 .n = _SUNXI_CCU_MULT(_nshift, _nwidth), \
51 .fixed_post_div = _postdiv, \
52 .common = { \
53 .reg = _reg, \
54 .features = CCU_FEATURE_FIXED_POSTDIV, \
55 .hw.init = CLK_HW_INIT(_name, \
56 _parent, \
57 &ccu_nk_ops, \
58 _flags), \
59 }, \
60 }
61
62static inline struct ccu_nk *hw_to_ccu_nk(struct clk_hw *hw)
63{
64 struct ccu_common *common = hw_to_ccu_common(hw);
65
66 return container_of(common, struct ccu_nk, common);
67}
68
69extern const struct clk_ops ccu_nk_ops;
70
71#endif /* _CCU_NK_H_ */
diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c
new file mode 100644
index 000000000000..2071822b1e9c
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_nkm.c
@@ -0,0 +1,153 @@
1/*
2 * Copyright (C) 2016 Maxime Ripard
3 * Maxime Ripard <maxime.ripard@free-electrons.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 */
10
11#include <linux/clk-provider.h>
12#include <linux/rational.h>
13
14#include "ccu_gate.h"
15#include "ccu_nkm.h"
16
17struct _ccu_nkm {
18 unsigned long n, max_n;
19 unsigned long k, max_k;
20 unsigned long m, max_m;
21};
22
23static void ccu_nkm_find_best(unsigned long parent, unsigned long rate,
24 struct _ccu_nkm *nkm)
25{
26 unsigned long best_rate = 0;
27 unsigned long best_n = 0, best_k = 0, best_m = 0;
28 unsigned long _n, _k, _m;
29
30 for (_k = 1; _k <= nkm->max_k; _k++) {
31 unsigned long tmp_rate;
32
33 rational_best_approximation(rate / _k, parent,
34 nkm->max_n, nkm->max_m, &_n, &_m);
35
36 tmp_rate = parent * _n * _k / _m;
37
38 if (tmp_rate > rate)
39 continue;
40
41 if ((rate - tmp_rate) < (rate - best_rate)) {
42 best_rate = tmp_rate;
43 best_n = _n;
44 best_k = _k;
45 best_m = _m;
46 }
47 }
48
49 nkm->n = best_n;
50 nkm->k = best_k;
51 nkm->m = best_m;
52}
53
54static void ccu_nkm_disable(struct clk_hw *hw)
55{
56 struct ccu_nkm *nkm = hw_to_ccu_nkm(hw);
57
58 return ccu_gate_helper_disable(&nkm->common, nkm->enable);
59}
60
61static int ccu_nkm_enable(struct clk_hw *hw)
62{
63 struct ccu_nkm *nkm = hw_to_ccu_nkm(hw);
64
65 return ccu_gate_helper_enable(&nkm->common, nkm->enable);
66}
67
68static int ccu_nkm_is_enabled(struct clk_hw *hw)
69{
70 struct ccu_nkm *nkm = hw_to_ccu_nkm(hw);
71
72 return ccu_gate_helper_is_enabled(&nkm->common, nkm->enable);
73}
74
75static unsigned long ccu_nkm_recalc_rate(struct clk_hw *hw,
76 unsigned long parent_rate)
77{
78 struct ccu_nkm *nkm = hw_to_ccu_nkm(hw);
79 unsigned long n, m, k;
80 u32 reg;
81
82 reg = readl(nkm->common.base + nkm->common.reg);
83
84 n = reg >> nkm->n.shift;
85 n &= (1 << nkm->n.width) - 1;
86
87 k = reg >> nkm->k.shift;
88 k &= (1 << nkm->k.width) - 1;
89
90 m = reg >> nkm->m.shift;
91 m &= (1 << nkm->m.width) - 1;
92
93 return parent_rate * (n + 1) * (k + 1) / (m + 1);
94}
95
96static long ccu_nkm_round_rate(struct clk_hw *hw, unsigned long rate,
97 unsigned long *parent_rate)
98{
99 struct ccu_nkm *nkm = hw_to_ccu_nkm(hw);
100 struct _ccu_nkm _nkm;
101
102 _nkm.max_n = 1 << nkm->n.width;
103 _nkm.max_k = 1 << nkm->k.width;
104 _nkm.max_m = 1 << nkm->m.width;
105
106 ccu_nkm_find_best(*parent_rate, rate, &_nkm);
107
108 return *parent_rate * _nkm.n * _nkm.k / _nkm.m;
109}
110
111static int ccu_nkm_set_rate(struct clk_hw *hw, unsigned long rate,
112 unsigned long parent_rate)
113{
114 struct ccu_nkm *nkm = hw_to_ccu_nkm(hw);
115 struct _ccu_nkm _nkm;
116 unsigned long flags;
117 u32 reg;
118
119 _nkm.max_n = 1 << nkm->n.width;
120 _nkm.max_k = 1 << nkm->k.width;
121 _nkm.max_m = 1 << nkm->m.width;
122
123 ccu_nkm_find_best(parent_rate, rate, &_nkm);
124
125 spin_lock_irqsave(nkm->common.lock, flags);
126
127 reg = readl(nkm->common.base + nkm->common.reg);
128 reg &= ~GENMASK(nkm->n.width + nkm->n.shift - 1, nkm->n.shift);
129 reg &= ~GENMASK(nkm->k.width + nkm->k.shift - 1, nkm->k.shift);
130 reg &= ~GENMASK(nkm->m.width + nkm->m.shift - 1, nkm->m.shift);
131
132 reg |= (_nkm.n - 1) << nkm->n.shift;
133 reg |= (_nkm.k - 1) << nkm->k.shift;
134 reg |= (_nkm.m - 1) << nkm->m.shift;
135
136 writel(reg, nkm->common.base + nkm->common.reg);
137
138 spin_unlock_irqrestore(nkm->common.lock, flags);
139
140 ccu_helper_wait_for_lock(&nkm->common, nkm->lock);
141
142 return 0;
143}
144
145const struct clk_ops ccu_nkm_ops = {
146 .disable = ccu_nkm_disable,
147 .enable = ccu_nkm_enable,
148 .is_enabled = ccu_nkm_is_enabled,
149
150 .recalc_rate = ccu_nkm_recalc_rate,
151 .round_rate = ccu_nkm_round_rate,
152 .set_rate = ccu_nkm_set_rate,
153};
diff --git a/drivers/clk/sunxi-ng/ccu_nkm.h b/drivers/clk/sunxi-ng/ccu_nkm.h
new file mode 100644
index 000000000000..1936ac1c6b37
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_nkm.h
@@ -0,0 +1,68 @@
1/*
2 * Copyright (c) 2016 Maxime Ripard. 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#ifndef _CCU_NKM_H_
15#define _CCU_NKM_H_
16
17#include <linux/clk-provider.h>
18
19#include "ccu_common.h"
20#include "ccu_div.h"
21#include "ccu_mult.h"
22
23/*
24 * struct ccu_nkm - Definition of an N-K-M clock
25 *
26 * Clocks based on the formula parent * N * K / M
27 */
28struct ccu_nkm {
29 u32 enable;
30 u32 lock;
31
32 struct _ccu_mult n;
33 struct _ccu_mult k;
34 struct _ccu_div m;
35
36 struct ccu_common common;
37};
38
39#define SUNXI_CCU_NKM_WITH_GATE_LOCK(_struct, _name, _parent, _reg, \
40 _nshift, _nwidth, \
41 _kshift, _kwidth, \
42 _mshift, _mwidth, \
43 _gate, _lock, _flags) \
44 struct ccu_nkm _struct = { \
45 .enable = _gate, \
46 .lock = _lock, \
47 .k = _SUNXI_CCU_MULT(_kshift, _kwidth), \
48 .n = _SUNXI_CCU_MULT(_nshift, _nwidth), \
49 .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
50 .common = { \
51 .reg = _reg, \
52 .hw.init = CLK_HW_INIT(_name, \
53 _parent, \
54 &ccu_nkm_ops, \
55 _flags), \
56 }, \
57 }
58
59static inline struct ccu_nkm *hw_to_ccu_nkm(struct clk_hw *hw)
60{
61 struct ccu_common *common = hw_to_ccu_common(hw);
62
63 return container_of(common, struct ccu_nkm, common);
64}
65
66extern const struct clk_ops ccu_nkm_ops;
67
68#endif /* _CCU_NKM_H_ */
diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c
new file mode 100644
index 000000000000..9f2b98e19dc9
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_nkmp.c
@@ -0,0 +1,167 @@
1/*
2 * Copyright (C) 2016 Maxime Ripard
3 * Maxime Ripard <maxime.ripard@free-electrons.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 */
10
11#include <linux/clk-provider.h>
12#include <linux/rational.h>
13
14#include "ccu_gate.h"
15#include "ccu_nkmp.h"
16
17struct _ccu_nkmp {
18 unsigned long n, max_n;
19 unsigned long k, max_k;
20 unsigned long m, max_m;
21 unsigned long p, max_p;
22};
23
24static void ccu_nkmp_find_best(unsigned long parent, unsigned long rate,
25 struct _ccu_nkmp *nkmp)
26{
27 unsigned long best_rate = 0;
28 unsigned long best_n = 0, best_k = 0, best_m = 0, best_p = 0;
29 unsigned long _n, _k, _m, _p;
30
31 for (_k = 1; _k <= nkmp->max_k; _k++) {
32 for (_p = 0; _p <= nkmp->max_p; _p++) {
33 unsigned long tmp_rate;
34
35 rational_best_approximation(rate / _k, parent >> _p,
36 nkmp->max_n, nkmp->max_m,
37 &_n, &_m);
38
39 tmp_rate = (parent * _n * _k >> _p) / _m;
40
41 if (tmp_rate > rate)
42 continue;
43
44 if ((rate - tmp_rate) < (rate - best_rate)) {
45 best_rate = tmp_rate;
46 best_n = _n;
47 best_k = _k;
48 best_m = _m;
49 best_p = _p;
50 }
51 }
52 }
53
54 nkmp->n = best_n;
55 nkmp->k = best_k;
56 nkmp->m = best_m;
57 nkmp->p = best_p;
58}
59
60static void ccu_nkmp_disable(struct clk_hw *hw)
61{
62 struct ccu_nkmp *nkmp = hw_to_ccu_nkmp(hw);
63
64 return ccu_gate_helper_disable(&nkmp->common, nkmp->enable);
65}
66
67static int ccu_nkmp_enable(struct clk_hw *hw)
68{
69 struct ccu_nkmp *nkmp = hw_to_ccu_nkmp(hw);
70
71 return ccu_gate_helper_enable(&nkmp->common, nkmp->enable);
72}
73
74static int ccu_nkmp_is_enabled(struct clk_hw *hw)
75{
76 struct ccu_nkmp *nkmp = hw_to_ccu_nkmp(hw);
77
78 return ccu_gate_helper_is_enabled(&nkmp->common, nkmp->enable);
79}
80
81static unsigned long ccu_nkmp_recalc_rate(struct clk_hw *hw,
82 unsigned long parent_rate)
83{
84 struct ccu_nkmp *nkmp = hw_to_ccu_nkmp(hw);
85 unsigned long n, m, k, p;
86 u32 reg;
87
88 reg = readl(nkmp->common.base + nkmp->common.reg);
89
90 n = reg >> nkmp->n.shift;
91 n &= (1 << nkmp->n.width) - 1;
92
93 k = reg >> nkmp->k.shift;
94 k &= (1 << nkmp->k.width) - 1;
95
96 m = reg >> nkmp->m.shift;
97 m &= (1 << nkmp->m.width) - 1;
98
99 p = reg >> nkmp->p.shift;
100 p &= (1 << nkmp->p.width) - 1;
101
102 return (parent_rate * (n + 1) * (k + 1) >> p) / (m + 1);
103}
104
105static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate,
106 unsigned long *parent_rate)
107{
108 struct ccu_nkmp *nkmp = hw_to_ccu_nkmp(hw);
109 struct _ccu_nkmp _nkmp;
110
111 _nkmp.max_n = 1 << nkmp->n.width;
112 _nkmp.max_k = 1 << nkmp->k.width;
113 _nkmp.max_m = 1 << nkmp->m.width;
114 _nkmp.max_p = (1 << nkmp->p.width) - 1;
115
116 ccu_nkmp_find_best(*parent_rate, rate,
117 &_nkmp);
118
119 return (*parent_rate * _nkmp.n * _nkmp.k >> _nkmp.p) / _nkmp.m;
120}
121
122static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate,
123 unsigned long parent_rate)
124{
125 struct ccu_nkmp *nkmp = hw_to_ccu_nkmp(hw);
126 struct _ccu_nkmp _nkmp;
127 unsigned long flags;
128 u32 reg;
129
130 _nkmp.max_n = 1 << nkmp->n.width;
131 _nkmp.max_k = 1 << nkmp->k.width;
132 _nkmp.max_m = 1 << nkmp->m.width;
133 _nkmp.max_p = (1 << nkmp->p.width) - 1;
134
135 ccu_nkmp_find_best(parent_rate, rate, &_nkmp);
136
137 spin_lock_irqsave(nkmp->common.lock, flags);
138
139 reg = readl(nkmp->common.base + nkmp->common.reg);
140 reg &= ~GENMASK(nkmp->n.width + nkmp->n.shift - 1, nkmp->n.shift);
141 reg &= ~GENMASK(nkmp->k.width + nkmp->k.shift - 1, nkmp->k.shift);
142 reg &= ~GENMASK(nkmp->m.width + nkmp->m.shift - 1, nkmp->m.shift);
143 reg &= ~GENMASK(nkmp->p.width + nkmp->p.shift - 1, nkmp->p.shift);
144
145 reg |= (_nkmp.n - 1) << nkmp->n.shift;
146 reg |= (_nkmp.k - 1) << nkmp->k.shift;
147 reg |= (_nkmp.m - 1) << nkmp->m.shift;
148 reg |= _nkmp.p << nkmp->p.shift;
149
150 writel(reg, nkmp->common.base + nkmp->common.reg);
151
152 spin_unlock_irqrestore(nkmp->common.lock, flags);
153
154 ccu_helper_wait_for_lock(&nkmp->common, nkmp->lock);
155
156 return 0;
157}
158
159const struct clk_ops ccu_nkmp_ops = {
160 .disable = ccu_nkmp_disable,
161 .enable = ccu_nkmp_enable,
162 .is_enabled = ccu_nkmp_is_enabled,
163
164 .recalc_rate = ccu_nkmp_recalc_rate,
165 .round_rate = ccu_nkmp_round_rate,
166 .set_rate = ccu_nkmp_set_rate,
167};
diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.h b/drivers/clk/sunxi-ng/ccu_nkmp.h
new file mode 100644
index 000000000000..5adb0c92a614
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_nkmp.h
@@ -0,0 +1,71 @@
1/*
2 * Copyright (c) 2016 Maxime Ripard. 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#ifndef _CCU_NKMP_H_
15#define _CCU_NKMP_H_
16
17#include <linux/clk-provider.h>
18
19#include "ccu_common.h"
20#include "ccu_div.h"
21#include "ccu_mult.h"
22
23/*
24 * struct ccu_nkmp - Definition of an N-K-M-P clock
25 *
26 * Clocks based on the formula parent * N * K >> P / M
27 */
28struct ccu_nkmp {
29 u32 enable;
30 u32 lock;
31
32 struct _ccu_mult n;
33 struct _ccu_mult k;
34 struct _ccu_div m;
35 struct _ccu_div p;
36
37 struct ccu_common common;
38};
39
40#define SUNXI_CCU_NKMP_WITH_GATE_LOCK(_struct, _name, _parent, _reg, \
41 _nshift, _nwidth, \
42 _kshift, _kwidth, \
43 _mshift, _mwidth, \
44 _pshift, _pwidth, \
45 _gate, _lock, _flags) \
46 struct ccu_nkmp _struct = { \
47 .enable = _gate, \
48 .lock = _lock, \
49 .n = _SUNXI_CCU_MULT(_nshift, _nwidth), \
50 .k = _SUNXI_CCU_MULT(_kshift, _kwidth), \
51 .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
52 .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \
53 .common = { \
54 .reg = _reg, \
55 .hw.init = CLK_HW_INIT(_name, \
56 _parent, \
57 &ccu_nkmp_ops, \
58 _flags), \
59 }, \
60 }
61
62static inline struct ccu_nkmp *hw_to_ccu_nkmp(struct clk_hw *hw)
63{
64 struct ccu_common *common = hw_to_ccu_common(hw);
65
66 return container_of(common, struct ccu_nkmp, common);
67}
68
69extern const struct clk_ops ccu_nkmp_ops;
70
71#endif /* _CCU_NKMP_H_ */
diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c
new file mode 100644
index 000000000000..e35ddd8eec8b
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_nm.c
@@ -0,0 +1,114 @@
1/*
2 * Copyright (C) 2016 Maxime Ripard
3 * Maxime Ripard <maxime.ripard@free-electrons.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 */
10
11#include <linux/clk-provider.h>
12#include <linux/rational.h>
13
14#include "ccu_frac.h"
15#include "ccu_gate.h"
16#include "ccu_nm.h"
17
18static void ccu_nm_disable(struct clk_hw *hw)
19{
20 struct ccu_nm *nm = hw_to_ccu_nm(hw);
21
22 return ccu_gate_helper_disable(&nm->common, nm->enable);
23}
24
25static int ccu_nm_enable(struct clk_hw *hw)
26{
27 struct ccu_nm *nm = hw_to_ccu_nm(hw);
28
29 return ccu_gate_helper_enable(&nm->common, nm->enable);
30}
31
32static int ccu_nm_is_enabled(struct clk_hw *hw)
33{
34 struct ccu_nm *nm = hw_to_ccu_nm(hw);
35
36 return ccu_gate_helper_is_enabled(&nm->common, nm->enable);
37}
38
39static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw,
40 unsigned long parent_rate)
41{
42 struct ccu_nm *nm = hw_to_ccu_nm(hw);
43 unsigned long n, m;
44 u32 reg;
45
46 if (ccu_frac_helper_is_enabled(&nm->common, &nm->frac))
47 return ccu_frac_helper_read_rate(&nm->common, &nm->frac);
48
49 reg = readl(nm->common.base + nm->common.reg);
50
51 n = reg >> nm->n.shift;
52 n &= (1 << nm->n.width) - 1;
53
54 m = reg >> nm->m.shift;
55 m &= (1 << nm->m.width) - 1;
56
57 return parent_rate * (n + 1) / (m + 1);
58}
59
60static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
61 unsigned long *parent_rate)
62{
63 struct ccu_nm *nm = hw_to_ccu_nm(hw);
64 unsigned long n, m;
65
66 rational_best_approximation(rate, *parent_rate,
67 1 << nm->n.width, 1 << nm->m.width,
68 &n, &m);
69
70 return *parent_rate * n / m;
71}
72
73static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate,
74 unsigned long parent_rate)
75{
76 struct ccu_nm *nm = hw_to_ccu_nm(hw);
77 unsigned long flags;
78 unsigned long n, m;
79 u32 reg;
80
81 if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate))
82 return ccu_frac_helper_set_rate(&nm->common, &nm->frac, rate);
83 else
84 ccu_frac_helper_disable(&nm->common, &nm->frac);
85
86 rational_best_approximation(rate, parent_rate,
87 1 << nm->n.width, 1 << nm->m.width,
88 &n, &m);
89
90 spin_lock_irqsave(nm->common.lock, flags);
91
92 reg = readl(nm->common.base + nm->common.reg);
93 reg &= ~GENMASK(nm->n.width + nm->n.shift - 1, nm->n.shift);
94 reg &= ~GENMASK(nm->m.width + nm->m.shift - 1, nm->m.shift);
95
96 writel(reg | ((m - 1) << nm->m.shift) | ((n - 1) << nm->n.shift),
97 nm->common.base + nm->common.reg);
98
99 spin_unlock_irqrestore(nm->common.lock, flags);
100
101 ccu_helper_wait_for_lock(&nm->common, nm->lock);
102
103 return 0;
104}
105
106const struct clk_ops ccu_nm_ops = {
107 .disable = ccu_nm_disable,
108 .enable = ccu_nm_enable,
109 .is_enabled = ccu_nm_is_enabled,
110
111 .recalc_rate = ccu_nm_recalc_rate,
112 .round_rate = ccu_nm_round_rate,
113 .set_rate = ccu_nm_set_rate,
114};
diff --git a/drivers/clk/sunxi-ng/ccu_nm.h b/drivers/clk/sunxi-ng/ccu_nm.h
new file mode 100644
index 000000000000..0b7bcd33a2df
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_nm.h
@@ -0,0 +1,91 @@
1/*
2 * Copyright (c) 2016 Maxime Ripard. 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#ifndef _CCU_NM_H_
15#define _CCU_NM_H_
16
17#include <linux/clk-provider.h>
18
19#include "ccu_common.h"
20#include "ccu_div.h"
21#include "ccu_frac.h"
22#include "ccu_mult.h"
23
24/*
25 * struct ccu_nm - Definition of an N-M clock
26 *
27 * Clocks based on the formula parent * N / M
28 */
29struct ccu_nm {
30 u32 enable;
31 u32 lock;
32
33 struct _ccu_mult n;
34 struct _ccu_div m;
35 struct _ccu_frac frac;
36
37 struct ccu_common common;
38};
39
40#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(_struct, _name, _parent, _reg, \
41 _nshift, _nwidth, \
42 _mshift, _mwidth, \
43 _frac_en, _frac_sel, \
44 _frac_rate_0, _frac_rate_1, \
45 _gate, _lock, _flags) \
46 struct ccu_nm _struct = { \
47 .enable = _gate, \
48 .lock = _lock, \
49 .n = _SUNXI_CCU_MULT(_nshift, _nwidth), \
50 .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
51 .frac = _SUNXI_CCU_FRAC(_frac_en, _frac_sel, \
52 _frac_rate_0, \
53 _frac_rate_1), \
54 .common = { \
55 .reg = _reg, \
56 .features = CCU_FEATURE_FRACTIONAL, \
57 .hw.init = CLK_HW_INIT(_name, \
58 _parent, \
59 &ccu_nm_ops, \
60 _flags), \
61 }, \
62 }
63
64#define SUNXI_CCU_NM_WITH_GATE_LOCK(_struct, _name, _parent, _reg, \
65 _nshift, _nwidth, \
66 _mshift, _mwidth, \
67 _gate, _lock, _flags) \
68 struct ccu_nm _struct = { \
69 .enable = _gate, \
70 .lock = _lock, \
71 .n = _SUNXI_CCU_MULT(_nshift, _nwidth), \
72 .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
73 .common = { \
74 .reg = _reg, \
75 .hw.init = CLK_HW_INIT(_name, \
76 _parent, \
77 &ccu_nm_ops, \
78 _flags), \
79 }, \
80 }
81
82static inline struct ccu_nm *hw_to_ccu_nm(struct clk_hw *hw)
83{
84 struct ccu_common *common = hw_to_ccu_common(hw);
85
86 return container_of(common, struct ccu_nm, common);
87}
88
89extern const struct clk_ops ccu_nm_ops;
90
91#endif /* _CCU_NM_H_ */
diff --git a/drivers/clk/sunxi-ng/ccu_phase.c b/drivers/clk/sunxi-ng/ccu_phase.c
new file mode 100644
index 000000000000..400c58ad72fd
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_phase.c
@@ -0,0 +1,126 @@
1/*
2 * Copyright (C) 2016 Maxime Ripard
3 * Maxime Ripard <maxime.ripard@free-electrons.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 */
10
11#include <linux/clk-provider.h>
12#include <linux/spinlock.h>
13
14#include "ccu_phase.h"
15
16static int ccu_phase_get_phase(struct clk_hw *hw)
17{
18 struct ccu_phase *phase = hw_to_ccu_phase(hw);
19 struct clk_hw *parent, *grandparent;
20 unsigned int parent_rate, grandparent_rate;
21 u16 step, parent_div;
22 u32 reg;
23 u8 delay;
24
25 reg = readl(phase->common.base + phase->common.reg);
26 delay = (reg >> phase->shift);
27 delay &= (1 << phase->width) - 1;
28
29 if (!delay)
30 return 180;
31
32 /* Get our parent clock, it's the one that can adjust its rate */
33 parent = clk_hw_get_parent(hw);
34 if (!parent)
35 return -EINVAL;
36
37 /* And its rate */
38 parent_rate = clk_hw_get_rate(parent);
39 if (!parent_rate)
40 return -EINVAL;
41
42 /* Now, get our parent's parent (most likely some PLL) */
43 grandparent = clk_hw_get_parent(parent);
44 if (!grandparent)
45 return -EINVAL;
46
47 /* And its rate */
48 grandparent_rate = clk_hw_get_rate(grandparent);
49 if (!grandparent_rate)
50 return -EINVAL;
51
52 /* Get our parent clock divider */
53 parent_div = grandparent_rate / parent_rate;
54
55 step = DIV_ROUND_CLOSEST(360, parent_div);
56 return delay * step;
57}
58
59static int ccu_phase_set_phase(struct clk_hw *hw, int degrees)
60{
61 struct ccu_phase *phase = hw_to_ccu_phase(hw);
62 struct clk_hw *parent, *grandparent;
63 unsigned int parent_rate, grandparent_rate;
64 unsigned long flags;
65 u32 reg;
66 u8 delay;
67
68 /* Get our parent clock, it's the one that can adjust its rate */
69 parent = clk_hw_get_parent(hw);
70 if (!parent)
71 return -EINVAL;
72
73 /* And its rate */
74 parent_rate = clk_hw_get_rate(parent);
75 if (!parent_rate)
76 return -EINVAL;
77
78 /* Now, get our parent's parent (most likely some PLL) */
79 grandparent = clk_hw_get_parent(parent);
80 if (!grandparent)
81 return -EINVAL;
82
83 /* And its rate */
84 grandparent_rate = clk_hw_get_rate(grandparent);
85 if (!grandparent_rate)
86 return -EINVAL;
87
88 if (degrees != 180) {
89 u16 step, parent_div;
90
91 /* Get our parent divider */
92 parent_div = grandparent_rate / parent_rate;
93
94 /*
95 * We can only outphase the clocks by multiple of the
96 * PLL's period.
97 *
98 * Since our parent clock is only a divider, and the
99 * formula to get the outphasing in degrees is deg =
100 * 360 * delta / period
101 *
102 * If we simplify this formula, we can see that the
103 * only thing that we're concerned about is the number
104 * of period we want to outphase our clock from, and
105 * the divider set by our parent clock.
106 */
107 step = DIV_ROUND_CLOSEST(360, parent_div);
108 delay = DIV_ROUND_CLOSEST(degrees, step);
109 } else {
110 delay = 0;
111 }
112
113 spin_lock_irqsave(phase->common.lock, flags);
114 reg = readl(phase->common.base + phase->common.reg);
115 reg &= ~GENMASK(phase->width + phase->shift - 1, phase->shift);
116 writel(reg | (delay << phase->shift),
117 phase->common.base + phase->common.reg);
118 spin_unlock_irqrestore(phase->common.lock, flags);
119
120 return 0;
121}
122
123const struct clk_ops ccu_phase_ops = {
124 .get_phase = ccu_phase_get_phase,
125 .set_phase = ccu_phase_set_phase,
126};
diff --git a/drivers/clk/sunxi-ng/ccu_phase.h b/drivers/clk/sunxi-ng/ccu_phase.h
new file mode 100644
index 000000000000..75a091a4c565
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_phase.h
@@ -0,0 +1,50 @@
1/*
2 * Copyright (c) 2016 Maxime Ripard. 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#ifndef _CCU_PHASE_H_
15#define _CCU_PHASE_H_
16
17#include <linux/clk-provider.h>
18
19#include "ccu_common.h"
20
21struct ccu_phase {
22 u8 shift;
23 u8 width;
24
25 struct ccu_common common;
26};
27
28#define SUNXI_CCU_PHASE(_struct, _name, _parent, _reg, _shift, _width, _flags) \
29 struct ccu_phase _struct = { \
30 .shift = _shift, \
31 .width = _width, \
32 .common = { \
33 .reg = _reg, \
34 .hw.init = CLK_HW_INIT(_name, \
35 _parent, \
36 &ccu_phase_ops, \
37 _flags), \
38 } \
39 }
40
41static inline struct ccu_phase *hw_to_ccu_phase(struct clk_hw *hw)
42{
43 struct ccu_common *common = hw_to_ccu_common(hw);
44
45 return container_of(common, struct ccu_phase, common);
46}
47
48extern const struct clk_ops ccu_phase_ops;
49
50#endif /* _CCU_PHASE_H_ */
diff --git a/drivers/clk/sunxi-ng/ccu_reset.c b/drivers/clk/sunxi-ng/ccu_reset.c
new file mode 100644
index 000000000000..6c31d48783a7
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_reset.c
@@ -0,0 +1,55 @@
1/*
2 * Copyright (C) 2016 Maxime Ripard
3 * Maxime Ripard <maxime.ripard@free-electrons.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 */
10
11#include <linux/io.h>
12#include <linux/reset-controller.h>
13
14#include "ccu_reset.h"
15
16static int ccu_reset_assert(struct reset_controller_dev *rcdev,
17 unsigned long id)
18{
19 struct ccu_reset *ccu = rcdev_to_ccu_reset(rcdev);
20 const struct ccu_reset_map *map = &ccu->reset_map[id];
21 unsigned long flags;
22 u32 reg;
23
24 spin_lock_irqsave(ccu->lock, flags);
25
26 reg = readl(ccu->base + map->reg);
27 writel(reg & ~map->bit, ccu->base + map->reg);
28
29 spin_unlock_irqrestore(ccu->lock, flags);
30
31 return 0;
32}
33
34static int ccu_reset_deassert(struct reset_controller_dev *rcdev,
35 unsigned long id)
36{
37 struct ccu_reset *ccu = rcdev_to_ccu_reset(rcdev);
38 const struct ccu_reset_map *map = &ccu->reset_map[id];
39 unsigned long flags;
40 u32 reg;
41
42 spin_lock_irqsave(ccu->lock, flags);
43
44 reg = readl(ccu->base + map->reg);
45 writel(reg | map->bit, ccu->base + map->reg);
46
47 spin_unlock_irqrestore(ccu->lock, flags);
48
49 return 0;
50}
51
52const struct reset_control_ops ccu_reset_ops = {
53 .assert = ccu_reset_assert,
54 .deassert = ccu_reset_deassert,
55};
diff --git a/drivers/clk/sunxi-ng/ccu_reset.h b/drivers/clk/sunxi-ng/ccu_reset.h
new file mode 100644
index 000000000000..36a4679210bd
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_reset.h
@@ -0,0 +1,40 @@
1/*
2 * Copyright (c) 2016 Maxime Ripard. 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#ifndef _CCU_RESET_H_
15#define _CCU_RESET_H_
16
17#include <linux/reset-controller.h>
18
19struct ccu_reset_map {
20 u16 reg;
21 u32 bit;
22};
23
24
25struct ccu_reset {
26 void __iomem *base;
27 struct ccu_reset_map *reset_map;
28 spinlock_t *lock;
29
30 struct reset_controller_dev rcdev;
31};
32
33static inline struct ccu_reset *rcdev_to_ccu_reset(struct reset_controller_dev *rcdev)
34{
35 return container_of(rcdev, struct ccu_reset, rcdev);
36}
37
38extern const struct reset_control_ops ccu_reset_ops;
39
40#endif /* _CCU_RESET_H_ */
diff --git a/include/dt-bindings/clock/sun8i-h3-ccu.h b/include/dt-bindings/clock/sun8i-h3-ccu.h
new file mode 100644
index 000000000000..efb7ba2bd515
--- /dev/null
+++ b/include/dt-bindings/clock/sun8i-h3-ccu.h
@@ -0,0 +1,145 @@
1/*
2 * Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com>
3 *
4 * This file is dual-licensed: you can use it either under the terms
5 * of the GPL or the X11 license, at your option. Note that this dual
6 * licensing only applies to this file, and not this project as a
7 * whole.
8 *
9 * a) This file is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This file is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * Or, alternatively,
20 *
21 * b) Permission is hereby granted, free of charge, to any person
22 * obtaining a copy of this software and associated documentation
23 * files (the "Software"), to deal in the Software without
24 * restriction, including without limitation the rights to use,
25 * copy, modify, merge, publish, distribute, sublicense, and/or
26 * sell copies of the Software, and to permit persons to whom the
27 * Software is furnished to do so, subject to the following
28 * conditions:
29 *
30 * The above copyright notice and this permission notice shall be
31 * included in all copies or substantial portions of the Software.
32 *
33 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
34 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
35 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
36 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
37 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
38 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
39 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
40 * OTHER DEALINGS IN THE SOFTWARE.
41 */
42
43#ifndef _DT_BINDINGS_CLK_SUN8I_H3_H_
44#define _DT_BINDINGS_CLK_SUN8I_H3_H_
45
46#define CLK_CPUX 14
47
48#define CLK_BUS_CE 20
49#define CLK_BUS_DMA 21
50#define CLK_BUS_MMC0 22
51#define CLK_BUS_MMC1 23
52#define CLK_BUS_MMC2 24
53#define CLK_BUS_NAND 25
54#define CLK_BUS_DRAM 26
55#define CLK_BUS_EMAC 27
56#define CLK_BUS_TS 28
57#define CLK_BUS_HSTIMER 29
58#define CLK_BUS_SPI0 30
59#define CLK_BUS_SPI1 31
60#define CLK_BUS_OTG 32
61#define CLK_BUS_EHCI0 33
62#define CLK_BUS_EHCI1 34
63#define CLK_BUS_EHCI2 35
64#define CLK_BUS_EHCI3 36
65#define CLK_BUS_OHCI0 37
66#define CLK_BUS_OHCI1 38
67#define CLK_BUS_OHCI2 39
68#define CLK_BUS_OHCI3 40
69#define CLK_BUS_VE 41
70#define CLK_BUS_TCON0 42
71#define CLK_BUS_TCON1 43
72#define CLK_BUS_DEINTERLACE 44
73#define CLK_BUS_CSI 45
74#define CLK_BUS_TVE 46
75#define CLK_BUS_HDMI 47
76#define CLK_BUS_DE 48
77#define CLK_BUS_GPU 49
78#define CLK_BUS_MSGBOX 50
79#define CLK_BUS_SPINLOCK 51
80#define CLK_BUS_CODEC 52
81#define CLK_BUS_SPDIF 53
82#define CLK_BUS_PIO 54
83#define CLK_BUS_THS 55
84#define CLK_BUS_I2S0 56
85#define CLK_BUS_I2S1 57
86#define CLK_BUS_I2S2 58
87#define CLK_BUS_I2C0 59
88#define CLK_BUS_I2C1 60
89#define CLK_BUS_I2C2 61
90#define CLK_BUS_UART0 62
91#define CLK_BUS_UART1 63
92#define CLK_BUS_UART2 64
93#define CLK_BUS_UART3 65
94#define CLK_BUS_SCR 66
95#define CLK_BUS_EPHY 67
96#define CLK_BUS_DBG 68
97
98#define CLK_THS 69
99#define CLK_NAND 70
100#define CLK_MMC0 71
101#define CLK_MMC0_SAMPLE 72
102#define CLK_MMC0_OUTPUT 73
103#define CLK_MMC1 74
104#define CLK_MMC1_SAMPLE 75
105#define CLK_MMC1_OUTPUT 76
106#define CLK_MMC2 77
107#define CLK_MMC2_SAMPLE 78
108#define CLK_MMC2_OUTPUT 79
109#define CLK_TS 80
110#define CLK_CE 81
111#define CLK_SPI0 82
112#define CLK_SPI1 83
113#define CLK_I2S0 84
114#define CLK_I2S1 85
115#define CLK_I2S2 86
116#define CLK_SPDIF 87
117#define CLK_USB_PHY0 88
118#define CLK_USB_PHY1 89
119#define CLK_USB_PHY2 90
120#define CLK_USB_PHY3 91
121#define CLK_USB_OHCI0 92
122#define CLK_USB_OHCI1 93
123#define CLK_USB_OHCI2 94
124#define CLK_USB_OHCI3 95
125
126#define CLK_DRAM_VE 97
127#define CLK_DRAM_CSI 98
128#define CLK_DRAM_DEINTERLACE 99
129#define CLK_DRAM_TS 100
130#define CLK_DE 101
131#define CLK_TCON0 102
132#define CLK_TVE 103
133#define CLK_DEINTERLACE 104
134#define CLK_CSI_MISC 105
135#define CLK_CSI_SCLK 106
136#define CLK_CSI_MCLK 107
137#define CLK_VE 108
138#define CLK_AC_DIG 109
139#define CLK_AVS 110
140#define CLK_HDMI 111
141#define CLK_HDMI_DDC 112
142
143#define CLK_GPU 114
144
145#endif /* _DT_BINDINGS_CLK_SUN8I_H3_H_ */
diff --git a/include/dt-bindings/reset/sun8i-h3-ccu.h b/include/dt-bindings/reset/sun8i-h3-ccu.h
new file mode 100644
index 000000000000..6b7af80c26ec
--- /dev/null
+++ b/include/dt-bindings/reset/sun8i-h3-ccu.h
@@ -0,0 +1,103 @@
1/*
2 * Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com>
3 *
4 * This file is dual-licensed: you can use it either under the terms
5 * of the GPL or the X11 license, at your option. Note that this dual
6 * licensing only applies to this file, and not this project as a
7 * whole.
8 *
9 * a) This file is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This file is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * Or, alternatively,
20 *
21 * b) Permission is hereby granted, free of charge, to any person
22 * obtaining a copy of this software and associated documentation
23 * files (the "Software"), to deal in the Software without
24 * restriction, including without limitation the rights to use,
25 * copy, modify, merge, publish, distribute, sublicense, and/or
26 * sell copies of the Software, and to permit persons to whom the
27 * Software is furnished to do so, subject to the following
28 * conditions:
29 *
30 * The above copyright notice and this permission notice shall be
31 * included in all copies or substantial portions of the Software.
32 *
33 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
34 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
35 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
36 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
37 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
38 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
39 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
40 * OTHER DEALINGS IN THE SOFTWARE.
41 */
42
43#ifndef _DT_BINDINGS_RST_SUN8I_H3_H_
44#define _DT_BINDINGS_RST_SUN8I_H3_H_
45
46#define RST_USB_PHY0 0
47#define RST_USB_PHY1 1
48#define RST_USB_PHY2 2
49#define RST_USB_PHY3 3
50
51#define RST_MBUS 4
52
53#define RST_BUS_CE 5
54#define RST_BUS_DMA 6
55#define RST_BUS_MMC0 7
56#define RST_BUS_MMC1 8
57#define RST_BUS_MMC2 9
58#define RST_BUS_NAND 10
59#define RST_BUS_DRAM 11
60#define RST_BUS_EMAC 12
61#define RST_BUS_TS 13
62#define RST_BUS_HSTIMER 14
63#define RST_BUS_SPI0 15
64#define RST_BUS_SPI1 16
65#define RST_BUS_OTG 17
66#define RST_BUS_EHCI0 18
67#define RST_BUS_EHCI1 19
68#define RST_BUS_EHCI2 20
69#define RST_BUS_EHCI3 21
70#define RST_BUS_OHCI0 22
71#define RST_BUS_OHCI1 23
72#define RST_BUS_OHCI2 24
73#define RST_BUS_OHCI3 25
74#define RST_BUS_VE 26
75#define RST_BUS_TCON0 27
76#define RST_BUS_TCON1 28
77#define RST_BUS_DEINTERLACE 29
78#define RST_BUS_CSI 30
79#define RST_BUS_TVE 31
80#define RST_BUS_HDMI0 32
81#define RST_BUS_HDMI1 33
82#define RST_BUS_DE 34
83#define RST_BUS_GPU 35
84#define RST_BUS_MSGBOX 36
85#define RST_BUS_SPINLOCK 37
86#define RST_BUS_DBG 38
87#define RST_BUS_EPHY 39
88#define RST_BUS_CODEC 40
89#define RST_BUS_SPDIF 41
90#define RST_BUS_THS 42
91#define RST_BUS_I2S0 43
92#define RST_BUS_I2S1 44
93#define RST_BUS_I2S2 45
94#define RST_BUS_I2C0 46
95#define RST_BUS_I2C1 47
96#define RST_BUS_I2C2 48
97#define RST_BUS_UART0 49
98#define RST_BUS_UART1 50
99#define RST_BUS_UART2 51
100#define RST_BUS_UART3 52
101#define RST_BUS_SCR 53
102
103#endif /* _DT_BINDINGS_RST_SUN8I_H3_H_ */