diff options
Diffstat (limited to 'drivers/clk')
26 files changed, 3585 insertions, 228 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 165e1febae5..4864407e3fc 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig | |||
@@ -12,6 +12,7 @@ config HAVE_MACH_CLKDEV | |||
12 | config COMMON_CLK | 12 | config COMMON_CLK |
13 | bool | 13 | bool |
14 | select HAVE_CLK_PREPARE | 14 | select HAVE_CLK_PREPARE |
15 | select CLKDEV_LOOKUP | ||
15 | ---help--- | 16 | ---help--- |
16 | The common clock framework is a single definition of struct | 17 | The common clock framework is a single definition of struct |
17 | clk, useful across many platforms, as well as an | 18 | clk, useful across many platforms, as well as an |
@@ -22,17 +23,6 @@ config COMMON_CLK | |||
22 | menu "Common Clock Framework" | 23 | menu "Common Clock Framework" |
23 | depends on COMMON_CLK | 24 | depends on COMMON_CLK |
24 | 25 | ||
25 | config COMMON_CLK_DISABLE_UNUSED | ||
26 | bool "Disabled unused clocks at boot" | ||
27 | depends on COMMON_CLK | ||
28 | ---help--- | ||
29 | Traverses the entire clock tree and disables any clocks that are | ||
30 | enabled in hardware but have not been enabled by any device drivers. | ||
31 | This saves power and keeps the software model of the clock in line | ||
32 | with reality. | ||
33 | |||
34 | If in doubt, say "N". | ||
35 | |||
36 | config COMMON_CLK_DEBUG | 26 | config COMMON_CLK_DEBUG |
37 | bool "DebugFS representation of clock tree" | 27 | bool "DebugFS representation of clock tree" |
38 | depends on COMMON_CLK | 28 | depends on COMMON_CLK |
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 1f736bc11c4..b9a5158a30b 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile | |||
@@ -1,4 +1,7 @@ | |||
1 | 1 | ||
2 | obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o | 2 | obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o |
3 | obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \ | 3 | obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \ |
4 | clk-mux.o clk-divider.o | 4 | clk-mux.o clk-divider.o clk-fixed-factor.o |
5 | # SoCs specific | ||
6 | obj-$(CONFIG_ARCH_MXS) += mxs/ | ||
7 | obj-$(CONFIG_PLAT_SPEAR) += spear/ | ||
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index d5ac6a75ea5..8ea11b44452 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c | |||
@@ -45,7 +45,6 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, | |||
45 | 45 | ||
46 | return parent_rate / div; | 46 | return parent_rate / div; |
47 | } | 47 | } |
48 | EXPORT_SYMBOL_GPL(clk_divider_recalc_rate); | ||
49 | 48 | ||
50 | /* | 49 | /* |
51 | * The reverse of DIV_ROUND_UP: The maximum number which | 50 | * The reverse of DIV_ROUND_UP: The maximum number which |
@@ -68,8 +67,8 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, | |||
68 | if (divider->flags & CLK_DIVIDER_ONE_BASED) | 67 | if (divider->flags & CLK_DIVIDER_ONE_BASED) |
69 | maxdiv--; | 68 | maxdiv--; |
70 | 69 | ||
71 | if (!best_parent_rate) { | 70 | if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { |
72 | parent_rate = __clk_get_rate(__clk_get_parent(hw->clk)); | 71 | parent_rate = *best_parent_rate; |
73 | bestdiv = DIV_ROUND_UP(parent_rate, rate); | 72 | bestdiv = DIV_ROUND_UP(parent_rate, rate); |
74 | bestdiv = bestdiv == 0 ? 1 : bestdiv; | 73 | bestdiv = bestdiv == 0 ? 1 : bestdiv; |
75 | bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; | 74 | bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; |
@@ -109,24 +108,18 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, | |||
109 | int div; | 108 | int div; |
110 | div = clk_divider_bestdiv(hw, rate, prate); | 109 | div = clk_divider_bestdiv(hw, rate, prate); |
111 | 110 | ||
112 | if (prate) | 111 | return *prate / div; |
113 | return *prate / div; | ||
114 | else { | ||
115 | unsigned long r; | ||
116 | r = __clk_get_rate(__clk_get_parent(hw->clk)); | ||
117 | return r / div; | ||
118 | } | ||
119 | } | 112 | } |
120 | EXPORT_SYMBOL_GPL(clk_divider_round_rate); | ||
121 | 113 | ||
122 | static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate) | 114 | static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, |
115 | unsigned long parent_rate) | ||
123 | { | 116 | { |
124 | struct clk_divider *divider = to_clk_divider(hw); | 117 | struct clk_divider *divider = to_clk_divider(hw); |
125 | unsigned int div; | 118 | unsigned int div; |
126 | unsigned long flags = 0; | 119 | unsigned long flags = 0; |
127 | u32 val; | 120 | u32 val; |
128 | 121 | ||
129 | div = __clk_get_rate(__clk_get_parent(hw->clk)) / rate; | 122 | div = parent_rate / rate; |
130 | 123 | ||
131 | if (!(divider->flags & CLK_DIVIDER_ONE_BASED)) | 124 | if (!(divider->flags & CLK_DIVIDER_ONE_BASED)) |
132 | div--; | 125 | div--; |
@@ -147,15 +140,26 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate) | |||
147 | 140 | ||
148 | return 0; | 141 | return 0; |
149 | } | 142 | } |
150 | EXPORT_SYMBOL_GPL(clk_divider_set_rate); | ||
151 | 143 | ||
152 | struct clk_ops clk_divider_ops = { | 144 | const struct clk_ops clk_divider_ops = { |
153 | .recalc_rate = clk_divider_recalc_rate, | 145 | .recalc_rate = clk_divider_recalc_rate, |
154 | .round_rate = clk_divider_round_rate, | 146 | .round_rate = clk_divider_round_rate, |
155 | .set_rate = clk_divider_set_rate, | 147 | .set_rate = clk_divider_set_rate, |
156 | }; | 148 | }; |
157 | EXPORT_SYMBOL_GPL(clk_divider_ops); | 149 | EXPORT_SYMBOL_GPL(clk_divider_ops); |
158 | 150 | ||
151 | /** | ||
152 | * clk_register_divider - register a divider clock with the clock framework | ||
153 | * @dev: device registering this clock | ||
154 | * @name: name of this clock | ||
155 | * @parent_name: name of clock's parent | ||
156 | * @flags: framework-specific flags | ||
157 | * @reg: register address to adjust divider | ||
158 | * @shift: number of bits to shift the bitfield | ||
159 | * @width: width of the bitfield | ||
160 | * @clk_divider_flags: divider-specific flags for this clock | ||
161 | * @lock: shared register lock for this clock | ||
162 | */ | ||
159 | struct clk *clk_register_divider(struct device *dev, const char *name, | 163 | struct clk *clk_register_divider(struct device *dev, const char *name, |
160 | const char *parent_name, unsigned long flags, | 164 | const char *parent_name, unsigned long flags, |
161 | void __iomem *reg, u8 shift, u8 width, | 165 | void __iomem *reg, u8 shift, u8 width, |
@@ -163,38 +167,34 @@ struct clk *clk_register_divider(struct device *dev, const char *name, | |||
163 | { | 167 | { |
164 | struct clk_divider *div; | 168 | struct clk_divider *div; |
165 | struct clk *clk; | 169 | struct clk *clk; |
170 | struct clk_init_data init; | ||
166 | 171 | ||
172 | /* allocate the divider */ | ||
167 | div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL); | 173 | div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL); |
168 | |||
169 | if (!div) { | 174 | if (!div) { |
170 | pr_err("%s: could not allocate divider clk\n", __func__); | 175 | pr_err("%s: could not allocate divider clk\n", __func__); |
171 | return NULL; | 176 | return ERR_PTR(-ENOMEM); |
172 | } | 177 | } |
173 | 178 | ||
179 | init.name = name; | ||
180 | init.ops = &clk_divider_ops; | ||
181 | init.flags = flags; | ||
182 | init.parent_names = (parent_name ? &parent_name: NULL); | ||
183 | init.num_parents = (parent_name ? 1 : 0); | ||
184 | |||
174 | /* struct clk_divider assignments */ | 185 | /* struct clk_divider assignments */ |
175 | div->reg = reg; | 186 | div->reg = reg; |
176 | div->shift = shift; | 187 | div->shift = shift; |
177 | div->width = width; | 188 | div->width = width; |
178 | div->flags = clk_divider_flags; | 189 | div->flags = clk_divider_flags; |
179 | div->lock = lock; | 190 | div->lock = lock; |
191 | div->hw.init = &init; | ||
180 | 192 | ||
181 | if (parent_name) { | 193 | /* register the clock */ |
182 | div->parent[0] = kstrdup(parent_name, GFP_KERNEL); | 194 | clk = clk_register(dev, &div->hw); |
183 | if (!div->parent[0]) | ||
184 | goto out; | ||
185 | } | ||
186 | |||
187 | clk = clk_register(dev, name, | ||
188 | &clk_divider_ops, &div->hw, | ||
189 | div->parent, | ||
190 | (parent_name ? 1 : 0), | ||
191 | flags); | ||
192 | if (clk) | ||
193 | return clk; | ||
194 | 195 | ||
195 | out: | 196 | if (IS_ERR(clk)) |
196 | kfree(div->parent[0]); | 197 | kfree(div); |
197 | kfree(div); | ||
198 | 198 | ||
199 | return NULL; | 199 | return clk; |
200 | } | 200 | } |
diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c new file mode 100644 index 00000000000..c8c003e217a --- /dev/null +++ b/drivers/clk/clk-fixed-factor.c | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Standard functionality for the common clock API. | ||
9 | */ | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/clk-provider.h> | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/err.h> | ||
14 | |||
15 | /* | ||
16 | * DOC: basic fixed multiplier and divider clock that cannot gate | ||
17 | * | ||
18 | * Traits of this clock: | ||
19 | * prepare - clk_prepare only ensures that parents are prepared | ||
20 | * enable - clk_enable only ensures that parents are enabled | ||
21 | * rate - rate is fixed. clk->rate = parent->rate / div * mult | ||
22 | * parent - fixed parent. No clk_set_parent support | ||
23 | */ | ||
24 | |||
25 | #define to_clk_fixed_factor(_hw) container_of(_hw, struct clk_fixed_factor, hw) | ||
26 | |||
27 | static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, | ||
28 | unsigned long parent_rate) | ||
29 | { | ||
30 | struct clk_fixed_factor *fix = to_clk_fixed_factor(hw); | ||
31 | |||
32 | return parent_rate * fix->mult / fix->div; | ||
33 | } | ||
34 | |||
35 | static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate, | ||
36 | unsigned long *prate) | ||
37 | { | ||
38 | struct clk_fixed_factor *fix = to_clk_fixed_factor(hw); | ||
39 | |||
40 | if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) { | ||
41 | unsigned long best_parent; | ||
42 | |||
43 | best_parent = (rate / fix->mult) * fix->div; | ||
44 | *prate = __clk_round_rate(__clk_get_parent(hw->clk), | ||
45 | best_parent); | ||
46 | } | ||
47 | |||
48 | return (*prate / fix->div) * fix->mult; | ||
49 | } | ||
50 | |||
51 | static int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate, | ||
52 | unsigned long parent_rate) | ||
53 | { | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | struct clk_ops clk_fixed_factor_ops = { | ||
58 | .round_rate = clk_factor_round_rate, | ||
59 | .set_rate = clk_factor_set_rate, | ||
60 | .recalc_rate = clk_factor_recalc_rate, | ||
61 | }; | ||
62 | EXPORT_SYMBOL_GPL(clk_fixed_factor_ops); | ||
63 | |||
64 | struct clk *clk_register_fixed_factor(struct device *dev, const char *name, | ||
65 | const char *parent_name, unsigned long flags, | ||
66 | unsigned int mult, unsigned int div) | ||
67 | { | ||
68 | struct clk_fixed_factor *fix; | ||
69 | struct clk_init_data init; | ||
70 | struct clk *clk; | ||
71 | |||
72 | fix = kmalloc(sizeof(*fix), GFP_KERNEL); | ||
73 | if (!fix) { | ||
74 | pr_err("%s: could not allocate fixed factor clk\n", __func__); | ||
75 | return ERR_PTR(-ENOMEM); | ||
76 | } | ||
77 | |||
78 | /* struct clk_fixed_factor assignments */ | ||
79 | fix->mult = mult; | ||
80 | fix->div = div; | ||
81 | fix->hw.init = &init; | ||
82 | |||
83 | init.name = name; | ||
84 | init.ops = &clk_fixed_factor_ops; | ||
85 | init.flags = flags; | ||
86 | init.parent_names = &parent_name; | ||
87 | init.num_parents = 1; | ||
88 | |||
89 | clk = clk_register(dev, &fix->hw); | ||
90 | |||
91 | if (IS_ERR(clk)) | ||
92 | kfree(fix); | ||
93 | |||
94 | return clk; | ||
95 | } | ||
diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c index 90c79fb5d1b..cbd24622978 100644 --- a/drivers/clk/clk-fixed-rate.c +++ b/drivers/clk/clk-fixed-rate.c | |||
@@ -32,51 +32,50 @@ static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw, | |||
32 | { | 32 | { |
33 | return to_clk_fixed_rate(hw)->fixed_rate; | 33 | return to_clk_fixed_rate(hw)->fixed_rate; |
34 | } | 34 | } |
35 | EXPORT_SYMBOL_GPL(clk_fixed_rate_recalc_rate); | ||
36 | 35 | ||
37 | struct clk_ops clk_fixed_rate_ops = { | 36 | const struct clk_ops clk_fixed_rate_ops = { |
38 | .recalc_rate = clk_fixed_rate_recalc_rate, | 37 | .recalc_rate = clk_fixed_rate_recalc_rate, |
39 | }; | 38 | }; |
40 | EXPORT_SYMBOL_GPL(clk_fixed_rate_ops); | 39 | EXPORT_SYMBOL_GPL(clk_fixed_rate_ops); |
41 | 40 | ||
41 | /** | ||
42 | * clk_register_fixed_rate - register fixed-rate clock with the clock framework | ||
43 | * @dev: device that is registering this clock | ||
44 | * @name: name of this clock | ||
45 | * @parent_name: name of clock's parent | ||
46 | * @flags: framework-specific flags | ||
47 | * @fixed_rate: non-adjustable clock rate | ||
48 | */ | ||
42 | struct clk *clk_register_fixed_rate(struct device *dev, const char *name, | 49 | struct clk *clk_register_fixed_rate(struct device *dev, const char *name, |
43 | const char *parent_name, unsigned long flags, | 50 | const char *parent_name, unsigned long flags, |
44 | unsigned long fixed_rate) | 51 | unsigned long fixed_rate) |
45 | { | 52 | { |
46 | struct clk_fixed_rate *fixed; | 53 | struct clk_fixed_rate *fixed; |
47 | char **parent_names = NULL; | 54 | struct clk *clk; |
48 | u8 len; | 55 | struct clk_init_data init; |
49 | 56 | ||
57 | /* allocate fixed-rate clock */ | ||
50 | fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL); | 58 | fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL); |
51 | |||
52 | if (!fixed) { | 59 | if (!fixed) { |
53 | pr_err("%s: could not allocate fixed clk\n", __func__); | 60 | pr_err("%s: could not allocate fixed clk\n", __func__); |
54 | return ERR_PTR(-ENOMEM); | 61 | return ERR_PTR(-ENOMEM); |
55 | } | 62 | } |
56 | 63 | ||
64 | init.name = name; | ||
65 | init.ops = &clk_fixed_rate_ops; | ||
66 | init.flags = flags; | ||
67 | init.parent_names = (parent_name ? &parent_name: NULL); | ||
68 | init.num_parents = (parent_name ? 1 : 0); | ||
69 | |||
57 | /* struct clk_fixed_rate assignments */ | 70 | /* struct clk_fixed_rate assignments */ |
58 | fixed->fixed_rate = fixed_rate; | 71 | fixed->fixed_rate = fixed_rate; |
72 | fixed->hw.init = &init; | ||
59 | 73 | ||
60 | if (parent_name) { | 74 | /* register the clock */ |
61 | parent_names = kmalloc(sizeof(char *), GFP_KERNEL); | 75 | clk = clk_register(dev, &fixed->hw); |
62 | |||
63 | if (! parent_names) | ||
64 | goto out; | ||
65 | 76 | ||
66 | len = sizeof(char) * strlen(parent_name); | 77 | if (IS_ERR(clk)) |
67 | 78 | kfree(fixed); | |
68 | parent_names[0] = kmalloc(len, GFP_KERNEL); | ||
69 | |||
70 | if (!parent_names[0]) | ||
71 | goto out; | ||
72 | |||
73 | strncpy(parent_names[0], parent_name, len); | ||
74 | } | ||
75 | 79 | ||
76 | out: | 80 | return clk; |
77 | return clk_register(dev, name, | ||
78 | &clk_fixed_rate_ops, &fixed->hw, | ||
79 | parent_names, | ||
80 | (parent_name ? 1 : 0), | ||
81 | flags); | ||
82 | } | 81 | } |
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c index b5902e2ef2f..578465e04be 100644 --- a/drivers/clk/clk-gate.c +++ b/drivers/clk/clk-gate.c | |||
@@ -28,32 +28,38 @@ | |||
28 | 28 | ||
29 | #define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) | 29 | #define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) |
30 | 30 | ||
31 | static void clk_gate_set_bit(struct clk_gate *gate) | 31 | /* |
32 | * It works on following logic: | ||
33 | * | ||
34 | * For enabling clock, enable = 1 | ||
35 | * set2dis = 1 -> clear bit -> set = 0 | ||
36 | * set2dis = 0 -> set bit -> set = 1 | ||
37 | * | ||
38 | * For disabling clock, enable = 0 | ||
39 | * set2dis = 1 -> set bit -> set = 1 | ||
40 | * set2dis = 0 -> clear bit -> set = 0 | ||
41 | * | ||
42 | * So, result is always: enable xor set2dis. | ||
43 | */ | ||
44 | static void clk_gate_endisable(struct clk_hw *hw, int enable) | ||
32 | { | 45 | { |
33 | u32 reg; | 46 | struct clk_gate *gate = to_clk_gate(hw); |
47 | int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0; | ||
34 | unsigned long flags = 0; | 48 | unsigned long flags = 0; |
49 | u32 reg; | ||
50 | |||
51 | set ^= enable; | ||
35 | 52 | ||
36 | if (gate->lock) | 53 | if (gate->lock) |
37 | spin_lock_irqsave(gate->lock, flags); | 54 | spin_lock_irqsave(gate->lock, flags); |
38 | 55 | ||
39 | reg = readl(gate->reg); | 56 | reg = readl(gate->reg); |
40 | reg |= BIT(gate->bit_idx); | ||
41 | writel(reg, gate->reg); | ||
42 | |||
43 | if (gate->lock) | ||
44 | spin_unlock_irqrestore(gate->lock, flags); | ||
45 | } | ||
46 | |||
47 | static void clk_gate_clear_bit(struct clk_gate *gate) | ||
48 | { | ||
49 | u32 reg; | ||
50 | unsigned long flags = 0; | ||
51 | 57 | ||
52 | if (gate->lock) | 58 | if (set) |
53 | spin_lock_irqsave(gate->lock, flags); | 59 | reg |= BIT(gate->bit_idx); |
60 | else | ||
61 | reg &= ~BIT(gate->bit_idx); | ||
54 | 62 | ||
55 | reg = readl(gate->reg); | ||
56 | reg &= ~BIT(gate->bit_idx); | ||
57 | writel(reg, gate->reg); | 63 | writel(reg, gate->reg); |
58 | 64 | ||
59 | if (gate->lock) | 65 | if (gate->lock) |
@@ -62,27 +68,15 @@ static void clk_gate_clear_bit(struct clk_gate *gate) | |||
62 | 68 | ||
63 | static int clk_gate_enable(struct clk_hw *hw) | 69 | static int clk_gate_enable(struct clk_hw *hw) |
64 | { | 70 | { |
65 | struct clk_gate *gate = to_clk_gate(hw); | 71 | clk_gate_endisable(hw, 1); |
66 | |||
67 | if (gate->flags & CLK_GATE_SET_TO_DISABLE) | ||
68 | clk_gate_clear_bit(gate); | ||
69 | else | ||
70 | clk_gate_set_bit(gate); | ||
71 | 72 | ||
72 | return 0; | 73 | return 0; |
73 | } | 74 | } |
74 | EXPORT_SYMBOL_GPL(clk_gate_enable); | ||
75 | 75 | ||
76 | static void clk_gate_disable(struct clk_hw *hw) | 76 | static void clk_gate_disable(struct clk_hw *hw) |
77 | { | 77 | { |
78 | struct clk_gate *gate = to_clk_gate(hw); | 78 | clk_gate_endisable(hw, 0); |
79 | |||
80 | if (gate->flags & CLK_GATE_SET_TO_DISABLE) | ||
81 | clk_gate_set_bit(gate); | ||
82 | else | ||
83 | clk_gate_clear_bit(gate); | ||
84 | } | 79 | } |
85 | EXPORT_SYMBOL_GPL(clk_gate_disable); | ||
86 | 80 | ||
87 | static int clk_gate_is_enabled(struct clk_hw *hw) | 81 | static int clk_gate_is_enabled(struct clk_hw *hw) |
88 | { | 82 | { |
@@ -99,15 +93,25 @@ static int clk_gate_is_enabled(struct clk_hw *hw) | |||
99 | 93 | ||
100 | return reg ? 1 : 0; | 94 | return reg ? 1 : 0; |
101 | } | 95 | } |
102 | EXPORT_SYMBOL_GPL(clk_gate_is_enabled); | ||
103 | 96 | ||
104 | struct clk_ops clk_gate_ops = { | 97 | const struct clk_ops clk_gate_ops = { |
105 | .enable = clk_gate_enable, | 98 | .enable = clk_gate_enable, |
106 | .disable = clk_gate_disable, | 99 | .disable = clk_gate_disable, |
107 | .is_enabled = clk_gate_is_enabled, | 100 | .is_enabled = clk_gate_is_enabled, |
108 | }; | 101 | }; |
109 | EXPORT_SYMBOL_GPL(clk_gate_ops); | 102 | EXPORT_SYMBOL_GPL(clk_gate_ops); |
110 | 103 | ||
104 | /** | ||
105 | * clk_register_gate - register a gate clock with the clock framework | ||
106 | * @dev: device that is registering this clock | ||
107 | * @name: name of this clock | ||
108 | * @parent_name: name of this clock's parent | ||
109 | * @flags: framework-specific flags for this clock | ||
110 | * @reg: register address to control gating of this clock | ||
111 | * @bit_idx: which bit in the register controls gating of this clock | ||
112 | * @clk_gate_flags: gate-specific flags for this clock | ||
113 | * @lock: shared register lock for this clock | ||
114 | */ | ||
111 | struct clk *clk_register_gate(struct device *dev, const char *name, | 115 | struct clk *clk_register_gate(struct device *dev, const char *name, |
112 | const char *parent_name, unsigned long flags, | 116 | const char *parent_name, unsigned long flags, |
113 | void __iomem *reg, u8 bit_idx, | 117 | void __iomem *reg, u8 bit_idx, |
@@ -115,36 +119,32 @@ struct clk *clk_register_gate(struct device *dev, const char *name, | |||
115 | { | 119 | { |
116 | struct clk_gate *gate; | 120 | struct clk_gate *gate; |
117 | struct clk *clk; | 121 | struct clk *clk; |
122 | struct clk_init_data init; | ||
118 | 123 | ||
124 | /* allocate the gate */ | ||
119 | gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); | 125 | gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); |
120 | |||
121 | if (!gate) { | 126 | if (!gate) { |
122 | pr_err("%s: could not allocate gated clk\n", __func__); | 127 | pr_err("%s: could not allocate gated clk\n", __func__); |
123 | return NULL; | 128 | return ERR_PTR(-ENOMEM); |
124 | } | 129 | } |
125 | 130 | ||
131 | init.name = name; | ||
132 | init.ops = &clk_gate_ops; | ||
133 | init.flags = flags; | ||
134 | init.parent_names = (parent_name ? &parent_name: NULL); | ||
135 | init.num_parents = (parent_name ? 1 : 0); | ||
136 | |||
126 | /* struct clk_gate assignments */ | 137 | /* struct clk_gate assignments */ |
127 | gate->reg = reg; | 138 | gate->reg = reg; |
128 | gate->bit_idx = bit_idx; | 139 | gate->bit_idx = bit_idx; |
129 | gate->flags = clk_gate_flags; | 140 | gate->flags = clk_gate_flags; |
130 | gate->lock = lock; | 141 | gate->lock = lock; |
142 | gate->hw.init = &init; | ||
131 | 143 | ||
132 | if (parent_name) { | 144 | clk = clk_register(dev, &gate->hw); |
133 | gate->parent[0] = kstrdup(parent_name, GFP_KERNEL); | 145 | |
134 | if (!gate->parent[0]) | 146 | if (IS_ERR(clk)) |
135 | goto out; | 147 | kfree(gate); |
136 | } | ||
137 | 148 | ||
138 | clk = clk_register(dev, name, | 149 | return clk; |
139 | &clk_gate_ops, &gate->hw, | ||
140 | gate->parent, | ||
141 | (parent_name ? 1 : 0), | ||
142 | flags); | ||
143 | if (clk) | ||
144 | return clk; | ||
145 | out: | ||
146 | kfree(gate->parent[0]); | ||
147 | kfree(gate); | ||
148 | |||
149 | return NULL; | ||
150 | } | 150 | } |
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index c71ad1f41a9..fd36a8ea73d 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c | |||
@@ -55,7 +55,6 @@ static u8 clk_mux_get_parent(struct clk_hw *hw) | |||
55 | 55 | ||
56 | return val; | 56 | return val; |
57 | } | 57 | } |
58 | EXPORT_SYMBOL_GPL(clk_mux_get_parent); | ||
59 | 58 | ||
60 | static int clk_mux_set_parent(struct clk_hw *hw, u8 index) | 59 | static int clk_mux_set_parent(struct clk_hw *hw, u8 index) |
61 | { | 60 | { |
@@ -82,35 +81,47 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index) | |||
82 | 81 | ||
83 | return 0; | 82 | return 0; |
84 | } | 83 | } |
85 | EXPORT_SYMBOL_GPL(clk_mux_set_parent); | ||
86 | 84 | ||
87 | struct clk_ops clk_mux_ops = { | 85 | const struct clk_ops clk_mux_ops = { |
88 | .get_parent = clk_mux_get_parent, | 86 | .get_parent = clk_mux_get_parent, |
89 | .set_parent = clk_mux_set_parent, | 87 | .set_parent = clk_mux_set_parent, |
90 | }; | 88 | }; |
91 | EXPORT_SYMBOL_GPL(clk_mux_ops); | 89 | EXPORT_SYMBOL_GPL(clk_mux_ops); |
92 | 90 | ||
93 | struct clk *clk_register_mux(struct device *dev, const char *name, | 91 | struct clk *clk_register_mux(struct device *dev, const char *name, |
94 | char **parent_names, u8 num_parents, unsigned long flags, | 92 | const char **parent_names, u8 num_parents, unsigned long flags, |
95 | void __iomem *reg, u8 shift, u8 width, | 93 | void __iomem *reg, u8 shift, u8 width, |
96 | u8 clk_mux_flags, spinlock_t *lock) | 94 | u8 clk_mux_flags, spinlock_t *lock) |
97 | { | 95 | { |
98 | struct clk_mux *mux; | 96 | struct clk_mux *mux; |
97 | struct clk *clk; | ||
98 | struct clk_init_data init; | ||
99 | 99 | ||
100 | mux = kmalloc(sizeof(struct clk_mux), GFP_KERNEL); | 100 | /* allocate the mux */ |
101 | 101 | mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); | |
102 | if (!mux) { | 102 | if (!mux) { |
103 | pr_err("%s: could not allocate mux clk\n", __func__); | 103 | pr_err("%s: could not allocate mux clk\n", __func__); |
104 | return ERR_PTR(-ENOMEM); | 104 | return ERR_PTR(-ENOMEM); |
105 | } | 105 | } |
106 | 106 | ||
107 | init.name = name; | ||
108 | init.ops = &clk_mux_ops; | ||
109 | init.flags = flags; | ||
110 | init.parent_names = parent_names; | ||
111 | init.num_parents = num_parents; | ||
112 | |||
107 | /* struct clk_mux assignments */ | 113 | /* struct clk_mux assignments */ |
108 | mux->reg = reg; | 114 | mux->reg = reg; |
109 | mux->shift = shift; | 115 | mux->shift = shift; |
110 | mux->width = width; | 116 | mux->width = width; |
111 | mux->flags = clk_mux_flags; | 117 | mux->flags = clk_mux_flags; |
112 | mux->lock = lock; | 118 | mux->lock = lock; |
119 | mux->hw.init = &init; | ||
120 | |||
121 | clk = clk_register(dev, &mux->hw); | ||
122 | |||
123 | if (IS_ERR(clk)) | ||
124 | kfree(mux); | ||
113 | 125 | ||
114 | return clk_register(dev, name, &clk_mux_ops, &mux->hw, | 126 | return clk; |
115 | parent_names, num_parents, flags); | ||
116 | } | 127 | } |
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 9cf6f59e3e1..687b00d67c8 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c | |||
@@ -194,9 +194,8 @@ static int __init clk_debug_init(void) | |||
194 | late_initcall(clk_debug_init); | 194 | late_initcall(clk_debug_init); |
195 | #else | 195 | #else |
196 | static inline int clk_debug_register(struct clk *clk) { return 0; } | 196 | static inline int clk_debug_register(struct clk *clk) { return 0; } |
197 | #endif /* CONFIG_COMMON_CLK_DEBUG */ | 197 | #endif |
198 | 198 | ||
199 | #ifdef CONFIG_COMMON_CLK_DISABLE_UNUSED | ||
200 | /* caller must hold prepare_lock */ | 199 | /* caller must hold prepare_lock */ |
201 | static void clk_disable_unused_subtree(struct clk *clk) | 200 | static void clk_disable_unused_subtree(struct clk *clk) |
202 | { | 201 | { |
@@ -246,9 +245,6 @@ static int clk_disable_unused(void) | |||
246 | return 0; | 245 | return 0; |
247 | } | 246 | } |
248 | late_initcall(clk_disable_unused); | 247 | late_initcall(clk_disable_unused); |
249 | #else | ||
250 | static inline int clk_disable_unused(struct clk *clk) { return 0; } | ||
251 | #endif /* CONFIG_COMMON_CLK_DISABLE_UNUSED */ | ||
252 | 248 | ||
253 | /*** helper functions ***/ | 249 | /*** helper functions ***/ |
254 | 250 | ||
@@ -287,7 +283,7 @@ unsigned long __clk_get_rate(struct clk *clk) | |||
287 | unsigned long ret; | 283 | unsigned long ret; |
288 | 284 | ||
289 | if (!clk) { | 285 | if (!clk) { |
290 | ret = -EINVAL; | 286 | ret = 0; |
291 | goto out; | 287 | goto out; |
292 | } | 288 | } |
293 | 289 | ||
@@ -297,7 +293,7 @@ unsigned long __clk_get_rate(struct clk *clk) | |||
297 | goto out; | 293 | goto out; |
298 | 294 | ||
299 | if (!clk->parent) | 295 | if (!clk->parent) |
300 | ret = -ENODEV; | 296 | ret = 0; |
301 | 297 | ||
302 | out: | 298 | out: |
303 | return ret; | 299 | return ret; |
@@ -562,7 +558,7 @@ EXPORT_SYMBOL_GPL(clk_enable); | |||
562 | * @clk: the clk whose rate is being returned | 558 | * @clk: the clk whose rate is being returned |
563 | * | 559 | * |
564 | * Simply returns the cached rate of the clk. Does not query the hardware. If | 560 | * Simply returns the cached rate of the clk. Does not query the hardware. If |
565 | * clk is NULL then returns -EINVAL. | 561 | * clk is NULL then returns 0. |
566 | */ | 562 | */ |
567 | unsigned long clk_get_rate(struct clk *clk) | 563 | unsigned long clk_get_rate(struct clk *clk) |
568 | { | 564 | { |
@@ -584,18 +580,22 @@ EXPORT_SYMBOL_GPL(clk_get_rate); | |||
584 | */ | 580 | */ |
585 | unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) | 581 | unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) |
586 | { | 582 | { |
587 | unsigned long unused; | 583 | unsigned long parent_rate = 0; |
588 | 584 | ||
589 | if (!clk) | 585 | if (!clk) |
590 | return -EINVAL; | 586 | return -EINVAL; |
591 | 587 | ||
592 | if (!clk->ops->round_rate) | 588 | if (!clk->ops->round_rate) { |
593 | return clk->rate; | 589 | if (clk->flags & CLK_SET_RATE_PARENT) |
590 | return __clk_round_rate(clk->parent, rate); | ||
591 | else | ||
592 | return clk->rate; | ||
593 | } | ||
594 | 594 | ||
595 | if (clk->flags & CLK_SET_RATE_PARENT) | 595 | if (clk->parent) |
596 | return clk->ops->round_rate(clk->hw, rate, &unused); | 596 | parent_rate = clk->parent->rate; |
597 | else | 597 | |
598 | return clk->ops->round_rate(clk->hw, rate, NULL); | 598 | return clk->ops->round_rate(clk->hw, rate, &parent_rate); |
599 | } | 599 | } |
600 | 600 | ||
601 | /** | 601 | /** |
@@ -765,25 +765,41 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate) | |||
765 | static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate) | 765 | static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate) |
766 | { | 766 | { |
767 | struct clk *top = clk; | 767 | struct clk *top = clk; |
768 | unsigned long best_parent_rate = clk->parent->rate; | 768 | unsigned long best_parent_rate = 0; |
769 | unsigned long new_rate; | 769 | unsigned long new_rate; |
770 | 770 | ||
771 | if (!clk->ops->round_rate && !(clk->flags & CLK_SET_RATE_PARENT)) { | 771 | /* sanity */ |
772 | clk->new_rate = clk->rate; | 772 | if (IS_ERR_OR_NULL(clk)) |
773 | return NULL; | ||
774 | |||
775 | /* save parent rate, if it exists */ | ||
776 | if (clk->parent) | ||
777 | best_parent_rate = clk->parent->rate; | ||
778 | |||
779 | /* never propagate up to the parent */ | ||
780 | if (!(clk->flags & CLK_SET_RATE_PARENT)) { | ||
781 | if (!clk->ops->round_rate) { | ||
782 | clk->new_rate = clk->rate; | ||
783 | return NULL; | ||
784 | } | ||
785 | new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate); | ||
786 | goto out; | ||
787 | } | ||
788 | |||
789 | /* need clk->parent from here on out */ | ||
790 | if (!clk->parent) { | ||
791 | pr_debug("%s: %s has NULL parent\n", __func__, clk->name); | ||
773 | return NULL; | 792 | return NULL; |
774 | } | 793 | } |
775 | 794 | ||
776 | if (!clk->ops->round_rate && (clk->flags & CLK_SET_RATE_PARENT)) { | 795 | if (!clk->ops->round_rate) { |
777 | top = clk_calc_new_rates(clk->parent, rate); | 796 | top = clk_calc_new_rates(clk->parent, rate); |
778 | new_rate = clk->new_rate = clk->parent->new_rate; | 797 | new_rate = clk->parent->new_rate; |
779 | 798 | ||
780 | goto out; | 799 | goto out; |
781 | } | 800 | } |
782 | 801 | ||
783 | if (clk->flags & CLK_SET_RATE_PARENT) | 802 | new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate); |
784 | new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate); | ||
785 | else | ||
786 | new_rate = clk->ops->round_rate(clk->hw, rate, NULL); | ||
787 | 803 | ||
788 | if (best_parent_rate != clk->parent->rate) { | 804 | if (best_parent_rate != clk->parent->rate) { |
789 | top = clk_calc_new_rates(clk->parent, best_parent_rate); | 805 | top = clk_calc_new_rates(clk->parent, best_parent_rate); |
@@ -839,7 +855,7 @@ static void clk_change_rate(struct clk *clk) | |||
839 | old_rate = clk->rate; | 855 | old_rate = clk->rate; |
840 | 856 | ||
841 | if (clk->ops->set_rate) | 857 | if (clk->ops->set_rate) |
842 | clk->ops->set_rate(clk->hw, clk->new_rate); | 858 | clk->ops->set_rate(clk->hw, clk->new_rate, clk->parent->rate); |
843 | 859 | ||
844 | if (clk->ops->recalc_rate) | 860 | if (clk->ops->recalc_rate) |
845 | clk->rate = clk->ops->recalc_rate(clk->hw, | 861 | clk->rate = clk->ops->recalc_rate(clk->hw, |
@@ -859,38 +875,19 @@ static void clk_change_rate(struct clk *clk) | |||
859 | * @clk: the clk whose rate is being changed | 875 | * @clk: the clk whose rate is being changed |
860 | * @rate: the new rate for clk | 876 | * @rate: the new rate for clk |
861 | * | 877 | * |
862 | * In the simplest case clk_set_rate will only change the rate of clk. | 878 | * In the simplest case clk_set_rate will only adjust the rate of clk. |
863 | * | ||
864 | * If clk has the CLK_SET_RATE_GATE flag set and it is enabled this call | ||
865 | * will fail; only when the clk is disabled will it be able to change | ||
866 | * its rate. | ||
867 | * | 879 | * |
868 | * Setting the CLK_SET_RATE_PARENT flag allows clk_set_rate to | 880 | * Setting the CLK_SET_RATE_PARENT flag allows the rate change operation to |
869 | * recursively propagate up to clk's parent; whether or not this happens | 881 | * propagate up to clk's parent; whether or not this happens depends on the |
870 | * depends on the outcome of clk's .round_rate implementation. If | 882 | * outcome of clk's .round_rate implementation. If *parent_rate is unchanged |
871 | * *parent_rate is 0 after calling .round_rate then upstream parent | 883 | * after calling .round_rate then upstream parent propagation is ignored. If |
872 | * propagation is ignored. If *parent_rate comes back with a new rate | 884 | * *parent_rate comes back with a new rate for clk's parent then we propagate |
873 | * for clk's parent then we propagate up to clk's parent and set it's | 885 | * up to clk's parent and set it's rate. Upward propagation will continue |
874 | * rate. Upward propagation will continue until either a clk does not | 886 | * until either a clk does not support the CLK_SET_RATE_PARENT flag or |
875 | * support the CLK_SET_RATE_PARENT flag or .round_rate stops requesting | 887 | * .round_rate stops requesting changes to clk's parent_rate. |
876 | * changes to clk's parent_rate. If there is a failure during upstream | ||
877 | * propagation then clk_set_rate will unwind and restore each clk's rate | ||
878 | * that had been successfully changed. Afterwards a rate change abort | ||
879 | * notification will be propagated downstream, starting from the clk | ||
880 | * that failed. | ||
881 | * | 888 | * |
882 | * At the end of all of the rate setting, clk_set_rate internally calls | 889 | * Rate changes are accomplished via tree traversal that also recalculates the |
883 | * __clk_recalc_rates and propagates the rate changes downstream, | 890 | * rates for the clocks and fires off POST_RATE_CHANGE notifiers. |
884 | * starting from the highest clk whose rate was changed. This has the | ||
885 | * added benefit of propagating post-rate change notifiers. | ||
886 | * | ||
887 | * Note that while post-rate change and rate change abort notifications | ||
888 | * are guaranteed to be sent to a clk only once per call to | ||
889 | * clk_set_rate, pre-change notifications will be sent for every clk | ||
890 | * whose rate is changed. Stacking pre-change notifications is noisy | ||
891 | * for the drivers subscribed to them, but this allows drivers to react | ||
892 | * to intermediate clk rate changes up until the point where the final | ||
893 | * rate is achieved at the end of upstream propagation. | ||
894 | * | 891 | * |
895 | * Returns 0 on success, -EERROR otherwise. | 892 | * Returns 0 on success, -EERROR otherwise. |
896 | */ | 893 | */ |
@@ -906,6 +903,11 @@ int clk_set_rate(struct clk *clk, unsigned long rate) | |||
906 | if (rate == clk->rate) | 903 | if (rate == clk->rate) |
907 | goto out; | 904 | goto out; |
908 | 905 | ||
906 | if ((clk->flags & CLK_SET_RATE_GATE) && clk->prepare_count) { | ||
907 | ret = -EBUSY; | ||
908 | goto out; | ||
909 | } | ||
910 | |||
909 | /* calculate new rates and get the topmost changed clock */ | 911 | /* calculate new rates and get the topmost changed clock */ |
910 | top = clk_calc_new_rates(clk, rate); | 912 | top = clk_calc_new_rates(clk, rate); |
911 | if (!top) { | 913 | if (!top) { |
@@ -1175,40 +1177,41 @@ EXPORT_SYMBOL_GPL(clk_set_parent); | |||
1175 | * | 1177 | * |
1176 | * Initializes the lists in struct clk, queries the hardware for the | 1178 | * Initializes the lists in struct clk, queries the hardware for the |
1177 | * parent and rate and sets them both. | 1179 | * parent and rate and sets them both. |
1178 | * | ||
1179 | * Any struct clk passed into __clk_init must have the following members | ||
1180 | * populated: | ||
1181 | * .name | ||
1182 | * .ops | ||
1183 | * .hw | ||
1184 | * .parent_names | ||
1185 | * .num_parents | ||
1186 | * .flags | ||
1187 | * | ||
1188 | * Essentially, everything that would normally be passed into clk_register is | ||
1189 | * assumed to be initialized already in __clk_init. The other members may be | ||
1190 | * populated, but are optional. | ||
1191 | * | ||
1192 | * __clk_init is only exposed via clk-private.h and is intended for use with | ||
1193 | * very large numbers of clocks that need to be statically initialized. It is | ||
1194 | * a layering violation to include clk-private.h from any code which implements | ||
1195 | * a clock's .ops; as such any statically initialized clock data MUST be in a | ||
1196 | * separate C file from the logic that implements it's operations. | ||
1197 | */ | 1180 | */ |
1198 | void __clk_init(struct device *dev, struct clk *clk) | 1181 | int __clk_init(struct device *dev, struct clk *clk) |
1199 | { | 1182 | { |
1200 | int i; | 1183 | int i, ret = 0; |
1201 | struct clk *orphan; | 1184 | struct clk *orphan; |
1202 | struct hlist_node *tmp, *tmp2; | 1185 | struct hlist_node *tmp, *tmp2; |
1203 | 1186 | ||
1204 | if (!clk) | 1187 | if (!clk) |
1205 | return; | 1188 | return -EINVAL; |
1206 | 1189 | ||
1207 | mutex_lock(&prepare_lock); | 1190 | mutex_lock(&prepare_lock); |
1208 | 1191 | ||
1209 | /* check to see if a clock with this name is already registered */ | 1192 | /* check to see if a clock with this name is already registered */ |
1210 | if (__clk_lookup(clk->name)) | 1193 | if (__clk_lookup(clk->name)) { |
1194 | pr_debug("%s: clk %s already initialized\n", | ||
1195 | __func__, clk->name); | ||
1196 | ret = -EEXIST; | ||
1197 | goto out; | ||
1198 | } | ||
1199 | |||
1200 | /* check that clk_ops are sane. See Documentation/clk.txt */ | ||
1201 | if (clk->ops->set_rate && | ||
1202 | !(clk->ops->round_rate && clk->ops->recalc_rate)) { | ||
1203 | pr_warning("%s: %s must implement .round_rate & .recalc_rate\n", | ||
1204 | __func__, clk->name); | ||
1205 | ret = -EINVAL; | ||
1206 | goto out; | ||
1207 | } | ||
1208 | |||
1209 | if (clk->ops->set_parent && !clk->ops->get_parent) { | ||
1210 | pr_warning("%s: %s must implement .get_parent & .set_parent\n", | ||
1211 | __func__, clk->name); | ||
1212 | ret = -EINVAL; | ||
1211 | goto out; | 1213 | goto out; |
1214 | } | ||
1212 | 1215 | ||
1213 | /* throw a WARN if any entries in parent_names are NULL */ | 1216 | /* throw a WARN if any entries in parent_names are NULL */ |
1214 | for (i = 0; i < clk->num_parents; i++) | 1217 | for (i = 0; i < clk->num_parents; i++) |
@@ -1302,48 +1305,130 @@ void __clk_init(struct device *dev, struct clk *clk) | |||
1302 | out: | 1305 | out: |
1303 | mutex_unlock(&prepare_lock); | 1306 | mutex_unlock(&prepare_lock); |
1304 | 1307 | ||
1305 | return; | 1308 | return ret; |
1306 | } | 1309 | } |
1307 | 1310 | ||
1308 | /** | 1311 | /** |
1312 | * __clk_register - register a clock and return a cookie. | ||
1313 | * | ||
1314 | * Same as clk_register, except that the .clk field inside hw shall point to a | ||
1315 | * preallocated (generally statically allocated) struct clk. None of the fields | ||
1316 | * of the struct clk need to be initialized. | ||
1317 | * | ||
1318 | * The data pointed to by .init and .clk field shall NOT be marked as init | ||
1319 | * data. | ||
1320 | * | ||
1321 | * __clk_register is only exposed via clk-private.h and is intended for use with | ||
1322 | * very large numbers of clocks that need to be statically initialized. It is | ||
1323 | * a layering violation to include clk-private.h from any code which implements | ||
1324 | * a clock's .ops; as such any statically initialized clock data MUST be in a | ||
1325 | * separate C file from the logic that implements it's operations. Returns 0 | ||
1326 | * on success, otherwise an error code. | ||
1327 | */ | ||
1328 | struct clk *__clk_register(struct device *dev, struct clk_hw *hw) | ||
1329 | { | ||
1330 | int ret; | ||
1331 | struct clk *clk; | ||
1332 | |||
1333 | clk = hw->clk; | ||
1334 | clk->name = hw->init->name; | ||
1335 | clk->ops = hw->init->ops; | ||
1336 | clk->hw = hw; | ||
1337 | clk->flags = hw->init->flags; | ||
1338 | clk->parent_names = hw->init->parent_names; | ||
1339 | clk->num_parents = hw->init->num_parents; | ||
1340 | |||
1341 | ret = __clk_init(dev, clk); | ||
1342 | if (ret) | ||
1343 | return ERR_PTR(ret); | ||
1344 | |||
1345 | return clk; | ||
1346 | } | ||
1347 | EXPORT_SYMBOL_GPL(__clk_register); | ||
1348 | |||
1349 | /** | ||
1309 | * clk_register - allocate a new clock, register it and return an opaque cookie | 1350 | * clk_register - allocate a new clock, register it and return an opaque cookie |
1310 | * @dev: device that is registering this clock | 1351 | * @dev: device that is registering this clock |
1311 | * @name: clock name | ||
1312 | * @ops: operations this clock supports | ||
1313 | * @hw: link to hardware-specific clock data | 1352 | * @hw: link to hardware-specific clock data |
1314 | * @parent_names: array of string names for all possible parents | ||
1315 | * @num_parents: number of possible parents | ||
1316 | * @flags: framework-level hints and quirks | ||
1317 | * | 1353 | * |
1318 | * clk_register is the primary interface for populating the clock tree with new | 1354 | * clk_register is the primary interface for populating the clock tree with new |
1319 | * clock nodes. It returns a pointer to the newly allocated struct clk which | 1355 | * clock nodes. It returns a pointer to the newly allocated struct clk which |
1320 | * cannot be dereferenced by driver code but may be used in conjuction with the | 1356 | * cannot be dereferenced by driver code but may be used in conjuction with the |
1321 | * rest of the clock API. | 1357 | * rest of the clock API. In the event of an error clk_register will return an |
1358 | * error code; drivers must test for an error code after calling clk_register. | ||
1322 | */ | 1359 | */ |
1323 | struct clk *clk_register(struct device *dev, const char *name, | 1360 | struct clk *clk_register(struct device *dev, struct clk_hw *hw) |
1324 | const struct clk_ops *ops, struct clk_hw *hw, | ||
1325 | char **parent_names, u8 num_parents, unsigned long flags) | ||
1326 | { | 1361 | { |
1362 | int i, ret; | ||
1327 | struct clk *clk; | 1363 | struct clk *clk; |
1328 | 1364 | ||
1329 | clk = kzalloc(sizeof(*clk), GFP_KERNEL); | 1365 | clk = kzalloc(sizeof(*clk), GFP_KERNEL); |
1330 | if (!clk) | 1366 | if (!clk) { |
1331 | return NULL; | 1367 | pr_err("%s: could not allocate clk\n", __func__); |
1368 | ret = -ENOMEM; | ||
1369 | goto fail_out; | ||
1370 | } | ||
1332 | 1371 | ||
1333 | clk->name = name; | 1372 | clk->name = kstrdup(hw->init->name, GFP_KERNEL); |
1334 | clk->ops = ops; | 1373 | if (!clk->name) { |
1374 | pr_err("%s: could not allocate clk->name\n", __func__); | ||
1375 | ret = -ENOMEM; | ||
1376 | goto fail_name; | ||
1377 | } | ||
1378 | clk->ops = hw->init->ops; | ||
1335 | clk->hw = hw; | 1379 | clk->hw = hw; |
1336 | clk->flags = flags; | 1380 | clk->flags = hw->init->flags; |
1337 | clk->parent_names = parent_names; | 1381 | clk->num_parents = hw->init->num_parents; |
1338 | clk->num_parents = num_parents; | ||
1339 | hw->clk = clk; | 1382 | hw->clk = clk; |
1340 | 1383 | ||
1341 | __clk_init(dev, clk); | 1384 | /* allocate local copy in case parent_names is __initdata */ |
1385 | clk->parent_names = kzalloc((sizeof(char*) * clk->num_parents), | ||
1386 | GFP_KERNEL); | ||
1342 | 1387 | ||
1343 | return clk; | 1388 | if (!clk->parent_names) { |
1389 | pr_err("%s: could not allocate clk->parent_names\n", __func__); | ||
1390 | ret = -ENOMEM; | ||
1391 | goto fail_parent_names; | ||
1392 | } | ||
1393 | |||
1394 | |||
1395 | /* copy each string name in case parent_names is __initdata */ | ||
1396 | for (i = 0; i < clk->num_parents; i++) { | ||
1397 | clk->parent_names[i] = kstrdup(hw->init->parent_names[i], | ||
1398 | GFP_KERNEL); | ||
1399 | if (!clk->parent_names[i]) { | ||
1400 | pr_err("%s: could not copy parent_names\n", __func__); | ||
1401 | ret = -ENOMEM; | ||
1402 | goto fail_parent_names_copy; | ||
1403 | } | ||
1404 | } | ||
1405 | |||
1406 | ret = __clk_init(dev, clk); | ||
1407 | if (!ret) | ||
1408 | return clk; | ||
1409 | |||
1410 | fail_parent_names_copy: | ||
1411 | while (--i >= 0) | ||
1412 | kfree(clk->parent_names[i]); | ||
1413 | kfree(clk->parent_names); | ||
1414 | fail_parent_names: | ||
1415 | kfree(clk->name); | ||
1416 | fail_name: | ||
1417 | kfree(clk); | ||
1418 | fail_out: | ||
1419 | return ERR_PTR(ret); | ||
1344 | } | 1420 | } |
1345 | EXPORT_SYMBOL_GPL(clk_register); | 1421 | EXPORT_SYMBOL_GPL(clk_register); |
1346 | 1422 | ||
1423 | /** | ||
1424 | * clk_unregister - unregister a currently registered clock | ||
1425 | * @clk: clock to unregister | ||
1426 | * | ||
1427 | * Currently unimplemented. | ||
1428 | */ | ||
1429 | void clk_unregister(struct clk *clk) {} | ||
1430 | EXPORT_SYMBOL_GPL(clk_unregister); | ||
1431 | |||
1347 | /*** clk rate change notifiers ***/ | 1432 | /*** clk rate change notifiers ***/ |
1348 | 1433 | ||
1349 | /** | 1434 | /** |
diff --git a/drivers/clk/mxs/Makefile b/drivers/clk/mxs/Makefile new file mode 100644 index 00000000000..7bedeec0852 --- /dev/null +++ b/drivers/clk/mxs/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # Makefile for mxs specific clk | ||
3 | # | ||
4 | |||
5 | obj-y += clk.o clk-pll.o clk-ref.o clk-div.o clk-frac.o | ||
6 | |||
7 | obj-$(CONFIG_SOC_IMX23) += clk-imx23.o | ||
8 | obj-$(CONFIG_SOC_IMX28) += clk-imx28.o | ||
diff --git a/drivers/clk/mxs/clk-div.c b/drivers/clk/mxs/clk-div.c new file mode 100644 index 00000000000..90e1da93877 --- /dev/null +++ b/drivers/clk/mxs/clk-div.c | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * The code contained herein is licensed under the GNU General Public | ||
5 | * License. You may obtain a copy of the GNU General Public License | ||
6 | * Version 2 or later at the following locations: | ||
7 | * | ||
8 | * http://www.opensource.org/licenses/gpl-license.html | ||
9 | * http://www.gnu.org/copyleft/gpl.html | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/clk-provider.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include "clk.h" | ||
17 | |||
18 | /** | ||
19 | * struct clk_div - mxs integer divider clock | ||
20 | * @divider: the parent class | ||
21 | * @ops: pointer to clk_ops of parent class | ||
22 | * @reg: register address | ||
23 | * @busy: busy bit shift | ||
24 | * | ||
25 | * The mxs divider clock is a subclass of basic clk_divider with an | ||
26 | * addtional busy bit. | ||
27 | */ | ||
28 | struct clk_div { | ||
29 | struct clk_divider divider; | ||
30 | const struct clk_ops *ops; | ||
31 | void __iomem *reg; | ||
32 | u8 busy; | ||
33 | }; | ||
34 | |||
35 | static inline struct clk_div *to_clk_div(struct clk_hw *hw) | ||
36 | { | ||
37 | struct clk_divider *divider = container_of(hw, struct clk_divider, hw); | ||
38 | |||
39 | return container_of(divider, struct clk_div, divider); | ||
40 | } | ||
41 | |||
42 | static unsigned long clk_div_recalc_rate(struct clk_hw *hw, | ||
43 | unsigned long parent_rate) | ||
44 | { | ||
45 | struct clk_div *div = to_clk_div(hw); | ||
46 | |||
47 | return div->ops->recalc_rate(&div->divider.hw, parent_rate); | ||
48 | } | ||
49 | |||
50 | static long clk_div_round_rate(struct clk_hw *hw, unsigned long rate, | ||
51 | unsigned long *prate) | ||
52 | { | ||
53 | struct clk_div *div = to_clk_div(hw); | ||
54 | |||
55 | return div->ops->round_rate(&div->divider.hw, rate, prate); | ||
56 | } | ||
57 | |||
58 | static int clk_div_set_rate(struct clk_hw *hw, unsigned long rate, | ||
59 | unsigned long parent_rate) | ||
60 | { | ||
61 | struct clk_div *div = to_clk_div(hw); | ||
62 | int ret; | ||
63 | |||
64 | ret = div->ops->set_rate(&div->divider.hw, rate, parent_rate); | ||
65 | if (!ret) | ||
66 | ret = mxs_clk_wait(div->reg, div->busy); | ||
67 | |||
68 | return ret; | ||
69 | } | ||
70 | |||
71 | static struct clk_ops clk_div_ops = { | ||
72 | .recalc_rate = clk_div_recalc_rate, | ||
73 | .round_rate = clk_div_round_rate, | ||
74 | .set_rate = clk_div_set_rate, | ||
75 | }; | ||
76 | |||
77 | struct clk *mxs_clk_div(const char *name, const char *parent_name, | ||
78 | void __iomem *reg, u8 shift, u8 width, u8 busy) | ||
79 | { | ||
80 | struct clk_div *div; | ||
81 | struct clk *clk; | ||
82 | struct clk_init_data init; | ||
83 | |||
84 | div = kzalloc(sizeof(*div), GFP_KERNEL); | ||
85 | if (!div) | ||
86 | return ERR_PTR(-ENOMEM); | ||
87 | |||
88 | init.name = name; | ||
89 | init.ops = &clk_div_ops; | ||
90 | init.flags = CLK_SET_RATE_PARENT; | ||
91 | init.parent_names = (parent_name ? &parent_name: NULL); | ||
92 | init.num_parents = (parent_name ? 1 : 0); | ||
93 | |||
94 | div->reg = reg; | ||
95 | div->busy = busy; | ||
96 | |||
97 | div->divider.reg = reg; | ||
98 | div->divider.shift = shift; | ||
99 | div->divider.width = width; | ||
100 | div->divider.flags = CLK_DIVIDER_ONE_BASED; | ||
101 | div->divider.lock = &mxs_lock; | ||
102 | div->divider.hw.init = &init; | ||
103 | div->ops = &clk_divider_ops; | ||
104 | |||
105 | clk = clk_register(NULL, &div->divider.hw); | ||
106 | if (IS_ERR(clk)) | ||
107 | kfree(div); | ||
108 | |||
109 | return clk; | ||
110 | } | ||
diff --git a/drivers/clk/mxs/clk-frac.c b/drivers/clk/mxs/clk-frac.c new file mode 100644 index 00000000000..e6aa6b567d6 --- /dev/null +++ b/drivers/clk/mxs/clk-frac.c | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * The code contained herein is licensed under the GNU General Public | ||
5 | * License. You may obtain a copy of the GNU General Public License | ||
6 | * Version 2 or later at the following locations: | ||
7 | * | ||
8 | * http://www.opensource.org/licenses/gpl-license.html | ||
9 | * http://www.gnu.org/copyleft/gpl.html | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/clk-provider.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include "clk.h" | ||
18 | |||
19 | /** | ||
20 | * struct clk_frac - mxs fractional divider clock | ||
21 | * @hw: clk_hw for the fractional divider clock | ||
22 | * @reg: register address | ||
23 | * @shift: the divider bit shift | ||
24 | * @width: the divider bit width | ||
25 | * @busy: busy bit shift | ||
26 | * | ||
27 | * The clock is an adjustable fractional divider with a busy bit to wait | ||
28 | * when the divider is adjusted. | ||
29 | */ | ||
30 | struct clk_frac { | ||
31 | struct clk_hw hw; | ||
32 | void __iomem *reg; | ||
33 | u8 shift; | ||
34 | u8 width; | ||
35 | u8 busy; | ||
36 | }; | ||
37 | |||
38 | #define to_clk_frac(_hw) container_of(_hw, struct clk_frac, hw) | ||
39 | |||
40 | static unsigned long clk_frac_recalc_rate(struct clk_hw *hw, | ||
41 | unsigned long parent_rate) | ||
42 | { | ||
43 | struct clk_frac *frac = to_clk_frac(hw); | ||
44 | u32 div; | ||
45 | |||
46 | div = readl_relaxed(frac->reg) >> frac->shift; | ||
47 | div &= (1 << frac->width) - 1; | ||
48 | |||
49 | return (parent_rate >> frac->width) * div; | ||
50 | } | ||
51 | |||
52 | static long clk_frac_round_rate(struct clk_hw *hw, unsigned long rate, | ||
53 | unsigned long *prate) | ||
54 | { | ||
55 | struct clk_frac *frac = to_clk_frac(hw); | ||
56 | unsigned long parent_rate = *prate; | ||
57 | u32 div; | ||
58 | u64 tmp; | ||
59 | |||
60 | if (rate > parent_rate) | ||
61 | return -EINVAL; | ||
62 | |||
63 | tmp = rate; | ||
64 | tmp <<= frac->width; | ||
65 | do_div(tmp, parent_rate); | ||
66 | div = tmp; | ||
67 | |||
68 | if (!div) | ||
69 | return -EINVAL; | ||
70 | |||
71 | return (parent_rate >> frac->width) * div; | ||
72 | } | ||
73 | |||
74 | static int clk_frac_set_rate(struct clk_hw *hw, unsigned long rate, | ||
75 | unsigned long parent_rate) | ||
76 | { | ||
77 | struct clk_frac *frac = to_clk_frac(hw); | ||
78 | unsigned long flags; | ||
79 | u32 div, val; | ||
80 | u64 tmp; | ||
81 | |||
82 | if (rate > parent_rate) | ||
83 | return -EINVAL; | ||
84 | |||
85 | tmp = rate; | ||
86 | tmp <<= frac->width; | ||
87 | do_div(tmp, parent_rate); | ||
88 | div = tmp; | ||
89 | |||
90 | if (!div) | ||
91 | return -EINVAL; | ||
92 | |||
93 | spin_lock_irqsave(&mxs_lock, flags); | ||
94 | |||
95 | val = readl_relaxed(frac->reg); | ||
96 | val &= ~(((1 << frac->width) - 1) << frac->shift); | ||
97 | val |= div << frac->shift; | ||
98 | writel_relaxed(val, frac->reg); | ||
99 | |||
100 | spin_unlock_irqrestore(&mxs_lock, flags); | ||
101 | |||
102 | return mxs_clk_wait(frac->reg, frac->busy); | ||
103 | } | ||
104 | |||
105 | static struct clk_ops clk_frac_ops = { | ||
106 | .recalc_rate = clk_frac_recalc_rate, | ||
107 | .round_rate = clk_frac_round_rate, | ||
108 | .set_rate = clk_frac_set_rate, | ||
109 | }; | ||
110 | |||
111 | struct clk *mxs_clk_frac(const char *name, const char *parent_name, | ||
112 | void __iomem *reg, u8 shift, u8 width, u8 busy) | ||
113 | { | ||
114 | struct clk_frac *frac; | ||
115 | struct clk *clk; | ||
116 | struct clk_init_data init; | ||
117 | |||
118 | frac = kzalloc(sizeof(*frac), GFP_KERNEL); | ||
119 | if (!frac) | ||
120 | return ERR_PTR(-ENOMEM); | ||
121 | |||
122 | init.name = name; | ||
123 | init.ops = &clk_frac_ops; | ||
124 | init.flags = CLK_SET_RATE_PARENT; | ||
125 | init.parent_names = (parent_name ? &parent_name: NULL); | ||
126 | init.num_parents = (parent_name ? 1 : 0); | ||
127 | |||
128 | frac->reg = reg; | ||
129 | frac->shift = shift; | ||
130 | frac->width = width; | ||
131 | frac->busy = busy; | ||
132 | frac->hw.init = &init; | ||
133 | |||
134 | clk = clk_register(NULL, &frac->hw); | ||
135 | if (IS_ERR(clk)) | ||
136 | kfree(frac); | ||
137 | |||
138 | return clk; | ||
139 | } | ||
diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c new file mode 100644 index 00000000000..dcae1128571 --- /dev/null +++ b/drivers/clk/mxs/clk-imx23.c | |||
@@ -0,0 +1,204 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * The code contained herein is licensed under the GNU General Public | ||
5 | * License. You may obtain a copy of the GNU General Public License | ||
6 | * Version 2 or later at the following locations: | ||
7 | * | ||
8 | * http://www.opensource.org/licenses/gpl-license.html | ||
9 | * http://www.gnu.org/copyleft/gpl.html | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/clkdev.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <mach/common.h> | ||
18 | #include <mach/mx23.h> | ||
19 | #include "clk.h" | ||
20 | |||
21 | #define DIGCTRL MX23_IO_ADDRESS(MX23_DIGCTL_BASE_ADDR) | ||
22 | #define CLKCTRL MX23_IO_ADDRESS(MX23_CLKCTRL_BASE_ADDR) | ||
23 | #define PLLCTRL0 (CLKCTRL + 0x0000) | ||
24 | #define CPU (CLKCTRL + 0x0020) | ||
25 | #define HBUS (CLKCTRL + 0x0030) | ||
26 | #define XBUS (CLKCTRL + 0x0040) | ||
27 | #define XTAL (CLKCTRL + 0x0050) | ||
28 | #define PIX (CLKCTRL + 0x0060) | ||
29 | #define SSP (CLKCTRL + 0x0070) | ||
30 | #define GPMI (CLKCTRL + 0x0080) | ||
31 | #define SPDIF (CLKCTRL + 0x0090) | ||
32 | #define EMI (CLKCTRL + 0x00a0) | ||
33 | #define SAIF (CLKCTRL + 0x00c0) | ||
34 | #define TV (CLKCTRL + 0x00d0) | ||
35 | #define ETM (CLKCTRL + 0x00e0) | ||
36 | #define FRAC (CLKCTRL + 0x00f0) | ||
37 | #define CLKSEQ (CLKCTRL + 0x0110) | ||
38 | |||
39 | #define BP_CPU_INTERRUPT_WAIT 12 | ||
40 | #define BP_CLKSEQ_BYPASS_SAIF 0 | ||
41 | #define BP_CLKSEQ_BYPASS_SSP 5 | ||
42 | #define BP_SAIF_DIV_FRAC_EN 16 | ||
43 | #define BP_FRAC_IOFRAC 24 | ||
44 | |||
45 | static void __init clk_misc_init(void) | ||
46 | { | ||
47 | u32 val; | ||
48 | |||
49 | /* Gate off cpu clock in WFI for power saving */ | ||
50 | __mxs_setl(1 << BP_CPU_INTERRUPT_WAIT, CPU); | ||
51 | |||
52 | /* Clear BYPASS for SAIF */ | ||
53 | __mxs_clrl(1 << BP_CLKSEQ_BYPASS_SAIF, CLKSEQ); | ||
54 | |||
55 | /* SAIF has to use frac div for functional operation */ | ||
56 | val = readl_relaxed(SAIF); | ||
57 | val |= 1 << BP_SAIF_DIV_FRAC_EN; | ||
58 | writel_relaxed(val, SAIF); | ||
59 | |||
60 | /* | ||
61 | * Source ssp clock from ref_io than ref_xtal, | ||
62 | * as ref_xtal only provides 24 MHz as maximum. | ||
63 | */ | ||
64 | __mxs_clrl(1 << BP_CLKSEQ_BYPASS_SSP, CLKSEQ); | ||
65 | |||
66 | /* | ||
67 | * 480 MHz seems too high to be ssp clock source directly, | ||
68 | * so set frac to get a 288 MHz ref_io. | ||
69 | */ | ||
70 | __mxs_clrl(0x3f << BP_FRAC_IOFRAC, FRAC); | ||
71 | __mxs_setl(30 << BP_FRAC_IOFRAC, FRAC); | ||
72 | } | ||
73 | |||
74 | static struct clk_lookup uart_lookups[] __initdata = { | ||
75 | { .dev_id = "duart", }, | ||
76 | { .dev_id = "mxs-auart.0", }, | ||
77 | { .dev_id = "mxs-auart.1", }, | ||
78 | { .dev_id = "8006c000.serial", }, | ||
79 | { .dev_id = "8006e000.serial", }, | ||
80 | { .dev_id = "80070000.serial", }, | ||
81 | }; | ||
82 | |||
83 | static struct clk_lookup hbus_lookups[] __initdata = { | ||
84 | { .dev_id = "mxs-dma-apbh", }, | ||
85 | { .dev_id = "80004000.dma-apbh", }, | ||
86 | }; | ||
87 | |||
88 | static struct clk_lookup xbus_lookups[] __initdata = { | ||
89 | { .dev_id = "duart", .con_id = "apb_pclk"}, | ||
90 | { .dev_id = "mxs-dma-apbx", }, | ||
91 | { .dev_id = "80024000.dma-apbx", }, | ||
92 | }; | ||
93 | |||
94 | static struct clk_lookup ssp_lookups[] __initdata = { | ||
95 | { .dev_id = "mxs-mmc.0", }, | ||
96 | { .dev_id = "mxs-mmc.1", }, | ||
97 | { .dev_id = "80010000.ssp", }, | ||
98 | { .dev_id = "80034000.ssp", }, | ||
99 | }; | ||
100 | |||
101 | static struct clk_lookup lcdif_lookups[] __initdata = { | ||
102 | { .dev_id = "imx23-fb", }, | ||
103 | { .dev_id = "80030000.lcdif", }, | ||
104 | }; | ||
105 | |||
106 | static struct clk_lookup gpmi_lookups[] __initdata = { | ||
107 | { .dev_id = "imx23-gpmi-nand", }, | ||
108 | { .dev_id = "8000c000.gpmi", }, | ||
109 | }; | ||
110 | |||
111 | static const char *sel_pll[] __initconst = { "pll", "ref_xtal", }; | ||
112 | static const char *sel_cpu[] __initconst = { "ref_cpu", "ref_xtal", }; | ||
113 | static const char *sel_pix[] __initconst = { "ref_pix", "ref_xtal", }; | ||
114 | static const char *sel_io[] __initconst = { "ref_io", "ref_xtal", }; | ||
115 | static const char *cpu_sels[] __initconst = { "cpu_pll", "cpu_xtal", }; | ||
116 | static const char *emi_sels[] __initconst = { "emi_pll", "emi_xtal", }; | ||
117 | |||
118 | enum imx23_clk { | ||
119 | ref_xtal, pll, ref_cpu, ref_emi, ref_pix, ref_io, saif_sel, | ||
120 | lcdif_sel, gpmi_sel, ssp_sel, emi_sel, cpu, etm_sel, cpu_pll, | ||
121 | cpu_xtal, hbus, xbus, lcdif_div, ssp_div, gpmi_div, emi_pll, | ||
122 | emi_xtal, etm_div, saif_div, clk32k_div, rtc, adc, spdif_div, | ||
123 | clk32k, dri, pwm, filt, uart, ssp, gpmi, spdif, emi, saif, | ||
124 | lcdif, etm, usb, usb_pwr, | ||
125 | clk_max | ||
126 | }; | ||
127 | |||
128 | static struct clk *clks[clk_max]; | ||
129 | |||
130 | static enum imx23_clk clks_init_on[] __initdata = { | ||
131 | cpu, hbus, xbus, emi, uart, | ||
132 | }; | ||
133 | |||
134 | int __init mx23_clocks_init(void) | ||
135 | { | ||
136 | int i; | ||
137 | |||
138 | clk_misc_init(); | ||
139 | |||
140 | clks[ref_xtal] = mxs_clk_fixed("ref_xtal", 24000000); | ||
141 | clks[pll] = mxs_clk_pll("pll", "ref_xtal", PLLCTRL0, 16, 480000000); | ||
142 | clks[ref_cpu] = mxs_clk_ref("ref_cpu", "pll", FRAC, 0); | ||
143 | clks[ref_emi] = mxs_clk_ref("ref_emi", "pll", FRAC, 1); | ||
144 | clks[ref_pix] = mxs_clk_ref("ref_pix", "pll", FRAC, 2); | ||
145 | clks[ref_io] = mxs_clk_ref("ref_io", "pll", FRAC, 3); | ||
146 | clks[saif_sel] = mxs_clk_mux("saif_sel", CLKSEQ, 0, 1, sel_pll, ARRAY_SIZE(sel_pll)); | ||
147 | clks[lcdif_sel] = mxs_clk_mux("lcdif_sel", CLKSEQ, 1, 1, sel_pix, ARRAY_SIZE(sel_pix)); | ||
148 | clks[gpmi_sel] = mxs_clk_mux("gpmi_sel", CLKSEQ, 4, 1, sel_io, ARRAY_SIZE(sel_io)); | ||
149 | clks[ssp_sel] = mxs_clk_mux("ssp_sel", CLKSEQ, 5, 1, sel_io, ARRAY_SIZE(sel_io)); | ||
150 | clks[emi_sel] = mxs_clk_mux("emi_sel", CLKSEQ, 6, 1, emi_sels, ARRAY_SIZE(emi_sels)); | ||
151 | clks[cpu] = mxs_clk_mux("cpu", CLKSEQ, 7, 1, cpu_sels, ARRAY_SIZE(cpu_sels)); | ||
152 | clks[etm_sel] = mxs_clk_mux("etm_sel", CLKSEQ, 8, 1, sel_cpu, ARRAY_SIZE(sel_cpu)); | ||
153 | clks[cpu_pll] = mxs_clk_div("cpu_pll", "ref_cpu", CPU, 0, 6, 28); | ||
154 | clks[cpu_xtal] = mxs_clk_div("cpu_xtal", "ref_xtal", CPU, 16, 10, 29); | ||
155 | clks[hbus] = mxs_clk_div("hbus", "cpu", HBUS, 0, 5, 29); | ||
156 | clks[xbus] = mxs_clk_div("xbus", "ref_xtal", XBUS, 0, 10, 31); | ||
157 | clks[lcdif_div] = mxs_clk_div("lcdif_div", "lcdif_sel", PIX, 0, 12, 29); | ||
158 | clks[ssp_div] = mxs_clk_div("ssp_div", "ssp_sel", SSP, 0, 9, 29); | ||
159 | clks[gpmi_div] = mxs_clk_div("gpmi_div", "gpmi_sel", GPMI, 0, 10, 29); | ||
160 | clks[emi_pll] = mxs_clk_div("emi_pll", "ref_emi", EMI, 0, 6, 28); | ||
161 | clks[emi_xtal] = mxs_clk_div("emi_xtal", "ref_xtal", EMI, 8, 4, 29); | ||
162 | clks[etm_div] = mxs_clk_div("etm_div", "etm_sel", ETM, 0, 6, 29); | ||
163 | clks[saif_div] = mxs_clk_frac("saif_div", "saif_sel", SAIF, 0, 16, 29); | ||
164 | clks[clk32k_div] = mxs_clk_fixed_factor("clk32k_div", "ref_xtal", 1, 750); | ||
165 | clks[rtc] = mxs_clk_fixed_factor("rtc", "ref_xtal", 1, 768); | ||
166 | clks[adc] = mxs_clk_fixed_factor("adc", "clk32k", 1, 16); | ||
167 | clks[spdif_div] = mxs_clk_fixed_factor("spdif_div", "pll", 1, 4); | ||
168 | clks[clk32k] = mxs_clk_gate("clk32k", "clk32k_div", XTAL, 26); | ||
169 | clks[dri] = mxs_clk_gate("dri", "ref_xtal", XTAL, 28); | ||
170 | clks[pwm] = mxs_clk_gate("pwm", "ref_xtal", XTAL, 29); | ||
171 | clks[filt] = mxs_clk_gate("filt", "ref_xtal", XTAL, 30); | ||
172 | clks[uart] = mxs_clk_gate("uart", "ref_xtal", XTAL, 31); | ||
173 | clks[ssp] = mxs_clk_gate("ssp", "ssp_div", SSP, 31); | ||
174 | clks[gpmi] = mxs_clk_gate("gpmi", "gpmi_div", GPMI, 31); | ||
175 | clks[spdif] = mxs_clk_gate("spdif", "spdif_div", SPDIF, 31); | ||
176 | clks[emi] = mxs_clk_gate("emi", "emi_sel", EMI, 31); | ||
177 | clks[saif] = mxs_clk_gate("saif", "saif_div", SAIF, 31); | ||
178 | clks[lcdif] = mxs_clk_gate("lcdif", "lcdif_div", PIX, 31); | ||
179 | clks[etm] = mxs_clk_gate("etm", "etm_div", ETM, 31); | ||
180 | clks[usb] = mxs_clk_gate("usb", "usb_pwr", DIGCTRL, 2); | ||
181 | clks[usb_pwr] = clk_register_gate(NULL, "usb_pwr", "pll", 0, PLLCTRL0, 18, 0, &mxs_lock); | ||
182 | |||
183 | for (i = 0; i < ARRAY_SIZE(clks); i++) | ||
184 | if (IS_ERR(clks[i])) { | ||
185 | pr_err("i.MX23 clk %d: register failed with %ld\n", | ||
186 | i, PTR_ERR(clks[i])); | ||
187 | return PTR_ERR(clks[i]); | ||
188 | } | ||
189 | |||
190 | clk_register_clkdev(clks[clk32k], NULL, "timrot"); | ||
191 | clk_register_clkdevs(clks[hbus], hbus_lookups, ARRAY_SIZE(hbus_lookups)); | ||
192 | clk_register_clkdevs(clks[xbus], xbus_lookups, ARRAY_SIZE(xbus_lookups)); | ||
193 | clk_register_clkdevs(clks[uart], uart_lookups, ARRAY_SIZE(uart_lookups)); | ||
194 | clk_register_clkdevs(clks[ssp], ssp_lookups, ARRAY_SIZE(ssp_lookups)); | ||
195 | clk_register_clkdevs(clks[gpmi], gpmi_lookups, ARRAY_SIZE(gpmi_lookups)); | ||
196 | clk_register_clkdevs(clks[lcdif], lcdif_lookups, ARRAY_SIZE(lcdif_lookups)); | ||
197 | |||
198 | for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) | ||
199 | clk_prepare_enable(clks[clks_init_on[i]]); | ||
200 | |||
201 | mxs_timer_init(MX23_INT_TIMER0); | ||
202 | |||
203 | return 0; | ||
204 | } | ||
diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c new file mode 100644 index 00000000000..b2a3257d4f6 --- /dev/null +++ b/drivers/clk/mxs/clk-imx28.c | |||
@@ -0,0 +1,337 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * The code contained herein is licensed under the GNU General Public | ||
5 | * License. You may obtain a copy of the GNU General Public License | ||
6 | * Version 2 or later at the following locations: | ||
7 | * | ||
8 | * http://www.opensource.org/licenses/gpl-license.html | ||
9 | * http://www.gnu.org/copyleft/gpl.html | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/clkdev.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <mach/common.h> | ||
18 | #include <mach/mx28.h> | ||
19 | #include "clk.h" | ||
20 | |||
21 | #define CLKCTRL MX28_IO_ADDRESS(MX28_CLKCTRL_BASE_ADDR) | ||
22 | #define PLL0CTRL0 (CLKCTRL + 0x0000) | ||
23 | #define PLL1CTRL0 (CLKCTRL + 0x0020) | ||
24 | #define PLL2CTRL0 (CLKCTRL + 0x0040) | ||
25 | #define CPU (CLKCTRL + 0x0050) | ||
26 | #define HBUS (CLKCTRL + 0x0060) | ||
27 | #define XBUS (CLKCTRL + 0x0070) | ||
28 | #define XTAL (CLKCTRL + 0x0080) | ||
29 | #define SSP0 (CLKCTRL + 0x0090) | ||
30 | #define SSP1 (CLKCTRL + 0x00a0) | ||
31 | #define SSP2 (CLKCTRL + 0x00b0) | ||
32 | #define SSP3 (CLKCTRL + 0x00c0) | ||
33 | #define GPMI (CLKCTRL + 0x00d0) | ||
34 | #define SPDIF (CLKCTRL + 0x00e0) | ||
35 | #define EMI (CLKCTRL + 0x00f0) | ||
36 | #define SAIF0 (CLKCTRL + 0x0100) | ||
37 | #define SAIF1 (CLKCTRL + 0x0110) | ||
38 | #define LCDIF (CLKCTRL + 0x0120) | ||
39 | #define ETM (CLKCTRL + 0x0130) | ||
40 | #define ENET (CLKCTRL + 0x0140) | ||
41 | #define FLEXCAN (CLKCTRL + 0x0160) | ||
42 | #define FRAC0 (CLKCTRL + 0x01b0) | ||
43 | #define FRAC1 (CLKCTRL + 0x01c0) | ||
44 | #define CLKSEQ (CLKCTRL + 0x01d0) | ||
45 | |||
46 | #define BP_CPU_INTERRUPT_WAIT 12 | ||
47 | #define BP_SAIF_DIV_FRAC_EN 16 | ||
48 | #define BP_ENET_DIV_TIME 21 | ||
49 | #define BP_ENET_SLEEP 31 | ||
50 | #define BP_CLKSEQ_BYPASS_SAIF0 0 | ||
51 | #define BP_CLKSEQ_BYPASS_SSP0 3 | ||
52 | #define BP_FRAC0_IO1FRAC 16 | ||
53 | #define BP_FRAC0_IO0FRAC 24 | ||
54 | |||
55 | #define DIGCTRL MX28_IO_ADDRESS(MX28_DIGCTL_BASE_ADDR) | ||
56 | #define BP_SAIF_CLKMUX 10 | ||
57 | |||
58 | /* | ||
59 | * HW_SAIF_CLKMUX_SEL: | ||
60 | * DIRECT(0x0): SAIF0 clock pins selected for SAIF0 input clocks, and SAIF1 | ||
61 | * clock pins selected for SAIF1 input clocks. | ||
62 | * CROSSINPUT(0x1): SAIF1 clock inputs selected for SAIF0 input clocks, and | ||
63 | * SAIF0 clock inputs selected for SAIF1 input clocks. | ||
64 | * EXTMSTR0(0x2): SAIF0 clock pin selected for both SAIF0 and SAIF1 input | ||
65 | * clocks. | ||
66 | * EXTMSTR1(0x3): SAIF1 clock pin selected for both SAIF0 and SAIF1 input | ||
67 | * clocks. | ||
68 | */ | ||
69 | int mxs_saif_clkmux_select(unsigned int clkmux) | ||
70 | { | ||
71 | if (clkmux > 0x3) | ||
72 | return -EINVAL; | ||
73 | |||
74 | __mxs_clrl(0x3 << BP_SAIF_CLKMUX, DIGCTRL); | ||
75 | __mxs_setl(clkmux << BP_SAIF_CLKMUX, DIGCTRL); | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static void __init clk_misc_init(void) | ||
81 | { | ||
82 | u32 val; | ||
83 | |||
84 | /* Gate off cpu clock in WFI for power saving */ | ||
85 | __mxs_setl(1 << BP_CPU_INTERRUPT_WAIT, CPU); | ||
86 | |||
87 | /* 0 is a bad default value for a divider */ | ||
88 | __mxs_setl(1 << BP_ENET_DIV_TIME, ENET); | ||
89 | |||
90 | /* Clear BYPASS for SAIF */ | ||
91 | __mxs_clrl(0x3 << BP_CLKSEQ_BYPASS_SAIF0, CLKSEQ); | ||
92 | |||
93 | /* SAIF has to use frac div for functional operation */ | ||
94 | val = readl_relaxed(SAIF0); | ||
95 | val |= 1 << BP_SAIF_DIV_FRAC_EN; | ||
96 | writel_relaxed(val, SAIF0); | ||
97 | |||
98 | val = readl_relaxed(SAIF1); | ||
99 | val |= 1 << BP_SAIF_DIV_FRAC_EN; | ||
100 | writel_relaxed(val, SAIF1); | ||
101 | |||
102 | /* Extra fec clock setting */ | ||
103 | val = readl_relaxed(ENET); | ||
104 | val &= ~(1 << BP_ENET_SLEEP); | ||
105 | writel_relaxed(val, ENET); | ||
106 | |||
107 | /* | ||
108 | * Source ssp clock from ref_io than ref_xtal, | ||
109 | * as ref_xtal only provides 24 MHz as maximum. | ||
110 | */ | ||
111 | __mxs_clrl(0xf << BP_CLKSEQ_BYPASS_SSP0, CLKSEQ); | ||
112 | |||
113 | /* | ||
114 | * 480 MHz seems too high to be ssp clock source directly, | ||
115 | * so set frac0 to get a 288 MHz ref_io0. | ||
116 | */ | ||
117 | val = readl_relaxed(FRAC0); | ||
118 | val &= ~(0x3f << BP_FRAC0_IO0FRAC); | ||
119 | val |= 30 << BP_FRAC0_IO0FRAC; | ||
120 | writel_relaxed(val, FRAC0); | ||
121 | } | ||
122 | |||
123 | static struct clk_lookup uart_lookups[] __initdata = { | ||
124 | { .dev_id = "duart", }, | ||
125 | { .dev_id = "mxs-auart.0", }, | ||
126 | { .dev_id = "mxs-auart.1", }, | ||
127 | { .dev_id = "mxs-auart.2", }, | ||
128 | { .dev_id = "mxs-auart.3", }, | ||
129 | { .dev_id = "mxs-auart.4", }, | ||
130 | { .dev_id = "8006a000.serial", }, | ||
131 | { .dev_id = "8006c000.serial", }, | ||
132 | { .dev_id = "8006e000.serial", }, | ||
133 | { .dev_id = "80070000.serial", }, | ||
134 | { .dev_id = "80072000.serial", }, | ||
135 | { .dev_id = "80074000.serial", }, | ||
136 | }; | ||
137 | |||
138 | static struct clk_lookup hbus_lookups[] __initdata = { | ||
139 | { .dev_id = "mxs-dma-apbh", }, | ||
140 | { .dev_id = "80004000.dma-apbh", }, | ||
141 | }; | ||
142 | |||
143 | static struct clk_lookup xbus_lookups[] __initdata = { | ||
144 | { .dev_id = "duart", .con_id = "apb_pclk"}, | ||
145 | { .dev_id = "mxs-dma-apbx", }, | ||
146 | { .dev_id = "80024000.dma-apbx", }, | ||
147 | }; | ||
148 | |||
149 | static struct clk_lookup ssp0_lookups[] __initdata = { | ||
150 | { .dev_id = "mxs-mmc.0", }, | ||
151 | { .dev_id = "80010000.ssp", }, | ||
152 | }; | ||
153 | |||
154 | static struct clk_lookup ssp1_lookups[] __initdata = { | ||
155 | { .dev_id = "mxs-mmc.1", }, | ||
156 | { .dev_id = "80012000.ssp", }, | ||
157 | }; | ||
158 | |||
159 | static struct clk_lookup ssp2_lookups[] __initdata = { | ||
160 | { .dev_id = "mxs-mmc.2", }, | ||
161 | { .dev_id = "80014000.ssp", }, | ||
162 | }; | ||
163 | |||
164 | static struct clk_lookup ssp3_lookups[] __initdata = { | ||
165 | { .dev_id = "mxs-mmc.3", }, | ||
166 | { .dev_id = "80016000.ssp", }, | ||
167 | }; | ||
168 | |||
169 | static struct clk_lookup lcdif_lookups[] __initdata = { | ||
170 | { .dev_id = "imx28-fb", }, | ||
171 | { .dev_id = "80030000.lcdif", }, | ||
172 | }; | ||
173 | |||
174 | static struct clk_lookup gpmi_lookups[] __initdata = { | ||
175 | { .dev_id = "imx28-gpmi-nand", }, | ||
176 | { .dev_id = "8000c000.gpmi", }, | ||
177 | }; | ||
178 | |||
179 | static struct clk_lookup fec_lookups[] __initdata = { | ||
180 | { .dev_id = "imx28-fec.0", }, | ||
181 | { .dev_id = "imx28-fec.1", }, | ||
182 | { .dev_id = "800f0000.ethernet", }, | ||
183 | { .dev_id = "800f4000.ethernet", }, | ||
184 | }; | ||
185 | |||
186 | static struct clk_lookup can0_lookups[] __initdata = { | ||
187 | { .dev_id = "flexcan.0", }, | ||
188 | { .dev_id = "80032000.can", }, | ||
189 | }; | ||
190 | |||
191 | static struct clk_lookup can1_lookups[] __initdata = { | ||
192 | { .dev_id = "flexcan.1", }, | ||
193 | { .dev_id = "80034000.can", }, | ||
194 | }; | ||
195 | |||
196 | static struct clk_lookup saif0_lookups[] __initdata = { | ||
197 | { .dev_id = "mxs-saif.0", }, | ||
198 | { .dev_id = "80042000.saif", }, | ||
199 | }; | ||
200 | |||
201 | static struct clk_lookup saif1_lookups[] __initdata = { | ||
202 | { .dev_id = "mxs-saif.1", }, | ||
203 | { .dev_id = "80046000.saif", }, | ||
204 | }; | ||
205 | |||
206 | static const char *sel_cpu[] __initconst = { "ref_cpu", "ref_xtal", }; | ||
207 | static const char *sel_io0[] __initconst = { "ref_io0", "ref_xtal", }; | ||
208 | static const char *sel_io1[] __initconst = { "ref_io1", "ref_xtal", }; | ||
209 | static const char *sel_pix[] __initconst = { "ref_pix", "ref_xtal", }; | ||
210 | static const char *sel_gpmi[] __initconst = { "ref_gpmi", "ref_xtal", }; | ||
211 | static const char *sel_pll0[] __initconst = { "pll0", "ref_xtal", }; | ||
212 | static const char *cpu_sels[] __initconst = { "cpu_pll", "cpu_xtal", }; | ||
213 | static const char *emi_sels[] __initconst = { "emi_pll", "emi_xtal", }; | ||
214 | static const char *ptp_sels[] __initconst = { "ref_xtal", "pll0", }; | ||
215 | |||
216 | enum imx28_clk { | ||
217 | ref_xtal, pll0, pll1, pll2, ref_cpu, ref_emi, ref_io0, ref_io1, | ||
218 | ref_pix, ref_hsadc, ref_gpmi, saif0_sel, saif1_sel, gpmi_sel, | ||
219 | ssp0_sel, ssp1_sel, ssp2_sel, ssp3_sel, emi_sel, etm_sel, | ||
220 | lcdif_sel, cpu, ptp_sel, cpu_pll, cpu_xtal, hbus, xbus, | ||
221 | ssp0_div, ssp1_div, ssp2_div, ssp3_div, gpmi_div, emi_pll, | ||
222 | emi_xtal, lcdif_div, etm_div, ptp, saif0_div, saif1_div, | ||
223 | clk32k_div, rtc, lradc, spdif_div, clk32k, pwm, uart, ssp0, | ||
224 | ssp1, ssp2, ssp3, gpmi, spdif, emi, saif0, saif1, lcdif, etm, | ||
225 | fec, can0, can1, usb0, usb1, usb0_pwr, usb1_pwr, enet_out, | ||
226 | clk_max | ||
227 | }; | ||
228 | |||
229 | static struct clk *clks[clk_max]; | ||
230 | |||
231 | static enum imx28_clk clks_init_on[] __initdata = { | ||
232 | cpu, hbus, xbus, emi, uart, | ||
233 | }; | ||
234 | |||
235 | int __init mx28_clocks_init(void) | ||
236 | { | ||
237 | int i; | ||
238 | |||
239 | clk_misc_init(); | ||
240 | |||
241 | clks[ref_xtal] = mxs_clk_fixed("ref_xtal", 24000000); | ||
242 | clks[pll0] = mxs_clk_pll("pll0", "ref_xtal", PLL0CTRL0, 17, 480000000); | ||
243 | clks[pll1] = mxs_clk_pll("pll1", "ref_xtal", PLL1CTRL0, 17, 480000000); | ||
244 | clks[pll2] = mxs_clk_pll("pll2", "ref_xtal", PLL2CTRL0, 23, 50000000); | ||
245 | clks[ref_cpu] = mxs_clk_ref("ref_cpu", "pll0", FRAC0, 0); | ||
246 | clks[ref_emi] = mxs_clk_ref("ref_emi", "pll0", FRAC0, 1); | ||
247 | clks[ref_io0] = mxs_clk_ref("ref_io0", "pll0", FRAC0, 2); | ||
248 | clks[ref_io1] = mxs_clk_ref("ref_io1", "pll0", FRAC0, 3); | ||
249 | clks[ref_pix] = mxs_clk_ref("ref_pix", "pll0", FRAC1, 0); | ||
250 | clks[ref_hsadc] = mxs_clk_ref("ref_hsadc", "pll0", FRAC1, 1); | ||
251 | clks[ref_gpmi] = mxs_clk_ref("ref_gpmi", "pll0", FRAC1, 2); | ||
252 | clks[saif0_sel] = mxs_clk_mux("saif0_sel", CLKSEQ, 0, 1, sel_pll0, ARRAY_SIZE(sel_pll0)); | ||
253 | clks[saif1_sel] = mxs_clk_mux("saif1_sel", CLKSEQ, 1, 1, sel_pll0, ARRAY_SIZE(sel_pll0)); | ||
254 | clks[gpmi_sel] = mxs_clk_mux("gpmi_sel", CLKSEQ, 2, 1, sel_gpmi, ARRAY_SIZE(sel_gpmi)); | ||
255 | clks[ssp0_sel] = mxs_clk_mux("ssp0_sel", CLKSEQ, 3, 1, sel_io0, ARRAY_SIZE(sel_io0)); | ||
256 | clks[ssp1_sel] = mxs_clk_mux("ssp1_sel", CLKSEQ, 4, 1, sel_io0, ARRAY_SIZE(sel_io0)); | ||
257 | clks[ssp2_sel] = mxs_clk_mux("ssp2_sel", CLKSEQ, 5, 1, sel_io1, ARRAY_SIZE(sel_io1)); | ||
258 | clks[ssp3_sel] = mxs_clk_mux("ssp3_sel", CLKSEQ, 6, 1, sel_io1, ARRAY_SIZE(sel_io1)); | ||
259 | clks[emi_sel] = mxs_clk_mux("emi_sel", CLKSEQ, 7, 1, emi_sels, ARRAY_SIZE(emi_sels)); | ||
260 | clks[etm_sel] = mxs_clk_mux("etm_sel", CLKSEQ, 8, 1, sel_cpu, ARRAY_SIZE(sel_cpu)); | ||
261 | clks[lcdif_sel] = mxs_clk_mux("lcdif_sel", CLKSEQ, 14, 1, sel_pix, ARRAY_SIZE(sel_pix)); | ||
262 | clks[cpu] = mxs_clk_mux("cpu", CLKSEQ, 18, 1, cpu_sels, ARRAY_SIZE(cpu_sels)); | ||
263 | clks[ptp_sel] = mxs_clk_mux("ptp_sel", ENET, 19, 1, ptp_sels, ARRAY_SIZE(ptp_sels)); | ||
264 | clks[cpu_pll] = mxs_clk_div("cpu_pll", "ref_cpu", CPU, 0, 6, 28); | ||
265 | clks[cpu_xtal] = mxs_clk_div("cpu_xtal", "ref_xtal", CPU, 16, 10, 29); | ||
266 | clks[hbus] = mxs_clk_div("hbus", "cpu", HBUS, 0, 5, 31); | ||
267 | clks[xbus] = mxs_clk_div("xbus", "ref_xtal", XBUS, 0, 10, 31); | ||
268 | clks[ssp0_div] = mxs_clk_div("ssp0_div", "ssp0_sel", SSP0, 0, 9, 29); | ||
269 | clks[ssp1_div] = mxs_clk_div("ssp1_div", "ssp1_sel", SSP1, 0, 9, 29); | ||
270 | clks[ssp2_div] = mxs_clk_div("ssp2_div", "ssp2_sel", SSP2, 0, 9, 29); | ||
271 | clks[ssp3_div] = mxs_clk_div("ssp3_div", "ssp3_sel", SSP3, 0, 9, 29); | ||
272 | clks[gpmi_div] = mxs_clk_div("gpmi_div", "gpmi_sel", GPMI, 0, 10, 29); | ||
273 | clks[emi_pll] = mxs_clk_div("emi_pll", "ref_emi", EMI, 0, 6, 28); | ||
274 | clks[emi_xtal] = mxs_clk_div("emi_xtal", "ref_xtal", EMI, 8, 4, 29); | ||
275 | clks[lcdif_div] = mxs_clk_div("lcdif_div", "lcdif_sel", LCDIF, 0, 13, 29); | ||
276 | clks[etm_div] = mxs_clk_div("etm_div", "etm_sel", ETM, 0, 7, 29); | ||
277 | clks[ptp] = mxs_clk_div("ptp", "ptp_sel", ENET, 21, 6, 27); | ||
278 | clks[saif0_div] = mxs_clk_frac("saif0_div", "saif0_sel", SAIF0, 0, 16, 29); | ||
279 | clks[saif1_div] = mxs_clk_frac("saif1_div", "saif1_sel", SAIF1, 0, 16, 29); | ||
280 | clks[clk32k_div] = mxs_clk_fixed_factor("clk32k_div", "ref_xtal", 1, 750); | ||
281 | clks[rtc] = mxs_clk_fixed_factor("rtc", "ref_xtal", 1, 768); | ||
282 | clks[lradc] = mxs_clk_fixed_factor("lradc", "clk32k", 1, 16); | ||
283 | clks[spdif_div] = mxs_clk_fixed_factor("spdif_div", "pll0", 1, 4); | ||
284 | clks[clk32k] = mxs_clk_gate("clk32k", "clk32k_div", XTAL, 26); | ||
285 | clks[pwm] = mxs_clk_gate("pwm", "ref_xtal", XTAL, 29); | ||
286 | clks[uart] = mxs_clk_gate("uart", "ref_xtal", XTAL, 31); | ||
287 | clks[ssp0] = mxs_clk_gate("ssp0", "ssp0_div", SSP0, 31); | ||
288 | clks[ssp1] = mxs_clk_gate("ssp1", "ssp1_div", SSP1, 31); | ||
289 | clks[ssp2] = mxs_clk_gate("ssp2", "ssp2_div", SSP2, 31); | ||
290 | clks[ssp3] = mxs_clk_gate("ssp3", "ssp3_div", SSP3, 31); | ||
291 | clks[gpmi] = mxs_clk_gate("gpmi", "gpmi_div", GPMI, 31); | ||
292 | clks[spdif] = mxs_clk_gate("spdif", "spdif_div", SPDIF, 31); | ||
293 | clks[emi] = mxs_clk_gate("emi", "emi_sel", EMI, 31); | ||
294 | clks[saif0] = mxs_clk_gate("saif0", "saif0_div", SAIF0, 31); | ||
295 | clks[saif1] = mxs_clk_gate("saif1", "saif1_div", SAIF1, 31); | ||
296 | clks[lcdif] = mxs_clk_gate("lcdif", "lcdif_div", LCDIF, 31); | ||
297 | clks[etm] = mxs_clk_gate("etm", "etm_div", ETM, 31); | ||
298 | clks[fec] = mxs_clk_gate("fec", "hbus", ENET, 30); | ||
299 | clks[can0] = mxs_clk_gate("can0", "ref_xtal", FLEXCAN, 30); | ||
300 | clks[can1] = mxs_clk_gate("can1", "ref_xtal", FLEXCAN, 28); | ||
301 | clks[usb0] = mxs_clk_gate("usb0", "usb0_pwr", DIGCTRL, 2); | ||
302 | clks[usb1] = mxs_clk_gate("usb1", "usb1_pwr", DIGCTRL, 16); | ||
303 | clks[usb0_pwr] = clk_register_gate(NULL, "usb0_pwr", "pll0", 0, PLL0CTRL0, 18, 0, &mxs_lock); | ||
304 | clks[usb1_pwr] = clk_register_gate(NULL, "usb1_pwr", "pll1", 0, PLL1CTRL0, 18, 0, &mxs_lock); | ||
305 | clks[enet_out] = clk_register_gate(NULL, "enet_out", "pll2", 0, ENET, 18, 0, &mxs_lock); | ||
306 | |||
307 | for (i = 0; i < ARRAY_SIZE(clks); i++) | ||
308 | if (IS_ERR(clks[i])) { | ||
309 | pr_err("i.MX28 clk %d: register failed with %ld\n", | ||
310 | i, PTR_ERR(clks[i])); | ||
311 | return PTR_ERR(clks[i]); | ||
312 | } | ||
313 | |||
314 | clk_register_clkdev(clks[clk32k], NULL, "timrot"); | ||
315 | clk_register_clkdev(clks[enet_out], NULL, "enet_out"); | ||
316 | clk_register_clkdevs(clks[hbus], hbus_lookups, ARRAY_SIZE(hbus_lookups)); | ||
317 | clk_register_clkdevs(clks[xbus], xbus_lookups, ARRAY_SIZE(xbus_lookups)); | ||
318 | clk_register_clkdevs(clks[uart], uart_lookups, ARRAY_SIZE(uart_lookups)); | ||
319 | clk_register_clkdevs(clks[ssp0], ssp0_lookups, ARRAY_SIZE(ssp0_lookups)); | ||
320 | clk_register_clkdevs(clks[ssp1], ssp1_lookups, ARRAY_SIZE(ssp1_lookups)); | ||
321 | clk_register_clkdevs(clks[ssp2], ssp2_lookups, ARRAY_SIZE(ssp2_lookups)); | ||
322 | clk_register_clkdevs(clks[ssp3], ssp3_lookups, ARRAY_SIZE(ssp3_lookups)); | ||
323 | clk_register_clkdevs(clks[gpmi], gpmi_lookups, ARRAY_SIZE(gpmi_lookups)); | ||
324 | clk_register_clkdevs(clks[saif0], saif0_lookups, ARRAY_SIZE(saif0_lookups)); | ||
325 | clk_register_clkdevs(clks[saif1], saif1_lookups, ARRAY_SIZE(saif1_lookups)); | ||
326 | clk_register_clkdevs(clks[lcdif], lcdif_lookups, ARRAY_SIZE(lcdif_lookups)); | ||
327 | clk_register_clkdevs(clks[fec], fec_lookups, ARRAY_SIZE(fec_lookups)); | ||
328 | clk_register_clkdevs(clks[can0], can0_lookups, ARRAY_SIZE(can0_lookups)); | ||
329 | clk_register_clkdevs(clks[can1], can1_lookups, ARRAY_SIZE(can1_lookups)); | ||
330 | |||
331 | for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) | ||
332 | clk_prepare_enable(clks[clks_init_on[i]]); | ||
333 | |||
334 | mxs_timer_init(MX28_INT_TIMER0); | ||
335 | |||
336 | return 0; | ||
337 | } | ||
diff --git a/drivers/clk/mxs/clk-pll.c b/drivers/clk/mxs/clk-pll.c new file mode 100644 index 00000000000..fadae41833e --- /dev/null +++ b/drivers/clk/mxs/clk-pll.c | |||
@@ -0,0 +1,116 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * The code contained herein is licensed under the GNU General Public | ||
5 | * License. You may obtain a copy of the GNU General Public License | ||
6 | * Version 2 or later at the following locations: | ||
7 | * | ||
8 | * http://www.opensource.org/licenses/gpl-license.html | ||
9 | * http://www.gnu.org/copyleft/gpl.html | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/clk-provider.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include "clk.h" | ||
19 | |||
20 | /** | ||
21 | * struct clk_pll - mxs pll clock | ||
22 | * @hw: clk_hw for the pll | ||
23 | * @base: base address of the pll | ||
24 | * @power: the shift of power bit | ||
25 | * @rate: the clock rate of the pll | ||
26 | * | ||
27 | * The mxs pll is a fixed rate clock with power and gate control, | ||
28 | * and the shift of gate bit is always 31. | ||
29 | */ | ||
30 | struct clk_pll { | ||
31 | struct clk_hw hw; | ||
32 | void __iomem *base; | ||
33 | u8 power; | ||
34 | unsigned long rate; | ||
35 | }; | ||
36 | |||
37 | #define to_clk_pll(_hw) container_of(_hw, struct clk_pll, hw) | ||
38 | |||
39 | static int clk_pll_prepare(struct clk_hw *hw) | ||
40 | { | ||
41 | struct clk_pll *pll = to_clk_pll(hw); | ||
42 | |||
43 | writel_relaxed(1 << pll->power, pll->base + SET); | ||
44 | |||
45 | udelay(10); | ||
46 | |||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static void clk_pll_unprepare(struct clk_hw *hw) | ||
51 | { | ||
52 | struct clk_pll *pll = to_clk_pll(hw); | ||
53 | |||
54 | writel_relaxed(1 << pll->power, pll->base + CLR); | ||
55 | } | ||
56 | |||
57 | static int clk_pll_enable(struct clk_hw *hw) | ||
58 | { | ||
59 | struct clk_pll *pll = to_clk_pll(hw); | ||
60 | |||
61 | writel_relaxed(1 << 31, pll->base + CLR); | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static void clk_pll_disable(struct clk_hw *hw) | ||
67 | { | ||
68 | struct clk_pll *pll = to_clk_pll(hw); | ||
69 | |||
70 | writel_relaxed(1 << 31, pll->base + SET); | ||
71 | } | ||
72 | |||
73 | static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, | ||
74 | unsigned long parent_rate) | ||
75 | { | ||
76 | struct clk_pll *pll = to_clk_pll(hw); | ||
77 | |||
78 | return pll->rate; | ||
79 | } | ||
80 | |||
81 | static const struct clk_ops clk_pll_ops = { | ||
82 | .prepare = clk_pll_prepare, | ||
83 | .unprepare = clk_pll_unprepare, | ||
84 | .enable = clk_pll_enable, | ||
85 | .disable = clk_pll_disable, | ||
86 | .recalc_rate = clk_pll_recalc_rate, | ||
87 | }; | ||
88 | |||
89 | struct clk *mxs_clk_pll(const char *name, const char *parent_name, | ||
90 | void __iomem *base, u8 power, unsigned long rate) | ||
91 | { | ||
92 | struct clk_pll *pll; | ||
93 | struct clk *clk; | ||
94 | struct clk_init_data init; | ||
95 | |||
96 | pll = kzalloc(sizeof(*pll), GFP_KERNEL); | ||
97 | if (!pll) | ||
98 | return ERR_PTR(-ENOMEM); | ||
99 | |||
100 | init.name = name; | ||
101 | init.ops = &clk_pll_ops; | ||
102 | init.flags = 0; | ||
103 | init.parent_names = (parent_name ? &parent_name: NULL); | ||
104 | init.num_parents = (parent_name ? 1 : 0); | ||
105 | |||
106 | pll->base = base; | ||
107 | pll->rate = rate; | ||
108 | pll->power = power; | ||
109 | pll->hw.init = &init; | ||
110 | |||
111 | clk = clk_register(NULL, &pll->hw); | ||
112 | if (IS_ERR(clk)) | ||
113 | kfree(pll); | ||
114 | |||
115 | return clk; | ||
116 | } | ||
diff --git a/drivers/clk/mxs/clk-ref.c b/drivers/clk/mxs/clk-ref.c new file mode 100644 index 00000000000..4adeed6c2f9 --- /dev/null +++ b/drivers/clk/mxs/clk-ref.c | |||
@@ -0,0 +1,154 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * The code contained herein is licensed under the GNU General Public | ||
5 | * License. You may obtain a copy of the GNU General Public License | ||
6 | * Version 2 or later at the following locations: | ||
7 | * | ||
8 | * http://www.opensource.org/licenses/gpl-license.html | ||
9 | * http://www.gnu.org/copyleft/gpl.html | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/clk-provider.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include "clk.h" | ||
18 | |||
19 | /** | ||
20 | * struct clk_ref - mxs reference clock | ||
21 | * @hw: clk_hw for the reference clock | ||
22 | * @reg: register address | ||
23 | * @idx: the index of the reference clock within the same register | ||
24 | * | ||
25 | * The mxs reference clock sources from pll. Every 4 reference clocks share | ||
26 | * one register space, and @idx is used to identify them. Each reference | ||
27 | * clock has a gate control and a fractional * divider. The rate is calculated | ||
28 | * as pll rate * (18 / FRAC), where FRAC = 18 ~ 35. | ||
29 | */ | ||
30 | struct clk_ref { | ||
31 | struct clk_hw hw; | ||
32 | void __iomem *reg; | ||
33 | u8 idx; | ||
34 | }; | ||
35 | |||
36 | #define to_clk_ref(_hw) container_of(_hw, struct clk_ref, hw) | ||
37 | |||
38 | static int clk_ref_enable(struct clk_hw *hw) | ||
39 | { | ||
40 | struct clk_ref *ref = to_clk_ref(hw); | ||
41 | |||
42 | writel_relaxed(1 << ((ref->idx + 1) * 8 - 1), ref->reg + CLR); | ||
43 | |||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | static void clk_ref_disable(struct clk_hw *hw) | ||
48 | { | ||
49 | struct clk_ref *ref = to_clk_ref(hw); | ||
50 | |||
51 | writel_relaxed(1 << ((ref->idx + 1) * 8 - 1), ref->reg + SET); | ||
52 | } | ||
53 | |||
54 | static unsigned long clk_ref_recalc_rate(struct clk_hw *hw, | ||
55 | unsigned long parent_rate) | ||
56 | { | ||
57 | struct clk_ref *ref = to_clk_ref(hw); | ||
58 | u64 tmp = parent_rate; | ||
59 | u8 frac = (readl_relaxed(ref->reg) >> (ref->idx * 8)) & 0x3f; | ||
60 | |||
61 | tmp *= 18; | ||
62 | do_div(tmp, frac); | ||
63 | |||
64 | return tmp; | ||
65 | } | ||
66 | |||
67 | static long clk_ref_round_rate(struct clk_hw *hw, unsigned long rate, | ||
68 | unsigned long *prate) | ||
69 | { | ||
70 | unsigned long parent_rate = *prate; | ||
71 | u64 tmp = parent_rate; | ||
72 | u8 frac; | ||
73 | |||
74 | tmp = tmp * 18 + rate / 2; | ||
75 | do_div(tmp, rate); | ||
76 | frac = tmp; | ||
77 | |||
78 | if (frac < 18) | ||
79 | frac = 18; | ||
80 | else if (frac > 35) | ||
81 | frac = 35; | ||
82 | |||
83 | tmp = parent_rate; | ||
84 | tmp *= 18; | ||
85 | do_div(tmp, frac); | ||
86 | |||
87 | return tmp; | ||
88 | } | ||
89 | |||
90 | static int clk_ref_set_rate(struct clk_hw *hw, unsigned long rate, | ||
91 | unsigned long parent_rate) | ||
92 | { | ||
93 | struct clk_ref *ref = to_clk_ref(hw); | ||
94 | unsigned long flags; | ||
95 | u64 tmp = parent_rate; | ||
96 | u32 val; | ||
97 | u8 frac, shift = ref->idx * 8; | ||
98 | |||
99 | tmp = tmp * 18 + rate / 2; | ||
100 | do_div(tmp, rate); | ||
101 | frac = tmp; | ||
102 | |||
103 | if (frac < 18) | ||
104 | frac = 18; | ||
105 | else if (frac > 35) | ||
106 | frac = 35; | ||
107 | |||
108 | spin_lock_irqsave(&mxs_lock, flags); | ||
109 | |||
110 | val = readl_relaxed(ref->reg); | ||
111 | val &= ~(0x3f << shift); | ||
112 | val |= frac << shift; | ||
113 | writel_relaxed(val, ref->reg); | ||
114 | |||
115 | spin_unlock_irqrestore(&mxs_lock, flags); | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static const struct clk_ops clk_ref_ops = { | ||
121 | .enable = clk_ref_enable, | ||
122 | .disable = clk_ref_disable, | ||
123 | .recalc_rate = clk_ref_recalc_rate, | ||
124 | .round_rate = clk_ref_round_rate, | ||
125 | .set_rate = clk_ref_set_rate, | ||
126 | }; | ||
127 | |||
128 | struct clk *mxs_clk_ref(const char *name, const char *parent_name, | ||
129 | void __iomem *reg, u8 idx) | ||
130 | { | ||
131 | struct clk_ref *ref; | ||
132 | struct clk *clk; | ||
133 | struct clk_init_data init; | ||
134 | |||
135 | ref = kzalloc(sizeof(*ref), GFP_KERNEL); | ||
136 | if (!ref) | ||
137 | return ERR_PTR(-ENOMEM); | ||
138 | |||
139 | init.name = name; | ||
140 | init.ops = &clk_ref_ops; | ||
141 | init.flags = 0; | ||
142 | init.parent_names = (parent_name ? &parent_name: NULL); | ||
143 | init.num_parents = (parent_name ? 1 : 0); | ||
144 | |||
145 | ref->reg = reg; | ||
146 | ref->idx = idx; | ||
147 | ref->hw.init = &init; | ||
148 | |||
149 | clk = clk_register(NULL, &ref->hw); | ||
150 | if (IS_ERR(clk)) | ||
151 | kfree(ref); | ||
152 | |||
153 | return clk; | ||
154 | } | ||
diff --git a/drivers/clk/mxs/clk.c b/drivers/clk/mxs/clk.c new file mode 100644 index 00000000000..b24d56067c8 --- /dev/null +++ b/drivers/clk/mxs/clk.c | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * The code contained herein is licensed under the GNU General Public | ||
5 | * License. You may obtain a copy of the GNU General Public License | ||
6 | * Version 2 or later at the following locations: | ||
7 | * | ||
8 | * http://www.opensource.org/licenses/gpl-license.html | ||
9 | * http://www.gnu.org/copyleft/gpl.html | ||
10 | */ | ||
11 | |||
12 | #include <linux/err.h> | ||
13 | #include <linux/io.h> | ||
14 | #include <linux/jiffies.h> | ||
15 | #include <linux/spinlock.h> | ||
16 | |||
17 | DEFINE_SPINLOCK(mxs_lock); | ||
18 | |||
19 | int mxs_clk_wait(void __iomem *reg, u8 shift) | ||
20 | { | ||
21 | unsigned long timeout = jiffies + msecs_to_jiffies(10); | ||
22 | |||
23 | while (readl_relaxed(reg) & (1 << shift)) | ||
24 | if (time_after(jiffies, timeout)) | ||
25 | return -ETIMEDOUT; | ||
26 | |||
27 | return 0; | ||
28 | } | ||
diff --git a/drivers/clk/mxs/clk.h b/drivers/clk/mxs/clk.h new file mode 100644 index 00000000000..81421e28e69 --- /dev/null +++ b/drivers/clk/mxs/clk.h | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * The code contained herein is licensed under the GNU General Public | ||
5 | * License. You may obtain a copy of the GNU General Public License | ||
6 | * Version 2 or later at the following locations: | ||
7 | * | ||
8 | * http://www.opensource.org/licenses/gpl-license.html | ||
9 | * http://www.gnu.org/copyleft/gpl.html | ||
10 | */ | ||
11 | |||
12 | #ifndef __MXS_CLK_H | ||
13 | #define __MXS_CLK_H | ||
14 | |||
15 | #include <linux/clk.h> | ||
16 | #include <linux/clk-provider.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | |||
19 | #define SET 0x4 | ||
20 | #define CLR 0x8 | ||
21 | |||
22 | extern spinlock_t mxs_lock; | ||
23 | |||
24 | int mxs_clk_wait(void __iomem *reg, u8 shift); | ||
25 | |||
26 | struct clk *mxs_clk_pll(const char *name, const char *parent_name, | ||
27 | void __iomem *base, u8 power, unsigned long rate); | ||
28 | |||
29 | struct clk *mxs_clk_ref(const char *name, const char *parent_name, | ||
30 | void __iomem *reg, u8 idx); | ||
31 | |||
32 | struct clk *mxs_clk_div(const char *name, const char *parent_name, | ||
33 | void __iomem *reg, u8 shift, u8 width, u8 busy); | ||
34 | |||
35 | struct clk *mxs_clk_frac(const char *name, const char *parent_name, | ||
36 | void __iomem *reg, u8 shift, u8 width, u8 busy); | ||
37 | |||
38 | static inline struct clk *mxs_clk_fixed(const char *name, int rate) | ||
39 | { | ||
40 | return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate); | ||
41 | } | ||
42 | |||
43 | static inline struct clk *mxs_clk_gate(const char *name, | ||
44 | const char *parent_name, void __iomem *reg, u8 shift) | ||
45 | { | ||
46 | return clk_register_gate(NULL, name, parent_name, CLK_SET_RATE_PARENT, | ||
47 | reg, shift, CLK_GATE_SET_TO_DISABLE, | ||
48 | &mxs_lock); | ||
49 | } | ||
50 | |||
51 | static inline struct clk *mxs_clk_mux(const char *name, void __iomem *reg, | ||
52 | u8 shift, u8 width, const char **parent_names, int num_parents) | ||
53 | { | ||
54 | return clk_register_mux(NULL, name, parent_names, num_parents, | ||
55 | CLK_SET_RATE_PARENT, reg, shift, width, | ||
56 | 0, &mxs_lock); | ||
57 | } | ||
58 | |||
59 | static inline struct clk *mxs_clk_fixed_factor(const char *name, | ||
60 | const char *parent_name, unsigned int mult, unsigned int div) | ||
61 | { | ||
62 | return clk_register_fixed_factor(NULL, name, parent_name, | ||
63 | CLK_SET_RATE_PARENT, mult, div); | ||
64 | } | ||
65 | |||
66 | #endif /* __MXS_CLK_H */ | ||
diff --git a/drivers/clk/spear/Makefile b/drivers/clk/spear/Makefile new file mode 100644 index 00000000000..335886049c8 --- /dev/null +++ b/drivers/clk/spear/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # SPEAr Clock specific Makefile | ||
3 | # | ||
4 | |||
5 | obj-y += clk.o clk-aux-synth.o clk-frac-synth.o clk-gpt-synth.o clk-vco-pll.o | ||
6 | |||
7 | obj-$(CONFIG_ARCH_SPEAR3XX) += spear3xx_clock.o | ||
8 | obj-$(CONFIG_ARCH_SPEAR6XX) += spear6xx_clock.o | ||
diff --git a/drivers/clk/spear/clk-aux-synth.c b/drivers/clk/spear/clk-aux-synth.c new file mode 100644 index 00000000000..af34074e702 --- /dev/null +++ b/drivers/clk/spear/clk-aux-synth.c | |||
@@ -0,0 +1,198 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 ST Microelectronics | ||
3 | * Viresh Kumar <viresh.kumar@st.com> | ||
4 | * | ||
5 | * This file is licensed under the terms of the GNU General Public | ||
6 | * License version 2. This program is licensed "as is" without any | ||
7 | * warranty of any kind, whether express or implied. | ||
8 | * | ||
9 | * Auxiliary Synthesizer clock implementation | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "clk-aux-synth: " fmt | ||
13 | |||
14 | #include <linux/clk-provider.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/err.h> | ||
18 | #include "clk.h" | ||
19 | |||
20 | /* | ||
21 | * DOC: Auxiliary Synthesizer clock | ||
22 | * | ||
23 | * Aux synth gives rate for different values of eq, x and y | ||
24 | * | ||
25 | * Fout from synthesizer can be given from two equations: | ||
26 | * Fout1 = (Fin * X/Y)/2 EQ1 | ||
27 | * Fout2 = Fin * X/Y EQ2 | ||
28 | */ | ||
29 | |||
30 | #define to_clk_aux(_hw) container_of(_hw, struct clk_aux, hw) | ||
31 | |||
32 | static struct aux_clk_masks default_aux_masks = { | ||
33 | .eq_sel_mask = AUX_EQ_SEL_MASK, | ||
34 | .eq_sel_shift = AUX_EQ_SEL_SHIFT, | ||
35 | .eq1_mask = AUX_EQ1_SEL, | ||
36 | .eq2_mask = AUX_EQ2_SEL, | ||
37 | .xscale_sel_mask = AUX_XSCALE_MASK, | ||
38 | .xscale_sel_shift = AUX_XSCALE_SHIFT, | ||
39 | .yscale_sel_mask = AUX_YSCALE_MASK, | ||
40 | .yscale_sel_shift = AUX_YSCALE_SHIFT, | ||
41 | .enable_bit = AUX_SYNT_ENB, | ||
42 | }; | ||
43 | |||
44 | static unsigned long aux_calc_rate(struct clk_hw *hw, unsigned long prate, | ||
45 | int index) | ||
46 | { | ||
47 | struct clk_aux *aux = to_clk_aux(hw); | ||
48 | struct aux_rate_tbl *rtbl = aux->rtbl; | ||
49 | u8 eq = rtbl[index].eq ? 1 : 2; | ||
50 | |||
51 | return (((prate / 10000) * rtbl[index].xscale) / | ||
52 | (rtbl[index].yscale * eq)) * 10000; | ||
53 | } | ||
54 | |||
55 | static long clk_aux_round_rate(struct clk_hw *hw, unsigned long drate, | ||
56 | unsigned long *prate) | ||
57 | { | ||
58 | struct clk_aux *aux = to_clk_aux(hw); | ||
59 | int unused; | ||
60 | |||
61 | return clk_round_rate_index(hw, drate, *prate, aux_calc_rate, | ||
62 | aux->rtbl_cnt, &unused); | ||
63 | } | ||
64 | |||
65 | static unsigned long clk_aux_recalc_rate(struct clk_hw *hw, | ||
66 | unsigned long parent_rate) | ||
67 | { | ||
68 | struct clk_aux *aux = to_clk_aux(hw); | ||
69 | unsigned int num = 1, den = 1, val, eqn; | ||
70 | unsigned long flags = 0; | ||
71 | |||
72 | if (aux->lock) | ||
73 | spin_lock_irqsave(aux->lock, flags); | ||
74 | |||
75 | val = readl_relaxed(aux->reg); | ||
76 | |||
77 | if (aux->lock) | ||
78 | spin_unlock_irqrestore(aux->lock, flags); | ||
79 | |||
80 | eqn = (val >> aux->masks->eq_sel_shift) & aux->masks->eq_sel_mask; | ||
81 | if (eqn == aux->masks->eq1_mask) | ||
82 | den = 2; | ||
83 | |||
84 | /* calculate numerator */ | ||
85 | num = (val >> aux->masks->xscale_sel_shift) & | ||
86 | aux->masks->xscale_sel_mask; | ||
87 | |||
88 | /* calculate denominator */ | ||
89 | den *= (val >> aux->masks->yscale_sel_shift) & | ||
90 | aux->masks->yscale_sel_mask; | ||
91 | |||
92 | if (!den) | ||
93 | return 0; | ||
94 | |||
95 | return (((parent_rate / 10000) * num) / den) * 10000; | ||
96 | } | ||
97 | |||
98 | /* Configures new clock rate of aux */ | ||
99 | static int clk_aux_set_rate(struct clk_hw *hw, unsigned long drate, | ||
100 | unsigned long prate) | ||
101 | { | ||
102 | struct clk_aux *aux = to_clk_aux(hw); | ||
103 | struct aux_rate_tbl *rtbl = aux->rtbl; | ||
104 | unsigned long val, flags = 0; | ||
105 | int i; | ||
106 | |||
107 | clk_round_rate_index(hw, drate, prate, aux_calc_rate, aux->rtbl_cnt, | ||
108 | &i); | ||
109 | |||
110 | if (aux->lock) | ||
111 | spin_lock_irqsave(aux->lock, flags); | ||
112 | |||
113 | val = readl_relaxed(aux->reg) & | ||
114 | ~(aux->masks->eq_sel_mask << aux->masks->eq_sel_shift); | ||
115 | val |= (rtbl[i].eq & aux->masks->eq_sel_mask) << | ||
116 | aux->masks->eq_sel_shift; | ||
117 | val &= ~(aux->masks->xscale_sel_mask << aux->masks->xscale_sel_shift); | ||
118 | val |= (rtbl[i].xscale & aux->masks->xscale_sel_mask) << | ||
119 | aux->masks->xscale_sel_shift; | ||
120 | val &= ~(aux->masks->yscale_sel_mask << aux->masks->yscale_sel_shift); | ||
121 | val |= (rtbl[i].yscale & aux->masks->yscale_sel_mask) << | ||
122 | aux->masks->yscale_sel_shift; | ||
123 | writel_relaxed(val, aux->reg); | ||
124 | |||
125 | if (aux->lock) | ||
126 | spin_unlock_irqrestore(aux->lock, flags); | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static struct clk_ops clk_aux_ops = { | ||
132 | .recalc_rate = clk_aux_recalc_rate, | ||
133 | .round_rate = clk_aux_round_rate, | ||
134 | .set_rate = clk_aux_set_rate, | ||
135 | }; | ||
136 | |||
137 | struct clk *clk_register_aux(const char *aux_name, const char *gate_name, | ||
138 | const char *parent_name, unsigned long flags, void __iomem *reg, | ||
139 | struct aux_clk_masks *masks, struct aux_rate_tbl *rtbl, | ||
140 | u8 rtbl_cnt, spinlock_t *lock, struct clk **gate_clk) | ||
141 | { | ||
142 | struct clk_aux *aux; | ||
143 | struct clk_init_data init; | ||
144 | struct clk *clk; | ||
145 | |||
146 | if (!aux_name || !parent_name || !reg || !rtbl || !rtbl_cnt) { | ||
147 | pr_err("Invalid arguments passed"); | ||
148 | return ERR_PTR(-EINVAL); | ||
149 | } | ||
150 | |||
151 | aux = kzalloc(sizeof(*aux), GFP_KERNEL); | ||
152 | if (!aux) { | ||
153 | pr_err("could not allocate aux clk\n"); | ||
154 | return ERR_PTR(-ENOMEM); | ||
155 | } | ||
156 | |||
157 | /* struct clk_aux assignments */ | ||
158 | if (!masks) | ||
159 | aux->masks = &default_aux_masks; | ||
160 | else | ||
161 | aux->masks = masks; | ||
162 | |||
163 | aux->reg = reg; | ||
164 | aux->rtbl = rtbl; | ||
165 | aux->rtbl_cnt = rtbl_cnt; | ||
166 | aux->lock = lock; | ||
167 | aux->hw.init = &init; | ||
168 | |||
169 | init.name = aux_name; | ||
170 | init.ops = &clk_aux_ops; | ||
171 | init.flags = flags; | ||
172 | init.parent_names = &parent_name; | ||
173 | init.num_parents = 1; | ||
174 | |||
175 | clk = clk_register(NULL, &aux->hw); | ||
176 | if (IS_ERR_OR_NULL(clk)) | ||
177 | goto free_aux; | ||
178 | |||
179 | if (gate_name) { | ||
180 | struct clk *tgate_clk; | ||
181 | |||
182 | tgate_clk = clk_register_gate(NULL, gate_name, aux_name, 0, reg, | ||
183 | aux->masks->enable_bit, 0, lock); | ||
184 | if (IS_ERR_OR_NULL(tgate_clk)) | ||
185 | goto free_aux; | ||
186 | |||
187 | if (gate_clk) | ||
188 | *gate_clk = tgate_clk; | ||
189 | } | ||
190 | |||
191 | return clk; | ||
192 | |||
193 | free_aux: | ||
194 | kfree(aux); | ||
195 | pr_err("clk register failed\n"); | ||
196 | |||
197 | return NULL; | ||
198 | } | ||
diff --git a/drivers/clk/spear/clk-frac-synth.c b/drivers/clk/spear/clk-frac-synth.c new file mode 100644 index 00000000000..4dbdb3fe18e --- /dev/null +++ b/drivers/clk/spear/clk-frac-synth.c | |||
@@ -0,0 +1,165 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 ST Microelectronics | ||
3 | * Viresh Kumar <viresh.kumar@st.com> | ||
4 | * | ||
5 | * This file is licensed under the terms of the GNU General Public | ||
6 | * License version 2. This program is licensed "as is" without any | ||
7 | * warranty of any kind, whether express or implied. | ||
8 | * | ||
9 | * Fractional Synthesizer clock implementation | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "clk-frac-synth: " fmt | ||
13 | |||
14 | #include <linux/clk-provider.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/err.h> | ||
18 | #include "clk.h" | ||
19 | |||
20 | #define DIV_FACTOR_MASK 0x1FFFF | ||
21 | |||
22 | /* | ||
23 | * DOC: Fractional Synthesizer clock | ||
24 | * | ||
25 | * Fout from synthesizer can be given from below equation: | ||
26 | * | ||
27 | * Fout= Fin/2*div (division factor) | ||
28 | * div is 17 bits:- | ||
29 | * 0-13 (fractional part) | ||
30 | * 14-16 (integer part) | ||
31 | * div is (16-14 bits).(13-0 bits) (in binary) | ||
32 | * | ||
33 | * Fout = Fin/(2 * div) | ||
34 | * Fout = ((Fin / 10000)/(2 * div)) * 10000 | ||
35 | * Fout = (2^14 * (Fin / 10000)/(2^14 * (2 * div))) * 10000 | ||
36 | * Fout = (((Fin / 10000) << 14)/(2 * (div << 14))) * 10000 | ||
37 | * | ||
38 | * div << 14 simply 17 bit value written at register. | ||
39 | * Max error due to scaling down by 10000 is 10 KHz | ||
40 | */ | ||
41 | |||
42 | #define to_clk_frac(_hw) container_of(_hw, struct clk_frac, hw) | ||
43 | |||
44 | static unsigned long frac_calc_rate(struct clk_hw *hw, unsigned long prate, | ||
45 | int index) | ||
46 | { | ||
47 | struct clk_frac *frac = to_clk_frac(hw); | ||
48 | struct frac_rate_tbl *rtbl = frac->rtbl; | ||
49 | |||
50 | prate /= 10000; | ||
51 | prate <<= 14; | ||
52 | prate /= (2 * rtbl[index].div); | ||
53 | prate *= 10000; | ||
54 | |||
55 | return prate; | ||
56 | } | ||
57 | |||
58 | static long clk_frac_round_rate(struct clk_hw *hw, unsigned long drate, | ||
59 | unsigned long *prate) | ||
60 | { | ||
61 | struct clk_frac *frac = to_clk_frac(hw); | ||
62 | int unused; | ||
63 | |||
64 | return clk_round_rate_index(hw, drate, *prate, frac_calc_rate, | ||
65 | frac->rtbl_cnt, &unused); | ||
66 | } | ||
67 | |||
68 | static unsigned long clk_frac_recalc_rate(struct clk_hw *hw, | ||
69 | unsigned long parent_rate) | ||
70 | { | ||
71 | struct clk_frac *frac = to_clk_frac(hw); | ||
72 | unsigned long flags = 0; | ||
73 | unsigned int div = 1, val; | ||
74 | |||
75 | if (frac->lock) | ||
76 | spin_lock_irqsave(frac->lock, flags); | ||
77 | |||
78 | val = readl_relaxed(frac->reg); | ||
79 | |||
80 | if (frac->lock) | ||
81 | spin_unlock_irqrestore(frac->lock, flags); | ||
82 | |||
83 | div = val & DIV_FACTOR_MASK; | ||
84 | |||
85 | if (!div) | ||
86 | return 0; | ||
87 | |||
88 | parent_rate = parent_rate / 10000; | ||
89 | |||
90 | parent_rate = (parent_rate << 14) / (2 * div); | ||
91 | return parent_rate * 10000; | ||
92 | } | ||
93 | |||
94 | /* Configures new clock rate of frac */ | ||
95 | static int clk_frac_set_rate(struct clk_hw *hw, unsigned long drate, | ||
96 | unsigned long prate) | ||
97 | { | ||
98 | struct clk_frac *frac = to_clk_frac(hw); | ||
99 | struct frac_rate_tbl *rtbl = frac->rtbl; | ||
100 | unsigned long flags = 0, val; | ||
101 | int i; | ||
102 | |||
103 | clk_round_rate_index(hw, drate, prate, frac_calc_rate, frac->rtbl_cnt, | ||
104 | &i); | ||
105 | |||
106 | if (frac->lock) | ||
107 | spin_lock_irqsave(frac->lock, flags); | ||
108 | |||
109 | val = readl_relaxed(frac->reg) & ~DIV_FACTOR_MASK; | ||
110 | val |= rtbl[i].div & DIV_FACTOR_MASK; | ||
111 | writel_relaxed(val, frac->reg); | ||
112 | |||
113 | if (frac->lock) | ||
114 | spin_unlock_irqrestore(frac->lock, flags); | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | struct clk_ops clk_frac_ops = { | ||
120 | .recalc_rate = clk_frac_recalc_rate, | ||
121 | .round_rate = clk_frac_round_rate, | ||
122 | .set_rate = clk_frac_set_rate, | ||
123 | }; | ||
124 | |||
125 | struct clk *clk_register_frac(const char *name, const char *parent_name, | ||
126 | unsigned long flags, void __iomem *reg, | ||
127 | struct frac_rate_tbl *rtbl, u8 rtbl_cnt, spinlock_t *lock) | ||
128 | { | ||
129 | struct clk_init_data init; | ||
130 | struct clk_frac *frac; | ||
131 | struct clk *clk; | ||
132 | |||
133 | if (!name || !parent_name || !reg || !rtbl || !rtbl_cnt) { | ||
134 | pr_err("Invalid arguments passed"); | ||
135 | return ERR_PTR(-EINVAL); | ||
136 | } | ||
137 | |||
138 | frac = kzalloc(sizeof(*frac), GFP_KERNEL); | ||
139 | if (!frac) { | ||
140 | pr_err("could not allocate frac clk\n"); | ||
141 | return ERR_PTR(-ENOMEM); | ||
142 | } | ||
143 | |||
144 | /* struct clk_frac assignments */ | ||
145 | frac->reg = reg; | ||
146 | frac->rtbl = rtbl; | ||
147 | frac->rtbl_cnt = rtbl_cnt; | ||
148 | frac->lock = lock; | ||
149 | frac->hw.init = &init; | ||
150 | |||
151 | init.name = name; | ||
152 | init.ops = &clk_frac_ops; | ||
153 | init.flags = flags; | ||
154 | init.parent_names = &parent_name; | ||
155 | init.num_parents = 1; | ||
156 | |||
157 | clk = clk_register(NULL, &frac->hw); | ||
158 | if (!IS_ERR_OR_NULL(clk)) | ||
159 | return clk; | ||
160 | |||
161 | pr_err("clk register failed\n"); | ||
162 | kfree(frac); | ||
163 | |||
164 | return NULL; | ||
165 | } | ||
diff --git a/drivers/clk/spear/clk-gpt-synth.c b/drivers/clk/spear/clk-gpt-synth.c new file mode 100644 index 00000000000..b471c9762a9 --- /dev/null +++ b/drivers/clk/spear/clk-gpt-synth.c | |||
@@ -0,0 +1,154 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 ST Microelectronics | ||
3 | * Viresh Kumar <viresh.kumar@st.com> | ||
4 | * | ||
5 | * This file is licensed under the terms of the GNU General Public | ||
6 | * License version 2. This program is licensed "as is" without any | ||
7 | * warranty of any kind, whether express or implied. | ||
8 | * | ||
9 | * General Purpose Timer Synthesizer clock implementation | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "clk-gpt-synth: " fmt | ||
13 | |||
14 | #include <linux/clk-provider.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/err.h> | ||
18 | #include "clk.h" | ||
19 | |||
20 | #define GPT_MSCALE_MASK 0xFFF | ||
21 | #define GPT_NSCALE_SHIFT 12 | ||
22 | #define GPT_NSCALE_MASK 0xF | ||
23 | |||
24 | /* | ||
25 | * DOC: General Purpose Timer Synthesizer clock | ||
26 | * | ||
27 | * Calculates gpt synth clk rate for different values of mscale and nscale | ||
28 | * | ||
29 | * Fout= Fin/((2 ^ (N+1)) * (M+1)) | ||
30 | */ | ||
31 | |||
32 | #define to_clk_gpt(_hw) container_of(_hw, struct clk_gpt, hw) | ||
33 | |||
34 | static unsigned long gpt_calc_rate(struct clk_hw *hw, unsigned long prate, | ||
35 | int index) | ||
36 | { | ||
37 | struct clk_gpt *gpt = to_clk_gpt(hw); | ||
38 | struct gpt_rate_tbl *rtbl = gpt->rtbl; | ||
39 | |||
40 | prate /= ((1 << (rtbl[index].nscale + 1)) * (rtbl[index].mscale + 1)); | ||
41 | |||
42 | return prate; | ||
43 | } | ||
44 | |||
45 | static long clk_gpt_round_rate(struct clk_hw *hw, unsigned long drate, | ||
46 | unsigned long *prate) | ||
47 | { | ||
48 | struct clk_gpt *gpt = to_clk_gpt(hw); | ||
49 | int unused; | ||
50 | |||
51 | return clk_round_rate_index(hw, drate, *prate, gpt_calc_rate, | ||
52 | gpt->rtbl_cnt, &unused); | ||
53 | } | ||
54 | |||
55 | static unsigned long clk_gpt_recalc_rate(struct clk_hw *hw, | ||
56 | unsigned long parent_rate) | ||
57 | { | ||
58 | struct clk_gpt *gpt = to_clk_gpt(hw); | ||
59 | unsigned long flags = 0; | ||
60 | unsigned int div = 1, val; | ||
61 | |||
62 | if (gpt->lock) | ||
63 | spin_lock_irqsave(gpt->lock, flags); | ||
64 | |||
65 | val = readl_relaxed(gpt->reg); | ||
66 | |||
67 | if (gpt->lock) | ||
68 | spin_unlock_irqrestore(gpt->lock, flags); | ||
69 | |||
70 | div += val & GPT_MSCALE_MASK; | ||
71 | div *= 1 << (((val >> GPT_NSCALE_SHIFT) & GPT_NSCALE_MASK) + 1); | ||
72 | |||
73 | if (!div) | ||
74 | return 0; | ||
75 | |||
76 | return parent_rate / div; | ||
77 | } | ||
78 | |||
79 | /* Configures new clock rate of gpt */ | ||
80 | static int clk_gpt_set_rate(struct clk_hw *hw, unsigned long drate, | ||
81 | unsigned long prate) | ||
82 | { | ||
83 | struct clk_gpt *gpt = to_clk_gpt(hw); | ||
84 | struct gpt_rate_tbl *rtbl = gpt->rtbl; | ||
85 | unsigned long flags = 0, val; | ||
86 | int i; | ||
87 | |||
88 | clk_round_rate_index(hw, drate, prate, gpt_calc_rate, gpt->rtbl_cnt, | ||
89 | &i); | ||
90 | |||
91 | if (gpt->lock) | ||
92 | spin_lock_irqsave(gpt->lock, flags); | ||
93 | |||
94 | val = readl(gpt->reg) & ~GPT_MSCALE_MASK; | ||
95 | val &= ~(GPT_NSCALE_MASK << GPT_NSCALE_SHIFT); | ||
96 | |||
97 | val |= rtbl[i].mscale & GPT_MSCALE_MASK; | ||
98 | val |= (rtbl[i].nscale & GPT_NSCALE_MASK) << GPT_NSCALE_SHIFT; | ||
99 | |||
100 | writel_relaxed(val, gpt->reg); | ||
101 | |||
102 | if (gpt->lock) | ||
103 | spin_unlock_irqrestore(gpt->lock, flags); | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static struct clk_ops clk_gpt_ops = { | ||
109 | .recalc_rate = clk_gpt_recalc_rate, | ||
110 | .round_rate = clk_gpt_round_rate, | ||
111 | .set_rate = clk_gpt_set_rate, | ||
112 | }; | ||
113 | |||
114 | struct clk *clk_register_gpt(const char *name, const char *parent_name, unsigned | ||
115 | long flags, void __iomem *reg, struct gpt_rate_tbl *rtbl, u8 | ||
116 | rtbl_cnt, spinlock_t *lock) | ||
117 | { | ||
118 | struct clk_init_data init; | ||
119 | struct clk_gpt *gpt; | ||
120 | struct clk *clk; | ||
121 | |||
122 | if (!name || !parent_name || !reg || !rtbl || !rtbl_cnt) { | ||
123 | pr_err("Invalid arguments passed"); | ||
124 | return ERR_PTR(-EINVAL); | ||
125 | } | ||
126 | |||
127 | gpt = kzalloc(sizeof(*gpt), GFP_KERNEL); | ||
128 | if (!gpt) { | ||
129 | pr_err("could not allocate gpt clk\n"); | ||
130 | return ERR_PTR(-ENOMEM); | ||
131 | } | ||
132 | |||
133 | /* struct clk_gpt assignments */ | ||
134 | gpt->reg = reg; | ||
135 | gpt->rtbl = rtbl; | ||
136 | gpt->rtbl_cnt = rtbl_cnt; | ||
137 | gpt->lock = lock; | ||
138 | gpt->hw.init = &init; | ||
139 | |||
140 | init.name = name; | ||
141 | init.ops = &clk_gpt_ops; | ||
142 | init.flags = flags; | ||
143 | init.parent_names = &parent_name; | ||
144 | init.num_parents = 1; | ||
145 | |||
146 | clk = clk_register(NULL, &gpt->hw); | ||
147 | if (!IS_ERR_OR_NULL(clk)) | ||
148 | return clk; | ||
149 | |||
150 | pr_err("clk register failed\n"); | ||
151 | kfree(gpt); | ||
152 | |||
153 | return NULL; | ||
154 | } | ||
diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c new file mode 100644 index 00000000000..dcd4bdf4b0d --- /dev/null +++ b/drivers/clk/spear/clk-vco-pll.c | |||
@@ -0,0 +1,363 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 ST Microelectronics | ||
3 | * Viresh Kumar <viresh.kumar@st.com> | ||
4 | * | ||
5 | * This file is licensed under the terms of the GNU General Public | ||
6 | * License version 2. This program is licensed "as is" without any | ||
7 | * warranty of any kind, whether express or implied. | ||
8 | * | ||
9 | * VCO-PLL clock implementation | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "clk-vco-pll: " fmt | ||
13 | |||
14 | #include <linux/clk-provider.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/err.h> | ||
18 | #include "clk.h" | ||
19 | |||
20 | /* | ||
21 | * DOC: VCO-PLL clock | ||
22 | * | ||
23 | * VCO and PLL rate are derived from following equations: | ||
24 | * | ||
25 | * In normal mode | ||
26 | * vco = (2 * M[15:8] * Fin)/N | ||
27 | * | ||
28 | * In Dithered mode | ||
29 | * vco = (2 * M[15:0] * Fin)/(256 * N) | ||
30 | * | ||
31 | * pll_rate = pll/2^p | ||
32 | * | ||
33 | * vco and pll are very closely bound to each other, "vco needs to program: | ||
34 | * mode, m & n" and "pll needs to program p", both share common enable/disable | ||
35 | * logic. | ||
36 | * | ||
37 | * clk_register_vco_pll() registers instances of both vco & pll. | ||
38 | * CLK_SET_RATE_PARENT flag is forced for pll, as it will always pass its | ||
39 | * set_rate to vco. A single rate table exists for both the clocks, which | ||
40 | * configures m, n and p. | ||
41 | */ | ||
42 | |||
43 | /* PLL_CTR register masks */ | ||
44 | #define PLL_MODE_NORMAL 0 | ||
45 | #define PLL_MODE_FRACTION 1 | ||
46 | #define PLL_MODE_DITH_DSM 2 | ||
47 | #define PLL_MODE_DITH_SSM 3 | ||
48 | #define PLL_MODE_MASK 3 | ||
49 | #define PLL_MODE_SHIFT 3 | ||
50 | #define PLL_ENABLE 2 | ||
51 | |||
52 | #define PLL_LOCK_SHIFT 0 | ||
53 | #define PLL_LOCK_MASK 1 | ||
54 | |||
55 | /* PLL FRQ register masks */ | ||
56 | #define PLL_NORM_FDBK_M_MASK 0xFF | ||
57 | #define PLL_NORM_FDBK_M_SHIFT 24 | ||
58 | #define PLL_DITH_FDBK_M_MASK 0xFFFF | ||
59 | #define PLL_DITH_FDBK_M_SHIFT 16 | ||
60 | #define PLL_DIV_P_MASK 0x7 | ||
61 | #define PLL_DIV_P_SHIFT 8 | ||
62 | #define PLL_DIV_N_MASK 0xFF | ||
63 | #define PLL_DIV_N_SHIFT 0 | ||
64 | |||
65 | #define to_clk_vco(_hw) container_of(_hw, struct clk_vco, hw) | ||
66 | #define to_clk_pll(_hw) container_of(_hw, struct clk_pll, hw) | ||
67 | |||
68 | /* Calculates pll clk rate for specific value of mode, m, n and p */ | ||
69 | static unsigned long pll_calc_rate(struct pll_rate_tbl *rtbl, | ||
70 | unsigned long prate, int index, unsigned long *pll_rate) | ||
71 | { | ||
72 | unsigned long rate = prate; | ||
73 | unsigned int mode; | ||
74 | |||
75 | mode = rtbl[index].mode ? 256 : 1; | ||
76 | rate = (((2 * rate / 10000) * rtbl[index].m) / (mode * rtbl[index].n)); | ||
77 | |||
78 | if (pll_rate) | ||
79 | *pll_rate = (rate / (1 << rtbl[index].p)) * 10000; | ||
80 | |||
81 | return rate * 10000; | ||
82 | } | ||
83 | |||
84 | static long clk_pll_round_rate_index(struct clk_hw *hw, unsigned long drate, | ||
85 | unsigned long *prate, int *index) | ||
86 | { | ||
87 | struct clk_pll *pll = to_clk_pll(hw); | ||
88 | unsigned long prev_rate, vco_prev_rate, rate = 0; | ||
89 | unsigned long vco_parent_rate = | ||
90 | __clk_get_rate(__clk_get_parent(__clk_get_parent(hw->clk))); | ||
91 | |||
92 | if (!prate) { | ||
93 | pr_err("%s: prate is must for pll clk\n", __func__); | ||
94 | return -EINVAL; | ||
95 | } | ||
96 | |||
97 | for (*index = 0; *index < pll->vco->rtbl_cnt; (*index)++) { | ||
98 | prev_rate = rate; | ||
99 | vco_prev_rate = *prate; | ||
100 | *prate = pll_calc_rate(pll->vco->rtbl, vco_parent_rate, *index, | ||
101 | &rate); | ||
102 | if (drate < rate) { | ||
103 | /* previous clock was best */ | ||
104 | if (*index) { | ||
105 | rate = prev_rate; | ||
106 | *prate = vco_prev_rate; | ||
107 | (*index)--; | ||
108 | } | ||
109 | break; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | return rate; | ||
114 | } | ||
115 | |||
116 | static long clk_pll_round_rate(struct clk_hw *hw, unsigned long drate, | ||
117 | unsigned long *prate) | ||
118 | { | ||
119 | int unused; | ||
120 | |||
121 | return clk_pll_round_rate_index(hw, drate, prate, &unused); | ||
122 | } | ||
123 | |||
124 | static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, unsigned long | ||
125 | parent_rate) | ||
126 | { | ||
127 | struct clk_pll *pll = to_clk_pll(hw); | ||
128 | unsigned long flags = 0; | ||
129 | unsigned int p; | ||
130 | |||
131 | if (pll->vco->lock) | ||
132 | spin_lock_irqsave(pll->vco->lock, flags); | ||
133 | |||
134 | p = readl_relaxed(pll->vco->cfg_reg); | ||
135 | |||
136 | if (pll->vco->lock) | ||
137 | spin_unlock_irqrestore(pll->vco->lock, flags); | ||
138 | |||
139 | p = (p >> PLL_DIV_P_SHIFT) & PLL_DIV_P_MASK; | ||
140 | |||
141 | return parent_rate / (1 << p); | ||
142 | } | ||
143 | |||
144 | static int clk_pll_set_rate(struct clk_hw *hw, unsigned long drate, | ||
145 | unsigned long prate) | ||
146 | { | ||
147 | struct clk_pll *pll = to_clk_pll(hw); | ||
148 | struct pll_rate_tbl *rtbl = pll->vco->rtbl; | ||
149 | unsigned long flags = 0, val; | ||
150 | int i; | ||
151 | |||
152 | clk_pll_round_rate_index(hw, drate, NULL, &i); | ||
153 | |||
154 | if (pll->vco->lock) | ||
155 | spin_lock_irqsave(pll->vco->lock, flags); | ||
156 | |||
157 | val = readl_relaxed(pll->vco->cfg_reg); | ||
158 | val &= ~(PLL_DIV_P_MASK << PLL_DIV_P_SHIFT); | ||
159 | val |= (rtbl[i].p & PLL_DIV_P_MASK) << PLL_DIV_P_SHIFT; | ||
160 | writel_relaxed(val, pll->vco->cfg_reg); | ||
161 | |||
162 | if (pll->vco->lock) | ||
163 | spin_unlock_irqrestore(pll->vco->lock, flags); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static struct clk_ops clk_pll_ops = { | ||
169 | .recalc_rate = clk_pll_recalc_rate, | ||
170 | .round_rate = clk_pll_round_rate, | ||
171 | .set_rate = clk_pll_set_rate, | ||
172 | }; | ||
173 | |||
174 | static inline unsigned long vco_calc_rate(struct clk_hw *hw, | ||
175 | unsigned long prate, int index) | ||
176 | { | ||
177 | struct clk_vco *vco = to_clk_vco(hw); | ||
178 | |||
179 | return pll_calc_rate(vco->rtbl, prate, index, NULL); | ||
180 | } | ||
181 | |||
182 | static long clk_vco_round_rate(struct clk_hw *hw, unsigned long drate, | ||
183 | unsigned long *prate) | ||
184 | { | ||
185 | struct clk_vco *vco = to_clk_vco(hw); | ||
186 | int unused; | ||
187 | |||
188 | return clk_round_rate_index(hw, drate, *prate, vco_calc_rate, | ||
189 | vco->rtbl_cnt, &unused); | ||
190 | } | ||
191 | |||
192 | static unsigned long clk_vco_recalc_rate(struct clk_hw *hw, | ||
193 | unsigned long parent_rate) | ||
194 | { | ||
195 | struct clk_vco *vco = to_clk_vco(hw); | ||
196 | unsigned long flags = 0; | ||
197 | unsigned int num = 2, den = 0, val, mode = 0; | ||
198 | |||
199 | if (vco->lock) | ||
200 | spin_lock_irqsave(vco->lock, flags); | ||
201 | |||
202 | mode = (readl_relaxed(vco->mode_reg) >> PLL_MODE_SHIFT) & PLL_MODE_MASK; | ||
203 | |||
204 | val = readl_relaxed(vco->cfg_reg); | ||
205 | |||
206 | if (vco->lock) | ||
207 | spin_unlock_irqrestore(vco->lock, flags); | ||
208 | |||
209 | den = (val >> PLL_DIV_N_SHIFT) & PLL_DIV_N_MASK; | ||
210 | |||
211 | /* calculate numerator & denominator */ | ||
212 | if (!mode) { | ||
213 | /* Normal mode */ | ||
214 | num *= (val >> PLL_NORM_FDBK_M_SHIFT) & PLL_NORM_FDBK_M_MASK; | ||
215 | } else { | ||
216 | /* Dithered mode */ | ||
217 | num *= (val >> PLL_DITH_FDBK_M_SHIFT) & PLL_DITH_FDBK_M_MASK; | ||
218 | den *= 256; | ||
219 | } | ||
220 | |||
221 | if (!den) { | ||
222 | WARN(1, "%s: denominator can't be zero\n", __func__); | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | return (((parent_rate / 10000) * num) / den) * 10000; | ||
227 | } | ||
228 | |||
229 | /* Configures new clock rate of vco */ | ||
230 | static int clk_vco_set_rate(struct clk_hw *hw, unsigned long drate, | ||
231 | unsigned long prate) | ||
232 | { | ||
233 | struct clk_vco *vco = to_clk_vco(hw); | ||
234 | struct pll_rate_tbl *rtbl = vco->rtbl; | ||
235 | unsigned long flags = 0, val; | ||
236 | int i; | ||
237 | |||
238 | clk_round_rate_index(hw, drate, prate, vco_calc_rate, vco->rtbl_cnt, | ||
239 | &i); | ||
240 | |||
241 | if (vco->lock) | ||
242 | spin_lock_irqsave(vco->lock, flags); | ||
243 | |||
244 | val = readl_relaxed(vco->mode_reg); | ||
245 | val &= ~(PLL_MODE_MASK << PLL_MODE_SHIFT); | ||
246 | val |= (rtbl[i].mode & PLL_MODE_MASK) << PLL_MODE_SHIFT; | ||
247 | writel_relaxed(val, vco->mode_reg); | ||
248 | |||
249 | val = readl_relaxed(vco->cfg_reg); | ||
250 | val &= ~(PLL_DIV_N_MASK << PLL_DIV_N_SHIFT); | ||
251 | val |= (rtbl[i].n & PLL_DIV_N_MASK) << PLL_DIV_N_SHIFT; | ||
252 | |||
253 | val &= ~(PLL_DITH_FDBK_M_MASK << PLL_DITH_FDBK_M_SHIFT); | ||
254 | if (rtbl[i].mode) | ||
255 | val |= (rtbl[i].m & PLL_DITH_FDBK_M_MASK) << | ||
256 | PLL_DITH_FDBK_M_SHIFT; | ||
257 | else | ||
258 | val |= (rtbl[i].m & PLL_NORM_FDBK_M_MASK) << | ||
259 | PLL_NORM_FDBK_M_SHIFT; | ||
260 | |||
261 | writel_relaxed(val, vco->cfg_reg); | ||
262 | |||
263 | if (vco->lock) | ||
264 | spin_unlock_irqrestore(vco->lock, flags); | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static struct clk_ops clk_vco_ops = { | ||
270 | .recalc_rate = clk_vco_recalc_rate, | ||
271 | .round_rate = clk_vco_round_rate, | ||
272 | .set_rate = clk_vco_set_rate, | ||
273 | }; | ||
274 | |||
275 | struct clk *clk_register_vco_pll(const char *vco_name, const char *pll_name, | ||
276 | const char *vco_gate_name, const char *parent_name, | ||
277 | unsigned long flags, void __iomem *mode_reg, void __iomem | ||
278 | *cfg_reg, struct pll_rate_tbl *rtbl, u8 rtbl_cnt, | ||
279 | spinlock_t *lock, struct clk **pll_clk, | ||
280 | struct clk **vco_gate_clk) | ||
281 | { | ||
282 | struct clk_vco *vco; | ||
283 | struct clk_pll *pll; | ||
284 | struct clk *vco_clk, *tpll_clk, *tvco_gate_clk; | ||
285 | struct clk_init_data vco_init, pll_init; | ||
286 | const char **vco_parent_name; | ||
287 | |||
288 | if (!vco_name || !pll_name || !parent_name || !mode_reg || !cfg_reg || | ||
289 | !rtbl || !rtbl_cnt) { | ||
290 | pr_err("Invalid arguments passed"); | ||
291 | return ERR_PTR(-EINVAL); | ||
292 | } | ||
293 | |||
294 | vco = kzalloc(sizeof(*vco), GFP_KERNEL); | ||
295 | if (!vco) { | ||
296 | pr_err("could not allocate vco clk\n"); | ||
297 | return ERR_PTR(-ENOMEM); | ||
298 | } | ||
299 | |||
300 | pll = kzalloc(sizeof(*pll), GFP_KERNEL); | ||
301 | if (!pll) { | ||
302 | pr_err("could not allocate pll clk\n"); | ||
303 | goto free_vco; | ||
304 | } | ||
305 | |||
306 | /* struct clk_vco assignments */ | ||
307 | vco->mode_reg = mode_reg; | ||
308 | vco->cfg_reg = cfg_reg; | ||
309 | vco->rtbl = rtbl; | ||
310 | vco->rtbl_cnt = rtbl_cnt; | ||
311 | vco->lock = lock; | ||
312 | vco->hw.init = &vco_init; | ||
313 | |||
314 | pll->vco = vco; | ||
315 | pll->hw.init = &pll_init; | ||
316 | |||
317 | if (vco_gate_name) { | ||
318 | tvco_gate_clk = clk_register_gate(NULL, vco_gate_name, | ||
319 | parent_name, 0, mode_reg, PLL_ENABLE, 0, lock); | ||
320 | if (IS_ERR_OR_NULL(tvco_gate_clk)) | ||
321 | goto free_pll; | ||
322 | |||
323 | if (vco_gate_clk) | ||
324 | *vco_gate_clk = tvco_gate_clk; | ||
325 | vco_parent_name = &vco_gate_name; | ||
326 | } else { | ||
327 | vco_parent_name = &parent_name; | ||
328 | } | ||
329 | |||
330 | vco_init.name = vco_name; | ||
331 | vco_init.ops = &clk_vco_ops; | ||
332 | vco_init.flags = flags; | ||
333 | vco_init.parent_names = vco_parent_name; | ||
334 | vco_init.num_parents = 1; | ||
335 | |||
336 | pll_init.name = pll_name; | ||
337 | pll_init.ops = &clk_pll_ops; | ||
338 | pll_init.flags = CLK_SET_RATE_PARENT; | ||
339 | pll_init.parent_names = &vco_name; | ||
340 | pll_init.num_parents = 1; | ||
341 | |||
342 | vco_clk = clk_register(NULL, &vco->hw); | ||
343 | if (IS_ERR_OR_NULL(vco_clk)) | ||
344 | goto free_pll; | ||
345 | |||
346 | tpll_clk = clk_register(NULL, &pll->hw); | ||
347 | if (IS_ERR_OR_NULL(tpll_clk)) | ||
348 | goto free_pll; | ||
349 | |||
350 | if (pll_clk) | ||
351 | *pll_clk = tpll_clk; | ||
352 | |||
353 | return vco_clk; | ||
354 | |||
355 | free_pll: | ||
356 | kfree(pll); | ||
357 | free_vco: | ||
358 | kfree(vco); | ||
359 | |||
360 | pr_err("Failed to register vco pll clock\n"); | ||
361 | |||
362 | return ERR_PTR(-ENOMEM); | ||
363 | } | ||
diff --git a/drivers/clk/spear/clk.c b/drivers/clk/spear/clk.c new file mode 100644 index 00000000000..376d4e5ff32 --- /dev/null +++ b/drivers/clk/spear/clk.c | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 ST Microelectronics | ||
3 | * Viresh Kumar <viresh.kumar@st.com> | ||
4 | * | ||
5 | * This file is licensed under the terms of the GNU General Public | ||
6 | * License version 2. This program is licensed "as is" without any | ||
7 | * warranty of any kind, whether express or implied. | ||
8 | * | ||
9 | * SPEAr clk - Common routines | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk-provider.h> | ||
13 | #include <linux/types.h> | ||
14 | #include "clk.h" | ||
15 | |||
16 | long clk_round_rate_index(struct clk_hw *hw, unsigned long drate, | ||
17 | unsigned long parent_rate, clk_calc_rate calc_rate, u8 rtbl_cnt, | ||
18 | int *index) | ||
19 | { | ||
20 | unsigned long prev_rate, rate = 0; | ||
21 | |||
22 | for (*index = 0; *index < rtbl_cnt; (*index)++) { | ||
23 | prev_rate = rate; | ||
24 | rate = calc_rate(hw, parent_rate, *index); | ||
25 | if (drate < rate) { | ||
26 | /* previous clock was best */ | ||
27 | if (*index) { | ||
28 | rate = prev_rate; | ||
29 | (*index)--; | ||
30 | } | ||
31 | break; | ||
32 | } | ||
33 | } | ||
34 | |||
35 | return rate; | ||
36 | } | ||
diff --git a/drivers/clk/spear/clk.h b/drivers/clk/spear/clk.h new file mode 100644 index 00000000000..3321c46a071 --- /dev/null +++ b/drivers/clk/spear/clk.h | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * Clock framework definitions for SPEAr platform | ||
3 | * | ||
4 | * Copyright (C) 2012 ST Microelectronics | ||
5 | * Viresh Kumar <viresh.kumar@st.com> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public | ||
8 | * License version 2. This program is licensed "as is" without any | ||
9 | * warranty of any kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #ifndef __SPEAR_CLK_H | ||
13 | #define __SPEAR_CLK_H | ||
14 | |||
15 | #include <linux/clk-provider.h> | ||
16 | #include <linux/spinlock_types.h> | ||
17 | #include <linux/types.h> | ||
18 | |||
19 | /* Auxiliary Synth clk */ | ||
20 | /* Default masks */ | ||
21 | #define AUX_EQ_SEL_SHIFT 30 | ||
22 | #define AUX_EQ_SEL_MASK 1 | ||
23 | #define AUX_EQ1_SEL 0 | ||
24 | #define AUX_EQ2_SEL 1 | ||
25 | #define AUX_XSCALE_SHIFT 16 | ||
26 | #define AUX_XSCALE_MASK 0xFFF | ||
27 | #define AUX_YSCALE_SHIFT 0 | ||
28 | #define AUX_YSCALE_MASK 0xFFF | ||
29 | #define AUX_SYNT_ENB 31 | ||
30 | |||
31 | struct aux_clk_masks { | ||
32 | u32 eq_sel_mask; | ||
33 | u32 eq_sel_shift; | ||
34 | u32 eq1_mask; | ||
35 | u32 eq2_mask; | ||
36 | u32 xscale_sel_mask; | ||
37 | u32 xscale_sel_shift; | ||
38 | u32 yscale_sel_mask; | ||
39 | u32 yscale_sel_shift; | ||
40 | u32 enable_bit; | ||
41 | }; | ||
42 | |||
43 | struct aux_rate_tbl { | ||
44 | u16 xscale; | ||
45 | u16 yscale; | ||
46 | u8 eq; | ||
47 | }; | ||
48 | |||
49 | struct clk_aux { | ||
50 | struct clk_hw hw; | ||
51 | void __iomem *reg; | ||
52 | struct aux_clk_masks *masks; | ||
53 | struct aux_rate_tbl *rtbl; | ||
54 | u8 rtbl_cnt; | ||
55 | spinlock_t *lock; | ||
56 | }; | ||
57 | |||
58 | /* Fractional Synth clk */ | ||
59 | struct frac_rate_tbl { | ||
60 | u32 div; | ||
61 | }; | ||
62 | |||
63 | struct clk_frac { | ||
64 | struct clk_hw hw; | ||
65 | void __iomem *reg; | ||
66 | struct frac_rate_tbl *rtbl; | ||
67 | u8 rtbl_cnt; | ||
68 | spinlock_t *lock; | ||
69 | }; | ||
70 | |||
71 | /* GPT clk */ | ||
72 | struct gpt_rate_tbl { | ||
73 | u16 mscale; | ||
74 | u16 nscale; | ||
75 | }; | ||
76 | |||
77 | struct clk_gpt { | ||
78 | struct clk_hw hw; | ||
79 | void __iomem *reg; | ||
80 | struct gpt_rate_tbl *rtbl; | ||
81 | u8 rtbl_cnt; | ||
82 | spinlock_t *lock; | ||
83 | }; | ||
84 | |||
85 | /* VCO-PLL clk */ | ||
86 | struct pll_rate_tbl { | ||
87 | u8 mode; | ||
88 | u16 m; | ||
89 | u8 n; | ||
90 | u8 p; | ||
91 | }; | ||
92 | |||
93 | struct clk_vco { | ||
94 | struct clk_hw hw; | ||
95 | void __iomem *mode_reg; | ||
96 | void __iomem *cfg_reg; | ||
97 | struct pll_rate_tbl *rtbl; | ||
98 | u8 rtbl_cnt; | ||
99 | spinlock_t *lock; | ||
100 | }; | ||
101 | |||
102 | struct clk_pll { | ||
103 | struct clk_hw hw; | ||
104 | struct clk_vco *vco; | ||
105 | const char *parent[1]; | ||
106 | spinlock_t *lock; | ||
107 | }; | ||
108 | |||
109 | typedef unsigned long (*clk_calc_rate)(struct clk_hw *hw, unsigned long prate, | ||
110 | int index); | ||
111 | |||
112 | /* clk register routines */ | ||
113 | struct clk *clk_register_aux(const char *aux_name, const char *gate_name, | ||
114 | const char *parent_name, unsigned long flags, void __iomem *reg, | ||
115 | struct aux_clk_masks *masks, struct aux_rate_tbl *rtbl, | ||
116 | u8 rtbl_cnt, spinlock_t *lock, struct clk **gate_clk); | ||
117 | struct clk *clk_register_frac(const char *name, const char *parent_name, | ||
118 | unsigned long flags, void __iomem *reg, | ||
119 | struct frac_rate_tbl *rtbl, u8 rtbl_cnt, spinlock_t *lock); | ||
120 | struct clk *clk_register_gpt(const char *name, const char *parent_name, unsigned | ||
121 | long flags, void __iomem *reg, struct gpt_rate_tbl *rtbl, u8 | ||
122 | rtbl_cnt, spinlock_t *lock); | ||
123 | struct clk *clk_register_vco_pll(const char *vco_name, const char *pll_name, | ||
124 | const char *vco_gate_name, const char *parent_name, | ||
125 | unsigned long flags, void __iomem *mode_reg, void __iomem | ||
126 | *cfg_reg, struct pll_rate_tbl *rtbl, u8 rtbl_cnt, | ||
127 | spinlock_t *lock, struct clk **pll_clk, | ||
128 | struct clk **vco_gate_clk); | ||
129 | |||
130 | long clk_round_rate_index(struct clk_hw *hw, unsigned long drate, | ||
131 | unsigned long parent_rate, clk_calc_rate calc_rate, u8 rtbl_cnt, | ||
132 | int *index); | ||
133 | |||
134 | #endif /* __SPEAR_CLK_H */ | ||
diff --git a/drivers/clk/spear/spear3xx_clock.c b/drivers/clk/spear/spear3xx_clock.c new file mode 100644 index 00000000000..440bb3e4c97 --- /dev/null +++ b/drivers/clk/spear/spear3xx_clock.c | |||
@@ -0,0 +1,612 @@ | |||
1 | /* | ||
2 | * SPEAr3xx machines clock framework source file | ||
3 | * | ||
4 | * Copyright (C) 2012 ST Microelectronics | ||
5 | * Viresh Kumar <viresh.kumar@st.com> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public | ||
8 | * License version 2. This program is licensed "as is" without any | ||
9 | * warranty of any kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/clkdev.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/of_platform.h> | ||
17 | #include <linux/spinlock_types.h> | ||
18 | #include <mach/misc_regs.h> | ||
19 | #include "clk.h" | ||
20 | |||
21 | static DEFINE_SPINLOCK(_lock); | ||
22 | |||
23 | #define PLL1_CTR (MISC_BASE + 0x008) | ||
24 | #define PLL1_FRQ (MISC_BASE + 0x00C) | ||
25 | #define PLL2_CTR (MISC_BASE + 0x014) | ||
26 | #define PLL2_FRQ (MISC_BASE + 0x018) | ||
27 | #define PLL_CLK_CFG (MISC_BASE + 0x020) | ||
28 | /* PLL_CLK_CFG register masks */ | ||
29 | #define MCTR_CLK_SHIFT 28 | ||
30 | #define MCTR_CLK_MASK 3 | ||
31 | |||
32 | #define CORE_CLK_CFG (MISC_BASE + 0x024) | ||
33 | /* CORE CLK CFG register masks */ | ||
34 | #define GEN_SYNTH2_3_CLK_SHIFT 18 | ||
35 | #define GEN_SYNTH2_3_CLK_MASK 1 | ||
36 | |||
37 | #define HCLK_RATIO_SHIFT 10 | ||
38 | #define HCLK_RATIO_MASK 2 | ||
39 | #define PCLK_RATIO_SHIFT 8 | ||
40 | #define PCLK_RATIO_MASK 2 | ||
41 | |||
42 | #define PERIP_CLK_CFG (MISC_BASE + 0x028) | ||
43 | /* PERIP_CLK_CFG register masks */ | ||
44 | #define UART_CLK_SHIFT 4 | ||
45 | #define UART_CLK_MASK 1 | ||
46 | #define FIRDA_CLK_SHIFT 5 | ||
47 | #define FIRDA_CLK_MASK 2 | ||
48 | #define GPT0_CLK_SHIFT 8 | ||
49 | #define GPT1_CLK_SHIFT 11 | ||
50 | #define GPT2_CLK_SHIFT 12 | ||
51 | #define GPT_CLK_MASK 1 | ||
52 | |||
53 | #define PERIP1_CLK_ENB (MISC_BASE + 0x02C) | ||
54 | /* PERIP1_CLK_ENB register masks */ | ||
55 | #define UART_CLK_ENB 3 | ||
56 | #define SSP_CLK_ENB 5 | ||
57 | #define I2C_CLK_ENB 7 | ||
58 | #define JPEG_CLK_ENB 8 | ||
59 | #define FIRDA_CLK_ENB 10 | ||
60 | #define GPT1_CLK_ENB 11 | ||
61 | #define GPT2_CLK_ENB 12 | ||
62 | #define ADC_CLK_ENB 15 | ||
63 | #define RTC_CLK_ENB 17 | ||
64 | #define GPIO_CLK_ENB 18 | ||
65 | #define DMA_CLK_ENB 19 | ||
66 | #define SMI_CLK_ENB 21 | ||
67 | #define GMAC_CLK_ENB 23 | ||
68 | #define USBD_CLK_ENB 24 | ||
69 | #define USBH_CLK_ENB 25 | ||
70 | #define C3_CLK_ENB 31 | ||
71 | |||
72 | #define RAS_CLK_ENB (MISC_BASE + 0x034) | ||
73 | #define RAS_AHB_CLK_ENB 0 | ||
74 | #define RAS_PLL1_CLK_ENB 1 | ||
75 | #define RAS_APB_CLK_ENB 2 | ||
76 | #define RAS_32K_CLK_ENB 3 | ||
77 | #define RAS_24M_CLK_ENB 4 | ||
78 | #define RAS_48M_CLK_ENB 5 | ||
79 | #define RAS_PLL2_CLK_ENB 7 | ||
80 | #define RAS_SYNT0_CLK_ENB 8 | ||
81 | #define RAS_SYNT1_CLK_ENB 9 | ||
82 | #define RAS_SYNT2_CLK_ENB 10 | ||
83 | #define RAS_SYNT3_CLK_ENB 11 | ||
84 | |||
85 | #define PRSC0_CLK_CFG (MISC_BASE + 0x044) | ||
86 | #define PRSC1_CLK_CFG (MISC_BASE + 0x048) | ||
87 | #define PRSC2_CLK_CFG (MISC_BASE + 0x04C) | ||
88 | #define AMEM_CLK_CFG (MISC_BASE + 0x050) | ||
89 | #define AMEM_CLK_ENB 0 | ||
90 | |||
91 | #define CLCD_CLK_SYNT (MISC_BASE + 0x05C) | ||
92 | #define FIRDA_CLK_SYNT (MISC_BASE + 0x060) | ||
93 | #define UART_CLK_SYNT (MISC_BASE + 0x064) | ||
94 | #define GMAC_CLK_SYNT (MISC_BASE + 0x068) | ||
95 | #define GEN0_CLK_SYNT (MISC_BASE + 0x06C) | ||
96 | #define GEN1_CLK_SYNT (MISC_BASE + 0x070) | ||
97 | #define GEN2_CLK_SYNT (MISC_BASE + 0x074) | ||
98 | #define GEN3_CLK_SYNT (MISC_BASE + 0x078) | ||
99 | |||
100 | /* pll rate configuration table, in ascending order of rates */ | ||
101 | static struct pll_rate_tbl pll_rtbl[] = { | ||
102 | {.mode = 0, .m = 0x53, .n = 0x0C, .p = 0x1}, /* vco 332 & pll 166 MHz */ | ||
103 | {.mode = 0, .m = 0x85, .n = 0x0C, .p = 0x1}, /* vco 532 & pll 266 MHz */ | ||
104 | {.mode = 0, .m = 0xA6, .n = 0x0C, .p = 0x1}, /* vco 664 & pll 332 MHz */ | ||
105 | }; | ||
106 | |||
107 | /* aux rate configuration table, in ascending order of rates */ | ||
108 | static struct aux_rate_tbl aux_rtbl[] = { | ||
109 | /* For PLL1 = 332 MHz */ | ||
110 | {.xscale = 2, .yscale = 27, .eq = 0}, /* 12.296 MHz */ | ||
111 | {.xscale = 2, .yscale = 8, .eq = 0}, /* 41.5 MHz */ | ||
112 | {.xscale = 2, .yscale = 4, .eq = 0}, /* 83 MHz */ | ||
113 | {.xscale = 1, .yscale = 2, .eq = 1}, /* 166 MHz */ | ||
114 | }; | ||
115 | |||
116 | /* gpt rate configuration table, in ascending order of rates */ | ||
117 | static struct gpt_rate_tbl gpt_rtbl[] = { | ||
118 | /* For pll1 = 332 MHz */ | ||
119 | {.mscale = 4, .nscale = 0}, /* 41.5 MHz */ | ||
120 | {.mscale = 2, .nscale = 0}, /* 55.3 MHz */ | ||
121 | {.mscale = 1, .nscale = 0}, /* 83 MHz */ | ||
122 | }; | ||
123 | |||
124 | /* clock parents */ | ||
125 | static const char *uart0_parents[] = { "pll3_48m_clk", "uart_synth_gate_clk", }; | ||
126 | static const char *firda_parents[] = { "pll3_48m_clk", "firda_synth_gate_clk", | ||
127 | }; | ||
128 | static const char *gpt0_parents[] = { "pll3_48m_clk", "gpt0_synth_clk", }; | ||
129 | static const char *gpt1_parents[] = { "pll3_48m_clk", "gpt1_synth_clk", }; | ||
130 | static const char *gpt2_parents[] = { "pll3_48m_clk", "gpt2_synth_clk", }; | ||
131 | static const char *gen2_3_parents[] = { "pll1_clk", "pll2_clk", }; | ||
132 | static const char *ddr_parents[] = { "ahb_clk", "ahbmult2_clk", "none", | ||
133 | "pll2_clk", }; | ||
134 | |||
135 | #ifdef CONFIG_MACH_SPEAR300 | ||
136 | static void __init spear300_clk_init(void) | ||
137 | { | ||
138 | struct clk *clk; | ||
139 | |||
140 | clk = clk_register_fixed_factor(NULL, "clcd_clk", "ras_pll3_48m_clk", 0, | ||
141 | 1, 1); | ||
142 | clk_register_clkdev(clk, NULL, "60000000.clcd"); | ||
143 | |||
144 | clk = clk_register_fixed_factor(NULL, "fsmc_clk", "ras_ahb_clk", 0, 1, | ||
145 | 1); | ||
146 | clk_register_clkdev(clk, NULL, "94000000.flash"); | ||
147 | |||
148 | clk = clk_register_fixed_factor(NULL, "sdhci_clk", "ras_ahb_clk", 0, 1, | ||
149 | 1); | ||
150 | clk_register_clkdev(clk, NULL, "70000000.sdhci"); | ||
151 | |||
152 | clk = clk_register_fixed_factor(NULL, "gpio1_clk", "ras_apb_clk", 0, 1, | ||
153 | 1); | ||
154 | clk_register_clkdev(clk, NULL, "a9000000.gpio"); | ||
155 | |||
156 | clk = clk_register_fixed_factor(NULL, "kbd_clk", "ras_apb_clk", 0, 1, | ||
157 | 1); | ||
158 | clk_register_clkdev(clk, NULL, "a0000000.kbd"); | ||
159 | } | ||
160 | #endif | ||
161 | |||
162 | /* array of all spear 310 clock lookups */ | ||
163 | #ifdef CONFIG_MACH_SPEAR310 | ||
164 | static void __init spear310_clk_init(void) | ||
165 | { | ||
166 | struct clk *clk; | ||
167 | |||
168 | clk = clk_register_fixed_factor(NULL, "emi_clk", "ras_ahb_clk", 0, 1, | ||
169 | 1); | ||
170 | clk_register_clkdev(clk, "emi", NULL); | ||
171 | |||
172 | clk = clk_register_fixed_factor(NULL, "fsmc_clk", "ras_ahb_clk", 0, 1, | ||
173 | 1); | ||
174 | clk_register_clkdev(clk, NULL, "44000000.flash"); | ||
175 | |||
176 | clk = clk_register_fixed_factor(NULL, "tdm_clk", "ras_ahb_clk", 0, 1, | ||
177 | 1); | ||
178 | clk_register_clkdev(clk, NULL, "tdm"); | ||
179 | |||
180 | clk = clk_register_fixed_factor(NULL, "uart1_clk", "ras_apb_clk", 0, 1, | ||
181 | 1); | ||
182 | clk_register_clkdev(clk, NULL, "b2000000.serial"); | ||
183 | |||
184 | clk = clk_register_fixed_factor(NULL, "uart2_clk", "ras_apb_clk", 0, 1, | ||
185 | 1); | ||
186 | clk_register_clkdev(clk, NULL, "b2080000.serial"); | ||
187 | |||
188 | clk = clk_register_fixed_factor(NULL, "uart3_clk", "ras_apb_clk", 0, 1, | ||
189 | 1); | ||
190 | clk_register_clkdev(clk, NULL, "b2100000.serial"); | ||
191 | |||
192 | clk = clk_register_fixed_factor(NULL, "uart4_clk", "ras_apb_clk", 0, 1, | ||
193 | 1); | ||
194 | clk_register_clkdev(clk, NULL, "b2180000.serial"); | ||
195 | |||
196 | clk = clk_register_fixed_factor(NULL, "uart5_clk", "ras_apb_clk", 0, 1, | ||
197 | 1); | ||
198 | clk_register_clkdev(clk, NULL, "b2200000.serial"); | ||
199 | } | ||
200 | #endif | ||
201 | |||
202 | /* array of all spear 320 clock lookups */ | ||
203 | #ifdef CONFIG_MACH_SPEAR320 | ||
204 | #define SMII_PCLK_SHIFT 18 | ||
205 | #define SMII_PCLK_MASK 2 | ||
206 | #define SMII_PCLK_VAL_PAD 0x0 | ||
207 | #define SMII_PCLK_VAL_PLL2 0x1 | ||
208 | #define SMII_PCLK_VAL_SYNTH0 0x2 | ||
209 | #define SDHCI_PCLK_SHIFT 15 | ||
210 | #define SDHCI_PCLK_MASK 1 | ||
211 | #define SDHCI_PCLK_VAL_48M 0x0 | ||
212 | #define SDHCI_PCLK_VAL_SYNTH3 0x1 | ||
213 | #define I2S_REF_PCLK_SHIFT 8 | ||
214 | #define I2S_REF_PCLK_MASK 1 | ||
215 | #define I2S_REF_PCLK_SYNTH_VAL 0x1 | ||
216 | #define I2S_REF_PCLK_PLL2_VAL 0x0 | ||
217 | #define UART1_PCLK_SHIFT 6 | ||
218 | #define UART1_PCLK_MASK 1 | ||
219 | #define SPEAR320_UARTX_PCLK_VAL_SYNTH1 0x0 | ||
220 | #define SPEAR320_UARTX_PCLK_VAL_APB 0x1 | ||
221 | |||
222 | static const char *i2s_ref_parents[] = { "ras_pll2_clk", | ||
223 | "ras_gen2_synth_gate_clk", }; | ||
224 | static const char *sdhci_parents[] = { "ras_pll3_48m_clk", | ||
225 | "ras_gen3_synth_gate_clk", | ||
226 | }; | ||
227 | static const char *smii0_parents[] = { "smii_125m_pad", "ras_pll2_clk", | ||
228 | "ras_gen0_synth_gate_clk", }; | ||
229 | static const char *uartx_parents[] = { "ras_gen1_synth_gate_clk", "ras_apb_clk", | ||
230 | }; | ||
231 | |||
232 | static void __init spear320_clk_init(void) | ||
233 | { | ||
234 | struct clk *clk; | ||
235 | |||
236 | clk = clk_register_fixed_rate(NULL, "smii_125m_pad_clk", NULL, | ||
237 | CLK_IS_ROOT, 125000000); | ||
238 | clk_register_clkdev(clk, "smii_125m_pad", NULL); | ||
239 | |||
240 | clk = clk_register_fixed_factor(NULL, "clcd_clk", "ras_pll3_48m_clk", 0, | ||
241 | 1, 1); | ||
242 | clk_register_clkdev(clk, NULL, "90000000.clcd"); | ||
243 | |||
244 | clk = clk_register_fixed_factor(NULL, "emi_clk", "ras_ahb_clk", 0, 1, | ||
245 | 1); | ||
246 | clk_register_clkdev(clk, "emi", NULL); | ||
247 | |||
248 | clk = clk_register_fixed_factor(NULL, "fsmc_clk", "ras_ahb_clk", 0, 1, | ||
249 | 1); | ||
250 | clk_register_clkdev(clk, NULL, "4c000000.flash"); | ||
251 | |||
252 | clk = clk_register_fixed_factor(NULL, "i2c1_clk", "ras_ahb_clk", 0, 1, | ||
253 | 1); | ||
254 | clk_register_clkdev(clk, NULL, "a7000000.i2c"); | ||
255 | |||
256 | clk = clk_register_fixed_factor(NULL, "pwm_clk", "ras_ahb_clk", 0, 1, | ||
257 | 1); | ||
258 | clk_register_clkdev(clk, "pwm", NULL); | ||
259 | |||
260 | clk = clk_register_fixed_factor(NULL, "ssp1_clk", "ras_ahb_clk", 0, 1, | ||
261 | 1); | ||
262 | clk_register_clkdev(clk, NULL, "a5000000.spi"); | ||
263 | |||
264 | clk = clk_register_fixed_factor(NULL, "ssp2_clk", "ras_ahb_clk", 0, 1, | ||
265 | 1); | ||
266 | clk_register_clkdev(clk, NULL, "a6000000.spi"); | ||
267 | |||
268 | clk = clk_register_fixed_factor(NULL, "can0_clk", "ras_apb_clk", 0, 1, | ||
269 | 1); | ||
270 | clk_register_clkdev(clk, NULL, "c_can_platform.0"); | ||
271 | |||
272 | clk = clk_register_fixed_factor(NULL, "can1_clk", "ras_apb_clk", 0, 1, | ||
273 | 1); | ||
274 | clk_register_clkdev(clk, NULL, "c_can_platform.1"); | ||
275 | |||
276 | clk = clk_register_fixed_factor(NULL, "i2s_clk", "ras_apb_clk", 0, 1, | ||
277 | 1); | ||
278 | clk_register_clkdev(clk, NULL, "i2s"); | ||
279 | |||
280 | clk = clk_register_mux(NULL, "i2s_ref_clk", i2s_ref_parents, | ||
281 | ARRAY_SIZE(i2s_ref_parents), 0, SPEAR320_CONTROL_REG, | ||
282 | I2S_REF_PCLK_SHIFT, I2S_REF_PCLK_MASK, 0, &_lock); | ||
283 | clk_register_clkdev(clk, "i2s_ref_clk", NULL); | ||
284 | |||
285 | clk = clk_register_fixed_factor(NULL, "i2s_sclk", "i2s_ref_clk", 0, 1, | ||
286 | 4); | ||
287 | clk_register_clkdev(clk, "i2s_sclk", NULL); | ||
288 | |||
289 | clk = clk_register_mux(NULL, "rs485_clk", uartx_parents, | ||
290 | ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, | ||
291 | SPEAR320_RS485_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, | ||
292 | &_lock); | ||
293 | clk_register_clkdev(clk, NULL, "a9300000.serial"); | ||
294 | |||
295 | clk = clk_register_mux(NULL, "sdhci_clk", sdhci_parents, | ||
296 | ARRAY_SIZE(sdhci_parents), 0, SPEAR320_CONTROL_REG, | ||
297 | SDHCI_PCLK_SHIFT, SDHCI_PCLK_MASK, 0, &_lock); | ||
298 | clk_register_clkdev(clk, NULL, "70000000.sdhci"); | ||
299 | |||
300 | clk = clk_register_mux(NULL, "smii_pclk", smii0_parents, | ||
301 | ARRAY_SIZE(smii0_parents), 0, SPEAR320_CONTROL_REG, | ||
302 | SMII_PCLK_SHIFT, SMII_PCLK_MASK, 0, &_lock); | ||
303 | clk_register_clkdev(clk, NULL, "smii_pclk"); | ||
304 | |||
305 | clk = clk_register_fixed_factor(NULL, "smii_clk", "smii_pclk", 0, 1, 1); | ||
306 | clk_register_clkdev(clk, NULL, "smii"); | ||
307 | |||
308 | clk = clk_register_mux(NULL, "uart1_clk", uartx_parents, | ||
309 | ARRAY_SIZE(uartx_parents), 0, SPEAR320_CONTROL_REG, | ||
310 | UART1_PCLK_SHIFT, UART1_PCLK_MASK, 0, &_lock); | ||
311 | clk_register_clkdev(clk, NULL, "a3000000.serial"); | ||
312 | |||
313 | clk = clk_register_mux(NULL, "uart2_clk", uartx_parents, | ||
314 | ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, | ||
315 | SPEAR320_UART2_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, | ||
316 | &_lock); | ||
317 | clk_register_clkdev(clk, NULL, "a4000000.serial"); | ||
318 | |||
319 | clk = clk_register_mux(NULL, "uart3_clk", uartx_parents, | ||
320 | ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, | ||
321 | SPEAR320_UART3_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, | ||
322 | &_lock); | ||
323 | clk_register_clkdev(clk, NULL, "a9100000.serial"); | ||
324 | |||
325 | clk = clk_register_mux(NULL, "uart4_clk", uartx_parents, | ||
326 | ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, | ||
327 | SPEAR320_UART4_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, | ||
328 | &_lock); | ||
329 | clk_register_clkdev(clk, NULL, "a9200000.serial"); | ||
330 | |||
331 | clk = clk_register_mux(NULL, "uart5_clk", uartx_parents, | ||
332 | ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, | ||
333 | SPEAR320_UART5_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, | ||
334 | &_lock); | ||
335 | clk_register_clkdev(clk, NULL, "60000000.serial"); | ||
336 | |||
337 | clk = clk_register_mux(NULL, "uart6_clk", uartx_parents, | ||
338 | ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, | ||
339 | SPEAR320_UART6_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, | ||
340 | &_lock); | ||
341 | clk_register_clkdev(clk, NULL, "60100000.serial"); | ||
342 | } | ||
343 | #endif | ||
344 | |||
345 | void __init spear3xx_clk_init(void) | ||
346 | { | ||
347 | struct clk *clk, *clk1; | ||
348 | |||
349 | clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); | ||
350 | clk_register_clkdev(clk, "apb_pclk", NULL); | ||
351 | |||
352 | clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT, | ||
353 | 32000); | ||
354 | clk_register_clkdev(clk, "osc_32k_clk", NULL); | ||
355 | |||
356 | clk = clk_register_fixed_rate(NULL, "osc_24m_clk", NULL, CLK_IS_ROOT, | ||
357 | 24000000); | ||
358 | clk_register_clkdev(clk, "osc_24m_clk", NULL); | ||
359 | |||
360 | /* clock derived from 32 KHz osc clk */ | ||
361 | clk = clk_register_gate(NULL, "rtc-spear", "osc_32k_clk", 0, | ||
362 | PERIP1_CLK_ENB, RTC_CLK_ENB, 0, &_lock); | ||
363 | clk_register_clkdev(clk, NULL, "fc900000.rtc"); | ||
364 | |||
365 | /* clock derived from 24 MHz osc clk */ | ||
366 | clk = clk_register_fixed_rate(NULL, "pll3_48m_clk", "osc_24m_clk", 0, | ||
367 | 48000000); | ||
368 | clk_register_clkdev(clk, "pll3_48m_clk", NULL); | ||
369 | |||
370 | clk = clk_register_fixed_factor(NULL, "wdt_clk", "osc_24m_clk", 0, 1, | ||
371 | 1); | ||
372 | clk_register_clkdev(clk, NULL, "fc880000.wdt"); | ||
373 | |||
374 | clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, | ||
375 | "osc_24m_clk", 0, PLL1_CTR, PLL1_FRQ, pll_rtbl, | ||
376 | ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL); | ||
377 | clk_register_clkdev(clk, "vco1_clk", NULL); | ||
378 | clk_register_clkdev(clk1, "pll1_clk", NULL); | ||
379 | |||
380 | clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, | ||
381 | "osc_24m_clk", 0, PLL2_CTR, PLL2_FRQ, pll_rtbl, | ||
382 | ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL); | ||
383 | clk_register_clkdev(clk, "vco2_clk", NULL); | ||
384 | clk_register_clkdev(clk1, "pll2_clk", NULL); | ||
385 | |||
386 | /* clock derived from pll1 clk */ | ||
387 | clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk", 0, 1, 1); | ||
388 | clk_register_clkdev(clk, "cpu_clk", NULL); | ||
389 | |||
390 | clk = clk_register_divider(NULL, "ahb_clk", "pll1_clk", | ||
391 | CLK_SET_RATE_PARENT, CORE_CLK_CFG, HCLK_RATIO_SHIFT, | ||
392 | HCLK_RATIO_MASK, 0, &_lock); | ||
393 | clk_register_clkdev(clk, "ahb_clk", NULL); | ||
394 | |||
395 | clk = clk_register_aux("uart_synth_clk", "uart_synth_gate_clk", | ||
396 | "pll1_clk", 0, UART_CLK_SYNT, NULL, aux_rtbl, | ||
397 | ARRAY_SIZE(aux_rtbl), &_lock, &clk1); | ||
398 | clk_register_clkdev(clk, "uart_synth_clk", NULL); | ||
399 | clk_register_clkdev(clk1, "uart_synth_gate_clk", NULL); | ||
400 | |||
401 | clk = clk_register_mux(NULL, "uart0_mux_clk", uart0_parents, | ||
402 | ARRAY_SIZE(uart0_parents), 0, PERIP_CLK_CFG, | ||
403 | UART_CLK_SHIFT, UART_CLK_MASK, 0, &_lock); | ||
404 | clk_register_clkdev(clk, "uart0_mux_clk", NULL); | ||
405 | |||
406 | clk = clk_register_gate(NULL, "uart0", "uart0_mux_clk", 0, | ||
407 | PERIP1_CLK_ENB, UART_CLK_ENB, 0, &_lock); | ||
408 | clk_register_clkdev(clk, NULL, "d0000000.serial"); | ||
409 | |||
410 | clk = clk_register_aux("firda_synth_clk", "firda_synth_gate_clk", | ||
411 | "pll1_clk", 0, FIRDA_CLK_SYNT, NULL, aux_rtbl, | ||
412 | ARRAY_SIZE(aux_rtbl), &_lock, &clk1); | ||
413 | clk_register_clkdev(clk, "firda_synth_clk", NULL); | ||
414 | clk_register_clkdev(clk1, "firda_synth_gate_clk", NULL); | ||
415 | |||
416 | clk = clk_register_mux(NULL, "firda_mux_clk", firda_parents, | ||
417 | ARRAY_SIZE(firda_parents), 0, PERIP_CLK_CFG, | ||
418 | FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0, &_lock); | ||
419 | clk_register_clkdev(clk, "firda_mux_clk", NULL); | ||
420 | |||
421 | clk = clk_register_gate(NULL, "firda_clk", "firda_mux_clk", 0, | ||
422 | PERIP1_CLK_ENB, FIRDA_CLK_ENB, 0, &_lock); | ||
423 | clk_register_clkdev(clk, NULL, "firda"); | ||
424 | |||
425 | /* gpt clocks */ | ||
426 | clk_register_gpt("gpt0_synth_clk", "pll1_clk", 0, PRSC0_CLK_CFG, | ||
427 | gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); | ||
428 | clk = clk_register_mux(NULL, "gpt0_clk", gpt0_parents, | ||
429 | ARRAY_SIZE(gpt0_parents), 0, PERIP_CLK_CFG, | ||
430 | GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); | ||
431 | clk_register_clkdev(clk, NULL, "gpt0"); | ||
432 | |||
433 | clk_register_gpt("gpt1_synth_clk", "pll1_clk", 0, PRSC1_CLK_CFG, | ||
434 | gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); | ||
435 | clk = clk_register_mux(NULL, "gpt1_mux_clk", gpt1_parents, | ||
436 | ARRAY_SIZE(gpt1_parents), 0, PERIP_CLK_CFG, | ||
437 | GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); | ||
438 | clk_register_clkdev(clk, "gpt1_mux_clk", NULL); | ||
439 | clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mux_clk", 0, | ||
440 | PERIP1_CLK_ENB, GPT1_CLK_ENB, 0, &_lock); | ||
441 | clk_register_clkdev(clk, NULL, "gpt1"); | ||
442 | |||
443 | clk_register_gpt("gpt2_synth_clk", "pll1_clk", 0, PRSC2_CLK_CFG, | ||
444 | gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); | ||
445 | clk = clk_register_mux(NULL, "gpt2_mux_clk", gpt2_parents, | ||
446 | ARRAY_SIZE(gpt2_parents), 0, PERIP_CLK_CFG, | ||
447 | GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); | ||
448 | clk_register_clkdev(clk, "gpt2_mux_clk", NULL); | ||
449 | clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mux_clk", 0, | ||
450 | PERIP1_CLK_ENB, GPT2_CLK_ENB, 0, &_lock); | ||
451 | clk_register_clkdev(clk, NULL, "gpt2"); | ||
452 | |||
453 | /* general synths clocks */ | ||
454 | clk = clk_register_aux("gen0_synth_clk", "gen0_synth_gate_clk", | ||
455 | "pll1_clk", 0, GEN0_CLK_SYNT, NULL, aux_rtbl, | ||
456 | ARRAY_SIZE(aux_rtbl), &_lock, &clk1); | ||
457 | clk_register_clkdev(clk, "gen0_synth_clk", NULL); | ||
458 | clk_register_clkdev(clk1, "gen0_synth_gate_clk", NULL); | ||
459 | |||
460 | clk = clk_register_aux("gen1_synth_clk", "gen1_synth_gate_clk", | ||
461 | "pll1_clk", 0, GEN1_CLK_SYNT, NULL, aux_rtbl, | ||
462 | ARRAY_SIZE(aux_rtbl), &_lock, &clk1); | ||
463 | clk_register_clkdev(clk, "gen1_synth_clk", NULL); | ||
464 | clk_register_clkdev(clk1, "gen1_synth_gate_clk", NULL); | ||
465 | |||
466 | clk = clk_register_mux(NULL, "gen2_3_parent_clk", gen2_3_parents, | ||
467 | ARRAY_SIZE(gen2_3_parents), 0, CORE_CLK_CFG, | ||
468 | GEN_SYNTH2_3_CLK_SHIFT, GEN_SYNTH2_3_CLK_MASK, 0, | ||
469 | &_lock); | ||
470 | clk_register_clkdev(clk, "gen2_3_parent_clk", NULL); | ||
471 | |||
472 | clk = clk_register_aux("gen2_synth_clk", "gen2_synth_gate_clk", | ||
473 | "gen2_3_parent_clk", 0, GEN2_CLK_SYNT, NULL, aux_rtbl, | ||
474 | ARRAY_SIZE(aux_rtbl), &_lock, &clk1); | ||
475 | clk_register_clkdev(clk, "gen2_synth_clk", NULL); | ||
476 | clk_register_clkdev(clk1, "gen2_synth_gate_clk", NULL); | ||
477 | |||
478 | clk = clk_register_aux("gen3_synth_clk", "gen3_synth_gate_clk", | ||
479 | "gen2_3_parent_clk", 0, GEN3_CLK_SYNT, NULL, aux_rtbl, | ||
480 | ARRAY_SIZE(aux_rtbl), &_lock, &clk1); | ||
481 | clk_register_clkdev(clk, "gen3_synth_clk", NULL); | ||
482 | clk_register_clkdev(clk1, "gen3_synth_gate_clk", NULL); | ||
483 | |||
484 | /* clock derived from pll3 clk */ | ||
485 | clk = clk_register_gate(NULL, "usbh_clk", "pll3_48m_clk", 0, | ||
486 | PERIP1_CLK_ENB, USBH_CLK_ENB, 0, &_lock); | ||
487 | clk_register_clkdev(clk, "usbh_clk", NULL); | ||
488 | |||
489 | clk = clk_register_fixed_factor(NULL, "usbh.0_clk", "usbh_clk", 0, 1, | ||
490 | 1); | ||
491 | clk_register_clkdev(clk, "usbh.0_clk", NULL); | ||
492 | |||
493 | clk = clk_register_fixed_factor(NULL, "usbh.1_clk", "usbh_clk", 0, 1, | ||
494 | 1); | ||
495 | clk_register_clkdev(clk, "usbh.1_clk", NULL); | ||
496 | |||
497 | clk = clk_register_gate(NULL, "usbd_clk", "pll3_48m_clk", 0, | ||
498 | PERIP1_CLK_ENB, USBD_CLK_ENB, 0, &_lock); | ||
499 | clk_register_clkdev(clk, NULL, "designware_udc"); | ||
500 | |||
501 | /* clock derived from ahb clk */ | ||
502 | clk = clk_register_fixed_factor(NULL, "ahbmult2_clk", "ahb_clk", 0, 2, | ||
503 | 1); | ||
504 | clk_register_clkdev(clk, "ahbmult2_clk", NULL); | ||
505 | |||
506 | clk = clk_register_mux(NULL, "ddr_clk", ddr_parents, | ||
507 | ARRAY_SIZE(ddr_parents), 0, PLL_CLK_CFG, MCTR_CLK_SHIFT, | ||
508 | MCTR_CLK_MASK, 0, &_lock); | ||
509 | clk_register_clkdev(clk, "ddr_clk", NULL); | ||
510 | |||
511 | clk = clk_register_divider(NULL, "apb_clk", "ahb_clk", | ||
512 | CLK_SET_RATE_PARENT, CORE_CLK_CFG, PCLK_RATIO_SHIFT, | ||
513 | PCLK_RATIO_MASK, 0, &_lock); | ||
514 | clk_register_clkdev(clk, "apb_clk", NULL); | ||
515 | |||
516 | clk = clk_register_gate(NULL, "amem_clk", "ahb_clk", 0, AMEM_CLK_CFG, | ||
517 | AMEM_CLK_ENB, 0, &_lock); | ||
518 | clk_register_clkdev(clk, "amem_clk", NULL); | ||
519 | |||
520 | clk = clk_register_gate(NULL, "c3_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
521 | C3_CLK_ENB, 0, &_lock); | ||
522 | clk_register_clkdev(clk, NULL, "c3_clk"); | ||
523 | |||
524 | clk = clk_register_gate(NULL, "dma_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
525 | DMA_CLK_ENB, 0, &_lock); | ||
526 | clk_register_clkdev(clk, NULL, "fc400000.dma"); | ||
527 | |||
528 | clk = clk_register_gate(NULL, "gmac_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
529 | GMAC_CLK_ENB, 0, &_lock); | ||
530 | clk_register_clkdev(clk, NULL, "e0800000.eth"); | ||
531 | |||
532 | clk = clk_register_gate(NULL, "i2c0_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
533 | I2C_CLK_ENB, 0, &_lock); | ||
534 | clk_register_clkdev(clk, NULL, "d0180000.i2c"); | ||
535 | |||
536 | clk = clk_register_gate(NULL, "jpeg_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
537 | JPEG_CLK_ENB, 0, &_lock); | ||
538 | clk_register_clkdev(clk, NULL, "jpeg"); | ||
539 | |||
540 | clk = clk_register_gate(NULL, "smi_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
541 | SMI_CLK_ENB, 0, &_lock); | ||
542 | clk_register_clkdev(clk, NULL, "fc000000.flash"); | ||
543 | |||
544 | /* clock derived from apb clk */ | ||
545 | clk = clk_register_gate(NULL, "adc_clk", "apb_clk", 0, PERIP1_CLK_ENB, | ||
546 | ADC_CLK_ENB, 0, &_lock); | ||
547 | clk_register_clkdev(clk, NULL, "adc"); | ||
548 | |||
549 | clk = clk_register_gate(NULL, "gpio0_clk", "apb_clk", 0, PERIP1_CLK_ENB, | ||
550 | GPIO_CLK_ENB, 0, &_lock); | ||
551 | clk_register_clkdev(clk, NULL, "fc980000.gpio"); | ||
552 | |||
553 | clk = clk_register_gate(NULL, "ssp0_clk", "apb_clk", 0, PERIP1_CLK_ENB, | ||
554 | SSP_CLK_ENB, 0, &_lock); | ||
555 | clk_register_clkdev(clk, NULL, "d0100000.spi"); | ||
556 | |||
557 | /* RAS clk enable */ | ||
558 | clk = clk_register_gate(NULL, "ras_ahb_clk", "ahb_clk", 0, RAS_CLK_ENB, | ||
559 | RAS_AHB_CLK_ENB, 0, &_lock); | ||
560 | clk_register_clkdev(clk, "ras_ahb_clk", NULL); | ||
561 | |||
562 | clk = clk_register_gate(NULL, "ras_apb_clk", "apb_clk", 0, RAS_CLK_ENB, | ||
563 | RAS_APB_CLK_ENB, 0, &_lock); | ||
564 | clk_register_clkdev(clk, "ras_apb_clk", NULL); | ||
565 | |||
566 | clk = clk_register_gate(NULL, "ras_32k_clk", "osc_32k_clk", 0, | ||
567 | RAS_CLK_ENB, RAS_32K_CLK_ENB, 0, &_lock); | ||
568 | clk_register_clkdev(clk, "ras_32k_clk", NULL); | ||
569 | |||
570 | clk = clk_register_gate(NULL, "ras_24m_clk", "osc_24m_clk", 0, | ||
571 | RAS_CLK_ENB, RAS_24M_CLK_ENB, 0, &_lock); | ||
572 | clk_register_clkdev(clk, "ras_24m_clk", NULL); | ||
573 | |||
574 | clk = clk_register_gate(NULL, "ras_pll1_clk", "pll1_clk", 0, | ||
575 | RAS_CLK_ENB, RAS_PLL1_CLK_ENB, 0, &_lock); | ||
576 | clk_register_clkdev(clk, "ras_pll1_clk", NULL); | ||
577 | |||
578 | clk = clk_register_gate(NULL, "ras_pll2_clk", "pll2_clk", 0, | ||
579 | RAS_CLK_ENB, RAS_PLL2_CLK_ENB, 0, &_lock); | ||
580 | clk_register_clkdev(clk, "ras_pll2_clk", NULL); | ||
581 | |||
582 | clk = clk_register_gate(NULL, "ras_pll3_48m_clk", "pll3_48m_clk", 0, | ||
583 | RAS_CLK_ENB, RAS_48M_CLK_ENB, 0, &_lock); | ||
584 | clk_register_clkdev(clk, "ras_pll3_48m_clk", NULL); | ||
585 | |||
586 | clk = clk_register_gate(NULL, "ras_gen0_synth_gate_clk", | ||
587 | "gen0_synth_gate_clk", 0, RAS_CLK_ENB, | ||
588 | RAS_SYNT0_CLK_ENB, 0, &_lock); | ||
589 | clk_register_clkdev(clk, "ras_gen0_synth_gate_clk", NULL); | ||
590 | |||
591 | clk = clk_register_gate(NULL, "ras_gen1_synth_gate_clk", | ||
592 | "gen1_synth_gate_clk", 0, RAS_CLK_ENB, | ||
593 | RAS_SYNT1_CLK_ENB, 0, &_lock); | ||
594 | clk_register_clkdev(clk, "ras_gen1_synth_gate_clk", NULL); | ||
595 | |||
596 | clk = clk_register_gate(NULL, "ras_gen2_synth_gate_clk", | ||
597 | "gen2_synth_gate_clk", 0, RAS_CLK_ENB, | ||
598 | RAS_SYNT2_CLK_ENB, 0, &_lock); | ||
599 | clk_register_clkdev(clk, "ras_gen2_synth_gate_clk", NULL); | ||
600 | |||
601 | clk = clk_register_gate(NULL, "ras_gen3_synth_gate_clk", | ||
602 | "gen3_synth_gate_clk", 0, RAS_CLK_ENB, | ||
603 | RAS_SYNT3_CLK_ENB, 0, &_lock); | ||
604 | clk_register_clkdev(clk, "ras_gen3_synth_gate_clk", NULL); | ||
605 | |||
606 | if (of_machine_is_compatible("st,spear300")) | ||
607 | spear300_clk_init(); | ||
608 | else if (of_machine_is_compatible("st,spear310")) | ||
609 | spear310_clk_init(); | ||
610 | else if (of_machine_is_compatible("st,spear320")) | ||
611 | spear320_clk_init(); | ||
612 | } | ||
diff --git a/drivers/clk/spear/spear6xx_clock.c b/drivers/clk/spear/spear6xx_clock.c new file mode 100644 index 00000000000..f9a20b38230 --- /dev/null +++ b/drivers/clk/spear/spear6xx_clock.c | |||
@@ -0,0 +1,342 @@ | |||
1 | /* | ||
2 | * SPEAr6xx machines clock framework source file | ||
3 | * | ||
4 | * Copyright (C) 2012 ST Microelectronics | ||
5 | * Viresh Kumar <viresh.kumar@st.com> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public | ||
8 | * License version 2. This program is licensed "as is" without any | ||
9 | * warranty of any kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/clkdev.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/spinlock_types.h> | ||
16 | #include <mach/misc_regs.h> | ||
17 | #include "clk.h" | ||
18 | |||
19 | static DEFINE_SPINLOCK(_lock); | ||
20 | |||
21 | #define PLL1_CTR (MISC_BASE + 0x008) | ||
22 | #define PLL1_FRQ (MISC_BASE + 0x00C) | ||
23 | #define PLL2_CTR (MISC_BASE + 0x014) | ||
24 | #define PLL2_FRQ (MISC_BASE + 0x018) | ||
25 | #define PLL_CLK_CFG (MISC_BASE + 0x020) | ||
26 | /* PLL_CLK_CFG register masks */ | ||
27 | #define MCTR_CLK_SHIFT 28 | ||
28 | #define MCTR_CLK_MASK 3 | ||
29 | |||
30 | #define CORE_CLK_CFG (MISC_BASE + 0x024) | ||
31 | /* CORE CLK CFG register masks */ | ||
32 | #define HCLK_RATIO_SHIFT 10 | ||
33 | #define HCLK_RATIO_MASK 2 | ||
34 | #define PCLK_RATIO_SHIFT 8 | ||
35 | #define PCLK_RATIO_MASK 2 | ||
36 | |||
37 | #define PERIP_CLK_CFG (MISC_BASE + 0x028) | ||
38 | /* PERIP_CLK_CFG register masks */ | ||
39 | #define CLCD_CLK_SHIFT 2 | ||
40 | #define CLCD_CLK_MASK 2 | ||
41 | #define UART_CLK_SHIFT 4 | ||
42 | #define UART_CLK_MASK 1 | ||
43 | #define FIRDA_CLK_SHIFT 5 | ||
44 | #define FIRDA_CLK_MASK 2 | ||
45 | #define GPT0_CLK_SHIFT 8 | ||
46 | #define GPT1_CLK_SHIFT 10 | ||
47 | #define GPT2_CLK_SHIFT 11 | ||
48 | #define GPT3_CLK_SHIFT 12 | ||
49 | #define GPT_CLK_MASK 1 | ||
50 | |||
51 | #define PERIP1_CLK_ENB (MISC_BASE + 0x02C) | ||
52 | /* PERIP1_CLK_ENB register masks */ | ||
53 | #define UART0_CLK_ENB 3 | ||
54 | #define UART1_CLK_ENB 4 | ||
55 | #define SSP0_CLK_ENB 5 | ||
56 | #define SSP1_CLK_ENB 6 | ||
57 | #define I2C_CLK_ENB 7 | ||
58 | #define JPEG_CLK_ENB 8 | ||
59 | #define FSMC_CLK_ENB 9 | ||
60 | #define FIRDA_CLK_ENB 10 | ||
61 | #define GPT2_CLK_ENB 11 | ||
62 | #define GPT3_CLK_ENB 12 | ||
63 | #define GPIO2_CLK_ENB 13 | ||
64 | #define SSP2_CLK_ENB 14 | ||
65 | #define ADC_CLK_ENB 15 | ||
66 | #define GPT1_CLK_ENB 11 | ||
67 | #define RTC_CLK_ENB 17 | ||
68 | #define GPIO1_CLK_ENB 18 | ||
69 | #define DMA_CLK_ENB 19 | ||
70 | #define SMI_CLK_ENB 21 | ||
71 | #define CLCD_CLK_ENB 22 | ||
72 | #define GMAC_CLK_ENB 23 | ||
73 | #define USBD_CLK_ENB 24 | ||
74 | #define USBH0_CLK_ENB 25 | ||
75 | #define USBH1_CLK_ENB 26 | ||
76 | |||
77 | #define PRSC0_CLK_CFG (MISC_BASE + 0x044) | ||
78 | #define PRSC1_CLK_CFG (MISC_BASE + 0x048) | ||
79 | #define PRSC2_CLK_CFG (MISC_BASE + 0x04C) | ||
80 | |||
81 | #define CLCD_CLK_SYNT (MISC_BASE + 0x05C) | ||
82 | #define FIRDA_CLK_SYNT (MISC_BASE + 0x060) | ||
83 | #define UART_CLK_SYNT (MISC_BASE + 0x064) | ||
84 | |||
85 | /* vco rate configuration table, in ascending order of rates */ | ||
86 | static struct pll_rate_tbl pll_rtbl[] = { | ||
87 | {.mode = 0, .m = 0x53, .n = 0x0F, .p = 0x1}, /* vco 332 & pll 166 MHz */ | ||
88 | {.mode = 0, .m = 0x85, .n = 0x0F, .p = 0x1}, /* vco 532 & pll 266 MHz */ | ||
89 | {.mode = 0, .m = 0xA6, .n = 0x0F, .p = 0x1}, /* vco 664 & pll 332 MHz */ | ||
90 | }; | ||
91 | |||
92 | /* aux rate configuration table, in ascending order of rates */ | ||
93 | static struct aux_rate_tbl aux_rtbl[] = { | ||
94 | /* For PLL1 = 332 MHz */ | ||
95 | {.xscale = 2, .yscale = 8, .eq = 0}, /* 41.5 MHz */ | ||
96 | {.xscale = 2, .yscale = 4, .eq = 0}, /* 83 MHz */ | ||
97 | {.xscale = 1, .yscale = 2, .eq = 1}, /* 166 MHz */ | ||
98 | }; | ||
99 | |||
100 | static const char *clcd_parents[] = { "pll3_48m_clk", "clcd_synth_gate_clk", }; | ||
101 | static const char *firda_parents[] = { "pll3_48m_clk", "firda_synth_gate_clk", | ||
102 | }; | ||
103 | static const char *uart_parents[] = { "pll3_48m_clk", "uart_synth_gate_clk", }; | ||
104 | static const char *gpt0_1_parents[] = { "pll3_48m_clk", "gpt0_1_synth_clk", }; | ||
105 | static const char *gpt2_parents[] = { "pll3_48m_clk", "gpt2_synth_clk", }; | ||
106 | static const char *gpt3_parents[] = { "pll3_48m_clk", "gpt3_synth_clk", }; | ||
107 | static const char *ddr_parents[] = { "ahb_clk", "ahbmult2_clk", "none", | ||
108 | "pll2_clk", }; | ||
109 | |||
110 | /* gpt rate configuration table, in ascending order of rates */ | ||
111 | static struct gpt_rate_tbl gpt_rtbl[] = { | ||
112 | /* For pll1 = 332 MHz */ | ||
113 | {.mscale = 4, .nscale = 0}, /* 41.5 MHz */ | ||
114 | {.mscale = 2, .nscale = 0}, /* 55.3 MHz */ | ||
115 | {.mscale = 1, .nscale = 0}, /* 83 MHz */ | ||
116 | }; | ||
117 | |||
118 | void __init spear6xx_clk_init(void) | ||
119 | { | ||
120 | struct clk *clk, *clk1; | ||
121 | |||
122 | clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); | ||
123 | clk_register_clkdev(clk, "apb_pclk", NULL); | ||
124 | |||
125 | clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT, | ||
126 | 32000); | ||
127 | clk_register_clkdev(clk, "osc_32k_clk", NULL); | ||
128 | |||
129 | clk = clk_register_fixed_rate(NULL, "osc_30m_clk", NULL, CLK_IS_ROOT, | ||
130 | 30000000); | ||
131 | clk_register_clkdev(clk, "osc_30m_clk", NULL); | ||
132 | |||
133 | /* clock derived from 32 KHz osc clk */ | ||
134 | clk = clk_register_gate(NULL, "rtc_spear", "osc_32k_clk", 0, | ||
135 | PERIP1_CLK_ENB, RTC_CLK_ENB, 0, &_lock); | ||
136 | clk_register_clkdev(clk, NULL, "rtc-spear"); | ||
137 | |||
138 | /* clock derived from 30 MHz osc clk */ | ||
139 | clk = clk_register_fixed_rate(NULL, "pll3_48m_clk", "osc_24m_clk", 0, | ||
140 | 48000000); | ||
141 | clk_register_clkdev(clk, "pll3_48m_clk", NULL); | ||
142 | |||
143 | clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, "osc_30m_clk", | ||
144 | 0, PLL1_CTR, PLL1_FRQ, pll_rtbl, ARRAY_SIZE(pll_rtbl), | ||
145 | &_lock, &clk1, NULL); | ||
146 | clk_register_clkdev(clk, "vco1_clk", NULL); | ||
147 | clk_register_clkdev(clk1, "pll1_clk", NULL); | ||
148 | |||
149 | clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, | ||
150 | "osc_30m_clk", 0, PLL2_CTR, PLL2_FRQ, pll_rtbl, | ||
151 | ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL); | ||
152 | clk_register_clkdev(clk, "vco2_clk", NULL); | ||
153 | clk_register_clkdev(clk1, "pll2_clk", NULL); | ||
154 | |||
155 | clk = clk_register_fixed_factor(NULL, "wdt_clk", "osc_30m_clk", 0, 1, | ||
156 | 1); | ||
157 | clk_register_clkdev(clk, NULL, "wdt"); | ||
158 | |||
159 | /* clock derived from pll1 clk */ | ||
160 | clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk", 0, 1, 1); | ||
161 | clk_register_clkdev(clk, "cpu_clk", NULL); | ||
162 | |||
163 | clk = clk_register_divider(NULL, "ahb_clk", "pll1_clk", | ||
164 | CLK_SET_RATE_PARENT, CORE_CLK_CFG, HCLK_RATIO_SHIFT, | ||
165 | HCLK_RATIO_MASK, 0, &_lock); | ||
166 | clk_register_clkdev(clk, "ahb_clk", NULL); | ||
167 | |||
168 | clk = clk_register_aux("uart_synth_clk", "uart_synth_gate_clk", | ||
169 | "pll1_clk", 0, UART_CLK_SYNT, NULL, aux_rtbl, | ||
170 | ARRAY_SIZE(aux_rtbl), &_lock, &clk1); | ||
171 | clk_register_clkdev(clk, "uart_synth_clk", NULL); | ||
172 | clk_register_clkdev(clk1, "uart_synth_gate_clk", NULL); | ||
173 | |||
174 | clk = clk_register_mux(NULL, "uart_mux_clk", uart_parents, | ||
175 | ARRAY_SIZE(uart_parents), 0, PERIP_CLK_CFG, | ||
176 | UART_CLK_SHIFT, UART_CLK_MASK, 0, &_lock); | ||
177 | clk_register_clkdev(clk, "uart_mux_clk", NULL); | ||
178 | |||
179 | clk = clk_register_gate(NULL, "uart0", "uart_mux_clk", 0, | ||
180 | PERIP1_CLK_ENB, UART0_CLK_ENB, 0, &_lock); | ||
181 | clk_register_clkdev(clk, NULL, "d0000000.serial"); | ||
182 | |||
183 | clk = clk_register_gate(NULL, "uart1", "uart_mux_clk", 0, | ||
184 | PERIP1_CLK_ENB, UART1_CLK_ENB, 0, &_lock); | ||
185 | clk_register_clkdev(clk, NULL, "d0080000.serial"); | ||
186 | |||
187 | clk = clk_register_aux("firda_synth_clk", "firda_synth_gate_clk", | ||
188 | "pll1_clk", 0, FIRDA_CLK_SYNT, NULL, aux_rtbl, | ||
189 | ARRAY_SIZE(aux_rtbl), &_lock, &clk1); | ||
190 | clk_register_clkdev(clk, "firda_synth_clk", NULL); | ||
191 | clk_register_clkdev(clk1, "firda_synth_gate_clk", NULL); | ||
192 | |||
193 | clk = clk_register_mux(NULL, "firda_mux_clk", firda_parents, | ||
194 | ARRAY_SIZE(firda_parents), 0, PERIP_CLK_CFG, | ||
195 | FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0, &_lock); | ||
196 | clk_register_clkdev(clk, "firda_mux_clk", NULL); | ||
197 | |||
198 | clk = clk_register_gate(NULL, "firda_clk", "firda_mux_clk", 0, | ||
199 | PERIP1_CLK_ENB, FIRDA_CLK_ENB, 0, &_lock); | ||
200 | clk_register_clkdev(clk, NULL, "firda"); | ||
201 | |||
202 | clk = clk_register_aux("clcd_synth_clk", "clcd_synth_gate_clk", | ||
203 | "pll1_clk", 0, CLCD_CLK_SYNT, NULL, aux_rtbl, | ||
204 | ARRAY_SIZE(aux_rtbl), &_lock, &clk1); | ||
205 | clk_register_clkdev(clk, "clcd_synth_clk", NULL); | ||
206 | clk_register_clkdev(clk1, "clcd_synth_gate_clk", NULL); | ||
207 | |||
208 | clk = clk_register_mux(NULL, "clcd_mux_clk", clcd_parents, | ||
209 | ARRAY_SIZE(clcd_parents), 0, PERIP_CLK_CFG, | ||
210 | CLCD_CLK_SHIFT, CLCD_CLK_MASK, 0, &_lock); | ||
211 | clk_register_clkdev(clk, "clcd_mux_clk", NULL); | ||
212 | |||
213 | clk = clk_register_gate(NULL, "clcd_clk", "clcd_mux_clk", 0, | ||
214 | PERIP1_CLK_ENB, CLCD_CLK_ENB, 0, &_lock); | ||
215 | clk_register_clkdev(clk, NULL, "clcd"); | ||
216 | |||
217 | /* gpt clocks */ | ||
218 | clk = clk_register_gpt("gpt0_1_synth_clk", "pll1_clk", 0, PRSC0_CLK_CFG, | ||
219 | gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); | ||
220 | clk_register_clkdev(clk, "gpt0_1_synth_clk", NULL); | ||
221 | |||
222 | clk = clk_register_mux(NULL, "gpt0_mux_clk", gpt0_1_parents, | ||
223 | ARRAY_SIZE(gpt0_1_parents), 0, PERIP_CLK_CFG, | ||
224 | GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); | ||
225 | clk_register_clkdev(clk, NULL, "gpt0"); | ||
226 | |||
227 | clk = clk_register_mux(NULL, "gpt1_mux_clk", gpt0_1_parents, | ||
228 | ARRAY_SIZE(gpt0_1_parents), 0, PERIP_CLK_CFG, | ||
229 | GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); | ||
230 | clk_register_clkdev(clk, "gpt1_mux_clk", NULL); | ||
231 | |||
232 | clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mux_clk", 0, | ||
233 | PERIP1_CLK_ENB, GPT1_CLK_ENB, 0, &_lock); | ||
234 | clk_register_clkdev(clk, NULL, "gpt1"); | ||
235 | |||
236 | clk = clk_register_gpt("gpt2_synth_clk", "pll1_clk", 0, PRSC1_CLK_CFG, | ||
237 | gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); | ||
238 | clk_register_clkdev(clk, "gpt2_synth_clk", NULL); | ||
239 | |||
240 | clk = clk_register_mux(NULL, "gpt2_mux_clk", gpt2_parents, | ||
241 | ARRAY_SIZE(gpt2_parents), 0, PERIP_CLK_CFG, | ||
242 | GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); | ||
243 | clk_register_clkdev(clk, "gpt2_mux_clk", NULL); | ||
244 | |||
245 | clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mux_clk", 0, | ||
246 | PERIP1_CLK_ENB, GPT2_CLK_ENB, 0, &_lock); | ||
247 | clk_register_clkdev(clk, NULL, "gpt2"); | ||
248 | |||
249 | clk = clk_register_gpt("gpt3_synth_clk", "pll1_clk", 0, PRSC2_CLK_CFG, | ||
250 | gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); | ||
251 | clk_register_clkdev(clk, "gpt3_synth_clk", NULL); | ||
252 | |||
253 | clk = clk_register_mux(NULL, "gpt3_mux_clk", gpt3_parents, | ||
254 | ARRAY_SIZE(gpt3_parents), 0, PERIP_CLK_CFG, | ||
255 | GPT3_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); | ||
256 | clk_register_clkdev(clk, "gpt3_mux_clk", NULL); | ||
257 | |||
258 | clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mux_clk", 0, | ||
259 | PERIP1_CLK_ENB, GPT3_CLK_ENB, 0, &_lock); | ||
260 | clk_register_clkdev(clk, NULL, "gpt3"); | ||
261 | |||
262 | /* clock derived from pll3 clk */ | ||
263 | clk = clk_register_gate(NULL, "usbh0_clk", "pll3_48m_clk", 0, | ||
264 | PERIP1_CLK_ENB, USBH0_CLK_ENB, 0, &_lock); | ||
265 | clk_register_clkdev(clk, NULL, "usbh.0_clk"); | ||
266 | |||
267 | clk = clk_register_gate(NULL, "usbh1_clk", "pll3_48m_clk", 0, | ||
268 | PERIP1_CLK_ENB, USBH1_CLK_ENB, 0, &_lock); | ||
269 | clk_register_clkdev(clk, NULL, "usbh.1_clk"); | ||
270 | |||
271 | clk = clk_register_gate(NULL, "usbd_clk", "pll3_48m_clk", 0, | ||
272 | PERIP1_CLK_ENB, USBD_CLK_ENB, 0, &_lock); | ||
273 | clk_register_clkdev(clk, NULL, "designware_udc"); | ||
274 | |||
275 | /* clock derived from ahb clk */ | ||
276 | clk = clk_register_fixed_factor(NULL, "ahbmult2_clk", "ahb_clk", 0, 2, | ||
277 | 1); | ||
278 | clk_register_clkdev(clk, "ahbmult2_clk", NULL); | ||
279 | |||
280 | clk = clk_register_mux(NULL, "ddr_clk", ddr_parents, | ||
281 | ARRAY_SIZE(ddr_parents), | ||
282 | 0, PLL_CLK_CFG, MCTR_CLK_SHIFT, MCTR_CLK_MASK, 0, | ||
283 | &_lock); | ||
284 | clk_register_clkdev(clk, "ddr_clk", NULL); | ||
285 | |||
286 | clk = clk_register_divider(NULL, "apb_clk", "ahb_clk", | ||
287 | CLK_SET_RATE_PARENT, CORE_CLK_CFG, PCLK_RATIO_SHIFT, | ||
288 | PCLK_RATIO_MASK, 0, &_lock); | ||
289 | clk_register_clkdev(clk, "apb_clk", NULL); | ||
290 | |||
291 | clk = clk_register_gate(NULL, "dma_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
292 | DMA_CLK_ENB, 0, &_lock); | ||
293 | clk_register_clkdev(clk, NULL, "fc400000.dma"); | ||
294 | |||
295 | clk = clk_register_gate(NULL, "fsmc_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
296 | FSMC_CLK_ENB, 0, &_lock); | ||
297 | clk_register_clkdev(clk, NULL, "d1800000.flash"); | ||
298 | |||
299 | clk = clk_register_gate(NULL, "gmac_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
300 | GMAC_CLK_ENB, 0, &_lock); | ||
301 | clk_register_clkdev(clk, NULL, "gmac"); | ||
302 | |||
303 | clk = clk_register_gate(NULL, "i2c_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
304 | I2C_CLK_ENB, 0, &_lock); | ||
305 | clk_register_clkdev(clk, NULL, "d0200000.i2c"); | ||
306 | |||
307 | clk = clk_register_gate(NULL, "jpeg_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
308 | JPEG_CLK_ENB, 0, &_lock); | ||
309 | clk_register_clkdev(clk, NULL, "jpeg"); | ||
310 | |||
311 | clk = clk_register_gate(NULL, "smi_clk", "ahb_clk", 0, PERIP1_CLK_ENB, | ||
312 | SMI_CLK_ENB, 0, &_lock); | ||
313 | clk_register_clkdev(clk, NULL, "fc000000.flash"); | ||
314 | |||
315 | /* clock derived from apb clk */ | ||
316 | clk = clk_register_gate(NULL, "adc_clk", "apb_clk", 0, PERIP1_CLK_ENB, | ||
317 | ADC_CLK_ENB, 0, &_lock); | ||
318 | clk_register_clkdev(clk, NULL, "adc"); | ||
319 | |||
320 | clk = clk_register_fixed_factor(NULL, "gpio0_clk", "apb_clk", 0, 1, 1); | ||
321 | clk_register_clkdev(clk, NULL, "f0100000.gpio"); | ||
322 | |||
323 | clk = clk_register_gate(NULL, "gpio1_clk", "apb_clk", 0, PERIP1_CLK_ENB, | ||
324 | GPIO1_CLK_ENB, 0, &_lock); | ||
325 | clk_register_clkdev(clk, NULL, "fc980000.gpio"); | ||
326 | |||
327 | clk = clk_register_gate(NULL, "gpio2_clk", "apb_clk", 0, PERIP1_CLK_ENB, | ||
328 | GPIO2_CLK_ENB, 0, &_lock); | ||
329 | clk_register_clkdev(clk, NULL, "d8100000.gpio"); | ||
330 | |||
331 | clk = clk_register_gate(NULL, "ssp0_clk", "apb_clk", 0, PERIP1_CLK_ENB, | ||
332 | SSP0_CLK_ENB, 0, &_lock); | ||
333 | clk_register_clkdev(clk, NULL, "ssp-pl022.0"); | ||
334 | |||
335 | clk = clk_register_gate(NULL, "ssp1_clk", "apb_clk", 0, PERIP1_CLK_ENB, | ||
336 | SSP1_CLK_ENB, 0, &_lock); | ||
337 | clk_register_clkdev(clk, NULL, "ssp-pl022.1"); | ||
338 | |||
339 | clk = clk_register_gate(NULL, "ssp2_clk", "apb_clk", 0, PERIP1_CLK_ENB, | ||
340 | SSP2_CLK_ENB, 0, &_lock); | ||
341 | clk_register_clkdev(clk, NULL, "ssp-pl022.2"); | ||
342 | } | ||