]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - drivers/clk/exynos/clk-exynos7420.c
clk: convert API to match reset/mailbox style
[karo-tx-uboot.git] / drivers / clk / exynos / clk-exynos7420.c
1 /*
2  * Samsung Exynos7420 clock driver.
3  * Copyright (C) 2016 Samsung Electronics
4  * Thomas Abraham <thomas.ab@samsung.com>
5  *
6  * SPDX-License-Identifier:     GPL-2.0+
7  */
8
9 #include <common.h>
10 #include <dm.h>
11 #include <errno.h>
12 #include <clk-uclass.h>
13 #include <asm/io.h>
14 #include <dt-bindings/clock/exynos7420-clk.h>
15 #include "clk-pll.h"
16
17 DECLARE_GLOBAL_DATA_PTR;
18
19 #define DIVIDER(reg, shift, mask)       \
20         (((readl(reg) >> shift) & mask) + 1)
21
22 /* CMU TOPC block device structure */
23 struct exynos7420_clk_cmu_topc {
24         unsigned int    rsvd1[68];
25         unsigned int    bus0_pll_con[2];
26         unsigned int    rsvd2[2];
27         unsigned int    bus1_pll_con[2];
28         unsigned int    rsvd3[54];
29         unsigned int    mux_sel[6];
30         unsigned int    rsvd4[250];
31         unsigned int    div[4];
32 };
33
34 /* CMU TOP0 block device structure */
35 struct exynos7420_clk_cmu_top0 {
36         unsigned int    rsvd0[128];
37         unsigned int    mux_sel[7];
38         unsigned int    rsvd1[261];
39         unsigned int    div_peric[5];
40 };
41
42 /**
43  * struct exynos7420_clk_topc_priv - private data for CMU topc clock driver.
44  *
45  * @topc: base address of the memory mapped CMU TOPC controller.
46  * @fin_freq: frequency of the Oscillator clock.
47  * @sclk_bus0_pll_a: frequency of sclk_bus0_pll_a clock.
48  * @sclk_bus1_pll_a: frequency of sclk_bus1_pll_a clock.
49  */
50 struct exynos7420_clk_topc_priv {
51         struct exynos7420_clk_cmu_topc *topc;
52         unsigned long fin_freq;
53         unsigned long sclk_bus0_pll_a;
54         unsigned long sclk_bus1_pll_a;
55 };
56
57 /**
58  * struct exynos7420_clk_top0_priv - private data for CMU top0 clock driver.
59  *
60  * @top0: base address of the memory mapped CMU TOP0 controller.
61  * @mout_top0_bus0_pll_half: frequency of mout_top0_bus0_pll_half clock
62  * @sclk_uart2: frequency of sclk_uart2 clock.
63  */
64 struct exynos7420_clk_top0_priv {
65         struct exynos7420_clk_cmu_top0 *top0;
66         unsigned long mout_top0_bus0_pll_half;
67         unsigned long sclk_uart2;
68 };
69
70 static ulong exynos7420_topc_get_rate(struct clk *clk)
71 {
72         struct exynos7420_clk_topc_priv *priv = dev_get_priv(clk->dev);
73
74         switch (clk->id) {
75         case DOUT_SCLK_BUS0_PLL:
76         case SCLK_BUS0_PLL_A:
77         case SCLK_BUS0_PLL_B:
78                 return priv->sclk_bus0_pll_a;
79         case DOUT_SCLK_BUS1_PLL:
80         case SCLK_BUS1_PLL_A:
81         case SCLK_BUS1_PLL_B:
82                 return priv->sclk_bus1_pll_a;
83         default:
84                 return 0;
85         }
86 }
87
88 static struct clk_ops exynos7420_clk_topc_ops = {
89         .get_rate       = exynos7420_topc_get_rate,
90 };
91
92 static int exynos7420_clk_topc_probe(struct udevice *dev)
93 {
94         struct exynos7420_clk_topc_priv *priv = dev_get_priv(dev);
95         struct exynos7420_clk_cmu_topc *topc;
96         struct clk in_clk;
97         unsigned long rate;
98         fdt_addr_t base;
99         int ret;
100
101         base = dev_get_addr(dev);
102         if (base == FDT_ADDR_T_NONE)
103                 return -EINVAL;
104
105         topc = (struct exynos7420_clk_cmu_topc *)base;
106         priv->topc = topc;
107
108         ret = clk_get_by_index(dev, 0, &in_clk);
109         if (ret >= 0)
110                 priv->fin_freq = clk_get_rate(&in_clk);
111
112         rate = pll145x_get_rate(&topc->bus0_pll_con[0], priv->fin_freq);
113         if (readl(&topc->mux_sel[1]) & (1 << 16))
114                 rate >>= 1;
115         rate /= DIVIDER(&topc->div[3], 0, 0xf);
116         priv->sclk_bus0_pll_a = rate;
117
118         rate = pll145x_get_rate(&topc->bus1_pll_con[0], priv->fin_freq) /
119                         DIVIDER(&topc->div[3], 8, 0xf);
120         priv->sclk_bus1_pll_a = rate;
121
122         return 0;
123 }
124
125 static ulong exynos7420_top0_get_rate(struct clk *clk)
126 {
127         struct exynos7420_clk_top0_priv *priv = dev_get_priv(clk->dev);
128         struct exynos7420_clk_cmu_top0 *top0 = priv->top0;
129
130         switch (clk->id) {
131         case CLK_SCLK_UART2:
132                 return priv->mout_top0_bus0_pll_half /
133                         DIVIDER(&top0->div_peric[3], 8, 0xf);
134         default:
135                 return 0;
136         }
137 }
138
139 static struct clk_ops exynos7420_clk_top0_ops = {
140         .get_rate       = exynos7420_top0_get_rate,
141 };
142
143 static int exynos7420_clk_top0_probe(struct udevice *dev)
144 {
145         struct exynos7420_clk_top0_priv *priv;
146         struct exynos7420_clk_cmu_top0 *top0;
147         struct clk in_clk;
148         fdt_addr_t base;
149         int ret;
150
151         priv = dev_get_priv(dev);
152         if (!priv)
153                 return -EINVAL;
154
155         base = dev_get_addr(dev);
156         if (base == FDT_ADDR_T_NONE)
157                 return -EINVAL;
158
159         top0 = (struct exynos7420_clk_cmu_top0 *)base;
160         priv->top0 = top0;
161
162         ret = clk_get_by_index(dev, 1, &in_clk);
163         if (ret >= 0) {
164                 priv->mout_top0_bus0_pll_half =
165                         clk_get_rate(&in_clk);
166                 if (readl(&top0->mux_sel[1]) & (1 << 16))
167                         priv->mout_top0_bus0_pll_half >>= 1;
168         }
169
170         return 0;
171 }
172
173 static ulong exynos7420_peric1_get_rate(struct clk *clk)
174 {
175         struct clk in_clk;
176         unsigned int ret;
177         unsigned long freq = 0;
178
179         switch (clk->id) {
180         case SCLK_UART2:
181                 ret = clk_get_by_index(clk->dev, 3, &in_clk);
182                 if (ret < 0)
183                         return ret;
184                 freq = clk_get_rate(&in_clk);
185                 break;
186         }
187
188         return freq;
189 }
190
191 static struct clk_ops exynos7420_clk_peric1_ops = {
192         .get_rate       = exynos7420_peric1_get_rate,
193 };
194
195 static const struct udevice_id exynos7420_clk_topc_compat[] = {
196         { .compatible = "samsung,exynos7-clock-topc" },
197         { }
198 };
199
200 U_BOOT_DRIVER(exynos7420_clk_topc) = {
201         .name = "exynos7420-clock-topc",
202         .id = UCLASS_CLK,
203         .of_match = exynos7420_clk_topc_compat,
204         .probe = exynos7420_clk_topc_probe,
205         .priv_auto_alloc_size = sizeof(struct exynos7420_clk_topc_priv),
206         .ops = &exynos7420_clk_topc_ops,
207         .flags = DM_FLAG_PRE_RELOC,
208 };
209
210 static const struct udevice_id exynos7420_clk_top0_compat[] = {
211         { .compatible = "samsung,exynos7-clock-top0" },
212         { }
213 };
214
215 U_BOOT_DRIVER(exynos7420_clk_top0) = {
216         .name = "exynos7420-clock-top0",
217         .id = UCLASS_CLK,
218         .of_match = exynos7420_clk_top0_compat,
219         .probe = exynos7420_clk_top0_probe,
220         .priv_auto_alloc_size = sizeof(struct exynos7420_clk_top0_priv),
221         .ops = &exynos7420_clk_top0_ops,
222         .flags = DM_FLAG_PRE_RELOC,
223 };
224
225 static const struct udevice_id exynos7420_clk_peric1_compat[] = {
226         { .compatible = "samsung,exynos7-clock-peric1" },
227         { }
228 };
229
230 U_BOOT_DRIVER(exynos7420_clk_peric1) = {
231         .name = "exynos7420-clock-peric1",
232         .id = UCLASS_CLK,
233         .of_match = exynos7420_clk_peric1_compat,
234         .ops = &exynos7420_clk_peric1_ops,
235         .flags = DM_FLAG_PRE_RELOC,
236 };