diff options
| author | Shawn Guo <shawn.guo@linaro.org> | 2012-04-28 12:02:34 -0400 |
|---|---|---|
| committer | Shawn Guo <shawn.guo@linaro.org> | 2012-05-08 12:02:35 -0400 |
| commit | 23b5e15a2994fb0c1444f92b76f09a482f32843c (patch) | |
| tree | 54695e5b39977bd1ed04dfd945c9052a85b57e0f | |
| parent | d48b97b403d23f6df0b990cee652bdf9a52337a3 (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/Makefile | 5 | ||||
| -rw-r--r-- | drivers/clk/mxs/clk-div.c | 110 | ||||
| -rw-r--r-- | drivers/clk/mxs/clk-frac.c | 139 | ||||
| -rw-r--r-- | drivers/clk/mxs/clk-pll.c | 116 | ||||
| -rw-r--r-- | drivers/clk/mxs/clk-ref.c | 154 | ||||
| -rw-r--r-- | drivers/clk/mxs/clk.c | 28 | ||||
| -rw-r--r-- | drivers/clk/mxs/clk.h | 66 |
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 | |||
| 5 | obj-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 | */ | ||
| 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 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 | */ | ||
| 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) | ||
