aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/mvebu
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-01-23 21:56:08 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-01-23 21:56:08 -0500
commit7e21774db5cc9cf8fe93a64a2f0c6cf47db8ab24 (patch)
tree460812792bc3b23789a83968b7bad840cc3eb047 /drivers/clk/mvebu
parent0ba3307a8ec35252f7b1e222e32889a6f3d9ceb3 (diff)
parent2e84d75116c17c2034e917b411250d2d11755435 (diff)
Merge tag 'clk-for-linus-3.14-part1' of git://git.linaro.org/people/mike.turquette/linux
Pull clk framework changes from Mike Turquette: "The first half of the clk framework pull request is made up almost entirely of new platform/driver support. There are some conversions of existing drivers to the common-clock Device Tree binding, and a few non-critical fixes to the framework. Due to an entirely unnecessary cyclical dependency with the arm-soc tree this pull request is broken into two pieces. The second piece will be sent out after arm-soc sends you the pull request that merged in core support for the HiSilicon 3620 platform. That same pull request from arm-soc depends on this pull request to merge in those HiSilicon bits without causing build failures" [ Just did the ARM SoC merges, so getting ready for the second clk tree pull request - Linus ] * tag 'clk-for-linus-3.14-part1' of git://git.linaro.org/people/mike.turquette/linux: (97 commits) devicetree: bindings: Document qcom,mmcc devicetree: bindings: Document qcom,gcc clk: qcom: Add support for MSM8660's global clock controller (GCC) clk: qcom: Add support for MSM8974's multimedia clock controller (MMCC) clk: qcom: Add support for MSM8974's global clock controller (GCC) clk: qcom: Add support for MSM8960's multimedia clock controller (MMCC) clk: qcom: Add support for MSM8960's global clock controller (GCC) clk: qcom: Add reset controller support clk: qcom: Add support for branches/gate clocks clk: qcom: Add support for root clock generators (RCGs) clk: qcom: Add support for phase locked loops (PLLs) clk: qcom: Add a regmap type clock struct clk: Add set_rate_and_parent() op reset: Silence warning in reset-controller.h clk: sirf: re-arch to make the codes support both prima2 and atlas6 clk: composite: pass mux_hw into determine_rate clk: shmobile: Fix MSTP clock array initialization clk: shmobile: Fix MSTP clock index ARM: dts: Add clock provider specific properties to max77686 node clk: max77686: Register OF clock provider ...
Diffstat (limited to 'drivers/clk/mvebu')
-rw-r--r--drivers/clk/mvebu/Kconfig5
-rw-r--r--drivers/clk/mvebu/Makefile1
-rw-r--r--drivers/clk/mvebu/clk-corediv.c223
-rw-r--r--drivers/clk/mvebu/clk-cpu.c2
4 files changed, 230 insertions, 1 deletions
diff --git a/drivers/clk/mvebu/Kconfig b/drivers/clk/mvebu/Kconfig
index 0b0f3e729cf7..c339b829d3e3 100644
--- a/drivers/clk/mvebu/Kconfig
+++ b/drivers/clk/mvebu/Kconfig
@@ -4,15 +4,20 @@ config MVEBU_CLK_COMMON
4config MVEBU_CLK_CPU 4config MVEBU_CLK_CPU
5 bool 5 bool
6 6
7config MVEBU_CLK_COREDIV
8 bool
9
7config ARMADA_370_CLK 10config ARMADA_370_CLK
8 bool 11 bool
9 select MVEBU_CLK_COMMON 12 select MVEBU_CLK_COMMON
10 select MVEBU_CLK_CPU 13 select MVEBU_CLK_CPU
14 select MVEBU_CLK_COREDIV
11 15
12config ARMADA_XP_CLK 16config ARMADA_XP_CLK
13 bool 17 bool
14 select MVEBU_CLK_COMMON 18 select MVEBU_CLK_COMMON
15 select MVEBU_CLK_CPU 19 select MVEBU_CLK_CPU
20 select MVEBU_CLK_COREDIV
16 21
17config DOVE_CLK 22config DOVE_CLK
18 bool 23 bool
diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile
index 1c7e70c63fb2..21bbfb4a9f42 100644
--- a/drivers/clk/mvebu/Makefile
+++ b/drivers/clk/mvebu/Makefile
@@ -1,5 +1,6 @@
1obj-$(CONFIG_MVEBU_CLK_COMMON) += common.o 1obj-$(CONFIG_MVEBU_CLK_COMMON) += common.o
2obj-$(CONFIG_MVEBU_CLK_CPU) += clk-cpu.o 2obj-$(CONFIG_MVEBU_CLK_CPU) += clk-cpu.o
3obj-$(CONFIG_MVEBU_CLK_COREDIV) += clk-corediv.o
3 4
4obj-$(CONFIG_ARMADA_370_CLK) += armada-370.o 5obj-$(CONFIG_ARMADA_370_CLK) += armada-370.o
5obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o 6obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o
diff --git a/drivers/clk/mvebu/clk-corediv.c b/drivers/clk/mvebu/clk-corediv.c
new file mode 100644
index 000000000000..7162615bcdcd
--- /dev/null
+++ b/drivers/clk/mvebu/clk-corediv.c
@@ -0,0 +1,223 @@
1/*
2 * MVEBU Core divider clock
3 *
4 * Copyright (C) 2013 Marvell
5 *
6 * Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
7 *
8 * This file is licensed under the terms of the GNU General Public
9 * License version 2. This program is licensed "as is" without any
10 * warranty of any kind, whether express or implied.
11 */
12
13#include <linux/kernel.h>
14#include <linux/clk-provider.h>
15#include <linux/of_address.h>
16#include <linux/slab.h>
17#include <linux/delay.h>
18#include "common.h"
19
20#define CORE_CLK_DIV_RATIO_MASK 0xff
21#define CORE_CLK_DIV_RATIO_RELOAD BIT(8)
22#define CORE_CLK_DIV_ENABLE_OFFSET 24
23#define CORE_CLK_DIV_RATIO_OFFSET 0x8
24
25struct clk_corediv_desc {
26 unsigned int mask;
27 unsigned int offset;
28 unsigned int fieldbit;
29};
30
31struct clk_corediv {
32 struct clk_hw hw;
33 void __iomem *reg;
34 struct clk_corediv_desc desc;
35 spinlock_t lock;
36};
37
38static struct clk_onecell_data clk_data;
39
40static const struct clk_corediv_desc mvebu_corediv_desc[] __initconst = {
41 { .mask = 0x3f, .offset = 8, .fieldbit = 1 }, /* NAND clock */
42};
43
44#define to_corediv_clk(p) container_of(p, struct clk_corediv, hw)
45
46static int clk_corediv_is_enabled(struct clk_hw *hwclk)
47{
48 struct clk_corediv *corediv = to_corediv_clk(hwclk);
49 struct clk_corediv_desc *desc = &corediv->desc;
50 u32 enable_mask = BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET;
51
52 return !!(readl(corediv->reg) & enable_mask);
53}
54
55static int clk_corediv_enable(struct clk_hw *hwclk)
56{
57 struct clk_corediv *corediv = to_corediv_clk(hwclk);
58 struct clk_corediv_desc *desc = &corediv->desc;
59 unsigned long flags = 0;
60 u32 reg;
61
62 spin_lock_irqsave(&corediv->lock, flags);
63
64 reg = readl(corediv->reg);
65 reg |= (BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET);
66 writel(reg, corediv->reg);
67
68 spin_unlock_irqrestore(&corediv->lock, flags);
69
70 return 0;
71}
72
73static void clk_corediv_disable(struct clk_hw *hwclk)
74{
75 struct clk_corediv *corediv = to_corediv_clk(hwclk);
76 struct clk_corediv_desc *desc = &corediv->desc;
77 unsigned long flags = 0;
78 u32 reg;
79
80 spin_lock_irqsave(&corediv->lock, flags);
81
82 reg = readl(corediv->reg);
83 reg &= ~(BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET);
84 writel(reg, corediv->reg);
85
86 spin_unlock_irqrestore(&corediv->lock, flags);
87}
88
89static unsigned long clk_corediv_recalc_rate(struct clk_hw *hwclk,
90 unsigned long parent_rate)
91{
92 struct clk_corediv *corediv = to_corediv_clk(hwclk);
93 struct clk_corediv_desc *desc = &corediv->desc;
94 u32 reg, div;
95
96 reg = readl(corediv->reg + CORE_CLK_DIV_RATIO_OFFSET);
97 div = (reg >> desc->offset) & desc->mask;
98 return parent_rate / div;
99}
100
101static long clk_corediv_round_rate(struct clk_hw *hwclk, unsigned long rate,
102 unsigned long *parent_rate)
103{
104 /* Valid ratio are 1:4, 1:5, 1:6 and 1:8 */
105 u32 div;
106
107 div = *parent_rate / rate;
108 if (div < 4)
109 div = 4;
110 else if (div > 6)
111 div = 8;
112
113 return *parent_rate / div;
114}
115
116static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate,
117 unsigned long parent_rate)
118{
119 struct clk_corediv *corediv = to_corediv_clk(hwclk);
120 struct clk_corediv_desc *desc = &corediv->desc;
121 unsigned long flags = 0;
122 u32 reg, div;
123
124 div = parent_rate / rate;
125
126 spin_lock_irqsave(&corediv->lock, flags);
127
128 /* Write new divider to the divider ratio register */
129 reg = readl(corediv->reg + CORE_CLK_DIV_RATIO_OFFSET);
130 reg &= ~(desc->mask << desc->offset);
131 reg |= (div & desc->mask) << desc->offset;
132 writel(reg, corediv->reg + CORE_CLK_DIV_RATIO_OFFSET);
133
134 /* Set reload-force for this clock */
135 reg = readl(corediv->reg) | BIT(desc->fieldbit);
136 writel(reg, corediv->reg);
137
138 /* Now trigger the clock update */
139 reg = readl(corediv->reg) | CORE_CLK_DIV_RATIO_RELOAD;
140 writel(reg, corediv->reg);
141
142 /*
143 * Wait for clocks to settle down, and then clear all the
144 * ratios request and the reload request.
145 */
146 udelay(1000);
147 reg &= ~(CORE_CLK_DIV_RATIO_MASK | CORE_CLK_DIV_RATIO_RELOAD);
148 writel(reg, corediv->reg);
149 udelay(1000);
150
151 spin_unlock_irqrestore(&corediv->lock, flags);
152
153 return 0;
154}
155
156static const struct clk_ops corediv_ops = {
157 .enable = clk_corediv_enable,
158 .disable = clk_corediv_disable,
159 .is_enabled = clk_corediv_is_enabled,
160 .recalc_rate = clk_corediv_recalc_rate,
161 .round_rate = clk_corediv_round_rate,
162 .set_rate = clk_corediv_set_rate,
163};
164
165static void __init mvebu_corediv_clk_init(struct device_node *node)
166{
167 struct clk_init_data init;
168 struct clk_corediv *corediv;
169 struct clk **clks;
170 void __iomem *base;
171 const char *parent_name;
172 const char *clk_name;
173 int i;
174
175 base = of_iomap(node, 0);
176 if (WARN_ON(!base))
177 return;
178
179 parent_name = of_clk_get_parent_name(node, 0);
180
181 clk_data.clk_num = ARRAY_SIZE(mvebu_corediv_desc);
182
183 /* clks holds the clock array */
184 clks = kcalloc(clk_data.clk_num, sizeof(struct clk *),
185 GFP_KERNEL);
186 if (WARN_ON(!clks))
187 goto err_unmap;
188 /* corediv holds the clock specific array */
189 corediv = kcalloc(clk_data.clk_num, sizeof(struct clk_corediv),
190 GFP_KERNEL);
191 if (WARN_ON(!corediv))
192 goto err_free_clks;
193
194 spin_lock_init(&corediv->lock);
195
196 for (i = 0; i < clk_data.clk_num; i++) {
197 of_property_read_string_index(node, "clock-output-names",
198 i, &clk_name);
199 init.num_parents = 1;
200 init.parent_names = &parent_name;
201 init.name = clk_name;
202 init.ops = &corediv_ops;
203 init.flags = 0;
204
205 corediv[i].desc = mvebu_corediv_desc[i];
206 corediv[i].reg = base;
207 corediv[i].hw.init = &init;
208
209 clks[i] = clk_register(NULL, &corediv[i].hw);
210 WARN_ON(IS_ERR(clks[i]));
211 }
212
213 clk_data.clks = clks;
214 of_clk_add_provider(node, of_clk_src_onecell_get, &clk_data);
215 return;
216
217err_free_clks:
218 kfree(clks);
219err_unmap:
220 iounmap(base);
221}
222CLK_OF_DECLARE(mvebu_corediv_clk, "marvell,armada-370-corediv-clock",
223 mvebu_corediv_clk_init);
diff --git a/drivers/clk/mvebu/clk-cpu.c b/drivers/clk/mvebu/clk-cpu.c
index 1466865b0743..8ebf757d29e2 100644
--- a/drivers/clk/mvebu/clk-cpu.c
+++ b/drivers/clk/mvebu/clk-cpu.c
@@ -101,7 +101,7 @@ static const struct clk_ops cpu_ops = {
101 .set_rate = clk_cpu_set_rate, 101 .set_rate = clk_cpu_set_rate,
102}; 102};
103 103
104void __init of_cpu_clk_setup(struct device_node *node) 104static void __init of_cpu_clk_setup(struct device_node *node)
105{ 105{
106 struct cpu_clk *cpuclk; 106 struct cpu_clk *cpuclk;
107 void __iomem *clock_complex_base = of_iomap(node, 0); 107 void __iomem *clock_complex_base = of_iomap(node, 0);