diff options
-rw-r--r-- | Documentation/devicetree/bindings/clock/sunxi.txt | 4 | ||||
-rw-r--r-- | arch/arm/boot/dts/sun5i-a10s.dtsi | 2 | ||||
-rw-r--r-- | arch/arm/boot/dts/sun5i-a13.dtsi | 2 | ||||
-rw-r--r-- | arch/arm/boot/dts/sun7i-a20.dtsi | 2 | ||||
-rw-r--r-- | drivers/clk/clk.c | 95 | ||||
-rw-r--r-- | drivers/clk/sunxi/Makefile | 2 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-factors.c | 101 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-factors.h | 16 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-mod0.c | 283 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-sun8i-mbus.c | 78 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-sunxi.c | 161 | ||||
-rw-r--r-- | include/linux/clk-private.h | 1 | ||||
-rw-r--r-- | include/linux/clk-provider.h | 11 | ||||
-rw-r--r-- | include/linux/clk.h | 29 |
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 | ||
129 | 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, |
@@ -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 | ||
187 | 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) |
@@ -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: | |||
1726 | EXPORT_SYMBOL_GPL(clk_set_parent); | 1732 | EXPORT_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 | */ | ||
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 | /** | ||
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 @@ | |||
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-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/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 | */ |
107 | long clk_get_accuracy(struct clk *clk); | 107 | long 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 | */ | ||
117 | int 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 | */ | ||
126 | int clk_get_phase(struct clk *clk); | ||
127 | |||
109 | #else | 128 | #else |
110 | 129 | ||
111 | static inline long clk_get_accuracy(struct clk *clk) | 130 | static 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 | ||
135 | static inline long clk_set_phase(struct clk *clk, int phase) | ||
136 | { | ||
137 | return -ENOTSUPP; | ||
138 | } | ||
139 | |||
140 | static inline long clk_get_phase(struct clk *clk) | ||
141 | { | ||
142 | return -ENOTSUPP; | ||
143 | } | ||
144 | |||
116 | #endif | 145 | #endif |
117 | 146 | ||
118 | /** | 147 | /** |