diff options
author | Jiri Kosina <jkosina@suse.cz> | 2014-11-20 08:42:02 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2014-11-20 08:42:02 -0500 |
commit | a02001086bbfb4da35d1228bebc2f1b442db455f (patch) | |
tree | 62ab47936cef06fd08657ca5b6cd1df98c19be57 /drivers/clk | |
parent | eff264efeeb0898408e8c9df72d8a32621035bed (diff) | |
parent | fc14f9c1272f62c3e8d01300f52467c0d9af50f9 (diff) |
Merge Linus' tree to be be to apply submitted patches to newer code than
current trivial.git base
Diffstat (limited to 'drivers/clk')
86 files changed, 5185 insertions, 796 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 01abbbe49bab..3f44f292d066 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig | |||
@@ -32,12 +32,32 @@ config COMMON_CLK_WM831X | |||
32 | 32 | ||
33 | source "drivers/clk/versatile/Kconfig" | 33 | source "drivers/clk/versatile/Kconfig" |
34 | 34 | ||
35 | config COMMON_CLK_MAX_GEN | ||
36 | bool | ||
37 | |||
35 | config COMMON_CLK_MAX77686 | 38 | config COMMON_CLK_MAX77686 |
36 | tristate "Clock driver for Maxim 77686 MFD" | 39 | tristate "Clock driver for Maxim 77686 MFD" |
37 | depends on MFD_MAX77686 | 40 | depends on MFD_MAX77686 |
41 | select COMMON_CLK_MAX_GEN | ||
38 | ---help--- | 42 | ---help--- |
39 | This driver supports Maxim 77686 crystal oscillator clock. | 43 | This driver supports Maxim 77686 crystal oscillator clock. |
40 | 44 | ||
45 | config COMMON_CLK_MAX77802 | ||
46 | tristate "Clock driver for Maxim 77802 PMIC" | ||
47 | depends on MFD_MAX77686 | ||
48 | select COMMON_CLK_MAX_GEN | ||
49 | ---help--- | ||
50 | This driver supports Maxim 77802 crystal oscillator clock. | ||
51 | |||
52 | config COMMON_CLK_RK808 | ||
53 | tristate "Clock driver for RK808" | ||
54 | depends on MFD_RK808 | ||
55 | ---help--- | ||
56 | This driver supports RK808 crystal oscillator clock. These | ||
57 | multi-function devices have two fixed-rate oscillators, | ||
58 | clocked at 32KHz each. Clkout1 is always on, Clkout2 can off | ||
59 | by control register. | ||
60 | |||
41 | config COMMON_CLK_SI5351 | 61 | config COMMON_CLK_SI5351 |
42 | tristate "Clock driver for SiLabs 5351A/B/C" | 62 | tristate "Clock driver for SiLabs 5351A/B/C" |
43 | depends on I2C | 63 | depends on I2C |
@@ -109,6 +129,11 @@ config COMMON_CLK_PALMAS | |||
109 | This driver supports TI Palmas devices 32KHz output KG and KG_AUDIO | 129 | This driver supports TI Palmas devices 32KHz output KG and KG_AUDIO |
110 | using common clock framework. | 130 | using common clock framework. |
111 | 131 | ||
132 | config COMMON_CLK_PXA | ||
133 | def_bool COMMON_CLK && ARCH_PXA | ||
134 | ---help--- | ||
135 | Sypport for the Marvell PXA SoC. | ||
136 | |||
112 | source "drivers/clk/qcom/Kconfig" | 137 | source "drivers/clk/qcom/Kconfig" |
113 | 138 | ||
114 | endmenu | 139 | endmenu |
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index f537a0b1f798..d5fba5bc6e1b 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile | |||
@@ -9,6 +9,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-gate.o | |||
9 | obj-$(CONFIG_COMMON_CLK) += clk-mux.o | 9 | obj-$(CONFIG_COMMON_CLK) += clk-mux.o |
10 | obj-$(CONFIG_COMMON_CLK) += clk-composite.o | 10 | obj-$(CONFIG_COMMON_CLK) += clk-composite.o |
11 | obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o | 11 | obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o |
12 | obj-$(CONFIG_COMMON_CLK) += clk-gpio-gate.o | ||
12 | ifeq ($(CONFIG_OF), y) | 13 | ifeq ($(CONFIG_OF), y) |
13 | obj-$(CONFIG_COMMON_CLK) += clk-conf.o | 14 | obj-$(CONFIG_COMMON_CLK) += clk-conf.o |
14 | endif | 15 | endif |
@@ -22,12 +23,15 @@ obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o | |||
22 | obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o | 23 | obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o |
23 | obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o | 24 | obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o |
24 | obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o | 25 | obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o |
26 | obj-$(CONFIG_COMMON_CLK_MAX_GEN) += clk-max-gen.o | ||
25 | obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o | 27 | obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o |
28 | obj-$(CONFIG_COMMON_CLK_MAX77802) += clk-max77802.o | ||
26 | obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o | 29 | obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o |
27 | obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o | 30 | obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o |
28 | obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o | 31 | obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o |
29 | obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o | 32 | obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o |
30 | obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o | 33 | obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o |
34 | obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o | ||
31 | obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o | 35 | obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o |
32 | obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o | 36 | obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o |
33 | obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o | 37 | obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o |
@@ -48,6 +52,7 @@ obj-$(CONFIG_ARCH_MMP) += mmp/ | |||
48 | endif | 52 | endif |
49 | obj-$(CONFIG_PLAT_ORION) += mvebu/ | 53 | obj-$(CONFIG_PLAT_ORION) += mvebu/ |
50 | obj-$(CONFIG_ARCH_MXS) += mxs/ | 54 | obj-$(CONFIG_ARCH_MXS) += mxs/ |
55 | obj-$(CONFIG_COMMON_CLK_PXA) += pxa/ | ||
51 | obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ | 56 | obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ |
52 | obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ | 57 | obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ |
53 | obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ | 58 | obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ |
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 4998aee59267..89a48a7bd5df 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile | |||
@@ -9,3 +9,4 @@ obj-y += clk-system.o clk-peripheral.o clk-programmable.o | |||
9 | obj-$(CONFIG_HAVE_AT91_UTMI) += clk-utmi.o | 9 | obj-$(CONFIG_HAVE_AT91_UTMI) += clk-utmi.o |
10 | obj-$(CONFIG_HAVE_AT91_USB_CLK) += clk-usb.o | 10 | obj-$(CONFIG_HAVE_AT91_USB_CLK) += clk-usb.o |
11 | obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o | 11 | obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o |
12 | obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o | ||
diff --git a/drivers/clk/at91/clk-h32mx.c b/drivers/clk/at91/clk-h32mx.c new file mode 100644 index 000000000000..152dcb3f7b5f --- /dev/null +++ b/drivers/clk/at91/clk-h32mx.c | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * clk-h32mx.c | ||
3 | * | ||
4 | * Copyright (C) 2014 Atmel | ||
5 | * | ||
6 | * Alexandre Belloni <alexandre.belloni@free-electrons.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/clk-provider.h> | ||
16 | #include <linux/clkdev.h> | ||
17 | #include <linux/clk/at91_pmc.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/of_address.h> | ||
21 | #include <linux/of_irq.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/irq.h> | ||
25 | #include <linux/sched.h> | ||
26 | #include <linux/wait.h> | ||
27 | |||
28 | #include "pmc.h" | ||
29 | |||
30 | #define H32MX_MAX_FREQ 90000000 | ||
31 | |||
32 | struct clk_sama5d4_h32mx { | ||
33 | struct clk_hw hw; | ||
34 | struct at91_pmc *pmc; | ||
35 | }; | ||
36 | |||
37 | #define to_clk_sama5d4_h32mx(hw) container_of(hw, struct clk_sama5d4_h32mx, hw) | ||
38 | |||
39 | static unsigned long clk_sama5d4_h32mx_recalc_rate(struct clk_hw *hw, | ||
40 | unsigned long parent_rate) | ||
41 | { | ||
42 | struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw); | ||
43 | |||
44 | if (pmc_read(h32mxclk->pmc, AT91_PMC_MCKR) & AT91_PMC_H32MXDIV) | ||
45 | return parent_rate / 2; | ||
46 | |||
47 | if (parent_rate > H32MX_MAX_FREQ) | ||
48 | pr_warn("H32MX clock is too fast\n"); | ||
49 | return parent_rate; | ||
50 | } | ||
51 | |||
52 | static long clk_sama5d4_h32mx_round_rate(struct clk_hw *hw, unsigned long rate, | ||
53 | unsigned long *parent_rate) | ||
54 | { | ||
55 | unsigned long div; | ||
56 | |||
57 | if (rate > *parent_rate) | ||
58 | return *parent_rate; | ||
59 | div = *parent_rate / 2; | ||
60 | if (rate < div) | ||
61 | return div; | ||
62 | |||
63 | if (rate - div < *parent_rate - rate) | ||
64 | return div; | ||
65 | |||
66 | return *parent_rate; | ||
67 | } | ||
68 | |||
69 | static int clk_sama5d4_h32mx_set_rate(struct clk_hw *hw, unsigned long rate, | ||
70 | unsigned long parent_rate) | ||
71 | { | ||
72 | struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw); | ||
73 | struct at91_pmc *pmc = h32mxclk->pmc; | ||
74 | u32 tmp; | ||
75 | |||
76 | if (parent_rate != rate && (parent_rate / 2) != rate) | ||
77 | return -EINVAL; | ||
78 | |||
79 | pmc_lock(pmc); | ||
80 | tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_H32MXDIV; | ||
81 | if ((parent_rate / 2) == rate) | ||
82 | tmp |= AT91_PMC_H32MXDIV; | ||
83 | pmc_write(pmc, AT91_PMC_MCKR, tmp); | ||
84 | pmc_unlock(pmc); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static const struct clk_ops h32mx_ops = { | ||
90 | .recalc_rate = clk_sama5d4_h32mx_recalc_rate, | ||
91 | .round_rate = clk_sama5d4_h32mx_round_rate, | ||
92 | .set_rate = clk_sama5d4_h32mx_set_rate, | ||
93 | }; | ||
94 | |||
95 | void __init of_sama5d4_clk_h32mx_setup(struct device_node *np, | ||
96 | struct at91_pmc *pmc) | ||
97 | { | ||
98 | struct clk_sama5d4_h32mx *h32mxclk; | ||
99 | struct clk_init_data init; | ||
100 | const char *parent_name; | ||
101 | struct clk *clk; | ||
102 | |||
103 | h32mxclk = kzalloc(sizeof(*h32mxclk), GFP_KERNEL); | ||
104 | if (!h32mxclk) | ||
105 | return; | ||
106 | |||
107 | parent_name = of_clk_get_parent_name(np, 0); | ||
108 | |||
109 | init.name = np->name; | ||
110 | init.ops = &h32mx_ops; | ||
111 | init.parent_names = parent_name ? &parent_name : NULL; | ||
112 | init.num_parents = parent_name ? 1 : 0; | ||
113 | init.flags = CLK_SET_RATE_GATE; | ||
114 | |||
115 | h32mxclk->hw.init = &init; | ||
116 | h32mxclk->pmc = pmc; | ||
117 | |||
118 | clk = clk_register(NULL, &h32mxclk->hw); | ||
119 | if (!clk) | ||
120 | return; | ||
121 | |||
122 | of_clk_add_provider(np, of_clk_src_simple_get, clk); | ||
123 | } | ||
diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c index cf6ed023504c..6ec79dbc0840 100644 --- a/drivers/clk/at91/clk-pll.c +++ b/drivers/clk/at91/clk-pll.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/of_address.h> | 15 | #include <linux/of_address.h> |
16 | #include <linux/of_irq.h> | 16 | #include <linux/of_irq.h> |
17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
18 | #include <linux/kernel.h> | ||
18 | #include <linux/wait.h> | 19 | #include <linux/wait.h> |
19 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
20 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
@@ -29,9 +30,12 @@ | |||
29 | #define PLL_DIV(reg) ((reg) & PLL_DIV_MASK) | 30 | #define PLL_DIV(reg) ((reg) & PLL_DIV_MASK) |
30 | #define PLL_MUL(reg, layout) (((reg) >> (layout)->mul_shift) & \ | 31 | #define PLL_MUL(reg, layout) (((reg) >> (layout)->mul_shift) & \ |
31 | (layout)->mul_mask) | 32 | (layout)->mul_mask) |
33 | #define PLL_MUL_MIN 2 | ||
34 | #define PLL_MUL_MASK(layout) ((layout)->mul_mask) | ||
35 | #define PLL_MUL_MAX(layout) (PLL_MUL_MASK(layout) + 1) | ||
32 | #define PLL_ICPR_SHIFT(id) ((id) * 16) | 36 | #define PLL_ICPR_SHIFT(id) ((id) * 16) |
33 | #define PLL_ICPR_MASK(id) (0xffff << PLL_ICPR_SHIFT(id)) | 37 | #define PLL_ICPR_MASK(id) (0xffff << PLL_ICPR_SHIFT(id)) |
34 | #define PLL_MAX_COUNT 0x3ff | 38 | #define PLL_MAX_COUNT 0x3f |
35 | #define PLL_COUNT_SHIFT 8 | 39 | #define PLL_COUNT_SHIFT 8 |
36 | #define PLL_OUT_SHIFT 14 | 40 | #define PLL_OUT_SHIFT 14 |
37 | #define PLL_MAX_ID 1 | 41 | #define PLL_MAX_ID 1 |
@@ -147,115 +151,113 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, | |||
147 | unsigned long parent_rate) | 151 | unsigned long parent_rate) |
148 | { | 152 | { |
149 | struct clk_pll *pll = to_clk_pll(hw); | 153 | struct clk_pll *pll = to_clk_pll(hw); |
150 | const struct clk_pll_layout *layout = pll->layout; | 154 | |
151 | struct at91_pmc *pmc = pll->pmc; | 155 | if (!pll->div || !pll->mul) |
152 | int offset = PLL_REG(pll->id); | ||
153 | u32 tmp = pmc_read(pmc, offset) & layout->pllr_mask; | ||
154 | u8 div = PLL_DIV(tmp); | ||
155 | u16 mul = PLL_MUL(tmp, layout); | ||
156 | if (!div || !mul) | ||
157 | return 0; | 156 | return 0; |
158 | 157 | ||
159 | return (parent_rate * (mul + 1)) / div; | 158 | return (parent_rate / pll->div) * (pll->mul + 1); |
160 | } | 159 | } |
161 | 160 | ||
162 | static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate, | 161 | static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate, |
163 | unsigned long parent_rate, | 162 | unsigned long parent_rate, |
164 | u32 *div, u32 *mul, | 163 | u32 *div, u32 *mul, |
165 | u32 *index) { | 164 | u32 *index) { |
166 | unsigned long maxrate; | ||
167 | unsigned long minrate; | ||
168 | unsigned long divrate; | ||
169 | unsigned long bestdiv = 1; | ||
170 | unsigned long bestmul; | ||
171 | unsigned long tmpdiv; | ||
172 | unsigned long roundup; | ||
173 | unsigned long rounddown; | ||
174 | unsigned long remainder; | ||
175 | unsigned long bestremainder; | ||
176 | unsigned long maxmul; | ||
177 | unsigned long maxdiv; | ||
178 | unsigned long mindiv; | ||
179 | int i = 0; | ||
180 | const struct clk_pll_layout *layout = pll->layout; | 165 | const struct clk_pll_layout *layout = pll->layout; |
181 | const struct clk_pll_characteristics *characteristics = | 166 | const struct clk_pll_characteristics *characteristics = |
182 | pll->characteristics; | 167 | pll->characteristics; |
168 | unsigned long bestremainder = ULONG_MAX; | ||
169 | unsigned long maxdiv, mindiv, tmpdiv; | ||
170 | long bestrate = -ERANGE; | ||
171 | unsigned long bestdiv; | ||
172 | unsigned long bestmul; | ||
173 | int i = 0; | ||
183 | 174 | ||
184 | /* Minimum divider = 1 */ | 175 | /* Check if parent_rate is a valid input rate */ |
185 | /* Maximum multiplier = max_mul */ | ||
186 | maxmul = layout->mul_mask + 1; | ||
187 | maxrate = (parent_rate * maxmul) / 1; | ||
188 | |||
189 | /* Maximum divider = max_div */ | ||
190 | /* Minimum multiplier = 2 */ | ||
191 | maxdiv = PLL_DIV_MAX; | ||
192 | minrate = (parent_rate * 2) / maxdiv; | ||
193 | |||
194 | if (parent_rate < characteristics->input.min || | 176 | if (parent_rate < characteristics->input.min || |
195 | parent_rate < characteristics->input.max) | 177 | parent_rate > characteristics->input.max) |
196 | return -ERANGE; | ||
197 | |||
198 | if (parent_rate < minrate || parent_rate > maxrate) | ||
199 | return -ERANGE; | 178 | return -ERANGE; |
200 | 179 | ||
201 | for (i = 0; i < characteristics->num_output; i++) { | 180 | /* |
202 | if (parent_rate >= characteristics->output[i].min && | 181 | * Calculate minimum divider based on the minimum multiplier, the |
203 | parent_rate <= characteristics->output[i].max) | 182 | * parent_rate and the requested rate. |
204 | break; | 183 | * Should always be 2 according to the input and output characteristics |
205 | } | 184 | * of the PLL blocks. |
206 | 185 | */ | |
207 | if (i >= characteristics->num_output) | 186 | mindiv = (parent_rate * PLL_MUL_MIN) / rate; |
208 | return -ERANGE; | 187 | if (!mindiv) |
209 | 188 | mindiv = 1; | |
210 | bestmul = rate / parent_rate; | 189 | |
211 | rounddown = parent_rate % rate; | 190 | /* |
212 | roundup = rate - rounddown; | 191 | * Calculate the maximum divider which is limited by PLL register |
213 | bestremainder = roundup < rounddown ? roundup : rounddown; | 192 | * layout (limited by the MUL or DIV field size). |
214 | 193 | */ | |
215 | if (!bestremainder) { | 194 | maxdiv = DIV_ROUND_UP(parent_rate * PLL_MUL_MAX(layout), rate); |
216 | if (div) | 195 | if (maxdiv > PLL_DIV_MAX) |
217 | *div = bestdiv; | 196 | maxdiv = PLL_DIV_MAX; |
218 | if (mul) | 197 | |
219 | *mul = bestmul; | 198 | /* |
220 | if (index) | 199 | * Iterate over the acceptable divider values to find the best |
221 | *index = i; | 200 | * divider/multiplier pair (the one that generates the closest |
222 | return rate; | 201 | * rate to the requested one). |
223 | } | 202 | */ |
224 | 203 | for (tmpdiv = mindiv; tmpdiv <= maxdiv; tmpdiv++) { | |
225 | maxdiv = 255 / (bestmul + 1); | 204 | unsigned long remainder; |
226 | if (parent_rate / maxdiv < characteristics->input.min) | 205 | unsigned long tmprate; |
227 | maxdiv = parent_rate / characteristics->input.min; | 206 | unsigned long tmpmul; |
228 | mindiv = parent_rate / characteristics->input.max; | 207 | |
229 | if (parent_rate % characteristics->input.max) | 208 | /* |
230 | mindiv++; | 209 | * Calculate the multiplier associated with the current |
231 | 210 | * divider that provide the closest rate to the requested one. | |
232 | for (tmpdiv = mindiv; tmpdiv < maxdiv; tmpdiv++) { | 211 | */ |
233 | divrate = parent_rate / tmpdiv; | 212 | tmpmul = DIV_ROUND_CLOSEST(rate, parent_rate / tmpdiv); |
234 | 213 | tmprate = (parent_rate / tmpdiv) * tmpmul; | |
235 | rounddown = rate % divrate; | 214 | if (tmprate > rate) |
236 | roundup = divrate - rounddown; | 215 | remainder = tmprate - rate; |
237 | remainder = roundup < rounddown ? roundup : rounddown; | 216 | else |
238 | 217 | remainder = rate - tmprate; | |
218 | |||
219 | /* | ||
220 | * Compare the remainder with the best remainder found until | ||
221 | * now and elect a new best multiplier/divider pair if the | ||
222 | * current remainder is smaller than the best one. | ||
223 | */ | ||
239 | if (remainder < bestremainder) { | 224 | if (remainder < bestremainder) { |
240 | bestremainder = remainder; | 225 | bestremainder = remainder; |
241 | bestmul = rate / divrate; | ||
242 | bestdiv = tmpdiv; | 226 | bestdiv = tmpdiv; |
227 | bestmul = tmpmul; | ||
228 | bestrate = tmprate; | ||
243 | } | 229 | } |
244 | 230 | ||
231 | /* | ||
232 | * We've found a perfect match! | ||
233 | * Stop searching now and use this multiplier/divider pair. | ||
234 | */ | ||
245 | if (!remainder) | 235 | if (!remainder) |
246 | break; | 236 | break; |
247 | } | 237 | } |
248 | 238 | ||
249 | rate = (parent_rate / bestdiv) * bestmul; | 239 | /* We haven't found any multiplier/divider pair => return -ERANGE */ |
240 | if (bestrate < 0) | ||
241 | return bestrate; | ||
242 | |||
243 | /* Check if bestrate is a valid output rate */ | ||
244 | for (i = 0; i < characteristics->num_output; i++) { | ||
245 | if (bestrate >= characteristics->output[i].min && | ||
246 | bestrate <= characteristics->output[i].max) | ||
247 | break; | ||
248 | } | ||
249 | |||
250 | if (i >= characteristics->num_output) | ||
251 | return -ERANGE; | ||
250 | 252 | ||
251 | if (div) | 253 | if (div) |
252 | *div = bestdiv; | 254 | *div = bestdiv; |
253 | if (mul) | 255 | if (mul) |
254 | *mul = bestmul; | 256 | *mul = bestmul - 1; |
255 | if (index) | 257 | if (index) |
256 | *index = i; | 258 | *index = i; |
257 | 259 | ||
258 | return rate; | 260 | return bestrate; |
259 | } | 261 | } |
260 | 262 | ||
261 | static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, | 263 | static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, |
diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c index 0300c46ee247..32f7c1b36204 100644 --- a/drivers/clk/at91/clk-slow.c +++ b/drivers/clk/at91/clk-slow.c | |||
@@ -447,7 +447,7 @@ void __init of_at91sam9260_clk_slow_setup(struct device_node *np, | |||
447 | int i; | 447 | int i; |
448 | 448 | ||
449 | num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); | 449 | num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); |
450 | if (num_parents <= 0 || num_parents > 1) | 450 | if (num_parents != 2) |
451 | return; | 451 | return; |
452 | 452 | ||
453 | for (i = 0; i < num_parents; ++i) { | 453 | for (i = 0; i < num_parents; ++i) { |
diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c index 8c96307d7363..a76d03fd577b 100644 --- a/drivers/clk/at91/clk-system.c +++ b/drivers/clk/at91/clk-system.c | |||
@@ -119,13 +119,7 @@ at91_clk_register_system(struct at91_pmc *pmc, const char *name, | |||
119 | init.ops = &system_ops; | 119 | init.ops = &system_ops; |
120 | init.parent_names = &parent_name; | 120 | init.parent_names = &parent_name; |
121 | init.num_parents = 1; | 121 | init.num_parents = 1; |
122 | /* | 122 | init.flags = CLK_SET_RATE_PARENT; |
123 | * CLK_IGNORE_UNUSED is used to avoid ddrck switch off. | ||
124 | * TODO : we should implement a driver supporting at91 ddr controller | ||
125 | * (see drivers/memory) which would request and enable the ddrck clock. | ||
126 | * When this is done we will be able to remove CLK_IGNORE_UNUSED flag. | ||
127 | */ | ||
128 | init.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED; | ||
129 | 123 | ||
130 | sys->id = id; | 124 | sys->id = id; |
131 | sys->hw.init = &init; | 125 | sys->hw.init = &init; |
diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index 7d1d26a4bd04..24b5b020753a 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c | |||
@@ -238,16 +238,22 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, | |||
238 | unsigned long *parent_rate) | 238 | unsigned long *parent_rate) |
239 | { | 239 | { |
240 | struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); | 240 | struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); |
241 | struct clk *parent = __clk_get_parent(hw->clk); | ||
241 | unsigned long bestrate = 0; | 242 | unsigned long bestrate = 0; |
242 | int bestdiff = -1; | 243 | int bestdiff = -1; |
243 | unsigned long tmprate; | 244 | unsigned long tmprate; |
244 | int tmpdiff; | 245 | int tmpdiff; |
245 | int i = 0; | 246 | int i = 0; |
246 | 247 | ||
247 | for (i = 0; i < 4; i++) { | 248 | for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) { |
249 | unsigned long tmp_parent_rate; | ||
250 | |||
248 | if (!usb->divisors[i]) | 251 | if (!usb->divisors[i]) |
249 | continue; | 252 | continue; |
250 | tmprate = *parent_rate / usb->divisors[i]; | 253 | |
254 | tmp_parent_rate = rate * usb->divisors[i]; | ||
255 | tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate); | ||
256 | tmprate = tmp_parent_rate / usb->divisors[i]; | ||
251 | if (tmprate < rate) | 257 | if (tmprate < rate) |
252 | tmpdiff = rate - tmprate; | 258 | tmpdiff = rate - tmprate; |
253 | else | 259 | else |
@@ -256,6 +262,7 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, | |||
256 | if (bestdiff < 0 || bestdiff > tmpdiff) { | 262 | if (bestdiff < 0 || bestdiff > tmpdiff) { |
257 | bestrate = tmprate; | 263 | bestrate = tmprate; |
258 | bestdiff = tmpdiff; | 264 | bestdiff = tmpdiff; |
265 | *parent_rate = tmp_parent_rate; | ||
259 | } | 266 | } |
260 | 267 | ||
261 | if (!bestdiff) | 268 | if (!bestdiff) |
@@ -272,10 +279,13 @@ static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, | |||
272 | int i; | 279 | int i; |
273 | struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); | 280 | struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); |
274 | struct at91_pmc *pmc = usb->pmc; | 281 | struct at91_pmc *pmc = usb->pmc; |
275 | unsigned long div = parent_rate / rate; | 282 | unsigned long div; |
276 | 283 | ||
277 | if (parent_rate % rate) | 284 | if (!rate || parent_rate % rate) |
278 | return -EINVAL; | 285 | return -EINVAL; |
286 | |||
287 | div = parent_rate / rate; | ||
288 | |||
279 | for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) { | 289 | for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) { |
280 | if (usb->divisors[i] == div) { | 290 | if (usb->divisors[i] == div) { |
281 | tmp = pmc_read(pmc, AT91_CKGR_PLLBR) & | 291 | tmp = pmc_read(pmc, AT91_CKGR_PLLBR) & |
@@ -311,7 +321,7 @@ at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name, | |||
311 | init.ops = &at91rm9200_usb_ops; | 321 | init.ops = &at91rm9200_usb_ops; |
312 | init.parent_names = &parent_name; | 322 | init.parent_names = &parent_name; |
313 | init.num_parents = 1; | 323 | init.num_parents = 1; |
314 | init.flags = 0; | 324 | init.flags = CLK_SET_RATE_PARENT; |
315 | 325 | ||
316 | usb->hw.init = &init; | 326 | usb->hw.init = &init; |
317 | usb->pmc = pmc; | 327 | usb->pmc = pmc; |
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index 524196bb35a5..386999b4f8eb 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c | |||
@@ -337,6 +337,12 @@ static const struct of_device_id pmc_clk_ids[] __initconst = { | |||
337 | .data = of_at91sam9x5_clk_smd_setup, | 337 | .data = of_at91sam9x5_clk_smd_setup, |
338 | }, | 338 | }, |
339 | #endif | 339 | #endif |
340 | #if defined(CONFIG_HAVE_AT91_H32MX) | ||
341 | { | ||
342 | .compatible = "atmel,sama5d4-clk-h32mx", | ||
343 | .data = of_sama5d4_clk_h32mx_setup, | ||
344 | }, | ||
345 | #endif | ||
340 | { /*sentinel*/ } | 346 | { /*sentinel*/ } |
341 | }; | 347 | }; |
342 | 348 | ||
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 6c7625976113..52d2041fa3f6 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h | |||
@@ -120,4 +120,9 @@ extern void __init of_at91sam9x5_clk_smd_setup(struct device_node *np, | |||
120 | struct at91_pmc *pmc); | 120 | struct at91_pmc *pmc); |
121 | #endif | 121 | #endif |
122 | 122 | ||
123 | #if defined(CONFIG_HAVE_AT91_SMD) | ||
124 | extern void __init of_sama5d4_clk_h32mx_setup(struct device_node *np, | ||
125 | struct at91_pmc *pmc); | ||
126 | #endif | ||
127 | |||
123 | #endif /* __PMC_H_ */ | 128 | #endif /* __PMC_H_ */ |
diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c index 1127ee46b802..e619285c6def 100644 --- a/drivers/clk/clk-axi-clkgen.c +++ b/drivers/clk/clk-axi-clkgen.c | |||
@@ -544,7 +544,6 @@ static int axi_clkgen_remove(struct platform_device *pdev) | |||
544 | static struct platform_driver axi_clkgen_driver = { | 544 | static struct platform_driver axi_clkgen_driver = { |
545 | .driver = { | 545 | .driver = { |
546 | .name = "adi-axi-clkgen", | 546 | .name = "adi-axi-clkgen", |
547 | .owner = THIS_MODULE, | ||
548 | .of_match_table = axi_clkgen_ids, | 547 | .of_match_table = axi_clkgen_ids, |
549 | }, | 548 | }, |
550 | .probe = axi_clkgen_probe, | 549 | .probe = axi_clkgen_probe, |
diff --git a/drivers/clk/clk-efm32gg.c b/drivers/clk/clk-efm32gg.c index bac2ddf49d02..73a8d0ff530c 100644 --- a/drivers/clk/clk-efm32gg.c +++ b/drivers/clk/clk-efm32gg.c | |||
@@ -22,7 +22,7 @@ static struct clk_onecell_data clk_data = { | |||
22 | .clk_num = ARRAY_SIZE(clk), | 22 | .clk_num = ARRAY_SIZE(clk), |
23 | }; | 23 | }; |
24 | 24 | ||
25 | static int __init efm32gg_cmu_init(struct device_node *np) | 25 | static void __init efm32gg_cmu_init(struct device_node *np) |
26 | { | 26 | { |
27 | int i; | 27 | int i; |
28 | void __iomem *base; | 28 | void __iomem *base; |
@@ -33,7 +33,7 @@ static int __init efm32gg_cmu_init(struct device_node *np) | |||
33 | base = of_iomap(np, 0); | 33 | base = of_iomap(np, 0); |
34 | if (!base) { | 34 | if (!base) { |
35 | pr_warn("Failed to map address range for efm32gg,cmu node\n"); | 35 | pr_warn("Failed to map address range for efm32gg,cmu node\n"); |
36 | return -EADDRNOTAVAIL; | 36 | return; |
37 | } | 37 | } |
38 | 38 | ||
39 | clk[clk_HFXO] = clk_register_fixed_rate(NULL, "HFXO", NULL, | 39 | clk[clk_HFXO] = clk_register_fixed_rate(NULL, "HFXO", NULL, |
@@ -76,6 +76,6 @@ static int __init efm32gg_cmu_init(struct device_node *np) | |||
76 | clk[clk_HFPERCLKDAC0] = clk_register_gate(NULL, "HFPERCLK.DAC0", | 76 | clk[clk_HFPERCLKDAC0] = clk_register_gate(NULL, "HFPERCLK.DAC0", |
77 | "HFXO", 0, base + CMU_HFPERCLKEN0, 17, 0, NULL); | 77 | "HFXO", 0, base + CMU_HFPERCLKEN0, 17, 0, NULL); |
78 | 78 | ||
79 | return of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); | 79 | of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); |
80 | } | 80 | } |
81 | CLK_OF_DECLARE(efm32ggcmu, "efm32gg,cmu", efm32gg_cmu_init); | 81 | CLK_OF_DECLARE(efm32ggcmu, "efm32gg,cmu", efm32gg_cmu_init); |
diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index ede685ca0d20..82a59d0086cc 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c | |||
@@ -36,7 +36,7 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw, | |||
36 | m = (val & fd->mmask) >> fd->mshift; | 36 | m = (val & fd->mmask) >> fd->mshift; |
37 | n = (val & fd->nmask) >> fd->nshift; | 37 | n = (val & fd->nmask) >> fd->nshift; |
38 | 38 | ||
39 | ret = parent_rate * m; | 39 | ret = (u64)parent_rate * m; |
40 | do_div(ret, n); | 40 | do_div(ret, n); |
41 | 41 | ||
42 | return ret; | 42 | return ret; |
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c index 4a58c55255bd..51fd87fb7ba6 100644 --- a/drivers/clk/clk-gate.c +++ b/drivers/clk/clk-gate.c | |||
@@ -45,7 +45,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable) | |||
45 | { | 45 | { |
46 | struct clk_gate *gate = to_clk_gate(hw); | 46 | struct clk_gate *gate = to_clk_gate(hw); |
47 | int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0; | 47 | int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0; |
48 | unsigned long flags = 0; | 48 | unsigned long uninitialized_var(flags); |
49 | u32 reg; | 49 | u32 reg; |
50 | 50 | ||
51 | set ^= enable; | 51 | set ^= enable; |
diff --git a/drivers/clk/clk-gpio-gate.c b/drivers/clk/clk-gpio-gate.c new file mode 100644 index 000000000000..08e43224fd52 --- /dev/null +++ b/drivers/clk/clk-gpio-gate.c | |||
@@ -0,0 +1,205 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 - 2014 Texas Instruments Incorporated - http://www.ti.com | ||
3 | * Author: Jyri Sarha <jsarha@ti.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * Gpio gated clock implementation | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk-provider.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/gpio.h> | ||
16 | #include <linux/gpio/consumer.h> | ||
17 | #include <linux/of_gpio.h> | ||
18 | #include <linux/err.h> | ||
19 | #include <linux/device.h> | ||
20 | |||
21 | /** | ||
22 | * DOC: basic gpio gated clock which can be enabled and disabled | ||
23 | * with gpio output | ||
24 | * Traits of this clock: | ||
25 | * prepare - clk_(un)prepare only ensures parent is (un)prepared | ||
26 | * enable - clk_enable and clk_disable are functional & control gpio | ||
27 | * rate - inherits rate from parent. No clk_set_rate support | ||
28 | * parent - fixed parent. No clk_set_parent support | ||
29 | */ | ||
30 | |||
31 | #define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw) | ||
32 | |||
33 | static int clk_gpio_gate_enable(struct clk_hw *hw) | ||
34 | { | ||
35 | struct clk_gpio *clk = to_clk_gpio(hw); | ||
36 | |||
37 | gpiod_set_value(clk->gpiod, 1); | ||
38 | |||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static void clk_gpio_gate_disable(struct clk_hw *hw) | ||
43 | { | ||
44 | struct clk_gpio *clk = to_clk_gpio(hw); | ||
45 | |||
46 | gpiod_set_value(clk->gpiod, 0); | ||
47 | } | ||
48 | |||
49 | static int clk_gpio_gate_is_enabled(struct clk_hw *hw) | ||
50 | { | ||
51 | struct clk_gpio *clk = to_clk_gpio(hw); | ||
52 | |||
53 | return gpiod_get_value(clk->gpiod); | ||
54 | } | ||
55 | |||
56 | const struct clk_ops clk_gpio_gate_ops = { | ||
57 | .enable = clk_gpio_gate_enable, | ||
58 | .disable = clk_gpio_gate_disable, | ||
59 | .is_enabled = clk_gpio_gate_is_enabled, | ||
60 | }; | ||
61 | EXPORT_SYMBOL_GPL(clk_gpio_gate_ops); | ||
62 | |||
63 | /** | ||
64 | * clk_register_gpio - register a gpip clock with the clock framework | ||
65 | * @dev: device that is registering this clock | ||
66 | * @name: name of this clock | ||
67 | * @parent_name: name of this clock's parent | ||
68 | * @gpiod: gpio descriptor to gate this clock | ||
69 | */ | ||
70 | struct clk *clk_register_gpio_gate(struct device *dev, const char *name, | ||
71 | const char *parent_name, struct gpio_desc *gpiod, | ||
72 | unsigned long flags) | ||
73 | { | ||
74 | struct clk_gpio *clk_gpio = NULL; | ||
75 | struct clk *clk = ERR_PTR(-EINVAL); | ||
76 | struct clk_init_data init = { NULL }; | ||
77 | unsigned long gpio_flags; | ||
78 | int err; | ||
79 | |||
80 | if (gpiod_is_active_low(gpiod)) | ||
81 | gpio_flags = GPIOF_OUT_INIT_HIGH; | ||
82 | else | ||
83 | gpio_flags = GPIOF_OUT_INIT_LOW; | ||
84 | |||
85 | if (dev) | ||
86 | err = devm_gpio_request_one(dev, desc_to_gpio(gpiod), | ||
87 | gpio_flags, name); | ||
88 | else | ||
89 | err = gpio_request_one(desc_to_gpio(gpiod), gpio_flags, name); | ||
90 | |||
91 | if (err) { | ||
92 | pr_err("%s: %s: Error requesting clock control gpio %u\n", | ||
93 | __func__, name, desc_to_gpio(gpiod)); | ||
94 | return ERR_PTR(err); | ||
95 | } | ||
96 | |||
97 | if (dev) | ||
98 | clk_gpio = devm_kzalloc(dev, sizeof(struct clk_gpio), | ||
99 | GFP_KERNEL); | ||
100 | else | ||
101 | clk_gpio = kzalloc(sizeof(struct clk_gpio), GFP_KERNEL); | ||
102 | |||
103 | if (!clk_gpio) { | ||
104 | clk = ERR_PTR(-ENOMEM); | ||
105 | goto clk_register_gpio_gate_err; | ||
106 | } | ||
107 | |||
108 | init.name = name; | ||
109 | init.ops = &clk_gpio_gate_ops; | ||
110 | init.flags = flags | CLK_IS_BASIC; | ||
111 | init.parent_names = (parent_name ? &parent_name : NULL); | ||
112 | init.num_parents = (parent_name ? 1 : 0); | ||
113 | |||
114 | clk_gpio->gpiod = gpiod; | ||
115 | clk_gpio->hw.init = &init; | ||
116 | |||
117 | clk = clk_register(dev, &clk_gpio->hw); | ||
118 | |||
119 | if (!IS_ERR(clk)) | ||
120 | return clk; | ||
121 | |||
122 | if (!dev) | ||
123 | kfree(clk_gpio); | ||
124 | |||
125 | clk_register_gpio_gate_err: | ||
126 | gpiod_put(gpiod); | ||
127 | |||
128 | return clk; | ||
129 | } | ||
130 | EXPORT_SYMBOL_GPL(clk_register_gpio_gate); | ||
131 | |||
132 | #ifdef CONFIG_OF | ||
133 | /** | ||
134 | * The clk_register_gpio_gate has to be delayed, because the EPROBE_DEFER | ||
135 | * can not be handled properly at of_clk_init() call time. | ||
136 | */ | ||
137 | |||
138 | struct clk_gpio_gate_delayed_register_data { | ||
139 | struct device_node *node; | ||
140 | struct mutex lock; | ||
141 | struct clk *clk; | ||
142 | }; | ||
143 | |||
144 | static struct clk *of_clk_gpio_gate_delayed_register_get( | ||
145 | struct of_phandle_args *clkspec, | ||
146 | void *_data) | ||
147 | { | ||
148 | struct clk_gpio_gate_delayed_register_data *data = _data; | ||
149 | struct clk *clk; | ||
150 | const char *clk_name = data->node->name; | ||
151 | const char *parent_name; | ||
152 | struct gpio_desc *gpiod; | ||
153 | int gpio; | ||
154 | |||
155 | mutex_lock(&data->lock); | ||
156 | |||
157 | if (data->clk) { | ||
158 | mutex_unlock(&data->lock); | ||
159 | return data->clk; | ||
160 | } | ||
161 | |||
162 | gpio = of_get_named_gpio_flags(data->node, "enable-gpios", 0, NULL); | ||
163 | if (gpio < 0) { | ||
164 | mutex_unlock(&data->lock); | ||
165 | if (gpio != -EPROBE_DEFER) | ||
166 | pr_err("%s: %s: Can't get 'enable-gpios' DT property\n", | ||
167 | __func__, clk_name); | ||
168 | return ERR_PTR(gpio); | ||
169 | } | ||
170 | gpiod = gpio_to_desc(gpio); | ||
171 | |||
172 | parent_name = of_clk_get_parent_name(data->node, 0); | ||
173 | |||
174 | clk = clk_register_gpio_gate(NULL, clk_name, parent_name, gpiod, 0); | ||
175 | if (IS_ERR(clk)) { | ||
176 | mutex_unlock(&data->lock); | ||
177 | return clk; | ||
178 | } | ||
179 | |||
180 | data->clk = clk; | ||
181 | mutex_unlock(&data->lock); | ||
182 | |||
183 | return clk; | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * of_gpio_gate_clk_setup() - Setup function for gpio controlled clock | ||
188 | */ | ||
189 | void __init of_gpio_gate_clk_setup(struct device_node *node) | ||
190 | { | ||
191 | struct clk_gpio_gate_delayed_register_data *data; | ||
192 | |||
193 | data = kzalloc(sizeof(struct clk_gpio_gate_delayed_register_data), | ||
194 | GFP_KERNEL); | ||
195 | if (!data) | ||
196 | return; | ||
197 | |||
198 | data->node = node; | ||
199 | mutex_init(&data->lock); | ||
200 | |||
201 | of_clk_add_provider(node, of_clk_gpio_gate_delayed_register_get, data); | ||
202 | } | ||
203 | EXPORT_SYMBOL_GPL(of_gpio_gate_clk_setup); | ||
204 | CLK_OF_DECLARE(gpio_gate_clk, "gpio-gate-clock", of_gpio_gate_clk_setup); | ||
205 | #endif | ||
diff --git a/drivers/clk/clk-max-gen.c b/drivers/clk/clk-max-gen.c new file mode 100644 index 000000000000..6505049d50f1 --- /dev/null +++ b/drivers/clk/clk-max-gen.c | |||
@@ -0,0 +1,192 @@ | |||
1 | /* | ||
2 | * clk-max-gen.c - Generic clock driver for Maxim PMICs clocks | ||
3 | * | ||
4 | * Copyright (C) 2014 Google, Inc | ||
5 | * | ||
6 | * Copyright (C) 2012 Samsung Electornics | ||
7 | * Jonghwa Lee <jonghwa3.lee@samsung.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | * This program 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 | * This driver is based on clk-max77686.c | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/regmap.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/clk-provider.h> | ||
29 | #include <linux/mutex.h> | ||
30 | #include <linux/clkdev.h> | ||
31 | #include <linux/of.h> | ||
32 | #include <linux/export.h> | ||
33 | |||
34 | struct max_gen_clk { | ||
35 | struct regmap *regmap; | ||
36 | u32 mask; | ||
37 | u32 reg; | ||
38 | struct clk_hw hw; | ||
39 | }; | ||
40 | |||
41 | static struct max_gen_clk *to_max_gen_clk(struct clk_hw *hw) | ||
42 | { | ||
43 | return container_of(hw, struct max_gen_clk, hw); | ||
44 | } | ||
45 | |||
46 | static int max_gen_clk_prepare(struct clk_hw *hw) | ||
47 | { | ||
48 | struct max_gen_clk *max_gen = to_max_gen_clk(hw); | ||
49 | |||
50 | return regmap_update_bits(max_gen->regmap, max_gen->reg, | ||
51 | max_gen->mask, max_gen->mask); | ||
52 | } | ||
53 | |||
54 | static void max_gen_clk_unprepare(struct clk_hw *hw) | ||
55 | { | ||
56 | struct max_gen_clk *max_gen = to_max_gen_clk(hw); | ||
57 | |||
58 | regmap_update_bits(max_gen->regmap, max_gen->reg, | ||
59 | max_gen->mask, ~max_gen->mask); | ||
60 | } | ||
61 | |||
62 | static int max_gen_clk_is_prepared(struct clk_hw *hw) | ||
63 | { | ||
64 | struct max_gen_clk *max_gen = to_max_gen_clk(hw); | ||
65 | int ret; | ||
66 | u32 val; | ||
67 | |||
68 | ret = regmap_read(max_gen->regmap, max_gen->reg, &val); | ||
69 | |||
70 | if (ret < 0) | ||
71 | return -EINVAL; | ||
72 | |||
73 | return val & max_gen->mask; | ||
74 | } | ||
75 | |||
76 | static unsigned long max_gen_recalc_rate(struct clk_hw *hw, | ||
77 | unsigned long parent_rate) | ||
78 | { | ||
79 | return 32768; | ||
80 | } | ||
81 | |||
82 | struct clk_ops max_gen_clk_ops = { | ||
83 | .prepare = max_gen_clk_prepare, | ||
84 | .unprepare = max_gen_clk_unprepare, | ||
85 | .is_prepared = max_gen_clk_is_prepared, | ||
86 | .recalc_rate = max_gen_recalc_rate, | ||
87 | }; | ||
88 | EXPORT_SYMBOL_GPL(max_gen_clk_ops); | ||
89 | |||
90 | static struct clk *max_gen_clk_register(struct device *dev, | ||
91 | struct max_gen_clk *max_gen) | ||
92 | { | ||
93 | struct clk *clk; | ||
94 | struct clk_hw *hw = &max_gen->hw; | ||
95 | int ret; | ||
96 | |||
97 | clk = devm_clk_register(dev, hw); | ||
98 | if (IS_ERR(clk)) | ||
99 | return clk; | ||
100 | |||
101 | ret = clk_register_clkdev(clk, hw->init->name, NULL); | ||
102 | |||
103 | if (ret) | ||
104 | return ERR_PTR(ret); | ||
105 | |||
106 | return clk; | ||
107 | } | ||
108 | |||
109 | int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap, | ||
110 | u32 reg, struct clk_init_data *clks_init, int num_init) | ||
111 | { | ||
112 | int i, ret; | ||
113 | struct max_gen_clk *max_gen_clks; | ||
114 | struct clk **clocks; | ||
115 | struct device *dev = pdev->dev.parent; | ||
116 | const char *clk_name; | ||
117 | struct clk_init_data *init; | ||
118 | |||
119 | clocks = devm_kzalloc(dev, sizeof(struct clk *) * num_init, GFP_KERNEL); | ||
120 | if (!clocks) | ||
121 | return -ENOMEM; | ||
122 | |||
123 | max_gen_clks = devm_kzalloc(dev, sizeof(struct max_gen_clk) | ||
124 | * num_init, GFP_KERNEL); | ||
125 | if (!max_gen_clks) | ||
126 | return -ENOMEM; | ||
127 | |||
128 | for (i = 0; i < num_init; i++) { | ||
129 | max_gen_clks[i].regmap = regmap; | ||
130 | max_gen_clks[i].mask = 1 << i; | ||
131 | max_gen_clks[i].reg = reg; | ||
132 | |||
133 | init = devm_kzalloc(dev, sizeof(*init), GFP_KERNEL); | ||
134 | if (!init) | ||
135 | return -ENOMEM; | ||
136 | |||
137 | if (dev->of_node && | ||
138 | !of_property_read_string_index(dev->of_node, | ||
139 | "clock-output-names", | ||
140 | i, &clk_name)) | ||
141 | init->name = clk_name; | ||
142 | else | ||
143 | init->name = clks_init[i].name; | ||
144 | |||
145 | init->ops = clks_init[i].ops; | ||
146 | init->flags = clks_init[i].flags; | ||
147 | |||
148 | max_gen_clks[i].hw.init = init; | ||
149 | |||
150 | clocks[i] = max_gen_clk_register(dev, &max_gen_clks[i]); | ||
151 | if (IS_ERR(clocks[i])) { | ||
152 | ret = PTR_ERR(clocks[i]); | ||
153 | dev_err(dev, "failed to register %s\n", | ||
154 | max_gen_clks[i].hw.init->name); | ||
155 | return ret; | ||
156 | } | ||
157 | } | ||
158 | |||
159 | platform_set_drvdata(pdev, clocks); | ||
160 | |||
161 | if (dev->of_node) { | ||
162 | struct clk_onecell_data *of_data; | ||
163 | |||
164 | of_data = devm_kzalloc(dev, sizeof(*of_data), GFP_KERNEL); | ||
165 | if (!of_data) | ||
166 | return -ENOMEM; | ||
167 | |||
168 | of_data->clks = clocks; | ||
169 | of_data->clk_num = num_init; | ||
170 | ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, | ||
171 | of_data); | ||
172 | |||
173 | if (ret) { | ||
174 | dev_err(dev, "failed to register OF clock provider\n"); | ||
175 | return ret; | ||
176 | } | ||
177 | } | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | EXPORT_SYMBOL_GPL(max_gen_clk_probe); | ||
182 | |||
183 | int max_gen_clk_remove(struct platform_device *pdev, int num_init) | ||
184 | { | ||
185 | struct device *dev = pdev->dev.parent; | ||
186 | |||
187 | if (dev->of_node) | ||
188 | of_clk_del_provider(dev->of_node); | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | EXPORT_SYMBOL_GPL(max_gen_clk_remove); | ||
diff --git a/drivers/clk/clk-max-gen.h b/drivers/clk/clk-max-gen.h new file mode 100644 index 000000000000..997e86fc3f4d --- /dev/null +++ b/drivers/clk/clk-max-gen.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * clk-max-gen.h - Generic clock driver for Maxim PMICs clocks | ||
3 | * | ||
4 | * Copyright (C) 2014 Google, Inc | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * 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 | |||
18 | #ifndef __CLK_MAX_GEN_H__ | ||
19 | #define __CLK_MAX_GEN_H__ | ||
20 | |||
21 | #include <linux/types.h> | ||
22 | #include <linux/device.h> | ||
23 | #include <linux/clkdev.h> | ||
24 | #include <linux/regmap.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | |||
27 | int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap, | ||
28 | u32 reg, struct clk_init_data *clks_init, int num_init); | ||
29 | int max_gen_clk_remove(struct platform_device *pdev, int num_init); | ||
30 | extern struct clk_ops max_gen_clk_ops; | ||
31 | |||
32 | #endif /* __CLK_MAX_GEN_H__ */ | ||
diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c index 3d7e8dd8fd58..86cdb3a28629 100644 --- a/drivers/clk/clk-max77686.c +++ b/drivers/clk/clk-max77686.c | |||
@@ -30,193 +30,38 @@ | |||
30 | #include <linux/mutex.h> | 30 | #include <linux/mutex.h> |
31 | #include <linux/clkdev.h> | 31 | #include <linux/clkdev.h> |
32 | 32 | ||
33 | enum { | 33 | #include <dt-bindings/clock/maxim,max77686.h> |
34 | MAX77686_CLK_AP = 0, | 34 | #include "clk-max-gen.h" |
35 | MAX77686_CLK_CP, | ||
36 | MAX77686_CLK_PMIC, | ||
37 | MAX77686_CLKS_NUM, | ||
38 | }; | ||
39 | |||
40 | struct max77686_clk { | ||
41 | struct max77686_dev *iodev; | ||
42 | u32 mask; | ||
43 | struct clk_hw hw; | ||
44 | struct clk_lookup *lookup; | ||
45 | }; | ||
46 | |||
47 | static struct max77686_clk *to_max77686_clk(struct clk_hw *hw) | ||
48 | { | ||
49 | return container_of(hw, struct max77686_clk, hw); | ||
50 | } | ||
51 | |||
52 | static int max77686_clk_prepare(struct clk_hw *hw) | ||
53 | { | ||
54 | struct max77686_clk *max77686 = to_max77686_clk(hw); | ||
55 | |||
56 | return regmap_update_bits(max77686->iodev->regmap, | ||
57 | MAX77686_REG_32KHZ, max77686->mask, | ||
58 | max77686->mask); | ||
59 | } | ||
60 | |||
61 | static void max77686_clk_unprepare(struct clk_hw *hw) | ||
62 | { | ||
63 | struct max77686_clk *max77686 = to_max77686_clk(hw); | ||
64 | |||
65 | regmap_update_bits(max77686->iodev->regmap, | ||
66 | MAX77686_REG_32KHZ, max77686->mask, ~max77686->mask); | ||
67 | } | ||
68 | |||
69 | static int max77686_clk_is_prepared(struct clk_hw *hw) | ||
70 | { | ||
71 | struct max77686_clk *max77686 = to_max77686_clk(hw); | ||
72 | int ret; | ||
73 | u32 val; | ||
74 | |||
75 | ret = regmap_read(max77686->iodev->regmap, | ||
76 | MAX77686_REG_32KHZ, &val); | ||
77 | |||
78 | if (ret < 0) | ||
79 | return -EINVAL; | ||
80 | |||
81 | return val & max77686->mask; | ||
82 | } | ||
83 | |||
84 | static unsigned long max77686_recalc_rate(struct clk_hw *hw, | ||
85 | unsigned long parent_rate) | ||
86 | { | ||
87 | return 32768; | ||
88 | } | ||
89 | |||
90 | static struct clk_ops max77686_clk_ops = { | ||
91 | .prepare = max77686_clk_prepare, | ||
92 | .unprepare = max77686_clk_unprepare, | ||
93 | .is_prepared = max77686_clk_is_prepared, | ||
94 | .recalc_rate = max77686_recalc_rate, | ||
95 | }; | ||
96 | 35 | ||
97 | static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = { | 36 | static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = { |
98 | [MAX77686_CLK_AP] = { | 37 | [MAX77686_CLK_AP] = { |
99 | .name = "32khz_ap", | 38 | .name = "32khz_ap", |
100 | .ops = &max77686_clk_ops, | 39 | .ops = &max_gen_clk_ops, |
101 | .flags = CLK_IS_ROOT, | 40 | .flags = CLK_IS_ROOT, |
102 | }, | 41 | }, |
103 | [MAX77686_CLK_CP] = { | 42 | [MAX77686_CLK_CP] = { |
104 | .name = "32khz_cp", | 43 | .name = "32khz_cp", |
105 | .ops = &max77686_clk_ops, | 44 | .ops = &max_gen_clk_ops, |
106 | .flags = CLK_IS_ROOT, | 45 | .flags = CLK_IS_ROOT, |
107 | }, | 46 | }, |
108 | [MAX77686_CLK_PMIC] = { | 47 | [MAX77686_CLK_PMIC] = { |
109 | .name = "32khz_pmic", | 48 | .name = "32khz_pmic", |
110 | .ops = &max77686_clk_ops, | 49 | .ops = &max_gen_clk_ops, |
111 | .flags = CLK_IS_ROOT, | 50 | .flags = CLK_IS_ROOT, |
112 | }, | 51 | }, |
113 | }; | 52 | }; |
114 | 53 | ||
115 | static struct clk *max77686_clk_register(struct device *dev, | ||
116 | struct max77686_clk *max77686) | ||
117 | { | ||
118 | struct clk *clk; | ||
119 | struct clk_hw *hw = &max77686->hw; | ||
120 | |||
121 | clk = clk_register(dev, hw); | ||
122 | if (IS_ERR(clk)) | ||
123 | return clk; | ||
124 | |||
125 | max77686->lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL); | ||
126 | if (!max77686->lookup) | ||
127 | return ERR_PTR(-ENOMEM); | ||
128 | |||
129 | max77686->lookup->con_id = hw->init->name; | ||
130 | max77686->lookup->clk = clk; | ||
131 | |||
132 | clkdev_add(max77686->lookup); | ||
133 | |||
134 | return clk; | ||
135 | } | ||
136 | |||
137 | static int max77686_clk_probe(struct platform_device *pdev) | 54 | static int max77686_clk_probe(struct platform_device *pdev) |
138 | { | 55 | { |
139 | struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); | 56 | struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); |
140 | struct max77686_clk *max77686_clks[MAX77686_CLKS_NUM]; | ||
141 | struct clk **clocks; | ||
142 | int i, ret; | ||
143 | |||
144 | clocks = devm_kzalloc(&pdev->dev, sizeof(struct clk *) | ||
145 | * MAX77686_CLKS_NUM, GFP_KERNEL); | ||
146 | if (!clocks) | ||
147 | return -ENOMEM; | ||
148 | |||
149 | for (i = 0; i < MAX77686_CLKS_NUM; i++) { | ||
150 | max77686_clks[i] = devm_kzalloc(&pdev->dev, | ||
151 | sizeof(struct max77686_clk), GFP_KERNEL); | ||
152 | if (!max77686_clks[i]) | ||
153 | return -ENOMEM; | ||
154 | } | ||
155 | |||
156 | for (i = 0; i < MAX77686_CLKS_NUM; i++) { | ||
157 | max77686_clks[i]->iodev = iodev; | ||
158 | max77686_clks[i]->mask = 1 << i; | ||
159 | max77686_clks[i]->hw.init = &max77686_clks_init[i]; | ||
160 | |||
161 | clocks[i] = max77686_clk_register(&pdev->dev, max77686_clks[i]); | ||
162 | if (IS_ERR(clocks[i])) { | ||
163 | ret = PTR_ERR(clocks[i]); | ||
164 | dev_err(&pdev->dev, "failed to register %s\n", | ||
165 | max77686_clks[i]->hw.init->name); | ||
166 | goto err_clocks; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | platform_set_drvdata(pdev, clocks); | ||
171 | |||
172 | if (iodev->dev->of_node) { | ||
173 | struct clk_onecell_data *of_data; | ||
174 | 57 | ||
175 | of_data = devm_kzalloc(&pdev->dev, | 58 | return max_gen_clk_probe(pdev, iodev->regmap, MAX77686_REG_32KHZ, |
176 | sizeof(*of_data), GFP_KERNEL); | 59 | max77686_clks_init, MAX77686_CLKS_NUM); |
177 | if (!of_data) { | ||
178 | ret = -ENOMEM; | ||
179 | goto err_clocks; | ||
180 | } | ||
181 | |||
182 | of_data->clks = clocks; | ||
183 | of_data->clk_num = MAX77686_CLKS_NUM; | ||
184 | ret = of_clk_add_provider(iodev->dev->of_node, | ||
185 | of_clk_src_onecell_get, of_data); | ||
186 | if (ret) { | ||
187 | dev_err(&pdev->dev, "failed to register OF clock provider\n"); | ||
188 | goto err_clocks; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | return 0; | ||
193 | |||
194 | err_clocks: | ||
195 | for (--i; i >= 0; --i) { | ||
196 | clkdev_drop(max77686_clks[i]->lookup); | ||
197 | clk_unregister(max77686_clks[i]->hw.clk); | ||
198 | } | ||
199 | |||
200 | return ret; | ||
201 | } | 60 | } |
202 | 61 | ||
203 | static int max77686_clk_remove(struct platform_device *pdev) | 62 | static int max77686_clk_remove(struct platform_device *pdev) |
204 | { | 63 | { |
205 | struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); | 64 | return max_gen_clk_remove(pdev, MAX77686_CLKS_NUM); |
206 | struct clk **clocks = platform_get_drvdata(pdev); | ||
207 | int i; | ||
208 | |||
209 | if (iodev->dev->of_node) | ||
210 | of_clk_del_provider(iodev->dev->of_node); | ||
211 | |||
212 | for (i = 0; i < MAX77686_CLKS_NUM; i++) { | ||
213 | struct clk_hw *hw = __clk_get_hw(clocks[i]); | ||
214 | struct max77686_clk *max77686 = to_max77686_clk(hw); | ||
215 | |||
216 | clkdev_drop(max77686->lookup); | ||
217 | clk_unregister(clocks[i]); | ||
218 | } | ||
219 | return 0; | ||
220 | } | 65 | } |
221 | 66 | ||
222 | static const struct platform_device_id max77686_clk_id[] = { | 67 | static const struct platform_device_id max77686_clk_id[] = { |
@@ -228,24 +73,13 @@ MODULE_DEVICE_TABLE(platform, max77686_clk_id); | |||
228 | static struct platform_driver max77686_clk_driver = { | 73 | static struct platform_driver max77686_clk_driver = { |
229 | .driver = { | 74 | .driver = { |
230 | .name = "max77686-clk", | 75 | .name = "max77686-clk", |
231 | .owner = THIS_MODULE, | ||
232 | }, | 76 | }, |
233 | .probe = max77686_clk_probe, | 77 | .probe = max77686_clk_probe, |
234 | .remove = max77686_clk_remove, | 78 | .remove = max77686_clk_remove, |
235 | .id_table = max77686_clk_id, | 79 | .id_table = max77686_clk_id, |
236 | }; | 80 | }; |
237 | 81 | ||
238 | static int __init max77686_clk_init(void) | 82 | module_platform_driver(max77686_clk_driver); |
239 | { | ||
240 | return platform_driver_register(&max77686_clk_driver); | ||
241 | } | ||
242 | subsys_initcall(max77686_clk_init); | ||
243 | |||
244 | static void __init max77686_clk_cleanup(void) | ||
245 | { | ||
246 | platform_driver_unregister(&max77686_clk_driver); | ||
247 | } | ||
248 | module_exit(max77686_clk_cleanup); | ||
249 | 83 | ||
250 | MODULE_DESCRIPTION("MAXIM 77686 Clock Driver"); | 84 | MODULE_DESCRIPTION("MAXIM 77686 Clock Driver"); |
251 | MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>"); | 85 | MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>"); |
diff --git a/drivers/clk/clk-max77802.c b/drivers/clk/clk-max77802.c new file mode 100644 index 000000000000..0729dc723a8f --- /dev/null +++ b/drivers/clk/clk-max77802.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * clk-max77802.c - Clock driver for Maxim 77802 | ||
3 | * | ||
4 | * Copyright (C) 2014 Google, Inc | ||
5 | * | ||
6 | * Copyright (C) 2012 Samsung Electornics | ||
7 | * Jonghwa Lee <jonghwa3.lee@samsung.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | * This program 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 | * This driver is based on clk-max77686.c | ||
20 | */ | ||
21 | |||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/err.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/mfd/max77686-private.h> | ||
27 | #include <linux/clk-provider.h> | ||
28 | #include <linux/mutex.h> | ||
29 | #include <linux/clkdev.h> | ||
30 | |||
31 | #include <dt-bindings/clock/maxim,max77802.h> | ||
32 | #include "clk-max-gen.h" | ||
33 | |||
34 | #define MAX77802_CLOCK_OPMODE_MASK 0x1 | ||
35 | #define MAX77802_CLOCK_LOW_JITTER_SHIFT 0x3 | ||
36 | |||
37 | static struct clk_init_data max77802_clks_init[MAX77802_CLKS_NUM] = { | ||
38 | [MAX77802_CLK_32K_AP] = { | ||
39 | .name = "32khz_ap", | ||
40 | .ops = &max_gen_clk_ops, | ||
41 | .flags = CLK_IS_ROOT, | ||
42 | }, | ||
43 | [MAX77802_CLK_32K_CP] = { | ||
44 | .name = "32khz_cp", | ||
45 | .ops = &max_gen_clk_ops, | ||
46 | .flags = CLK_IS_ROOT, | ||
47 | }, | ||
48 | }; | ||
49 | |||
50 | static int max77802_clk_probe(struct platform_device *pdev) | ||
51 | { | ||
52 | struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); | ||
53 | int ret; | ||
54 | |||
55 | ret = max_gen_clk_probe(pdev, iodev->regmap, MAX77802_REG_32KHZ, | ||
56 | max77802_clks_init, MAX77802_CLKS_NUM); | ||
57 | |||
58 | if (ret) { | ||
59 | dev_err(&pdev->dev, "generic probe failed %d\n", ret); | ||
60 | return ret; | ||
61 | } | ||
62 | |||
63 | /* Enable low-jitter mode on the 32khz clocks. */ | ||
64 | ret = regmap_update_bits(iodev->regmap, MAX77802_REG_32KHZ, | ||
65 | 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT, | ||
66 | 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT); | ||
67 | if (ret < 0) | ||
68 | dev_err(&pdev->dev, "failed to enable low-jitter mode\n"); | ||
69 | |||
70 | return ret; | ||
71 | } | ||
72 | |||
73 | static int max77802_clk_remove(struct platform_device *pdev) | ||
74 | { | ||
75 | return max_gen_clk_remove(pdev, MAX77802_CLKS_NUM); | ||
76 | } | ||
77 | |||
78 | static const struct platform_device_id max77802_clk_id[] = { | ||
79 | { "max77802-clk", 0}, | ||
80 | { }, | ||
81 | }; | ||
82 | MODULE_DEVICE_TABLE(platform, max77802_clk_id); | ||
83 | |||
84 | static struct platform_driver max77802_clk_driver = { | ||
85 | .driver = { | ||
86 | .name = "max77802-clk", | ||
87 | }, | ||
88 | .probe = max77802_clk_probe, | ||
89 | .remove = max77802_clk_remove, | ||
90 | .id_table = max77802_clk_id, | ||
91 | }; | ||
92 | |||
93 | module_platform_driver(max77802_clk_driver); | ||
94 | |||
95 | MODULE_DESCRIPTION("MAXIM 77802 Clock Driver"); | ||
96 | MODULE_AUTHOR("Javier Martinez Canillas <javier.martinez@collabora.co.uk>"); | ||
97 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/clk/clk-palmas.c b/drivers/clk/clk-palmas.c index 781630e1372b..8d459923a15f 100644 --- a/drivers/clk/clk-palmas.c +++ b/drivers/clk/clk-palmas.c | |||
@@ -292,7 +292,6 @@ static int palmas_clks_remove(struct platform_device *pdev) | |||
292 | static struct platform_driver palmas_clks_driver = { | 292 | static struct platform_driver palmas_clks_driver = { |
293 | .driver = { | 293 | .driver = { |
294 | .name = "palmas-clk", | 294 | .name = "palmas-clk", |
295 | .owner = THIS_MODULE, | ||
296 | .of_match_table = palmas_clks_of_match, | 295 | .of_match_table = palmas_clks_of_match, |
297 | }, | 296 | }, |
298 | .probe = palmas_clks_probe, | 297 | .probe = palmas_clks_probe, |
diff --git a/drivers/clk/clk-rk808.c b/drivers/clk/clk-rk808.c new file mode 100644 index 000000000000..83902b9cd49e --- /dev/null +++ b/drivers/clk/clk-rk808.c | |||
@@ -0,0 +1,170 @@ | |||
1 | /* | ||
2 | * Clkout driver for Rockchip RK808 | ||
3 | * | ||
4 | * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd | ||
5 | * | ||
6 | * Author:Chris Zhong <zyw@rock-chips.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/clk.h> | ||
19 | #include <linux/clk-provider.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/mfd/rk808.h> | ||
24 | #include <linux/i2c.h> | ||
25 | |||
26 | #define RK808_NR_OUTPUT 2 | ||
27 | |||
28 | struct rk808_clkout { | ||
29 | struct rk808 *rk808; | ||
30 | struct clk_onecell_data clk_data; | ||
31 | struct clk_hw clkout1_hw; | ||
32 | struct clk_hw clkout2_hw; | ||
33 | }; | ||
34 | |||
35 | static unsigned long rk808_clkout_recalc_rate(struct clk_hw *hw, | ||
36 | unsigned long parent_rate) | ||
37 | { | ||
38 | return 32768; | ||
39 | } | ||
40 | |||
41 | static int rk808_clkout2_enable(struct clk_hw *hw, bool enable) | ||
42 | { | ||
43 | struct rk808_clkout *rk808_clkout = container_of(hw, | ||
44 | struct rk808_clkout, | ||
45 | clkout2_hw); | ||
46 | struct rk808 *rk808 = rk808_clkout->rk808; | ||
47 | |||
48 | return regmap_update_bits(rk808->regmap, RK808_CLK32OUT_REG, | ||
49 | CLK32KOUT2_EN, enable ? CLK32KOUT2_EN : 0); | ||
50 | } | ||
51 | |||
52 | static int rk808_clkout2_prepare(struct clk_hw *hw) | ||
53 | { | ||
54 | return rk808_clkout2_enable(hw, true); | ||
55 | } | ||
56 | |||
57 | static void rk808_clkout2_unprepare(struct clk_hw *hw) | ||
58 | { | ||
59 | rk808_clkout2_enable(hw, false); | ||
60 | } | ||
61 | |||
62 | static int rk808_clkout2_is_prepared(struct clk_hw *hw) | ||
63 | { | ||
64 | struct rk808_clkout *rk808_clkout = container_of(hw, | ||
65 | struct rk808_clkout, | ||
66 | clkout2_hw); | ||
67 | struct rk808 *rk808 = rk808_clkout->rk808; | ||
68 | uint32_t val; | ||
69 | |||
70 | int ret = regmap_read(rk808->regmap, RK808_CLK32OUT_REG, &val); | ||
71 | |||
72 | if (ret < 0) | ||
73 | return ret; | ||
74 | |||
75 | return (val & CLK32KOUT2_EN) ? 1 : 0; | ||
76 | } | ||
77 | |||
78 | static const struct clk_ops rk808_clkout1_ops = { | ||
79 | .recalc_rate = rk808_clkout_recalc_rate, | ||
80 | }; | ||
81 | |||
82 | static const struct clk_ops rk808_clkout2_ops = { | ||
83 | .prepare = rk808_clkout2_prepare, | ||
84 | .unprepare = rk808_clkout2_unprepare, | ||
85 | .is_prepared = rk808_clkout2_is_prepared, | ||
86 | .recalc_rate = rk808_clkout_recalc_rate, | ||
87 | }; | ||
88 | |||
89 | static int rk808_clkout_probe(struct platform_device *pdev) | ||
90 | { | ||
91 | struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent); | ||
92 | struct i2c_client *client = rk808->i2c; | ||
93 | struct device_node *node = client->dev.of_node; | ||
94 | struct clk_init_data init = {}; | ||
95 | struct clk **clk_table; | ||
96 | struct rk808_clkout *rk808_clkout; | ||
97 | |||
98 | rk808_clkout = devm_kzalloc(&client->dev, | ||
99 | sizeof(*rk808_clkout), GFP_KERNEL); | ||
100 | if (!rk808_clkout) | ||
101 | return -ENOMEM; | ||
102 | |||
103 | rk808_clkout->rk808 = rk808; | ||
104 | |||
105 | clk_table = devm_kcalloc(&client->dev, RK808_NR_OUTPUT, | ||
106 | sizeof(struct clk *), GFP_KERNEL); | ||
107 | if (!clk_table) | ||
108 | return -ENOMEM; | ||
109 | |||
110 | init.flags = CLK_IS_ROOT; | ||
111 | init.parent_names = NULL; | ||
112 | init.num_parents = 0; | ||
113 | init.name = "rk808-clkout1"; | ||
114 | init.ops = &rk808_clkout1_ops; | ||
115 | rk808_clkout->clkout1_hw.init = &init; | ||
116 | |||
117 | /* optional override of the clockname */ | ||
118 | of_property_read_string_index(node, "clock-output-names", | ||
119 | 0, &init.name); | ||
120 | |||
121 | clk_table[0] = devm_clk_register(&client->dev, | ||
122 | &rk808_clkout->clkout1_hw); | ||
123 | if (IS_ERR(clk_table[0])) | ||
124 | return PTR_ERR(clk_table[0]); | ||
125 | |||
126 | init.name = "rk808-clkout2"; | ||
127 | init.ops = &rk808_clkout2_ops; | ||
128 | rk808_clkout->clkout2_hw.init = &init; | ||
129 | |||
130 | /* optional override of the clockname */ | ||
131 | of_property_read_string_index(node, "clock-output-names", | ||
132 | 1, &init.name); | ||
133 | |||
134 | clk_table[1] = devm_clk_register(&client->dev, | ||
135 | &rk808_clkout->clkout2_hw); | ||
136 | if (IS_ERR(clk_table[1])) | ||
137 | return PTR_ERR(clk_table[1]); | ||
138 | |||
139 | rk808_clkout->clk_data.clks = clk_table; | ||
140 | rk808_clkout->clk_data.clk_num = RK808_NR_OUTPUT; | ||
141 | |||
142 | return of_clk_add_provider(node, of_clk_src_onecell_get, | ||
143 | &rk808_clkout->clk_data); | ||
144 | } | ||
145 | |||
146 | static int rk808_clkout_remove(struct platform_device *pdev) | ||
147 | { | ||
148 | struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent); | ||
149 | struct i2c_client *client = rk808->i2c; | ||
150 | struct device_node *node = client->dev.of_node; | ||
151 | |||
152 | of_clk_del_provider(node); | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static struct platform_driver rk808_clkout_driver = { | ||
158 | .probe = rk808_clkout_probe, | ||
159 | .remove = rk808_clkout_remove, | ||
160 | .driver = { | ||
161 | .name = "rk808-clkout", | ||
162 | }, | ||
163 | }; | ||
164 | |||
165 | module_platform_driver(rk808_clkout_driver); | ||
166 | |||
167 | MODULE_DESCRIPTION("Clkout driver for the rk808 series PMICs"); | ||
168 | MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>"); | ||
169 | MODULE_LICENSE("GPL"); | ||
170 | MODULE_ALIAS("platform:rk808-clkout"); | ||
diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c index 1ada79a28052..4a755135bcd3 100644 --- a/drivers/clk/clk-twl6040.c +++ b/drivers/clk/clk-twl6040.c | |||
@@ -112,7 +112,6 @@ static int twl6040_clk_remove(struct platform_device *pdev) | |||
112 | static struct platform_driver twl6040_clk_driver = { | 112 | static struct platform_driver twl6040_clk_driver = { |
113 | .driver = { | 113 | .driver = { |
114 | .name = "twl6040-clk", | 114 | .name = "twl6040-clk", |
115 | .owner = THIS_MODULE, | ||
116 | }, | 115 | }, |
117 | .probe = twl6040_clk_probe, | 116 | .probe = twl6040_clk_probe, |
118 | .remove = twl6040_clk_remove, | 117 | .remove = twl6040_clk_remove, |
diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c index b131041c8f48..ef67719f4e52 100644 --- a/drivers/clk/clk-wm831x.c +++ b/drivers/clk/clk-wm831x.c | |||
@@ -395,7 +395,6 @@ static struct platform_driver wm831x_clk_driver = { | |||
395 | .probe = wm831x_clk_probe, | 395 | .probe = wm831x_clk_probe, |
396 | .driver = { | 396 | .driver = { |
397 | .name = "wm831x-clk", | 397 | .name = "wm831x-clk", |
398 | .owner = THIS_MODULE, | ||
399 | }, | 398 | }, |
400 | }; | 399 | }; |
401 | 400 | ||
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index b76fa69b44cb..4896ae9e23da 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c | |||
@@ -100,6 +100,8 @@ static void clk_enable_unlock(unsigned long flags) | |||
100 | 100 | ||
101 | static struct dentry *rootdir; | 101 | static struct dentry *rootdir; |
102 | static int inited = 0; | 102 | static int inited = 0; |
103 | static DEFINE_MUTEX(clk_debug_lock); | ||
104 | static HLIST_HEAD(clk_debug_list); | ||
103 | 105 | ||
104 | static struct hlist_head *all_lists[] = { | 106 | static struct hlist_head *all_lists[] = { |
105 | &clk_root_list, | 107 | &clk_root_list, |
@@ -117,11 +119,11 @@ static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level) | |||
117 | if (!c) | 119 | if (!c) |
118 | return; | 120 | return; |
119 | 121 | ||
120 | seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu\n", | 122 | seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu %-3d\n", |
121 | level * 3 + 1, "", | 123 | level * 3 + 1, "", |
122 | 30 - level * 3, c->name, | 124 | 30 - level * 3, c->name, |
123 | c->enable_count, c->prepare_count, clk_get_rate(c), | 125 | c->enable_count, c->prepare_count, clk_get_rate(c), |
124 | clk_get_accuracy(c)); | 126 | clk_get_accuracy(c), clk_get_phase(c)); |
125 | } | 127 | } |
126 | 128 | ||
127 | static void clk_summary_show_subtree(struct seq_file *s, struct clk *c, | 129 | static void clk_summary_show_subtree(struct seq_file *s, struct clk *c, |
@@ -143,8 +145,8 @@ static int clk_summary_show(struct seq_file *s, void *data) | |||
143 | struct clk *c; | 145 | struct clk *c; |
144 | struct hlist_head **lists = (struct hlist_head **)s->private; | 146 | struct hlist_head **lists = (struct hlist_head **)s->private; |
145 | 147 | ||
146 | seq_puts(s, " clock enable_cnt prepare_cnt rate accuracy\n"); | 148 | seq_puts(s, " clock enable_cnt prepare_cnt rate accuracy phase\n"); |
147 | seq_puts(s, "--------------------------------------------------------------------------------\n"); | 149 | seq_puts(s, "----------------------------------------------------------------------------------------\n"); |
148 | 150 | ||
149 | clk_prepare_lock(); | 151 | clk_prepare_lock(); |
150 | 152 | ||
@@ -180,6 +182,7 @@ static void clk_dump_one(struct seq_file *s, struct clk *c, int level) | |||
180 | seq_printf(s, "\"prepare_count\": %d,", c->prepare_count); | 182 | seq_printf(s, "\"prepare_count\": %d,", c->prepare_count); |
181 | seq_printf(s, "\"rate\": %lu", clk_get_rate(c)); | 183 | seq_printf(s, "\"rate\": %lu", clk_get_rate(c)); |
182 | seq_printf(s, "\"accuracy\": %lu", clk_get_accuracy(c)); | 184 | seq_printf(s, "\"accuracy\": %lu", clk_get_accuracy(c)); |
185 | seq_printf(s, "\"phase\": %d", clk_get_phase(c)); | ||
183 | } | 186 | } |
184 | 187 | ||
185 | static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level) | 188 | static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level) |
@@ -264,6 +267,11 @@ static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry) | |||
264 | if (!d) | 267 | if (!d) |
265 | goto err_out; | 268 | goto err_out; |
266 | 269 | ||
270 | d = debugfs_create_u32("clk_phase", S_IRUGO, clk->dentry, | ||
271 | (u32 *)&clk->phase); | ||
272 | if (!d) | ||
273 | goto err_out; | ||
274 | |||
267 | d = debugfs_create_x32("clk_flags", S_IRUGO, clk->dentry, | 275 | d = debugfs_create_x32("clk_flags", S_IRUGO, clk->dentry, |
268 | (u32 *)&clk->flags); | 276 | (u32 *)&clk->flags); |
269 | if (!d) | 277 | if (!d) |
@@ -300,28 +308,6 @@ out: | |||
300 | return ret; | 308 | return ret; |
301 | } | 309 | } |
302 | 310 | ||
303 | /* caller must hold prepare_lock */ | ||
304 | static int clk_debug_create_subtree(struct clk *clk, struct dentry *pdentry) | ||
305 | { | ||
306 | struct clk *child; | ||
307 | int ret = -EINVAL;; | ||
308 | |||
309 | if (!clk || !pdentry) | ||
310 | goto out; | ||
311 | |||
312 | ret = clk_debug_create_one(clk, pdentry); | ||
313 | |||
314 | if (ret) | ||
315 | goto out; | ||
316 | |||
317 | hlist_for_each_entry(child, &clk->children, child_node) | ||
318 | clk_debug_create_subtree(child, pdentry); | ||
319 | |||
320 | ret = 0; | ||
321 | out: | ||
322 | return ret; | ||
323 | } | ||
324 | |||
325 | /** | 311 | /** |
326 | * clk_debug_register - add a clk node to the debugfs clk tree | 312 | * clk_debug_register - add a clk node to the debugfs clk tree |
327 | * @clk: the clk being added to the debugfs clk tree | 313 | * @clk: the clk being added to the debugfs clk tree |
@@ -329,20 +315,21 @@ out: | |||
329 | * Dynamically adds a clk to the debugfs clk tree if debugfs has been | 315 | * Dynamically adds a clk to the debugfs clk tree if debugfs has been |
330 | * initialized. Otherwise it bails out early since the debugfs clk tree | 316 | * initialized. Otherwise it bails out early since the debugfs clk tree |
331 | * will be created lazily by clk_debug_init as part of a late_initcall. | 317 | * will be created lazily by clk_debug_init as part of a late_initcall. |
332 | * | ||
333 | * Caller must hold prepare_lock. Only clk_init calls this function (so | ||
334 | * far) so this is taken care. | ||
335 | */ | 318 | */ |
336 | static int clk_debug_register(struct clk *clk) | 319 | static int clk_debug_register(struct clk *clk) |
337 | { | 320 | { |
338 | int ret = 0; | 321 | int ret = 0; |
339 | 322 | ||
323 | mutex_lock(&clk_debug_lock); | ||
324 | hlist_add_head(&clk->debug_node, &clk_debug_list); | ||
325 | |||
340 | if (!inited) | 326 | if (!inited) |
341 | goto out; | 327 | goto unlock; |
342 | 328 | ||
343 | ret = clk_debug_create_subtree(clk, rootdir); | 329 | ret = clk_debug_create_one(clk, rootdir); |
330 | unlock: | ||
331 | mutex_unlock(&clk_debug_lock); | ||
344 | 332 | ||
345 | out: | ||
346 | return ret; | 333 | return ret; |
347 | } | 334 | } |
348 | 335 | ||
@@ -353,12 +340,18 @@ out: | |||
353 | * Dynamically removes a clk and all it's children clk nodes from the | 340 | * Dynamically removes a clk and all it's children clk nodes from the |
354 | * debugfs clk tree if clk->dentry points to debugfs created by | 341 | * debugfs clk tree if clk->dentry points to debugfs created by |
355 | * clk_debug_register in __clk_init. | 342 | * clk_debug_register in __clk_init. |
356 | * | ||
357 | * Caller must hold prepare_lock. | ||
358 | */ | 343 | */ |
359 | static void clk_debug_unregister(struct clk *clk) | 344 | static void clk_debug_unregister(struct clk *clk) |
360 | { | 345 | { |
346 | mutex_lock(&clk_debug_lock); | ||
347 | if (!clk->dentry) | ||
348 | goto out; | ||
349 | |||
350 | hlist_del_init(&clk->debug_node); | ||
361 | debugfs_remove_recursive(clk->dentry); | 351 | debugfs_remove_recursive(clk->dentry); |
352 | clk->dentry = NULL; | ||
353 | out: | ||
354 | mutex_unlock(&clk_debug_lock); | ||
362 | } | 355 | } |
363 | 356 | ||
364 | struct dentry *clk_debugfs_add_file(struct clk *clk, char *name, umode_t mode, | 357 | struct dentry *clk_debugfs_add_file(struct clk *clk, char *name, umode_t mode, |
@@ -415,17 +408,12 @@ static int __init clk_debug_init(void) | |||
415 | if (!d) | 408 | if (!d) |
416 | return -ENOMEM; | 409 | return -ENOMEM; |
417 | 410 | ||
418 | clk_prepare_lock(); | 411 | mutex_lock(&clk_debug_lock); |
419 | 412 | hlist_for_each_entry(clk, &clk_debug_list, debug_node) | |
420 | hlist_for_each_entry(clk, &clk_root_list, child_node) | 413 | clk_debug_create_one(clk, rootdir); |
421 | clk_debug_create_subtree(clk, rootdir); | ||
422 | |||
423 | hlist_for_each_entry(clk, &clk_orphan_list, child_node) | ||
424 | clk_debug_create_subtree(clk, rootdir); | ||
425 | 414 | ||
426 | inited = 1; | 415 | inited = 1; |
427 | 416 | mutex_unlock(&clk_debug_lock); | |
428 | clk_prepare_unlock(); | ||
429 | 417 | ||
430 | return 0; | 418 | return 0; |
431 | } | 419 | } |
@@ -1467,6 +1455,7 @@ static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long even | |||
1467 | static void clk_change_rate(struct clk *clk) | 1455 | static void clk_change_rate(struct clk *clk) |
1468 | { | 1456 | { |
1469 | struct clk *child; | 1457 | struct clk *child; |
1458 | struct hlist_node *tmp; | ||
1470 | unsigned long old_rate; | 1459 | unsigned long old_rate; |
1471 | unsigned long best_parent_rate = 0; | 1460 | unsigned long best_parent_rate = 0; |
1472 | bool skip_set_rate = false; | 1461 | bool skip_set_rate = false; |
@@ -1502,7 +1491,11 @@ static void clk_change_rate(struct clk *clk) | |||
1502 | if (clk->notifier_count && old_rate != clk->rate) | 1491 | if (clk->notifier_count && old_rate != clk->rate) |
1503 | __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate); | 1492 | __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate); |
1504 | 1493 | ||
1505 | hlist_for_each_entry(child, &clk->children, child_node) { | 1494 | /* |
1495 | * Use safe iteration, as change_rate can actually swap parents | ||
1496 | * for certain clock types. | ||
1497 | */ | ||
1498 | hlist_for_each_entry_safe(child, tmp, &clk->children, child_node) { | ||
1506 | /* Skip children who will be reparented to another clock */ | 1499 | /* Skip children who will be reparented to another clock */ |
1507 | if (child->new_parent && child->new_parent != clk) | 1500 | if (child->new_parent && child->new_parent != clk) |
1508 | continue; | 1501 | continue; |
@@ -1739,6 +1732,77 @@ out: | |||
1739 | EXPORT_SYMBOL_GPL(clk_set_parent); | 1732 | EXPORT_SYMBOL_GPL(clk_set_parent); |
1740 | 1733 | ||
1741 | /** | 1734 | /** |
1735 | * clk_set_phase - adjust the phase shift of a clock signal | ||
1736 | * @clk: clock signal source | ||
1737 | * @degrees: number of degrees the signal is shifted | ||
1738 | * | ||
1739 | * Shifts the phase of a clock signal by the specified | ||
1740 | * degrees. Returns 0 on success, -EERROR otherwise. | ||
1741 | * | ||
1742 | * This function makes no distinction about the input or reference | ||
1743 | * signal that we adjust the clock signal phase against. For example | ||
1744 | * phase locked-loop clock signal generators we may shift phase with | ||
1745 | * respect to feedback clock signal input, but for other cases the | ||
1746 | * clock phase may be shifted with respect to some other, unspecified | ||
1747 | * signal. | ||
1748 | * | ||
1749 | * Additionally the concept of phase shift does not propagate through | ||
1750 | * the clock tree hierarchy, which sets it apart from clock rates and | ||
1751 | * clock accuracy. A parent clock phase attribute does not have an | ||
1752 | * impact on the phase attribute of a child clock. | ||
1753 | */ | ||
1754 | int clk_set_phase(struct clk *clk, int degrees) | ||
1755 | { | ||
1756 | int ret = 0; | ||
1757 | |||
1758 | if (!clk) | ||
1759 | goto out; | ||
1760 | |||
1761 | /* sanity check degrees */ | ||
1762 | degrees %= 360; | ||
1763 | if (degrees < 0) | ||
1764 | degrees += 360; | ||
1765 | |||
1766 | clk_prepare_lock(); | ||
1767 | |||
1768 | if (!clk->ops->set_phase) | ||
1769 | goto out_unlock; | ||
1770 | |||
1771 | ret = clk->ops->set_phase(clk->hw, degrees); | ||
1772 | |||
1773 | if (!ret) | ||
1774 | clk->phase = degrees; | ||
1775 | |||
1776 | out_unlock: | ||
1777 | clk_prepare_unlock(); | ||
1778 | |||
1779 | out: | ||
1780 | return ret; | ||
1781 | } | ||
1782 | |||
1783 | /** | ||
1784 | * clk_get_phase - return the phase shift of a clock signal | ||
1785 | * @clk: clock signal source | ||
1786 | * | ||
1787 | * Returns the phase shift of a clock node in degrees, otherwise returns | ||
1788 | * -EERROR. | ||
1789 | */ | ||
1790 | int clk_get_phase(struct clk *clk) | ||
1791 | { | ||
1792 | int ret = 0; | ||
1793 | |||
1794 | if (!clk) | ||
1795 | goto out; | ||
1796 | |||
1797 | clk_prepare_lock(); | ||
1798 | ret = clk->phase; | ||
1799 | clk_prepare_unlock(); | ||
1800 | |||
1801 | out: | ||
1802 | return ret; | ||
1803 | } | ||
1804 | |||
1805 | /** | ||
1742 | * __clk_init - initialize the data structures in a struct clk | 1806 | * __clk_init - initialize the data structures in a struct clk |
1743 | * @dev: device initializing this clk, placeholder for now | 1807 | * @dev: device initializing this clk, placeholder for now |
1744 | * @clk: clk being initialized | 1808 | * @clk: clk being initialized |
@@ -1857,6 +1921,16 @@ int __clk_init(struct device *dev, struct clk *clk) | |||
1857 | clk->accuracy = 0; | 1921 | clk->accuracy = 0; |
1858 | 1922 | ||
1859 | /* | 1923 | /* |
1924 | * Set clk's phase. | ||
1925 | * Since a phase is by definition relative to its parent, just | ||
1926 | * query the current clock phase, or just assume it's in phase. | ||
1927 | */ | ||
1928 | if (clk->ops->get_phase) | ||
1929 | clk->phase = clk->ops->get_phase(clk->hw); | ||
1930 | else | ||
1931 | clk->phase = 0; | ||
1932 | |||
1933 | /* | ||
1860 | * Set clk's rate. The preferred method is to use .recalc_rate. For | 1934 | * Set clk's rate. The preferred method is to use .recalc_rate. For |
1861 | * simple clocks and lazy developers the default fallback is to use the | 1935 | * simple clocks and lazy developers the default fallback is to use the |
1862 | * parent's rate. If a clock doesn't have a parent (or is orphaned) | 1936 | * parent's rate. If a clock doesn't have a parent (or is orphaned) |
@@ -2087,14 +2161,16 @@ void clk_unregister(struct clk *clk) | |||
2087 | { | 2161 | { |
2088 | unsigned long flags; | 2162 | unsigned long flags; |
2089 | 2163 | ||
2090 | if (!clk || WARN_ON_ONCE(IS_ERR(clk))) | 2164 | if (!clk || WARN_ON_ONCE(IS_ERR(clk))) |
2091 | return; | 2165 | return; |
2166 | |||
2167 | clk_debug_unregister(clk); | ||
2092 | 2168 | ||
2093 | clk_prepare_lock(); | 2169 | clk_prepare_lock(); |
2094 | 2170 | ||
2095 | if (clk->ops == &clk_nodrv_ops) { | 2171 | if (clk->ops == &clk_nodrv_ops) { |
2096 | pr_err("%s: unregistered clock: %s\n", __func__, clk->name); | 2172 | pr_err("%s: unregistered clock: %s\n", __func__, clk->name); |
2097 | goto out; | 2173 | return; |
2098 | } | 2174 | } |
2099 | /* | 2175 | /* |
2100 | * Assign empty clock ops for consumers that might still hold | 2176 | * Assign empty clock ops for consumers that might still hold |
@@ -2113,16 +2189,13 @@ void clk_unregister(struct clk *clk) | |||
2113 | clk_set_parent(child, NULL); | 2189 | clk_set_parent(child, NULL); |
2114 | } | 2190 | } |
2115 | 2191 | ||
2116 | clk_debug_unregister(clk); | ||
2117 | |||
2118 | hlist_del_init(&clk->child_node); | 2192 | hlist_del_init(&clk->child_node); |
2119 | 2193 | ||
2120 | if (clk->prepare_count) | 2194 | if (clk->prepare_count) |
2121 | pr_warn("%s: unregistering prepared clock: %s\n", | 2195 | pr_warn("%s: unregistering prepared clock: %s\n", |
2122 | __func__, clk->name); | 2196 | __func__, clk->name); |
2123 | |||
2124 | kref_put(&clk->ref, __clk_release); | 2197 | kref_put(&clk->ref, __clk_release); |
2125 | out: | 2198 | |
2126 | clk_prepare_unlock(); | 2199 | clk_prepare_unlock(); |
2127 | } | 2200 | } |
2128 | EXPORT_SYMBOL_GPL(clk_unregister); | 2201 | EXPORT_SYMBOL_GPL(clk_unregister); |
diff --git a/drivers/clk/hisilicon/clk-hix5hd2.c b/drivers/clk/hisilicon/clk-hix5hd2.c index e5fcfb4e32ef..3f369c60fe56 100644 --- a/drivers/clk/hisilicon/clk-hix5hd2.c +++ b/drivers/clk/hisilicon/clk-hix5hd2.c | |||
@@ -9,6 +9,8 @@ | |||
9 | 9 | ||
10 | #include <linux/of_address.h> | 10 | #include <linux/of_address.h> |
11 | #include <dt-bindings/clock/hix5hd2-clock.h> | 11 | #include <dt-bindings/clock/hix5hd2-clock.h> |
12 | #include <linux/slab.h> | ||
13 | #include <linux/delay.h> | ||
12 | #include "clk.h" | 14 | #include "clk.h" |
13 | 15 | ||
14 | static struct hisi_fixed_rate_clock hix5hd2_fixed_rate_clks[] __initdata = { | 16 | static struct hisi_fixed_rate_clock hix5hd2_fixed_rate_clks[] __initdata = { |
@@ -48,9 +50,9 @@ static const char *sfc_mux_p[] __initconst = { | |||
48 | "24m", "150m", "200m", "100m", "75m", }; | 50 | "24m", "150m", "200m", "100m", "75m", }; |
49 | static u32 sfc_mux_table[] = {0, 4, 5, 6, 7}; | 51 | static u32 sfc_mux_table[] = {0, 4, 5, 6, 7}; |
50 | 52 | ||
51 | static const char *sdio1_mux_p[] __initconst = { | 53 | static const char *sdio_mux_p[] __initconst = { |
52 | "75m", "100m", "50m", "15m", }; | 54 | "75m", "100m", "50m", "15m", }; |
53 | static u32 sdio1_mux_table[] = {0, 1, 2, 3}; | 55 | static u32 sdio_mux_table[] = {0, 1, 2, 3}; |
54 | 56 | ||
55 | static const char *fephy_mux_p[] __initconst = { "25m", "125m"}; | 57 | static const char *fephy_mux_p[] __initconst = { "25m", "125m"}; |
56 | static u32 fephy_mux_table[] = {0, 1}; | 58 | static u32 fephy_mux_table[] = {0, 1}; |
@@ -59,28 +61,243 @@ static u32 fephy_mux_table[] = {0, 1}; | |||
59 | static struct hisi_mux_clock hix5hd2_mux_clks[] __initdata = { | 61 | static struct hisi_mux_clock hix5hd2_mux_clks[] __initdata = { |
60 | { HIX5HD2_SFC_MUX, "sfc_mux", sfc_mux_p, ARRAY_SIZE(sfc_mux_p), | 62 | { HIX5HD2_SFC_MUX, "sfc_mux", sfc_mux_p, ARRAY_SIZE(sfc_mux_p), |
61 | CLK_SET_RATE_PARENT, 0x5c, 8, 3, 0, sfc_mux_table, }, | 63 | CLK_SET_RATE_PARENT, 0x5c, 8, 3, 0, sfc_mux_table, }, |
62 | { HIX5HD2_MMC_MUX, "mmc_mux", sdio1_mux_p, ARRAY_SIZE(sdio1_mux_p), | 64 | { HIX5HD2_MMC_MUX, "mmc_mux", sdio_mux_p, ARRAY_SIZE(sdio_mux_p), |
63 | CLK_SET_RATE_PARENT, 0xa0, 8, 2, 0, sdio1_mux_table, }, | 65 | CLK_SET_RATE_PARENT, 0xa0, 8, 2, 0, sdio_mux_table, }, |
66 | { HIX5HD2_SD_MUX, "sd_mux", sdio_mux_p, ARRAY_SIZE(sdio_mux_p), | ||
67 | CLK_SET_RATE_PARENT, 0x9c, 8, 2, 0, sdio_mux_table, }, | ||
64 | { HIX5HD2_FEPHY_MUX, "fephy_mux", | 68 | { HIX5HD2_FEPHY_MUX, "fephy_mux", |
65 | fephy_mux_p, ARRAY_SIZE(fephy_mux_p), | 69 | fephy_mux_p, ARRAY_SIZE(fephy_mux_p), |
66 | CLK_SET_RATE_PARENT, 0x120, 8, 2, 0, fephy_mux_table, }, | 70 | CLK_SET_RATE_PARENT, 0x120, 8, 2, 0, fephy_mux_table, }, |
67 | }; | 71 | }; |
68 | 72 | ||
69 | static struct hisi_gate_clock hix5hd2_gate_clks[] __initdata = { | 73 | static struct hisi_gate_clock hix5hd2_gate_clks[] __initdata = { |
70 | /*sfc*/ | 74 | /* sfc */ |
71 | { HIX5HD2_SFC_CLK, "clk_sfc", "sfc_mux", | 75 | { HIX5HD2_SFC_CLK, "clk_sfc", "sfc_mux", |
72 | CLK_SET_RATE_PARENT, 0x5c, 0, 0, }, | 76 | CLK_SET_RATE_PARENT, 0x5c, 0, 0, }, |
73 | { HIX5HD2_SFC_RST, "rst_sfc", "clk_sfc", | 77 | { HIX5HD2_SFC_RST, "rst_sfc", "clk_sfc", |
74 | CLK_SET_RATE_PARENT, 0x5c, 4, CLK_GATE_SET_TO_DISABLE, }, | 78 | CLK_SET_RATE_PARENT, 0x5c, 4, CLK_GATE_SET_TO_DISABLE, }, |
75 | /*sdio1*/ | 79 | /* sdio0 */ |
80 | { HIX5HD2_SD_BIU_CLK, "clk_sd_biu", "200m", | ||
81 | CLK_SET_RATE_PARENT, 0x9c, 0, 0, }, | ||
82 | { HIX5HD2_SD_CIU_CLK, "clk_sd_ciu", "sd_mux", | ||
83 | CLK_SET_RATE_PARENT, 0x9c, 1, 0, }, | ||
84 | { HIX5HD2_SD_CIU_RST, "rst_sd_ciu", "clk_sd_ciu", | ||
85 | CLK_SET_RATE_PARENT, 0x9c, 4, CLK_GATE_SET_TO_DISABLE, }, | ||
86 | /* sdio1 */ | ||
76 | { HIX5HD2_MMC_BIU_CLK, "clk_mmc_biu", "200m", | 87 | { HIX5HD2_MMC_BIU_CLK, "clk_mmc_biu", "200m", |
77 | CLK_SET_RATE_PARENT, 0xa0, 0, 0, }, | 88 | CLK_SET_RATE_PARENT, 0xa0, 0, 0, }, |
78 | { HIX5HD2_MMC_CIU_CLK, "clk_mmc_ciu", "mmc_mux", | 89 | { HIX5HD2_MMC_CIU_CLK, "clk_mmc_ciu", "mmc_mux", |
79 | CLK_SET_RATE_PARENT, 0xa0, 1, 0, }, | 90 | CLK_SET_RATE_PARENT, 0xa0, 1, 0, }, |
80 | { HIX5HD2_MMC_CIU_RST, "rst_mmc_ciu", "clk_mmc_ciu", | 91 | { HIX5HD2_MMC_CIU_RST, "rst_mmc_ciu", "clk_mmc_ciu", |
81 | CLK_SET_RATE_PARENT, 0xa0, 4, CLK_GATE_SET_TO_DISABLE, }, | 92 | CLK_SET_RATE_PARENT, 0xa0, 4, CLK_GATE_SET_TO_DISABLE, }, |
93 | /* gsf */ | ||
94 | { HIX5HD2_FWD_BUS_CLK, "clk_fwd_bus", NULL, 0, 0xcc, 0, 0, }, | ||
95 | { HIX5HD2_FWD_SYS_CLK, "clk_fwd_sys", "clk_fwd_bus", 0, 0xcc, 5, 0, }, | ||
96 | { HIX5HD2_MAC0_PHY_CLK, "clk_fephy", "clk_fwd_sys", | ||
97 | CLK_SET_RATE_PARENT, 0x120, 0, 0, }, | ||
98 | /* wdg0 */ | ||
99 | { HIX5HD2_WDG0_CLK, "clk_wdg0", "24m", | ||
100 | CLK_SET_RATE_PARENT, 0x178, 0, 0, }, | ||
101 | { HIX5HD2_WDG0_RST, "rst_wdg0", "clk_wdg0", | ||
102 | CLK_SET_RATE_PARENT, 0x178, 4, CLK_GATE_SET_TO_DISABLE, }, | ||
103 | /* I2C */ | ||
104 | {HIX5HD2_I2C0_CLK, "clk_i2c0", "100m", | ||
105 | CLK_SET_RATE_PARENT, 0x06c, 4, 0, }, | ||
106 | {HIX5HD2_I2C0_RST, "rst_i2c0", "clk_i2c0", | ||
107 | CLK_SET_RATE_PARENT, 0x06c, 5, CLK_GATE_SET_TO_DISABLE, }, | ||
108 | {HIX5HD2_I2C1_CLK, "clk_i2c1", "100m", | ||
109 | CLK_SET_RATE_PARENT, 0x06c, 8, 0, }, | ||
110 | {HIX5HD2_I2C1_RST, "rst_i2c1", "clk_i2c1", | ||
111 | CLK_SET_RATE_PARENT, 0x06c, 9, CLK_GATE_SET_TO_DISABLE, }, | ||
112 | {HIX5HD2_I2C2_CLK, "clk_i2c2", "100m", | ||
113 | CLK_SET_RATE_PARENT, 0x06c, 12, 0, }, | ||
114 | {HIX5HD2_I2C2_RST, "rst_i2c2", "clk_i2c2", | ||
115 | CLK_SET_RATE_PARENT, 0x06c, 13, CLK_GATE_SET_TO_DISABLE, }, | ||
116 | {HIX5HD2_I2C3_CLK, "clk_i2c3", "100m", | ||
117 | CLK_SET_RATE_PARENT, 0x06c, 16, 0, }, | ||
118 | {HIX5HD2_I2C3_RST, "rst_i2c3", "clk_i2c3", | ||
119 | CLK_SET_RATE_PARENT, 0x06c, 17, CLK_GATE_SET_TO_DISABLE, }, | ||
120 | {HIX5HD2_I2C4_CLK, "clk_i2c4", "100m", | ||
121 | CLK_SET_RATE_PARENT, 0x06c, 20, 0, }, | ||
122 | {HIX5HD2_I2C4_RST, "rst_i2c4", "clk_i2c4", | ||
123 | CLK_SET_RATE_PARENT, 0x06c, 21, CLK_GATE_SET_TO_DISABLE, }, | ||
124 | {HIX5HD2_I2C5_CLK, "clk_i2c5", "100m", | ||
125 | CLK_SET_RATE_PARENT, 0x06c, 0, 0, }, | ||
126 | {HIX5HD2_I2C5_RST, "rst_i2c5", "clk_i2c5", | ||
127 | CLK_SET_RATE_PARENT, 0x06c, 1, CLK_GATE_SET_TO_DISABLE, }, | ||
82 | }; | 128 | }; |
83 | 129 | ||
130 | enum hix5hd2_clk_type { | ||
131 | TYPE_COMPLEX, | ||
132 | TYPE_ETHER, | ||
133 | }; | ||
134 | |||
135 | struct hix5hd2_complex_clock { | ||
136 | const char *name; | ||
137 | const char *parent_name; | ||
138 | u32 id; | ||
139 | u32 ctrl_reg; | ||
140 | u32 ctrl_clk_mask; | ||
141 | u32 ctrl_rst_mask; | ||
142 | u32 phy_reg; | ||
143 | u32 phy_clk_mask; | ||
144 | u32 phy_rst_mask; | ||
145 | enum hix5hd2_clk_type type; | ||
146 | }; | ||
147 | |||
148 | struct hix5hd2_clk_complex { | ||
149 | struct clk_hw hw; | ||
150 | u32 id; | ||
151 | void __iomem *ctrl_reg; | ||
152 | u32 ctrl_clk_mask; | ||
153 | u32 ctrl_rst_mask; | ||
154 | void __iomem *phy_reg; | ||
155 | u32 phy_clk_mask; | ||
156 | u32 phy_rst_mask; | ||
157 | }; | ||
158 | |||
159 | static struct hix5hd2_complex_clock hix5hd2_complex_clks[] __initdata = { | ||
160 | {"clk_mac0", "clk_fephy", HIX5HD2_MAC0_CLK, | ||
161 | 0xcc, 0xa, 0x500, 0x120, 0, 0x10, TYPE_ETHER}, | ||
162 | {"clk_mac1", "clk_fwd_sys", HIX5HD2_MAC1_CLK, | ||
163 | 0xcc, 0x14, 0xa00, 0x168, 0x2, 0, TYPE_ETHER}, | ||
164 | {"clk_sata", NULL, HIX5HD2_SATA_CLK, | ||
165 | 0xa8, 0x1f, 0x300, 0xac, 0x1, 0x0, TYPE_COMPLEX}, | ||
166 | {"clk_usb", NULL, HIX5HD2_USB_CLK, | ||
167 | 0xb8, 0xff, 0x3f000, 0xbc, 0x7, 0x3f00, TYPE_COMPLEX}, | ||
168 | }; | ||
169 | |||
170 | #define to_complex_clk(_hw) container_of(_hw, struct hix5hd2_clk_complex, hw) | ||
171 | |||
172 | static int clk_ether_prepare(struct clk_hw *hw) | ||
173 | { | ||
174 | struct hix5hd2_clk_complex *clk = to_complex_clk(hw); | ||
175 | u32 val; | ||
176 | |||
177 | val = readl_relaxed(clk->ctrl_reg); | ||
178 | val |= clk->ctrl_clk_mask | clk->ctrl_rst_mask; | ||
179 | writel_relaxed(val, clk->ctrl_reg); | ||
180 | val &= ~(clk->ctrl_rst_mask); | ||
181 | writel_relaxed(val, clk->ctrl_reg); | ||
182 | |||
183 | val = readl_relaxed(clk->phy_reg); | ||
184 | val |= clk->phy_clk_mask; | ||
185 | val &= ~(clk->phy_rst_mask); | ||
186 | writel_relaxed(val, clk->phy_reg); | ||
187 | mdelay(10); | ||
188 | |||
189 | val &= ~(clk->phy_clk_mask); | ||
190 | val |= clk->phy_rst_mask; | ||
191 | writel_relaxed(val, clk->phy_reg); | ||
192 | mdelay(10); | ||
193 | |||
194 | val |= clk->phy_clk_mask; | ||
195 | val &= ~(clk->phy_rst_mask); | ||
196 | writel_relaxed(val, clk->phy_reg); | ||
197 | mdelay(30); | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static void clk_ether_unprepare(struct clk_hw *hw) | ||
202 | { | ||
203 | struct hix5hd2_clk_complex *clk = to_complex_clk(hw); | ||
204 | u32 val; | ||
205 | |||
206 | val = readl_relaxed(clk->ctrl_reg); | ||
207 | val &= ~(clk->ctrl_clk_mask); | ||
208 | writel_relaxed(val, clk->ctrl_reg); | ||
209 | } | ||
210 | |||
211 | static struct clk_ops clk_ether_ops = { | ||
212 | .prepare = clk_ether_prepare, | ||
213 | .unprepare = clk_ether_unprepare, | ||
214 | }; | ||
215 | |||
216 | static int clk_complex_enable(struct clk_hw *hw) | ||
217 | { | ||
218 | struct hix5hd2_clk_complex *clk = to_complex_clk(hw); | ||
219 | u32 val; | ||
220 | |||
221 | val = readl_relaxed(clk->ctrl_reg); | ||
222 | val |= clk->ctrl_clk_mask; | ||
223 | val &= ~(clk->ctrl_rst_mask); | ||
224 | writel_relaxed(val, clk->ctrl_reg); | ||
225 | |||
226 | val = readl_relaxed(clk->phy_reg); | ||
227 | val |= clk->phy_clk_mask; | ||
228 | val &= ~(clk->phy_rst_mask); | ||
229 | writel_relaxed(val, clk->phy_reg); | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static void clk_complex_disable(struct clk_hw *hw) | ||
235 | { | ||
236 | struct hix5hd2_clk_complex *clk = to_complex_clk(hw); | ||
237 | u32 val; | ||
238 | |||
239 | val = readl_relaxed(clk->ctrl_reg); | ||
240 | val |= clk->ctrl_rst_mask; | ||
241 | val &= ~(clk->ctrl_clk_mask); | ||
242 | writel_relaxed(val, clk->ctrl_reg); | ||
243 | |||
244 | val = readl_relaxed(clk->phy_reg); | ||
245 | val |= clk->phy_rst_mask; | ||
246 | val &= ~(clk->phy_clk_mask); | ||
247 | writel_relaxed(val, clk->phy_reg); | ||
248 | } | ||
249 | |||
250 | static struct clk_ops clk_complex_ops = { | ||
251 | .enable = clk_complex_enable, | ||
252 | .disable = clk_complex_disable, | ||
253 | }; | ||
254 | |||
255 | void __init hix5hd2_clk_register_complex(struct hix5hd2_complex_clock *clks, | ||
256 | int nums, struct hisi_clock_data *data) | ||
257 | { | ||
258 | void __iomem *base = data->base; | ||
259 | int i; | ||
260 | |||
261 | for (i = 0; i < nums; i++) { | ||
262 | struct hix5hd2_clk_complex *p_clk; | ||
263 | struct clk *clk; | ||
264 | struct clk_init_data init; | ||
265 | |||
266 | p_clk = kzalloc(sizeof(*p_clk), GFP_KERNEL); | ||
267 | if (!p_clk) | ||
268 | return; | ||
269 | |||
270 | init.name = clks[i].name; | ||
271 | if (clks[i].type == TYPE_ETHER) | ||
272 | init.ops = &clk_ether_ops; | ||
273 | else | ||
274 | init.ops = &clk_complex_ops; | ||
275 | |||
276 | init.flags = CLK_IS_BASIC; | ||
277 | init.parent_names = | ||
278 | (clks[i].parent_name ? &clks[i].parent_name : NULL); | ||
279 | init.num_parents = (clks[i].parent_name ? 1 : 0); | ||
280 | |||
281 | p_clk->ctrl_reg = base + clks[i].ctrl_reg; | ||
282 | p_clk->ctrl_clk_mask = clks[i].ctrl_clk_mask; | ||
283 | p_clk->ctrl_rst_mask = clks[i].ctrl_rst_mask; | ||
284 | p_clk->phy_reg = base + clks[i].phy_reg; | ||
285 | p_clk->phy_clk_mask = clks[i].phy_clk_mask; | ||
286 | p_clk->phy_rst_mask = clks[i].phy_rst_mask; | ||
287 | p_clk->hw.init = &init; | ||
288 | |||
289 | clk = clk_register(NULL, &p_clk->hw); | ||
290 | if (IS_ERR(clk)) { | ||
291 | kfree(p_clk); | ||
292 | pr_err("%s: failed to register clock %s\n", | ||
293 | __func__, clks[i].name); | ||
294 | continue; | ||
295 | } | ||
296 | |||
297 | data->clk_data.clks[clks[i].id] = clk; | ||
298 | } | ||
299 | } | ||
300 | |||
84 | static void __init hix5hd2_clk_init(struct device_node *np) | 301 | static void __init hix5hd2_clk_init(struct device_node *np) |
85 | { | 302 | { |
86 | struct hisi_clock_data *clk_data; | 303 | struct hisi_clock_data *clk_data; |
@@ -96,6 +313,9 @@ static void __init hix5hd2_clk_init(struct device_node *np) | |||
96 | clk_data); | 313 | clk_data); |
97 | hisi_clk_register_gate(hix5hd2_gate_clks, | 314 | hisi_clk_register_gate(hix5hd2_gate_clks, |
98 | ARRAY_SIZE(hix5hd2_gate_clks), clk_data); | 315 | ARRAY_SIZE(hix5hd2_gate_clks), clk_data); |
316 | hix5hd2_clk_register_complex(hix5hd2_complex_clks, | ||
317 | ARRAY_SIZE(hix5hd2_complex_clks), | ||
318 | clk_data); | ||
99 | } | 319 | } |
100 | 320 | ||
101 | CLK_OF_DECLARE(hix5hd2_clk, "hisilicon,hix5hd2-clock", hix5hd2_clk_init); | 321 | CLK_OF_DECLARE(hix5hd2_clk, "hisilicon,hix5hd2-clock", hix5hd2_clk_init); |
diff --git a/drivers/clk/mvebu/armada-370.c b/drivers/clk/mvebu/armada-370.c index bef198a83863..756f0f39d6a3 100644 --- a/drivers/clk/mvebu/armada-370.c +++ b/drivers/clk/mvebu/armada-370.c | |||
@@ -23,6 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #define SARL 0 /* Low part [0:31] */ | 25 | #define SARL 0 /* Low part [0:31] */ |
26 | #define SARL_A370_SSCG_ENABLE BIT(10) | ||
26 | #define SARL_A370_PCLK_FREQ_OPT 11 | 27 | #define SARL_A370_PCLK_FREQ_OPT 11 |
27 | #define SARL_A370_PCLK_FREQ_OPT_MASK 0xF | 28 | #define SARL_A370_PCLK_FREQ_OPT_MASK 0xF |
28 | #define SARL_A370_FAB_FREQ_OPT 15 | 29 | #define SARL_A370_FAB_FREQ_OPT 15 |
@@ -133,10 +134,17 @@ static void __init a370_get_clk_ratio( | |||
133 | } | 134 | } |
134 | } | 135 | } |
135 | 136 | ||
137 | static bool a370_is_sscg_enabled(void __iomem *sar) | ||
138 | { | ||
139 | return !(readl(sar) & SARL_A370_SSCG_ENABLE); | ||
140 | } | ||
141 | |||
136 | static const struct coreclk_soc_desc a370_coreclks = { | 142 | static const struct coreclk_soc_desc a370_coreclks = { |
137 | .get_tclk_freq = a370_get_tclk_freq, | 143 | .get_tclk_freq = a370_get_tclk_freq, |
138 | .get_cpu_freq = a370_get_cpu_freq, | 144 | .get_cpu_freq = a370_get_cpu_freq, |
139 | .get_clk_ratio = a370_get_clk_ratio, | 145 | .get_clk_ratio = a370_get_clk_ratio, |
146 | .is_sscg_enabled = a370_is_sscg_enabled, | ||
147 | .fix_sscg_deviation = kirkwood_fix_sscg_deviation, | ||
140 | .ratios = a370_coreclk_ratios, | 148 | .ratios = a370_coreclk_ratios, |
141 | .num_ratios = ARRAY_SIZE(a370_coreclk_ratios), | 149 | .num_ratios = ARRAY_SIZE(a370_coreclk_ratios), |
142 | }; | 150 | }; |
diff --git a/drivers/clk/mvebu/armada-375.c b/drivers/clk/mvebu/armada-375.c index c991a4d95e10..c7af2242b796 100644 --- a/drivers/clk/mvebu/armada-375.c +++ b/drivers/clk/mvebu/armada-375.c | |||
@@ -27,14 +27,14 @@ | |||
27 | * all modified at the same time, and not separately as for the Armada | 27 | * all modified at the same time, and not separately as for the Armada |
28 | * 370 or the Armada XP SoCs. | 28 | * 370 or the Armada XP SoCs. |
29 | * | 29 | * |
30 | * SAR0[21:17] : CPU frequency DDR frequency L2 frequency | 30 | * SAR1[21:17] : CPU frequency DDR frequency L2 frequency |
31 | * 6 = 400 MHz 400 MHz 200 MHz | 31 | * 6 = 400 MHz 400 MHz 200 MHz |
32 | * 15 = 600 MHz 600 MHz 300 MHz | 32 | * 15 = 600 MHz 600 MHz 300 MHz |
33 | * 21 = 800 MHz 534 MHz 400 MHz | 33 | * 21 = 800 MHz 534 MHz 400 MHz |
34 | * 25 = 1000 MHz 500 MHz 500 MHz | 34 | * 25 = 1000 MHz 500 MHz 500 MHz |
35 | * others reserved. | 35 | * others reserved. |
36 | * | 36 | * |
37 | * SAR0[22] : TCLK frequency | 37 | * SAR1[22] : TCLK frequency |
38 | * 0 = 166 MHz | 38 | * 0 = 166 MHz |
39 | * 1 = 200 MHz | 39 | * 1 = 200 MHz |
40 | */ | 40 | */ |
diff --git a/drivers/clk/mvebu/clk-cpu.c b/drivers/clk/mvebu/clk-cpu.c index 8ebf757d29e2..3821a88077ea 100644 --- a/drivers/clk/mvebu/clk-cpu.c +++ b/drivers/clk/mvebu/clk-cpu.c | |||
@@ -16,10 +16,19 @@ | |||
16 | #include <linux/io.h> | 16 | #include <linux/io.h> |
17 | #include <linux/of.h> | 17 | #include <linux/of.h> |
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include <linux/mvebu-pmsu.h> | ||
20 | #include <asm/smp_plat.h> | ||
19 | 21 | ||
20 | #define SYS_CTRL_CLK_DIVIDER_CTRL_OFFSET 0x0 | 22 | #define SYS_CTRL_CLK_DIVIDER_CTRL_OFFSET 0x0 |
21 | #define SYS_CTRL_CLK_DIVIDER_VALUE_OFFSET 0xC | 23 | #define SYS_CTRL_CLK_DIVIDER_CTRL_RESET_ALL 0xff |
22 | #define SYS_CTRL_CLK_DIVIDER_MASK 0x3F | 24 | #define SYS_CTRL_CLK_DIVIDER_CTRL_RESET_SHIFT 8 |
25 | #define SYS_CTRL_CLK_DIVIDER_CTRL2_OFFSET 0x8 | ||
26 | #define SYS_CTRL_CLK_DIVIDER_CTRL2_NBCLK_RATIO_SHIFT 16 | ||
27 | #define SYS_CTRL_CLK_DIVIDER_VALUE_OFFSET 0xC | ||
28 | #define SYS_CTRL_CLK_DIVIDER_MASK 0x3F | ||
29 | |||
30 | #define PMU_DFS_RATIO_SHIFT 16 | ||
31 | #define PMU_DFS_RATIO_MASK 0x3F | ||
23 | 32 | ||
24 | #define MAX_CPU 4 | 33 | #define MAX_CPU 4 |
25 | struct cpu_clk { | 34 | struct cpu_clk { |
@@ -28,6 +37,7 @@ struct cpu_clk { | |||
28 | const char *clk_name; | 37 | const char *clk_name; |
29 | const char *parent_name; | 38 | const char *parent_name; |
30 | void __iomem *reg_base; | 39 | void __iomem *reg_base; |
40 | void __iomem *pmu_dfs; | ||
31 | }; | 41 | }; |
32 | 42 | ||
33 | static struct clk **clks; | 43 | static struct clk **clks; |
@@ -62,8 +72,9 @@ static long clk_cpu_round_rate(struct clk_hw *hwclk, unsigned long rate, | |||
62 | return *parent_rate / div; | 72 | return *parent_rate / div; |
63 | } | 73 | } |
64 | 74 | ||
65 | static int clk_cpu_set_rate(struct clk_hw *hwclk, unsigned long rate, | 75 | static int clk_cpu_off_set_rate(struct clk_hw *hwclk, unsigned long rate, |
66 | unsigned long parent_rate) | 76 | unsigned long parent_rate) |
77 | |||
67 | { | 78 | { |
68 | struct cpu_clk *cpuclk = to_cpu_clk(hwclk); | 79 | struct cpu_clk *cpuclk = to_cpu_clk(hwclk); |
69 | u32 reg, div; | 80 | u32 reg, div; |
@@ -95,6 +106,58 @@ static int clk_cpu_set_rate(struct clk_hw *hwclk, unsigned long rate, | |||
95 | return 0; | 106 | return 0; |
96 | } | 107 | } |
97 | 108 | ||
109 | static int clk_cpu_on_set_rate(struct clk_hw *hwclk, unsigned long rate, | ||
110 | unsigned long parent_rate) | ||
111 | { | ||
112 | u32 reg; | ||
113 | unsigned long fabric_div, target_div, cur_rate; | ||
114 | struct cpu_clk *cpuclk = to_cpu_clk(hwclk); | ||
115 | |||
116 | /* | ||
117 | * PMU DFS registers are not mapped, Device Tree does not | ||
118 | * describes them. We cannot change the frequency dynamically. | ||
119 | */ | ||
120 | if (!cpuclk->pmu_dfs) | ||
121 | return -ENODEV; | ||
122 | |||
123 | cur_rate = __clk_get_rate(hwclk->clk); | ||
124 | |||
125 | reg = readl(cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_CTRL2_OFFSET); | ||
126 | fabric_div = (reg >> SYS_CTRL_CLK_DIVIDER_CTRL2_NBCLK_RATIO_SHIFT) & | ||
127 | SYS_CTRL_CLK_DIVIDER_MASK; | ||
128 | |||
129 | /* Frequency is going up */ | ||
130 | if (rate == 2 * cur_rate) | ||
131 | target_div = fabric_div / 2; | ||
132 | /* Frequency is going down */ | ||
133 | else | ||
134 | target_div = fabric_div; | ||
135 | |||
136 | if (target_div == 0) | ||
137 | target_div = 1; | ||
138 | |||
139 | reg = readl(cpuclk->pmu_dfs); | ||
140 | reg &= ~(PMU_DFS_RATIO_MASK << PMU_DFS_RATIO_SHIFT); | ||
141 | reg |= (target_div << PMU_DFS_RATIO_SHIFT); | ||
142 | writel(reg, cpuclk->pmu_dfs); | ||
143 | |||
144 | reg = readl(cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_CTRL_OFFSET); | ||
145 | reg |= (SYS_CTRL_CLK_DIVIDER_CTRL_RESET_ALL << | ||
146 | SYS_CTRL_CLK_DIVIDER_CTRL_RESET_SHIFT); | ||
147 | writel(reg, cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_CTRL_OFFSET); | ||
148 | |||
149 | return mvebu_pmsu_dfs_request(cpuclk->cpu); | ||
150 | } | ||
151 | |||
152 | static int clk_cpu_set_rate(struct clk_hw *hwclk, unsigned long rate, | ||
153 | unsigned long parent_rate) | ||
154 | { | ||
155 | if (__clk_is_enabled(hwclk->clk)) | ||
156 | return clk_cpu_on_set_rate(hwclk, rate, parent_rate); | ||
157 | else | ||
158 | return clk_cpu_off_set_rate(hwclk, rate, parent_rate); | ||
159 | } | ||
160 | |||
98 | static const struct clk_ops cpu_ops = { | 161 | static const struct clk_ops cpu_ops = { |
99 | .recalc_rate = clk_cpu_recalc_rate, | 162 | .recalc_rate = clk_cpu_recalc_rate, |
100 | .round_rate = clk_cpu_round_rate, | 163 | .round_rate = clk_cpu_round_rate, |
@@ -105,6 +168,7 @@ static void __init of_cpu_clk_setup(struct device_node *node) | |||
105 | { | 168 | { |
106 | struct cpu_clk *cpuclk; | 169 | struct cpu_clk *cpuclk; |
107 | void __iomem *clock_complex_base = of_iomap(node, 0); | 170 | void __iomem *clock_complex_base = of_iomap(node, 0); |
171 | void __iomem *pmu_dfs_base = of_iomap(node, 1); | ||
108 | int ncpus = 0; | 172 | int ncpus = 0; |
109 | struct device_node *dn; | 173 | struct device_node *dn; |
110 | 174 | ||
@@ -114,6 +178,10 @@ static void __init of_cpu_clk_setup(struct device_node *node) | |||
114 | return; | 178 | return; |
115 | } | 179 | } |
116 | 180 | ||
181 | if (pmu_dfs_base == NULL) | ||
182 | pr_warn("%s: pmu-dfs base register not set, dynamic frequency scaling not available\n", | ||
183 | __func__); | ||
184 | |||
117 | for_each_node_by_type(dn, "cpu") | 185 | for_each_node_by_type(dn, "cpu") |
118 | ncpus++; | 186 | ncpus++; |
119 | 187 | ||
@@ -146,6 +214,8 @@ static void __init of_cpu_clk_setup(struct device_node *node) | |||
146 | cpuclk[cpu].clk_name = clk_name; | 214 | cpuclk[cpu].clk_name = clk_name; |
147 | cpuclk[cpu].cpu = cpu; | 215 | cpuclk[cpu].cpu = cpu; |
148 | cpuclk[cpu].reg_base = clock_complex_base; | 216 | cpuclk[cpu].reg_base = clock_complex_base; |
217 | if (pmu_dfs_base) | ||
218 | cpuclk[cpu].pmu_dfs = pmu_dfs_base + 4 * cpu; | ||
149 | cpuclk[cpu].hw.init = &init; | 219 | cpuclk[cpu].hw.init = &init; |
150 | 220 | ||
151 | init.name = cpuclk[cpu].clk_name; | 221 | init.name = cpuclk[cpu].clk_name; |
diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c index 25ceccf939ad..b7fcb469c87a 100644 --- a/drivers/clk/mvebu/common.c +++ b/drivers/clk/mvebu/common.c | |||
@@ -26,8 +26,85 @@ | |||
26 | * Core Clocks | 26 | * Core Clocks |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #define SSCG_CONF_MODE(reg) (((reg) >> 16) & 0x3) | ||
30 | #define SSCG_SPREAD_DOWN 0x0 | ||
31 | #define SSCG_SPREAD_UP 0x1 | ||
32 | #define SSCG_SPREAD_CENTRAL 0x2 | ||
33 | #define SSCG_CONF_LOW(reg) (((reg) >> 8) & 0xFF) | ||
34 | #define SSCG_CONF_HIGH(reg) ((reg) & 0xFF) | ||
35 | |||
29 | static struct clk_onecell_data clk_data; | 36 | static struct clk_onecell_data clk_data; |
30 | 37 | ||
38 | /* | ||
39 | * This function can be used by the Kirkwood, the Armada 370, the | ||
40 | * Armada XP and the Armada 375 SoC. The name of the function was | ||
41 | * chosen following the dt convention: using the first known SoC | ||
42 | * compatible with it. | ||
43 | */ | ||
44 | u32 kirkwood_fix_sscg_deviation(u32 system_clk) | ||
45 | { | ||
46 | struct device_node *sscg_np = NULL; | ||
47 | void __iomem *sscg_map; | ||
48 | u32 sscg_reg; | ||
49 | s32 low_bound, high_bound; | ||
50 | u64 freq_swing_half; | ||
51 | |||
52 | sscg_np = of_find_node_by_name(NULL, "sscg"); | ||
53 | if (sscg_np == NULL) { | ||
54 | pr_err("cannot get SSCG register node\n"); | ||
55 | return system_clk; | ||
56 | } | ||
57 | |||
58 | sscg_map = of_iomap(sscg_np, 0); | ||
59 | if (sscg_map == NULL) { | ||
60 | pr_err("cannot map SSCG register\n"); | ||
61 | goto out; | ||
62 | } | ||
63 | |||
64 | sscg_reg = readl(sscg_map); | ||
65 | high_bound = SSCG_CONF_HIGH(sscg_reg); | ||
66 | low_bound = SSCG_CONF_LOW(sscg_reg); | ||
67 | |||
68 | if ((high_bound - low_bound) <= 0) | ||
69 | goto out; | ||
70 | /* | ||
71 | * From Marvell engineer we got the following formula (when | ||
72 | * this code was written, the datasheet was erroneous) | ||
73 | * Spread percentage = 1/96 * (H - L) / H | ||
74 | * H = SSCG_High_Boundary | ||
75 | * L = SSCG_Low_Boundary | ||
76 | * | ||
77 | * As the deviation is half of spread then it lead to the | ||
78 | * following formula in the code. | ||
79 | * | ||
80 | * To avoid an overflow and not lose any significant digit in | ||
81 | * the same time we have to use a 64 bit integer. | ||
82 | */ | ||
83 | |||
84 | freq_swing_half = (((u64)high_bound - (u64)low_bound) | ||
85 | * (u64)system_clk); | ||
86 | do_div(freq_swing_half, (2 * 96 * high_bound)); | ||
87 | |||
88 | switch (SSCG_CONF_MODE(sscg_reg)) { | ||
89 | case SSCG_SPREAD_DOWN: | ||
90 | system_clk -= freq_swing_half; | ||
91 | break; | ||
92 | case SSCG_SPREAD_UP: | ||
93 | system_clk += freq_swing_half; | ||
94 | break; | ||
95 | case SSCG_SPREAD_CENTRAL: | ||
96 | default: | ||
97 | break; | ||
98 | } | ||
99 | |||
100 | iounmap(sscg_map); | ||
101 | |||
102 | out: | ||
103 | of_node_put(sscg_np); | ||
104 | |||
105 | return system_clk; | ||
106 | } | ||
107 | |||
31 | void __init mvebu_coreclk_setup(struct device_node *np, | 108 | void __init mvebu_coreclk_setup(struct device_node *np, |
32 | const struct coreclk_soc_desc *desc) | 109 | const struct coreclk_soc_desc *desc) |
33 | { | 110 | { |
@@ -62,6 +139,11 @@ void __init mvebu_coreclk_setup(struct device_node *np, | |||
62 | of_property_read_string_index(np, "clock-output-names", 1, | 139 | of_property_read_string_index(np, "clock-output-names", 1, |
63 | &cpuclk_name); | 140 | &cpuclk_name); |
64 | rate = desc->get_cpu_freq(base); | 141 | rate = desc->get_cpu_freq(base); |
142 | |||
143 | if (desc->is_sscg_enabled && desc->fix_sscg_deviation | ||
144 | && desc->is_sscg_enabled(base)) | ||
145 | rate = desc->fix_sscg_deviation(rate); | ||
146 | |||
65 | clk_data.clks[1] = clk_register_fixed_rate(NULL, cpuclk_name, NULL, | 147 | clk_data.clks[1] = clk_register_fixed_rate(NULL, cpuclk_name, NULL, |
66 | CLK_IS_ROOT, rate); | 148 | CLK_IS_ROOT, rate); |
67 | WARN_ON(IS_ERR(clk_data.clks[1])); | 149 | WARN_ON(IS_ERR(clk_data.clks[1])); |
@@ -89,8 +171,10 @@ void __init mvebu_coreclk_setup(struct device_node *np, | |||
89 | * Clock Gating Control | 171 | * Clock Gating Control |
90 | */ | 172 | */ |
91 | 173 | ||
174 | DEFINE_SPINLOCK(ctrl_gating_lock); | ||
175 | |||
92 | struct clk_gating_ctrl { | 176 | struct clk_gating_ctrl { |
93 | spinlock_t lock; | 177 | spinlock_t *lock; |
94 | struct clk **gates; | 178 | struct clk **gates; |
95 | int num_gates; | 179 | int num_gates; |
96 | }; | 180 | }; |
@@ -138,7 +222,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np, | |||
138 | if (WARN_ON(!ctrl)) | 222 | if (WARN_ON(!ctrl)) |
139 | goto ctrl_out; | 223 | goto ctrl_out; |
140 | 224 | ||
141 | spin_lock_init(&ctrl->lock); | 225 | /* lock must already be initialized */ |
226 | ctrl->lock = &ctrl_gating_lock; | ||
142 | 227 | ||
143 | /* Count, allocate, and register clock gates */ | 228 | /* Count, allocate, and register clock gates */ |
144 | for (n = 0; desc[n].name;) | 229 | for (n = 0; desc[n].name;) |
@@ -155,7 +240,7 @@ void __init mvebu_clk_gating_setup(struct device_node *np, | |||
155 | (desc[n].parent) ? desc[n].parent : default_parent; | 240 | (desc[n].parent) ? desc[n].parent : default_parent; |
156 | ctrl->gates[n] = clk_register_gate(NULL, desc[n].name, parent, | 241 | ctrl->gates[n] = clk_register_gate(NULL, desc[n].name, parent, |
157 | desc[n].flags, base, desc[n].bit_idx, | 242 | desc[n].flags, base, desc[n].bit_idx, |
158 | 0, &ctrl->lock); | 243 | 0, ctrl->lock); |
159 | WARN_ON(IS_ERR(ctrl->gates[n])); | 244 | WARN_ON(IS_ERR(ctrl->gates[n])); |
160 | } | 245 | } |
161 | 246 | ||
diff --git a/drivers/clk/mvebu/common.h b/drivers/clk/mvebu/common.h index f968b4d9df92..783b5631a453 100644 --- a/drivers/clk/mvebu/common.h +++ b/drivers/clk/mvebu/common.h | |||
@@ -17,6 +17,8 @@ | |||
17 | 17 | ||
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | 19 | ||
20 | extern spinlock_t ctrl_gating_lock; | ||
21 | |||
20 | struct device_node; | 22 | struct device_node; |
21 | 23 | ||
22 | struct coreclk_ratio { | 24 | struct coreclk_ratio { |
@@ -28,6 +30,8 @@ struct coreclk_soc_desc { | |||
28 | u32 (*get_tclk_freq)(void __iomem *sar); | 30 | u32 (*get_tclk_freq)(void __iomem *sar); |
29 | u32 (*get_cpu_freq)(void __iomem *sar); | 31 | u32 (*get_cpu_freq)(void __iomem *sar); |
30 | void (*get_clk_ratio)(void __iomem *sar, int id, int *mult, int *div); | 32 | void (*get_clk_ratio)(void __iomem *sar, int id, int *mult, int *div); |
33 | bool (*is_sscg_enabled)(void __iomem *sar); | ||
34 | u32 (*fix_sscg_deviation)(u32 system_clk); | ||
31 | const struct coreclk_ratio *ratios; | 35 | const struct coreclk_ratio *ratios; |
32 | int num_ratios; | 36 | int num_ratios; |
33 | }; | 37 | }; |
@@ -45,4 +49,9 @@ void __init mvebu_coreclk_setup(struct device_node *np, | |||
45 | void __init mvebu_clk_gating_setup(struct device_node *np, | 49 | void __init mvebu_clk_gating_setup(struct device_node *np, |
46 | const struct clk_gating_soc_desc *desc); | 50 | const struct clk_gating_soc_desc *desc); |
47 | 51 | ||
52 | /* | ||
53 | * This function is shared among the Kirkwood, Armada 370, Armada XP | ||
54 | * and Armada 375 SoC | ||
55 | */ | ||
56 | u32 kirkwood_fix_sscg_deviation(u32 system_clk); | ||
48 | #endif | 57 | #endif |
diff --git a/drivers/clk/mvebu/kirkwood.c b/drivers/clk/mvebu/kirkwood.c index ddb666a86500..99550f25975e 100644 --- a/drivers/clk/mvebu/kirkwood.c +++ b/drivers/clk/mvebu/kirkwood.c | |||
@@ -13,9 +13,11 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/slab.h> | ||
16 | #include <linux/clk-provider.h> | 17 | #include <linux/clk-provider.h> |
17 | #include <linux/io.h> | 18 | #include <linux/io.h> |
18 | #include <linux/of.h> | 19 | #include <linux/of.h> |
20 | #include <linux/of_address.h> | ||
19 | #include "common.h" | 21 | #include "common.h" |
20 | 22 | ||
21 | /* | 23 | /* |
@@ -214,7 +216,6 @@ static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = { | |||
214 | { "runit", NULL, 7, 0 }, | 216 | { "runit", NULL, 7, 0 }, |
215 | { "xor0", NULL, 8, 0 }, | 217 | { "xor0", NULL, 8, 0 }, |
216 | { "audio", NULL, 9, 0 }, | 218 | { "audio", NULL, 9, 0 }, |
217 | { "powersave", "cpuclk", 11, 0 }, | ||
218 | { "sata0", NULL, 14, 0 }, | 219 | { "sata0", NULL, 14, 0 }, |
219 | { "sata1", NULL, 15, 0 }, | 220 | { "sata1", NULL, 15, 0 }, |
220 | { "xor1", NULL, 16, 0 }, | 221 | { "xor1", NULL, 16, 0 }, |
@@ -225,6 +226,101 @@ static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = { | |||
225 | { } | 226 | { } |
226 | }; | 227 | }; |
227 | 228 | ||
229 | |||
230 | /* | ||
231 | * Clock Muxing Control | ||
232 | */ | ||
233 | |||
234 | struct clk_muxing_soc_desc { | ||
235 | const char *name; | ||
236 | const char **parents; | ||
237 | int num_parents; | ||
238 | int shift; | ||
239 | int width; | ||
240 | unsigned long flags; | ||
241 | }; | ||
242 | |||
243 | struct clk_muxing_ctrl { | ||
244 | spinlock_t *lock; | ||
245 | struct clk **muxes; | ||
246 | int num_muxes; | ||
247 | }; | ||
248 | |||
249 | static const char *powersave_parents[] = { | ||
250 | "cpuclk", | ||
251 | "ddrclk", | ||
252 | }; | ||
253 | |||
254 | static const struct clk_muxing_soc_desc kirkwood_mux_desc[] __initconst = { | ||
255 | { "powersave", powersave_parents, ARRAY_SIZE(powersave_parents), | ||
256 | 11, 1, 0 }, | ||
257 | }; | ||
258 | |||
259 | #define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw) | ||
260 | |||
261 | static struct clk *clk_muxing_get_src( | ||
262 | struct of_phandle_args *clkspec, void *data) | ||
263 | { | ||
264 | struct clk_muxing_ctrl *ctrl = (struct clk_muxing_ctrl *)data; | ||
265 | int n; | ||
266 | |||
267 | if (clkspec->args_count < 1) | ||
268 | return ERR_PTR(-EINVAL); | ||
269 | |||
270 | for (n = 0; n < ctrl->num_muxes; n++) { | ||
271 | struct clk_mux *mux = | ||
272 | to_clk_mux(__clk_get_hw(ctrl->muxes[n])); | ||
273 | if (clkspec->args[0] == mux->shift) | ||
274 | return ctrl->muxes[n]; | ||
275 | } | ||
276 | return ERR_PTR(-ENODEV); | ||
277 | } | ||
278 | |||
279 | static void __init kirkwood_clk_muxing_setup(struct device_node *np, | ||
280 | const struct clk_muxing_soc_desc *desc) | ||
281 | { | ||
282 | struct clk_muxing_ctrl *ctrl; | ||
283 | void __iomem *base; | ||
284 | int n; | ||
285 | |||
286 | base = of_iomap(np, 0); | ||
287 | if (WARN_ON(!base)) | ||
288 | return; | ||
289 | |||
290 | ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); | ||
291 | if (WARN_ON(!ctrl)) | ||
292 | goto ctrl_out; | ||
293 | |||
294 | /* lock must already be initialized */ | ||
295 | ctrl->lock = &ctrl_gating_lock; | ||
296 | |||
297 | /* Count, allocate, and register clock muxes */ | ||
298 | for (n = 0; desc[n].name;) | ||
299 | n++; | ||
300 | |||
301 | ctrl->num_muxes = n; | ||
302 | ctrl->muxes = kcalloc(ctrl->num_muxes, sizeof(struct clk *), | ||
303 | GFP_KERNEL); | ||
304 | if (WARN_ON(!ctrl->muxes)) | ||
305 | goto muxes_out; | ||
306 | |||
307 | for (n = 0; n < ctrl->num_muxes; n++) { | ||
308 | ctrl->muxes[n] = clk_register_mux(NULL, desc[n].name, | ||
309 | desc[n].parents, desc[n].num_parents, | ||
310 | desc[n].flags, base, desc[n].shift, | ||
311 | desc[n].width, desc[n].flags, ctrl->lock); | ||
312 | WARN_ON(IS_ERR(ctrl->muxes[n])); | ||
313 | } | ||
314 | |||
315 | of_clk_add_provider(np, clk_muxing_get_src, ctrl); | ||
316 | |||
317 | return; | ||
318 | muxes_out: | ||
319 | kfree(ctrl); | ||
320 | ctrl_out: | ||
321 | iounmap(base); | ||
322 | } | ||
323 | |||
228 | static void __init kirkwood_clk_init(struct device_node *np) | 324 | static void __init kirkwood_clk_init(struct device_node *np) |
229 | { | 325 | { |
230 | struct device_node *cgnp = | 326 | struct device_node *cgnp = |
@@ -236,8 +332,10 @@ static void __init kirkwood_clk_init(struct device_node *np) | |||
236 | else | 332 | else |
237 | mvebu_coreclk_setup(np, &kirkwood_coreclks); | 333 | mvebu_coreclk_setup(np, &kirkwood_coreclks); |
238 | 334 | ||
239 | if (cgnp) | 335 | if (cgnp) { |
240 | mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc); | 336 | mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc); |
337 | kirkwood_clk_muxing_setup(cgnp, kirkwood_mux_desc); | ||
338 | } | ||
241 | } | 339 | } |
242 | CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock", | 340 | CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock", |
243 | kirkwood_clk_init); | 341 | kirkwood_clk_init); |
diff --git a/drivers/clk/pxa/Makefile b/drivers/clk/pxa/Makefile new file mode 100644 index 000000000000..4ff2abcd500b --- /dev/null +++ b/drivers/clk/pxa/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | obj-y += clk-pxa.o | ||
2 | obj-$(CONFIG_PXA27x) += clk-pxa27x.o | ||
diff --git a/drivers/clk/pxa/clk-pxa.c b/drivers/clk/pxa/clk-pxa.c new file mode 100644 index 000000000000..ef3c05389c0a --- /dev/null +++ b/drivers/clk/pxa/clk-pxa.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * Marvell PXA family clocks | ||
3 | * | ||
4 | * Copyright (C) 2014 Robert Jarzmik | ||
5 | * | ||
6 | * Common clock code for PXA clocks ("CKEN" type clocks + DT) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; version 2 of the License. | ||
11 | * | ||
12 | */ | ||
13 | #include <linux/clk.h> | ||
14 | #include <linux/clk-provider.h> | ||
15 | #include <linux/clkdev.h> | ||
16 | #include <linux/of.h> | ||
17 | |||
18 | #include <dt-bindings/clock/pxa-clock.h> | ||
19 | #include "clk-pxa.h" | ||
20 | |||
21 | DEFINE_SPINLOCK(lock); | ||
22 | |||
23 | static struct clk *pxa_clocks[CLK_MAX]; | ||
24 | static struct clk_onecell_data onecell_data = { | ||
25 | .clks = pxa_clocks, | ||
26 | .clk_num = CLK_MAX, | ||
27 | }; | ||
28 | |||
29 | #define to_pxa_clk(_hw) container_of(_hw, struct pxa_clk_cken, hw) | ||
30 | |||
31 | static unsigned long cken_recalc_rate(struct clk_hw *hw, | ||
32 | unsigned long parent_rate) | ||
33 | { | ||
34 | struct pxa_clk_cken *pclk = to_pxa_clk(hw); | ||
35 | struct clk_fixed_factor *fix; | ||
36 | |||
37 | if (!pclk->is_in_low_power || pclk->is_in_low_power()) | ||
38 | fix = &pclk->lp; | ||
39 | else | ||
40 | fix = &pclk->hp; | ||
41 | fix->hw.clk = hw->clk; | ||
42 | return clk_fixed_factor_ops.recalc_rate(&fix->hw, parent_rate); | ||
43 | } | ||
44 | |||
45 | static struct clk_ops cken_rate_ops = { | ||
46 | .recalc_rate = cken_recalc_rate, | ||
47 | }; | ||
48 | |||
49 | static u8 cken_get_parent(struct clk_hw *hw) | ||
50 | { | ||
51 | struct pxa_clk_cken *pclk = to_pxa_clk(hw); | ||
52 | |||
53 | if (!pclk->is_in_low_power) | ||
54 | return 0; | ||
55 | return pclk->is_in_low_power() ? 0 : 1; | ||
56 | } | ||
57 | |||
58 | static struct clk_ops cken_mux_ops = { | ||
59 | .get_parent = cken_get_parent, | ||
60 | .set_parent = dummy_clk_set_parent, | ||
61 | }; | ||
62 | |||
63 | void __init clkdev_pxa_register(int ckid, const char *con_id, | ||
64 | const char *dev_id, struct clk *clk) | ||
65 | { | ||
66 | if (!IS_ERR(clk) && (ckid != CLK_NONE)) | ||
67 | pxa_clocks[ckid] = clk; | ||
68 | if (!IS_ERR(clk)) | ||
69 | clk_register_clkdev(clk, con_id, dev_id); | ||
70 | } | ||
71 | |||
72 | int __init clk_pxa_cken_init(struct pxa_clk_cken *clks, int nb_clks) | ||
73 | { | ||
74 | int i; | ||
75 | struct pxa_clk_cken *pclk; | ||
76 | struct clk *clk; | ||
77 | |||
78 | for (i = 0; i < nb_clks; i++) { | ||
79 | pclk = clks + i; | ||
80 | pclk->gate.lock = &lock; | ||
81 | clk = clk_register_composite(NULL, pclk->name, | ||
82 | pclk->parent_names, 2, | ||
83 | &pclk->hw, &cken_mux_ops, | ||
84 | &pclk->hw, &cken_rate_ops, | ||
85 | &pclk->gate.hw, &clk_gate_ops, | ||
86 | pclk->flags); | ||
87 | clkdev_pxa_register(pclk->ckid, pclk->con_id, pclk->dev_id, | ||
88 | clk); | ||
89 | } | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static void __init pxa_dt_clocks_init(struct device_node *np) | ||
94 | { | ||
95 | of_clk_add_provider(np, of_clk_src_onecell_get, &onecell_data); | ||
96 | } | ||
97 | CLK_OF_DECLARE(pxa_clks, "marvell,pxa-clocks", pxa_dt_clocks_init); | ||
diff --git a/drivers/clk/pxa/clk-pxa.h b/drivers/clk/pxa/clk-pxa.h new file mode 100644 index 000000000000..5fe219d06b49 --- /dev/null +++ b/drivers/clk/pxa/clk-pxa.h | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * Marvell PXA family clocks | ||
3 | * | ||
4 | * Copyright (C) 2014 Robert Jarzmik | ||
5 | * | ||
6 | * Common clock code for PXA clocks ("CKEN" type clocks + DT) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; version 2 of the License. | ||
11 | * | ||
12 | */ | ||
13 | #ifndef _CLK_PXA_ | ||
14 | #define _CLK_PXA_ | ||
15 | |||
16 | #define PARENTS(name) \ | ||
17 | static const char *name ## _parents[] __initconst | ||
18 | #define MUX_RO_RATE_RO_OPS(name, clk_name) \ | ||
19 | static struct clk_hw name ## _mux_hw; \ | ||
20 | static struct clk_hw name ## _rate_hw; \ | ||
21 | static struct clk_ops name ## _mux_ops = { \ | ||
22 | .get_parent = name ## _get_parent, \ | ||
23 | .set_parent = dummy_clk_set_parent, \ | ||
24 | }; \ | ||
25 | static struct clk_ops name ## _rate_ops = { \ | ||
26 | .recalc_rate = name ## _get_rate, \ | ||
27 | }; \ | ||
28 | static struct clk *clk_register_ ## name(void) \ | ||
29 | { \ | ||
30 | return clk_register_composite(NULL, clk_name, \ | ||
31 | name ## _parents, \ | ||
32 | ARRAY_SIZE(name ## _parents), \ | ||
33 | &name ## _mux_hw, &name ## _mux_ops, \ | ||
34 | &name ## _rate_hw, &name ## _rate_ops, \ | ||
35 | NULL, NULL, CLK_GET_RATE_NOCACHE); \ | ||
36 | } | ||
37 | |||
38 | #define RATE_RO_OPS(name, clk_name) \ | ||
39 | static struct clk_hw name ## _rate_hw; \ | ||
40 | static struct clk_ops name ## _rate_ops = { \ | ||
41 | .recalc_rate = name ## _get_rate, \ | ||
42 | }; \ | ||
43 | static struct clk *clk_register_ ## name(void) \ | ||
44 | { \ | ||
45 | return clk_register_composite(NULL, clk_name, \ | ||
46 | name ## _parents, \ | ||
47 | ARRAY_SIZE(name ## _parents), \ | ||
48 | NULL, NULL, \ | ||
49 | &name ## _rate_hw, &name ## _rate_ops, \ | ||
50 | NULL, NULL, CLK_GET_RATE_NOCACHE); \ | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | * CKEN clock type | ||
55 | * This clock takes it source from 2 possible parents : | ||
56 | * - a low power parent | ||
57 | * - a normal parent | ||
58 | * | ||
59 | * +------------+ +-----------+ | ||
60 | * | Low Power | --- | x mult_lp | | ||
61 | * | Clock | | / div_lp |\ | ||
62 | * +------------+ +-----------+ \+-----+ +-----------+ | ||
63 | * | Mux |---| CKEN gate | | ||
64 | * +------------+ +-----------+ /+-----+ +-----------+ | ||
65 | * | High Power | | x mult_hp |/ | ||
66 | * | Clock | --- | / div_hp | | ||
67 | * +------------+ +-----------+ | ||
68 | */ | ||
69 | struct pxa_clk_cken { | ||
70 | struct clk_hw hw; | ||
71 | int ckid; | ||
72 | const char *name; | ||
73 | const char *dev_id; | ||
74 | const char *con_id; | ||
75 | const char **parent_names; | ||
76 | struct clk_fixed_factor lp; | ||
77 | struct clk_fixed_factor hp; | ||
78 | struct clk_gate gate; | ||
79 | bool (*is_in_low_power)(void); | ||
80 | const unsigned long flags; | ||
81 | }; | ||
82 | |||
83 | #define PXA_CKEN(_dev_id, _con_id, _name, parents, _mult_lp, _div_lp, \ | ||
84 | _mult_hp, _div_hp, is_lp, _cken_reg, _cken_bit, flag) \ | ||
85 | { .ckid = CLK_ ## _name, .name = #_name, \ | ||
86 | .dev_id = _dev_id, .con_id = _con_id, .parent_names = parents,\ | ||
87 | .lp = { .mult = _mult_lp, .div = _div_lp }, \ | ||
88 | .hp = { .mult = _mult_hp, .div = _div_hp }, \ | ||
89 | .is_in_low_power = is_lp, \ | ||
90 | .gate = { .reg = (void __iomem *)_cken_reg, .bit_idx = _cken_bit }, \ | ||
91 | .flags = flag, \ | ||
92 | } | ||
93 | #define PXA_CKEN_1RATE(dev_id, con_id, name, parents, cken_reg, \ | ||
94 | cken_bit, flag) \ | ||
95 | PXA_CKEN(dev_id, con_id, name, parents, 1, 1, 1, 1, \ | ||
96 | NULL, cken_reg, cken_bit, flag) | ||
97 | |||
98 | static int dummy_clk_set_parent(struct clk_hw *hw, u8 index) | ||
99 | { | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | extern void clkdev_pxa_register(int ckid, const char *con_id, | ||
104 | const char *dev_id, struct clk *clk); | ||
105 | extern int clk_pxa_cken_init(struct pxa_clk_cken *clks, int nb_clks); | ||
106 | |||
107 | #endif | ||
diff --git a/drivers/clk/pxa/clk-pxa27x.c b/drivers/clk/pxa/clk-pxa27x.c new file mode 100644 index 000000000000..b345cc791e5d --- /dev/null +++ b/drivers/clk/pxa/clk-pxa27x.c | |||
@@ -0,0 +1,370 @@ | |||
1 | /* | ||
2 | * Marvell PXA27x family clocks | ||
3 | * | ||
4 | * Copyright (C) 2014 Robert Jarzmik | ||
5 | * | ||
6 | * Heavily inspired from former arch/arm/mach-pxa/clock.c. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; version 2 of the License. | ||
11 | * | ||
12 | */ | ||
13 | #include <linux/clk-provider.h> | ||
14 | #include <mach/pxa2xx-regs.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/clk.h> | ||
17 | #include <linux/clkdev.h> | ||
18 | #include <linux/of.h> | ||
19 | |||
20 | #include <dt-bindings/clock/pxa-clock.h> | ||
21 | #include "clk-pxa.h" | ||
22 | |||
23 | #define KHz 1000 | ||
24 | #define MHz (1000 * 1000) | ||
25 | |||
26 | enum { | ||
27 | PXA_CORE_13Mhz = 0, | ||
28 | PXA_CORE_RUN, | ||
29 | PXA_CORE_TURBO, | ||
30 | }; | ||
31 | |||
32 | enum { | ||
33 | PXA_BUS_13Mhz = 0, | ||
34 | PXA_BUS_RUN, | ||
35 | }; | ||
36 | |||
37 | enum { | ||
38 | PXA_LCD_13Mhz = 0, | ||
39 | PXA_LCD_RUN, | ||
40 | }; | ||
41 | |||
42 | enum { | ||
43 | PXA_MEM_13Mhz = 0, | ||
44 | PXA_MEM_SYSTEM_BUS, | ||
45 | PXA_MEM_RUN, | ||
46 | }; | ||
47 | |||
48 | static const char * const get_freq_khz[] = { | ||
49 | "core", "run", "cpll", "memory", | ||
50 | "system_bus" | ||
51 | }; | ||
52 | |||
53 | /* | ||
54 | * Get the clock frequency as reflected by CCSR and the turbo flag. | ||
55 | * We assume these values have been applied via a fcs. | ||
56 | * If info is not 0 we also display the current settings. | ||
57 | */ | ||
58 | unsigned int pxa27x_get_clk_frequency_khz(int info) | ||
59 | { | ||
60 | struct clk *clk; | ||
61 | unsigned long clks[5]; | ||
62 | int i; | ||
63 | |||
64 | for (i = 0; i < 5; i++) { | ||
65 | clk = clk_get(NULL, get_freq_khz[i]); | ||
66 | if (IS_ERR(clk)) { | ||
67 | clks[i] = 0; | ||
68 | } else { | ||
69 | clks[i] = clk_get_rate(clk); | ||
70 | clk_put(clk); | ||
71 | } | ||
72 | } | ||
73 | if (info) { | ||
74 | pr_info("Run Mode clock: %ld.%02ldMHz\n", | ||
75 | clks[1] / 1000000, (clks[1] % 1000000) / 10000); | ||
76 | pr_info("Turbo Mode clock: %ld.%02ldMHz\n", | ||
77 | clks[2] / 1000000, (clks[2] % 1000000) / 10000); | ||
78 | pr_info("Memory clock: %ld.%02ldMHz\n", | ||
79 | clks[3] / 1000000, (clks[3] % 1000000) / 10000); | ||
80 | pr_info("System bus clock: %ld.%02ldMHz\n", | ||
81 | clks[4] / 1000000, (clks[4] % 1000000) / 10000); | ||
82 | } | ||
83 | return (unsigned int)clks[0]; | ||
84 | } | ||
85 | |||
86 | bool pxa27x_is_ppll_disabled(void) | ||
87 | { | ||
88 | unsigned long ccsr = CCSR; | ||
89 | |||
90 | return ccsr & (1 << CCCR_PPDIS_BIT); | ||
91 | } | ||
92 | |||
93 | #define PXA27X_CKEN(dev_id, con_id, parents, mult_hp, div_hp, \ | ||
94 | bit, is_lp, flags) \ | ||
95 | PXA_CKEN(dev_id, con_id, bit, parents, 1, 1, mult_hp, div_hp, \ | ||
96 | is_lp, &CKEN, CKEN_ ## bit, flags) | ||
97 | #define PXA27X_PBUS_CKEN(dev_id, con_id, bit, mult_hp, div_hp, delay) \ | ||
98 | PXA27X_CKEN(dev_id, con_id, pxa27x_pbus_parents, mult_hp, \ | ||
99 | div_hp, bit, pxa27x_is_ppll_disabled, 0) | ||
100 | |||
101 | PARENTS(pxa27x_pbus) = { "osc_13mhz", "ppll_312mhz" }; | ||
102 | PARENTS(pxa27x_sbus) = { "system_bus", "system_bus" }; | ||
103 | PARENTS(pxa27x_32Mhz_bus) = { "osc_32_768khz", "osc_32_768khz" }; | ||
104 | PARENTS(pxa27x_lcd_bus) = { "lcd_base", "lcd_base" }; | ||
105 | PARENTS(pxa27x_membus) = { "lcd_base", "lcd_base" }; | ||
106 | |||
107 | #define PXA27X_CKEN_1RATE(dev_id, con_id, bit, parents, delay) \ | ||
108 | PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \ | ||
109 | &CKEN, CKEN_ ## bit, 0) | ||
110 | #define PXA27X_CKEN_1RATE_AO(dev_id, con_id, bit, parents, delay) \ | ||
111 | PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \ | ||
112 | &CKEN, CKEN_ ## bit, CLK_IGNORE_UNUSED) | ||
113 | |||
114 | static struct pxa_clk_cken pxa27x_clocks[] = { | ||
115 | PXA27X_PBUS_CKEN("pxa2xx-uart.0", NULL, FFUART, 2, 42, 1), | ||
116 | PXA27X_PBUS_CKEN("pxa2xx-uart.1", NULL, BTUART, 2, 42, 1), | ||
117 | PXA27X_PBUS_CKEN("pxa2xx-uart.2", NULL, STUART, 2, 42, 1), | ||
118 | PXA27X_PBUS_CKEN("pxa2xx-i2s", NULL, I2S, 2, 51, 0), | ||
119 | PXA27X_PBUS_CKEN("pxa2xx-i2c.0", NULL, I2C, 2, 19, 0), | ||
120 | PXA27X_PBUS_CKEN("pxa27x-udc", NULL, USB, 2, 13, 5), | ||
121 | PXA27X_PBUS_CKEN("pxa2xx-mci.0", NULL, MMC, 2, 32, 0), | ||
122 | PXA27X_PBUS_CKEN("pxa2xx-ir", "FICPCLK", FICP, 2, 13, 0), | ||
123 | PXA27X_PBUS_CKEN("pxa27x-ohci", NULL, USBHOST, 2, 13, 0), | ||
124 | PXA27X_PBUS_CKEN("pxa2xx-i2c.1", NULL, PWRI2C, 1, 24, 0), | ||
125 | PXA27X_PBUS_CKEN("pxa27x-ssp.0", NULL, SSP1, 1, 24, 0), | ||
126 | PXA27X_PBUS_CKEN("pxa27x-ssp.1", NULL, SSP2, 1, 24, 0), | ||
127 | PXA27X_PBUS_CKEN("pxa27x-ssp.2", NULL, SSP3, 1, 24, 0), | ||
128 | PXA27X_PBUS_CKEN("pxa27x-pwm.0", NULL, PWM0, 1, 24, 0), | ||
129 | PXA27X_PBUS_CKEN("pxa27x-pwm.1", NULL, PWM1, 1, 24, 0), | ||
130 | PXA27X_PBUS_CKEN(NULL, "MSLCLK", MSL, 2, 13, 0), | ||
131 | PXA27X_PBUS_CKEN(NULL, "USIMCLK", USIM, 2, 13, 0), | ||
132 | PXA27X_PBUS_CKEN(NULL, "MSTKCLK", MEMSTK, 2, 32, 0), | ||
133 | PXA27X_PBUS_CKEN(NULL, "AC97CLK", AC97, 1, 1, 0), | ||
134 | PXA27X_PBUS_CKEN(NULL, "AC97CONFCLK", AC97CONF, 1, 1, 0), | ||
135 | PXA27X_PBUS_CKEN(NULL, "OSTIMER0", OSTIMER, 1, 96, 0), | ||
136 | |||
137 | PXA27X_CKEN_1RATE("pxa27x-keypad", NULL, KEYPAD, | ||
138 | pxa27x_32Mhz_bus_parents, 0), | ||
139 | PXA27X_CKEN_1RATE(NULL, "IMCLK", IM, pxa27x_sbus_parents, 0), | ||
140 | PXA27X_CKEN_1RATE("pxa2xx-fb", NULL, LCD, pxa27x_lcd_bus_parents, 0), | ||
141 | PXA27X_CKEN_1RATE("pxa27x-camera.0", NULL, CAMERA, | ||
142 | pxa27x_lcd_bus_parents, 0), | ||
143 | PXA27X_CKEN_1RATE_AO("pxa2xx-pcmcia", NULL, MEMC, | ||
144 | pxa27x_membus_parents, 0), | ||
145 | |||
146 | }; | ||
147 | |||
148 | static unsigned long clk_pxa27x_cpll_get_rate(struct clk_hw *hw, | ||
149 | unsigned long parent_rate) | ||
150 | { | ||
151 | unsigned long clkcfg; | ||
152 | unsigned int t, ht; | ||
153 | unsigned int l, L, n2, N; | ||
154 | unsigned long ccsr = CCSR; | ||
155 | |||
156 | asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); | ||
157 | t = clkcfg & (1 << 0); | ||
158 | ht = clkcfg & (1 << 2); | ||
159 | |||
160 | l = ccsr & CCSR_L_MASK; | ||
161 | n2 = (ccsr & CCSR_N2_MASK) >> CCSR_N2_SHIFT; | ||
162 | L = l * parent_rate; | ||
163 | N = (L * n2) / 2; | ||
164 | |||
165 | return t ? N : L; | ||
166 | } | ||
167 | PARENTS(clk_pxa27x_cpll) = { "osc_13mhz" }; | ||
168 | RATE_RO_OPS(clk_pxa27x_cpll, "cpll"); | ||
169 | |||
170 | static unsigned long clk_pxa27x_lcd_base_get_rate(struct clk_hw *hw, | ||
171 | unsigned long parent_rate) | ||
172 | { | ||
173 | unsigned int l, osc_forced; | ||
174 | unsigned long ccsr = CCSR; | ||
175 | unsigned long cccr = CCCR; | ||
176 | |||
177 | l = ccsr & CCSR_L_MASK; | ||
178 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
179 | if (osc_forced) { | ||
180 | if (cccr & (1 << CCCR_LCD_26_BIT)) | ||
181 | return parent_rate * 2; | ||
182 | else | ||
183 | return parent_rate; | ||
184 | } | ||
185 | |||
186 | if (l <= 7) | ||
187 | return parent_rate; | ||
188 | if (l <= 16) | ||
189 | return parent_rate / 2; | ||
190 | return parent_rate / 4; | ||
191 | } | ||
192 | |||
193 | static u8 clk_pxa27x_lcd_base_get_parent(struct clk_hw *hw) | ||
194 | { | ||
195 | unsigned int osc_forced; | ||
196 | unsigned long ccsr = CCSR; | ||
197 | |||
198 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
199 | if (osc_forced) | ||
200 | return PXA_LCD_13Mhz; | ||
201 | else | ||
202 | return PXA_LCD_RUN; | ||
203 | } | ||
204 | |||
205 | PARENTS(clk_pxa27x_lcd_base) = { "osc_13mhz", "run" }; | ||
206 | MUX_RO_RATE_RO_OPS(clk_pxa27x_lcd_base, "lcd_base"); | ||
207 | |||
208 | static void __init pxa27x_register_plls(void) | ||
209 | { | ||
210 | clk_register_fixed_rate(NULL, "osc_13mhz", NULL, | ||
211 | CLK_GET_RATE_NOCACHE | CLK_IS_ROOT, | ||
212 | 13 * MHz); | ||
213 | clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, | ||
214 | CLK_GET_RATE_NOCACHE | CLK_IS_ROOT, | ||
215 | 32768 * KHz); | ||
216 | clk_register_fixed_rate(NULL, "clk_dummy", NULL, CLK_IS_ROOT, 0); | ||
217 | clk_register_fixed_factor(NULL, "ppll_312mhz", "osc_13mhz", 0, 24, 1); | ||
218 | } | ||
219 | |||
220 | static unsigned long clk_pxa27x_core_get_rate(struct clk_hw *hw, | ||
221 | unsigned long parent_rate) | ||
222 | { | ||
223 | unsigned long clkcfg; | ||
224 | unsigned int t, ht, b, osc_forced; | ||
225 | unsigned long ccsr = CCSR; | ||
226 | |||
227 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
228 | asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); | ||
229 | t = clkcfg & (1 << 0); | ||
230 | ht = clkcfg & (1 << 2); | ||
231 | b = clkcfg & (1 << 3); | ||
232 | |||
233 | if (osc_forced) | ||
234 | return parent_rate; | ||
235 | if (ht) | ||
236 | return parent_rate / 2; | ||
237 | else | ||
238 | return parent_rate; | ||
239 | } | ||
240 | |||
241 | static u8 clk_pxa27x_core_get_parent(struct clk_hw *hw) | ||
242 | { | ||
243 | unsigned long clkcfg; | ||
244 | unsigned int t, ht, b, osc_forced; | ||
245 | unsigned long ccsr = CCSR; | ||
246 | |||
247 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
248 | if (osc_forced) | ||
249 | return PXA_CORE_13Mhz; | ||
250 | |||
251 | asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); | ||
252 | t = clkcfg & (1 << 0); | ||
253 | ht = clkcfg & (1 << 2); | ||
254 | b = clkcfg & (1 << 3); | ||
255 | |||
256 | if (ht || t) | ||
257 | return PXA_CORE_TURBO; | ||
258 | return PXA_CORE_RUN; | ||
259 | } | ||
260 | PARENTS(clk_pxa27x_core) = { "osc_13mhz", "run", "cpll" }; | ||
261 | MUX_RO_RATE_RO_OPS(clk_pxa27x_core, "core"); | ||
262 | |||
263 | static unsigned long clk_pxa27x_run_get_rate(struct clk_hw *hw, | ||
264 | unsigned long parent_rate) | ||
265 | { | ||
266 | unsigned long ccsr = CCSR; | ||
267 | unsigned int n2 = (ccsr & CCSR_N2_MASK) >> CCSR_N2_SHIFT; | ||
268 | |||
269 | return (parent_rate / n2) * 2; | ||
270 | } | ||
271 | PARENTS(clk_pxa27x_run) = { "cpll" }; | ||
272 | RATE_RO_OPS(clk_pxa27x_run, "run"); | ||
273 | |||
274 | static void __init pxa27x_register_core(void) | ||
275 | { | ||
276 | clk_register_clk_pxa27x_cpll(); | ||
277 | clk_register_clk_pxa27x_run(); | ||
278 | |||
279 | clkdev_pxa_register(CLK_CORE, "core", NULL, | ||
280 | clk_register_clk_pxa27x_core()); | ||
281 | } | ||
282 | |||
283 | static unsigned long clk_pxa27x_system_bus_get_rate(struct clk_hw *hw, | ||
284 | unsigned long parent_rate) | ||
285 | { | ||
286 | unsigned long clkcfg; | ||
287 | unsigned int b, osc_forced; | ||
288 | unsigned long ccsr = CCSR; | ||
289 | |||
290 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
291 | asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); | ||
292 | b = clkcfg & (1 << 3); | ||
293 | |||
294 | if (osc_forced) | ||
295 | return parent_rate; | ||
296 | if (b) | ||
297 | return parent_rate / 2; | ||
298 | else | ||
299 | return parent_rate; | ||
300 | } | ||
301 | |||
302 | static u8 clk_pxa27x_system_bus_get_parent(struct clk_hw *hw) | ||
303 | { | ||
304 | unsigned int osc_forced; | ||
305 | unsigned long ccsr = CCSR; | ||
306 | |||
307 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
308 | if (osc_forced) | ||
309 | return PXA_BUS_13Mhz; | ||
310 | else | ||
311 | return PXA_BUS_RUN; | ||
312 | } | ||
313 | |||
314 | PARENTS(clk_pxa27x_system_bus) = { "osc_13mhz", "run" }; | ||
315 | MUX_RO_RATE_RO_OPS(clk_pxa27x_system_bus, "system_bus"); | ||
316 | |||
317 | static unsigned long clk_pxa27x_memory_get_rate(struct clk_hw *hw, | ||
318 | unsigned long parent_rate) | ||
319 | { | ||
320 | unsigned int a, l, osc_forced; | ||
321 | unsigned long cccr = CCCR; | ||
322 | unsigned long ccsr = CCSR; | ||
323 | |||
324 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
325 | a = cccr & CCCR_A_BIT; | ||
326 | l = ccsr & CCSR_L_MASK; | ||
327 | |||
328 | if (osc_forced || a) | ||
329 | return parent_rate; | ||
330 | if (l <= 10) | ||
331 | return parent_rate; | ||
332 | if (l <= 20) | ||
333 | return parent_rate / 2; | ||
334 | return parent_rate / 4; | ||
335 | } | ||
336 | |||
337 | static u8 clk_pxa27x_memory_get_parent(struct clk_hw *hw) | ||
338 | { | ||
339 | unsigned int osc_forced, a; | ||
340 | unsigned long cccr = CCCR; | ||
341 | unsigned long ccsr = CCSR; | ||
342 | |||
343 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
344 | a = cccr & CCCR_A_BIT; | ||
345 | if (osc_forced) | ||
346 | return PXA_MEM_13Mhz; | ||
347 | if (a) | ||
348 | return PXA_MEM_SYSTEM_BUS; | ||
349 | else | ||
350 | return PXA_MEM_RUN; | ||
351 | } | ||
352 | |||
353 | PARENTS(clk_pxa27x_memory) = { "osc_13mhz", "system_bus", "run" }; | ||
354 | MUX_RO_RATE_RO_OPS(clk_pxa27x_memory, "memory"); | ||
355 | |||
356 | static void __init pxa27x_base_clocks_init(void) | ||
357 | { | ||
358 | pxa27x_register_plls(); | ||
359 | pxa27x_register_core(); | ||
360 | clk_register_clk_pxa27x_system_bus(); | ||
361 | clk_register_clk_pxa27x_memory(); | ||
362 | clk_register_clk_pxa27x_lcd_base(); | ||
363 | } | ||
364 | |||
365 | static int __init pxa27x_clocks_init(void) | ||
366 | { | ||
367 | pxa27x_base_clocks_init(); | ||
368 | return clk_pxa_cken_init(pxa27x_clocks, ARRAY_SIZE(pxa27x_clocks)); | ||
369 | } | ||
370 | postcore_initcall(pxa27x_clocks_init); | ||
diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c index 9db03d3b1657..b823bc3b6250 100644 --- a/drivers/clk/qcom/clk-pll.c +++ b/drivers/clk/qcom/clk-pll.c | |||
@@ -97,7 +97,7 @@ static unsigned long | |||
97 | clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | 97 | clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) |
98 | { | 98 | { |
99 | struct clk_pll *pll = to_clk_pll(hw); | 99 | struct clk_pll *pll = to_clk_pll(hw); |
100 | u32 l, m, n; | 100 | u32 l, m, n, config; |
101 | unsigned long rate; | 101 | unsigned long rate; |
102 | u64 tmp; | 102 | u64 tmp; |
103 | 103 | ||
@@ -116,13 +116,79 @@ clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | |||
116 | do_div(tmp, n); | 116 | do_div(tmp, n); |
117 | rate += tmp; | 117 | rate += tmp; |
118 | } | 118 | } |
119 | if (pll->post_div_width) { | ||
120 | regmap_read(pll->clkr.regmap, pll->config_reg, &config); | ||
121 | config >>= pll->post_div_shift; | ||
122 | config &= BIT(pll->post_div_width) - 1; | ||
123 | rate /= config + 1; | ||
124 | } | ||
125 | |||
119 | return rate; | 126 | return rate; |
120 | } | 127 | } |
121 | 128 | ||
129 | static const | ||
130 | struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate) | ||
131 | { | ||
132 | if (!f) | ||
133 | return NULL; | ||
134 | |||
135 | for (; f->freq; f++) | ||
136 | if (rate <= f->freq) | ||
137 | return f; | ||
138 | |||
139 | return NULL; | ||
140 | } | ||
141 | |||
142 | static long | ||
143 | clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate, | ||
144 | unsigned long *p_rate, struct clk **p) | ||
145 | { | ||
146 | struct clk_pll *pll = to_clk_pll(hw); | ||
147 | const struct pll_freq_tbl *f; | ||
148 | |||
149 | f = find_freq(pll->freq_tbl, rate); | ||
150 | if (!f) | ||
151 | return clk_pll_recalc_rate(hw, *p_rate); | ||
152 | |||
153 | return f->freq; | ||
154 | } | ||
155 | |||
156 | static int | ||
157 | clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long p_rate) | ||
158 | { | ||
159 | struct clk_pll *pll = to_clk_pll(hw); | ||
160 | const struct pll_freq_tbl *f; | ||
161 | bool enabled; | ||
162 | u32 mode; | ||
163 | u32 enable_mask = PLL_OUTCTRL | PLL_BYPASSNL | PLL_RESET_N; | ||
164 | |||
165 | f = find_freq(pll->freq_tbl, rate); | ||
166 | if (!f) | ||
167 | return -EINVAL; | ||
168 | |||
169 | regmap_read(pll->clkr.regmap, pll->mode_reg, &mode); | ||
170 | enabled = (mode & enable_mask) == enable_mask; | ||
171 | |||
172 | if (enabled) | ||
173 | clk_pll_disable(hw); | ||
174 | |||
175 | regmap_update_bits(pll->clkr.regmap, pll->l_reg, 0x3ff, f->l); | ||
176 | regmap_update_bits(pll->clkr.regmap, pll->m_reg, 0x7ffff, f->m); | ||
177 | regmap_update_bits(pll->clkr.regmap, pll->n_reg, 0x7ffff, f->n); | ||
178 | regmap_write(pll->clkr.regmap, pll->config_reg, f->ibits); | ||
179 | |||
180 | if (enabled) | ||
181 | clk_pll_enable(hw); | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
122 | const struct clk_ops clk_pll_ops = { | 186 | const struct clk_ops clk_pll_ops = { |
123 | .enable = clk_pll_enable, | 187 | .enable = clk_pll_enable, |
124 | .disable = clk_pll_disable, | 188 | .disable = clk_pll_disable, |
125 | .recalc_rate = clk_pll_recalc_rate, | 189 | .recalc_rate = clk_pll_recalc_rate, |
190 | .determine_rate = clk_pll_determine_rate, | ||
191 | .set_rate = clk_pll_set_rate, | ||
126 | }; | 192 | }; |
127 | EXPORT_SYMBOL_GPL(clk_pll_ops); | 193 | EXPORT_SYMBOL_GPL(clk_pll_ops); |
128 | 194 | ||
diff --git a/drivers/clk/qcom/clk-pll.h b/drivers/clk/qcom/clk-pll.h index 3003e9962472..c9c0cda306d0 100644 --- a/drivers/clk/qcom/clk-pll.h +++ b/drivers/clk/qcom/clk-pll.h | |||
@@ -18,6 +18,21 @@ | |||
18 | #include "clk-regmap.h" | 18 | #include "clk-regmap.h" |
19 | 19 | ||
20 | /** | 20 | /** |
21 | * struct pll_freq_tbl - PLL frequency table | ||
22 | * @l: L value | ||
23 | * @m: M value | ||
24 | * @n: N value | ||
25 | * @ibits: internal values | ||
26 | */ | ||
27 | struct pll_freq_tbl { | ||
28 | unsigned long freq; | ||
29 | u16 l; | ||
30 | u16 m; | ||
31 | u16 n; | ||
32 | u32 ibits; | ||
33 | }; | ||
34 | |||
35 | /** | ||
21 | * struct clk_pll - phase locked loop (PLL) | 36 | * struct clk_pll - phase locked loop (PLL) |
22 | * @l_reg: L register | 37 | * @l_reg: L register |
23 | * @m_reg: M register | 38 | * @m_reg: M register |
@@ -26,6 +41,7 @@ | |||
26 | * @mode_reg: mode register | 41 | * @mode_reg: mode register |
27 | * @status_reg: status register | 42 | * @status_reg: status register |
28 | * @status_bit: ANDed with @status_reg to determine if PLL is enabled | 43 | * @status_bit: ANDed with @status_reg to determine if PLL is enabled |
44 | * @freq_tbl: PLL frequency table | ||
29 | * @hw: handle between common and hardware-specific interfaces | 45 | * @hw: handle between common and hardware-specific interfaces |
30 | */ | 46 | */ |
31 | struct clk_pll { | 47 | struct clk_pll { |
@@ -36,6 +52,10 @@ struct clk_pll { | |||
36 | u32 mode_reg; | 52 | u32 mode_reg; |
37 | u32 status_reg; | 53 | u32 status_reg; |
38 | u8 status_bit; | 54 | u8 status_bit; |
55 | u8 post_div_width; | ||
56 | u8 post_div_shift; | ||
57 | |||
58 | const struct pll_freq_tbl *freq_tbl; | ||
39 | 59 | ||
40 | struct clk_regmap clkr; | 60 | struct clk_regmap clkr; |
41 | }; | 61 | }; |
diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c index b638c5846dbf..b6e6959e89aa 100644 --- a/drivers/clk/qcom/clk-rcg.c +++ b/drivers/clk/qcom/clk-rcg.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <asm/div64.h> | 21 | #include <asm/div64.h> |
22 | 22 | ||
23 | #include "clk-rcg.h" | 23 | #include "clk-rcg.h" |
24 | #include "common.h" | ||
24 | 25 | ||
25 | static u32 ns_to_src(struct src_sel *s, u32 ns) | 26 | static u32 ns_to_src(struct src_sel *s, u32 ns) |
26 | { | 27 | { |
@@ -67,16 +68,16 @@ static u8 clk_dyn_rcg_get_parent(struct clk_hw *hw) | |||
67 | { | 68 | { |
68 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); | 69 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); |
69 | int num_parents = __clk_get_num_parents(hw->clk); | 70 | int num_parents = __clk_get_num_parents(hw->clk); |
70 | u32 ns, ctl; | 71 | u32 ns, reg; |
71 | int bank; | 72 | int bank; |
72 | int i; | 73 | int i; |
73 | struct src_sel *s; | 74 | struct src_sel *s; |
74 | 75 | ||
75 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl); | 76 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
76 | bank = reg_to_bank(rcg, ctl); | 77 | bank = reg_to_bank(rcg, reg); |
77 | s = &rcg->s[bank]; | 78 | s = &rcg->s[bank]; |
78 | 79 | ||
79 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | 80 | regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns); |
80 | ns = ns_to_src(s, ns); | 81 | ns = ns_to_src(s, ns); |
81 | 82 | ||
82 | for (i = 0; i < num_parents; i++) | 83 | for (i = 0; i < num_parents; i++) |
@@ -192,90 +193,93 @@ static u32 mn_to_reg(struct mn *mn, u32 m, u32 n, u32 val) | |||
192 | 193 | ||
193 | static void configure_bank(struct clk_dyn_rcg *rcg, const struct freq_tbl *f) | 194 | static void configure_bank(struct clk_dyn_rcg *rcg, const struct freq_tbl *f) |
194 | { | 195 | { |
195 | u32 ns, md, ctl, *regp; | 196 | u32 ns, md, reg; |
196 | int bank, new_bank; | 197 | int bank, new_bank; |
197 | struct mn *mn; | 198 | struct mn *mn; |
198 | struct pre_div *p; | 199 | struct pre_div *p; |
199 | struct src_sel *s; | 200 | struct src_sel *s; |
200 | bool enabled; | 201 | bool enabled; |
201 | u32 md_reg; | 202 | u32 md_reg, ns_reg; |
202 | u32 bank_reg; | ||
203 | bool banked_mn = !!rcg->mn[1].width; | 203 | bool banked_mn = !!rcg->mn[1].width; |
204 | bool banked_p = !!rcg->p[1].pre_div_width; | ||
204 | struct clk_hw *hw = &rcg->clkr.hw; | 205 | struct clk_hw *hw = &rcg->clkr.hw; |
205 | 206 | ||
206 | enabled = __clk_is_enabled(hw->clk); | 207 | enabled = __clk_is_enabled(hw->clk); |
207 | 208 | ||
208 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | 209 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
209 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl); | 210 | bank = reg_to_bank(rcg, reg); |
210 | |||
211 | if (banked_mn) { | ||
212 | regp = &ctl; | ||
213 | bank_reg = rcg->clkr.enable_reg; | ||
214 | } else { | ||
215 | regp = &ns; | ||
216 | bank_reg = rcg->ns_reg; | ||
217 | } | ||
218 | |||
219 | bank = reg_to_bank(rcg, *regp); | ||
220 | new_bank = enabled ? !bank : bank; | 211 | new_bank = enabled ? !bank : bank; |
221 | 212 | ||
213 | ns_reg = rcg->ns_reg[new_bank]; | ||
214 | regmap_read(rcg->clkr.regmap, ns_reg, &ns); | ||
215 | |||
222 | if (banked_mn) { | 216 | if (banked_mn) { |
223 | mn = &rcg->mn[new_bank]; | 217 | mn = &rcg->mn[new_bank]; |
224 | md_reg = rcg->md_reg[new_bank]; | 218 | md_reg = rcg->md_reg[new_bank]; |
225 | 219 | ||
226 | ns |= BIT(mn->mnctr_reset_bit); | 220 | ns |= BIT(mn->mnctr_reset_bit); |
227 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | 221 | regmap_write(rcg->clkr.regmap, ns_reg, ns); |
228 | 222 | ||
229 | regmap_read(rcg->clkr.regmap, md_reg, &md); | 223 | regmap_read(rcg->clkr.regmap, md_reg, &md); |
230 | md = mn_to_md(mn, f->m, f->n, md); | 224 | md = mn_to_md(mn, f->m, f->n, md); |
231 | regmap_write(rcg->clkr.regmap, md_reg, md); | 225 | regmap_write(rcg->clkr.regmap, md_reg, md); |
232 | 226 | ||
233 | ns = mn_to_ns(mn, f->m, f->n, ns); | 227 | ns = mn_to_ns(mn, f->m, f->n, ns); |
234 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | 228 | regmap_write(rcg->clkr.regmap, ns_reg, ns); |
235 | 229 | ||
236 | ctl = mn_to_reg(mn, f->m, f->n, ctl); | 230 | /* Two NS registers means mode control is in NS register */ |
237 | regmap_write(rcg->clkr.regmap, rcg->clkr.enable_reg, ctl); | 231 | if (rcg->ns_reg[0] != rcg->ns_reg[1]) { |
232 | ns = mn_to_reg(mn, f->m, f->n, ns); | ||
233 | regmap_write(rcg->clkr.regmap, ns_reg, ns); | ||
234 | } else { | ||
235 | reg = mn_to_reg(mn, f->m, f->n, reg); | ||
236 | regmap_write(rcg->clkr.regmap, rcg->bank_reg, reg); | ||
237 | } | ||
238 | 238 | ||
239 | ns &= ~BIT(mn->mnctr_reset_bit); | 239 | ns &= ~BIT(mn->mnctr_reset_bit); |
240 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | 240 | regmap_write(rcg->clkr.regmap, ns_reg, ns); |
241 | } else { | 241 | } |
242 | |||
243 | if (banked_p) { | ||
242 | p = &rcg->p[new_bank]; | 244 | p = &rcg->p[new_bank]; |
243 | ns = pre_div_to_ns(p, f->pre_div - 1, ns); | 245 | ns = pre_div_to_ns(p, f->pre_div - 1, ns); |
244 | } | 246 | } |
245 | 247 | ||
246 | s = &rcg->s[new_bank]; | 248 | s = &rcg->s[new_bank]; |
247 | ns = src_to_ns(s, s->parent_map[f->src], ns); | 249 | ns = src_to_ns(s, s->parent_map[f->src], ns); |
248 | regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); | 250 | regmap_write(rcg->clkr.regmap, ns_reg, ns); |
249 | 251 | ||
250 | if (enabled) { | 252 | if (enabled) { |
251 | *regp ^= BIT(rcg->mux_sel_bit); | 253 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
252 | regmap_write(rcg->clkr.regmap, bank_reg, *regp); | 254 | reg ^= BIT(rcg->mux_sel_bit); |
255 | regmap_write(rcg->clkr.regmap, rcg->bank_reg, reg); | ||
253 | } | 256 | } |
254 | } | 257 | } |
255 | 258 | ||
256 | static int clk_dyn_rcg_set_parent(struct clk_hw *hw, u8 index) | 259 | static int clk_dyn_rcg_set_parent(struct clk_hw *hw, u8 index) |
257 | { | 260 | { |
258 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); | 261 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); |
259 | u32 ns, ctl, md, reg; | 262 | u32 ns, md, reg; |
260 | int bank; | 263 | int bank; |
261 | struct freq_tbl f = { 0 }; | 264 | struct freq_tbl f = { 0 }; |
262 | bool banked_mn = !!rcg->mn[1].width; | 265 | bool banked_mn = !!rcg->mn[1].width; |
266 | bool banked_p = !!rcg->p[1].pre_div_width; | ||
263 | 267 | ||
264 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | 268 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
265 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl); | ||
266 | reg = banked_mn ? ctl : ns; | ||
267 | |||
268 | bank = reg_to_bank(rcg, reg); | 269 | bank = reg_to_bank(rcg, reg); |
269 | 270 | ||
271 | regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns); | ||
272 | |||
270 | if (banked_mn) { | 273 | if (banked_mn) { |
271 | regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); | 274 | regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); |
272 | f.m = md_to_m(&rcg->mn[bank], md); | 275 | f.m = md_to_m(&rcg->mn[bank], md); |
273 | f.n = ns_m_to_n(&rcg->mn[bank], ns, f.m); | 276 | f.n = ns_m_to_n(&rcg->mn[bank], ns, f.m); |
274 | } else { | ||
275 | f.pre_div = ns_to_pre_div(&rcg->p[bank], ns) + 1; | ||
276 | } | 277 | } |
277 | f.src = index; | ||
278 | 278 | ||
279 | if (banked_p) | ||
280 | f.pre_div = ns_to_pre_div(&rcg->p[bank], ns) + 1; | ||
281 | |||
282 | f.src = index; | ||
279 | configure_bank(rcg, &f); | 283 | configure_bank(rcg, &f); |
280 | 284 | ||
281 | return 0; | 285 | return 0; |
@@ -336,41 +340,30 @@ clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | |||
336 | u32 m, n, pre_div, ns, md, mode, reg; | 340 | u32 m, n, pre_div, ns, md, mode, reg; |
337 | int bank; | 341 | int bank; |
338 | struct mn *mn; | 342 | struct mn *mn; |
343 | bool banked_p = !!rcg->p[1].pre_div_width; | ||
339 | bool banked_mn = !!rcg->mn[1].width; | 344 | bool banked_mn = !!rcg->mn[1].width; |
340 | 345 | ||
341 | regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); | 346 | regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); |
342 | |||
343 | if (banked_mn) | ||
344 | regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, ®); | ||
345 | else | ||
346 | reg = ns; | ||
347 | |||
348 | bank = reg_to_bank(rcg, reg); | 347 | bank = reg_to_bank(rcg, reg); |
349 | 348 | ||
349 | regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns); | ||
350 | m = n = pre_div = mode = 0; | ||
351 | |||
350 | if (banked_mn) { | 352 | if (banked_mn) { |
351 | mn = &rcg->mn[bank]; | 353 | mn = &rcg->mn[bank]; |
352 | regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); | 354 | regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); |
353 | m = md_to_m(mn, md); | 355 | m = md_to_m(mn, md); |
354 | n = ns_m_to_n(mn, ns, m); | 356 | n = ns_m_to_n(mn, ns, m); |
357 | /* Two NS registers means mode control is in NS register */ | ||
358 | if (rcg->ns_reg[0] != rcg->ns_reg[1]) | ||
359 | reg = ns; | ||
355 | mode = reg_to_mnctr_mode(mn, reg); | 360 | mode = reg_to_mnctr_mode(mn, reg); |
356 | return calc_rate(parent_rate, m, n, mode, 0); | ||
357 | } else { | ||
358 | pre_div = ns_to_pre_div(&rcg->p[bank], ns); | ||
359 | return calc_rate(parent_rate, 0, 0, 0, pre_div); | ||
360 | } | 361 | } |
361 | } | ||
362 | 362 | ||
363 | static const | 363 | if (banked_p) |
364 | struct freq_tbl *find_freq(const struct freq_tbl *f, unsigned long rate) | 364 | pre_div = ns_to_pre_div(&rcg->p[bank], ns); |
365 | { | ||
366 | if (!f) | ||
367 | return NULL; | ||
368 | |||
369 | for (; f->freq; f++) | ||
370 | if (rate <= f->freq) | ||
371 | return f; | ||
372 | 365 | ||
373 | return NULL; | 366 | return calc_rate(parent_rate, m, n, mode, pre_div); |
374 | } | 367 | } |
375 | 368 | ||
376 | static long _freq_tbl_determine_rate(struct clk_hw *hw, | 369 | static long _freq_tbl_determine_rate(struct clk_hw *hw, |
@@ -379,7 +372,7 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw, | |||
379 | { | 372 | { |
380 | unsigned long clk_flags; | 373 | unsigned long clk_flags; |
381 | 374 | ||
382 | f = find_freq(f, rate); | 375 | f = qcom_find_freq(f, rate); |
383 | if (!f) | 376 | if (!f) |
384 | return -EINVAL; | 377 | return -EINVAL; |
385 | 378 | ||
@@ -477,7 +470,7 @@ static int clk_rcg_set_rate(struct clk_hw *hw, unsigned long rate, | |||
477 | struct clk_rcg *rcg = to_clk_rcg(hw); | 470 | struct clk_rcg *rcg = to_clk_rcg(hw); |
478 | const struct freq_tbl *f; | 471 | const struct freq_tbl *f; |
479 | 472 | ||
480 | f = find_freq(rcg->freq_tbl, rate); | 473 | f = qcom_find_freq(rcg->freq_tbl, rate); |
481 | if (!f) | 474 | if (!f) |
482 | return -EINVAL; | 475 | return -EINVAL; |
483 | 476 | ||
@@ -497,7 +490,7 @@ static int __clk_dyn_rcg_set_rate(struct clk_hw *hw, unsigned long rate) | |||
497 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); | 490 | struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); |
498 | const struct freq_tbl *f; | 491 | const struct freq_tbl *f; |
499 | 492 | ||
500 | f = find_freq(rcg->freq_tbl, rate); | 493 | f = qcom_find_freq(rcg->freq_tbl, rate); |
501 | if (!f) | 494 | if (!f) |
502 | return -EINVAL; | 495 | return -EINVAL; |
503 | 496 | ||
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index ba0523cefd2e..687e41f91d7c 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h | |||
@@ -103,8 +103,9 @@ extern const struct clk_ops clk_rcg_bypass_ops; | |||
103 | * struct clk_dyn_rcg - root clock generator with glitch free mux | 103 | * struct clk_dyn_rcg - root clock generator with glitch free mux |
104 | * | 104 | * |
105 | * @mux_sel_bit: bit to switch glitch free mux | 105 | * @mux_sel_bit: bit to switch glitch free mux |
106 | * @ns_reg: NS register | 106 | * @ns_reg: NS0 and NS1 register |
107 | * @md_reg: MD0 and MD1 register | 107 | * @md_reg: MD0 and MD1 register |
108 | * @bank_reg: register to XOR @mux_sel_bit into to switch glitch free mux | ||
108 | * @mn: mn counter (banked) | 109 | * @mn: mn counter (banked) |
109 | * @s: source selector (banked) | 110 | * @s: source selector (banked) |
110 | * @freq_tbl: frequency table | 111 | * @freq_tbl: frequency table |
@@ -113,8 +114,9 @@ extern const struct clk_ops clk_rcg_bypass_ops; | |||
113 | * | 114 | * |
114 | */ | 115 | */ |
115 | struct clk_dyn_rcg { | 116 | struct clk_dyn_rcg { |
116 | u32 ns_reg; | 117 | u32 ns_reg[2]; |
117 | u32 md_reg[2]; | 118 | u32 md_reg[2]; |
119 | u32 bank_reg; | ||
118 | 120 | ||
119 | u8 mux_sel_bit; | 121 | u8 mux_sel_bit; |
120 | 122 | ||
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index cd185d5cc67a..cfa9eb4fe9ca 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <asm/div64.h> | 24 | #include <asm/div64.h> |
25 | 25 | ||
26 | #include "clk-rcg.h" | 26 | #include "clk-rcg.h" |
27 | #include "common.h" | ||
27 | 28 | ||
28 | #define CMD_REG 0x0 | 29 | #define CMD_REG 0x0 |
29 | #define CMD_UPDATE BIT(0) | 30 | #define CMD_UPDATE BIT(0) |
@@ -172,27 +173,13 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | |||
172 | return calc_rate(parent_rate, m, n, mode, hid_div); | 173 | return calc_rate(parent_rate, m, n, mode, hid_div); |
173 | } | 174 | } |
174 | 175 | ||
175 | static const | ||
176 | struct freq_tbl *find_freq(const struct freq_tbl *f, unsigned long rate) | ||
177 | { | ||
178 | if (!f) | ||
179 | return NULL; | ||
180 | |||
181 | for (; f->freq; f++) | ||
182 | if (rate <= f->freq) | ||
183 | return f; | ||
184 | |||
185 | /* Default to our fastest rate */ | ||
186 | return f - 1; | ||
187 | } | ||
188 | |||
189 | static long _freq_tbl_determine_rate(struct clk_hw *hw, | 176 | static long _freq_tbl_determine_rate(struct clk_hw *hw, |
190 | const struct freq_tbl *f, unsigned long rate, | 177 | const struct freq_tbl *f, unsigned long rate, |
191 | unsigned long *p_rate, struct clk **p) | 178 | unsigned long *p_rate, struct clk **p) |
192 | { | 179 | { |
193 | unsigned long clk_flags; | 180 | unsigned long clk_flags; |
194 | 181 | ||
195 | f = find_freq(f, rate); | 182 | f = qcom_find_freq(f, rate); |
196 | if (!f) | 183 | if (!f) |
197 | return -EINVAL; | 184 | return -EINVAL; |
198 | 185 | ||
@@ -268,7 +255,7 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate) | |||
268 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | 255 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); |
269 | const struct freq_tbl *f; | 256 | const struct freq_tbl *f; |
270 | 257 | ||
271 | f = find_freq(rcg->freq_tbl, rate); | 258 | f = qcom_find_freq(rcg->freq_tbl, rate); |
272 | if (!f) | 259 | if (!f) |
273 | return -EINVAL; | 260 | return -EINVAL; |
274 | 261 | ||
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index eeb3eea01f4c..e20d947db3e5 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/reset-controller.h> | 18 | #include <linux/reset-controller.h> |
19 | 19 | ||
20 | #include "common.h" | 20 | #include "common.h" |
21 | #include "clk-rcg.h" | ||
21 | #include "clk-regmap.h" | 22 | #include "clk-regmap.h" |
22 | #include "reset.h" | 23 | #include "reset.h" |
23 | 24 | ||
@@ -27,6 +28,21 @@ struct qcom_cc { | |||
27 | struct clk *clks[]; | 28 | struct clk *clks[]; |
28 | }; | 29 | }; |
29 | 30 | ||
31 | const | ||
32 | struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, unsigned long rate) | ||
33 | { | ||
34 | if (!f) | ||
35 | return NULL; | ||
36 | |||
37 | for (; f->freq; f++) | ||
38 | if (rate <= f->freq) | ||
39 | return f; | ||
40 | |||
41 | /* Default to our fastest rate */ | ||
42 | return f - 1; | ||
43 | } | ||
44 | EXPORT_SYMBOL_GPL(qcom_find_freq); | ||
45 | |||
30 | struct regmap * | 46 | struct regmap * |
31 | qcom_cc_map(struct platform_device *pdev, const struct qcom_cc_desc *desc) | 47 | qcom_cc_map(struct platform_device *pdev, const struct qcom_cc_desc *desc) |
32 | { | 48 | { |
diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h index 2765e9d3da97..f519322acdf3 100644 --- a/drivers/clk/qcom/common.h +++ b/drivers/clk/qcom/common.h | |||
@@ -18,6 +18,7 @@ struct regmap_config; | |||
18 | struct clk_regmap; | 18 | struct clk_regmap; |
19 | struct qcom_reset_map; | 19 | struct qcom_reset_map; |
20 | struct regmap; | 20 | struct regmap; |
21 | struct freq_tbl; | ||
21 | 22 | ||
22 | struct qcom_cc_desc { | 23 | struct qcom_cc_desc { |
23 | const struct regmap_config *config; | 24 | const struct regmap_config *config; |
@@ -27,6 +28,9 @@ struct qcom_cc_desc { | |||
27 | size_t num_resets; | 28 | size_t num_resets; |
28 | }; | 29 | }; |
29 | 30 | ||
31 | extern const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, | ||
32 | unsigned long rate); | ||
33 | |||
30 | extern struct regmap *qcom_cc_map(struct platform_device *pdev, | 34 | extern struct regmap *qcom_cc_map(struct platform_device *pdev, |
31 | const struct qcom_cc_desc *desc); | 35 | const struct qcom_cc_desc *desc); |
32 | extern int qcom_cc_really_probe(struct platform_device *pdev, | 36 | extern int qcom_cc_really_probe(struct platform_device *pdev, |
diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c index 4032e510d9aa..5cd62a709ac7 100644 --- a/drivers/clk/qcom/gcc-ipq806x.c +++ b/drivers/clk/qcom/gcc-ipq806x.c | |||
@@ -32,6 +32,33 @@ | |||
32 | #include "clk-branch.h" | 32 | #include "clk-branch.h" |
33 | #include "reset.h" | 33 | #include "reset.h" |
34 | 34 | ||
35 | static struct clk_pll pll0 = { | ||
36 | .l_reg = 0x30c4, | ||
37 | .m_reg = 0x30c8, | ||
38 | .n_reg = 0x30cc, | ||
39 | .config_reg = 0x30d4, | ||
40 | .mode_reg = 0x30c0, | ||
41 | .status_reg = 0x30d8, | ||
42 | .status_bit = 16, | ||
43 | .clkr.hw.init = &(struct clk_init_data){ | ||
44 | .name = "pll0", | ||
45 | .parent_names = (const char *[]){ "pxo" }, | ||
46 | .num_parents = 1, | ||
47 | .ops = &clk_pll_ops, | ||
48 | }, | ||
49 | }; | ||
50 | |||
51 | static struct clk_regmap pll0_vote = { | ||
52 | .enable_reg = 0x34c0, | ||
53 | .enable_mask = BIT(0), | ||
54 | .hw.init = &(struct clk_init_data){ | ||
55 | .name = "pll0_vote", | ||
56 | .parent_names = (const char *[]){ "pll0" }, | ||
57 | .num_parents = 1, | ||
58 | .ops = &clk_pll_vote_ops, | ||
59 | }, | ||
60 | }; | ||
61 | |||
35 | static struct clk_pll pll3 = { | 62 | static struct clk_pll pll3 = { |
36 | .l_reg = 0x3164, | 63 | .l_reg = 0x3164, |
37 | .m_reg = 0x3168, | 64 | .m_reg = 0x3168, |
@@ -154,7 +181,7 @@ static const u8 gcc_pxo_pll8_pll0[] = { | |||
154 | static const char *gcc_pxo_pll8_pll0_map[] = { | 181 | static const char *gcc_pxo_pll8_pll0_map[] = { |
155 | "pxo", | 182 | "pxo", |
156 | "pll8_vote", | 183 | "pll8_vote", |
157 | "pll0", | 184 | "pll0_vote", |
158 | }; | 185 | }; |
159 | 186 | ||
160 | static struct freq_tbl clk_tbl_gsbi_uart[] = { | 187 | static struct freq_tbl clk_tbl_gsbi_uart[] = { |
@@ -1095,7 +1122,7 @@ static struct clk_branch prng_clk = { | |||
1095 | }; | 1122 | }; |
1096 | 1123 | ||
1097 | static const struct freq_tbl clk_tbl_sdc[] = { | 1124 | static const struct freq_tbl clk_tbl_sdc[] = { |
1098 | { 144000, P_PXO, 5, 18,625 }, | 1125 | { 200000, P_PXO, 2, 2, 125 }, |
1099 | { 400000, P_PLL8, 4, 1, 240 }, | 1126 | { 400000, P_PLL8, 4, 1, 240 }, |
1100 | { 16000000, P_PLL8, 4, 1, 6 }, | 1127 | { 16000000, P_PLL8, 4, 1, 6 }, |
1101 | { 17070000, P_PLL8, 1, 2, 45 }, | 1128 | { 17070000, P_PLL8, 1, 2, 45 }, |
@@ -2133,6 +2160,8 @@ static struct clk_branch usb_fs1_h_clk = { | |||
2133 | }; | 2160 | }; |
2134 | 2161 | ||
2135 | static struct clk_regmap *gcc_ipq806x_clks[] = { | 2162 | static struct clk_regmap *gcc_ipq806x_clks[] = { |
2163 | [PLL0] = &pll0.clkr, | ||
2164 | [PLL0_VOTE] = &pll0_vote, | ||
2136 | [PLL3] = &pll3.clkr, | 2165 | [PLL3] = &pll3.clkr, |
2137 | [PLL8] = &pll8.clkr, | 2166 | [PLL8] = &pll8.clkr, |
2138 | [PLL8_VOTE] = &pll8_vote, | 2167 | [PLL8_VOTE] = &pll8_vote, |
diff --git a/drivers/clk/qcom/mmcc-apq8084.c b/drivers/clk/qcom/mmcc-apq8084.c index 751eea376a2b..dab988ab8cf1 100644 --- a/drivers/clk/qcom/mmcc-apq8084.c +++ b/drivers/clk/qcom/mmcc-apq8084.c | |||
@@ -3341,7 +3341,6 @@ static struct platform_driver mmcc_apq8084_driver = { | |||
3341 | .remove = mmcc_apq8084_remove, | 3341 | .remove = mmcc_apq8084_remove, |
3342 | .driver = { | 3342 | .driver = { |
3343 | .name = "mmcc-apq8084", | 3343 | .name = "mmcc-apq8084", |
3344 | .owner = THIS_MODULE, | ||
3345 | .of_match_table = mmcc_apq8084_match_table, | 3344 | .of_match_table = mmcc_apq8084_match_table, |
3346 | }, | 3345 | }, |
3347 | }; | 3346 | }; |
diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c index 2e80a219b8ea..e8b33bbc362f 100644 --- a/drivers/clk/qcom/mmcc-msm8960.c +++ b/drivers/clk/qcom/mmcc-msm8960.c | |||
@@ -773,9 +773,11 @@ static struct freq_tbl clk_tbl_gfx2d[] = { | |||
773 | }; | 773 | }; |
774 | 774 | ||
775 | static struct clk_dyn_rcg gfx2d0_src = { | 775 | static struct clk_dyn_rcg gfx2d0_src = { |
776 | .ns_reg = 0x0070, | 776 | .ns_reg[0] = 0x0070, |
777 | .ns_reg[1] = 0x0070, | ||
777 | .md_reg[0] = 0x0064, | 778 | .md_reg[0] = 0x0064, |
778 | .md_reg[1] = 0x0068, | 779 | .md_reg[1] = 0x0068, |
780 | .bank_reg = 0x0060, | ||
779 | .mn[0] = { | 781 | .mn[0] = { |
780 | .mnctr_en_bit = 8, | 782 | .mnctr_en_bit = 8, |
781 | .mnctr_reset_bit = 25, | 783 | .mnctr_reset_bit = 25, |
@@ -831,9 +833,11 @@ static struct clk_branch gfx2d0_clk = { | |||
831 | }; | 833 | }; |
832 | 834 | ||
833 | static struct clk_dyn_rcg gfx2d1_src = { | 835 | static struct clk_dyn_rcg gfx2d1_src = { |
834 | .ns_reg = 0x007c, | 836 | .ns_reg[0] = 0x007c, |
837 | .ns_reg[1] = 0x007c, | ||
835 | .md_reg[0] = 0x0078, | 838 | .md_reg[0] = 0x0078, |
836 | .md_reg[1] = 0x006c, | 839 | .md_reg[1] = 0x006c, |
840 | .bank_reg = 0x0074, | ||
837 | .mn[0] = { | 841 | .mn[0] = { |
838 | .mnctr_en_bit = 8, | 842 | .mnctr_en_bit = 8, |
839 | .mnctr_reset_bit = 25, | 843 | .mnctr_reset_bit = 25, |
@@ -930,9 +934,11 @@ static struct freq_tbl clk_tbl_gfx3d_8064[] = { | |||
930 | }; | 934 | }; |
931 | 935 | ||
932 | static struct clk_dyn_rcg gfx3d_src = { | 936 | static struct clk_dyn_rcg gfx3d_src = { |
933 | .ns_reg = 0x008c, | 937 | .ns_reg[0] = 0x008c, |
938 | .ns_reg[1] = 0x008c, | ||
934 | .md_reg[0] = 0x0084, | 939 | .md_reg[0] = 0x0084, |
935 | .md_reg[1] = 0x0088, | 940 | .md_reg[1] = 0x0088, |
941 | .bank_reg = 0x0080, | ||
936 | .mn[0] = { | 942 | .mn[0] = { |
937 | .mnctr_en_bit = 8, | 943 | .mnctr_en_bit = 8, |
938 | .mnctr_reset_bit = 25, | 944 | .mnctr_reset_bit = 25, |
@@ -1006,9 +1012,11 @@ static struct freq_tbl clk_tbl_vcap[] = { | |||
1006 | }; | 1012 | }; |
1007 | 1013 | ||
1008 | static struct clk_dyn_rcg vcap_src = { | 1014 | static struct clk_dyn_rcg vcap_src = { |
1009 | .ns_reg = 0x021c, | 1015 | .ns_reg[0] = 0x021c, |
1016 | .ns_reg[1] = 0x021c, | ||
1010 | .md_reg[0] = 0x01ec, | 1017 | .md_reg[0] = 0x01ec, |
1011 | .md_reg[1] = 0x0218, | 1018 | .md_reg[1] = 0x0218, |
1019 | .bank_reg = 0x0178, | ||
1012 | .mn[0] = { | 1020 | .mn[0] = { |
1013 | .mnctr_en_bit = 8, | 1021 | .mnctr_en_bit = 8, |
1014 | .mnctr_reset_bit = 23, | 1022 | .mnctr_reset_bit = 23, |
@@ -1211,9 +1219,11 @@ static struct freq_tbl clk_tbl_mdp[] = { | |||
1211 | }; | 1219 | }; |
1212 | 1220 | ||
1213 | static struct clk_dyn_rcg mdp_src = { | 1221 | static struct clk_dyn_rcg mdp_src = { |
1214 | .ns_reg = 0x00d0, | 1222 | .ns_reg[0] = 0x00d0, |
1223 | .ns_reg[1] = 0x00d0, | ||
1215 | .md_reg[0] = 0x00c4, | 1224 | .md_reg[0] = 0x00c4, |
1216 | .md_reg[1] = 0x00c8, | 1225 | .md_reg[1] = 0x00c8, |
1226 | .bank_reg = 0x00c0, | ||
1217 | .mn[0] = { | 1227 | .mn[0] = { |
1218 | .mnctr_en_bit = 8, | 1228 | .mnctr_en_bit = 8, |
1219 | .mnctr_reset_bit = 31, | 1229 | .mnctr_reset_bit = 31, |
@@ -1318,7 +1328,9 @@ static struct freq_tbl clk_tbl_rot[] = { | |||
1318 | }; | 1328 | }; |
1319 | 1329 | ||
1320 | static struct clk_dyn_rcg rot_src = { | 1330 | static struct clk_dyn_rcg rot_src = { |
1321 | .ns_reg = 0x00e8, | 1331 | .ns_reg[0] = 0x00e8, |
1332 | .ns_reg[1] = 0x00e8, | ||
1333 | .bank_reg = 0x00e8, | ||
1322 | .p[0] = { | 1334 | .p[0] = { |
1323 | .pre_div_shift = 22, | 1335 | .pre_div_shift = 22, |
1324 | .pre_div_width = 4, | 1336 | .pre_div_width = 4, |
@@ -1542,9 +1554,11 @@ static struct freq_tbl clk_tbl_vcodec[] = { | |||
1542 | }; | 1554 | }; |
1543 | 1555 | ||
1544 | static struct clk_dyn_rcg vcodec_src = { | 1556 | static struct clk_dyn_rcg vcodec_src = { |
1545 | .ns_reg = 0x0100, | 1557 | .ns_reg[0] = 0x0100, |
1558 | .ns_reg[1] = 0x0100, | ||
1546 | .md_reg[0] = 0x00fc, | 1559 | .md_reg[0] = 0x00fc, |
1547 | .md_reg[1] = 0x0128, | 1560 | .md_reg[1] = 0x0128, |
1561 | .bank_reg = 0x00f8, | ||
1548 | .mn[0] = { | 1562 | .mn[0] = { |
1549 | .mnctr_en_bit = 5, | 1563 | .mnctr_en_bit = 5, |
1550 | .mnctr_reset_bit = 31, | 1564 | .mnctr_reset_bit = 31, |
@@ -2679,7 +2693,6 @@ static struct platform_driver mmcc_msm8960_driver = { | |||
2679 | .remove = mmcc_msm8960_remove, | 2693 | .remove = mmcc_msm8960_remove, |
2680 | .driver = { | 2694 | .driver = { |
2681 | .name = "mmcc-msm8960", | 2695 | .name = "mmcc-msm8960", |
2682 | .owner = THIS_MODULE, | ||
2683 | .of_match_table = mmcc_msm8960_match_table, | 2696 | .of_match_table = mmcc_msm8960_match_table, |
2684 | }, | 2697 | }, |
2685 | }; | 2698 | }; |
diff --git a/drivers/clk/qcom/mmcc-msm8974.c b/drivers/clk/qcom/mmcc-msm8974.c index bc8f519c47aa..be94c54a9a4f 100644 --- a/drivers/clk/qcom/mmcc-msm8974.c +++ b/drivers/clk/qcom/mmcc-msm8974.c | |||
@@ -2570,7 +2570,6 @@ static struct platform_driver mmcc_msm8974_driver = { | |||
2570 | .remove = mmcc_msm8974_remove, | 2570 | .remove = mmcc_msm8974_remove, |
2571 | .driver = { | 2571 | .driver = { |
2572 | .name = "mmcc-msm8974", | 2572 | .name = "mmcc-msm8974", |
2573 | .owner = THIS_MODULE, | ||
2574 | .of_match_table = mmcc_msm8974_match_table, | 2573 | .of_match_table = mmcc_msm8974_match_table, |
2575 | }, | 2574 | }, |
2576 | }; | 2575 | }; |
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index ee6b077381e1..bd8514d63634 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile | |||
@@ -5,6 +5,7 @@ | |||
5 | obj-y += clk-rockchip.o | 5 | obj-y += clk-rockchip.o |
6 | obj-y += clk.o | 6 | obj-y += clk.o |
7 | obj-y += clk-pll.o | 7 | obj-y += clk-pll.o |
8 | obj-y += clk-cpu.o | ||
8 | obj-$(CONFIG_RESET_CONTROLLER) += softrst.o | 9 | obj-$(CONFIG_RESET_CONTROLLER) += softrst.o |
9 | 10 | ||
10 | obj-y += clk-rk3188.o | 11 | obj-y += clk-rk3188.o |
diff --git a/drivers/clk/rockchip/clk-cpu.c b/drivers/clk/rockchip/clk-cpu.c new file mode 100644 index 000000000000..75c8c45ef728 --- /dev/null +++ b/drivers/clk/rockchip/clk-cpu.c | |||
@@ -0,0 +1,329 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014 MundoReader S.L. | ||
3 | * Author: Heiko Stuebner <heiko@sntech.de> | ||
4 | * | ||
5 | * based on clk/samsung/clk-cpu.c | ||
6 | * Copyright (c) 2014 Samsung Electronics Co., Ltd. | ||
7 | * Author: Thomas Abraham <thomas.ab@samsung.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * A CPU clock is defined as a clock supplied to a CPU or a group of CPUs. | ||
14 | * The CPU clock is typically derived from a hierarchy of clock | ||
15 | * blocks which includes mux and divider blocks. There are a number of other | ||
16 | * auxiliary clocks supplied to the CPU domain such as the debug blocks and AXI | ||
17 | * clock for CPU domain. The rates of these auxiliary clocks are related to the | ||
18 | * CPU clock rate and this relation is usually specified in the hardware manual | ||
19 | * of the SoC or supplied after the SoC characterization. | ||
20 | * | ||
21 | * The below implementation of the CPU clock allows the rate changes of the CPU | ||
22 | * clock and the corresponding rate changes of the auxillary clocks of the CPU | ||
23 | * domain. The platform clock driver provides a clock register configuration | ||
24 | * for each configurable rate which is then used to program the clock hardware | ||
25 | * registers to acheive a fast co-oridinated rate change for all the CPU domain | ||
26 | * clocks. | ||
27 | * | ||
28 | * On a rate change request for the CPU clock, the rate change is propagated | ||
29 | * upto the PLL supplying the clock to the CPU domain clock blocks. While the | ||
30 | * CPU domain PLL is reconfigured, the CPU domain clocks are driven using an | ||
31 | * alternate clock source. If required, the alternate clock source is divided | ||
32 | * down in order to keep the output clock rate within the previous OPP limits. | ||
33 | */ | ||
34 | |||
35 | #include <linux/of.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <linux/io.h> | ||
38 | #include <linux/clk-provider.h> | ||
39 | #include "clk.h" | ||
40 | |||
41 | /** | ||
42 | * struct rockchip_cpuclk: information about clock supplied to a CPU core. | ||
43 | * @hw: handle between ccf and cpu clock. | ||
44 | * @alt_parent: alternate parent clock to use when switching the speed | ||
45 | * of the primary parent clock. | ||
46 | * @reg_base: base register for cpu-clock values. | ||
47 | * @clk_nb: clock notifier registered for changes in clock speed of the | ||
48 | * primary parent clock. | ||
49 | * @rate_count: number of rates in the rate_table | ||
50 | * @rate_table: pll-rates and their associated dividers | ||
51 | * @reg_data: cpu-specific register settings | ||
52 | * @lock: clock lock | ||
53 | */ | ||
54 | struct rockchip_cpuclk { | ||
55 | struct clk_hw hw; | ||
56 | |||
57 | struct clk_mux cpu_mux; | ||
58 | const struct clk_ops *cpu_mux_ops; | ||
59 | |||
60 | struct clk *alt_parent; | ||
61 | void __iomem *reg_base; | ||
62 | struct notifier_block clk_nb; | ||
63 | unsigned int rate_count; | ||
64 | struct rockchip_cpuclk_rate_table *rate_table; | ||
65 | const struct rockchip_cpuclk_reg_data *reg_data; | ||
66 | spinlock_t *lock; | ||
67 | }; | ||
68 | |||
69 | #define to_rockchip_cpuclk_hw(hw) container_of(hw, struct rockchip_cpuclk, hw) | ||
70 | #define to_rockchip_cpuclk_nb(nb) \ | ||
71 | container_of(nb, struct rockchip_cpuclk, clk_nb) | ||
72 | |||
73 | static const struct rockchip_cpuclk_rate_table *rockchip_get_cpuclk_settings( | ||
74 | struct rockchip_cpuclk *cpuclk, unsigned long rate) | ||
75 | { | ||
76 | const struct rockchip_cpuclk_rate_table *rate_table = | ||
77 | cpuclk->rate_table; | ||
78 | int i; | ||
79 | |||
80 | for (i = 0; i < cpuclk->rate_count; i++) { | ||
81 | if (rate == rate_table[i].prate) | ||
82 | return &rate_table[i]; | ||
83 | } | ||
84 | |||
85 | return NULL; | ||
86 | } | ||
87 | |||
88 | static unsigned long rockchip_cpuclk_recalc_rate(struct clk_hw *hw, | ||
89 | unsigned long parent_rate) | ||
90 | { | ||
91 | struct rockchip_cpuclk *cpuclk = to_rockchip_cpuclk_hw(hw); | ||
92 | const struct rockchip_cpuclk_reg_data *reg_data = cpuclk->reg_data; | ||
93 | u32 clksel0 = readl_relaxed(cpuclk->reg_base + reg_data->core_reg); | ||
94 | |||
95 | clksel0 >>= reg_data->div_core_shift; | ||
96 | clksel0 &= reg_data->div_core_mask; | ||
97 | return parent_rate / (clksel0 + 1); | ||
98 | } | ||
99 | |||
100 | static const struct clk_ops rockchip_cpuclk_ops = { | ||
101 | .recalc_rate = rockchip_cpuclk_recalc_rate, | ||
102 | }; | ||
103 | |||
104 | static void rockchip_cpuclk_set_dividers(struct rockchip_cpuclk *cpuclk, | ||
105 | const struct rockchip_cpuclk_rate_table *rate) | ||
106 | { | ||
107 | int i; | ||
108 | |||
109 | /* alternate parent is active now. set the dividers */ | ||
110 | for (i = 0; i < ARRAY_SIZE(rate->divs); i++) { | ||
111 | const struct rockchip_cpuclk_clksel *clksel = &rate->divs[i]; | ||
112 | |||
113 | if (!clksel->reg) | ||
114 | continue; | ||
115 | |||
116 | pr_debug("%s: setting reg 0x%x to 0x%x\n", | ||
117 | __func__, clksel->reg, clksel->val); | ||
118 | writel(clksel->val , cpuclk->reg_base + clksel->reg); | ||
119 | } | ||
120 | } | ||
121 | |||
122 | static int rockchip_cpuclk_pre_rate_change(struct rockchip_cpuclk *cpuclk, | ||
123 | struct clk_notifier_data *ndata) | ||
124 | { | ||
125 | const struct rockchip_cpuclk_reg_data *reg_data = cpuclk->reg_data; | ||
126 | unsigned long alt_prate, alt_div; | ||
127 | |||
128 | alt_prate = clk_get_rate(cpuclk->alt_parent); | ||
129 | |||
130 | spin_lock(cpuclk->lock); | ||
131 | |||
132 | /* | ||
133 | * If the old parent clock speed is less than the clock speed | ||
134 | * of the alternate parent, then it should be ensured that at no point | ||
135 | * the armclk speed is more than the old_rate until the dividers are | ||
136 | * set. | ||
137 | */ | ||
138 | if (alt_prate > ndata->old_rate) { | ||
139 | /* calculate dividers */ | ||
140 | alt_div = DIV_ROUND_UP(alt_prate, ndata->old_rate) - 1; | ||
141 | if (alt_div > reg_data->div_core_mask) { | ||
142 | pr_warn("%s: limiting alt-divider %lu to %d\n", | ||
143 | __func__, alt_div, reg_data->div_core_mask); | ||
144 | alt_div = reg_data->div_core_mask; | ||
145 | } | ||
146 | |||
147 | /* | ||
148 | * Change parents and add dividers in a single transaction. | ||
149 | * | ||
150 | * NOTE: we do this in a single transaction so we're never | ||
151 | * dividing the primary parent by the extra dividers that were | ||
152 | * needed for the alt. | ||
153 | */ | ||
154 | pr_debug("%s: setting div %lu as alt-rate %lu > old-rate %lu\n", | ||
155 | __func__, alt_div, alt_prate, ndata->old_rate); | ||
156 | |||
157 | writel(HIWORD_UPDATE(alt_div, reg_data->div_core_mask, | ||
158 | reg_data->div_core_shift) | | ||
159 | HIWORD_UPDATE(1, 1, reg_data->mux_core_shift), | ||
160 | cpuclk->reg_base + reg_data->core_reg); | ||
161 | } else { | ||
162 | /* select alternate parent */ | ||
163 | writel(HIWORD_UPDATE(1, 1, reg_data->mux_core_shift), | ||
164 | cpuclk->reg_base + reg_data->core_reg); | ||
165 | } | ||
166 | |||
167 | spin_unlock(cpuclk->lock); | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static int rockchip_cpuclk_post_rate_change(struct rockchip_cpuclk *cpuclk, | ||
172 | struct clk_notifier_data *ndata) | ||
173 | { | ||
174 | const struct rockchip_cpuclk_reg_data *reg_data = cpuclk->reg_data; | ||
175 | const struct rockchip_cpuclk_rate_table *rate; | ||
176 | |||
177 | rate = rockchip_get_cpuclk_settings(cpuclk, ndata->new_rate); | ||
178 | if (!rate) { | ||
179 | pr_err("%s: Invalid rate : %lu for cpuclk\n", | ||
180 | __func__, ndata->new_rate); | ||
181 | return -EINVAL; | ||
182 | } | ||
183 | |||
184 | spin_lock(cpuclk->lock); | ||
185 | |||
186 | if (ndata->old_rate < ndata->new_rate) | ||
187 | rockchip_cpuclk_set_dividers(cpuclk, rate); | ||
188 | |||
189 | /* | ||
190 | * post-rate change event, re-mux to primary parent and remove dividers. | ||
191 | * | ||
192 | * NOTE: we do this in a single transaction so we're never dividing the | ||
193 | * primary parent by the extra dividers that were needed for the alt. | ||
194 | */ | ||
195 | |||
196 | writel(HIWORD_UPDATE(0, reg_data->div_core_mask, | ||
197 | reg_data->div_core_shift) | | ||
198 | HIWORD_UPDATE(0, 1, reg_data->mux_core_shift), | ||
199 | cpuclk->reg_base + reg_data->core_reg); | ||
200 | |||
201 | if (ndata->old_rate > ndata->new_rate) | ||
202 | rockchip_cpuclk_set_dividers(cpuclk, rate); | ||
203 | |||
204 | spin_unlock(cpuclk->lock); | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | /* | ||
209 | * This clock notifier is called when the frequency of the parent clock | ||
210 | * of cpuclk is to be changed. This notifier handles the setting up all | ||
211 | * the divider clocks, remux to temporary parent and handling the safe | ||
212 | * frequency levels when using temporary parent. | ||
213 | */ | ||
214 | static int rockchip_cpuclk_notifier_cb(struct notifier_block *nb, | ||
215 | unsigned long event, void *data) | ||
216 | { | ||
217 | struct clk_notifier_data *ndata = data; | ||
218 | struct rockchip_cpuclk *cpuclk = to_rockchip_cpuclk_nb(nb); | ||
219 | int ret = 0; | ||
220 | |||
221 | pr_debug("%s: event %lu, old_rate %lu, new_rate: %lu\n", | ||
222 | __func__, event, ndata->old_rate, ndata->new_rate); | ||
223 | if (event == PRE_RATE_CHANGE) | ||
224 | ret = rockchip_cpuclk_pre_rate_change(cpuclk, ndata); | ||
225 | else if (event == POST_RATE_CHANGE) | ||
226 | ret = rockchip_cpuclk_post_rate_change(cpuclk, ndata); | ||
227 | |||
228 | return notifier_from_errno(ret); | ||
229 | } | ||
230 | |||
231 | struct clk *rockchip_clk_register_cpuclk(const char *name, | ||
232 | const char **parent_names, u8 num_parents, | ||
233 | const struct rockchip_cpuclk_reg_data *reg_data, | ||
234 | const struct rockchip_cpuclk_rate_table *rates, | ||
235 | int nrates, void __iomem *reg_base, spinlock_t *lock) | ||
236 | { | ||
237 | struct rockchip_cpuclk *cpuclk; | ||
238 | struct clk_init_data init; | ||
239 | struct clk *clk, *cclk; | ||
240 | int ret; | ||
241 | |||
242 | if (num_parents != 2) { | ||
243 | pr_err("%s: needs two parent clocks\n", __func__); | ||
244 | return ERR_PTR(-EINVAL); | ||
245 | } | ||
246 | |||
247 | cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL); | ||
248 | if (!cpuclk) | ||
249 | return ERR_PTR(-ENOMEM); | ||
250 | |||
251 | init.name = name; | ||
252 | init.parent_names = &parent_names[0]; | ||
253 | init.num_parents = 1; | ||
254 | init.ops = &rockchip_cpuclk_ops; | ||
255 | |||
256 | /* only allow rate changes when we have a rate table */ | ||
257 | init.flags = (nrates > 0) ? CLK_SET_RATE_PARENT : 0; | ||
258 | |||
259 | /* disallow automatic parent changes by ccf */ | ||
260 | init.flags |= CLK_SET_RATE_NO_REPARENT; | ||
261 | |||
262 | init.flags |= CLK_GET_RATE_NOCACHE; | ||
263 | |||
264 | cpuclk->reg_base = reg_base; | ||
265 | cpuclk->lock = lock; | ||
266 | cpuclk->reg_data = reg_data; | ||
267 | cpuclk->clk_nb.notifier_call = rockchip_cpuclk_notifier_cb; | ||
268 | cpuclk->hw.init = &init; | ||
269 | |||
270 | cpuclk->alt_parent = __clk_lookup(parent_names[1]); | ||
271 | if (!cpuclk->alt_parent) { | ||
272 | pr_err("%s: could not lookup alternate parent\n", | ||
273 | __func__); | ||
274 | ret = -EINVAL; | ||
275 | goto free_cpuclk; | ||
276 | } | ||
277 | |||
278 | ret = clk_prepare_enable(cpuclk->alt_parent); | ||
279 | if (ret) { | ||
280 | pr_err("%s: could not enable alternate parent\n", | ||
281 | __func__); | ||
282 | goto free_cpuclk; | ||
283 | } | ||
284 | |||
285 | clk = __clk_lookup(parent_names[0]); | ||
286 | if (!clk) { | ||
287 | pr_err("%s: could not lookup parent clock %s\n", | ||
288 | __func__, parent_names[0]); | ||
289 | ret = -EINVAL; | ||
290 | goto free_cpuclk; | ||
291 | } | ||
292 | |||
293 | ret = clk_notifier_register(clk, &cpuclk->clk_nb); | ||
294 | if (ret) { | ||
295 | pr_err("%s: failed to register clock notifier for %s\n", | ||
296 | __func__, name); | ||
297 | goto free_cpuclk; | ||
298 | } | ||
299 | |||
300 | if (nrates > 0) { | ||
301 | cpuclk->rate_count = nrates; | ||
302 | cpuclk->rate_table = kmemdup(rates, | ||
303 | sizeof(*rates) * nrates, | ||
304 | GFP_KERNEL); | ||
305 | if (!cpuclk->rate_table) { | ||
306 | pr_err("%s: could not allocate memory for cpuclk rates\n", | ||
307 | __func__); | ||
308 | ret = -ENOMEM; | ||
309 | goto unregister_notifier; | ||
310 | } | ||
311 | } | ||
312 | |||
313 | cclk = clk_register(NULL, &cpuclk->hw); | ||
314 | if (IS_ERR(clk)) { | ||
315 | pr_err("%s: could not register cpuclk %s\n", __func__, name); | ||
316 | ret = PTR_ERR(clk); | ||
317 | goto free_rate_table; | ||
318 | } | ||
319 | |||
320 | return cclk; | ||
321 | |||
322 | free_rate_table: | ||
323 | kfree(cpuclk->rate_table); | ||
324 | unregister_notifier: | ||
325 | clk_notifier_unregister(clk, &cpuclk->clk_nb); | ||
326 | free_cpuclk: | ||
327 | kfree(cpuclk); | ||
328 | return ERR_PTR(ret); | ||
329 | } | ||
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index f2a1c7abf4d9..a3e886a38480 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c | |||
@@ -34,7 +34,6 @@ struct rockchip_clk_pll { | |||
34 | const struct clk_ops *pll_mux_ops; | 34 | const struct clk_ops *pll_mux_ops; |
35 | 35 | ||
36 | struct notifier_block clk_nb; | 36 | struct notifier_block clk_nb; |
37 | bool rate_change_remuxed; | ||
38 | 37 | ||
39 | void __iomem *reg_base; | 38 | void __iomem *reg_base; |
40 | int lock_offset; | 39 | int lock_offset; |
@@ -109,38 +108,6 @@ static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll) | |||
109 | } | 108 | } |
110 | 109 | ||
111 | /** | 110 | /** |
112 | * Set pll mux when changing the pll rate. | ||
113 | * This makes sure to move the pll mux away from the actual pll before | ||
114 | * changing its rate and back to the original parent after the change. | ||
115 | */ | ||
116 | static int rockchip_pll_notifier_cb(struct notifier_block *nb, | ||
117 | unsigned long event, void *data) | ||
118 | { | ||
119 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll_nb(nb); | ||
120 | struct clk_mux *pll_mux = &pll->pll_mux; | ||
121 | const struct clk_ops *pll_mux_ops = pll->pll_mux_ops; | ||
122 | int cur_parent; | ||
123 | |||
124 | switch (event) { | ||
125 | case PRE_RATE_CHANGE: | ||
126 | cur_parent = pll_mux_ops->get_parent(&pll_mux->hw); | ||
127 | if (cur_parent == PLL_MODE_NORM) { | ||
128 | pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW); | ||
129 | pll->rate_change_remuxed = 1; | ||
130 | } | ||
131 | break; | ||
132 | case POST_RATE_CHANGE: | ||
133 | if (pll->rate_change_remuxed) { | ||
134 | pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM); | ||
135 | pll->rate_change_remuxed = 0; | ||
136 | } | ||
137 | break; | ||
138 | } | ||
139 | |||
140 | return NOTIFY_OK; | ||
141 | } | ||
142 | |||
143 | /** | ||
144 | * PLL used in RK3066, RK3188 and RK3288 | 111 | * PLL used in RK3066, RK3188 and RK3288 |
145 | */ | 112 | */ |
146 | 113 | ||
@@ -194,6 +161,10 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate, | |||
194 | const struct rockchip_pll_rate_table *rate; | 161 | const struct rockchip_pll_rate_table *rate; |
195 | unsigned long old_rate = rockchip_rk3066_pll_recalc_rate(hw, prate); | 162 | unsigned long old_rate = rockchip_rk3066_pll_recalc_rate(hw, prate); |
196 | struct regmap *grf = rockchip_clk_get_grf(); | 163 | struct regmap *grf = rockchip_clk_get_grf(); |
164 | struct clk_mux *pll_mux = &pll->pll_mux; | ||
165 | const struct clk_ops *pll_mux_ops = pll->pll_mux_ops; | ||
166 | int rate_change_remuxed = 0; | ||
167 | int cur_parent; | ||
197 | int ret; | 168 | int ret; |
198 | 169 | ||
199 | if (IS_ERR(grf)) { | 170 | if (IS_ERR(grf)) { |
@@ -216,6 +187,12 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate, | |||
216 | pr_debug("%s: rate settings for %lu (nr, no, nf): (%d, %d, %d)\n", | 187 | pr_debug("%s: rate settings for %lu (nr, no, nf): (%d, %d, %d)\n", |
217 | __func__, rate->rate, rate->nr, rate->no, rate->nf); | 188 | __func__, rate->rate, rate->nr, rate->no, rate->nf); |
218 | 189 | ||
190 | cur_parent = pll_mux_ops->get_parent(&pll_mux->hw); | ||
191 | if (cur_parent == PLL_MODE_NORM) { | ||
192 | pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW); | ||
193 | rate_change_remuxed = 1; | ||
194 | } | ||
195 | |||
219 | /* enter reset mode */ | 196 | /* enter reset mode */ |
220 | writel(HIWORD_UPDATE(RK3066_PLLCON3_RESET, RK3066_PLLCON3_RESET, 0), | 197 | writel(HIWORD_UPDATE(RK3066_PLLCON3_RESET, RK3066_PLLCON3_RESET, 0), |
221 | pll->reg_base + RK3066_PLLCON(3)); | 198 | pll->reg_base + RK3066_PLLCON(3)); |
@@ -247,6 +224,9 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate, | |||
247 | rockchip_rk3066_pll_set_rate(hw, old_rate, prate); | 224 | rockchip_rk3066_pll_set_rate(hw, old_rate, prate); |
248 | } | 225 | } |
249 | 226 | ||
227 | if (rate_change_remuxed) | ||
228 | pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM); | ||
229 | |||
250 | return ret; | 230 | return ret; |
251 | } | 231 | } |
252 | 232 | ||
@@ -310,7 +290,6 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, | |||
310 | struct clk_mux *pll_mux; | 290 | struct clk_mux *pll_mux; |
311 | struct clk *pll_clk, *mux_clk; | 291 | struct clk *pll_clk, *mux_clk; |
312 | char pll_name[20]; | 292 | char pll_name[20]; |
313 | int ret; | ||
314 | 293 | ||
315 | if (num_parents != 2) { | 294 | if (num_parents != 2) { |
316 | pr_err("%s: needs two parent clocks\n", __func__); | 295 | pr_err("%s: needs two parent clocks\n", __func__); |
@@ -367,7 +346,6 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, | |||
367 | pll->lock_offset = grf_lock_offset; | 346 | pll->lock_offset = grf_lock_offset; |
368 | pll->lock_shift = lock_shift; | 347 | pll->lock_shift = lock_shift; |
369 | pll->lock = lock; | 348 | pll->lock = lock; |
370 | pll->clk_nb.notifier_call = rockchip_pll_notifier_cb; | ||
371 | 349 | ||
372 | pll_clk = clk_register(NULL, &pll->hw); | 350 | pll_clk = clk_register(NULL, &pll->hw); |
373 | if (IS_ERR(pll_clk)) { | 351 | if (IS_ERR(pll_clk)) { |
@@ -377,14 +355,6 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, | |||
377 | goto err_pll; | 355 | goto err_pll; |
378 | } | 356 | } |
379 | 357 | ||
380 | ret = clk_notifier_register(pll_clk, &pll->clk_nb); | ||
381 | if (ret) { | ||
382 | pr_err("%s: failed to register clock notifier for %s : %d\n", | ||
383 | __func__, name, ret); | ||
384 | mux_clk = ERR_PTR(ret); | ||
385 | goto err_pll_notifier; | ||
386 | } | ||
387 | |||
388 | /* create the mux on top of the real pll */ | 358 | /* create the mux on top of the real pll */ |
389 | pll->pll_mux_ops = &clk_mux_ops; | 359 | pll->pll_mux_ops = &clk_mux_ops; |
390 | pll_mux = &pll->pll_mux; | 360 | pll_mux = &pll->pll_mux; |
@@ -417,13 +387,6 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, | |||
417 | return mux_clk; | 387 | return mux_clk; |
418 | 388 | ||
419 | err_mux: | 389 | err_mux: |
420 | ret = clk_notifier_unregister(pll_clk, &pll->clk_nb); | ||
421 | if (ret) { | ||
422 | pr_err("%s: could not unregister clock notifier in error path : %d\n", | ||
423 | __func__, ret); | ||
424 | return mux_clk; | ||
425 | } | ||
426 | err_pll_notifier: | ||
427 | clk_unregister(pll_clk); | 390 | clk_unregister(pll_clk); |
428 | err_pll: | 391 | err_pll: |
429 | kfree(pll); | 392 | kfree(pll); |
diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index a83a6d8d0fb6..beed49c79126 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <dt-bindings/clock/rk3188-cru-common.h> | 19 | #include <dt-bindings/clock/rk3188-cru-common.h> |
20 | #include "clk.h" | 20 | #include "clk.h" |
21 | 21 | ||
22 | #define RK3066_GRF_SOC_STATUS 0x15c | ||
22 | #define RK3188_GRF_SOC_STATUS 0xac | 23 | #define RK3188_GRF_SOC_STATUS 0xac |
23 | 24 | ||
24 | enum rk3188_plls { | 25 | enum rk3188_plls { |
@@ -100,6 +101,98 @@ struct rockchip_pll_rate_table rk3188_pll_rates[] = { | |||
100 | { /* sentinel */ }, | 101 | { /* sentinel */ }, |
101 | }; | 102 | }; |
102 | 103 | ||
104 | #define RK3066_DIV_CORE_PERIPH_MASK 0x3 | ||
105 | #define RK3066_DIV_CORE_PERIPH_SHIFT 6 | ||
106 | #define RK3066_DIV_ACLK_CORE_MASK 0x7 | ||
107 | #define RK3066_DIV_ACLK_CORE_SHIFT 0 | ||
108 | #define RK3066_DIV_ACLK_HCLK_MASK 0x3 | ||
109 | #define RK3066_DIV_ACLK_HCLK_SHIFT 8 | ||
110 | #define RK3066_DIV_ACLK_PCLK_MASK 0x3 | ||
111 | #define RK3066_DIV_ACLK_PCLK_SHIFT 12 | ||
112 | #define RK3066_DIV_AHB2APB_MASK 0x3 | ||
113 | #define RK3066_DIV_AHB2APB_SHIFT 14 | ||
114 | |||
115 | #define RK3066_CLKSEL0(_core_peri) \ | ||
116 | { \ | ||
117 | .reg = RK2928_CLKSEL_CON(0), \ | ||
118 | .val = HIWORD_UPDATE(_core_peri, RK3066_DIV_CORE_PERIPH_MASK, \ | ||
119 | RK3066_DIV_CORE_PERIPH_SHIFT) \ | ||
120 | } | ||
121 | #define RK3066_CLKSEL1(_aclk_core, _aclk_hclk, _aclk_pclk, _ahb2apb) \ | ||
122 | { \ | ||
123 | .reg = RK2928_CLKSEL_CON(1), \ | ||
124 | .val = HIWORD_UPDATE(_aclk_core, RK3066_DIV_ACLK_CORE_MASK, \ | ||
125 | RK3066_DIV_ACLK_CORE_SHIFT) | \ | ||
126 | HIWORD_UPDATE(_aclk_hclk, RK3066_DIV_ACLK_HCLK_MASK, \ | ||
127 | RK3066_DIV_ACLK_HCLK_SHIFT) | \ | ||
128 | HIWORD_UPDATE(_aclk_pclk, RK3066_DIV_ACLK_PCLK_MASK, \ | ||
129 | RK3066_DIV_ACLK_PCLK_SHIFT) | \ | ||
130 | HIWORD_UPDATE(_ahb2apb, RK3066_DIV_AHB2APB_MASK, \ | ||
131 | RK3066_DIV_AHB2APB_SHIFT), \ | ||
132 | } | ||
133 | |||
134 | #define RK3066_CPUCLK_RATE(_prate, _core_peri, _acore, _ahclk, _apclk, _h2p) \ | ||
135 | { \ | ||
136 | .prate = _prate, \ | ||
137 | .divs = { \ | ||
138 | RK3066_CLKSEL0(_core_peri), \ | ||
139 | RK3066_CLKSEL1(_acore, _ahclk, _apclk, _h2p), \ | ||
140 | }, \ | ||
141 | } | ||
142 | |||
143 | static struct rockchip_cpuclk_rate_table rk3066_cpuclk_rates[] __initdata = { | ||
144 | RK3066_CPUCLK_RATE(1416000000, 2, 3, 1, 2, 1), | ||
145 | RK3066_CPUCLK_RATE(1200000000, 2, 3, 1, 2, 1), | ||
146 | RK3066_CPUCLK_RATE(1008000000, 2, 2, 1, 2, 1), | ||
147 | RK3066_CPUCLK_RATE( 816000000, 2, 2, 1, 2, 1), | ||
148 | RK3066_CPUCLK_RATE( 600000000, 1, 2, 1, 2, 1), | ||
149 | RK3066_CPUCLK_RATE( 504000000, 1, 1, 1, 2, 1), | ||
150 | RK3066_CPUCLK_RATE( 312000000, 0, 1, 1, 1, 0), | ||
151 | }; | ||
152 | |||
153 | static const struct rockchip_cpuclk_reg_data rk3066_cpuclk_data = { | ||
154 | .core_reg = RK2928_CLKSEL_CON(0), | ||
155 | .div_core_shift = 0, | ||
156 | .div_core_mask = 0x1f, | ||
157 | .mux_core_shift = 8, | ||
158 | }; | ||
159 | |||
160 | #define RK3188_DIV_ACLK_CORE_MASK 0x7 | ||
161 | #define RK3188_DIV_ACLK_CORE_SHIFT 3 | ||
162 | |||
163 | #define RK3188_CLKSEL1(_aclk_core) \ | ||
164 | { \ | ||
165 | .reg = RK2928_CLKSEL_CON(1), \ | ||
166 | .val = HIWORD_UPDATE(_aclk_core, RK3188_DIV_ACLK_CORE_MASK,\ | ||
167 | RK3188_DIV_ACLK_CORE_SHIFT) \ | ||
168 | } | ||
169 | #define RK3188_CPUCLK_RATE(_prate, _core_peri, _aclk_core) \ | ||
170 | { \ | ||
171 | .prate = _prate, \ | ||
172 | .divs = { \ | ||
173 | RK3066_CLKSEL0(_core_peri), \ | ||
174 | RK3188_CLKSEL1(_aclk_core), \ | ||
175 | }, \ | ||
176 | } | ||
177 | |||
178 | static struct rockchip_cpuclk_rate_table rk3188_cpuclk_rates[] __initdata = { | ||
179 | RK3188_CPUCLK_RATE(1608000000, 2, 3), | ||
180 | RK3188_CPUCLK_RATE(1416000000, 2, 3), | ||
181 | RK3188_CPUCLK_RATE(1200000000, 2, 3), | ||
182 | RK3188_CPUCLK_RATE(1008000000, 2, 3), | ||
183 | RK3188_CPUCLK_RATE( 816000000, 2, 3), | ||
184 | RK3188_CPUCLK_RATE( 600000000, 1, 3), | ||
185 | RK3188_CPUCLK_RATE( 504000000, 1, 3), | ||
186 | RK3188_CPUCLK_RATE( 312000000, 0, 1), | ||
187 | }; | ||
188 | |||
189 | static const struct rockchip_cpuclk_reg_data rk3188_cpuclk_data = { | ||
190 | .core_reg = RK2928_CLKSEL_CON(0), | ||
191 | .div_core_shift = 9, | ||
192 | .div_core_mask = 0x1f, | ||
193 | .mux_core_shift = 8, | ||
194 | }; | ||
195 | |||
103 | PNAME(mux_pll_p) = { "xin24m", "xin32k" }; | 196 | PNAME(mux_pll_p) = { "xin24m", "xin32k" }; |
104 | PNAME(mux_armclk_p) = { "apll", "gpll_armclk" }; | 197 | PNAME(mux_armclk_p) = { "apll", "gpll_armclk" }; |
105 | PNAME(mux_ddrphy_p) = { "dpll", "gpll_ddr" }; | 198 | PNAME(mux_ddrphy_p) = { "dpll", "gpll_ddr" }; |
@@ -173,17 +266,10 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { | |||
173 | GATE(0, "aclk_cpu", "aclk_cpu_pre", 0, | 266 | GATE(0, "aclk_cpu", "aclk_cpu_pre", 0, |
174 | RK2928_CLKGATE_CON(0), 3, GFLAGS), | 267 | RK2928_CLKGATE_CON(0), 3, GFLAGS), |
175 | 268 | ||
176 | DIV(0, "pclk_cpu_pre", "aclk_cpu_pre", 0, | ||
177 | RK2928_CLKSEL_CON(1), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), | ||
178 | GATE(0, "atclk_cpu", "pclk_cpu_pre", 0, | 269 | GATE(0, "atclk_cpu", "pclk_cpu_pre", 0, |
179 | RK2928_CLKGATE_CON(0), 6, GFLAGS), | 270 | RK2928_CLKGATE_CON(0), 6, GFLAGS), |
180 | GATE(0, "pclk_cpu", "pclk_cpu_pre", 0, | 271 | GATE(0, "pclk_cpu", "pclk_cpu_pre", 0, |
181 | RK2928_CLKGATE_CON(0), 5, GFLAGS), | 272 | RK2928_CLKGATE_CON(0), 5, GFLAGS), |
182 | DIV(0, "hclk_cpu_pre", "aclk_cpu_pre", 0, | ||
183 | RK2928_CLKSEL_CON(1), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), | ||
184 | COMPOSITE_NOMUX(0, "hclk_ahb2apb", "hclk_cpu_pre", 0, | ||
185 | RK2928_CLKSEL_CON(1), 14, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, | ||
186 | RK2928_CLKGATE_CON(4), 9, GFLAGS), | ||
187 | GATE(0, "hclk_cpu", "hclk_cpu_pre", 0, | 273 | GATE(0, "hclk_cpu", "hclk_cpu_pre", 0, |
188 | RK2928_CLKGATE_CON(0), 4, GFLAGS), | 274 | RK2928_CLKGATE_CON(0), 4, GFLAGS), |
189 | 275 | ||
@@ -412,10 +498,18 @@ static struct clk_div_table div_aclk_cpu_t[] = { | |||
412 | }; | 498 | }; |
413 | 499 | ||
414 | static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = { | 500 | static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = { |
415 | COMPOSITE_NOGATE(0, "armclk", mux_armclk_p, 0, | ||
416 | RK2928_CLKSEL_CON(0), 8, 1, MFLAGS, 0, 5, DFLAGS), | ||
417 | DIVTBL(0, "aclk_cpu_pre", "armclk", 0, | 501 | DIVTBL(0, "aclk_cpu_pre", "armclk", 0, |
418 | RK2928_CLKSEL_CON(1), 0, 3, DFLAGS, div_aclk_cpu_t), | 502 | RK2928_CLKSEL_CON(1), 0, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, div_aclk_cpu_t), |
503 | DIV(0, "pclk_cpu_pre", "aclk_cpu_pre", 0, | ||
504 | RK2928_CLKSEL_CON(1), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO | ||
505 | | CLK_DIVIDER_READ_ONLY), | ||
506 | DIV(0, "hclk_cpu_pre", "aclk_cpu_pre", 0, | ||
507 | RK2928_CLKSEL_CON(1), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO | ||
508 | | CLK_DIVIDER_READ_ONLY), | ||
509 | COMPOSITE_NOMUX(0, "hclk_ahb2apb", "hclk_cpu_pre", 0, | ||
510 | RK2928_CLKSEL_CON(1), 14, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO | ||
511 | | CLK_DIVIDER_READ_ONLY, | ||
512 | RK2928_CLKGATE_CON(4), 9, GFLAGS), | ||
419 | 513 | ||
420 | GATE(CORE_L2C, "core_l2c", "aclk_cpu", 0, | 514 | GATE(CORE_L2C, "core_l2c", "aclk_cpu", 0, |
421 | RK2928_CLKGATE_CON(9), 4, GFLAGS), | 515 | RK2928_CLKGATE_CON(9), 4, GFLAGS), |
@@ -524,8 +618,6 @@ PNAME(mux_hsicphy_p) = { "sclk_otgphy0", "sclk_otgphy1", | |||
524 | "gpll", "cpll" }; | 618 | "gpll", "cpll" }; |
525 | 619 | ||
526 | static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { | 620 | static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { |
527 | COMPOSITE_NOGATE(0, "armclk", mux_armclk_p, 0, | ||
528 | RK2928_CLKSEL_CON(0), 8, 1, MFLAGS, 9, 5, DFLAGS), | ||
529 | COMPOSITE_NOMUX_DIVTBL(0, "aclk_core", "armclk", 0, | 621 | COMPOSITE_NOMUX_DIVTBL(0, "aclk_core", "armclk", 0, |
530 | RK2928_CLKSEL_CON(1), 3, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, | 622 | RK2928_CLKSEL_CON(1), 3, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, |
531 | div_rk3188_aclk_core_t, RK2928_CLKGATE_CON(0), 7, GFLAGS), | 623 | div_rk3188_aclk_core_t, RK2928_CLKGATE_CON(0), 7, GFLAGS), |
@@ -533,6 +625,13 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { | |||
533 | /* do not source aclk_cpu_pre from the apll, to keep complexity down */ | 625 | /* do not source aclk_cpu_pre from the apll, to keep complexity down */ |
534 | COMPOSITE_NOGATE(0, "aclk_cpu_pre", mux_aclk_cpu_p, CLK_SET_RATE_NO_REPARENT, | 626 | COMPOSITE_NOGATE(0, "aclk_cpu_pre", mux_aclk_cpu_p, CLK_SET_RATE_NO_REPARENT, |
535 | RK2928_CLKSEL_CON(0), 5, 1, MFLAGS, 0, 5, DFLAGS), | 627 | RK2928_CLKSEL_CON(0), 5, 1, MFLAGS, 0, 5, DFLAGS), |
628 | DIV(0, "pclk_cpu_pre", "aclk_cpu_pre", 0, | ||
629 | RK2928_CLKSEL_CON(1), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), | ||
630 | DIV(0, "hclk_cpu_pre", "aclk_cpu_pre", 0, | ||
631 | RK2928_CLKSEL_CON(1), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), | ||
632 | COMPOSITE_NOMUX(0, "hclk_ahb2apb", "hclk_cpu_pre", 0, | ||
633 | RK2928_CLKSEL_CON(1), 14, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, | ||
634 | RK2928_CLKGATE_CON(4), 9, GFLAGS), | ||
536 | 635 | ||
537 | GATE(CORE_L2C, "core_l2c", "armclk", 0, | 636 | GATE(CORE_L2C, "core_l2c", "armclk", 0, |
538 | RK2928_CLKGATE_CON(9), 4, GFLAGS), | 637 | RK2928_CLKGATE_CON(9), 4, GFLAGS), |
@@ -599,6 +698,12 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { | |||
599 | GATE(ACLK_GPS, "aclk_gps", "aclk_peri", 0, RK2928_CLKGATE_CON(8), 13, GFLAGS), | 698 | GATE(ACLK_GPS, "aclk_gps", "aclk_peri", 0, RK2928_CLKGATE_CON(8), 13, GFLAGS), |
600 | }; | 699 | }; |
601 | 700 | ||
701 | static const char *rk3188_critical_clocks[] __initconst = { | ||
702 | "aclk_cpu", | ||
703 | "aclk_peri", | ||
704 | "hclk_peri", | ||
705 | }; | ||
706 | |||
602 | static void __init rk3188_common_clk_init(struct device_node *np) | 707 | static void __init rk3188_common_clk_init(struct device_node *np) |
603 | { | 708 | { |
604 | void __iomem *reg_base; | 709 | void __iomem *reg_base; |
@@ -623,29 +728,65 @@ static void __init rk3188_common_clk_init(struct device_node *np) | |||
623 | pr_warn("%s: could not register clock usb480m: %ld\n", | 728 | pr_warn("%s: could not register clock usb480m: %ld\n", |
624 | __func__, PTR_ERR(clk)); | 729 | __func__, PTR_ERR(clk)); |
625 | 730 | ||
626 | rockchip_clk_register_plls(rk3188_pll_clks, | ||
627 | ARRAY_SIZE(rk3188_pll_clks), | ||
628 | RK3188_GRF_SOC_STATUS); | ||
629 | rockchip_clk_register_branches(common_clk_branches, | 731 | rockchip_clk_register_branches(common_clk_branches, |
630 | ARRAY_SIZE(common_clk_branches)); | 732 | ARRAY_SIZE(common_clk_branches)); |
733 | rockchip_clk_protect_critical(rk3188_critical_clocks, | ||
734 | ARRAY_SIZE(rk3188_critical_clocks)); | ||
631 | 735 | ||
632 | rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0), | 736 | rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0), |
633 | ROCKCHIP_SOFTRST_HIWORD_MASK); | 737 | ROCKCHIP_SOFTRST_HIWORD_MASK); |
738 | |||
739 | rockchip_register_restart_notifier(RK2928_GLB_SRST_FST); | ||
634 | } | 740 | } |
635 | 741 | ||
636 | static void __init rk3066a_clk_init(struct device_node *np) | 742 | static void __init rk3066a_clk_init(struct device_node *np) |
637 | { | 743 | { |
638 | rk3188_common_clk_init(np); | 744 | rk3188_common_clk_init(np); |
745 | rockchip_clk_register_plls(rk3188_pll_clks, | ||
746 | ARRAY_SIZE(rk3188_pll_clks), | ||
747 | RK3066_GRF_SOC_STATUS); | ||
639 | rockchip_clk_register_branches(rk3066a_clk_branches, | 748 | rockchip_clk_register_branches(rk3066a_clk_branches, |
640 | ARRAY_SIZE(rk3066a_clk_branches)); | 749 | ARRAY_SIZE(rk3066a_clk_branches)); |
750 | rockchip_clk_register_armclk(ARMCLK, "armclk", | ||
751 | mux_armclk_p, ARRAY_SIZE(mux_armclk_p), | ||
752 | &rk3066_cpuclk_data, rk3066_cpuclk_rates, | ||
753 | ARRAY_SIZE(rk3066_cpuclk_rates)); | ||
641 | } | 754 | } |
642 | CLK_OF_DECLARE(rk3066a_cru, "rockchip,rk3066a-cru", rk3066a_clk_init); | 755 | CLK_OF_DECLARE(rk3066a_cru, "rockchip,rk3066a-cru", rk3066a_clk_init); |
643 | 756 | ||
644 | static void __init rk3188a_clk_init(struct device_node *np) | 757 | static void __init rk3188a_clk_init(struct device_node *np) |
645 | { | 758 | { |
759 | struct clk *clk1, *clk2; | ||
760 | unsigned long rate; | ||
761 | int ret; | ||
762 | |||
646 | rk3188_common_clk_init(np); | 763 | rk3188_common_clk_init(np); |
764 | rockchip_clk_register_plls(rk3188_pll_clks, | ||
765 | ARRAY_SIZE(rk3188_pll_clks), | ||
766 | RK3188_GRF_SOC_STATUS); | ||
647 | rockchip_clk_register_branches(rk3188_clk_branches, | 767 | rockchip_clk_register_branches(rk3188_clk_branches, |
648 | ARRAY_SIZE(rk3188_clk_branches)); | 768 | ARRAY_SIZE(rk3188_clk_branches)); |
769 | rockchip_clk_register_armclk(ARMCLK, "armclk", | ||
770 | mux_armclk_p, ARRAY_SIZE(mux_armclk_p), | ||
771 | &rk3188_cpuclk_data, rk3188_cpuclk_rates, | ||
772 | ARRAY_SIZE(rk3188_cpuclk_rates)); | ||
773 | |||
774 | /* reparent aclk_cpu_pre from apll */ | ||
775 | clk1 = __clk_lookup("aclk_cpu_pre"); | ||
776 | clk2 = __clk_lookup("gpll"); | ||
777 | if (clk1 && clk2) { | ||
778 | rate = clk_get_rate(clk1); | ||
779 | |||
780 | ret = clk_set_parent(clk1, clk2); | ||
781 | if (ret < 0) | ||
782 | pr_warn("%s: could not reparent aclk_cpu_pre to gpll\n", | ||
783 | __func__); | ||
784 | |||
785 | clk_set_rate(clk1, rate); | ||
786 | } else { | ||
787 | pr_warn("%s: missing clocks to reparent aclk_cpu_pre to gpll\n", | ||
788 | __func__); | ||
789 | } | ||
649 | } | 790 | } |
650 | CLK_OF_DECLARE(rk3188a_cru, "rockchip,rk3188a-cru", rk3188a_clk_init); | 791 | CLK_OF_DECLARE(rk3188a_cru, "rockchip,rk3188a-cru", rk3188a_clk_init); |
651 | 792 | ||
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index 0d8c6c59a75e..23278291da44 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c | |||
@@ -20,7 +20,7 @@ | |||
20 | #include "clk.h" | 20 | #include "clk.h" |
21 | 21 | ||
22 | #define RK3288_GRF_SOC_CON(x) (0x244 + x * 4) | 22 | #define RK3288_GRF_SOC_CON(x) (0x244 + x * 4) |
23 | #define RK3288_GRF_SOC_STATUS 0x280 | 23 | #define RK3288_GRF_SOC_STATUS1 0x284 |
24 | 24 | ||
25 | enum rk3288_plls { | 25 | enum rk3288_plls { |
26 | apll, dpll, cpll, gpll, npll, | 26 | apll, dpll, cpll, gpll, npll, |
@@ -101,6 +101,70 @@ struct rockchip_pll_rate_table rk3288_pll_rates[] = { | |||
101 | { /* sentinel */ }, | 101 | { /* sentinel */ }, |
102 | }; | 102 | }; |
103 | 103 | ||
104 | #define RK3288_DIV_ACLK_CORE_M0_MASK 0xf | ||
105 | #define RK3288_DIV_ACLK_CORE_M0_SHIFT 0 | ||
106 | #define RK3288_DIV_ACLK_CORE_MP_MASK 0xf | ||
107 | #define RK3288_DIV_ACLK_CORE_MP_SHIFT 4 | ||
108 | #define RK3288_DIV_L2RAM_MASK 0x7 | ||
109 | #define RK3288_DIV_L2RAM_SHIFT 0 | ||
110 | #define RK3288_DIV_ATCLK_MASK 0x1f | ||
111 | #define RK3288_DIV_ATCLK_SHIFT 4 | ||
112 | #define RK3288_DIV_PCLK_DBGPRE_MASK 0x1f | ||
113 | #define RK3288_DIV_PCLK_DBGPRE_SHIFT 9 | ||
114 | |||
115 | #define RK3288_CLKSEL0(_core_m0, _core_mp) \ | ||
116 | { \ | ||
117 | .reg = RK3288_CLKSEL_CON(0), \ | ||
118 | .val = HIWORD_UPDATE(_core_m0, RK3288_DIV_ACLK_CORE_M0_MASK, \ | ||
119 | RK3288_DIV_ACLK_CORE_M0_SHIFT) | \ | ||
120 | HIWORD_UPDATE(_core_mp, RK3288_DIV_ACLK_CORE_MP_MASK, \ | ||
121 | RK3288_DIV_ACLK_CORE_MP_SHIFT), \ | ||
122 | } | ||
123 | #define RK3288_CLKSEL37(_l2ram, _atclk, _pclk_dbg_pre) \ | ||
124 | { \ | ||
125 | .reg = RK3288_CLKSEL_CON(37), \ | ||
126 | .val = HIWORD_UPDATE(_l2ram, RK3288_DIV_L2RAM_MASK, \ | ||
127 | RK3288_DIV_L2RAM_SHIFT) | \ | ||
128 | HIWORD_UPDATE(_atclk, RK3288_DIV_ATCLK_MASK, \ | ||
129 | RK3288_DIV_ATCLK_SHIFT) | \ | ||
130 | HIWORD_UPDATE(_pclk_dbg_pre, \ | ||
131 | RK3288_DIV_PCLK_DBGPRE_MASK, \ | ||
132 | RK3288_DIV_PCLK_DBGPRE_SHIFT), \ | ||
133 | } | ||
134 | |||
135 | #define RK3288_CPUCLK_RATE(_prate, _core_m0, _core_mp, _l2ram, _atclk, _pdbg) \ | ||
136 | { \ | ||
137 | .prate = _prate, \ | ||
138 | .divs = { \ | ||
139 | RK3288_CLKSEL0(_core_m0, _core_mp), \ | ||
140 | RK3288_CLKSEL37(_l2ram, _atclk, _pdbg), \ | ||
141 | }, \ | ||
142 | } | ||
143 | |||
144 | static struct rockchip_cpuclk_rate_table rk3288_cpuclk_rates[] __initdata = { | ||
145 | RK3288_CPUCLK_RATE(1800000000, 2, 4, 2, 4, 4), | ||
146 | RK3288_CPUCLK_RATE(1704000000, 2, 4, 2, 4, 4), | ||
147 | RK3288_CPUCLK_RATE(1608000000, 2, 4, 2, 4, 4), | ||
148 | RK3288_CPUCLK_RATE(1512000000, 2, 4, 2, 4, 4), | ||
149 | RK3288_CPUCLK_RATE(1416000000, 2, 4, 2, 4, 4), | ||
150 | RK3288_CPUCLK_RATE(1200000000, 2, 4, 2, 4, 4), | ||
151 | RK3288_CPUCLK_RATE(1008000000, 2, 4, 2, 4, 4), | ||
152 | RK3288_CPUCLK_RATE( 816000000, 2, 4, 2, 4, 4), | ||
153 | RK3288_CPUCLK_RATE( 696000000, 2, 4, 2, 4, 4), | ||
154 | RK3288_CPUCLK_RATE( 600000000, 2, 4, 2, 4, 4), | ||
155 | RK3288_CPUCLK_RATE( 408000000, 2, 4, 2, 4, 4), | ||
156 | RK3288_CPUCLK_RATE( 312000000, 2, 4, 2, 4, 4), | ||
157 | RK3288_CPUCLK_RATE( 216000000, 2, 4, 2, 4, 4), | ||
158 | RK3288_CPUCLK_RATE( 126000000, 2, 4, 2, 4, 4), | ||
159 | }; | ||
160 | |||
161 | static const struct rockchip_cpuclk_reg_data rk3288_cpuclk_data = { | ||
162 | .core_reg = RK3288_CLKSEL_CON(0), | ||
163 | .div_core_shift = 8, | ||
164 | .div_core_mask = 0x1f, | ||
165 | .mux_core_shift = 15, | ||
166 | }; | ||
167 | |||
104 | PNAME(mux_pll_p) = { "xin24m", "xin32k" }; | 168 | PNAME(mux_pll_p) = { "xin24m", "xin32k" }; |
105 | PNAME(mux_armclk_p) = { "apll_core", "gpll_core" }; | 169 | PNAME(mux_armclk_p) = { "apll_core", "gpll_core" }; |
106 | PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" }; | 170 | PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" }; |
@@ -143,7 +207,7 @@ static struct rockchip_pll_clock rk3288_pll_clks[] __initdata = { | |||
143 | [gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3288_PLL_CON(12), | 207 | [gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3288_PLL_CON(12), |
144 | RK3288_MODE_CON, 12, 8, rk3288_pll_rates), | 208 | RK3288_MODE_CON, 12, 8, rk3288_pll_rates), |
145 | [npll] = PLL(pll_rk3066, PLL_NPLL, "npll", mux_pll_p, 0, RK3288_PLL_CON(16), | 209 | [npll] = PLL(pll_rk3066, PLL_NPLL, "npll", mux_pll_p, 0, RK3288_PLL_CON(16), |
146 | RK3288_MODE_CON, 14, 9, NULL), | 210 | RK3288_MODE_CON, 14, 9, rk3288_pll_rates), |
147 | }; | 211 | }; |
148 | 212 | ||
149 | static struct clk_div_table div_hclk_cpu_t[] = { | 213 | static struct clk_div_table div_hclk_cpu_t[] = { |
@@ -166,35 +230,33 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
166 | RK3288_CLKGATE_CON(0), 1, GFLAGS), | 230 | RK3288_CLKGATE_CON(0), 1, GFLAGS), |
167 | GATE(0, "gpll_core", "gpll", 0, | 231 | GATE(0, "gpll_core", "gpll", 0, |
168 | RK3288_CLKGATE_CON(0), 2, GFLAGS), | 232 | RK3288_CLKGATE_CON(0), 2, GFLAGS), |
169 | COMPOSITE_NOGATE(0, "armclk", mux_armclk_p, 0, | ||
170 | RK3288_CLKSEL_CON(0), 15, 1, MFLAGS, 8, 5, DFLAGS), | ||
171 | 233 | ||
172 | COMPOSITE_NOMUX(0, "armcore0", "armclk", 0, | 234 | COMPOSITE_NOMUX(0, "armcore0", "armclk", 0, |
173 | RK3288_CLKSEL_CON(36), 0, 3, DFLAGS, | 235 | RK3288_CLKSEL_CON(36), 0, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, |
174 | RK3288_CLKGATE_CON(12), 0, GFLAGS), | 236 | RK3288_CLKGATE_CON(12), 0, GFLAGS), |
175 | COMPOSITE_NOMUX(0, "armcore1", "armclk", 0, | 237 | COMPOSITE_NOMUX(0, "armcore1", "armclk", 0, |
176 | RK3288_CLKSEL_CON(36), 4, 3, DFLAGS, | 238 | RK3288_CLKSEL_CON(36), 4, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, |
177 | RK3288_CLKGATE_CON(12), 1, GFLAGS), | 239 | RK3288_CLKGATE_CON(12), 1, GFLAGS), |
178 | COMPOSITE_NOMUX(0, "armcore2", "armclk", 0, | 240 | COMPOSITE_NOMUX(0, "armcore2", "armclk", 0, |
179 | RK3288_CLKSEL_CON(36), 8, 3, DFLAGS, | 241 | RK3288_CLKSEL_CON(36), 8, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, |
180 | RK3288_CLKGATE_CON(12), 2, GFLAGS), | 242 | RK3288_CLKGATE_CON(12), 2, GFLAGS), |
181 | COMPOSITE_NOMUX(0, "armcore3", "armclk", 0, | 243 | COMPOSITE_NOMUX(0, "armcore3", "armclk", 0, |
182 | RK3288_CLKSEL_CON(36), 12, 3, DFLAGS, | 244 | RK3288_CLKSEL_CON(36), 12, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, |
183 | RK3288_CLKGATE_CON(12), 3, GFLAGS), | 245 | RK3288_CLKGATE_CON(12), 3, GFLAGS), |
184 | COMPOSITE_NOMUX(0, "l2ram", "armclk", 0, | 246 | COMPOSITE_NOMUX(0, "l2ram", "armclk", 0, |
185 | RK3288_CLKSEL_CON(37), 0, 3, DFLAGS, | 247 | RK3288_CLKSEL_CON(37), 0, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, |
186 | RK3288_CLKGATE_CON(12), 4, GFLAGS), | 248 | RK3288_CLKGATE_CON(12), 4, GFLAGS), |
187 | COMPOSITE_NOMUX(0, "aclk_core_m0", "armclk", 0, | 249 | COMPOSITE_NOMUX(0, "aclk_core_m0", "armclk", 0, |
188 | RK3288_CLKSEL_CON(0), 0, 4, DFLAGS, | 250 | RK3288_CLKSEL_CON(0), 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY, |
189 | RK3288_CLKGATE_CON(12), 5, GFLAGS), | 251 | RK3288_CLKGATE_CON(12), 5, GFLAGS), |
190 | COMPOSITE_NOMUX(0, "aclk_core_mp", "armclk", 0, | 252 | COMPOSITE_NOMUX(0, "aclk_core_mp", "armclk", 0, |
191 | RK3288_CLKSEL_CON(0), 4, 4, DFLAGS, | 253 | RK3288_CLKSEL_CON(0), 4, 4, DFLAGS | CLK_DIVIDER_READ_ONLY, |
192 | RK3288_CLKGATE_CON(12), 6, GFLAGS), | 254 | RK3288_CLKGATE_CON(12), 6, GFLAGS), |
193 | COMPOSITE_NOMUX(0, "atclk", "armclk", 0, | 255 | COMPOSITE_NOMUX(0, "atclk", "armclk", 0, |
194 | RK3288_CLKSEL_CON(37), 4, 5, DFLAGS, | 256 | RK3288_CLKSEL_CON(37), 4, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, |
195 | RK3288_CLKGATE_CON(12), 7, GFLAGS), | 257 | RK3288_CLKGATE_CON(12), 7, GFLAGS), |
196 | COMPOSITE_NOMUX(0, "pclk_dbg_pre", "armclk", 0, | 258 | COMPOSITE_NOMUX(0, "pclk_dbg_pre", "armclk", 0, |
197 | RK3288_CLKSEL_CON(37), 9, 5, DFLAGS, | 259 | RK3288_CLKSEL_CON(37), 9, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, |
198 | RK3288_CLKGATE_CON(12), 8, GFLAGS), | 260 | RK3288_CLKGATE_CON(12), 8, GFLAGS), |
199 | GATE(0, "pclk_dbg", "pclk_dbg_pre", 0, | 261 | GATE(0, "pclk_dbg", "pclk_dbg_pre", 0, |
200 | RK3288_CLKGATE_CON(12), 9, GFLAGS), | 262 | RK3288_CLKGATE_CON(12), 9, GFLAGS), |
@@ -219,12 +281,12 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
219 | RK3288_CLKSEL_CON(1), 15, 1, MFLAGS, 3, 5, DFLAGS), | 281 | RK3288_CLKSEL_CON(1), 15, 1, MFLAGS, 3, 5, DFLAGS), |
220 | DIV(0, "aclk_cpu_pre", "aclk_cpu_src", 0, | 282 | DIV(0, "aclk_cpu_pre", "aclk_cpu_src", 0, |
221 | RK3288_CLKSEL_CON(1), 0, 3, DFLAGS), | 283 | RK3288_CLKSEL_CON(1), 0, 3, DFLAGS), |
222 | GATE(0, "aclk_cpu", "aclk_cpu_pre", 0, | 284 | GATE(ACLK_CPU, "aclk_cpu", "aclk_cpu_pre", 0, |
223 | RK3288_CLKGATE_CON(0), 3, GFLAGS), | 285 | RK3288_CLKGATE_CON(0), 3, GFLAGS), |
224 | COMPOSITE_NOMUX(0, "pclk_cpu", "aclk_cpu_pre", 0, | 286 | COMPOSITE_NOMUX(PCLK_CPU, "pclk_cpu", "aclk_cpu_pre", 0, |
225 | RK3288_CLKSEL_CON(1), 12, 3, DFLAGS, | 287 | RK3288_CLKSEL_CON(1), 12, 3, DFLAGS, |
226 | RK3288_CLKGATE_CON(0), 5, GFLAGS), | 288 | RK3288_CLKGATE_CON(0), 5, GFLAGS), |
227 | COMPOSITE_NOMUX_DIVTBL(0, "hclk_cpu", "aclk_cpu_pre", 0, | 289 | COMPOSITE_NOMUX_DIVTBL(HCLK_CPU, "hclk_cpu", "aclk_cpu_pre", 0, |
228 | RK3288_CLKSEL_CON(1), 8, 2, DFLAGS, div_hclk_cpu_t, | 290 | RK3288_CLKSEL_CON(1), 8, 2, DFLAGS, div_hclk_cpu_t, |
229 | RK3288_CLKGATE_CON(0), 4, GFLAGS), | 291 | RK3288_CLKGATE_CON(0), 4, GFLAGS), |
230 | GATE(0, "c2c_host", "aclk_cpu_src", 0, | 292 | GATE(0, "c2c_host", "aclk_cpu_src", 0, |
@@ -238,15 +300,15 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
238 | COMPOSITE(0, "i2s_src", mux_pll_src_cpll_gpll_p, 0, | 300 | COMPOSITE(0, "i2s_src", mux_pll_src_cpll_gpll_p, 0, |
239 | RK3288_CLKSEL_CON(4), 15, 1, MFLAGS, 0, 7, DFLAGS, | 301 | RK3288_CLKSEL_CON(4), 15, 1, MFLAGS, 0, 7, DFLAGS, |
240 | RK3288_CLKGATE_CON(4), 1, GFLAGS), | 302 | RK3288_CLKGATE_CON(4), 1, GFLAGS), |
241 | COMPOSITE_FRAC(0, "i2s_frac", "i2s_src", 0, | 303 | COMPOSITE_FRAC(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT, |
242 | RK3288_CLKSEL_CON(8), 0, | 304 | RK3288_CLKSEL_CON(8), 0, |
243 | RK3288_CLKGATE_CON(4), 2, GFLAGS), | 305 | RK3288_CLKGATE_CON(4), 2, GFLAGS), |
244 | MUX(0, "i2s_pre", mux_i2s_pre_p, 0, | 306 | MUX(0, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT, |
245 | RK3288_CLKSEL_CON(4), 8, 2, MFLAGS), | 307 | RK3288_CLKSEL_CON(4), 8, 2, MFLAGS), |
246 | COMPOSITE_NODIV(0, "i2s0_clkout", mux_i2s_clkout_p, 0, | 308 | COMPOSITE_NODIV(0, "i2s0_clkout", mux_i2s_clkout_p, CLK_SET_RATE_PARENT, |
247 | RK3288_CLKSEL_CON(4), 12, 1, MFLAGS, | 309 | RK3288_CLKSEL_CON(4), 12, 1, MFLAGS, |
248 | RK3288_CLKGATE_CON(4), 0, GFLAGS), | 310 | RK3288_CLKGATE_CON(4), 0, GFLAGS), |
249 | GATE(SCLK_I2S0, "sclk_i2s0", "i2s_pre", 0, | 311 | GATE(SCLK_I2S0, "sclk_i2s0", "i2s_pre", CLK_SET_RATE_PARENT, |
250 | RK3288_CLKGATE_CON(4), 3, GFLAGS), | 312 | RK3288_CLKGATE_CON(4), 3, GFLAGS), |
251 | 313 | ||
252 | MUX(0, "spdif_src", mux_pll_src_cpll_gpll_p, 0, | 314 | MUX(0, "spdif_src", mux_pll_src_cpll_gpll_p, 0, |
@@ -296,6 +358,20 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
296 | COMPOSITE(0, "aclk_vdpu", mux_pll_src_cpll_gpll_usb480m_p, 0, | 358 | COMPOSITE(0, "aclk_vdpu", mux_pll_src_cpll_gpll_usb480m_p, 0, |
297 | RK3288_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS, | 359 | RK3288_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS, |
298 | RK3288_CLKGATE_CON(3), 11, GFLAGS), | 360 | RK3288_CLKGATE_CON(3), 11, GFLAGS), |
361 | /* | ||
362 | * We use aclk_vdpu by default GRF_SOC_CON0[7] setting in system, | ||
363 | * so we ignore the mux and make clocks nodes as following, | ||
364 | */ | ||
365 | GATE(ACLK_VCODEC, "aclk_vcodec", "aclk_vdpu", 0, | ||
366 | RK3288_CLKGATE_CON(9), 0, GFLAGS), | ||
367 | /* | ||
368 | * We introduce a virtul node of hclk_vodec_pre_v to split one clock | ||
369 | * struct with a gate and a fix divider into two node in software. | ||
370 | */ | ||
371 | GATE(0, "hclk_vcodec_pre_v", "aclk_vdpu", 0, | ||
372 | RK3288_CLKGATE_CON(3), 10, GFLAGS), | ||
373 | GATE(HCLK_VCODEC, "hclk_vcodec", "hclk_vcodec_pre", 0, | ||
374 | RK3288_CLKGATE_CON(9), 1, GFLAGS), | ||
299 | 375 | ||
300 | COMPOSITE(0, "aclk_vio0", mux_pll_src_cpll_gpll_usb480m_p, 0, | 376 | COMPOSITE(0, "aclk_vio0", mux_pll_src_cpll_gpll_usb480m_p, 0, |
301 | RK3288_CLKSEL_CON(31), 6, 2, MFLAGS, 0, 5, DFLAGS, | 377 | RK3288_CLKSEL_CON(31), 6, 2, MFLAGS, 0, 5, DFLAGS, |
@@ -309,7 +385,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
309 | COMPOSITE(0, "aclk_rga_pre", mux_pll_src_cpll_gpll_usb480m_p, 0, | 385 | COMPOSITE(0, "aclk_rga_pre", mux_pll_src_cpll_gpll_usb480m_p, 0, |
310 | RK3288_CLKSEL_CON(30), 6, 2, MFLAGS, 0, 5, DFLAGS, | 386 | RK3288_CLKSEL_CON(30), 6, 2, MFLAGS, 0, 5, DFLAGS, |
311 | RK3288_CLKGATE_CON(3), 5, GFLAGS), | 387 | RK3288_CLKGATE_CON(3), 5, GFLAGS), |
312 | COMPOSITE(0, "sclk_rga", mux_pll_src_cpll_gpll_usb480m_p, 0, | 388 | COMPOSITE(SCLK_RGA, "sclk_rga", mux_pll_src_cpll_gpll_usb480m_p, 0, |
313 | RK3288_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS, | 389 | RK3288_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS, |
314 | RK3288_CLKGATE_CON(3), 4, GFLAGS), | 390 | RK3288_CLKGATE_CON(3), 4, GFLAGS), |
315 | 391 | ||
@@ -320,35 +396,35 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
320 | RK3288_CLKSEL_CON(29), 6, 2, MFLAGS, 8, 8, DFLAGS, | 396 | RK3288_CLKSEL_CON(29), 6, 2, MFLAGS, 8, 8, DFLAGS, |
321 | RK3288_CLKGATE_CON(3), 3, GFLAGS), | 397 | RK3288_CLKGATE_CON(3), 3, GFLAGS), |
322 | 398 | ||
323 | COMPOSITE_NODIV(0, "sclk_edp_24m", mux_edp_24m_p, 0, | 399 | COMPOSITE_NODIV(SCLK_EDP_24M, "sclk_edp_24m", mux_edp_24m_p, 0, |
324 | RK3288_CLKSEL_CON(28), 15, 1, MFLAGS, | 400 | RK3288_CLKSEL_CON(28), 15, 1, MFLAGS, |
325 | RK3288_CLKGATE_CON(3), 12, GFLAGS), | 401 | RK3288_CLKGATE_CON(3), 12, GFLAGS), |
326 | COMPOSITE(0, "sclk_edp", mux_pll_src_cpll_gpll_npll_p, 0, | 402 | COMPOSITE(SCLK_EDP, "sclk_edp", mux_pll_src_cpll_gpll_npll_p, 0, |
327 | RK3288_CLKSEL_CON(28), 6, 2, MFLAGS, 0, 6, DFLAGS, | 403 | RK3288_CLKSEL_CON(28), 6, 2, MFLAGS, 0, 6, DFLAGS, |
328 | RK3288_CLKGATE_CON(3), 13, GFLAGS), | 404 | RK3288_CLKGATE_CON(3), 13, GFLAGS), |
329 | 405 | ||
330 | COMPOSITE(0, "sclk_isp", mux_pll_src_cpll_gpll_npll_p, 0, | 406 | COMPOSITE(SCLK_ISP, "sclk_isp", mux_pll_src_cpll_gpll_npll_p, 0, |
331 | RK3288_CLKSEL_CON(6), 6, 2, MFLAGS, 0, 6, DFLAGS, | 407 | RK3288_CLKSEL_CON(6), 6, 2, MFLAGS, 0, 6, DFLAGS, |
332 | RK3288_CLKGATE_CON(3), 14, GFLAGS), | 408 | RK3288_CLKGATE_CON(3), 14, GFLAGS), |
333 | COMPOSITE(0, "sclk_isp_jpe", mux_pll_src_cpll_gpll_npll_p, 0, | 409 | COMPOSITE(SCLK_ISP_JPE, "sclk_isp_jpe", mux_pll_src_cpll_gpll_npll_p, 0, |
334 | RK3288_CLKSEL_CON(6), 14, 2, MFLAGS, 8, 6, DFLAGS, | 410 | RK3288_CLKSEL_CON(6), 14, 2, MFLAGS, 8, 6, DFLAGS, |
335 | RK3288_CLKGATE_CON(3), 15, GFLAGS), | 411 | RK3288_CLKGATE_CON(3), 15, GFLAGS), |
336 | 412 | ||
337 | GATE(0, "sclk_hdmi_hdcp", "xin24m", 0, | 413 | GATE(SCLK_HDMI_HDCP, "sclk_hdmi_hdcp", "xin24m", 0, |
338 | RK3288_CLKGATE_CON(5), 12, GFLAGS), | 414 | RK3288_CLKGATE_CON(5), 12, GFLAGS), |
339 | GATE(0, "sclk_hdmi_cec", "xin32k", 0, | 415 | GATE(SCLK_HDMI_CEC, "sclk_hdmi_cec", "xin32k", 0, |
340 | RK3288_CLKGATE_CON(5), 11, GFLAGS), | 416 | RK3288_CLKGATE_CON(5), 11, GFLAGS), |
341 | 417 | ||
342 | COMPOSITE(0, "aclk_hevc", mux_pll_src_cpll_gpll_npll_p, 0, | 418 | COMPOSITE(ACLK_HEVC, "aclk_hevc", mux_pll_src_cpll_gpll_npll_p, 0, |
343 | RK3288_CLKSEL_CON(39), 14, 2, MFLAGS, 8, 5, DFLAGS, | 419 | RK3288_CLKSEL_CON(39), 14, 2, MFLAGS, 8, 5, DFLAGS, |
344 | RK3288_CLKGATE_CON(13), 13, GFLAGS), | 420 | RK3288_CLKGATE_CON(13), 13, GFLAGS), |
345 | DIV(0, "hclk_hevc", "aclk_hevc", 0, | 421 | DIV(HCLK_HEVC, "hclk_hevc", "aclk_hevc", 0, |
346 | RK3288_CLKSEL_CON(40), 12, 2, DFLAGS), | 422 | RK3288_CLKSEL_CON(40), 12, 2, DFLAGS), |
347 | 423 | ||
348 | COMPOSITE(0, "sclk_hevc_cabac", mux_pll_src_cpll_gpll_npll_p, 0, | 424 | COMPOSITE(SCLK_HEVC_CABAC, "sclk_hevc_cabac", mux_pll_src_cpll_gpll_npll_p, 0, |
349 | RK3288_CLKSEL_CON(42), 6, 2, MFLAGS, 0, 5, DFLAGS, | 425 | RK3288_CLKSEL_CON(42), 6, 2, MFLAGS, 0, 5, DFLAGS, |
350 | RK3288_CLKGATE_CON(13), 14, GFLAGS), | 426 | RK3288_CLKGATE_CON(13), 14, GFLAGS), |
351 | COMPOSITE(0, "sclk_hevc_core", mux_pll_src_cpll_gpll_npll_p, 0, | 427 | COMPOSITE(SCLK_HEVC_CORE, "sclk_hevc_core", mux_pll_src_cpll_gpll_npll_p, 0, |
352 | RK3288_CLKSEL_CON(42), 14, 2, MFLAGS, 8, 5, DFLAGS, | 428 | RK3288_CLKSEL_CON(42), 14, 2, MFLAGS, 8, 5, DFLAGS, |
353 | RK3288_CLKGATE_CON(13), 15, GFLAGS), | 429 | RK3288_CLKGATE_CON(13), 15, GFLAGS), |
354 | 430 | ||
@@ -371,13 +447,13 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
371 | COMPOSITE(0, "aclk_peri_src", mux_pll_src_cpll_gpll_p, 0, | 447 | COMPOSITE(0, "aclk_peri_src", mux_pll_src_cpll_gpll_p, 0, |
372 | RK3288_CLKSEL_CON(10), 15, 1, MFLAGS, 0, 5, DFLAGS, | 448 | RK3288_CLKSEL_CON(10), 15, 1, MFLAGS, 0, 5, DFLAGS, |
373 | RK3288_CLKGATE_CON(2), 0, GFLAGS), | 449 | RK3288_CLKGATE_CON(2), 0, GFLAGS), |
374 | COMPOSITE_NOMUX(0, "pclk_peri", "aclk_peri_src", 0, | 450 | COMPOSITE_NOMUX(PCLK_PERI, "pclk_peri", "aclk_peri_src", 0, |
375 | RK3288_CLKSEL_CON(10), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, | 451 | RK3288_CLKSEL_CON(10), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, |
376 | RK3288_CLKGATE_CON(2), 3, GFLAGS), | 452 | RK3288_CLKGATE_CON(2), 3, GFLAGS), |
377 | COMPOSITE_NOMUX(0, "hclk_peri", "aclk_peri_src", 0, | 453 | COMPOSITE_NOMUX(HCLK_PERI, "hclk_peri", "aclk_peri_src", 0, |
378 | RK3288_CLKSEL_CON(10), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, | 454 | RK3288_CLKSEL_CON(10), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, |
379 | RK3288_CLKGATE_CON(2), 2, GFLAGS), | 455 | RK3288_CLKGATE_CON(2), 2, GFLAGS), |
380 | GATE(0, "aclk_peri", "aclk_peri_src", 0, | 456 | GATE(ACLK_PERI, "aclk_peri", "aclk_peri_src", 0, |
381 | RK3288_CLKGATE_CON(2), 1, GFLAGS), | 457 | RK3288_CLKGATE_CON(2), 1, GFLAGS), |
382 | 458 | ||
383 | /* | 459 | /* |
@@ -545,7 +621,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
545 | GATE(PCLK_PWM, "pclk_pwm", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 0, GFLAGS), | 621 | GATE(PCLK_PWM, "pclk_pwm", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 0, GFLAGS), |
546 | GATE(PCLK_TIMER, "pclk_timer", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 1, GFLAGS), | 622 | GATE(PCLK_TIMER, "pclk_timer", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 1, GFLAGS), |
547 | GATE(PCLK_I2C0, "pclk_i2c0", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 2, GFLAGS), | 623 | GATE(PCLK_I2C0, "pclk_i2c0", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 2, GFLAGS), |
548 | GATE(PCLK_I2C1, "pclk_i2c1", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 3, GFLAGS), | 624 | GATE(PCLK_I2C2, "pclk_i2c2", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 3, GFLAGS), |
549 | GATE(0, "pclk_ddrupctl0", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 14, GFLAGS), | 625 | GATE(0, "pclk_ddrupctl0", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 14, GFLAGS), |
550 | GATE(0, "pclk_publ0", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 15, GFLAGS), | 626 | GATE(0, "pclk_publ0", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 15, GFLAGS), |
551 | GATE(0, "pclk_ddrupctl1", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 0, GFLAGS), | 627 | GATE(0, "pclk_ddrupctl1", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 0, GFLAGS), |
@@ -603,7 +679,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
603 | GATE(PCLK_I2C4, "pclk_i2c4", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 15, GFLAGS), | 679 | GATE(PCLK_I2C4, "pclk_i2c4", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 15, GFLAGS), |
604 | GATE(PCLK_UART3, "pclk_uart3", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 11, GFLAGS), | 680 | GATE(PCLK_UART3, "pclk_uart3", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 11, GFLAGS), |
605 | GATE(PCLK_UART4, "pclk_uart4", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 12, GFLAGS), | 681 | GATE(PCLK_UART4, "pclk_uart4", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 12, GFLAGS), |
606 | GATE(PCLK_I2C2, "pclk_i2c2", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 13, GFLAGS), | 682 | GATE(PCLK_I2C1, "pclk_i2c1", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 13, GFLAGS), |
607 | GATE(PCLK_I2C3, "pclk_i2c3", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 14, GFLAGS), | 683 | GATE(PCLK_I2C3, "pclk_i2c3", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 14, GFLAGS), |
608 | GATE(PCLK_SARADC, "pclk_saradc", "pclk_peri", 0, RK3288_CLKGATE_CON(7), 1, GFLAGS), | 684 | GATE(PCLK_SARADC, "pclk_saradc", "pclk_peri", 0, RK3288_CLKGATE_CON(7), 1, GFLAGS), |
609 | GATE(PCLK_TSADC, "pclk_tsadc", "pclk_peri", 0, RK3288_CLKGATE_CON(7), 2, GFLAGS), | 685 | GATE(PCLK_TSADC, "pclk_tsadc", "pclk_peri", 0, RK3288_CLKGATE_CON(7), 2, GFLAGS), |
@@ -643,34 +719,34 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
643 | GATE(HCLK_RGA, "hclk_rga", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 1, GFLAGS), | 719 | GATE(HCLK_RGA, "hclk_rga", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 1, GFLAGS), |
644 | GATE(HCLK_VOP0, "hclk_vop0", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 6, GFLAGS), | 720 | GATE(HCLK_VOP0, "hclk_vop0", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 6, GFLAGS), |
645 | GATE(HCLK_VOP1, "hclk_vop1", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 8, GFLAGS), | 721 | GATE(HCLK_VOP1, "hclk_vop1", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 8, GFLAGS), |
646 | GATE(0, "hclk_vio_ahb_arbi", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 9, GFLAGS), | 722 | GATE(HCLK_VIO_AHB_ARBI, "hclk_vio_ahb_arbi", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 9, GFLAGS), |
647 | GATE(0, "hclk_vio_niu", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 10, GFLAGS), | 723 | GATE(HCLK_VIO_NIU, "hclk_vio_niu", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 10, GFLAGS), |
648 | GATE(0, "hclk_vip", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 15, GFLAGS), | 724 | GATE(HCLK_VIP, "hclk_vip", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 15, GFLAGS), |
649 | GATE(HCLK_IEP, "hclk_iep", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 3, GFLAGS), | 725 | GATE(HCLK_IEP, "hclk_iep", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 3, GFLAGS), |
650 | GATE(HCLK_ISP, "hclk_isp", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 1, GFLAGS), | 726 | GATE(HCLK_ISP, "hclk_isp", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 1, GFLAGS), |
651 | GATE(0, "hclk_vio2_h2p", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 10, GFLAGS), | 727 | GATE(HCLK_VIO2_H2P, "hclk_vio2_h2p", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 10, GFLAGS), |
652 | GATE(0, "pclk_mipi_dsi0", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 4, GFLAGS), | 728 | GATE(PCLK_MIPI_DSI0, "pclk_mipi_dsi0", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 4, GFLAGS), |
653 | GATE(0, "pclk_mipi_dsi1", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 5, GFLAGS), | 729 | GATE(PCLK_MIPI_DSI1, "pclk_mipi_dsi1", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 5, GFLAGS), |
654 | GATE(0, "pclk_mipi_csi", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 6, GFLAGS), | 730 | GATE(PCLK_MIPI_CSI, "pclk_mipi_csi", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 6, GFLAGS), |
655 | GATE(0, "pclk_lvds_phy", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 7, GFLAGS), | 731 | GATE(PCLK_LVDS_PHY, "pclk_lvds_phy", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 7, GFLAGS), |
656 | GATE(0, "pclk_edp_ctrl", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 8, GFLAGS), | 732 | GATE(PCLK_EDP_CTRL, "pclk_edp_ctrl", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 8, GFLAGS), |
657 | GATE(0, "pclk_hdmi_ctrl", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 9, GFLAGS), | 733 | GATE(PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 9, GFLAGS), |
658 | GATE(0, "pclk_vio2_h2p", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 11, GFLAGS), | 734 | GATE(PCLK_VIO2_H2P, "pclk_vio2_h2p", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 11, GFLAGS), |
659 | 735 | ||
660 | /* aclk_vio0 gates */ | 736 | /* aclk_vio0 gates */ |
661 | GATE(ACLK_VOP0, "aclk_vop0", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 5, GFLAGS), | 737 | GATE(ACLK_VOP0, "aclk_vop0", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 5, GFLAGS), |
662 | GATE(0, "aclk_iep", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 2, GFLAGS), | 738 | GATE(ACLK_IEP, "aclk_iep", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 2, GFLAGS), |
663 | GATE(0, "aclk_vio0_niu", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 11, GFLAGS), | 739 | GATE(ACLK_VIO0_NIU, "aclk_vio0_niu", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 11, GFLAGS), |
664 | GATE(0, "aclk_vip", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 14, GFLAGS), | 740 | GATE(ACLK_VIP, "aclk_vip", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 14, GFLAGS), |
665 | 741 | ||
666 | /* aclk_vio1 gates */ | 742 | /* aclk_vio1 gates */ |
667 | GATE(ACLK_VOP1, "aclk_vop1", "aclk_vio1", 0, RK3288_CLKGATE_CON(15), 7, GFLAGS), | 743 | GATE(ACLK_VOP1, "aclk_vop1", "aclk_vio1", 0, RK3288_CLKGATE_CON(15), 7, GFLAGS), |
668 | GATE(0, "aclk_isp", "aclk_vio1", 0, RK3288_CLKGATE_CON(16), 2, GFLAGS), | 744 | GATE(ACLK_ISP, "aclk_isp", "aclk_vio1", 0, RK3288_CLKGATE_CON(16), 2, GFLAGS), |
669 | GATE(0, "aclk_vio1_niu", "aclk_vio1", 0, RK3288_CLKGATE_CON(15), 12, GFLAGS), | 745 | GATE(ACLK_VIO1_NIU, "aclk_vio1_niu", "aclk_vio1", 0, RK3288_CLKGATE_CON(15), 12, GFLAGS), |
670 | 746 | ||
671 | /* aclk_rga_pre gates */ | 747 | /* aclk_rga_pre gates */ |
672 | GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0, RK3288_CLKGATE_CON(15), 0, GFLAGS), | 748 | GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0, RK3288_CLKGATE_CON(15), 0, GFLAGS), |
673 | GATE(0, "aclk_rga_niu", "aclk_rga_pre", 0, RK3288_CLKGATE_CON(15), 13, GFLAGS), | 749 | GATE(ACLK_RGA_NIU, "aclk_rga_niu", "aclk_rga_pre", 0, RK3288_CLKGATE_CON(15), 13, GFLAGS), |
674 | 750 | ||
675 | /* | 751 | /* |
676 | * Other ungrouped clocks. | 752 | * Other ungrouped clocks. |
@@ -680,6 +756,12 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { | |||
680 | GATE(0, "pclk_isp_in", "ext_isp", 0, RK3288_CLKGATE_CON(16), 3, GFLAGS), | 756 | GATE(0, "pclk_isp_in", "ext_isp", 0, RK3288_CLKGATE_CON(16), 3, GFLAGS), |
681 | }; | 757 | }; |
682 | 758 | ||
759 | static const char *rk3288_critical_clocks[] __initconst = { | ||
760 | "aclk_cpu", | ||
761 | "aclk_peri", | ||
762 | "hclk_peri", | ||
763 | }; | ||
764 | |||
683 | static void __init rk3288_clk_init(struct device_node *np) | 765 | static void __init rk3288_clk_init(struct device_node *np) |
684 | { | 766 | { |
685 | void __iomem *reg_base; | 767 | void __iomem *reg_base; |
@@ -705,13 +787,28 @@ static void __init rk3288_clk_init(struct device_node *np) | |||
705 | pr_warn("%s: could not register clock usb480m: %ld\n", | 787 | pr_warn("%s: could not register clock usb480m: %ld\n", |
706 | __func__, PTR_ERR(clk)); | 788 | __func__, PTR_ERR(clk)); |
707 | 789 | ||
790 | clk = clk_register_fixed_factor(NULL, "hclk_vcodec_pre", | ||
791 | "hclk_vcodec_pre_v", 0, 1, 4); | ||
792 | if (IS_ERR(clk)) | ||
793 | pr_warn("%s: could not register clock hclk_vcodec_pre: %ld\n", | ||
794 | __func__, PTR_ERR(clk)); | ||
795 | |||
708 | rockchip_clk_register_plls(rk3288_pll_clks, | 796 | rockchip_clk_register_plls(rk3288_pll_clks, |
709 | ARRAY_SIZE(rk3288_pll_clks), | 797 | ARRAY_SIZE(rk3288_pll_clks), |
710 | RK3288_GRF_SOC_STATUS); | 798 | RK3288_GRF_SOC_STATUS1); |
711 | rockchip_clk_register_branches(rk3288_clk_branches, | 799 | rockchip_clk_register_branches(rk3288_clk_branches, |
712 | ARRAY_SIZE(rk3288_clk_branches)); | 800 | ARRAY_SIZE(rk3288_clk_branches)); |
801 | rockchip_clk_protect_critical(rk3288_critical_clocks, | ||
802 | ARRAY_SIZE(rk3288_critical_clocks)); | ||
713 | 803 | ||
714 | rockchip_register_softrst(np, 9, reg_base + RK3288_SOFTRST_CON(0), | 804 | rockchip_clk_register_armclk(ARMCLK, "armclk", |
805 | mux_armclk_p, ARRAY_SIZE(mux_armclk_p), | ||
806 | &rk3288_cpuclk_data, rk3288_cpuclk_rates, | ||
807 | ARRAY_SIZE(rk3288_cpuclk_rates)); | ||
808 | |||
809 | rockchip_register_softrst(np, 12, reg_base + RK3288_SOFTRST_CON(0), | ||
715 | ROCKCHIP_SOFTRST_HIWORD_MASK); | 810 | ROCKCHIP_SOFTRST_HIWORD_MASK); |
811 | |||
812 | rockchip_register_restart_notifier(RK3288_GLB_SRST_FST); | ||
716 | } | 813 | } |
717 | CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init); | 814 | CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init); |
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 278cf9dd1e23..1e68bff481b8 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/clk-provider.h> | 25 | #include <linux/clk-provider.h> |
26 | #include <linux/mfd/syscon.h> | 26 | #include <linux/mfd/syscon.h> |
27 | #include <linux/regmap.h> | 27 | #include <linux/regmap.h> |
28 | #include <linux/reboot.h> | ||
28 | #include "clk.h" | 29 | #include "clk.h" |
29 | 30 | ||
30 | /** | 31 | /** |
@@ -37,7 +38,7 @@ | |||
37 | * | 38 | * |
38 | * sometimes without one of those components. | 39 | * sometimes without one of those components. |
39 | */ | 40 | */ |
40 | struct clk *rockchip_clk_register_branch(const char *name, | 41 | static struct clk *rockchip_clk_register_branch(const char *name, |
41 | const char **parent_names, u8 num_parents, void __iomem *base, | 42 | const char **parent_names, u8 num_parents, void __iomem *base, |
42 | int muxdiv_offset, u8 mux_shift, u8 mux_width, u8 mux_flags, | 43 | int muxdiv_offset, u8 mux_shift, u8 mux_width, u8 mux_flags, |
43 | u8 div_shift, u8 div_width, u8 div_flags, | 44 | u8 div_shift, u8 div_width, u8 div_flags, |
@@ -103,6 +104,54 @@ struct clk *rockchip_clk_register_branch(const char *name, | |||
103 | return clk; | 104 | return clk; |
104 | } | 105 | } |
105 | 106 | ||
107 | static struct clk *rockchip_clk_register_frac_branch(const char *name, | ||
108 | const char **parent_names, u8 num_parents, void __iomem *base, | ||
109 | int muxdiv_offset, u8 div_flags, | ||
110 | int gate_offset, u8 gate_shift, u8 gate_flags, | ||
111 | unsigned long flags, spinlock_t *lock) | ||
112 | { | ||
113 | struct clk *clk; | ||
114 | struct clk_gate *gate = NULL; | ||
115 | struct clk_fractional_divider *div = NULL; | ||
116 | const struct clk_ops *div_ops = NULL, *gate_ops = NULL; | ||
117 | |||
118 | if (gate_offset >= 0) { | ||
119 | gate = kzalloc(sizeof(*gate), GFP_KERNEL); | ||
120 | if (!gate) | ||
121 | return ERR_PTR(-ENOMEM); | ||
122 | |||
123 | gate->flags = gate_flags; | ||
124 | gate->reg = base + gate_offset; | ||
125 | gate->bit_idx = gate_shift; | ||
126 | gate->lock = lock; | ||
127 | gate_ops = &clk_gate_ops; | ||
128 | } | ||
129 | |||
130 | if (muxdiv_offset < 0) | ||
131 | return ERR_PTR(-EINVAL); | ||
132 | |||
133 | div = kzalloc(sizeof(*div), GFP_KERNEL); | ||
134 | if (!div) | ||
135 | return ERR_PTR(-ENOMEM); | ||
136 | |||
137 | div->flags = div_flags; | ||
138 | div->reg = base + muxdiv_offset; | ||
139 | div->mshift = 16; | ||
140 | div->mmask = 0xffff0000; | ||
141 | div->nshift = 0; | ||
142 | div->nmask = 0xffff; | ||
143 | div->lock = lock; | ||
144 | div_ops = &clk_fractional_divider_ops; | ||
145 | |||
146 | clk = clk_register_composite(NULL, name, parent_names, num_parents, | ||
147 | NULL, NULL, | ||
148 | &div->hw, div_ops, | ||
149 | gate ? &gate->hw : NULL, gate_ops, | ||
150 | flags); | ||
151 | |||
152 | return clk; | ||
153 | } | ||
154 | |||
106 | static DEFINE_SPINLOCK(clk_lock); | 155 | static DEFINE_SPINLOCK(clk_lock); |
107 | static struct clk **clk_table; | 156 | static struct clk **clk_table; |
108 | static void __iomem *reg_base; | 157 | static void __iomem *reg_base; |
@@ -197,8 +246,14 @@ void __init rockchip_clk_register_branches( | |||
197 | list->div_flags, &clk_lock); | 246 | list->div_flags, &clk_lock); |
198 | break; | 247 | break; |
199 | case branch_fraction_divider: | 248 | case branch_fraction_divider: |
200 | /* unimplemented */ | 249 | /* keep all gates untouched for now */ |
201 | continue; | 250 | flags |= CLK_IGNORE_UNUSED; |
251 | |||
252 | clk = rockchip_clk_register_frac_branch(list->name, | ||
253 | list->parent_names, list->num_parents, | ||
254 | reg_base, list->muxdiv_offset, list->div_flags, | ||
255 | list->gate_offset, list->gate_shift, | ||
256 | list->gate_flags, flags, &clk_lock); | ||
202 | break; | 257 | break; |
203 | case branch_gate: | 258 | case branch_gate: |
204 | flags |= CLK_SET_RATE_PARENT; | 259 | flags |= CLK_SET_RATE_PARENT; |
@@ -242,3 +297,61 @@ void __init rockchip_clk_register_branches( | |||
242 | rockchip_clk_add_lookup(clk, list->id); | 297 | rockchip_clk_add_lookup(clk, list->id); |
243 | } | 298 | } |
244 | } | 299 | } |
300 | |||
301 | void __init rockchip_clk_register_armclk(unsigned int lookup_id, | ||
302 | const char *name, const char **parent_names, | ||
303 | u8 num_parents, | ||
304 | const struct rockchip_cpuclk_reg_data *reg_data, | ||
305 | const struct rockchip_cpuclk_rate_table *rates, | ||
306 | int nrates) | ||
307 | { | ||
308 | struct clk *clk; | ||
309 | |||
310 | clk = rockchip_clk_register_cpuclk(name, parent_names, num_parents, | ||
311 | reg_data, rates, nrates, reg_base, | ||
312 | &clk_lock); | ||
313 | if (IS_ERR(clk)) { | ||
314 | pr_err("%s: failed to register clock %s: %ld\n", | ||
315 | __func__, name, PTR_ERR(clk)); | ||
316 | return; | ||
317 | } | ||
318 | |||
319 | rockchip_clk_add_lookup(clk, lookup_id); | ||
320 | } | ||
321 | |||
322 | void __init rockchip_clk_protect_critical(const char *clocks[], int nclocks) | ||
323 | { | ||
324 | int i; | ||
325 | |||
326 | /* Protect the clocks that needs to stay on */ | ||
327 | for (i = 0; i < nclocks; i++) { | ||
328 | struct clk *clk = __clk_lookup(clocks[i]); | ||
329 | |||
330 | if (clk) | ||
331 | clk_prepare_enable(clk); | ||
332 | } | ||
333 | } | ||
334 | |||
335 | static unsigned int reg_restart; | ||
336 | static int rockchip_restart_notify(struct notifier_block *this, | ||
337 | unsigned long mode, void *cmd) | ||
338 | { | ||
339 | writel(0xfdb9, reg_base + reg_restart); | ||
340 | return NOTIFY_DONE; | ||
341 | } | ||
342 | |||
343 | static struct notifier_block rockchip_restart_handler = { | ||
344 | .notifier_call = rockchip_restart_notify, | ||
345 | .priority = 128, | ||
346 | }; | ||
347 | |||
348 | void __init rockchip_register_restart_notifier(unsigned int reg) | ||
349 | { | ||
350 | int ret; | ||
351 | |||
352 | reg_restart = reg; | ||
353 | ret = register_restart_handler(&rockchip_restart_handler); | ||
354 | if (ret) | ||
355 | pr_err("%s: cannot register restart handler, %d\n", | ||
356 | __func__, ret); | ||
357 | } | ||
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 887cbdeca2aa..ca009ab0a33a 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h | |||
@@ -120,6 +120,38 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, | |||
120 | struct rockchip_pll_rate_table *rate_table, | 120 | struct rockchip_pll_rate_table *rate_table, |
121 | spinlock_t *lock); | 121 | spinlock_t *lock); |
122 | 122 | ||
123 | struct rockchip_cpuclk_clksel { | ||
124 | int reg; | ||
125 | u32 val; | ||
126 | }; | ||
127 | |||
128 | #define ROCKCHIP_CPUCLK_NUM_DIVIDERS 2 | ||
129 | struct rockchip_cpuclk_rate_table { | ||
130 | unsigned long prate; | ||
131 | struct rockchip_cpuclk_clksel divs[ROCKCHIP_CPUCLK_NUM_DIVIDERS]; | ||
132 | }; | ||
133 | |||
134 | /** | ||
135 | * struct rockchip_cpuclk_reg_data: describes register offsets and masks of the cpuclock | ||
136 | * @core_reg: register offset of the core settings register | ||
137 | * @div_core_shift: core divider offset used to divide the pll value | ||
138 | * @div_core_mask: core divider mask | ||
139 | * @mux_core_shift: offset of the core multiplexer | ||
140 | */ | ||
141 | struct rockchip_cpuclk_reg_data { | ||
142 | int core_reg; | ||
143 | u8 div_core_shift; | ||
144 | u32 div_core_mask; | ||
145 | int mux_core_reg; | ||
146 | u8 mux_core_shift; | ||
147 | }; | ||
148 | |||
149 | struct clk *rockchip_clk_register_cpuclk(const char *name, | ||
150 | const char **parent_names, u8 num_parents, | ||
151 | const struct rockchip_cpuclk_reg_data *reg_data, | ||
152 | const struct rockchip_cpuclk_rate_table *rates, | ||
153 | int nrates, void __iomem *reg_base, spinlock_t *lock); | ||
154 | |||
123 | #define PNAME(x) static const char *x[] __initconst | 155 | #define PNAME(x) static const char *x[] __initconst |
124 | 156 | ||
125 | enum rockchip_clk_branch_type { | 157 | enum rockchip_clk_branch_type { |
@@ -329,6 +361,13 @@ void rockchip_clk_register_branches(struct rockchip_clk_branch *clk_list, | |||
329 | unsigned int nr_clk); | 361 | unsigned int nr_clk); |
330 | void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list, | 362 | void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list, |
331 | unsigned int nr_pll, int grf_lock_offset); | 363 | unsigned int nr_pll, int grf_lock_offset); |
364 | void rockchip_clk_register_armclk(unsigned int lookup_id, const char *name, | ||
365 | const char **parent_names, u8 num_parents, | ||
366 | const struct rockchip_cpuclk_reg_data *reg_data, | ||
367 | const struct rockchip_cpuclk_rate_table *rates, | ||
368 | int nrates); | ||
369 | void rockchip_clk_protect_critical(const char *clocks[], int nclocks); | ||
370 | void rockchip_register_restart_notifier(unsigned int reg); | ||
332 | 371 | ||
333 | #define ROCKCHIP_SOFTRST_HIWORD_MASK BIT(0) | 372 | #define ROCKCHIP_SOFTRST_HIWORD_MASK BIT(0) |
334 | 373 | ||
diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index 2949a556af8f..6fb4bc602e8a 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile | |||
@@ -17,3 +17,4 @@ obj-$(CONFIG_S3C2410_COMMON_DCLK)+= clk-s3c2410-dclk.o | |||
17 | obj-$(CONFIG_S3C2412_COMMON_CLK)+= clk-s3c2412.o | 17 | obj-$(CONFIG_S3C2412_COMMON_CLK)+= clk-s3c2412.o |
18 | obj-$(CONFIG_S3C2443_COMMON_CLK)+= clk-s3c2443.o | 18 | obj-$(CONFIG_S3C2443_COMMON_CLK)+= clk-s3c2443.o |
19 | obj-$(CONFIG_ARCH_S3C64XX) += clk-s3c64xx.o | 19 | obj-$(CONFIG_ARCH_S3C64XX) += clk-s3c64xx.o |
20 | obj-$(CONFIG_ARCH_S5PV210) += clk-s5pv210.o clk-s5pv210-audss.o | ||
diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c index dc85f8e7a2d7..6e6cca392082 100644 --- a/drivers/clk/samsung/clk-exynos3250.c +++ b/drivers/clk/samsung/clk-exynos3250.c | |||
@@ -110,7 +110,14 @@ enum exynos3250_plls { | |||
110 | nr_plls | 110 | nr_plls |
111 | }; | 111 | }; |
112 | 112 | ||
113 | /* list of PLLs in DMC block to be registered */ | ||
114 | enum exynos3250_dmc_plls { | ||
115 | bpll, epll, | ||
116 | nr_dmc_plls | ||
117 | }; | ||
118 | |||
113 | static void __iomem *reg_base; | 119 | static void __iomem *reg_base; |
120 | static void __iomem *dmc_reg_base; | ||
114 | 121 | ||
115 | /* | 122 | /* |
116 | * Support for CMU save/restore across system suspends | 123 | * Support for CMU save/restore across system suspends |
@@ -266,6 +273,7 @@ PNAME(group_sclk_cam_blk_p) = { "xxti", "xusbxti", | |||
266 | "none", "none", "none", | 273 | "none", "none", "none", |
267 | "none", "div_mpll_pre", | 274 | "none", "div_mpll_pre", |
268 | "mout_epll_user", "mout_vpll", | 275 | "mout_epll_user", "mout_vpll", |
276 | "none", "none", "none", | ||
269 | "div_cam_blk_320", }; | 277 | "div_cam_blk_320", }; |
270 | PNAME(group_sclk_fimd0_p) = { "xxti", "xusbxti", | 278 | PNAME(group_sclk_fimd0_p) = { "xxti", "xusbxti", |
271 | "m_bitclkhsdiv4_2l", "none", | 279 | "m_bitclkhsdiv4_2l", "none", |
@@ -353,8 +361,8 @@ static struct samsung_mux_clock mux_clks[] __initdata = { | |||
353 | 361 | ||
354 | /* SRC_FSYS */ | 362 | /* SRC_FSYS */ |
355 | MUX(CLK_MOUT_TSADC, "mout_tsadc", group_sclk_p, SRC_FSYS, 28, 4), | 363 | MUX(CLK_MOUT_TSADC, "mout_tsadc", group_sclk_p, SRC_FSYS, 28, 4), |
356 | MUX(CLK_MOUT_MMC1, "mout_mmc1", group_sclk_p, SRC_FSYS, 4, 3), | 364 | MUX(CLK_MOUT_MMC1, "mout_mmc1", group_sclk_p, SRC_FSYS, 4, 4), |
357 | MUX(CLK_MOUT_MMC0, "mout_mmc0", group_sclk_p, SRC_FSYS, 0, 3), | 365 | MUX(CLK_MOUT_MMC0, "mout_mmc0", group_sclk_p, SRC_FSYS, 0, 4), |
358 | 366 | ||
359 | /* SRC_PERIL0 */ | 367 | /* SRC_PERIL0 */ |
360 | MUX(CLK_MOUT_UART1, "mout_uart1", group_sclk_p, SRC_PERIL0, 4, 4), | 368 | MUX(CLK_MOUT_UART1, "mout_uart1", group_sclk_p, SRC_PERIL0, 4, 4), |
@@ -423,7 +431,7 @@ static struct samsung_div_clock div_clks[] __initdata = { | |||
423 | DIV(CLK_DIV_SPI1_ISP, "div_spi1_isp", "mout_spi1_isp", DIV_ISP, 16, 4), | 431 | DIV(CLK_DIV_SPI1_ISP, "div_spi1_isp", "mout_spi1_isp", DIV_ISP, 16, 4), |
424 | DIV_F(CLK_DIV_SPI0_ISP_PRE, "div_spi0_isp_pre", "div_spi0_isp", | 432 | DIV_F(CLK_DIV_SPI0_ISP_PRE, "div_spi0_isp_pre", "div_spi0_isp", |
425 | DIV_ISP, 8, 8, CLK_SET_RATE_PARENT, 0), | 433 | DIV_ISP, 8, 8, CLK_SET_RATE_PARENT, 0), |
426 | DIV(CLK_DIV_SPI0_ISP, "div_spi0_isp", "mout_spi0_isp", DIV_ISP, 0, 4), | 434 | DIV(CLK_DIV_SPI0_ISP, "div_spi0_isp", "mout_spi0_isp", DIV_ISP, 4, 4), |
427 | 435 | ||
428 | /* DIV_FSYS0 */ | 436 | /* DIV_FSYS0 */ |
429 | DIV_F(CLK_DIV_TSADC_PRE, "div_tsadc_pre", "div_tsadc", DIV_FSYS0, 8, 8, | 437 | DIV_F(CLK_DIV_TSADC_PRE, "div_tsadc_pre", "div_tsadc", DIV_FSYS0, 8, 8, |
@@ -724,6 +732,25 @@ static struct samsung_pll_rate_table exynos3250_pll_rates[] = { | |||
724 | { /* sentinel */ } | 732 | { /* sentinel */ } |
725 | }; | 733 | }; |
726 | 734 | ||
735 | /* EPLL */ | ||
736 | static struct samsung_pll_rate_table exynos3250_epll_rates[] = { | ||
737 | PLL_36XX_RATE(800000000, 200, 3, 1, 0), | ||
738 | PLL_36XX_RATE(288000000, 96, 2, 2, 0), | ||
739 | PLL_36XX_RATE(192000000, 128, 2, 3, 0), | ||
740 | PLL_36XX_RATE(144000000, 96, 2, 3, 0), | ||
741 | PLL_36XX_RATE( 96000000, 128, 2, 4, 0), | ||
742 | PLL_36XX_RATE( 84000000, 112, 2, 4, 0), | ||
743 | PLL_36XX_RATE( 80000004, 106, 2, 4, 43691), | ||
744 | PLL_36XX_RATE( 73728000, 98, 2, 4, 19923), | ||
745 | PLL_36XX_RATE( 67737598, 270, 3, 5, 62285), | ||
746 | PLL_36XX_RATE( 65535999, 174, 2, 5, 49982), | ||
747 | PLL_36XX_RATE( 50000000, 200, 3, 5, 0), | ||
748 | PLL_36XX_RATE( 49152002, 131, 2, 5, 4719), | ||
749 | PLL_36XX_RATE( 48000000, 128, 2, 5, 0), | ||
750 | PLL_36XX_RATE( 45158401, 180, 3, 5, 41524), | ||
751 | { /* sentinel */ } | ||
752 | }; | ||
753 | |||
727 | /* VPLL */ | 754 | /* VPLL */ |
728 | static struct samsung_pll_rate_table exynos3250_vpll_rates[] = { | 755 | static struct samsung_pll_rate_table exynos3250_vpll_rates[] = { |
729 | PLL_36XX_RATE(600000000, 100, 2, 1, 0), | 756 | PLL_36XX_RATE(600000000, 100, 2, 1, 0), |
@@ -821,3 +848,172 @@ static void __init exynos3250_cmu_init(struct device_node *np) | |||
821 | samsung_clk_of_add_provider(np, ctx); | 848 | samsung_clk_of_add_provider(np, ctx); |
822 | } | 849 | } |
823 | CLK_OF_DECLARE(exynos3250_cmu, "samsung,exynos3250-cmu", exynos3250_cmu_init); | 850 | CLK_OF_DECLARE(exynos3250_cmu, "samsung,exynos3250-cmu", exynos3250_cmu_init); |
851 | |||
852 | /* | ||
853 | * CMU DMC | ||
854 | */ | ||
855 | |||
856 | #define BPLL_LOCK 0x0118 | ||
857 | #define BPLL_CON0 0x0218 | ||
858 | #define BPLL_CON1 0x021c | ||
859 | #define BPLL_CON2 0x0220 | ||
860 | #define SRC_DMC 0x0300 | ||
861 | #define DIV_DMC1 0x0504 | ||
862 | #define GATE_BUS_DMC0 0x0700 | ||
863 | #define GATE_BUS_DMC1 0x0704 | ||
864 | #define GATE_BUS_DMC2 0x0708 | ||
865 | #define GATE_BUS_DMC3 0x070c | ||
866 | #define GATE_SCLK_DMC 0x0800 | ||
867 | #define GATE_IP_DMC0 0x0900 | ||
868 | #define GATE_IP_DMC1 0x0904 | ||
869 | #define EPLL_LOCK 0x1110 | ||
870 | #define EPLL_CON0 0x1114 | ||
871 | #define EPLL_CON1 0x1118 | ||
872 | #define EPLL_CON2 0x111c | ||
873 | #define SRC_EPLL 0x1120 | ||
874 | |||
875 | /* | ||
876 | * Support for CMU save/restore across system suspends | ||
877 | */ | ||
878 | #ifdef CONFIG_PM_SLEEP | ||
879 | static struct samsung_clk_reg_dump *exynos3250_dmc_clk_regs; | ||
880 | |||
881 | static unsigned long exynos3250_cmu_dmc_clk_regs[] __initdata = { | ||
882 | BPLL_LOCK, | ||
883 | BPLL_CON0, | ||
884 | BPLL_CON1, | ||
885 | BPLL_CON2, | ||
886 | SRC_DMC, | ||
887 | DIV_DMC1, | ||
888 | GATE_BUS_DMC0, | ||
889 | GATE_BUS_DMC1, | ||
890 | GATE_BUS_DMC2, | ||
891 | GATE_BUS_DMC3, | ||
892 | GATE_SCLK_DMC, | ||
893 | GATE_IP_DMC0, | ||
894 | GATE_IP_DMC1, | ||
895 | EPLL_LOCK, | ||
896 | EPLL_CON0, | ||
897 | EPLL_CON1, | ||
898 | EPLL_CON2, | ||
899 | SRC_EPLL, | ||
900 | }; | ||
901 | |||
902 | static int exynos3250_dmc_clk_suspend(void) | ||
903 | { | ||
904 | samsung_clk_save(dmc_reg_base, exynos3250_dmc_clk_regs, | ||
905 | ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs)); | ||
906 | return 0; | ||
907 | } | ||
908 | |||
909 | static void exynos3250_dmc_clk_resume(void) | ||
910 | { | ||
911 | samsung_clk_restore(dmc_reg_base, exynos3250_dmc_clk_regs, | ||
912 | ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs)); | ||
913 | } | ||
914 | |||
915 | static struct syscore_ops exynos3250_dmc_clk_syscore_ops = { | ||
916 | .suspend = exynos3250_dmc_clk_suspend, | ||
917 | .resume = exynos3250_dmc_clk_resume, | ||
918 | }; | ||
919 | |||
920 | static void exynos3250_dmc_clk_sleep_init(void) | ||
921 | { | ||
922 | exynos3250_dmc_clk_regs = | ||
923 | samsung_clk_alloc_reg_dump(exynos3250_cmu_dmc_clk_regs, | ||
924 | ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs)); | ||
925 | if (!exynos3250_dmc_clk_regs) { | ||
926 | pr_warn("%s: Failed to allocate sleep save data\n", __func__); | ||
927 | goto err; | ||
928 | } | ||
929 | |||
930 | register_syscore_ops(&exynos3250_dmc_clk_syscore_ops); | ||
931 | return; | ||
932 | err: | ||
933 | kfree(exynos3250_dmc_clk_regs); | ||
934 | } | ||
935 | #else | ||
936 | static inline void exynos3250_dmc_clk_sleep_init(void) { } | ||
937 | #endif | ||
938 | |||
939 | PNAME(mout_epll_p) = { "fin_pll", "fout_epll", }; | ||
940 | PNAME(mout_bpll_p) = { "fin_pll", "fout_bpll", }; | ||
941 | PNAME(mout_mpll_mif_p) = { "fin_pll", "sclk_mpll_mif", }; | ||
942 | PNAME(mout_dphy_p) = { "mout_mpll_mif", "mout_bpll", }; | ||
943 | |||
944 | static struct samsung_mux_clock dmc_mux_clks[] __initdata = { | ||
945 | /* | ||
946 | * NOTE: Following table is sorted by register address in ascending | ||
947 | * order and then bitfield shift in descending order, as it is done | ||
948 | * in the User's Manual. When adding new entries, please make sure | ||
949 | * that the order is preserved, to avoid merge conflicts and make | ||
950 | * further work with defined data easier. | ||
951 | */ | ||
952 | |||
953 | /* SRC_DMC */ | ||
954 | MUX(CLK_MOUT_MPLL_MIF, "mout_mpll_mif", mout_mpll_mif_p, SRC_DMC, 12, 1), | ||
955 | MUX(CLK_MOUT_BPLL, "mout_bpll", mout_bpll_p, SRC_DMC, 10, 1), | ||
956 | MUX(CLK_MOUT_DPHY, "mout_dphy", mout_dphy_p, SRC_DMC, 8, 1), | ||
957 | MUX(CLK_MOUT_DMC_BUS, "mout_dmc_bus", mout_dphy_p, SRC_DMC, 4, 1), | ||
958 | |||
959 | /* SRC_EPLL */ | ||
960 | MUX(CLK_MOUT_EPLL, "mout_epll", mout_epll_p, SRC_EPLL, 4, 1), | ||
961 | }; | ||
962 | |||
963 | static struct samsung_div_clock dmc_div_clks[] __initdata = { | ||
964 | /* | ||
965 | * NOTE: Following table is sorted by register address in ascending | ||
966 | * order and then bitfield shift in descending order, as it is done | ||
967 | * in the User's Manual. When adding new entries, please make sure | ||
968 | * that the order is preserved, to avoid merge conflicts and make | ||
969 | * further work with defined data easier. | ||
970 | */ | ||
971 | |||
972 | /* DIV_DMC1 */ | ||
973 | DIV(CLK_DIV_DMC, "div_dmc", "div_dmc_pre", DIV_DMC1, 27, 3), | ||
974 | DIV(CLK_DIV_DPHY, "div_dphy", "mout_dphy", DIV_DMC1, 23, 3), | ||
975 | DIV(CLK_DIV_DMC_PRE, "div_dmc_pre", "mout_dmc_bus", DIV_DMC1, 19, 2), | ||
976 | DIV(CLK_DIV_DMCP, "div_dmcp", "div_dmcd", DIV_DMC1, 15, 3), | ||
977 | DIV(CLK_DIV_DMCD, "div_dmcd", "div_dmc", DIV_DMC1, 11, 3), | ||
978 | }; | ||
979 | |||
980 | static struct samsung_pll_clock exynos3250_dmc_plls[nr_dmc_plls] __initdata = { | ||
981 | [bpll] = PLL(pll_35xx, CLK_FOUT_BPLL, "fout_bpll", "fin_pll", | ||
982 | BPLL_LOCK, BPLL_CON0, NULL), | ||
983 | [epll] = PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll", | ||
984 | EPLL_LOCK, EPLL_CON0, NULL), | ||
985 | }; | ||
986 | |||
987 | static void __init exynos3250_cmu_dmc_init(struct device_node *np) | ||
988 | { | ||
989 | struct samsung_clk_provider *ctx; | ||
990 | |||
991 | dmc_reg_base = of_iomap(np, 0); | ||
992 | if (!dmc_reg_base) | ||
993 | panic("%s: failed to map registers\n", __func__); | ||
994 | |||
995 | ctx = samsung_clk_init(np, dmc_reg_base, NR_CLKS_DMC); | ||
996 | if (!ctx) | ||
997 | panic("%s: unable to allocate context.\n", __func__); | ||
998 | |||
999 | exynos3250_dmc_plls[bpll].rate_table = exynos3250_pll_rates; | ||
1000 | exynos3250_dmc_plls[epll].rate_table = exynos3250_epll_rates; | ||
1001 | |||
1002 | pr_err("CLK registering epll bpll: %d, %d, %d, %d\n", | ||
1003 | exynos3250_dmc_plls[bpll].rate_table[0].rate, | ||
1004 | exynos3250_dmc_plls[bpll].rate_table[0].mdiv, | ||
1005 | exynos3250_dmc_plls[bpll].rate_table[0].pdiv, | ||
1006 | exynos3250_dmc_plls[bpll].rate_table[0].sdiv | ||
1007 | ); | ||
1008 | samsung_clk_register_pll(ctx, exynos3250_dmc_plls, | ||
1009 | ARRAY_SIZE(exynos3250_dmc_plls), dmc_reg_base); | ||
1010 | |||
1011 | samsung_clk_register_mux(ctx, dmc_mux_clks, ARRAY_SIZE(dmc_mux_clks)); | ||
1012 | samsung_clk_register_div(ctx, dmc_div_clks, ARRAY_SIZE(dmc_div_clks)); | ||
1013 | |||
1014 | exynos3250_dmc_clk_sleep_init(); | ||
1015 | |||
1016 | samsung_clk_of_add_provider(np, ctx); | ||
1017 | } | ||
1018 | CLK_OF_DECLARE(exynos3250_cmu_dmc, "samsung,exynos3250-cmu-dmc", | ||
1019 | exynos3250_cmu_dmc_init); | ||
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index ac163d7f5bc3..940f02837b82 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c | |||
@@ -517,7 +517,7 @@ static struct samsung_fixed_factor_clock exynos4_fixed_factor_clks[] __initdata | |||
517 | FFACTOR(0, "sclk_apll_div_2", "sclk_apll", 1, 2, 0), | 517 | FFACTOR(0, "sclk_apll_div_2", "sclk_apll", 1, 2, 0), |
518 | FFACTOR(0, "fout_mpll_div_2", "fout_mpll", 1, 2, 0), | 518 | FFACTOR(0, "fout_mpll_div_2", "fout_mpll", 1, 2, 0), |
519 | FFACTOR(0, "fout_apll_div_2", "fout_apll", 1, 2, 0), | 519 | FFACTOR(0, "fout_apll_div_2", "fout_apll", 1, 2, 0), |
520 | FFACTOR(0, "arm_clk_div_2", "arm_clk", 1, 2, 0), | 520 | FFACTOR(0, "arm_clk_div_2", "div_core2", 1, 2, 0), |
521 | }; | 521 | }; |
522 | 522 | ||
523 | static struct samsung_fixed_factor_clock exynos4210_fixed_factor_clks[] __initdata = { | 523 | static struct samsung_fixed_factor_clock exynos4210_fixed_factor_clks[] __initdata = { |
@@ -535,7 +535,7 @@ static struct samsung_fixed_factor_clock exynos4x12_fixed_factor_clks[] __initda | |||
535 | static struct samsung_mux_clock exynos4_mux_clks[] __initdata = { | 535 | static struct samsung_mux_clock exynos4_mux_clks[] __initdata = { |
536 | MUX_FA(CLK_MOUT_APLL, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, | 536 | MUX_FA(CLK_MOUT_APLL, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, |
537 | CLK_SET_RATE_PARENT, 0, "mout_apll"), | 537 | CLK_SET_RATE_PARENT, 0, "mout_apll"), |
538 | MUX(0, "mout_hdmi", mout_hdmi_p, SRC_TV, 0, 1), | 538 | MUX(CLK_MOUT_HDMI, "mout_hdmi", mout_hdmi_p, SRC_TV, 0, 1), |
539 | MUX(0, "mout_mfc1", sclk_evpll_p, SRC_MFC, 4, 1), | 539 | MUX(0, "mout_mfc1", sclk_evpll_p, SRC_MFC, 4, 1), |
540 | MUX(0, "mout_mfc", mout_mfc_p, SRC_MFC, 8, 1), | 540 | MUX(0, "mout_mfc", mout_mfc_p, SRC_MFC, 8, 1), |
541 | MUX_F(CLK_MOUT_G3D1, "mout_g3d1", sclk_evpll_p, SRC_G3D, 4, 1, | 541 | MUX_F(CLK_MOUT_G3D1, "mout_g3d1", sclk_evpll_p, SRC_G3D, 4, 1, |
@@ -569,7 +569,7 @@ static struct samsung_mux_clock exynos4210_mux_clks[] __initdata = { | |||
569 | MUX(0, "mout_aclk100", sclk_ampll_p4210, SRC_TOP0, 16, 1), | 569 | MUX(0, "mout_aclk100", sclk_ampll_p4210, SRC_TOP0, 16, 1), |
570 | MUX(0, "mout_aclk160", sclk_ampll_p4210, SRC_TOP0, 20, 1), | 570 | MUX(0, "mout_aclk160", sclk_ampll_p4210, SRC_TOP0, 20, 1), |
571 | MUX(0, "mout_aclk133", sclk_ampll_p4210, SRC_TOP0, 24, 1), | 571 | MUX(0, "mout_aclk133", sclk_ampll_p4210, SRC_TOP0, 24, 1), |
572 | MUX(0, "mout_mixer", mout_mixer_p4210, SRC_TV, 4, 1), | 572 | MUX(CLK_MOUT_MIXER, "mout_mixer", mout_mixer_p4210, SRC_TV, 4, 1), |
573 | MUX(0, "mout_dac", mout_dac_p4210, SRC_TV, 8, 1), | 573 | MUX(0, "mout_dac", mout_dac_p4210, SRC_TV, 8, 1), |
574 | MUX(0, "mout_g2d0", sclk_ampll_p4210, E4210_SRC_IMAGE, 0, 1), | 574 | MUX(0, "mout_g2d0", sclk_ampll_p4210, E4210_SRC_IMAGE, 0, 1), |
575 | MUX(0, "mout_g2d1", sclk_evpll_p, E4210_SRC_IMAGE, 4, 1), | 575 | MUX(0, "mout_g2d1", sclk_evpll_p, E4210_SRC_IMAGE, 4, 1), |
@@ -719,7 +719,7 @@ static struct samsung_div_clock exynos4_div_clks[] __initdata = { | |||
719 | DIV(0, "div_periph", "div_core2", DIV_CPU0, 12, 3), | 719 | DIV(0, "div_periph", "div_core2", DIV_CPU0, 12, 3), |
720 | DIV(0, "div_atb", "mout_core", DIV_CPU0, 16, 3), | 720 | DIV(0, "div_atb", "mout_core", DIV_CPU0, 16, 3), |
721 | DIV(0, "div_pclk_dbg", "div_atb", DIV_CPU0, 20, 3), | 721 | DIV(0, "div_pclk_dbg", "div_atb", DIV_CPU0, 20, 3), |
722 | DIV(0, "div_core2", "div_core", DIV_CPU0, 28, 3), | 722 | DIV(CLK_ARM_CLK, "div_core2", "div_core", DIV_CPU0, 28, 3), |
723 | DIV(0, "div_copy", "mout_hpm", DIV_CPU1, 0, 3), | 723 | DIV(0, "div_copy", "mout_hpm", DIV_CPU1, 0, 3), |
724 | DIV(0, "div_hpm", "div_copy", DIV_CPU1, 4, 3), | 724 | DIV(0, "div_hpm", "div_copy", DIV_CPU1, 4, 3), |
725 | DIV(0, "div_clkout_cpu", "mout_clkout_cpu", CLKOUT_CMU_CPU, 8, 6), | 725 | DIV(0, "div_clkout_cpu", "mout_clkout_cpu", CLKOUT_CMU_CPU, 8, 6), |
@@ -733,8 +733,7 @@ static struct samsung_div_clock exynos4_div_clks[] __initdata = { | |||
733 | DIV(0, "div_csis0", "mout_csis0", DIV_CAM, 24, 4), | 733 | DIV(0, "div_csis0", "mout_csis0", DIV_CAM, 24, 4), |
734 | DIV(0, "div_csis1", "mout_csis1", DIV_CAM, 28, 4), | 734 | DIV(0, "div_csis1", "mout_csis1", DIV_CAM, 28, 4), |
735 | DIV(CLK_SCLK_MFC, "sclk_mfc", "mout_mfc", DIV_MFC, 0, 4), | 735 | DIV(CLK_SCLK_MFC, "sclk_mfc", "mout_mfc", DIV_MFC, 0, 4), |
736 | DIV_F(0, "div_g3d", "mout_g3d", DIV_G3D, 0, 4, | 736 | DIV(CLK_SCLK_G3D, "sclk_g3d", "mout_g3d", DIV_G3D, 0, 4), |
737 | CLK_SET_RATE_PARENT, 0), | ||
738 | DIV(0, "div_fimd0", "mout_fimd0", DIV_LCD0, 0, 4), | 737 | DIV(0, "div_fimd0", "mout_fimd0", DIV_LCD0, 0, 4), |
739 | DIV(0, "div_mipi0", "mout_mipi0", DIV_LCD0, 16, 4), | 738 | DIV(0, "div_mipi0", "mout_mipi0", DIV_LCD0, 16, 4), |
740 | DIV(0, "div_audio0", "mout_audio0", DIV_MAUDIO, 0, 4), | 739 | DIV(0, "div_audio0", "mout_audio0", DIV_MAUDIO, 0, 4), |
@@ -769,7 +768,6 @@ static struct samsung_div_clock exynos4_div_clks[] __initdata = { | |||
769 | DIV(0, "div_spi_pre2", "div_spi2", DIV_PERIL2, 8, 8), | 768 | DIV(0, "div_spi_pre2", "div_spi2", DIV_PERIL2, 8, 8), |
770 | DIV(0, "div_audio1", "mout_audio1", DIV_PERIL4, 0, 4), | 769 | DIV(0, "div_audio1", "mout_audio1", DIV_PERIL4, 0, 4), |
771 | DIV(0, "div_audio2", "mout_audio2", DIV_PERIL4, 16, 4), | 770 | DIV(0, "div_audio2", "mout_audio2", DIV_PERIL4, 16, 4), |
772 | DIV(CLK_ARM_CLK, "arm_clk", "div_core2", DIV_CPU0, 28, 3), | ||
773 | DIV(CLK_SCLK_APLL, "sclk_apll", "mout_apll", DIV_CPU0, 24, 3), | 771 | DIV(CLK_SCLK_APLL, "sclk_apll", "mout_apll", DIV_CPU0, 24, 3), |
774 | DIV_F(0, "div_mipi_pre0", "div_mipi0", DIV_LCD0, 20, 4, | 772 | DIV_F(0, "div_mipi_pre0", "div_mipi0", DIV_LCD0, 20, 4, |
775 | CLK_SET_RATE_PARENT, 0), | 773 | CLK_SET_RATE_PARENT, 0), |
@@ -857,8 +855,7 @@ static struct samsung_gate_clock exynos4_gate_clks[] __initdata = { | |||
857 | 0), | 855 | 0), |
858 | GATE(CLK_TSI, "tsi", "aclk133", GATE_IP_FSYS, 4, 0, 0), | 856 | GATE(CLK_TSI, "tsi", "aclk133", GATE_IP_FSYS, 4, 0, 0), |
859 | GATE(CLK_SROMC, "sromc", "aclk133", GATE_IP_FSYS, 11, 0, 0), | 857 | GATE(CLK_SROMC, "sromc", "aclk133", GATE_IP_FSYS, 11, 0, 0), |
860 | GATE(CLK_SCLK_G3D, "sclk_g3d", "div_g3d", GATE_IP_G3D, 0, | 858 | GATE(CLK_G3D, "g3d", "aclk200", GATE_IP_G3D, 0, 0, 0), |
861 | CLK_SET_RATE_PARENT, 0), | ||
862 | GATE(CLK_PPMUG3D, "ppmug3d", "aclk200", GATE_IP_G3D, 1, 0, 0), | 859 | GATE(CLK_PPMUG3D, "ppmug3d", "aclk200", GATE_IP_G3D, 1, 0, 0), |
863 | GATE(CLK_USB_DEVICE, "usb_device", "aclk133", GATE_IP_FSYS, 13, 0, 0), | 860 | GATE(CLK_USB_DEVICE, "usb_device", "aclk133", GATE_IP_FSYS, 13, 0, 0), |
864 | GATE(CLK_ONENAND, "onenand", "aclk133", GATE_IP_FSYS, 15, 0, 0), | 861 | GATE(CLK_ONENAND, "onenand", "aclk133", GATE_IP_FSYS, 15, 0, 0), |
@@ -1183,6 +1180,7 @@ static struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = { | |||
1183 | GATE(CLK_SPI1_ISP, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13, | 1180 | GATE(CLK_SPI1_ISP, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13, |
1184 | CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), | 1181 | CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), |
1185 | GATE(CLK_G2D, "g2d", "aclk200", GATE_IP_DMC, 23, 0, 0), | 1182 | GATE(CLK_G2D, "g2d", "aclk200", GATE_IP_DMC, 23, 0, 0), |
1183 | GATE(CLK_SMMU_G2D, "smmu_g2d", "aclk200", GATE_IP_DMC, 24, 0, 0), | ||
1186 | GATE(CLK_TMU_APBIF, "tmu_apbif", "aclk100", E4X12_GATE_IP_PERIR, 17, 0, | 1184 | GATE(CLK_TMU_APBIF, "tmu_apbif", "aclk100", E4X12_GATE_IP_PERIR, 17, 0, |
1187 | 0), | 1185 | 0), |
1188 | }; | 1186 | }; |
@@ -1486,7 +1484,7 @@ static void __init exynos4_clk_init(struct device_node *np, | |||
1486 | exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12", | 1484 | exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12", |
1487 | _get_rate("sclk_apll"), _get_rate("sclk_mpll"), | 1485 | _get_rate("sclk_apll"), _get_rate("sclk_mpll"), |
1488 | _get_rate("sclk_epll"), _get_rate("sclk_vpll"), | 1486 | _get_rate("sclk_epll"), _get_rate("sclk_vpll"), |
1489 | _get_rate("arm_clk")); | 1487 | _get_rate("div_core2")); |
1490 | } | 1488 | } |
1491 | 1489 | ||
1492 | 1490 | ||
diff --git a/drivers/clk/samsung/clk-exynos5260.c b/drivers/clk/samsung/clk-exynos5260.c index ce3de97e5f11..2527e39aadcf 100644 --- a/drivers/clk/samsung/clk-exynos5260.c +++ b/drivers/clk/samsung/clk-exynos5260.c | |||
@@ -1581,7 +1581,7 @@ struct samsung_fixed_rate_clock fixed_rate_clks[] __initdata = { | |||
1581 | FRATE(PHYCLK_HDMI_LINK_O_TMDS_CLKHI, "phyclk_hdmi_link_o_tmds_clkhi", | 1581 | FRATE(PHYCLK_HDMI_LINK_O_TMDS_CLKHI, "phyclk_hdmi_link_o_tmds_clkhi", |
1582 | NULL, CLK_IS_ROOT, 125000000), | 1582 | NULL, CLK_IS_ROOT, 125000000), |
1583 | FRATE(PHYCLK_MIPI_DPHY_4L_M_TXBYTECLKHS, | 1583 | FRATE(PHYCLK_MIPI_DPHY_4L_M_TXBYTECLKHS, |
1584 | "phyclk_mipi_dphy_4l_m_txbyteclkhs" , NULL, | 1584 | "phyclk_mipi_dphy_4l_m_txbyte_clkhs" , NULL, |
1585 | CLK_IS_ROOT, 187500000), | 1585 | CLK_IS_ROOT, 187500000), |
1586 | FRATE(PHYCLK_DPTX_PHY_O_REF_CLK_24M, "phyclk_dptx_phy_o_ref_clk_24m", | 1586 | FRATE(PHYCLK_DPTX_PHY_O_REF_CLK_24M, "phyclk_dptx_phy_o_ref_clk_24m", |
1587 | NULL, CLK_IS_ROOT, 24000000), | 1587 | NULL, CLK_IS_ROOT, 24000000), |
diff --git a/drivers/clk/samsung/clk-s3c2410-dclk.c b/drivers/clk/samsung/clk-s3c2410-dclk.c index 0449cc0458ed..f4f29ed6bd25 100644 --- a/drivers/clk/samsung/clk-s3c2410-dclk.c +++ b/drivers/clk/samsung/clk-s3c2410-dclk.c | |||
@@ -426,7 +426,6 @@ MODULE_DEVICE_TABLE(platform, s3c24xx_dclk_driver_ids); | |||
426 | static struct platform_driver s3c24xx_dclk_driver = { | 426 | static struct platform_driver s3c24xx_dclk_driver = { |
427 | .driver = { | 427 | .driver = { |
428 | .name = "s3c24xx-dclk", | 428 | .name = "s3c24xx-dclk", |
429 | .owner = THIS_MODULE, | ||
430 | .pm = &s3c24xx_dclk_pm_ops, | 429 | .pm = &s3c24xx_dclk_pm_ops, |
431 | }, | 430 | }, |
432 | .probe = s3c24xx_dclk_probe, | 431 | .probe = s3c24xx_dclk_probe, |
diff --git a/drivers/clk/samsung/clk-s3c2412.c b/drivers/clk/samsung/clk-s3c2412.c index 34af09f6a155..2ceedaf8ce18 100644 --- a/drivers/clk/samsung/clk-s3c2412.c +++ b/drivers/clk/samsung/clk-s3c2412.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/of.h> | 14 | #include <linux/of.h> |
15 | #include <linux/of_address.h> | 15 | #include <linux/of_address.h> |
16 | #include <linux/syscore_ops.h> | 16 | #include <linux/syscore_ops.h> |
17 | #include <linux/reboot.h> | ||
17 | 18 | ||
18 | #include <dt-bindings/clock/s3c2412.h> | 19 | #include <dt-bindings/clock/s3c2412.h> |
19 | 20 | ||
@@ -26,6 +27,7 @@ | |||
26 | #define CLKCON 0x0c | 27 | #define CLKCON 0x0c |
27 | #define CLKDIVN 0x14 | 28 | #define CLKDIVN 0x14 |
28 | #define CLKSRC 0x1c | 29 | #define CLKSRC 0x1c |
30 | #define SWRST 0x30 | ||
29 | 31 | ||
30 | /* list of PLLs to be registered */ | 32 | /* list of PLLs to be registered */ |
31 | enum s3c2412_plls { | 33 | enum s3c2412_plls { |
@@ -204,6 +206,28 @@ struct samsung_clock_alias s3c2412_aliases[] __initdata = { | |||
204 | ALIAS(MSYSCLK, NULL, "fclk"), | 206 | ALIAS(MSYSCLK, NULL, "fclk"), |
205 | }; | 207 | }; |
206 | 208 | ||
209 | static int s3c2412_restart(struct notifier_block *this, | ||
210 | unsigned long mode, void *cmd) | ||
211 | { | ||
212 | /* errata "Watch-dog/Software Reset Problem" specifies that | ||
213 | * this reset must be done with the SYSCLK sourced from | ||
214 | * EXTCLK instead of FOUT to avoid a glitch in the reset | ||
215 | * mechanism. | ||
216 | * | ||
217 | * See the watchdog section of the S3C2412 manual for more | ||
218 | * information on this fix. | ||
219 | */ | ||
220 | |||
221 | __raw_writel(0x00, reg_base + CLKSRC); | ||
222 | __raw_writel(0x533C2412, reg_base + SWRST); | ||
223 | return NOTIFY_DONE; | ||
224 | } | ||
225 | |||
226 | static struct notifier_block s3c2412_restart_handler = { | ||
227 | .notifier_call = s3c2412_restart, | ||
228 | .priority = 129, | ||
229 | }; | ||
230 | |||
207 | /* | 231 | /* |
208 | * fixed rate clocks generated outside the soc | 232 | * fixed rate clocks generated outside the soc |
209 | * Only necessary until the devicetree-move is complete | 233 | * Only necessary until the devicetree-move is complete |
@@ -233,6 +257,7 @@ void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f, | |||
233 | unsigned long ext_f, void __iomem *base) | 257 | unsigned long ext_f, void __iomem *base) |
234 | { | 258 | { |
235 | struct samsung_clk_provider *ctx; | 259 | struct samsung_clk_provider *ctx; |
260 | int ret; | ||
236 | reg_base = base; | 261 | reg_base = base; |
237 | 262 | ||
238 | if (np) { | 263 | if (np) { |
@@ -267,6 +292,10 @@ void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f, | |||
267 | s3c2412_clk_sleep_init(); | 292 | s3c2412_clk_sleep_init(); |
268 | 293 | ||
269 | samsung_clk_of_add_provider(np, ctx); | 294 | samsung_clk_of_add_provider(np, ctx); |
295 | |||
296 | ret = register_restart_handler(&s3c2412_restart_handler); | ||
297 | if (ret) | ||
298 | pr_warn("cannot register restart handler, %d\n", ret); | ||
270 | } | 299 | } |
271 | 300 | ||
272 | static void __init s3c2412_clk_init(struct device_node *np) | 301 | static void __init s3c2412_clk_init(struct device_node *np) |
diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c index c92f853fca9f..0c3c182b902a 100644 --- a/drivers/clk/samsung/clk-s3c2443.c +++ b/drivers/clk/samsung/clk-s3c2443.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/of.h> | 14 | #include <linux/of.h> |
15 | #include <linux/of_address.h> | 15 | #include <linux/of_address.h> |
16 | #include <linux/syscore_ops.h> | 16 | #include <linux/syscore_ops.h> |
17 | #include <linux/reboot.h> | ||
17 | 18 | ||
18 | #include <dt-bindings/clock/s3c2443.h> | 19 | #include <dt-bindings/clock/s3c2443.h> |
19 | 20 | ||
@@ -33,6 +34,7 @@ | |||
33 | #define HCLKCON 0x30 | 34 | #define HCLKCON 0x30 |
34 | #define PCLKCON 0x34 | 35 | #define PCLKCON 0x34 |
35 | #define SCLKCON 0x38 | 36 | #define SCLKCON 0x38 |
37 | #define SWRST 0x44 | ||
36 | 38 | ||
37 | /* the soc types */ | 39 | /* the soc types */ |
38 | enum supported_socs { | 40 | enum supported_socs { |
@@ -354,6 +356,18 @@ struct samsung_clock_alias s3c2450_aliases[] __initdata = { | |||
354 | ALIAS(PCLK_I2C1, "s3c2410-i2c.1", "i2c"), | 356 | ALIAS(PCLK_I2C1, "s3c2410-i2c.1", "i2c"), |
355 | }; | 357 | }; |
356 | 358 | ||
359 | static int s3c2443_restart(struct notifier_block *this, | ||
360 | unsigned long mode, void *cmd) | ||
361 | { | ||
362 | __raw_writel(0x533c2443, reg_base + SWRST); | ||
363 | return NOTIFY_DONE; | ||
364 | } | ||
365 | |||
366 | static struct notifier_block s3c2443_restart_handler = { | ||
367 | .notifier_call = s3c2443_restart, | ||
368 | .priority = 129, | ||
369 | }; | ||
370 | |||
357 | /* | 371 | /* |
358 | * fixed rate clocks generated outside the soc | 372 | * fixed rate clocks generated outside the soc |
359 | * Only necessary until the devicetree-move is complete | 373 | * Only necessary until the devicetree-move is complete |
@@ -378,6 +392,7 @@ void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f, | |||
378 | void __iomem *base) | 392 | void __iomem *base) |
379 | { | 393 | { |
380 | struct samsung_clk_provider *ctx; | 394 | struct samsung_clk_provider *ctx; |
395 | int ret; | ||
381 | reg_base = base; | 396 | reg_base = base; |
382 | 397 | ||
383 | if (np) { | 398 | if (np) { |
@@ -447,6 +462,10 @@ void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f, | |||
447 | s3c2443_clk_sleep_init(); | 462 | s3c2443_clk_sleep_init(); |
448 | 463 | ||
449 | samsung_clk_of_add_provider(np, ctx); | 464 | samsung_clk_of_add_provider(np, ctx); |
465 | |||
466 | ret = register_restart_handler(&s3c2443_restart_handler); | ||
467 | if (ret) | ||
468 | pr_warn("cannot register restart handler, %d\n", ret); | ||
450 | } | 469 | } |
451 | 470 | ||
452 | static void __init s3c2416_clk_init(struct device_node *np) | 471 | static void __init s3c2416_clk_init(struct device_node *np) |
diff --git a/drivers/clk/samsung/clk-s5pv210-audss.c b/drivers/clk/samsung/clk-s5pv210-audss.c new file mode 100644 index 000000000000..a8053b4aca56 --- /dev/null +++ b/drivers/clk/samsung/clk-s5pv210-audss.c | |||
@@ -0,0 +1,241 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014 Tomasz Figa <t.figa@samsung.com> | ||
3 | * | ||
4 | * Based on Exynos Audio Subsystem Clock Controller driver: | ||
5 | * | ||
6 | * Copyright (c) 2013 Samsung Electronics Co., Ltd. | ||
7 | * Author: Padmavathi Venna <padma.v@samsung.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * Driver for Audio Subsystem Clock Controller of S5PV210-compatible SoCs. | ||
14 | */ | ||
15 | |||
16 | #include <linux/clkdev.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/clk-provider.h> | ||
19 | #include <linux/of_address.h> | ||
20 | #include <linux/syscore_ops.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | |||
24 | #include <dt-bindings/clock/s5pv210-audss.h> | ||
25 | |||
26 | static DEFINE_SPINLOCK(lock); | ||
27 | static struct clk **clk_table; | ||
28 | static void __iomem *reg_base; | ||
29 | static struct clk_onecell_data clk_data; | ||
30 | |||
31 | #define ASS_CLK_SRC 0x0 | ||
32 | #define ASS_CLK_DIV 0x4 | ||
33 | #define ASS_CLK_GATE 0x8 | ||
34 | |||
35 | #ifdef CONFIG_PM_SLEEP | ||
36 | static unsigned long reg_save[][2] = { | ||
37 | {ASS_CLK_SRC, 0}, | ||
38 | {ASS_CLK_DIV, 0}, | ||
39 | {ASS_CLK_GATE, 0}, | ||
40 | }; | ||
41 | |||
42 | static int s5pv210_audss_clk_suspend(void) | ||
43 | { | ||
44 | int i; | ||
45 | |||
46 | for (i = 0; i < ARRAY_SIZE(reg_save); i++) | ||
47 | reg_save[i][1] = readl(reg_base + reg_save[i][0]); | ||
48 | |||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static void s5pv210_audss_clk_resume(void) | ||
53 | { | ||
54 | int i; | ||
55 | |||
56 | for (i = 0; i < ARRAY_SIZE(reg_save); i++) | ||
57 | writel(reg_save[i][1], reg_base + reg_save[i][0]); | ||
58 | } | ||
59 | |||
60 | static struct syscore_ops s5pv210_audss_clk_syscore_ops = { | ||
61 | .suspend = s5pv210_audss_clk_suspend, | ||
62 | .resume = s5pv210_audss_clk_resume, | ||
63 | }; | ||
64 | #endif /* CONFIG_PM_SLEEP */ | ||
65 | |||
66 | /* register s5pv210_audss clocks */ | ||
67 | static int s5pv210_audss_clk_probe(struct platform_device *pdev) | ||
68 | { | ||
69 | int i, ret = 0; | ||
70 | struct resource *res; | ||
71 | const char *mout_audss_p[2]; | ||
72 | const char *mout_i2s_p[3]; | ||
73 | const char *hclk_p; | ||
74 | struct clk *hclk, *pll_ref, *pll_in, *cdclk, *sclk_audio; | ||
75 | |||
76 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
77 | reg_base = devm_ioremap_resource(&pdev->dev, res); | ||
78 | if (IS_ERR(reg_base)) { | ||
79 | dev_err(&pdev->dev, "failed to map audss registers\n"); | ||
80 | return PTR_ERR(reg_base); | ||
81 | } | ||
82 | |||
83 | clk_table = devm_kzalloc(&pdev->dev, | ||
84 | sizeof(struct clk *) * AUDSS_MAX_CLKS, | ||
85 | GFP_KERNEL); | ||
86 | if (!clk_table) | ||
87 | return -ENOMEM; | ||
88 | |||
89 | clk_data.clks = clk_table; | ||
90 | clk_data.clk_num = AUDSS_MAX_CLKS; | ||
91 | |||
92 | hclk = devm_clk_get(&pdev->dev, "hclk"); | ||
93 | if (IS_ERR(hclk)) { | ||
94 | dev_err(&pdev->dev, "failed to get hclk clock\n"); | ||
95 | return PTR_ERR(hclk); | ||
96 | } | ||
97 | |||
98 | pll_in = devm_clk_get(&pdev->dev, "fout_epll"); | ||
99 | if (IS_ERR(pll_in)) { | ||
100 | dev_err(&pdev->dev, "failed to get fout_epll clock\n"); | ||
101 | return PTR_ERR(pll_in); | ||
102 | } | ||
103 | |||
104 | sclk_audio = devm_clk_get(&pdev->dev, "sclk_audio0"); | ||
105 | if (IS_ERR(sclk_audio)) { | ||
106 | dev_err(&pdev->dev, "failed to get sclk_audio0 clock\n"); | ||
107 | return PTR_ERR(sclk_audio); | ||
108 | } | ||
109 | |||
110 | /* iiscdclk0 is an optional external I2S codec clock */ | ||
111 | cdclk = devm_clk_get(&pdev->dev, "iiscdclk0"); | ||
112 | pll_ref = devm_clk_get(&pdev->dev, "xxti"); | ||
113 | |||
114 | if (!IS_ERR(pll_ref)) | ||
115 | mout_audss_p[0] = __clk_get_name(pll_ref); | ||
116 | else | ||
117 | mout_audss_p[0] = "xxti"; | ||
118 | mout_audss_p[1] = __clk_get_name(pll_in); | ||
119 | clk_table[CLK_MOUT_AUDSS] = clk_register_mux(NULL, "mout_audss", | ||
120 | mout_audss_p, ARRAY_SIZE(mout_audss_p), | ||
121 | CLK_SET_RATE_NO_REPARENT, | ||
122 | reg_base + ASS_CLK_SRC, 0, 1, 0, &lock); | ||
123 | |||
124 | mout_i2s_p[0] = "mout_audss"; | ||
125 | if (!IS_ERR(cdclk)) | ||
126 | mout_i2s_p[1] = __clk_get_name(cdclk); | ||
127 | else | ||
128 | mout_i2s_p[1] = "iiscdclk0"; | ||
129 | mout_i2s_p[2] = __clk_get_name(sclk_audio); | ||
130 | clk_table[CLK_MOUT_I2S_A] = clk_register_mux(NULL, "mout_i2s_audss", | ||
131 | mout_i2s_p, ARRAY_SIZE(mout_i2s_p), | ||
132 | CLK_SET_RATE_NO_REPARENT, | ||
133 | reg_base + ASS_CLK_SRC, 2, 2, 0, &lock); | ||
134 | |||
135 | clk_table[CLK_DOUT_AUD_BUS] = clk_register_divider(NULL, | ||
136 | "dout_aud_bus", "mout_audss", 0, | ||
137 | reg_base + ASS_CLK_DIV, 0, 4, 0, &lock); | ||
138 | clk_table[CLK_DOUT_I2S_A] = clk_register_divider(NULL, "dout_i2s_audss", | ||
139 | "mout_i2s_audss", 0, reg_base + ASS_CLK_DIV, | ||
140 | 4, 4, 0, &lock); | ||
141 | |||
142 | clk_table[CLK_I2S] = clk_register_gate(NULL, "i2s_audss", | ||
143 | "dout_i2s_audss", CLK_SET_RATE_PARENT, | ||
144 | reg_base + ASS_CLK_GATE, 6, 0, &lock); | ||
145 | |||
146 | hclk_p = __clk_get_name(hclk); | ||
147 | |||
148 | clk_table[CLK_HCLK_I2S] = clk_register_gate(NULL, "hclk_i2s_audss", | ||
149 | hclk_p, CLK_IGNORE_UNUSED, | ||
150 | reg_base + ASS_CLK_GATE, 5, 0, &lock); | ||
151 | clk_table[CLK_HCLK_UART] = clk_register_gate(NULL, "hclk_uart_audss", | ||
152 | hclk_p, CLK_IGNORE_UNUSED, | ||
153 | reg_base + ASS_CLK_GATE, 4, 0, &lock); | ||
154 | clk_table[CLK_HCLK_HWA] = clk_register_gate(NULL, "hclk_hwa_audss", | ||
155 | hclk_p, CLK_IGNORE_UNUSED, | ||
156 | reg_base + ASS_CLK_GATE, 3, 0, &lock); | ||
157 | clk_table[CLK_HCLK_DMA] = clk_register_gate(NULL, "hclk_dma_audss", | ||
158 | hclk_p, CLK_IGNORE_UNUSED, | ||
159 | reg_base + ASS_CLK_GATE, 2, 0, &lock); | ||
160 | clk_table[CLK_HCLK_BUF] = clk_register_gate(NULL, "hclk_buf_audss", | ||
161 | hclk_p, CLK_IGNORE_UNUSED, | ||
162 | reg_base + ASS_CLK_GATE, 1, 0, &lock); | ||
163 | clk_table[CLK_HCLK_RP] = clk_register_gate(NULL, "hclk_rp_audss", | ||
164 | hclk_p, CLK_IGNORE_UNUSED, | ||
165 | reg_base + ASS_CLK_GATE, 0, 0, &lock); | ||
166 | |||
167 | for (i = 0; i < clk_data.clk_num; i++) { | ||
168 | if (IS_ERR(clk_table[i])) { | ||
169 | dev_err(&pdev->dev, "failed to register clock %d\n", i); | ||
170 | ret = PTR_ERR(clk_table[i]); | ||
171 | goto unregister; | ||
172 | } | ||
173 | } | ||
174 | |||
175 | ret = of_clk_add_provider(pdev->dev.of_node, of_clk_src_onecell_get, | ||
176 | &clk_data); | ||
177 | if (ret) { | ||
178 | dev_err(&pdev->dev, "failed to add clock provider\n"); | ||
179 | goto unregister; | ||
180 | } | ||
181 | |||
182 | #ifdef CONFIG_PM_SLEEP | ||
183 | register_syscore_ops(&s5pv210_audss_clk_syscore_ops); | ||
184 | #endif | ||
185 | |||
186 | return 0; | ||
187 | |||
188 | unregister: | ||
189 | for (i = 0; i < clk_data.clk_num; i++) { | ||
190 | if (!IS_ERR(clk_table[i])) | ||
191 | clk_unregister(clk_table[i]); | ||
192 | } | ||
193 | |||
194 | return ret; | ||
195 | } | ||
196 | |||
197 | static int s5pv210_audss_clk_remove(struct platform_device *pdev) | ||
198 | { | ||
199 | int i; | ||
200 | |||
201 | of_clk_del_provider(pdev->dev.of_node); | ||
202 | |||
203 | for (i = 0; i < clk_data.clk_num; i++) { | ||
204 | if (!IS_ERR(clk_table[i])) | ||
205 | clk_unregister(clk_table[i]); | ||
206 | } | ||
207 | |||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static const struct of_device_id s5pv210_audss_clk_of_match[] = { | ||
212 | { .compatible = "samsung,s5pv210-audss-clock", }, | ||
213 | {}, | ||
214 | }; | ||
215 | |||
216 | static struct platform_driver s5pv210_audss_clk_driver = { | ||
217 | .driver = { | ||
218 | .name = "s5pv210-audss-clk", | ||
219 | .owner = THIS_MODULE, | ||
220 | .of_match_table = s5pv210_audss_clk_of_match, | ||
221 | }, | ||
222 | .probe = s5pv210_audss_clk_probe, | ||
223 | .remove = s5pv210_audss_clk_remove, | ||
224 | }; | ||
225 | |||
226 | static int __init s5pv210_audss_clk_init(void) | ||
227 | { | ||
228 | return platform_driver_register(&s5pv210_audss_clk_driver); | ||
229 | } | ||
230 | core_initcall(s5pv210_audss_clk_init); | ||
231 | |||
232 | static void __exit s5pv210_audss_clk_exit(void) | ||
233 | { | ||
234 | platform_driver_unregister(&s5pv210_audss_clk_driver); | ||
235 | } | ||
236 | module_exit(s5pv210_audss_clk_exit); | ||
237 | |||
238 | MODULE_AUTHOR("Tomasz Figa <t.figa@samsung.com>"); | ||
239 | MODULE_DESCRIPTION("S5PV210 Audio Subsystem Clock Controller"); | ||
240 | MODULE_LICENSE("GPL v2"); | ||
241 | MODULE_ALIAS("platform:s5pv210-audss-clk"); | ||
diff --git a/drivers/clk/samsung/clk-s5pv210.c b/drivers/clk/samsung/clk-s5pv210.c new file mode 100644 index 000000000000..d270a2084644 --- /dev/null +++ b/drivers/clk/samsung/clk-s5pv210.c | |||
@@ -0,0 +1,856 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013 Samsung Electronics Co., Ltd. | ||
3 | * Author: Mateusz Krawczuk <m.krawczuk@partner.samsung.com> | ||
4 | * | ||
5 | * Based on clock drivers for S3C64xx and Exynos4 SoCs. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * Common Clock Framework support for all S5PC110/S5PV210 SoCs. | ||
12 | */ | ||
13 | |||
14 | #include <linux/clk.h> | ||
15 | #include <linux/clkdev.h> | ||
16 | #include <linux/clk-provider.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/of_address.h> | ||
19 | #include <linux/syscore_ops.h> | ||
20 | |||
21 | #include "clk.h" | ||
22 | #include "clk-pll.h" | ||
23 | |||
24 | #include <dt-bindings/clock/s5pv210.h> | ||
25 | |||
26 | /* S5PC110/S5PV210 clock controller register offsets */ | ||
27 | #define APLL_LOCK 0x0000 | ||
28 | #define MPLL_LOCK 0x0008 | ||
29 | #define EPLL_LOCK 0x0010 | ||
30 | #define VPLL_LOCK 0x0020 | ||
31 | #define APLL_CON0 0x0100 | ||
32 | #define APLL_CON1 0x0104 | ||
33 | #define MPLL_CON 0x0108 | ||
34 | #define EPLL_CON0 0x0110 | ||
35 | #define EPLL_CON1 0x0114 | ||
36 | #define VPLL_CON 0x0120 | ||
37 | #define CLK_SRC0 0x0200 | ||
38 | #define CLK_SRC1 0x0204 | ||
39 | #define CLK_SRC2 0x0208 | ||
40 | #define CLK_SRC3 0x020c | ||
41 | #define CLK_SRC4 0x0210 | ||
42 | #define CLK_SRC5 0x0214 | ||
43 | #define CLK_SRC6 0x0218 | ||
44 | #define CLK_SRC_MASK0 0x0280 | ||
45 | #define CLK_SRC_MASK1 0x0284 | ||
46 | #define CLK_DIV0 0x0300 | ||
47 | #define CLK_DIV1 0x0304 | ||
48 | #define CLK_DIV2 0x0308 | ||
49 | #define CLK_DIV3 0x030c | ||
50 | #define CLK_DIV4 0x0310 | ||
51 | #define CLK_DIV5 0x0314 | ||
52 | #define CLK_DIV6 0x0318 | ||
53 | #define CLK_DIV7 0x031c | ||
54 | #define CLK_GATE_MAIN0 0x0400 | ||
55 | #define CLK_GATE_MAIN1 0x0404 | ||
56 | #define CLK_GATE_MAIN2 0x0408 | ||
57 | #define CLK_GATE_PERI0 0x0420 | ||
58 | #define CLK_GATE_PERI1 0x0424 | ||
59 | #define CLK_GATE_SCLK0 0x0440 | ||
60 | #define CLK_GATE_SCLK1 0x0444 | ||
61 | #define CLK_GATE_IP0 0x0460 | ||
62 | #define CLK_GATE_IP1 0x0464 | ||
63 | #define CLK_GATE_IP2 0x0468 | ||
64 | #define CLK_GATE_IP3 0x046c | ||
65 | #define CLK_GATE_IP4 0x0470 | ||
66 | #define CLK_GATE_BLOCK 0x0480 | ||
67 | #define CLK_GATE_IP5 0x0484 | ||
68 | #define CLK_OUT 0x0500 | ||
69 | #define MISC 0xe000 | ||
70 | #define OM_STAT 0xe100 | ||
71 | |||
72 | /* IDs of PLLs available on S5PV210/S5P6442 SoCs */ | ||
73 | enum { | ||
74 | apll, | ||
75 | mpll, | ||
76 | epll, | ||
77 | vpll, | ||
78 | }; | ||
79 | |||
80 | /* IDs of external clocks (used for legacy boards) */ | ||
81 | enum { | ||
82 | xxti, | ||
83 | xusbxti, | ||
84 | }; | ||
85 | |||
86 | static void __iomem *reg_base; | ||
87 | |||
88 | #ifdef CONFIG_PM_SLEEP | ||
89 | static struct samsung_clk_reg_dump *s5pv210_clk_dump; | ||
90 | |||
91 | /* List of registers that need to be preserved across suspend/resume. */ | ||
92 | static unsigned long s5pv210_clk_regs[] __initdata = { | ||
93 | CLK_SRC0, | ||
94 | CLK_SRC1, | ||
95 | CLK_SRC2, | ||
96 | CLK_SRC3, | ||
97 | CLK_SRC4, | ||
98 | CLK_SRC5, | ||
99 | CLK_SRC6, | ||
100 | CLK_SRC_MASK0, | ||
101 | CLK_SRC_MASK1, | ||
102 | CLK_DIV0, | ||
103 | CLK_DIV1, | ||
104 | CLK_DIV2, | ||
105 | CLK_DIV3, | ||
106 | CLK_DIV4, | ||
107 | CLK_DIV5, | ||
108 | CLK_DIV6, | ||
109 | CLK_DIV7, | ||
110 | CLK_GATE_MAIN0, | ||
111 | CLK_GATE_MAIN1, | ||
112 | CLK_GATE_MAIN2, | ||
113 | CLK_GATE_PERI0, | ||
114 | CLK_GATE_PERI1, | ||
115 | CLK_GATE_SCLK0, | ||
116 | CLK_GATE_SCLK1, | ||
117 | CLK_GATE_IP0, | ||
118 | CLK_GATE_IP1, | ||
119 | CLK_GATE_IP2, | ||
120 | CLK_GATE_IP3, | ||
121 | CLK_GATE_IP4, | ||
122 | CLK_GATE_IP5, | ||
123 | CLK_GATE_BLOCK, | ||
124 | APLL_LOCK, | ||
125 | MPLL_LOCK, | ||
126 | EPLL_LOCK, | ||
127 | VPLL_LOCK, | ||
128 | APLL_CON0, | ||
129 | APLL_CON1, | ||
130 | MPLL_CON, | ||
131 | EPLL_CON0, | ||
132 | EPLL_CON1, | ||
133 | VPLL_CON, | ||
134 | CLK_OUT, | ||
135 | }; | ||
136 | |||
137 | static int s5pv210_clk_suspend(void) | ||
138 | { | ||
139 | samsung_clk_save(reg_base, s5pv210_clk_dump, | ||
140 | ARRAY_SIZE(s5pv210_clk_regs)); | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static void s5pv210_clk_resume(void) | ||
145 | { | ||
146 | samsung_clk_restore(reg_base, s5pv210_clk_dump, | ||
147 | ARRAY_SIZE(s5pv210_clk_regs)); | ||
148 | } | ||
149 | |||
150 | static struct syscore_ops s5pv210_clk_syscore_ops = { | ||
151 | .suspend = s5pv210_clk_suspend, | ||
152 | .resume = s5pv210_clk_resume, | ||
153 | }; | ||
154 | |||
155 | static void s5pv210_clk_sleep_init(void) | ||
156 | { | ||
157 | s5pv210_clk_dump = | ||
158 | samsung_clk_alloc_reg_dump(s5pv210_clk_regs, | ||
159 | ARRAY_SIZE(s5pv210_clk_regs)); | ||
160 | if (!s5pv210_clk_dump) { | ||
161 | pr_warn("%s: Failed to allocate sleep save data\n", __func__); | ||
162 | return; | ||
163 | } | ||
164 | |||
165 | register_syscore_ops(&s5pv210_clk_syscore_ops); | ||
166 | } | ||
167 | #else | ||
168 | static inline void s5pv210_clk_sleep_init(void) { } | ||
169 | #endif | ||
170 | |||
171 | /* Mux parent lists. */ | ||
172 | static const char *fin_pll_p[] __initconst = { | ||
173 | "xxti", | ||
174 | "xusbxti" | ||
175 | }; | ||
176 | |||
177 | static const char *mout_apll_p[] __initconst = { | ||
178 | "fin_pll", | ||
179 | "fout_apll" | ||
180 | }; | ||
181 | |||
182 | static const char *mout_mpll_p[] __initconst = { | ||
183 | "fin_pll", | ||
184 | "fout_mpll" | ||
185 | }; | ||
186 | |||
187 | static const char *mout_epll_p[] __initconst = { | ||
188 | "fin_pll", | ||
189 | "fout_epll" | ||
190 | }; | ||
191 | |||
192 | static const char *mout_vpllsrc_p[] __initconst = { | ||
193 | "fin_pll", | ||
194 | "sclk_hdmi27m" | ||
195 | }; | ||
196 | |||
197 | static const char *mout_vpll_p[] __initconst = { | ||
198 | "mout_vpllsrc", | ||
199 | "fout_vpll" | ||
200 | }; | ||
201 | |||
202 | static const char *mout_group1_p[] __initconst = { | ||
203 | "dout_a2m", | ||
204 | "mout_mpll", | ||
205 | "mout_epll", | ||
206 | "mout_vpll" | ||
207 | }; | ||
208 | |||
209 | static const char *mout_group2_p[] __initconst = { | ||
210 | "xxti", | ||
211 | "xusbxti", | ||
212 | "sclk_hdmi27m", | ||
213 | "sclk_usbphy0", | ||
214 | "sclk_usbphy1", | ||
215 | "sclk_hdmiphy", | ||
216 | "mout_mpll", | ||
217 | "mout_epll", | ||
218 | "mout_vpll", | ||
219 | }; | ||
220 | |||
221 | static const char *mout_audio0_p[] __initconst = { | ||
222 | "xxti", | ||
223 | "pcmcdclk0", | ||
224 | "sclk_hdmi27m", | ||
225 | "sclk_usbphy0", | ||
226 | "sclk_usbphy1", | ||
227 | "sclk_hdmiphy", | ||
228 | "mout_mpll", | ||
229 | "mout_epll", | ||
230 | "mout_vpll", | ||
231 | }; | ||
232 | |||
233 | static const char *mout_audio1_p[] __initconst = { | ||
234 | "i2scdclk1", | ||
235 | "pcmcdclk1", | ||
236 | "sclk_hdmi27m", | ||
237 | "sclk_usbphy0", | ||
238 | "sclk_usbphy1", | ||
239 | "sclk_hdmiphy", | ||
240 | "mout_mpll", | ||
241 | "mout_epll", | ||
242 | "mout_vpll", | ||
243 | }; | ||
244 | |||
245 | static const char *mout_audio2_p[] __initconst = { | ||
246 | "i2scdclk2", | ||
247 | "pcmcdclk2", | ||
248 | "sclk_hdmi27m", | ||
249 | "sclk_usbphy0", | ||
250 | "sclk_usbphy1", | ||
251 | "sclk_hdmiphy", | ||
252 | "mout_mpll", | ||
253 | "mout_epll", | ||
254 | "mout_vpll", | ||
255 | }; | ||
256 | |||
257 | static const char *mout_spdif_p[] __initconst = { | ||
258 | "dout_audio0", | ||
259 | "dout_audio1", | ||
260 | "dout_audio3", | ||
261 | }; | ||
262 | |||
263 | static const char *mout_group3_p[] __initconst = { | ||
264 | "mout_apll", | ||
265 | "mout_mpll" | ||
266 | }; | ||
267 | |||
268 | static const char *mout_group4_p[] __initconst = { | ||
269 | "mout_mpll", | ||
270 | "dout_a2m" | ||
271 | }; | ||
272 | |||
273 | static const char *mout_flash_p[] __initconst = { | ||
274 | "dout_hclkd", | ||
275 | "dout_hclkp" | ||
276 | }; | ||
277 | |||
278 | static const char *mout_dac_p[] __initconst = { | ||
279 | "mout_vpll", | ||
280 | "sclk_hdmiphy" | ||
281 | }; | ||
282 | |||
283 | static const char *mout_hdmi_p[] __initconst = { | ||
284 | "sclk_hdmiphy", | ||
285 | "dout_tblk" | ||
286 | }; | ||
287 | |||
288 | static const char *mout_mixer_p[] __initconst = { | ||
289 | "mout_dac", | ||
290 | "mout_hdmi" | ||
291 | }; | ||
292 | |||
293 | static const char *mout_vpll_6442_p[] __initconst = { | ||
294 | "fin_pll", | ||
295 | "fout_vpll" | ||
296 | }; | ||
297 | |||
298 | static const char *mout_mixer_6442_p[] __initconst = { | ||
299 | "mout_vpll", | ||
300 | "dout_mixer" | ||
301 | }; | ||
302 | |||
303 | static const char *mout_d0sync_6442_p[] __initconst = { | ||
304 | "mout_dsys", | ||
305 | "div_apll" | ||
306 | }; | ||
307 | |||
308 | static const char *mout_d1sync_6442_p[] __initconst = { | ||
309 | "mout_psys", | ||
310 | "div_apll" | ||
311 | }; | ||
312 | |||
313 | static const char *mout_group2_6442_p[] __initconst = { | ||
314 | "fin_pll", | ||
315 | "none", | ||
316 | "none", | ||
317 | "sclk_usbphy0", | ||
318 | "none", | ||
319 | "none", | ||
320 | "mout_mpll", | ||
321 | "mout_epll", | ||
322 | "mout_vpll", | ||
323 | }; | ||
324 | |||
325 | static const char *mout_audio0_6442_p[] __initconst = { | ||
326 | "fin_pll", | ||
327 | "pcmcdclk0", | ||
328 | "none", | ||
329 | "sclk_usbphy0", | ||
330 | "none", | ||
331 | "none", | ||
332 | "mout_mpll", | ||
333 | "mout_epll", | ||
334 | "mout_vpll", | ||
335 | }; | ||
336 | |||
337 | static const char *mout_audio1_6442_p[] __initconst = { | ||
338 | "i2scdclk1", | ||
339 | "pcmcdclk1", | ||
340 | "none", | ||
341 | "sclk_usbphy0", | ||
342 | "none", | ||
343 | "none", | ||
344 | "mout_mpll", | ||
345 | "mout_epll", | ||
346 | "mout_vpll", | ||
347 | "fin_pll", | ||
348 | }; | ||
349 | |||
350 | static const char *mout_clksel_p[] __initconst = { | ||
351 | "fout_apll_clkout", | ||
352 | "fout_mpll_clkout", | ||
353 | "fout_epll", | ||
354 | "fout_vpll", | ||
355 | "sclk_usbphy0", | ||
356 | "sclk_usbphy1", | ||
357 | "sclk_hdmiphy", | ||
358 | "rtc", | ||
359 | "rtc_tick", | ||
360 | "dout_hclkm", | ||
361 | "dout_pclkm", | ||
362 | "dout_hclkd", | ||
363 | "dout_pclkd", | ||
364 | "dout_hclkp", | ||
365 | "dout_pclkp", | ||
366 | "dout_apll_clkout", | ||
367 | "dout_hpm", | ||
368 | "xxti", | ||
369 | "xusbxti", | ||
370 | "div_dclk" | ||
371 | }; | ||
372 | |||
373 | static const char *mout_clksel_6442_p[] __initconst = { | ||
374 | "fout_apll_clkout", | ||
375 | "fout_mpll_clkout", | ||
376 | "fout_epll", | ||
377 | "fout_vpll", | ||
378 | "sclk_usbphy0", | ||
379 | "none", | ||
380 | "none", | ||
381 | "rtc", | ||
382 | "rtc_tick", | ||
383 | "none", | ||
384 | "none", | ||
385 | "dout_hclkd", | ||
386 | "dout_pclkd", | ||
387 | "dout_hclkp", | ||
388 | "dout_pclkp", | ||
389 | "dout_apll_clkout", | ||
390 | "none", | ||
391 | "fin_pll", | ||
392 | "none", | ||
393 | "div_dclk" | ||
394 | }; | ||
395 | |||
396 | static const char *mout_clkout_p[] __initconst = { | ||
397 | "dout_clkout", | ||
398 | "none", | ||
399 | "xxti", | ||
400 | "xusbxti" | ||
401 | }; | ||
402 | |||
403 | /* Common fixed factor clocks. */ | ||
404 | static struct samsung_fixed_factor_clock ffactor_clks[] __initdata = { | ||
405 | FFACTOR(FOUT_APLL_CLKOUT, "fout_apll_clkout", "fout_apll", 1, 4, 0), | ||
406 | FFACTOR(FOUT_MPLL_CLKOUT, "fout_mpll_clkout", "fout_mpll", 1, 2, 0), | ||
407 | FFACTOR(DOUT_APLL_CLKOUT, "dout_apll_clkout", "dout_apll", 1, 4, 0), | ||
408 | }; | ||
409 | |||
410 | /* PLL input mux (fin_pll), which needs to be registered before PLLs. */ | ||
411 | static struct samsung_mux_clock early_mux_clks[] __initdata = { | ||
412 | MUX_F(FIN_PLL, "fin_pll", fin_pll_p, OM_STAT, 0, 1, | ||
413 | CLK_MUX_READ_ONLY, 0), | ||
414 | }; | ||
415 | |||
416 | /* Common clock muxes. */ | ||
417 | static struct samsung_mux_clock mux_clks[] __initdata = { | ||
418 | MUX(MOUT_FLASH, "mout_flash", mout_flash_p, CLK_SRC0, 28, 1), | ||
419 | MUX(MOUT_PSYS, "mout_psys", mout_group4_p, CLK_SRC0, 24, 1), | ||
420 | MUX(MOUT_DSYS, "mout_dsys", mout_group4_p, CLK_SRC0, 20, 1), | ||
421 | MUX(MOUT_MSYS, "mout_msys", mout_group3_p, CLK_SRC0, 16, 1), | ||
422 | MUX(MOUT_EPLL, "mout_epll", mout_epll_p, CLK_SRC0, 8, 1), | ||
423 | MUX(MOUT_MPLL, "mout_mpll", mout_mpll_p, CLK_SRC0, 4, 1), | ||
424 | MUX(MOUT_APLL, "mout_apll", mout_apll_p, CLK_SRC0, 0, 1), | ||
425 | |||
426 | MUX(MOUT_CLKOUT, "mout_clkout", mout_clkout_p, MISC, 8, 2), | ||
427 | }; | ||
428 | |||
429 | /* S5PV210-specific clock muxes. */ | ||
430 | static struct samsung_mux_clock s5pv210_mux_clks[] __initdata = { | ||
431 | MUX(MOUT_VPLL, "mout_vpll", mout_vpll_p, CLK_SRC0, 12, 1), | ||
432 | |||
433 | MUX(MOUT_VPLLSRC, "mout_vpllsrc", mout_vpllsrc_p, CLK_SRC1, 28, 1), | ||
434 | MUX(MOUT_CSIS, "mout_csis", mout_group2_p, CLK_SRC1, 24, 4), | ||
435 | MUX(MOUT_FIMD, "mout_fimd", mout_group2_p, CLK_SRC1, 20, 4), | ||
436 | MUX(MOUT_CAM1, "mout_cam1", mout_group2_p, CLK_SRC1, 16, 4), | ||
437 | MUX(MOUT_CAM0, "mout_cam0", mout_group2_p, CLK_SRC1, 12, 4), | ||
438 | MUX(MOUT_DAC, "mout_dac", mout_dac_p, CLK_SRC1, 8, 1), | ||
439 | MUX(MOUT_MIXER, "mout_mixer", mout_mixer_p, CLK_SRC1, 4, 1), | ||
440 | MUX(MOUT_HDMI, "mout_hdmi", mout_hdmi_p, CLK_SRC1, 0, 1), | ||
441 | |||
442 | MUX(MOUT_G2D, "mout_g2d", mout_group1_p, CLK_SRC2, 8, 2), | ||
443 | MUX(MOUT_MFC, "mout_mfc", mout_group1_p, CLK_SRC2, 4, 2), | ||
444 | MUX(MOUT_G3D, "mout_g3d", mout_group1_p, CLK_SRC2, 0, 2), | ||
445 | |||
446 | MUX(MOUT_FIMC2, "mout_fimc2", mout_group2_p, CLK_SRC3, 20, 4), | ||
447 | MUX(MOUT_FIMC1, "mout_fimc1", mout_group2_p, CLK_SRC3, 16, 4), | ||
448 | MUX(MOUT_FIMC0, "mout_fimc0", mout_group2_p, CLK_SRC3, 12, 4), | ||
449 | |||
450 | MUX(MOUT_UART3, "mout_uart3", mout_group2_p, CLK_SRC4, 28, 4), | ||
451 | MUX(MOUT_UART2, "mout_uart2", mout_group2_p, CLK_SRC4, 24, 4), | ||
452 | MUX(MOUT_UART1, "mout_uart1", mout_group2_p, CLK_SRC4, 20, 4), | ||
453 | MUX(MOUT_UART0, "mout_uart0", mout_group2_p, CLK_SRC4, 16, 4), | ||
454 | MUX(MOUT_MMC3, "mout_mmc3", mout_group2_p, CLK_SRC4, 12, 4), | ||
455 | MUX(MOUT_MMC2, "mout_mmc2", mout_group2_p, CLK_SRC4, 8, 4), | ||
456 | MUX(MOUT_MMC1, "mout_mmc1", mout_group2_p, CLK_SRC4, 4, 4), | ||
457 | MUX(MOUT_MMC0, "mout_mmc0", mout_group2_p, CLK_SRC4, 0, 4), | ||
458 | |||
459 | MUX(MOUT_PWM, "mout_pwm", mout_group2_p, CLK_SRC5, 12, 4), | ||
460 | MUX(MOUT_SPI1, "mout_spi1", mout_group2_p, CLK_SRC5, 4, 4), | ||
461 | MUX(MOUT_SPI0, "mout_spi0", mout_group2_p, CLK_SRC5, 0, 4), | ||
462 | |||
463 | MUX(MOUT_DMC0, "mout_dmc0", mout_group1_p, CLK_SRC6, 24, 2), | ||
464 | MUX(MOUT_PWI, "mout_pwi", mout_group2_p, CLK_SRC6, 20, 4), | ||
465 | MUX(MOUT_HPM, "mout_hpm", mout_group3_p, CLK_SRC6, 16, 1), | ||
466 | MUX(MOUT_SPDIF, "mout_spdif", mout_spdif_p, CLK_SRC6, 12, 2), | ||
467 | MUX(MOUT_AUDIO2, "mout_audio2", mout_audio2_p, CLK_SRC6, 8, 4), | ||
468 | MUX(MOUT_AUDIO1, "mout_audio1", mout_audio1_p, CLK_SRC6, 4, 4), | ||
469 | MUX(MOUT_AUDIO0, "mout_audio0", mout_audio0_p, CLK_SRC6, 0, 4), | ||
470 | |||
471 | MUX(MOUT_CLKSEL, "mout_clksel", mout_clksel_p, CLK_OUT, 12, 5), | ||
472 | }; | ||
473 | |||
474 | /* S5P6442-specific clock muxes. */ | ||
475 | static struct samsung_mux_clock s5p6442_mux_clks[] __initdata = { | ||
476 | MUX(MOUT_VPLL, "mout_vpll", mout_vpll_6442_p, CLK_SRC0, 12, 1), | ||
477 | |||
478 | MUX(MOUT_FIMD, "mout_fimd", mout_group2_6442_p, CLK_SRC1, 20, 4), | ||
479 | MUX(MOUT_CAM1, "mout_cam1", mout_group2_6442_p, CLK_SRC1, 16, 4), | ||
480 | MUX(MOUT_CAM0, "mout_cam0", mout_group2_6442_p, CLK_SRC1, 12, 4), | ||
481 | MUX(MOUT_MIXER, "mout_mixer", mout_mixer_6442_p, CLK_SRC1, 4, 1), | ||
482 | |||
483 | MUX(MOUT_D0SYNC, "mout_d0sync", mout_d0sync_6442_p, CLK_SRC2, 28, 1), | ||
484 | MUX(MOUT_D1SYNC, "mout_d1sync", mout_d1sync_6442_p, CLK_SRC2, 24, 1), | ||
485 | |||
486 | MUX(MOUT_FIMC2, "mout_fimc2", mout_group2_6442_p, CLK_SRC3, 20, 4), | ||
487 | MUX(MOUT_FIMC1, "mout_fimc1", mout_group2_6442_p, CLK_SRC3, 16, 4), | ||
488 | MUX(MOUT_FIMC0, "mout_fimc0", mout_group2_6442_p, CLK_SRC3, 12, 4), | ||
489 | |||
490 | MUX(MOUT_UART2, "mout_uart2", mout_group2_6442_p, CLK_SRC4, 24, 4), | ||
491 | MUX(MOUT_UART1, "mout_uart1", mout_group2_6442_p, CLK_SRC4, 20, 4), | ||
492 | MUX(MOUT_UART0, "mout_uart0", mout_group2_6442_p, CLK_SRC4, 16, 4), | ||
493 | MUX(MOUT_MMC2, "mout_mmc2", mout_group2_6442_p, CLK_SRC4, 8, 4), | ||
494 | MUX(MOUT_MMC1, "mout_mmc1", mout_group2_6442_p, CLK_SRC4, 4, 4), | ||
495 | MUX(MOUT_MMC0, "mout_mmc0", mout_group2_6442_p, CLK_SRC4, 0, 4), | ||
496 | |||
497 | MUX(MOUT_PWM, "mout_pwm", mout_group2_6442_p, CLK_SRC5, 12, 4), | ||
498 | MUX(MOUT_SPI0, "mout_spi0", mout_group2_6442_p, CLK_SRC5, 0, 4), | ||
499 | |||
500 | MUX(MOUT_AUDIO1, "mout_audio1", mout_audio1_6442_p, CLK_SRC6, 4, 4), | ||
501 | MUX(MOUT_AUDIO0, "mout_audio0", mout_audio0_6442_p, CLK_SRC6, 0, 4), | ||
502 | |||
503 | MUX(MOUT_CLKSEL, "mout_clksel", mout_clksel_6442_p, CLK_OUT, 12, 5), | ||
504 | }; | ||
505 | |||
506 | /* S5PV210-specific fixed rate clocks generated inside the SoC. */ | ||
507 | static struct samsung_fixed_rate_clock s5pv210_frate_clks[] __initdata = { | ||
508 | FRATE(SCLK_HDMI27M, "sclk_hdmi27m", NULL, CLK_IS_ROOT, 27000000), | ||
509 | FRATE(SCLK_HDMIPHY, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 27000000), | ||
510 | FRATE(SCLK_USBPHY0, "sclk_usbphy0", NULL, CLK_IS_ROOT, 48000000), | ||
511 | FRATE(SCLK_USBPHY1, "sclk_usbphy1", NULL, CLK_IS_ROOT, 48000000), | ||
512 | }; | ||
513 | |||
514 | /* S5P6442-specific fixed rate clocks generated inside the SoC. */ | ||
515 | static struct samsung_fixed_rate_clock s5p6442_frate_clks[] __initdata = { | ||
516 | FRATE(SCLK_USBPHY0, "sclk_usbphy0", NULL, CLK_IS_ROOT, 30000000), | ||
517 | }; | ||
518 | |||
519 | /* Common clock dividers. */ | ||
520 | static struct samsung_div_clock div_clks[] __initdata = { | ||
521 | DIV(DOUT_PCLKP, "dout_pclkp", "dout_hclkp", CLK_DIV0, 28, 3), | ||
522 | DIV(DOUT_PCLKD, "dout_pclkd", "dout_hclkd", CLK_DIV0, 20, 3), | ||
523 | DIV(DOUT_A2M, "dout_a2m", "mout_apll", CLK_DIV0, 4, 3), | ||
524 | DIV(DOUT_APLL, "dout_apll", "mout_msys", CLK_DIV0, 0, 3), | ||
525 | |||
526 | DIV(DOUT_FIMD, "dout_fimd", "mout_fimd", CLK_DIV1, 20, 4), | ||
527 | DIV(DOUT_CAM1, "dout_cam1", "mout_cam1", CLK_DIV1, 16, 4), | ||
528 | DIV(DOUT_CAM0, "dout_cam0", "mout_cam0", CLK_DIV1, 12, 4), | ||
529 | |||
530 | DIV(DOUT_FIMC2, "dout_fimc2", "mout_fimc2", CLK_DIV3, 20, 4), | ||
531 | DIV(DOUT_FIMC1, "dout_fimc1", "mout_fimc1", CLK_DIV3, 16, 4), | ||
532 | DIV(DOUT_FIMC0, "dout_fimc0", "mout_fimc0", CLK_DIV3, 12, 4), | ||
533 | |||
534 | DIV(DOUT_UART2, "dout_uart2", "mout_uart2", CLK_DIV4, 24, 4), | ||
535 | DIV(DOUT_UART1, "dout_uart1", "mout_uart1", CLK_DIV4, 20, 4), | ||
536 | DIV(DOUT_UART0, "dout_uart0", "mout_uart0", CLK_DIV4, 16, 4), | ||
537 | DIV(DOUT_MMC2, "dout_mmc2", "mout_mmc2", CLK_DIV4, 8, 4), | ||
538 | DIV(DOUT_MMC1, "dout_mmc1", "mout_mmc1", CLK_DIV4, 4, 4), | ||
539 | DIV(DOUT_MMC0, "dout_mmc0", "mout_mmc0", CLK_DIV4, 0, 4), | ||
540 | |||
541 | DIV(DOUT_PWM, "dout_pwm", "mout_pwm", CLK_DIV5, 12, 4), | ||
542 | DIV(DOUT_SPI0, "dout_spi0", "mout_spi0", CLK_DIV5, 0, 4), | ||
543 | |||
544 | DIV(DOUT_FLASH, "dout_flash", "mout_flash", CLK_DIV6, 12, 3), | ||
545 | DIV(DOUT_AUDIO1, "dout_audio1", "mout_audio1", CLK_DIV6, 4, 4), | ||
546 | DIV(DOUT_AUDIO0, "dout_audio0", "mout_audio0", CLK_DIV6, 0, 4), | ||
547 | |||
548 | DIV(DOUT_CLKOUT, "dout_clkout", "mout_clksel", CLK_OUT, 20, 4), | ||
549 | }; | ||
550 | |||
551 | /* S5PV210-specific clock dividers. */ | ||
552 | static struct samsung_div_clock s5pv210_div_clks[] __initdata = { | ||
553 | DIV(DOUT_HCLKP, "dout_hclkp", "mout_psys", CLK_DIV0, 24, 4), | ||
554 | DIV(DOUT_HCLKD, "dout_hclkd", "mout_dsys", CLK_DIV0, 16, 4), | ||
555 | DIV(DOUT_PCLKM, "dout_pclkm", "dout_hclkm", CLK_DIV0, 12, 3), | ||
556 | DIV(DOUT_HCLKM, "dout_hclkm", "dout_apll", CLK_DIV0, 8, 3), | ||
557 | |||
558 | DIV(DOUT_CSIS, "dout_csis", "mout_csis", CLK_DIV1, 28, 4), | ||
559 | DIV(DOUT_TBLK, "dout_tblk", "mout_vpll", CLK_DIV1, 0, 4), | ||
560 | |||
561 | DIV(DOUT_G2D, "dout_g2d", "mout_g2d", CLK_DIV2, 8, 4), | ||
562 | DIV(DOUT_MFC, "dout_mfc", "mout_mfc", CLK_DIV2, 4, 4), | ||
563 | DIV(DOUT_G3D, "dout_g3d", "mout_g3d", CLK_DIV2, 0, 4), | ||
564 | |||
565 | DIV(DOUT_UART3, "dout_uart3", "mout_uart3", CLK_DIV4, 28, 4), | ||
566 | DIV(DOUT_MMC3, "dout_mmc3", "mout_mmc3", CLK_DIV4, 12, 4), | ||
567 | |||
568 | DIV(DOUT_SPI1, "dout_spi1", "mout_spi1", CLK_DIV5, 4, 4), | ||
569 | |||
570 | DIV(DOUT_DMC0, "dout_dmc0", "mout_dmc0", CLK_DIV6, 28, 4), | ||
571 | DIV(DOUT_PWI, "dout_pwi", "mout_pwi", CLK_DIV6, 24, 4), | ||
572 | DIV(DOUT_HPM, "dout_hpm", "dout_copy", CLK_DIV6, 20, 3), | ||
573 | DIV(DOUT_COPY, "dout_copy", "mout_hpm", CLK_DIV6, 16, 3), | ||
574 | DIV(DOUT_AUDIO2, "dout_audio2", "mout_audio2", CLK_DIV6, 8, 4), | ||
575 | |||
576 | DIV(DOUT_DPM, "dout_dpm", "dout_pclkp", CLK_DIV7, 8, 7), | ||
577 | DIV(DOUT_DVSEM, "dout_dvsem", "dout_pclkp", CLK_DIV7, 0, 7), | ||
578 | }; | ||
579 | |||
580 | /* S5P6442-specific clock dividers. */ | ||
581 | static struct samsung_div_clock s5p6442_div_clks[] __initdata = { | ||
582 | DIV(DOUT_HCLKP, "dout_hclkp", "mout_d1sync", CLK_DIV0, 24, 4), | ||
583 | DIV(DOUT_HCLKD, "dout_hclkd", "mout_d0sync", CLK_DIV0, 16, 4), | ||
584 | |||
585 | DIV(DOUT_MIXER, "dout_mixer", "mout_vpll", CLK_DIV1, 0, 4), | ||
586 | }; | ||
587 | |||
588 | /* Common clock gates. */ | ||
589 | static struct samsung_gate_clock gate_clks[] __initdata = { | ||
590 | GATE(CLK_ROTATOR, "rotator", "dout_hclkd", CLK_GATE_IP0, 29, 0, 0), | ||
591 | GATE(CLK_FIMC2, "fimc2", "dout_hclkd", CLK_GATE_IP0, 26, 0, 0), | ||
592 | GATE(CLK_FIMC1, "fimc1", "dout_hclkd", CLK_GATE_IP0, 25, 0, 0), | ||
593 | GATE(CLK_FIMC0, "fimc0", "dout_hclkd", CLK_GATE_IP0, 24, 0, 0), | ||
594 | GATE(CLK_PDMA0, "pdma0", "dout_hclkp", CLK_GATE_IP0, 3, 0, 0), | ||
595 | GATE(CLK_MDMA, "mdma", "dout_hclkd", CLK_GATE_IP0, 2, 0, 0), | ||
596 | |||
597 | GATE(CLK_SROMC, "sromc", "dout_hclkp", CLK_GATE_IP1, 26, 0, 0), | ||
598 | GATE(CLK_NANDXL, "nandxl", "dout_hclkp", CLK_GATE_IP1, 24, 0, 0), | ||
599 | GATE(CLK_USB_OTG, "usb_otg", "dout_hclkp", CLK_GATE_IP1, 16, 0, 0), | ||
600 | GATE(CLK_TVENC, "tvenc", "dout_hclkd", CLK_GATE_IP1, 10, 0, 0), | ||
601 | GATE(CLK_MIXER, "mixer", "dout_hclkd", CLK_GATE_IP1, 9, 0, 0), | ||
602 | GATE(CLK_VP, "vp", "dout_hclkd", CLK_GATE_IP1, 8, 0, 0), | ||
603 | GATE(CLK_FIMD, "fimd", "dout_hclkd", CLK_GATE_IP1, 0, 0, 0), | ||
604 | |||
605 | GATE(CLK_HSMMC2, "hsmmc2", "dout_hclkp", CLK_GATE_IP2, 18, 0, 0), | ||
606 | GATE(CLK_HSMMC1, "hsmmc1", "dout_hclkp", CLK_GATE_IP2, 17, 0, 0), | ||
607 | GATE(CLK_HSMMC0, "hsmmc0", "dout_hclkp", CLK_GATE_IP2, 16, 0, 0), | ||
608 | GATE(CLK_MODEMIF, "modemif", "dout_hclkp", CLK_GATE_IP2, 9, 0, 0), | ||
609 | GATE(CLK_SECSS, "secss", "dout_hclkp", CLK_GATE_IP2, 0, 0, 0), | ||
610 | |||
611 | GATE(CLK_PCM1, "pcm1", "dout_pclkp", CLK_GATE_IP3, 29, 0, 0), | ||
612 | GATE(CLK_PCM0, "pcm0", "dout_pclkp", CLK_GATE_IP3, 28, 0, 0), | ||
613 | GATE(CLK_TSADC, "tsadc", "dout_pclkp", CLK_GATE_IP3, 24, 0, 0), | ||
614 | GATE(CLK_PWM, "pwm", "dout_pclkp", CLK_GATE_IP3, 23, 0, 0), | ||
615 | GATE(CLK_WDT, "watchdog", "dout_pclkp", CLK_GATE_IP3, 22, 0, 0), | ||
616 | GATE(CLK_KEYIF, "keyif", "dout_pclkp", CLK_GATE_IP3, 21, 0, 0), | ||
617 | GATE(CLK_UART2, "uart2", "dout_pclkp", CLK_GATE_IP3, 19, 0, 0), | ||
618 | GATE(CLK_UART1, "uart1", "dout_pclkp", CLK_GATE_IP3, 18, 0, 0), | ||
619 | GATE(CLK_UART0, "uart0", "dout_pclkp", CLK_GATE_IP3, 17, 0, 0), | ||
620 | GATE(CLK_SYSTIMER, "systimer", "dout_pclkp", CLK_GATE_IP3, 16, 0, 0), | ||
621 | GATE(CLK_RTC, "rtc", "dout_pclkp", CLK_GATE_IP3, 15, 0, 0), | ||
622 | GATE(CLK_SPI0, "spi0", "dout_pclkp", CLK_GATE_IP3, 12, 0, 0), | ||
623 | GATE(CLK_I2C2, "i2c2", "dout_pclkp", CLK_GATE_IP3, 9, 0, 0), | ||
624 | GATE(CLK_I2C0, "i2c0", "dout_pclkp", CLK_GATE_IP3, 7, 0, 0), | ||
625 | GATE(CLK_I2S1, "i2s1", "dout_pclkp", CLK_GATE_IP3, 5, 0, 0), | ||
626 | GATE(CLK_I2S0, "i2s0", "dout_pclkp", CLK_GATE_IP3, 4, 0, 0), | ||
627 | |||
628 | GATE(CLK_SECKEY, "seckey", "dout_pclkp", CLK_GATE_IP4, 3, 0, 0), | ||
629 | GATE(CLK_CHIPID, "chipid", "dout_pclkp", CLK_GATE_IP4, 0, 0, 0), | ||
630 | |||
631 | GATE(SCLK_AUDIO1, "sclk_audio1", "dout_audio1", CLK_SRC_MASK0, 25, | ||
632 | CLK_SET_RATE_PARENT, 0), | ||
633 | GATE(SCLK_AUDIO0, "sclk_audio0", "dout_audio0", CLK_SRC_MASK0, 24, | ||
634 | CLK_SET_RATE_PARENT, 0), | ||
635 | GATE(SCLK_PWM, "sclk_pwm", "dout_pwm", CLK_SRC_MASK0, 19, | ||
636 | CLK_SET_RATE_PARENT, 0), | ||
637 | GATE(SCLK_SPI0, "sclk_spi0", "dout_spi0", CLK_SRC_MASK0, 16, | ||
638 | CLK_SET_RATE_PARENT, 0), | ||
639 | GATE(SCLK_UART2, "sclk_uart2", "dout_uart2", CLK_SRC_MASK0, 14, | ||
640 | CLK_SET_RATE_PARENT, 0), | ||
641 | GATE(SCLK_UART1, "sclk_uart1", "dout_uart1", CLK_SRC_MASK0, 13, | ||
642 | CLK_SET_RATE_PARENT, 0), | ||
643 | GATE(SCLK_UART0, "sclk_uart0", "dout_uart0", CLK_SRC_MASK0, 12, | ||
644 | CLK_SET_RATE_PARENT, 0), | ||
645 | GATE(SCLK_MMC2, "sclk_mmc2", "dout_mmc2", CLK_SRC_MASK0, 10, | ||
646 | CLK_SET_RATE_PARENT, 0), | ||
647 | GATE(SCLK_MMC1, "sclk_mmc1", "dout_mmc1", CLK_SRC_MASK0, 9, | ||
648 | CLK_SET_RATE_PARENT, 0), | ||
649 | GATE(SCLK_MMC0, "sclk_mmc0", "dout_mmc0", CLK_SRC_MASK0, 8, | ||
650 | CLK_SET_RATE_PARENT, 0), | ||
651 | GATE(SCLK_FIMD, "sclk_fimd", "dout_fimd", CLK_SRC_MASK0, 5, | ||
652 | CLK_SET_RATE_PARENT, 0), | ||
653 | GATE(SCLK_CAM1, "sclk_cam1", "dout_cam1", CLK_SRC_MASK0, 4, | ||
654 | CLK_SET_RATE_PARENT, 0), | ||
655 | GATE(SCLK_CAM0, "sclk_cam0", "dout_cam0", CLK_SRC_MASK0, 3, | ||
656 | CLK_SET_RATE_PARENT, 0), | ||
657 | GATE(SCLK_MIXER, "sclk_mixer", "mout_mixer", CLK_SRC_MASK0, 1, | ||
658 | CLK_SET_RATE_PARENT, 0), | ||
659 | |||
660 | GATE(SCLK_FIMC2, "sclk_fimc2", "dout_fimc2", CLK_SRC_MASK1, 4, | ||
661 | CLK_SET_RATE_PARENT, 0), | ||
662 | GATE(SCLK_FIMC1, "sclk_fimc1", "dout_fimc1", CLK_SRC_MASK1, 3, | ||
663 | CLK_SET_RATE_PARENT, 0), | ||
664 | GATE(SCLK_FIMC0, "sclk_fimc0", "dout_fimc0", CLK_SRC_MASK1, 2, | ||
665 | CLK_SET_RATE_PARENT, 0), | ||
666 | }; | ||
667 | |||
668 | /* S5PV210-specific clock gates. */ | ||
669 | static struct samsung_gate_clock s5pv210_gate_clks[] __initdata = { | ||
670 | GATE(CLK_CSIS, "clk_csis", "dout_hclkd", CLK_GATE_IP0, 31, 0, 0), | ||
671 | GATE(CLK_MFC, "mfc", "dout_hclkm", CLK_GATE_IP0, 16, 0, 0), | ||
672 | GATE(CLK_G2D, "g2d", "dout_hclkd", CLK_GATE_IP0, 12, 0, 0), | ||
673 | GATE(CLK_G3D, "g3d", "dout_hclkm", CLK_GATE_IP0, 8, 0, 0), | ||
674 | GATE(CLK_IMEM, "imem", "dout_hclkm", CLK_GATE_IP0, 5, 0, 0), | ||
675 | GATE(CLK_PDMA1, "pdma1", "dout_hclkp", CLK_GATE_IP0, 4, 0, 0), | ||
676 | |||
677 | GATE(CLK_NFCON, "nfcon", "dout_hclkp", CLK_GATE_IP1, 28, 0, 0), | ||
678 | GATE(CLK_CFCON, "cfcon", "dout_hclkp", CLK_GATE_IP1, 25, 0, 0), | ||
679 | GATE(CLK_USB_HOST, "usb_host", "dout_hclkp", CLK_GATE_IP1, 17, 0, 0), | ||
680 | GATE(CLK_HDMI, "hdmi", "dout_hclkd", CLK_GATE_IP1, 11, 0, 0), | ||
681 | GATE(CLK_DSIM, "dsim", "dout_pclkd", CLK_GATE_IP1, 2, 0, 0), | ||
682 | |||
683 | GATE(CLK_TZIC3, "tzic3", "dout_hclkm", CLK_GATE_IP2, 31, 0, 0), | ||
684 | GATE(CLK_TZIC2, "tzic2", "dout_hclkm", CLK_GATE_IP2, 30, 0, 0), | ||
685 | GATE(CLK_TZIC1, "tzic1", "dout_hclkm", CLK_GATE_IP2, 29, 0, 0), | ||
686 | GATE(CLK_TZIC0, "tzic0", "dout_hclkm", CLK_GATE_IP2, 28, 0, 0), | ||
687 | GATE(CLK_TSI, "tsi", "dout_hclkd", CLK_GATE_IP2, 20, 0, 0), | ||
688 | GATE(CLK_HSMMC3, "hsmmc3", "dout_hclkp", CLK_GATE_IP2, 19, 0, 0), | ||
689 | GATE(CLK_JTAG, "jtag", "dout_hclkp", CLK_GATE_IP2, 11, 0, 0), | ||
690 | GATE(CLK_CORESIGHT, "coresight", "dout_pclkp", CLK_GATE_IP2, 8, 0, 0), | ||
691 | GATE(CLK_SDM, "sdm", "dout_pclkm", CLK_GATE_IP2, 1, 0, 0), | ||
692 | |||
693 | GATE(CLK_PCM2, "pcm2", "dout_pclkp", CLK_GATE_IP3, 30, 0, 0), | ||
694 | GATE(CLK_UART3, "uart3", "dout_pclkp", CLK_GATE_IP3, 20, 0, 0), | ||
695 | GATE(CLK_SPI1, "spi1", "dout_pclkp", CLK_GATE_IP3, 13, 0, 0), | ||
696 | GATE(CLK_I2C_HDMI_PHY, "i2c_hdmi_phy", "dout_pclkd", | ||
697 | CLK_GATE_IP3, 11, 0, 0), | ||
698 | GATE(CLK_I2C1, "i2c1", "dout_pclkd", CLK_GATE_IP3, 10, 0, 0), | ||
699 | GATE(CLK_I2S2, "i2s2", "dout_pclkp", CLK_GATE_IP3, 6, 0, 0), | ||
700 | GATE(CLK_AC97, "ac97", "dout_pclkp", CLK_GATE_IP3, 1, 0, 0), | ||
701 | GATE(CLK_SPDIF, "spdif", "dout_pclkp", CLK_GATE_IP3, 0, 0, 0), | ||
702 | |||
703 | GATE(CLK_TZPC3, "tzpc.3", "dout_pclkd", CLK_GATE_IP4, 8, 0, 0), | ||
704 | GATE(CLK_TZPC2, "tzpc.2", "dout_pclkd", CLK_GATE_IP4, 7, 0, 0), | ||
705 | GATE(CLK_TZPC1, "tzpc.1", "dout_pclkp", CLK_GATE_IP4, 6, 0, 0), | ||
706 | GATE(CLK_TZPC0, "tzpc.0", "dout_pclkm", CLK_GATE_IP4, 5, 0, 0), | ||
707 | GATE(CLK_IEM_APC, "iem_apc", "dout_pclkp", CLK_GATE_IP4, 2, 0, 0), | ||
708 | GATE(CLK_IEM_IEC, "iem_iec", "dout_pclkp", CLK_GATE_IP4, 1, 0, 0), | ||
709 | |||
710 | GATE(CLK_JPEG, "jpeg", "dout_hclkd", CLK_GATE_IP5, 29, 0, 0), | ||
711 | |||
712 | GATE(SCLK_SPDIF, "sclk_spdif", "mout_spdif", CLK_SRC_MASK0, 27, | ||
713 | CLK_SET_RATE_PARENT, 0), | ||
714 | GATE(SCLK_AUDIO2, "sclk_audio2", "dout_audio2", CLK_SRC_MASK0, 26, | ||
715 | CLK_SET_RATE_PARENT, 0), | ||
716 | GATE(SCLK_SPI1, "sclk_spi1", "dout_spi1", CLK_SRC_MASK0, 17, | ||
717 | CLK_SET_RATE_PARENT, 0), | ||
718 | GATE(SCLK_UART3, "sclk_uart3", "dout_uart3", CLK_SRC_MASK0, 15, | ||
719 | CLK_SET_RATE_PARENT, 0), | ||
720 | GATE(SCLK_MMC3, "sclk_mmc3", "dout_mmc3", CLK_SRC_MASK0, 11, | ||
721 | CLK_SET_RATE_PARENT, 0), | ||
722 | GATE(SCLK_CSIS, "sclk_csis", "dout_csis", CLK_SRC_MASK0, 6, | ||
723 | CLK_SET_RATE_PARENT, 0), | ||
724 | GATE(SCLK_DAC, "sclk_dac", "mout_dac", CLK_SRC_MASK0, 2, | ||
725 | CLK_SET_RATE_PARENT, 0), | ||
726 | GATE(SCLK_HDMI, "sclk_hdmi", "mout_hdmi", CLK_SRC_MASK0, 0, | ||
727 | CLK_SET_RATE_PARENT, 0), | ||
728 | }; | ||
729 | |||
730 | /* S5P6442-specific clock gates. */ | ||
731 | static struct samsung_gate_clock s5p6442_gate_clks[] __initdata = { | ||
732 | GATE(CLK_JPEG, "jpeg", "dout_hclkd", CLK_GATE_IP0, 28, 0, 0), | ||
733 | GATE(CLK_MFC, "mfc", "dout_hclkd", CLK_GATE_IP0, 16, 0, 0), | ||
734 | GATE(CLK_G2D, "g2d", "dout_hclkd", CLK_GATE_IP0, 12, 0, 0), | ||
735 | GATE(CLK_G3D, "g3d", "dout_hclkd", CLK_GATE_IP0, 8, 0, 0), | ||
736 | GATE(CLK_IMEM, "imem", "dout_hclkd", CLK_GATE_IP0, 5, 0, 0), | ||
737 | |||
738 | GATE(CLK_ETB, "etb", "dout_hclkd", CLK_GATE_IP1, 31, 0, 0), | ||
739 | GATE(CLK_ETM, "etm", "dout_hclkd", CLK_GATE_IP1, 30, 0, 0), | ||
740 | |||
741 | GATE(CLK_I2C1, "i2c1", "dout_pclkp", CLK_GATE_IP3, 8, 0, 0), | ||
742 | |||
743 | GATE(SCLK_DAC, "sclk_dac", "mout_vpll", CLK_SRC_MASK0, 2, | ||
744 | CLK_SET_RATE_PARENT, 0), | ||
745 | }; | ||
746 | |||
747 | /* | ||
748 | * Clock aliases for legacy clkdev look-up. | ||
749 | * NOTE: Needed only to support legacy board files. | ||
750 | */ | ||
751 | static struct samsung_clock_alias s5pv210_aliases[] = { | ||
752 | ALIAS(DOUT_APLL, NULL, "armclk"), | ||
753 | ALIAS(DOUT_HCLKM, NULL, "hclk_msys"), | ||
754 | ALIAS(MOUT_DMC0, NULL, "sclk_dmc0"), | ||
755 | }; | ||
756 | |||
757 | /* S5PV210-specific PLLs. */ | ||
758 | static struct samsung_pll_clock s5pv210_pll_clks[] __initdata = { | ||
759 | [apll] = PLL(pll_4508, FOUT_APLL, "fout_apll", "fin_pll", | ||
760 | APLL_LOCK, APLL_CON0, NULL), | ||
761 | [mpll] = PLL(pll_4502, FOUT_MPLL, "fout_mpll", "fin_pll", | ||
762 | MPLL_LOCK, MPLL_CON, NULL), | ||
763 | [epll] = PLL(pll_4600, FOUT_EPLL, "fout_epll", "fin_pll", | ||
764 | EPLL_LOCK, EPLL_CON0, NULL), | ||
765 | [vpll] = PLL(pll_4502, FOUT_VPLL, "fout_vpll", "mout_vpllsrc", | ||
766 | VPLL_LOCK, VPLL_CON, NULL), | ||
767 | }; | ||
768 | |||
769 | /* S5P6442-specific PLLs. */ | ||
770 | static struct samsung_pll_clock s5p6442_pll_clks[] __initdata = { | ||
771 | [apll] = PLL(pll_4502, FOUT_APLL, "fout_apll", "fin_pll", | ||
772 | APLL_LOCK, APLL_CON0, NULL), | ||
773 | [mpll] = PLL(pll_4502, FOUT_MPLL, "fout_mpll", "fin_pll", | ||
774 | MPLL_LOCK, MPLL_CON, NULL), | ||
775 | [epll] = PLL(pll_4500, FOUT_EPLL, "fout_epll", "fin_pll", | ||
776 | EPLL_LOCK, EPLL_CON0, NULL), | ||
777 | [vpll] = PLL(pll_4500, FOUT_VPLL, "fout_vpll", "fin_pll", | ||
778 | VPLL_LOCK, VPLL_CON, NULL), | ||
779 | }; | ||
780 | |||
781 | static void __init __s5pv210_clk_init(struct device_node *np, | ||
782 | unsigned long xxti_f, | ||
783 | unsigned long xusbxti_f, | ||
784 | bool is_s5p6442) | ||
785 | { | ||
786 | struct samsung_clk_provider *ctx; | ||
787 | |||
788 | ctx = samsung_clk_init(np, reg_base, NR_CLKS); | ||
789 | if (!ctx) | ||
790 | panic("%s: unable to allocate context.\n", __func__); | ||
791 | |||
792 | samsung_clk_register_mux(ctx, early_mux_clks, | ||
793 | ARRAY_SIZE(early_mux_clks)); | ||
794 | |||
795 | if (is_s5p6442) { | ||
796 | samsung_clk_register_fixed_rate(ctx, s5p6442_frate_clks, | ||
797 | ARRAY_SIZE(s5p6442_frate_clks)); | ||
798 | samsung_clk_register_pll(ctx, s5p6442_pll_clks, | ||
799 | ARRAY_SIZE(s5p6442_pll_clks), reg_base); | ||
800 | samsung_clk_register_mux(ctx, s5p6442_mux_clks, | ||
801 | ARRAY_SIZE(s5p6442_mux_clks)); | ||
802 | samsung_clk_register_div(ctx, s5p6442_div_clks, | ||
803 | ARRAY_SIZE(s5p6442_div_clks)); | ||
804 | samsung_clk_register_gate(ctx, s5p6442_gate_clks, | ||
805 | ARRAY_SIZE(s5p6442_gate_clks)); | ||
806 | } else { | ||
807 | samsung_clk_register_fixed_rate(ctx, s5pv210_frate_clks, | ||
808 | ARRAY_SIZE(s5pv210_frate_clks)); | ||
809 | samsung_clk_register_pll(ctx, s5pv210_pll_clks, | ||
810 | ARRAY_SIZE(s5pv210_pll_clks), reg_base); | ||
811 | samsung_clk_register_mux(ctx, s5pv210_mux_clks, | ||
812 | ARRAY_SIZE(s5pv210_mux_clks)); | ||
813 | samsung_clk_register_div(ctx, s5pv210_div_clks, | ||
814 | ARRAY_SIZE(s5pv210_div_clks)); | ||
815 | samsung_clk_register_gate(ctx, s5pv210_gate_clks, | ||
816 | ARRAY_SIZE(s5pv210_gate_clks)); | ||
817 | } | ||
818 | |||
819 | samsung_clk_register_mux(ctx, mux_clks, ARRAY_SIZE(mux_clks)); | ||
820 | samsung_clk_register_div(ctx, div_clks, ARRAY_SIZE(div_clks)); | ||
821 | samsung_clk_register_gate(ctx, gate_clks, ARRAY_SIZE(gate_clks)); | ||
822 | |||
823 | samsung_clk_register_fixed_factor(ctx, ffactor_clks, | ||
824 | ARRAY_SIZE(ffactor_clks)); | ||
825 | |||
826 | samsung_clk_register_alias(ctx, s5pv210_aliases, | ||
827 | ARRAY_SIZE(s5pv210_aliases)); | ||
828 | |||
829 | s5pv210_clk_sleep_init(); | ||
830 | |||
831 | pr_info("%s clocks: mout_apll = %ld, mout_mpll = %ld\n" | ||
832 | "\tmout_epll = %ld, mout_vpll = %ld\n", | ||
833 | is_s5p6442 ? "S5P6442" : "S5PV210", | ||
834 | _get_rate("mout_apll"), _get_rate("mout_mpll"), | ||
835 | _get_rate("mout_epll"), _get_rate("mout_vpll")); | ||
836 | } | ||
837 | |||
838 | static void __init s5pv210_clk_dt_init(struct device_node *np) | ||
839 | { | ||
840 | reg_base = of_iomap(np, 0); | ||
841 | if (!reg_base) | ||
842 | panic("%s: failed to map registers\n", __func__); | ||
843 | |||
844 | __s5pv210_clk_init(np, 0, 0, false); | ||
845 | } | ||
846 | CLK_OF_DECLARE(s5pv210_clk, "samsung,s5pv210-clock", s5pv210_clk_dt_init); | ||
847 | |||
848 | static void __init s5p6442_clk_dt_init(struct device_node *np) | ||
849 | { | ||
850 | reg_base = of_iomap(np, 0); | ||
851 | if (!reg_base) | ||
852 | panic("%s: failed to map registers\n", __func__); | ||
853 | |||
854 | __s5pv210_clk_init(np, 0, 0, true); | ||
855 | } | ||
856 | CLK_OF_DECLARE(s5p6442_clk, "samsung,s5p6442-clock", s5p6442_clk_dt_init); | ||
diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile index e0029237827a..960bf22d42ae 100644 --- a/drivers/clk/shmobile/Makefile +++ b/drivers/clk/shmobile/Makefile | |||
@@ -4,7 +4,6 @@ obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o | |||
4 | obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o | 4 | obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o |
5 | obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o | 5 | obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o |
6 | obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o | 6 | obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o |
7 | obj-$(CONFIG_ARCH_R8A7794) += clk-rcar-gen2.o | ||
7 | obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o | 8 | obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o |
8 | obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-mstp.o | 9 | obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-mstp.o |
9 | # for emply built-in.o | ||
10 | obj-n := dummy | ||
diff --git a/drivers/clk/shmobile/clk-rcar-gen2.c b/drivers/clk/shmobile/clk-rcar-gen2.c index dff7f79a19b9..e996425d06a9 100644 --- a/drivers/clk/shmobile/clk-rcar-gen2.c +++ b/drivers/clk/shmobile/clk-rcar-gen2.c | |||
@@ -202,6 +202,7 @@ static const struct clk_div_table cpg_sdh_div_table[] = { | |||
202 | }; | 202 | }; |
203 | 203 | ||
204 | static const struct clk_div_table cpg_sd01_div_table[] = { | 204 | static const struct clk_div_table cpg_sd01_div_table[] = { |
205 | { 4, 8 }, | ||
205 | { 5, 12 }, { 6, 16 }, { 7, 18 }, { 8, 24 }, | 206 | { 5, 12 }, { 6, 16 }, { 7, 18 }, { 8, 24 }, |
206 | { 10, 36 }, { 11, 48 }, { 12, 10 }, { 0, 0 }, | 207 | { 10, 36 }, { 11, 48 }, { 12, 10 }, { 0, 0 }, |
207 | }; | 208 | }; |
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index 6850cba35871..7ddc2b553846 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile | |||
@@ -5,6 +5,8 @@ | |||
5 | obj-y += clk-sunxi.o clk-factors.o | 5 | obj-y += clk-sunxi.o clk-factors.o |
6 | obj-y += clk-a10-hosc.o | 6 | obj-y += clk-a10-hosc.o |
7 | obj-y += clk-a20-gmac.o | 7 | obj-y += clk-a20-gmac.o |
8 | obj-y += clk-mod0.o | ||
9 | obj-y += clk-sun8i-mbus.o | ||
8 | 10 | ||
9 | obj-$(CONFIG_MFD_SUN6I_PRCM) += \ | 11 | obj-$(CONFIG_MFD_SUN6I_PRCM) += \ |
10 | clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \ | 12 | clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \ |
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c index 2057c8ac648f..f83ba097126c 100644 --- a/drivers/clk/sunxi/clk-factors.c +++ b/drivers/clk/sunxi/clk-factors.c | |||
@@ -9,18 +9,18 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/clk-provider.h> | 11 | #include <linux/clk-provider.h> |
12 | #include <linux/delay.h> | ||
13 | #include <linux/err.h> | ||
14 | #include <linux/io.h> | ||
12 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/of_address.h> | ||
13 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
14 | #include <linux/io.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/string.h> | 18 | #include <linux/string.h> |
17 | 19 | ||
18 | #include <linux/delay.h> | ||
19 | |||
20 | #include "clk-factors.h" | 20 | #include "clk-factors.h" |
21 | 21 | ||
22 | /* | 22 | /* |
23 | * DOC: basic adjustable factor-based clock that cannot gate | 23 | * DOC: basic adjustable factor-based clock |
24 | * | 24 | * |
25 | * Traits of this clock: | 25 | * Traits of this clock: |
26 | * prepare - clk_prepare only ensures that parents are prepared | 26 | * prepare - clk_prepare only ensures that parents are prepared |
@@ -32,6 +32,8 @@ | |||
32 | 32 | ||
33 | #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw) | 33 | #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw) |
34 | 34 | ||
35 | #define FACTORS_MAX_PARENTS 5 | ||
36 | |||
35 | #define SETMASK(len, pos) (((1U << (len)) - 1) << (pos)) | 37 | #define SETMASK(len, pos) (((1U << (len)) - 1) << (pos)) |
36 | #define CLRMASK(len, pos) (~(SETMASK(len, pos))) | 38 | #define CLRMASK(len, pos) (~(SETMASK(len, pos))) |
37 | #define FACTOR_GET(bit, len, reg) (((reg) & SETMASK(len, bit)) >> (bit)) | 39 | #define FACTOR_GET(bit, len, reg) (((reg) & SETMASK(len, bit)) >> (bit)) |
@@ -147,9 +149,96 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, | |||
147 | return 0; | 149 | return 0; |
148 | } | 150 | } |
149 | 151 | ||
150 | const struct clk_ops clk_factors_ops = { | 152 | static const struct clk_ops clk_factors_ops = { |
151 | .determine_rate = clk_factors_determine_rate, | 153 | .determine_rate = clk_factors_determine_rate, |
152 | .recalc_rate = clk_factors_recalc_rate, | 154 | .recalc_rate = clk_factors_recalc_rate, |
153 | .round_rate = clk_factors_round_rate, | 155 | .round_rate = clk_factors_round_rate, |
154 | .set_rate = clk_factors_set_rate, | 156 | .set_rate = clk_factors_set_rate, |
155 | }; | 157 | }; |
158 | |||
159 | struct clk * __init sunxi_factors_register(struct device_node *node, | ||
160 | const struct factors_data *data, | ||
161 | spinlock_t *lock) | ||
162 | { | ||
163 | struct clk *clk; | ||
164 | struct clk_factors *factors; | ||
165 | struct clk_gate *gate = NULL; | ||
166 | struct clk_mux *mux = NULL; | ||
167 | struct clk_hw *gate_hw = NULL; | ||
168 | struct clk_hw *mux_hw = NULL; | ||
169 | const char *clk_name = node->name; | ||
170 | const char *parents[FACTORS_MAX_PARENTS]; | ||
171 | void __iomem *reg; | ||
172 | int i = 0; | ||
173 | |||
174 | reg = of_iomap(node, 0); | ||
175 | |||
176 | /* if we have a mux, we will have >1 parents */ | ||
177 | while (i < FACTORS_MAX_PARENTS && | ||
178 | (parents[i] = of_clk_get_parent_name(node, i)) != NULL) | ||
179 | i++; | ||
180 | |||
181 | /* | ||
182 | * some factor clocks, such as pll5 and pll6, may have multiple | ||
183 | * outputs, and have their name designated in factors_data | ||
184 | */ | ||
185 | if (data->name) | ||
186 | clk_name = data->name; | ||
187 | else | ||
188 | of_property_read_string(node, "clock-output-names", &clk_name); | ||
189 | |||
190 | factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL); | ||
191 | if (!factors) | ||
192 | return NULL; | ||
193 | |||
194 | /* set up factors properties */ | ||
195 | factors->reg = reg; | ||
196 | factors->config = data->table; | ||
197 | factors->get_factors = data->getter; | ||
198 | factors->lock = lock; | ||
199 | |||
200 | /* Add a gate if this factor clock can be gated */ | ||
201 | if (data->enable) { | ||
202 | gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); | ||
203 | if (!gate) { | ||
204 | kfree(factors); | ||
205 | return NULL; | ||
206 | } | ||
207 | |||
208 | /* set up gate properties */ | ||
209 | gate->reg = reg; | ||
210 | gate->bit_idx = data->enable; | ||
211 | gate->lock = factors->lock; | ||
212 | gate_hw = &gate->hw; | ||
213 | } | ||
214 | |||
215 | /* Add a mux if this factor clock can be muxed */ | ||
216 | if (data->mux) { | ||
217 | mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); | ||
218 | if (!mux) { | ||
219 | kfree(factors); | ||
220 | kfree(gate); | ||
221 | return NULL; | ||
222 | } | ||
223 | |||
224 | /* set up gate properties */ | ||
225 | mux->reg = reg; | ||
226 | mux->shift = data->mux; | ||
227 | mux->mask = SUNXI_FACTORS_MUX_MASK; | ||
228 | mux->lock = factors->lock; | ||
229 | mux_hw = &mux->hw; | ||
230 | } | ||
231 | |||
232 | clk = clk_register_composite(NULL, clk_name, | ||
233 | parents, i, | ||
234 | mux_hw, &clk_mux_ops, | ||
235 | &factors->hw, &clk_factors_ops, | ||
236 | gate_hw, &clk_gate_ops, 0); | ||
237 | |||
238 | if (!IS_ERR(clk)) { | ||
239 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | ||
240 | clk_register_clkdev(clk, clk_name, NULL); | ||
241 | } | ||
242 | |||
243 | return clk; | ||
244 | } | ||
diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h index d2d0efa39379..9913840018d3 100644 --- a/drivers/clk/sunxi/clk-factors.h +++ b/drivers/clk/sunxi/clk-factors.h | |||
@@ -3,9 +3,12 @@ | |||
3 | 3 | ||
4 | #include <linux/clk-provider.h> | 4 | #include <linux/clk-provider.h> |
5 | #include <linux/clkdev.h> | 5 | #include <linux/clkdev.h> |
6 | #include <linux/spinlock.h> | ||
6 | 7 | ||
7 | #define SUNXI_FACTORS_NOT_APPLICABLE (0) | 8 | #define SUNXI_FACTORS_NOT_APPLICABLE (0) |
8 | 9 | ||
10 | #define SUNXI_FACTORS_MUX_MASK 0x3 | ||
11 | |||
9 | struct clk_factors_config { | 12 | struct clk_factors_config { |
10 | u8 nshift; | 13 | u8 nshift; |
11 | u8 nwidth; | 14 | u8 nwidth; |
@@ -18,6 +21,14 @@ struct clk_factors_config { | |||
18 | u8 n_start; | 21 | u8 n_start; |
19 | }; | 22 | }; |
20 | 23 | ||
24 | struct factors_data { | ||
25 | int enable; | ||
26 | int mux; | ||
27 | struct clk_factors_config *table; | ||
28 | void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p); | ||
29 | const char *name; | ||
30 | }; | ||
31 | |||
21 | struct clk_factors { | 32 | struct clk_factors { |
22 | struct clk_hw hw; | 33 | struct clk_hw hw; |
23 | void __iomem *reg; | 34 | void __iomem *reg; |
@@ -26,5 +37,8 @@ struct clk_factors { | |||
26 | spinlock_t *lock; | 37 | spinlock_t *lock; |
27 | }; | 38 | }; |
28 | 39 | ||
29 | extern const struct clk_ops clk_factors_ops; | 40 | struct clk * __init sunxi_factors_register(struct device_node *node, |
41 | const struct factors_data *data, | ||
42 | spinlock_t *lock); | ||
43 | |||
30 | #endif | 44 | #endif |
diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c new file mode 100644 index 000000000000..4a563850ee6e --- /dev/null +++ b/drivers/clk/sunxi/clk-mod0.c | |||
@@ -0,0 +1,283 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Emilio López | ||
3 | * | ||
4 | * Emilio López <emilio@elopez.com.ar> | ||
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/clkdev.h> | ||
19 | #include <linux/of_address.h> | ||
20 | |||
21 | #include "clk-factors.h" | ||
22 | |||
23 | /** | ||
24 | * sun4i_get_mod0_factors() - calculates m, n factors for MOD0-style clocks | ||
25 | * MOD0 rate is calculated as follows | ||
26 | * rate = (parent_rate >> p) / (m + 1); | ||
27 | */ | ||
28 | |||
29 | static void sun4i_a10_get_mod0_factors(u32 *freq, u32 parent_rate, | ||
30 | u8 *n, u8 *k, u8 *m, u8 *p) | ||
31 | { | ||
32 | u8 div, calcm, calcp; | ||
33 | |||
34 | /* These clocks can only divide, so we will never be able to achieve | ||
35 | * frequencies higher than the parent frequency */ | ||
36 | if (*freq > parent_rate) | ||
37 | *freq = parent_rate; | ||
38 | |||
39 | div = DIV_ROUND_UP(parent_rate, *freq); | ||
40 | |||
41 | if (div < 16) | ||
42 | calcp = 0; | ||
43 | else if (div / 2 < 16) | ||
44 | calcp = 1; | ||
45 | else if (div / 4 < 16) | ||
46 | calcp = 2; | ||
47 | else | ||
48 | calcp = 3; | ||
49 | |||
50 | calcm = DIV_ROUND_UP(div, 1 << calcp); | ||
51 | |||
52 | *freq = (parent_rate >> calcp) / calcm; | ||
53 | |||
54 | /* we were called to round the frequency, we can now return */ | ||
55 | if (n == NULL) | ||
56 | return; | ||
57 | |||
58 | *m = calcm - 1; | ||
59 | *p = calcp; | ||
60 | } | ||
61 | |||
62 | /* user manual says "n" but it's really "p" */ | ||
63 | static struct clk_factors_config sun4i_a10_mod0_config = { | ||
64 | .mshift = 0, | ||
65 | .mwidth = 4, | ||
66 | .pshift = 16, | ||
67 | .pwidth = 2, | ||
68 | }; | ||
69 | |||
70 | static const struct factors_data sun4i_a10_mod0_data __initconst = { | ||
71 | .enable = 31, | ||
72 | .mux = 24, | ||
73 | .table = &sun4i_a10_mod0_config, | ||
74 | .getter = sun4i_a10_get_mod0_factors, | ||
75 | }; | ||
76 | |||
77 | static DEFINE_SPINLOCK(sun4i_a10_mod0_lock); | ||
78 | |||
79 | static void __init sun4i_a10_mod0_setup(struct device_node *node) | ||
80 | { | ||
81 | sunxi_factors_register(node, &sun4i_a10_mod0_data, &sun4i_a10_mod0_lock); | ||
82 | } | ||
83 | CLK_OF_DECLARE(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", sun4i_a10_mod0_setup); | ||
84 | |||
85 | static DEFINE_SPINLOCK(sun5i_a13_mbus_lock); | ||
86 | |||
87 | static void __init sun5i_a13_mbus_setup(struct device_node *node) | ||
88 | { | ||
89 | struct clk *mbus = sunxi_factors_register(node, &sun4i_a10_mod0_data, &sun5i_a13_mbus_lock); | ||
90 | |||
91 | /* The MBUS clocks needs to be always enabled */ | ||
92 | __clk_get(mbus); | ||
93 | clk_prepare_enable(mbus); | ||
94 | } | ||
95 | CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup); | ||
96 | |||
97 | struct mmc_phase_data { | ||
98 | u8 offset; | ||
99 | }; | ||
100 | |||
101 | struct mmc_phase { | ||
102 | struct clk_hw hw; | ||
103 | void __iomem *reg; | ||
104 | struct mmc_phase_data *data; | ||
105 | spinlock_t *lock; | ||
106 | }; | ||
107 | |||
108 | #define to_mmc_phase(_hw) container_of(_hw, struct mmc_phase, hw) | ||
109 | |||
110 | static int mmc_get_phase(struct clk_hw *hw) | ||
111 | { | ||
112 | struct clk *mmc, *mmc_parent, *clk = hw->clk; | ||
113 | struct mmc_phase *phase = to_mmc_phase(hw); | ||
114 | unsigned int mmc_rate, mmc_parent_rate; | ||
115 | u16 step, mmc_div; | ||
116 | u32 value; | ||
117 | u8 delay; | ||
118 | |||
119 | value = readl(phase->reg); | ||
120 | delay = (value >> phase->data->offset) & 0x3; | ||
121 | |||
122 | if (!delay) | ||
123 | return 180; | ||
124 | |||
125 | /* Get the main MMC clock */ | ||
126 | mmc = clk_get_parent(clk); | ||
127 | if (!mmc) | ||
128 | return -EINVAL; | ||
129 | |||
130 | /* And its rate */ | ||
131 | mmc_rate = clk_get_rate(mmc); | ||
132 | if (!mmc_rate) | ||
133 | return -EINVAL; | ||
134 | |||
135 | /* Now, get the MMC parent (most likely some PLL) */ | ||
136 | mmc_parent = clk_get_parent(mmc); | ||
137 | if (!mmc_parent) | ||
138 | return -EINVAL; | ||
139 | |||
140 | /* And its rate */ | ||
141 | mmc_parent_rate = clk_get_rate(mmc_parent); | ||
142 | if (!mmc_parent_rate) | ||
143 | return -EINVAL; | ||
144 | |||
145 | /* Get MMC clock divider */ | ||
146 | mmc_div = mmc_parent_rate / mmc_rate; | ||
147 | |||
148 | step = DIV_ROUND_CLOSEST(360, mmc_div); | ||
149 | return delay * step; | ||
150 | } | ||
151 | |||
152 | static int mmc_set_phase(struct clk_hw *hw, int degrees) | ||
153 | { | ||
154 | struct clk *mmc, *mmc_parent, *clk = hw->clk; | ||
155 | struct mmc_phase *phase = to_mmc_phase(hw); | ||
156 | unsigned int mmc_rate, mmc_parent_rate; | ||
157 | unsigned long flags; | ||
158 | u32 value; | ||
159 | u8 delay; | ||
160 | |||
161 | /* Get the main MMC clock */ | ||
162 | mmc = clk_get_parent(clk); | ||
163 | if (!mmc) | ||
164 | return -EINVAL; | ||
165 | |||
166 | /* And its rate */ | ||
167 | mmc_rate = clk_get_rate(mmc); | ||
168 | if (!mmc_rate) | ||
169 | return -EINVAL; | ||
170 | |||
171 | /* Now, get the MMC parent (most likely some PLL) */ | ||
172 | mmc_parent = clk_get_parent(mmc); | ||
173 | if (!mmc_parent) | ||
174 | return -EINVAL; | ||
175 | |||
176 | /* And its rate */ | ||
177 | mmc_parent_rate = clk_get_rate(mmc_parent); | ||
178 | if (!mmc_parent_rate) | ||
179 | return -EINVAL; | ||
180 | |||
181 | if (degrees != 180) { | ||
182 | u16 step, mmc_div; | ||
183 | |||
184 | /* Get MMC clock divider */ | ||
185 | mmc_div = mmc_parent_rate / mmc_rate; | ||
186 | |||
187 | /* | ||
188 | * We can only outphase the clocks by multiple of the | ||
189 | * PLL's period. | ||
190 | * | ||
191 | * Since the MMC clock in only a divider, and the | ||
192 | * formula to get the outphasing in degrees is deg = | ||
193 | * 360 * delta / period | ||
194 | * | ||
195 | * If we simplify this formula, we can see that the | ||
196 | * only thing that we're concerned about is the number | ||
197 | * of period we want to outphase our clock from, and | ||
198 | * the divider set by the MMC clock. | ||
199 | */ | ||
200 | step = DIV_ROUND_CLOSEST(360, mmc_div); | ||
201 | delay = DIV_ROUND_CLOSEST(degrees, step); | ||
202 | } else { | ||
203 | delay = 0; | ||
204 | } | ||
205 | |||
206 | spin_lock_irqsave(phase->lock, flags); | ||
207 | value = readl(phase->reg); | ||
208 | value &= ~GENMASK(phase->data->offset + 3, phase->data->offset); | ||
209 | value |= delay << phase->data->offset; | ||
210 | writel(value, phase->reg); | ||
211 | spin_unlock_irqrestore(phase->lock, flags); | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static const struct clk_ops mmc_clk_ops = { | ||
217 | .get_phase = mmc_get_phase, | ||
218 | .set_phase = mmc_set_phase, | ||
219 | }; | ||
220 | |||
221 | static void __init sun4i_a10_mmc_phase_setup(struct device_node *node, | ||
222 | struct mmc_phase_data *data) | ||
223 | { | ||
224 | const char *parent_names[1] = { of_clk_get_parent_name(node, 0) }; | ||
225 | struct clk_init_data init = { | ||
226 | .num_parents = 1, | ||
227 | .parent_names = parent_names, | ||
228 | .ops = &mmc_clk_ops, | ||
229 | }; | ||
230 | |||
231 | struct mmc_phase *phase; | ||
232 | struct clk *clk; | ||
233 | |||
234 | phase = kmalloc(sizeof(*phase), GFP_KERNEL); | ||
235 | if (!phase) | ||
236 | return; | ||
237 | |||
238 | phase->hw.init = &init; | ||
239 | |||
240 | phase->reg = of_iomap(node, 0); | ||
241 | if (!phase->reg) | ||
242 | goto err_free; | ||
243 | |||
244 | phase->data = data; | ||
245 | phase->lock = &sun4i_a10_mod0_lock; | ||
246 | |||
247 | if (of_property_read_string(node, "clock-output-names", &init.name)) | ||
248 | init.name = node->name; | ||
249 | |||
250 | clk = clk_register(NULL, &phase->hw); | ||
251 | if (IS_ERR(clk)) | ||
252 | goto err_unmap; | ||
253 | |||
254 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | ||
255 | |||
256 | return; | ||
257 | |||
258 | err_unmap: | ||
259 | iounmap(phase->reg); | ||
260 | err_free: | ||
261 | kfree(phase); | ||
262 | } | ||
263 | |||
264 | |||
265 | static struct mmc_phase_data mmc_output_clk = { | ||
266 | .offset = 8, | ||
267 | }; | ||
268 | |||
269 | static struct mmc_phase_data mmc_sample_clk = { | ||
270 | .offset = 20, | ||
271 | }; | ||
272 | |||
273 | static void __init sun4i_a10_mmc_output_setup(struct device_node *node) | ||
274 | { | ||
275 | sun4i_a10_mmc_phase_setup(node, &mmc_output_clk); | ||
276 | } | ||
277 | CLK_OF_DECLARE(sun4i_a10_mmc_output, "allwinner,sun4i-a10-mmc-output-clk", sun4i_a10_mmc_output_setup); | ||
278 | |||
279 | static void __init sun4i_a10_mmc_sample_setup(struct device_node *node) | ||
280 | { | ||
281 | sun4i_a10_mmc_phase_setup(node, &mmc_sample_clk); | ||
282 | } | ||
283 | CLK_OF_DECLARE(sun4i_a10_mmc_sample, "allwinner,sun4i-a10-mmc-sample-clk", sun4i_a10_mmc_sample_setup); | ||
diff --git a/drivers/clk/sunxi/clk-sun6i-apb0-gates.c b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c index e10d0521ec76..64f3e46d383c 100644 --- a/drivers/clk/sunxi/clk-sun6i-apb0-gates.c +++ b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c | |||
@@ -99,7 +99,6 @@ static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev) | |||
99 | static struct platform_driver sun6i_a31_apb0_gates_clk_driver = { | 99 | static struct platform_driver sun6i_a31_apb0_gates_clk_driver = { |
100 | .driver = { | 100 | .driver = { |
101 | .name = "sun6i-a31-apb0-gates-clk", | 101 | .name = "sun6i-a31-apb0-gates-clk", |
102 | .owner = THIS_MODULE, | ||
103 | .of_match_table = sun6i_a31_apb0_gates_clk_dt_ids, | 102 | .of_match_table = sun6i_a31_apb0_gates_clk_dt_ids, |
104 | }, | 103 | }, |
105 | .probe = sun6i_a31_apb0_gates_clk_probe, | 104 | .probe = sun6i_a31_apb0_gates_clk_probe, |
diff --git a/drivers/clk/sunxi/clk-sun6i-apb0.c b/drivers/clk/sunxi/clk-sun6i-apb0.c index 1fa23371c8c6..70763600aeae 100644 --- a/drivers/clk/sunxi/clk-sun6i-apb0.c +++ b/drivers/clk/sunxi/clk-sun6i-apb0.c | |||
@@ -65,7 +65,6 @@ static const struct of_device_id sun6i_a31_apb0_clk_dt_ids[] = { | |||
65 | static struct platform_driver sun6i_a31_apb0_clk_driver = { | 65 | static struct platform_driver sun6i_a31_apb0_clk_driver = { |
66 | .driver = { | 66 | .driver = { |
67 | .name = "sun6i-a31-apb0-clk", | 67 | .name = "sun6i-a31-apb0-clk", |
68 | .owner = THIS_MODULE, | ||
69 | .of_match_table = sun6i_a31_apb0_clk_dt_ids, | 68 | .of_match_table = sun6i_a31_apb0_clk_dt_ids, |
70 | }, | 69 | }, |
71 | .probe = sun6i_a31_apb0_clk_probe, | 70 | .probe = sun6i_a31_apb0_clk_probe, |
diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c index eca8ca025b6a..acca53290be2 100644 --- a/drivers/clk/sunxi/clk-sun6i-ar100.c +++ b/drivers/clk/sunxi/clk-sun6i-ar100.c | |||
@@ -221,7 +221,6 @@ static const struct of_device_id sun6i_a31_ar100_clk_dt_ids[] = { | |||
221 | static struct platform_driver sun6i_a31_ar100_clk_driver = { | 221 | static struct platform_driver sun6i_a31_ar100_clk_driver = { |
222 | .driver = { | 222 | .driver = { |
223 | .name = "sun6i-a31-ar100-clk", | 223 | .name = "sun6i-a31-ar100-clk", |
224 | .owner = THIS_MODULE, | ||
225 | .of_match_table = sun6i_a31_ar100_clk_dt_ids, | 224 | .of_match_table = sun6i_a31_ar100_clk_dt_ids, |
226 | }, | 225 | }, |
227 | .probe = sun6i_a31_ar100_clk_probe, | 226 | .probe = sun6i_a31_ar100_clk_probe, |
diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c index 1f5ba9b4b8cd..155d0022194f 100644 --- a/drivers/clk/sunxi/clk-sun8i-apb0.c +++ b/drivers/clk/sunxi/clk-sun8i-apb0.c | |||
@@ -56,7 +56,6 @@ static const struct of_device_id sun8i_a23_apb0_clk_dt_ids[] = { | |||
56 | static struct platform_driver sun8i_a23_apb0_clk_driver = { | 56 | static struct platform_driver sun8i_a23_apb0_clk_driver = { |
57 | .driver = { | 57 | .driver = { |
58 | .name = "sun8i-a23-apb0-clk", | 58 | .name = "sun8i-a23-apb0-clk", |
59 | .owner = THIS_MODULE, | ||
60 | .of_match_table = sun8i_a23_apb0_clk_dt_ids, | 59 | .of_match_table = sun8i_a23_apb0_clk_dt_ids, |
61 | }, | 60 | }, |
62 | .probe = sun8i_a23_apb0_clk_probe, | 61 | .probe = sun8i_a23_apb0_clk_probe, |
diff --git a/drivers/clk/sunxi/clk-sun8i-mbus.c b/drivers/clk/sunxi/clk-sun8i-mbus.c new file mode 100644 index 000000000000..8e49b44cee41 --- /dev/null +++ b/drivers/clk/sunxi/clk-sun8i-mbus.c | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * Copyright 2014 Chen-Yu Tsai | ||
3 | * | ||
4 | * Chen-Yu Tsai <wens@csie.org> | ||
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/clkdev.h> | ||
19 | #include <linux/of_address.h> | ||
20 | |||
21 | #include "clk-factors.h" | ||
22 | |||
23 | /** | ||
24 | * sun8i_a23_get_mbus_factors() - calculates m factor for MBUS clocks | ||
25 | * MBUS rate is calculated as follows | ||
26 | * rate = parent_rate / (m + 1); | ||
27 | */ | ||
28 | |||
29 | static void sun8i_a23_get_mbus_factors(u32 *freq, u32 parent_rate, | ||
30 | u8 *n, u8 *k, u8 *m, u8 *p) | ||
31 | { | ||
32 | u8 div; | ||
33 | |||
34 | /* | ||
35 | * These clocks can only divide, so we will never be able to | ||
36 | * achieve frequencies higher than the parent frequency | ||
37 | */ | ||
38 | if (*freq > parent_rate) | ||
39 | *freq = parent_rate; | ||
40 | |||
41 | div = DIV_ROUND_UP(parent_rate, *freq); | ||
42 | |||
43 | if (div > 8) | ||
44 | div = 8; | ||
45 | |||
46 | *freq = parent_rate / div; | ||
47 | |||
48 | /* we were called to round the frequency, we can now return */ | ||
49 | if (m == NULL) | ||
50 | return; | ||
51 | |||
52 | *m = div - 1; | ||
53 | } | ||
54 | |||
55 | static struct clk_factors_config sun8i_a23_mbus_config = { | ||
56 | .mshift = 0, | ||
57 | .mwidth = 3, | ||
58 | }; | ||
59 | |||
60 | static const struct factors_data sun8i_a23_mbus_data __initconst = { | ||
61 | .enable = 31, | ||
62 | .mux = 24, | ||
63 | .table = &sun8i_a23_mbus_config, | ||
64 | .getter = sun8i_a23_get_mbus_factors, | ||
65 | }; | ||
66 | |||
67 | static DEFINE_SPINLOCK(sun8i_a23_mbus_lock); | ||
68 | |||
69 | static void __init sun8i_a23_mbus_setup(struct device_node *node) | ||
70 | { | ||
71 | struct clk *mbus = sunxi_factors_register(node, &sun8i_a23_mbus_data, | ||
72 | &sun8i_a23_mbus_lock); | ||
73 | |||
74 | /* The MBUS clocks needs to be always enabled */ | ||
75 | __clk_get(mbus); | ||
76 | clk_prepare_enable(mbus); | ||
77 | } | ||
78 | CLK_OF_DECLARE(sun8i_a23_mbus, "allwinner,sun8i-a23-mbus-clk", sun8i_a23_mbus_setup); | ||
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index b654b7b1d137..d5dc951264ca 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/of.h> | 19 | #include <linux/of.h> |
20 | #include <linux/of_address.h> | 20 | #include <linux/of_address.h> |
21 | #include <linux/reset-controller.h> | 21 | #include <linux/reset-controller.h> |
22 | #include <linux/spinlock.h> | ||
22 | 23 | ||
23 | #include "clk-factors.h" | 24 | #include "clk-factors.h" |
24 | 25 | ||
@@ -319,46 +320,6 @@ static void sun4i_get_apb1_factors(u32 *freq, u32 parent_rate, | |||
319 | 320 | ||
320 | 321 | ||
321 | 322 | ||
322 | /** | ||
323 | * sun4i_get_mod0_factors() - calculates m, n factors for MOD0-style clocks | ||
324 | * MOD0 rate is calculated as follows | ||
325 | * rate = (parent_rate >> p) / (m + 1); | ||
326 | */ | ||
327 | |||
328 | static void sun4i_get_mod0_factors(u32 *freq, u32 parent_rate, | ||
329 | u8 *n, u8 *k, u8 *m, u8 *p) | ||
330 | { | ||
331 | u8 div, calcm, calcp; | ||
332 | |||
333 | /* These clocks can only divide, so we will never be able to achieve | ||
334 | * frequencies higher than the parent frequency */ | ||
335 | if (*freq > parent_rate) | ||
336 | *freq = parent_rate; | ||
337 | |||
338 | div = DIV_ROUND_UP(parent_rate, *freq); | ||
339 | |||
340 | if (div < 16) | ||
341 | calcp = 0; | ||
342 | else if (div / 2 < 16) | ||
343 | calcp = 1; | ||
344 | else if (div / 4 < 16) | ||
345 | calcp = 2; | ||
346 | else | ||
347 | calcp = 3; | ||
348 | |||
349 | calcm = DIV_ROUND_UP(div, 1 << calcp); | ||
350 | |||
351 | *freq = (parent_rate >> calcp) / calcm; | ||
352 | |||
353 | /* we were called to round the frequency, we can now return */ | ||
354 | if (n == NULL) | ||
355 | return; | ||
356 | |||
357 | *m = calcm - 1; | ||
358 | *p = calcp; | ||
359 | } | ||
360 | |||
361 | |||
362 | 323 | ||
363 | /** | 324 | /** |
364 | * sun7i_a20_get_out_factors() - calculates m, p factors for CLK_OUT_A/B | 325 | * sun7i_a20_get_out_factors() - calculates m, p factors for CLK_OUT_A/B |
@@ -440,16 +401,6 @@ EXPORT_SYMBOL(clk_sunxi_mmc_phase_control); | |||
440 | * sunxi_factors_clk_setup() - Setup function for factor clocks | 401 | * sunxi_factors_clk_setup() - Setup function for factor clocks |
441 | */ | 402 | */ |
442 | 403 | ||
443 | #define SUNXI_FACTORS_MUX_MASK 0x3 | ||
444 | |||
445 | struct factors_data { | ||
446 | int enable; | ||
447 | int mux; | ||
448 | struct clk_factors_config *table; | ||
449 | void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p); | ||
450 | const char *name; | ||
451 | }; | ||
452 | |||
453 | static struct clk_factors_config sun4i_pll1_config = { | 404 | static struct clk_factors_config sun4i_pll1_config = { |
454 | .nshift = 8, | 405 | .nshift = 8, |
455 | .nwidth = 5, | 406 | .nwidth = 5, |
@@ -504,14 +455,6 @@ static struct clk_factors_config sun4i_apb1_config = { | |||
504 | }; | 455 | }; |
505 | 456 | ||
506 | /* user manual says "n" but it's really "p" */ | 457 | /* user manual says "n" but it's really "p" */ |
507 | static struct clk_factors_config sun4i_mod0_config = { | ||
508 | .mshift = 0, | ||
509 | .mwidth = 4, | ||
510 | .pshift = 16, | ||
511 | .pwidth = 2, | ||
512 | }; | ||
513 | |||
514 | /* user manual says "n" but it's really "p" */ | ||
515 | static struct clk_factors_config sun7i_a20_out_config = { | 458 | static struct clk_factors_config sun7i_a20_out_config = { |
516 | .mshift = 8, | 459 | .mshift = 8, |
517 | .mwidth = 5, | 460 | .mwidth = 5, |
@@ -568,13 +511,6 @@ static const struct factors_data sun4i_apb1_data __initconst = { | |||
568 | .getter = sun4i_get_apb1_factors, | 511 | .getter = sun4i_get_apb1_factors, |
569 | }; | 512 | }; |
570 | 513 | ||
571 | static const struct factors_data sun4i_mod0_data __initconst = { | ||
572 | .enable = 31, | ||
573 | .mux = 24, | ||
574 | .table = &sun4i_mod0_config, | ||
575 | .getter = sun4i_get_mod0_factors, | ||
576 | }; | ||
577 | |||
578 | static const struct factors_data sun7i_a20_out_data __initconst = { | 514 | static const struct factors_data sun7i_a20_out_data __initconst = { |
579 | .enable = 31, | 515 | .enable = 31, |
580 | .mux = 24, | 516 | .mux = 24, |
@@ -583,89 +519,9 @@ static const struct factors_data sun7i_a20_out_data __initconst = { | |||
583 | }; | 519 | }; |
584 | 520 | ||
585 | static struct clk * __init sunxi_factors_clk_setup(struct device_node *node, | 521 | static struct clk * __init sunxi_factors_clk_setup(struct device_node *node, |
586 | const struct factors_data *data) | 522 | const struct factors_data *data) |
587 | { | 523 | { |
588 | struct clk *clk; | 524 | return sunxi_factors_register(node, data, &clk_lock); |
589 | struct clk_factors *factors; | ||
590 | struct clk_gate *gate = NULL; | ||
591 | struct clk_mux *mux = NULL; | ||
592 | struct clk_hw *gate_hw = NULL; | ||
593 | struct clk_hw *mux_hw = NULL; | ||
594 | const char *clk_name = node->name; | ||
595 | const char *parents[SUNXI_MAX_PARENTS]; | ||
596 | void __iomem *reg; | ||
597 | int i = 0; | ||
598 | |||
599 | reg = of_iomap(node, 0); | ||
600 | |||
601 | /* if we have a mux, we will have >1 parents */ | ||
602 | while (i < SUNXI_MAX_PARENTS && | ||
603 | (parents[i] = of_clk_get_parent_name(node, i)) != NULL) | ||
604 | i++; | ||
605 | |||
606 | /* | ||
607 | * some factor clocks, such as pll5 and pll6, may have multiple | ||
608 | * outputs, and have their name designated in factors_data | ||
609 | */ | ||
610 | if (data->name) | ||
611 | clk_name = data->name; | ||
612 | else | ||
613 | of_property_read_string(node, "clock-output-names", &clk_name); | ||
614 | |||
615 | factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL); | ||
616 | if (!factors) | ||
617 | return NULL; | ||
618 | |||
619 | /* Add a gate if this factor clock can be gated */ | ||
620 | if (data->enable) { | ||
621 | gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); | ||
622 | if (!gate) { | ||
623 | kfree(factors); | ||
624 | return NULL; | ||
625 | } | ||
626 | |||
627 | /* set up gate properties */ | ||
628 | gate->reg = reg; | ||
629 | gate->bit_idx = data->enable; | ||
630 | gate->lock = &clk_lock; | ||
631 | gate_hw = &gate->hw; | ||
632 | } | ||
633 | |||
634 | /* Add a mux if this factor clock can be muxed */ | ||
635 | if (data->mux) { | ||
636 | mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); | ||
637 | if (!mux) { | ||
638 | kfree(factors); | ||
639 | kfree(gate); | ||
640 | return NULL; | ||
641 | } | ||
642 | |||
643 | /* set up gate properties */ | ||
644 | mux->reg = reg; | ||
645 | mux->shift = data->mux; | ||
646 | mux->mask = SUNXI_FACTORS_MUX_MASK; | ||
647 | mux->lock = &clk_lock; | ||
648 | mux_hw = &mux->hw; | ||
649 | } | ||
650 | |||
651 | /* set up factors properties */ | ||
652 | factors->reg = reg; | ||
653 | factors->config = data->table; | ||
654 | factors->get_factors = data->getter; | ||
655 | factors->lock = &clk_lock; | ||
656 | |||
657 | clk = clk_register_composite(NULL, clk_name, | ||
658 | parents, i, | ||
659 | mux_hw, &clk_mux_ops, | ||
660 | &factors->hw, &clk_factors_ops, | ||
661 | gate_hw, &clk_gate_ops, 0); | ||
662 | |||
663 | if (!IS_ERR(clk)) { | ||
664 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | ||
665 | clk_register_clkdev(clk, clk_name, NULL); | ||
666 | } | ||
667 | |||
668 | return clk; | ||
669 | } | 525 | } |
670 | 526 | ||
671 | 527 | ||
@@ -762,10 +618,19 @@ static const struct div_data sun4i_ahb_data __initconst = { | |||
762 | .width = 2, | 618 | .width = 2, |
763 | }; | 619 | }; |
764 | 620 | ||
621 | static const struct clk_div_table sun4i_apb0_table[] __initconst = { | ||
622 | { .val = 0, .div = 2 }, | ||
623 | { .val = 1, .div = 2 }, | ||
624 | { .val = 2, .div = 4 }, | ||
625 | { .val = 3, .div = 8 }, | ||
626 | { } /* sentinel */ | ||
627 | }; | ||
628 | |||
765 | static const struct div_data sun4i_apb0_data __initconst = { | 629 | static const struct div_data sun4i_apb0_data __initconst = { |
766 | .shift = 8, | 630 | .shift = 8, |
767 | .pow = 1, | 631 | .pow = 1, |
768 | .width = 2, | 632 | .width = 2, |
633 | .table = sun4i_apb0_table, | ||
769 | }; | 634 | }; |
770 | 635 | ||
771 | static const struct div_data sun6i_a31_apb2_div_data __initconst = { | 636 | static const struct div_data sun6i_a31_apb2_div_data __initconst = { |
@@ -1199,7 +1064,6 @@ static const struct of_device_id clk_factors_match[] __initconst = { | |||
1199 | {.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,}, | 1064 | {.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,}, |
1200 | {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,}, | 1065 | {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,}, |
1201 | {.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,}, | 1066 | {.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,}, |
1202 | {.compatible = "allwinner,sun4i-a10-mod0-clk", .data = &sun4i_mod0_data,}, | ||
1203 | {.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,}, | 1067 | {.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,}, |
1204 | {} | 1068 | {} |
1205 | }; | 1069 | }; |
@@ -1311,7 +1175,6 @@ static void __init sun4i_a10_init_clocks(struct device_node *node) | |||
1311 | CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sun4i_a10_init_clocks); | 1175 | CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sun4i_a10_init_clocks); |
1312 | 1176 | ||
1313 | static const char *sun5i_critical_clocks[] __initdata = { | 1177 | static const char *sun5i_critical_clocks[] __initdata = { |
1314 | "mbus", | ||
1315 | "pll5_ddr", | 1178 | "pll5_ddr", |
1316 | "ahb_sdram", | 1179 | "ahb_sdram", |
1317 | }; | 1180 | }; |
diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c index 507015314827..0aa8830ae7cc 100644 --- a/drivers/clk/tegra/clk-periph-gate.c +++ b/drivers/clk/tegra/clk-periph-gate.c | |||
@@ -20,7 +20,8 @@ | |||
20 | #include <linux/io.h> | 20 | #include <linux/io.h> |
21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
22 | #include <linux/err.h> | 22 | #include <linux/err.h> |
23 | #include <linux/tegra-soc.h> | 23 | |
24 | #include <soc/tegra/fuse.h> | ||
24 | 25 | ||
25 | #include "clk.h" | 26 | #include "clk.h" |
26 | 27 | ||
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index 9525c684d149..e3a85842ce0c 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c | |||
@@ -1166,6 +1166,12 @@ static void __init tegra124_pll_init(void __iomem *clk_base, | |||
1166 | clk_register_clkdev(clk, "pll_c_out1", NULL); | 1166 | clk_register_clkdev(clk, "pll_c_out1", NULL); |
1167 | clks[TEGRA124_CLK_PLL_C_OUT1] = clk; | 1167 | clks[TEGRA124_CLK_PLL_C_OUT1] = clk; |
1168 | 1168 | ||
1169 | /* PLLC_UD */ | ||
1170 | clk = clk_register_fixed_factor(NULL, "pll_c_ud", "pll_c", | ||
1171 | CLK_SET_RATE_PARENT, 1, 1); | ||
1172 | clk_register_clkdev(clk, "pll_c_ud", NULL); | ||
1173 | clks[TEGRA124_CLK_PLL_C_UD] = clk; | ||
1174 | |||
1169 | /* PLLC2 */ | 1175 | /* PLLC2 */ |
1170 | clk = tegra_clk_register_pllc("pll_c2", "pll_ref", clk_base, pmc, 0, | 1176 | clk = tegra_clk_register_pllc("pll_c2", "pll_ref", clk_base, pmc, 0, |
1171 | &pll_c2_params, NULL); | 1177 | &pll_c2_params, NULL); |
@@ -1198,6 +1204,8 @@ static void __init tegra124_pll_init(void __iomem *clk_base, | |||
1198 | /* PLLM_UD */ | 1204 | /* PLLM_UD */ |
1199 | clk = clk_register_fixed_factor(NULL, "pll_m_ud", "pll_m", | 1205 | clk = clk_register_fixed_factor(NULL, "pll_m_ud", "pll_m", |
1200 | CLK_SET_RATE_PARENT, 1, 1); | 1206 | CLK_SET_RATE_PARENT, 1, 1); |
1207 | clk_register_clkdev(clk, "pll_m_ud", NULL); | ||
1208 | clks[TEGRA124_CLK_PLL_M_UD] = clk; | ||
1201 | 1209 | ||
1202 | /* PLLU */ | 1210 | /* PLLU */ |
1203 | val = readl(clk_base + pll_u_params.base_reg); | 1211 | val = readl(clk_base + pll_u_params.base_reg); |
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 8b10c38b6e3c..5bbacd01094f 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c | |||
@@ -22,8 +22,11 @@ | |||
22 | #include <linux/of.h> | 22 | #include <linux/of.h> |
23 | #include <linux/of_address.h> | 23 | #include <linux/of_address.h> |
24 | #include <linux/clk/tegra.h> | 24 | #include <linux/clk/tegra.h> |
25 | #include <linux/tegra-powergate.h> | 25 | |
26 | #include <soc/tegra/pmc.h> | ||
27 | |||
26 | #include <dt-bindings/clock/tegra30-car.h> | 28 | #include <dt-bindings/clock/tegra30-car.h> |
29 | |||
27 | #include "clk.h" | 30 | #include "clk.h" |
28 | #include "clk-id.h" | 31 | #include "clk-id.h" |
29 | 32 | ||
diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c index bf452b62beb8..97dc8595c3cd 100644 --- a/drivers/clk/tegra/clk.c +++ b/drivers/clk/tegra/clk.c | |||
@@ -19,7 +19,8 @@ | |||
19 | #include <linux/of.h> | 19 | #include <linux/of.h> |
20 | #include <linux/clk/tegra.h> | 20 | #include <linux/clk/tegra.h> |
21 | #include <linux/reset-controller.h> | 21 | #include <linux/reset-controller.h> |
22 | #include <linux/tegra-soc.h> | 22 | |
23 | #include <soc/tegra/fuse.h> | ||
23 | 24 | ||
24 | #include "clk.h" | 25 | #include "clk.h" |
25 | 26 | ||
@@ -206,8 +207,13 @@ void __init tegra_init_from_table(struct tegra_clk_init_table *tbl, | |||
206 | 207 | ||
207 | for (; tbl->clk_id < clk_max; tbl++) { | 208 | for (; tbl->clk_id < clk_max; tbl++) { |
208 | clk = clks[tbl->clk_id]; | 209 | clk = clks[tbl->clk_id]; |
209 | if (IS_ERR_OR_NULL(clk)) | 210 | if (IS_ERR_OR_NULL(clk)) { |
210 | return; | 211 | pr_err("%s: invalid entry %ld in clks array for id %d\n", |
212 | __func__, PTR_ERR(clk), tbl->clk_id); | ||
213 | WARN_ON(1); | ||
214 | |||
215 | continue; | ||
216 | } | ||
211 | 217 | ||
212 | if (tbl->parent_id < clk_max) { | 218 | if (tbl->parent_id < clk_max) { |
213 | struct clk *parent = clks[tbl->parent_id]; | 219 | struct clk *parent = clks[tbl->parent_id]; |
diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c index 4a65b410e4d5..59bb4b39d12e 100644 --- a/drivers/clk/ti/clk-dra7-atl.c +++ b/drivers/clk/ti/clk-dra7-atl.c | |||
@@ -139,9 +139,13 @@ static long atl_clk_round_rate(struct clk_hw *hw, unsigned long rate, | |||
139 | static int atl_clk_set_rate(struct clk_hw *hw, unsigned long rate, | 139 | static int atl_clk_set_rate(struct clk_hw *hw, unsigned long rate, |
140 | unsigned long parent_rate) | 140 | unsigned long parent_rate) |
141 | { | 141 | { |
142 | struct dra7_atl_desc *cdesc = to_atl_desc(hw); | 142 | struct dra7_atl_desc *cdesc; |
143 | u32 divider; | 143 | u32 divider; |
144 | 144 | ||
145 | if (!hw || !rate) | ||
146 | return -EINVAL; | ||
147 | |||
148 | cdesc = to_atl_desc(hw); | ||
145 | divider = ((parent_rate + rate / 2) / rate) - 1; | 149 | divider = ((parent_rate + rate / 2) / rate) - 1; |
146 | if (divider > DRA7_ATL_DIVIDER_MASK) | 150 | if (divider > DRA7_ATL_DIVIDER_MASK) |
147 | divider = DRA7_ATL_DIVIDER_MASK; | 151 | divider = DRA7_ATL_DIVIDER_MASK; |
@@ -199,6 +203,7 @@ static void __init of_dra7_atl_clock_setup(struct device_node *node) | |||
199 | 203 | ||
200 | if (!IS_ERR(clk)) { | 204 | if (!IS_ERR(clk)) { |
201 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | 205 | of_clk_add_provider(node, of_clk_src_simple_get, clk); |
206 | kfree(parent_names); | ||
202 | return; | 207 | return; |
203 | } | 208 | } |
204 | cleanup: | 209 | cleanup: |
@@ -224,6 +229,7 @@ static int of_dra7_atl_clk_probe(struct platform_device *pdev) | |||
224 | cinfo->iobase = of_iomap(node, 0); | 229 | cinfo->iobase = of_iomap(node, 0); |
225 | cinfo->dev = &pdev->dev; | 230 | cinfo->dev = &pdev->dev; |
226 | pm_runtime_enable(cinfo->dev); | 231 | pm_runtime_enable(cinfo->dev); |
232 | pm_runtime_irq_safe(cinfo->dev); | ||
227 | 233 | ||
228 | pm_runtime_get_sync(cinfo->dev); | 234 | pm_runtime_get_sync(cinfo->dev); |
229 | atl_write(cinfo, DRA7_ATL_PCLKMUX_REG(0), DRA7_ATL_PCLKMUX); | 235 | atl_write(cinfo, DRA7_ATL_PCLKMUX_REG(0), DRA7_ATL_PCLKMUX); |
@@ -297,7 +303,6 @@ MODULE_DEVICE_TABLE(of, of_dra7_atl_clk_match_tbl); | |||
297 | static struct platform_driver dra7_atl_clk_driver = { | 303 | static struct platform_driver dra7_atl_clk_driver = { |
298 | .driver = { | 304 | .driver = { |
299 | .name = "dra7-atl", | 305 | .name = "dra7-atl", |
300 | .owner = THIS_MODULE, | ||
301 | .of_match_table = of_dra7_atl_clk_match_tbl, | 306 | .of_match_table = of_dra7_atl_clk_match_tbl, |
302 | }, | 307 | }, |
303 | .probe = of_dra7_atl_clk_probe, | 308 | .probe = of_dra7_atl_clk_probe, |
diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index b1a6f7144f3f..337abe5909e1 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c | |||
@@ -25,8 +25,8 @@ | |||
25 | #undef pr_fmt | 25 | #undef pr_fmt |
26 | #define pr_fmt(fmt) "%s: " fmt, __func__ | 26 | #define pr_fmt(fmt) "%s: " fmt, __func__ |
27 | 27 | ||
28 | static int ti_dt_clk_memmap_index; | ||
29 | struct ti_clk_ll_ops *ti_clk_ll_ops; | 28 | struct ti_clk_ll_ops *ti_clk_ll_ops; |
29 | static struct device_node *clocks_node_ptr[CLK_MAX_MEMMAPS]; | ||
30 | 30 | ||
31 | /** | 31 | /** |
32 | * ti_dt_clocks_register - register DT alias clocks during boot | 32 | * ti_dt_clocks_register - register DT alias clocks during boot |
@@ -108,9 +108,21 @@ void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index) | |||
108 | struct clk_omap_reg *reg; | 108 | struct clk_omap_reg *reg; |
109 | u32 val; | 109 | u32 val; |
110 | u32 tmp; | 110 | u32 tmp; |
111 | int i; | ||
111 | 112 | ||
112 | reg = (struct clk_omap_reg *)&tmp; | 113 | reg = (struct clk_omap_reg *)&tmp; |
113 | reg->index = ti_dt_clk_memmap_index; | 114 | |
115 | for (i = 0; i < CLK_MAX_MEMMAPS; i++) { | ||
116 | if (clocks_node_ptr[i] == node->parent) | ||
117 | break; | ||
118 | } | ||
119 | |||
120 | if (i == CLK_MAX_MEMMAPS) { | ||
121 | pr_err("clk-provider not found for %s!\n", node->name); | ||
122 | return NULL; | ||
123 | } | ||
124 | |||
125 | reg->index = i; | ||
114 | 126 | ||
115 | if (of_property_read_u32_index(node, "reg", index, &val)) { | 127 | if (of_property_read_u32_index(node, "reg", index, &val)) { |
116 | pr_err("%s must have reg[%d]!\n", node->name, index); | 128 | pr_err("%s must have reg[%d]!\n", node->name, index); |
@@ -127,20 +139,14 @@ void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index) | |||
127 | * @parent: master node | 139 | * @parent: master node |
128 | * @index: internal index for clk_reg_ops | 140 | * @index: internal index for clk_reg_ops |
129 | * | 141 | * |
130 | * Initializes a master clock IP block and its child clock nodes. | 142 | * Initializes a master clock IP block. This basically sets up the |
131 | * Regmap is provided for accessing the register space for the | 143 | * mapping from clocks node to the memory map index. All the clocks |
132 | * IP block and all the clocks under it. | 144 | * are then initialized through the common of_clk_init call, and the |
145 | * clocks will access their memory maps based on the node layout. | ||
133 | */ | 146 | */ |
134 | void ti_dt_clk_init_provider(struct device_node *parent, int index) | 147 | void ti_dt_clk_init_provider(struct device_node *parent, int index) |
135 | { | 148 | { |
136 | const struct of_device_id *match; | ||
137 | struct device_node *np; | ||
138 | struct device_node *clocks; | 149 | struct device_node *clocks; |
139 | of_clk_init_cb_t clk_init_cb; | ||
140 | struct clk_init_item *retry; | ||
141 | struct clk_init_item *tmp; | ||
142 | |||
143 | ti_dt_clk_memmap_index = index; | ||
144 | 150 | ||
145 | /* get clocks for this parent */ | 151 | /* get clocks for this parent */ |
146 | clocks = of_get_child_by_name(parent, "clocks"); | 152 | clocks = of_get_child_by_name(parent, "clocks"); |
@@ -149,19 +155,31 @@ void ti_dt_clk_init_provider(struct device_node *parent, int index) | |||
149 | return; | 155 | return; |
150 | } | 156 | } |
151 | 157 | ||
152 | for_each_child_of_node(clocks, np) { | 158 | /* add clocks node info */ |
153 | match = of_match_node(&__clk_of_table, np); | 159 | clocks_node_ptr[index] = clocks; |
154 | if (!match) | 160 | } |
155 | continue; | ||
156 | clk_init_cb = (of_clk_init_cb_t)match->data; | ||
157 | pr_debug("%s: initializing: %s\n", __func__, np->name); | ||
158 | clk_init_cb(np); | ||
159 | } | ||
160 | 161 | ||
161 | list_for_each_entry_safe(retry, tmp, &retry_list, link) { | 162 | /** |
162 | pr_debug("retry-init: %s\n", retry->node->name); | 163 | * ti_dt_clk_init_retry_clks - init clocks from the retry list |
163 | retry->func(retry->hw, retry->node); | 164 | * |
164 | list_del(&retry->link); | 165 | * Initializes any clocks that have failed to initialize before, |
165 | kfree(retry); | 166 | * reasons being missing parent node(s) during earlier init. This |
167 | * typically happens only for DPLLs which need to have both of their | ||
168 | * parent clocks ready during init. | ||
169 | */ | ||
170 | void ti_dt_clk_init_retry_clks(void) | ||
171 | { | ||
172 | struct clk_init_item *retry; | ||
173 | struct clk_init_item *tmp; | ||
174 | int retries = 5; | ||
175 | |||
176 | while (!list_empty(&retry_list) && retries) { | ||
177 | list_for_each_entry_safe(retry, tmp, &retry_list, link) { | ||
178 | pr_debug("retry-init: %s\n", retry->node->name); | ||
179 | retry->func(retry->hw, retry->node); | ||
180 | list_del(&retry->link); | ||
181 | kfree(retry); | ||
182 | } | ||
183 | retries--; | ||
166 | } | 184 | } |
167 | } | 185 | } |
diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c index f1e0038d76ac..b4c5faccaece 100644 --- a/drivers/clk/ti/clockdomain.c +++ b/drivers/clk/ti/clockdomain.c | |||
@@ -36,6 +36,11 @@ static void __init of_ti_clockdomain_setup(struct device_node *node) | |||
36 | 36 | ||
37 | for (i = 0; i < num_clks; i++) { | 37 | for (i = 0; i < num_clks; i++) { |
38 | clk = of_clk_get(node, i); | 38 | clk = of_clk_get(node, i); |
39 | if (IS_ERR(clk)) { | ||
40 | pr_err("%s: Failed get %s' clock nr %d (%ld)\n", | ||
41 | __func__, node->full_name, i, PTR_ERR(clk)); | ||
42 | continue; | ||
43 | } | ||
39 | if (__clk_get_flags(clk) & CLK_IS_BASIC) { | 44 | if (__clk_get_flags(clk) & CLK_IS_BASIC) { |
40 | pr_warn("can't setup clkdm for basic clk %s\n", | 45 | pr_warn("can't setup clkdm for basic clk %s\n", |
41 | __clk_get_name(clk)); | 46 | __clk_get_name(clk)); |
diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c index e6aa10db7bba..bff2b5b8ff59 100644 --- a/drivers/clk/ti/divider.c +++ b/drivers/clk/ti/divider.c | |||
@@ -211,11 +211,16 @@ static long ti_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, | |||
211 | static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, | 211 | static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, |
212 | unsigned long parent_rate) | 212 | unsigned long parent_rate) |
213 | { | 213 | { |
214 | struct clk_divider *divider = to_clk_divider(hw); | 214 | struct clk_divider *divider; |
215 | unsigned int div, value; | 215 | unsigned int div, value; |
216 | unsigned long flags = 0; | 216 | unsigned long flags = 0; |
217 | u32 val; | 217 | u32 val; |
218 | 218 | ||
219 | if (!hw || !rate) | ||
220 | return -EINVAL; | ||
221 | |||
222 | divider = to_clk_divider(hw); | ||
223 | |||
219 | div = DIV_ROUND_UP(parent_rate, rate); | 224 | div = DIV_ROUND_UP(parent_rate, rate); |
220 | value = _get_val(divider, div); | 225 | value = _get_val(divider, div); |
221 | 226 | ||
@@ -295,8 +300,8 @@ static struct clk *_register_divider(struct device *dev, const char *name, | |||
295 | return clk; | 300 | return clk; |
296 | } | 301 | } |
297 | 302 | ||
298 | static struct clk_div_table | 303 | static struct clk_div_table * |
299 | __init *ti_clk_get_div_table(struct device_node *node) | 304 | __init ti_clk_get_div_table(struct device_node *node) |
300 | { | 305 | { |
301 | struct clk_div_table *table; | 306 | struct clk_div_table *table; |
302 | const __be32 *divspec; | 307 | const __be32 *divspec; |
diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile index fd449f9b006d..162e519cb0f9 100644 --- a/drivers/clk/versatile/Makefile +++ b/drivers/clk/versatile/Makefile | |||
@@ -1,6 +1,5 @@ | |||
1 | # Makefile for Versatile-specific clocks | 1 | # Makefile for Versatile-specific clocks |
2 | obj-$(CONFIG_ICST) += clk-icst.o | 2 | obj-$(CONFIG_ICST) += clk-icst.o clk-versatile.o |
3 | obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o | ||
4 | obj-$(CONFIG_INTEGRATOR_IMPD1) += clk-impd1.o | 3 | obj-$(CONFIG_INTEGRATOR_IMPD1) += clk-impd1.o |
5 | obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o | 4 | obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o |
6 | obj-$(CONFIG_ARCH_VEXPRESS) += clk-vexpress.o | 5 | obj-$(CONFIG_ARCH_VEXPRESS) += clk-vexpress.o |
diff --git a/drivers/clk/versatile/clk-integrator.c b/drivers/clk/versatile/clk-versatile.c index 734c4b8fe6ab..a76981e88cb6 100644 --- a/drivers/clk/versatile/clk-integrator.c +++ b/drivers/clk/versatile/clk-versatile.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Clock driver for the ARM Integrator/AP and Integrator/CP boards | 2 | * Clock driver for the ARM Integrator/AP, Integrator/CP, Versatile AB and |
3 | * Versatile PB boards. | ||
3 | * Copyright (C) 2012 Linus Walleij | 4 | * Copyright (C) 2012 Linus Walleij |
4 | * | 5 | * |
5 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
@@ -17,6 +18,9 @@ | |||
17 | 18 | ||
18 | #define INTEGRATOR_HDR_LOCK_OFFSET 0x14 | 19 | #define INTEGRATOR_HDR_LOCK_OFFSET 0x14 |
19 | 20 | ||
21 | #define VERSATILE_SYS_OSCCLCD_OFFSET 0x1c | ||
22 | #define VERSATILE_SYS_LOCK_OFFSET 0x20 | ||
23 | |||
20 | /* Base offset for the core module */ | 24 | /* Base offset for the core module */ |
21 | static void __iomem *cm_base; | 25 | static void __iomem *cm_base; |
22 | 26 | ||
@@ -37,11 +41,27 @@ static const struct clk_icst_desc __initdata cm_auxosc_desc = { | |||
37 | .lock_offset = INTEGRATOR_HDR_LOCK_OFFSET, | 41 | .lock_offset = INTEGRATOR_HDR_LOCK_OFFSET, |
38 | }; | 42 | }; |
39 | 43 | ||
40 | static void __init of_integrator_cm_osc_setup(struct device_node *np) | 44 | static const struct icst_params versatile_auxosc_params = { |
45 | .vco_max = ICST307_VCO_MAX, | ||
46 | .vco_min = ICST307_VCO_MIN, | ||
47 | .vd_min = 4 + 8, | ||
48 | .vd_max = 511 + 8, | ||
49 | .rd_min = 1 + 2, | ||
50 | .rd_max = 127 + 2, | ||
51 | .s2div = icst307_s2div, | ||
52 | .idx2s = icst307_idx2s, | ||
53 | }; | ||
54 | |||
55 | static const struct clk_icst_desc versatile_auxosc_desc __initconst = { | ||
56 | .params = &versatile_auxosc_params, | ||
57 | .vco_offset = VERSATILE_SYS_OSCCLCD_OFFSET, | ||
58 | .lock_offset = VERSATILE_SYS_LOCK_OFFSET, | ||
59 | }; | ||
60 | static void __init cm_osc_setup(struct device_node *np, | ||
61 | const struct clk_icst_desc *desc) | ||
41 | { | 62 | { |
42 | struct clk *clk = ERR_PTR(-EINVAL); | 63 | struct clk *clk = ERR_PTR(-EINVAL); |
43 | const char *clk_name = np->name; | 64 | const char *clk_name = np->name; |
44 | const struct clk_icst_desc *desc = &cm_auxosc_desc; | ||
45 | const char *parent_name; | 65 | const char *parent_name; |
46 | 66 | ||
47 | if (!cm_base) { | 67 | if (!cm_base) { |
@@ -65,5 +85,17 @@ static void __init of_integrator_cm_osc_setup(struct device_node *np) | |||
65 | if (!IS_ERR(clk)) | 85 | if (!IS_ERR(clk)) |
66 | of_clk_add_provider(np, of_clk_src_simple_get, clk); | 86 | of_clk_add_provider(np, of_clk_src_simple_get, clk); |
67 | } | 87 | } |
88 | |||
89 | static void __init of_integrator_cm_osc_setup(struct device_node *np) | ||
90 | { | ||
91 | cm_osc_setup(np, &cm_auxosc_desc); | ||
92 | } | ||
68 | CLK_OF_DECLARE(integrator_cm_auxosc_clk, | 93 | CLK_OF_DECLARE(integrator_cm_auxosc_clk, |
69 | "arm,integrator-cm-auxosc", of_integrator_cm_osc_setup); | 94 | "arm,integrator-cm-auxosc", of_integrator_cm_osc_setup); |
95 | |||
96 | static void __init of_versatile_cm_osc_setup(struct device_node *np) | ||
97 | { | ||
98 | cm_osc_setup(np, &versatile_auxosc_desc); | ||
99 | } | ||
100 | CLK_OF_DECLARE(versatile_cm_auxosc_clk, | ||
101 | "arm,versatile-cm-auxosc", of_versatile_cm_osc_setup); | ||
diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c index 246cf1226eaa..9037bebd69f7 100644 --- a/drivers/clk/zynq/clkc.c +++ b/drivers/clk/zynq/clkc.c | |||
@@ -85,24 +85,22 @@ static DEFINE_SPINLOCK(canmioclk_lock); | |||
85 | static DEFINE_SPINLOCK(dbgclk_lock); | 85 | static DEFINE_SPINLOCK(dbgclk_lock); |
86 | static DEFINE_SPINLOCK(aperclk_lock); | 86 | static DEFINE_SPINLOCK(aperclk_lock); |
87 | 87 | ||
88 | static const char dummy_nm[] __initconst = "dummy_name"; | 88 | static const char *armpll_parents[] __initconst = {"armpll_int", "ps_clk"}; |
89 | 89 | static const char *ddrpll_parents[] __initconst = {"ddrpll_int", "ps_clk"}; | |
90 | static const char *armpll_parents[] __initdata = {"armpll_int", "ps_clk"}; | 90 | static const char *iopll_parents[] __initconst = {"iopll_int", "ps_clk"}; |
91 | static const char *ddrpll_parents[] __initdata = {"ddrpll_int", "ps_clk"}; | 91 | static const char *gem0_mux_parents[] __initconst = {"gem0_div1", "dummy_name"}; |
92 | static const char *iopll_parents[] __initdata = {"iopll_int", "ps_clk"}; | 92 | static const char *gem1_mux_parents[] __initconst = {"gem1_div1", "dummy_name"}; |
93 | static const char *gem0_mux_parents[] __initdata = {"gem0_div1", dummy_nm}; | 93 | static const char *can0_mio_mux2_parents[] __initconst = {"can0_gate", |
94 | static const char *gem1_mux_parents[] __initdata = {"gem1_div1", dummy_nm}; | ||
95 | static const char *can0_mio_mux2_parents[] __initdata = {"can0_gate", | ||
96 | "can0_mio_mux"}; | 94 | "can0_mio_mux"}; |
97 | static const char *can1_mio_mux2_parents[] __initdata = {"can1_gate", | 95 | static const char *can1_mio_mux2_parents[] __initconst = {"can1_gate", |
98 | "can1_mio_mux"}; | 96 | "can1_mio_mux"}; |
99 | static const char *dbg_emio_mux_parents[] __initdata = {"dbg_div", | 97 | static const char *dbg_emio_mux_parents[] __initconst = {"dbg_div", |
100 | dummy_nm}; | 98 | "dummy_name"}; |
101 | 99 | ||
102 | static const char *dbgtrc_emio_input_names[] __initdata = {"trace_emio_clk"}; | 100 | static const char *dbgtrc_emio_input_names[] __initconst = {"trace_emio_clk"}; |
103 | static const char *gem0_emio_input_names[] __initdata = {"gem0_emio_clk"}; | 101 | static const char *gem0_emio_input_names[] __initconst = {"gem0_emio_clk"}; |
104 | static const char *gem1_emio_input_names[] __initdata = {"gem1_emio_clk"}; | 102 | static const char *gem1_emio_input_names[] __initconst = {"gem1_emio_clk"}; |
105 | static const char *swdt_ext_clk_input_names[] __initdata = {"swdt_ext_clk"}; | 103 | static const char *swdt_ext_clk_input_names[] __initconst = {"swdt_ext_clk"}; |
106 | 104 | ||
107 | static void __init zynq_clk_register_fclk(enum zynq_clk fclk, | 105 | static void __init zynq_clk_register_fclk(enum zynq_clk fclk, |
108 | const char *clk_name, void __iomem *fclk_ctrl_reg, | 106 | const char *clk_name, void __iomem *fclk_ctrl_reg, |
@@ -230,6 +228,7 @@ static void __init zynq_clk_setup(struct device_node *np) | |||
230 | const char *periph_parents[4]; | 228 | const char *periph_parents[4]; |
231 | const char *swdt_ext_clk_mux_parents[2]; | 229 | const char *swdt_ext_clk_mux_parents[2]; |
232 | const char *can_mio_mux_parents[NUM_MIO_PINS]; | 230 | const char *can_mio_mux_parents[NUM_MIO_PINS]; |
231 | const char *dummy_nm = "dummy_name"; | ||
233 | 232 | ||
234 | pr_info("Zynq clock init\n"); | 233 | pr_info("Zynq clock init\n"); |
235 | 234 | ||
@@ -619,5 +618,4 @@ void __init zynq_clock_init(void) | |||
619 | np_err: | 618 | np_err: |
620 | of_node_put(np); | 619 | of_node_put(np); |
621 | BUG(); | 620 | BUG(); |
622 | return; | ||
623 | } | 621 | } |
diff --git a/drivers/clk/zynq/pll.c b/drivers/clk/zynq/pll.c index cec97596fe65..00d72fb5c036 100644 --- a/drivers/clk/zynq/pll.c +++ b/drivers/clk/zynq/pll.c | |||
@@ -211,10 +211,8 @@ struct clk *clk_register_zynq_pll(const char *name, const char *parent, | |||
211 | }; | 211 | }; |
212 | 212 | ||
213 | pll = kmalloc(sizeof(*pll), GFP_KERNEL); | 213 | pll = kmalloc(sizeof(*pll), GFP_KERNEL); |
214 | if (!pll) { | 214 | if (!pll) |
215 | pr_err("%s: Could not allocate Zynq PLL clk.\n", __func__); | ||
216 | return ERR_PTR(-ENOMEM); | 215 | return ERR_PTR(-ENOMEM); |
217 | } | ||
218 | 216 | ||
219 | /* Populate the struct */ | 217 | /* Populate the struct */ |
220 | pll->hw.init = &initd; | 218 | pll->hw.init = &initd; |