aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/clock/sunxi.txt4
-rw-r--r--arch/arm/boot/dts/sun5i-a10s.dtsi2
-rw-r--r--arch/arm/boot/dts/sun5i-a13.dtsi2
-rw-r--r--arch/arm/boot/dts/sun7i-a20.dtsi2
-rw-r--r--drivers/clk/clk.c95
-rw-r--r--drivers/clk/sunxi/Makefile2
-rw-r--r--drivers/clk/sunxi/clk-factors.c101
-rw-r--r--drivers/clk/sunxi/clk-factors.h16
-rw-r--r--drivers/clk/sunxi/clk-mod0.c283
-rw-r--r--drivers/clk/sunxi/clk-sun8i-mbus.c78
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c161
-rw-r--r--include/linux/clk-private.h1
-rw-r--r--include/linux/clk-provider.h11
-rw-r--r--include/linux/clk.h29
14 files changed, 624 insertions, 163 deletions
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index d3a5c3c6d677..ed116df9c3e7 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -46,7 +46,11 @@ Required properties:
46 "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31 46 "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31
47 "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 47 "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
48 "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23 48 "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
49 "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
50 "allwinner,sun4i-a10-mmc-output-clk" - for the MMC output clock on A10
51 "allwinner,sun4i-a10-mmc-sample-clk" - for the MMC sample clock on A10
49 "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks 52 "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
53 "allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23
50 "allwinner,sun7i-a20-out-clk" - for the external output clocks 54 "allwinner,sun7i-a20-out-clk" - for the external output clocks
51 "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31 55 "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
52 "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20 56 "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
index 24b0ad3a7c07..82094283473d 100644
--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
+++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
@@ -287,7 +287,7 @@
287 287
288 mbus_clk: clk@01c2015c { 288 mbus_clk: clk@01c2015c {
289 #clock-cells = <0>; 289 #clock-cells = <0>;
290 compatible = "allwinner,sun4i-a10-mod0-clk"; 290 compatible = "allwinner,sun5i-a13-mbus-clk";
291 reg = <0x01c2015c 0x4>; 291 reg = <0x01c2015c 0x4>;
292 clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; 292 clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
293 clock-output-names = "mbus"; 293 clock-output-names = "mbus";
diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
index bf86e65dd167..53e0e72a9d32 100644
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -285,7 +285,7 @@
285 285
286 mbus_clk: clk@01c2015c { 286 mbus_clk: clk@01c2015c {
287 #clock-cells = <0>; 287 #clock-cells = <0>;
288 compatible = "allwinner,sun4i-a10-mod0-clk"; 288 compatible = "allwinner,sun5i-a13-mbus-clk";
289 reg = <0x01c2015c 0x4>; 289 reg = <0x01c2015c 0x4>;
290 clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; 290 clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
291 clock-output-names = "mbus"; 291 clock-output-names = "mbus";
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index 4011628c7381..2edef89ef0a5 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -346,7 +346,7 @@
346 346
347 mbus_clk: clk@01c2015c { 347 mbus_clk: clk@01c2015c {
348 #clock-cells = <0>; 348 #clock-cells = <0>;
349 compatible = "allwinner,sun4i-a10-mod0-clk"; 349 compatible = "allwinner,sun5i-a13-mbus-clk";
350 reg = <0x01c2015c 0x4>; 350 reg = <0x01c2015c 0x4>;
351 clocks = <&osc24M>, <&pll6 2>, <&pll5 1>; 351 clocks = <&osc24M>, <&pll6 2>, <&pll5 1>;
352 clock-output-names = "mbus"; 352 clock-output-names = "mbus";
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 52d58279a612..4896ae9e23da 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -119,11 +119,11 @@ static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)
119 if (!c) 119 if (!c)
120 return; 120 return;
121 121
122 seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu\n", 122 seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu %-3d\n",
123 level * 3 + 1, "", 123 level * 3 + 1, "",
124 30 - level * 3, c->name, 124 30 - level * 3, c->name,
125 c->enable_count, c->prepare_count, clk_get_rate(c), 125 c->enable_count, c->prepare_count, clk_get_rate(c),
126 clk_get_accuracy(c)); 126 clk_get_accuracy(c), clk_get_phase(c));
127} 127}
128 128
129static void clk_summary_show_subtree(struct seq_file *s, struct clk *c, 129static void clk_summary_show_subtree(struct seq_file *s, struct clk *c,
@@ -145,8 +145,8 @@ static int clk_summary_show(struct seq_file *s, void *data)
145 struct clk *c; 145 struct clk *c;
146 struct hlist_head **lists = (struct hlist_head **)s->private; 146 struct hlist_head **lists = (struct hlist_head **)s->private;
147 147
148 seq_puts(s, " clock enable_cnt prepare_cnt rate accuracy\n"); 148 seq_puts(s, " clock enable_cnt prepare_cnt rate accuracy phase\n");
149 seq_puts(s, "--------------------------------------------------------------------------------\n"); 149 seq_puts(s, "----------------------------------------------------------------------------------------\n");
150 150
151 clk_prepare_lock(); 151 clk_prepare_lock();
152 152
@@ -182,6 +182,7 @@ static void clk_dump_one(struct seq_file *s, struct clk *c, int level)
182 seq_printf(s, "\"prepare_count\": %d,", c->prepare_count); 182 seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
183 seq_printf(s, "\"rate\": %lu", clk_get_rate(c)); 183 seq_printf(s, "\"rate\": %lu", clk_get_rate(c));
184 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));
185} 186}
186 187
187static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level) 188static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level)
@@ -266,6 +267,11 @@ static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
266 if (!d) 267 if (!d)
267 goto err_out; 268 goto err_out;
268 269
270 d = debugfs_create_u32("clk_phase", S_IRUGO, clk->dentry,
271 (u32 *)&clk->phase);
272 if (!d)
273 goto err_out;
274
269 d = debugfs_create_x32("clk_flags", S_IRUGO, clk->dentry, 275 d = debugfs_create_x32("clk_flags", S_IRUGO, clk->dentry,
270 (u32 *)&clk->flags); 276 (u32 *)&clk->flags);
271 if (!d) 277 if (!d)
@@ -1726,6 +1732,77 @@ out:
1726EXPORT_SYMBOL_GPL(clk_set_parent); 1732EXPORT_SYMBOL_GPL(clk_set_parent);
1727 1733
1728/** 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 */
1754int 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
1776out_unlock:
1777 clk_prepare_unlock();
1778
1779out:
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 */
1790int 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
1801out:
1802 return ret;
1803}
1804
1805/**
1729 * __clk_init - initialize the data structures in a struct clk 1806 * __clk_init - initialize the data structures in a struct clk
1730 * @dev: device initializing this clk, placeholder for now 1807 * @dev: device initializing this clk, placeholder for now
1731 * @clk: clk being initialized 1808 * @clk: clk being initialized
@@ -1844,6 +1921,16 @@ int __clk_init(struct device *dev, struct clk *clk)
1844 clk->accuracy = 0; 1921 clk->accuracy = 0;
1845 1922
1846 /* 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 /*
1847 * 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
1848 * 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
1849 * 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)
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 @@
5obj-y += clk-sunxi.o clk-factors.o 5obj-y += clk-sunxi.o clk-factors.o
6obj-y += clk-a10-hosc.o 6obj-y += clk-a10-hosc.o
7obj-y += clk-a20-gmac.o 7obj-y += clk-a20-gmac.o
8obj-y += clk-mod0.o
9obj-y += clk-sun8i-mbus.o
8 10
9obj-$(CONFIG_MFD_SUN6I_PRCM) += \ 11obj-$(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
150const struct clk_ops clk_factors_ops = { 152static 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
159struct 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
9struct clk_factors_config { 12struct 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
24struct 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
21struct clk_factors { 32struct 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
29extern const struct clk_ops clk_factors_ops; 40struct 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
29static 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" */
63static struct clk_factors_config sun4i_a10_mod0_config = {
64 .mshift = 0,
65 .mwidth = 4,
66 .pshift = 16,
67 .pwidth = 2,
68};
69
70static 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
77static DEFINE_SPINLOCK(sun4i_a10_mod0_lock);
78
79static 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}
83CLK_OF_DECLARE(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", sun4i_a10_mod0_setup);
84
85static DEFINE_SPINLOCK(sun5i_a13_mbus_lock);
86
87static 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}
95CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup);
96
97struct mmc_phase_data {
98 u8 offset;
99};
100
101struct 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
110static 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
152static 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
216static const struct clk_ops mmc_clk_ops = {
217 .get_phase = mmc_get_phase,
218 .set_phase = mmc_set_phase,
219};
220
221static 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
258err_unmap:
259 iounmap(phase->reg);
260err_free:
261 kfree(phase);
262}
263
264
265static struct mmc_phase_data mmc_output_clk = {
266 .offset = 8,
267};
268
269static struct mmc_phase_data mmc_sample_clk = {
270 .offset = 20,
271};
272
273static void __init sun4i_a10_mmc_output_setup(struct device_node *node)
274{
275 sun4i_a10_mmc_phase_setup(node, &mmc_output_clk);
276}
277CLK_OF_DECLARE(sun4i_a10_mmc_output, "allwinner,sun4i-a10-mmc-output-clk", sun4i_a10_mmc_output_setup);
278
279static void __init sun4i_a10_mmc_sample_setup(struct device_node *node)
280{
281 sun4i_a10_mmc_phase_setup(node, &mmc_sample_clk);
282}
283CLK_OF_DECLARE(sun4i_a10_mmc_sample, "allwinner,sun4i-a10-mmc-sample-clk", sun4i_a10_mmc_sample_setup);
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
29static 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
55static struct clk_factors_config sun8i_a23_mbus_config = {
56 .mshift = 0,
57 .mwidth = 3,
58};
59
60static 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
67static DEFINE_SPINLOCK(sun8i_a23_mbus_lock);
68
69static 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}
78CLK_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
328static 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
445struct 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
453static struct clk_factors_config sun4i_pll1_config = { 404static 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" */
507static 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" */
515static struct clk_factors_config sun7i_a20_out_config = { 458static 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
571static 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
578static const struct factors_data sun7i_a20_out_data __initconst = { 514static 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
585static struct clk * __init sunxi_factors_clk_setup(struct device_node *node, 521static 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
621static 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
765static const struct div_data sun4i_apb0_data __initconst = { 629static 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
771static const struct div_data sun6i_a31_apb2_div_data __initconst = { 636static 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)
1311CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sun4i_a10_init_clocks); 1175CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sun4i_a10_init_clocks);
1312 1176
1313static const char *sun5i_critical_clocks[] __initdata = { 1177static 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/include/linux/clk-private.h b/include/linux/clk-private.h
index 4ed34105c371..0ca5f6046920 100644
--- a/include/linux/clk-private.h
+++ b/include/linux/clk-private.h
@@ -46,6 +46,7 @@ struct clk {
46 unsigned int enable_count; 46 unsigned int enable_count;
47 unsigned int prepare_count; 47 unsigned int prepare_count;
48 unsigned long accuracy; 48 unsigned long accuracy;
49 int phase;
49 struct hlist_head children; 50 struct hlist_head children;
50 struct hlist_node child_node; 51 struct hlist_node child_node;
51 struct hlist_node debug_node; 52 struct hlist_node debug_node;
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index ec1581bd94cd..be21af149f11 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -13,6 +13,7 @@
13 13
14#include <linux/clk.h> 14#include <linux/clk.h>
15#include <linux/io.h> 15#include <linux/io.h>
16#include <linux/of.h>
16 17
17#ifdef CONFIG_COMMON_CLK 18#ifdef CONFIG_COMMON_CLK
18 19
@@ -129,6 +130,14 @@ struct dentry;
129 * set then clock accuracy will be initialized to parent accuracy 130 * set then clock accuracy will be initialized to parent accuracy
130 * or 0 (perfect clock) if clock has no parent. 131 * or 0 (perfect clock) if clock has no parent.
131 * 132 *
133 * @get_phase: Queries the hardware to get the current phase of a clock.
134 * Returned values are 0-359 degrees on success, negative
135 * error codes on failure.
136 *
137 * @set_phase: Shift the phase this clock signal in degrees specified
138 * by the second argument. Valid values for degrees are
139 * 0-359. Return 0 on success, otherwise -EERROR.
140 *
132 * @init: Perform platform-specific initialization magic. 141 * @init: Perform platform-specific initialization magic.
133 * This is not not used by any of the basic clock types. 142 * This is not not used by any of the basic clock types.
134 * Please consider other ways of solving initialization problems 143 * Please consider other ways of solving initialization problems
@@ -177,6 +186,8 @@ struct clk_ops {
177 unsigned long parent_rate, u8 index); 186 unsigned long parent_rate, u8 index);
178 unsigned long (*recalc_accuracy)(struct clk_hw *hw, 187 unsigned long (*recalc_accuracy)(struct clk_hw *hw,
179 unsigned long parent_accuracy); 188 unsigned long parent_accuracy);
189 int (*get_phase)(struct clk_hw *hw);
190 int (*set_phase)(struct clk_hw *hw, int degrees);
180 void (*init)(struct clk_hw *hw); 191 void (*init)(struct clk_hw *hw);
181 int (*debug_init)(struct clk_hw *hw, struct dentry *dentry); 192 int (*debug_init)(struct clk_hw *hw, struct dentry *dentry);
182}; 193};
diff --git a/include/linux/clk.h b/include/linux/clk.h
index fb5e097d8f72..38bdedd3e389 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -106,6 +106,25 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);
106 */ 106 */
107long clk_get_accuracy(struct clk *clk); 107long clk_get_accuracy(struct clk *clk);
108 108
109/**
110 * clk_set_phase - adjust the phase shift of a clock signal
111 * @clk: clock signal source
112 * @degrees: number of degrees the signal is shifted
113 *
114 * Shifts the phase of a clock signal by the specified degrees. Returns 0 on
115 * success, -EERROR otherwise.
116 */
117int clk_set_phase(struct clk *clk, int degrees);
118
119/**
120 * clk_get_phase - return the phase shift of a clock signal
121 * @clk: clock signal source
122 *
123 * Returns the phase shift of a clock node in degrees, otherwise returns
124 * -EERROR.
125 */
126int clk_get_phase(struct clk *clk);
127
109#else 128#else
110 129
111static inline long clk_get_accuracy(struct clk *clk) 130static inline long clk_get_accuracy(struct clk *clk)
@@ -113,6 +132,16 @@ static inline long clk_get_accuracy(struct clk *clk)
113 return -ENOTSUPP; 132 return -ENOTSUPP;
114} 133}
115 134
135static inline long clk_set_phase(struct clk *clk, int phase)
136{
137 return -ENOTSUPP;
138}
139
140static inline long clk_get_phase(struct clk *clk)
141{
142 return -ENOTSUPP;
143}
144
116#endif 145#endif
117 146
118/** 147/**