base-files: define yes/no as valid boolean options
[openwrt.git] / target / linux / mvebu / patches-3.10 / 0096-clk-mvebu-Add-Core-Divider-clock.patch
1 From ac8294dfb4085f3193bec27673062e5ad63d770a Mon Sep 17 00:00:00 2001
2 From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
3 Date: Thu, 26 Sep 2013 16:35:27 -0300
4 Subject: [PATCH 096/203] clk: mvebu: Add Core Divider clock
5
6 This commit introduces a new group of clocks present in Armada 370/XP
7 SoCs (called "Core Divider" clocks) and add a provider for them.
8 The only clock supported for now is the NAND clock (ndclk), but the
9 infrastructure to add the rest is already set.
10
11 Reviewed-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
12 Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
13 Signed-off-by: Mike Turquette <mturquette@linaro.org>
14 ---
15  arch/arm/mach-mvebu/Kconfig     |   1 +
16  drivers/clk/mvebu/Kconfig       |   3 +
17  drivers/clk/mvebu/Makefile      |   1 +
18  drivers/clk/mvebu/clk-corediv.c | 223 ++++++++++++++++++++++++++++++++++++++++
19  4 files changed, 228 insertions(+)
20  create mode 100644 drivers/clk/mvebu/clk-corediv.c
21
22 --- a/arch/arm/mach-mvebu/Kconfig
23 +++ b/arch/arm/mach-mvebu/Kconfig
24 @@ -13,6 +13,7 @@ config ARCH_MVEBU
25         select MVEBU_CLK_CORE
26         select MVEBU_CLK_CPU
27         select MVEBU_CLK_GATING
28 +       select MVEBU_CLK_COREDIV
29         select MVEBU_MBUS
30         select ZONE_DMA if ARM_LPAE
31         select ARCH_REQUIRE_GPIOLIB
32 --- a/drivers/clk/mvebu/Kconfig
33 +++ b/drivers/clk/mvebu/Kconfig
34 @@ -6,3 +6,6 @@ config MVEBU_CLK_CPU
35  
36  config MVEBU_CLK_GATING
37         bool
38 +
39 +config MVEBU_CLK_COREDIV
40 +       bool
41 --- a/drivers/clk/mvebu/Makefile
42 +++ b/drivers/clk/mvebu/Makefile
43 @@ -1,3 +1,4 @@
44  obj-$(CONFIG_MVEBU_CLK_CORE)   += clk.o clk-core.o
45  obj-$(CONFIG_MVEBU_CLK_CPU)    += clk-cpu.o
46  obj-$(CONFIG_MVEBU_CLK_GATING)         += clk-gating-ctrl.o
47 +obj-$(CONFIG_MVEBU_CLK_COREDIV)        += clk-corediv.o
48 --- /dev/null
49 +++ b/drivers/clk/mvebu/clk-corediv.c
50 @@ -0,0 +1,223 @@
51 +/*
52 + * MVEBU Core divider clock
53 + *
54 + * Copyright (C) 2013 Marvell
55 + *
56 + * Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
57 + *
58 + * This file is licensed under the terms of the GNU General Public
59 + * License version 2.  This program is licensed "as is" without any
60 + * warranty of any kind, whether express or implied.
61 + */
62 +
63 +#include <linux/kernel.h>
64 +#include <linux/clk-provider.h>
65 +#include <linux/of_address.h>
66 +#include <linux/slab.h>
67 +#include <linux/delay.h>
68 +#include <asm/io.h>
69 +
70 +#define CORE_CLK_DIV_RATIO_MASK                0xff
71 +#define CORE_CLK_DIV_RATIO_RELOAD      BIT(8)
72 +#define CORE_CLK_DIV_ENABLE_OFFSET     24
73 +#define CORE_CLK_DIV_RATIO_OFFSET      0x8
74 +
75 +struct clk_corediv_desc {
76 +       unsigned int mask;
77 +       unsigned int offset;
78 +       unsigned int fieldbit;
79 +};
80 +
81 +struct clk_corediv {
82 +       struct clk_hw hw;
83 +       void __iomem *reg;
84 +       struct clk_corediv_desc desc;
85 +       spinlock_t lock;
86 +};
87 +
88 +static struct clk_onecell_data clk_data;
89 +
90 +static const struct clk_corediv_desc mvebu_corediv_desc[] __initconst = {
91 +       { .mask = 0x3f, .offset = 8, .fieldbit = 1 }, /* NAND clock */
92 +};
93 +
94 +#define to_corediv_clk(p) container_of(p, struct clk_corediv, hw)
95 +
96 +static int clk_corediv_is_enabled(struct clk_hw *hwclk)
97 +{
98 +       struct clk_corediv *corediv = to_corediv_clk(hwclk);
99 +       struct clk_corediv_desc *desc = &corediv->desc;
100 +       u32 enable_mask = BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET;
101 +
102 +       return !!(readl(corediv->reg) & enable_mask);
103 +}
104 +
105 +static int clk_corediv_enable(struct clk_hw *hwclk)
106 +{
107 +       struct clk_corediv *corediv = to_corediv_clk(hwclk);
108 +       struct clk_corediv_desc *desc = &corediv->desc;
109 +       unsigned long flags = 0;
110 +       u32 reg;
111 +
112 +       spin_lock_irqsave(&corediv->lock, flags);
113 +
114 +       reg = readl(corediv->reg);
115 +       reg |= (BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET);
116 +       writel(reg, corediv->reg);
117 +
118 +       spin_unlock_irqrestore(&corediv->lock, flags);
119 +
120 +       return 0;
121 +}
122 +
123 +static void clk_corediv_disable(struct clk_hw *hwclk)
124 +{
125 +       struct clk_corediv *corediv = to_corediv_clk(hwclk);
126 +       struct clk_corediv_desc *desc = &corediv->desc;
127 +       unsigned long flags = 0;
128 +       u32 reg;
129 +
130 +       spin_lock_irqsave(&corediv->lock, flags);
131 +
132 +       reg = readl(corediv->reg);
133 +       reg &= ~(BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET);
134 +       writel(reg, corediv->reg);
135 +
136 +       spin_unlock_irqrestore(&corediv->lock, flags);
137 +}
138 +
139 +static unsigned long clk_corediv_recalc_rate(struct clk_hw *hwclk,
140 +                                        unsigned long parent_rate)
141 +{
142 +       struct clk_corediv *corediv = to_corediv_clk(hwclk);
143 +       struct clk_corediv_desc *desc = &corediv->desc;
144 +       u32 reg, div;
145 +
146 +       reg = readl(corediv->reg + CORE_CLK_DIV_RATIO_OFFSET);
147 +       div = (reg >> desc->offset) & desc->mask;
148 +       return parent_rate / div;
149 +}
150 +
151 +static long clk_corediv_round_rate(struct clk_hw *hwclk, unsigned long rate,
152 +                              unsigned long *parent_rate)
153 +{
154 +       /* Valid ratio are 1:4, 1:5, 1:6 and 1:8 */
155 +       u32 div;
156 +
157 +       div = *parent_rate / rate;
158 +       if (div < 4)
159 +               div = 4;
160 +       else if (div > 6)
161 +               div = 8;
162 +
163 +       return *parent_rate / div;
164 +}
165 +
166 +static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate,
167 +                           unsigned long parent_rate)
168 +{
169 +       struct clk_corediv *corediv = to_corediv_clk(hwclk);
170 +       struct clk_corediv_desc *desc = &corediv->desc;
171 +       unsigned long flags = 0;
172 +       u32 reg, div;
173 +
174 +       div = parent_rate / rate;
175 +
176 +       spin_lock_irqsave(&corediv->lock, flags);
177 +
178 +       /* Write new divider to the divider ratio register */
179 +       reg = readl(corediv->reg + CORE_CLK_DIV_RATIO_OFFSET);
180 +       reg &= ~(desc->mask << desc->offset);
181 +       reg |= (div & desc->mask) << desc->offset;
182 +       writel(reg, corediv->reg + CORE_CLK_DIV_RATIO_OFFSET);
183 +
184 +       /* Set reload-force for this clock */
185 +       reg = readl(corediv->reg) | BIT(desc->fieldbit);
186 +       writel(reg, corediv->reg);
187 +
188 +       /* Now trigger the clock update */
189 +       reg = readl(corediv->reg) | CORE_CLK_DIV_RATIO_RELOAD;
190 +       writel(reg, corediv->reg);
191 +
192 +       /*
193 +        * Wait for clocks to settle down, and then clear all the
194 +        * ratios request and the reload request.
195 +        */
196 +       udelay(1000);
197 +       reg &= ~(CORE_CLK_DIV_RATIO_MASK | CORE_CLK_DIV_RATIO_RELOAD);
198 +       writel(reg, corediv->reg);
199 +       udelay(1000);
200 +
201 +       spin_unlock_irqrestore(&corediv->lock, flags);
202 +
203 +       return 0;
204 +}
205 +
206 +static const struct clk_ops corediv_ops = {
207 +       .enable = clk_corediv_enable,
208 +       .disable = clk_corediv_disable,
209 +       .is_enabled = clk_corediv_is_enabled,
210 +       .recalc_rate = clk_corediv_recalc_rate,
211 +       .round_rate = clk_corediv_round_rate,
212 +       .set_rate = clk_corediv_set_rate,
213 +};
214 +
215 +static void __init mvebu_corediv_clk_init(struct device_node *node)
216 +{
217 +       struct clk_init_data init;
218 +       struct clk_corediv *corediv;
219 +       struct clk **clks;
220 +       void __iomem *base;
221 +       const char *parent_name;
222 +       const char *clk_name;
223 +       int i;
224 +
225 +       base = of_iomap(node, 0);
226 +       if (WARN_ON(!base))
227 +               return;
228 +
229 +       parent_name = of_clk_get_parent_name(node, 0);
230 +
231 +       clk_data.clk_num = ARRAY_SIZE(mvebu_corediv_desc);
232 +
233 +       /* clks holds the clock array */
234 +       clks = kcalloc(clk_data.clk_num, sizeof(struct clk *),
235 +                               GFP_KERNEL);
236 +       if (WARN_ON(!clks))
237 +               goto err_unmap;
238 +       /* corediv holds the clock specific array */
239 +       corediv = kcalloc(clk_data.clk_num, sizeof(struct clk_corediv),
240 +                               GFP_KERNEL);
241 +       if (WARN_ON(!corediv))
242 +               goto err_free_clks;
243 +
244 +       spin_lock_init(&corediv->lock);
245 +
246 +       for (i = 0; i < clk_data.clk_num; i++) {
247 +               of_property_read_string_index(node, "clock-output-names",
248 +                                             i, &clk_name);
249 +               init.num_parents = 1;
250 +               init.parent_names = &parent_name;
251 +               init.name = clk_name;
252 +               init.ops = &corediv_ops;
253 +               init.flags = 0;
254 +
255 +               corediv[i].desc = mvebu_corediv_desc[i];
256 +               corediv[i].reg = base;
257 +               corediv[i].hw.init = &init;
258 +
259 +               clks[i] = clk_register(NULL, &corediv[i].hw);
260 +               WARN_ON(IS_ERR(clks[i]));
261 +       }
262 +
263 +       clk_data.clks = clks;
264 +       of_clk_add_provider(node, of_clk_src_onecell_get, &clk_data);
265 +       return;
266 +
267 +err_free_clks:
268 +       kfree(clks);
269 +err_unmap:
270 +       iounmap(base);
271 +}
272 +CLK_OF_DECLARE(mvebu_corediv_clk, "marvell,armada-370-corediv-clock",
273 +              mvebu_corediv_clk_init);