aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Guo <shawn.guo@linaro.org>2012-04-28 12:02:34 -0400
committerShawn Guo <shawn.guo@linaro.org>2012-05-08 12:02:35 -0400
commit23b5e15a2994fb0c1444f92b76f09a482f32843c (patch)
tree54695e5b39977bd1ed04dfd945c9052a85b57e0f
parentd48b97b403d23f6df0b990cee652bdf9a52337a3 (diff)
clk: mxs: add mxs specific clocks
Add mxs specific clocks, pll, reference clock (PFD), integer divider and fractional divider. Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
-rw-r--r--drivers/clk/mxs/Makefile5
-rw-r--r--drivers/clk/mxs/clk-div.c110
-rw-r--r--drivers/clk/mxs/clk-frac.c139
-rw-r--r--drivers/clk/mxs/clk-pll.c116
-rw-r--r--drivers/clk/mxs/clk-ref.c154
-rw-r--r--drivers/clk/mxs/clk.c28
-rw-r--r--drivers/clk/mxs/clk.h66
7 files changed, 618 insertions, 0 deletions
diff --git a/drivers/clk/mxs/Makefile b/drivers/clk/mxs/Makefile
new file mode 100644
index 000000000000..d9472a809bba
--- /dev/null
+++ b/drivers/clk/mxs/Makefile
@@ -0,0 +1,5 @@
1#
2# Makefile for mxs specific clk
3#
4
5obj-y += clk.o clk-pll.o clk-ref.o clk-div.o clk-frac.o
diff --git a/drivers/clk/mxs/clk-div.c b/drivers/clk/mxs/clk-div.c
new file mode 100644
index 000000000000..90e1da93877e
--- /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 */
28struct clk_div {
29 struct clk_divider divider;
30 const struct clk_ops *ops;
31 void __iomem *reg;
32 u8 busy;
33};
34
35static 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
42static 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
50static 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
58static 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
71static 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
77struct 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 000000000000..e6aa6b567d68
--- /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 */
30struct 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
40static 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
52static 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
74static int clk_frac_set_rate(struct clk_hw *hw, unsigned long rate,
75 unsigned long parent_rate)