0001
0002
0003
0004
0005
0006 #include <linux/clk.h>
0007 #include <linux/clk-provider.h>
0008 #include <linux/export.h>
0009 #include <linux/slab.h>
0010 #include "clk.h"
0011
0012 struct clk_cpu {
0013 struct clk_hw hw;
0014 struct clk *div;
0015 struct clk *mux;
0016 struct clk *pll;
0017 struct clk *step;
0018 };
0019
0020 static inline struct clk_cpu *to_clk_cpu(struct clk_hw *hw)
0021 {
0022 return container_of(hw, struct clk_cpu, hw);
0023 }
0024
0025 static unsigned long clk_cpu_recalc_rate(struct clk_hw *hw,
0026 unsigned long parent_rate)
0027 {
0028 struct clk_cpu *cpu = to_clk_cpu(hw);
0029
0030 return clk_get_rate(cpu->div);
0031 }
0032
0033 static long clk_cpu_round_rate(struct clk_hw *hw, unsigned long rate,
0034 unsigned long *prate)
0035 {
0036 struct clk_cpu *cpu = to_clk_cpu(hw);
0037
0038 return clk_round_rate(cpu->pll, rate);
0039 }
0040
0041 static int clk_cpu_set_rate(struct clk_hw *hw, unsigned long rate,
0042 unsigned long parent_rate)
0043 {
0044 struct clk_cpu *cpu = to_clk_cpu(hw);
0045 int ret;
0046
0047
0048 ret = clk_set_parent(cpu->mux, cpu->step);
0049 if (ret)
0050 return ret;
0051
0052
0053 ret = clk_set_rate(cpu->pll, rate);
0054 if (ret) {
0055 clk_set_parent(cpu->mux, cpu->pll);
0056 return ret;
0057 }
0058
0059 clk_set_parent(cpu->mux, cpu->pll);
0060
0061
0062 clk_set_rate(cpu->div, rate);
0063
0064 return 0;
0065 }
0066
0067 static const struct clk_ops clk_cpu_ops = {
0068 .recalc_rate = clk_cpu_recalc_rate,
0069 .round_rate = clk_cpu_round_rate,
0070 .set_rate = clk_cpu_set_rate,
0071 };
0072
0073 struct clk_hw *imx_clk_hw_cpu(const char *name, const char *parent_name,
0074 struct clk *div, struct clk *mux, struct clk *pll,
0075 struct clk *step)
0076 {
0077 struct clk_cpu *cpu;
0078 struct clk_hw *hw;
0079 struct clk_init_data init;
0080 int ret;
0081
0082 cpu = kzalloc(sizeof(*cpu), GFP_KERNEL);
0083 if (!cpu)
0084 return ERR_PTR(-ENOMEM);
0085
0086 cpu->div = div;
0087 cpu->mux = mux;
0088 cpu->pll = pll;
0089 cpu->step = step;
0090
0091 init.name = name;
0092 init.ops = &clk_cpu_ops;
0093 init.flags = CLK_IS_CRITICAL;
0094 init.parent_names = &parent_name;
0095 init.num_parents = 1;
0096
0097 cpu->hw.init = &init;
0098 hw = &cpu->hw;
0099
0100 ret = clk_hw_register(NULL, hw);
0101 if (ret) {
0102 kfree(cpu);
0103 return ERR_PTR(ret);
0104 }
0105
0106 return hw;
0107 }
0108 EXPORT_SYMBOL_GPL(imx_clk_hw_cpu);