0001
0002
0003
0004
0005
0006 #include <linux/clk-provider.h>
0007 #include <linux/err.h>
0008 #include <linux/slab.h>
0009 #include "clk.h"
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 struct clk_div {
0022 struct clk_divider divider;
0023 const struct clk_ops *ops;
0024 void __iomem *reg;
0025 u8 busy;
0026 };
0027
0028 static inline struct clk_div *to_clk_div(struct clk_hw *hw)
0029 {
0030 struct clk_divider *divider = to_clk_divider(hw);
0031
0032 return container_of(divider, struct clk_div, divider);
0033 }
0034
0035 static unsigned long clk_div_recalc_rate(struct clk_hw *hw,
0036 unsigned long parent_rate)
0037 {
0038 struct clk_div *div = to_clk_div(hw);
0039
0040 return div->ops->recalc_rate(&div->divider.hw, parent_rate);
0041 }
0042
0043 static long clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
0044 unsigned long *prate)
0045 {
0046 struct clk_div *div = to_clk_div(hw);
0047
0048 return div->ops->round_rate(&div->divider.hw, rate, prate);
0049 }
0050
0051 static int clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
0052 unsigned long parent_rate)
0053 {
0054 struct clk_div *div = to_clk_div(hw);
0055 int ret;
0056
0057 ret = div->ops->set_rate(&div->divider.hw, rate, parent_rate);
0058 if (!ret)
0059 ret = mxs_clk_wait(div->reg, div->busy);
0060
0061 return ret;
0062 }
0063
0064 static const struct clk_ops clk_div_ops = {
0065 .recalc_rate = clk_div_recalc_rate,
0066 .round_rate = clk_div_round_rate,
0067 .set_rate = clk_div_set_rate,
0068 };
0069
0070 struct clk *mxs_clk_div(const char *name, const char *parent_name,
0071 void __iomem *reg, u8 shift, u8 width, u8 busy)
0072 {
0073 struct clk_div *div;
0074 struct clk *clk;
0075 struct clk_init_data init;
0076
0077 div = kzalloc(sizeof(*div), GFP_KERNEL);
0078 if (!div)
0079 return ERR_PTR(-ENOMEM);
0080
0081 init.name = name;
0082 init.ops = &clk_div_ops;
0083 init.flags = CLK_SET_RATE_PARENT;
0084 init.parent_names = (parent_name ? &parent_name: NULL);
0085 init.num_parents = (parent_name ? 1 : 0);
0086
0087 div->reg = reg;
0088 div->busy = busy;
0089
0090 div->divider.reg = reg;
0091 div->divider.shift = shift;
0092 div->divider.width = width;
0093 div->divider.flags = CLK_DIVIDER_ONE_BASED;
0094 div->divider.lock = &mxs_lock;
0095 div->divider.hw.init = &init;
0096 div->ops = &clk_divider_ops;
0097
0098 clk = clk_register(NULL, &div->divider.hw);
0099 if (IS_ERR(clk))
0100 kfree(div);
0101
0102 return clk;
0103 }