1 /* 2 * Copyright (c) 2014 Lucas Stach <l.stach@pengutronix.de>, Pengutronix 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 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/slab.h> 15 #include "clk.h" 16 17 struct clk_cpu { 18 struct clk_hw hw; 19 struct clk *div; 20 struct clk *mux; 21 struct clk *pll; 22 struct clk *step; 23 }; 24 25 static inline struct clk_cpu *to_clk_cpu(struct clk_hw *hw) 26 { 27 return container_of(hw, struct clk_cpu, hw); 28 } 29 30 static unsigned long clk_cpu_recalc_rate(struct clk_hw *hw, 31 unsigned long parent_rate) 32 { 33 struct clk_cpu *cpu = to_clk_cpu(hw); 34 35 return clk_get_rate(cpu->div); 36 } 37 38 static long clk_cpu_round_rate(struct clk_hw *hw, unsigned long rate, 39 unsigned long *prate) 40 { 41 struct clk_cpu *cpu = to_clk_cpu(hw); 42 43 return clk_round_rate(cpu->pll, rate); 44 } 45 46 static int clk_cpu_set_rate(struct clk_hw *hw, unsigned long rate, 47 unsigned long parent_rate) 48 { 49 struct clk_cpu *cpu = to_clk_cpu(hw); 50 int ret; 51 52 /* switch to PLL bypass clock */ 53 ret = clk_set_parent(cpu->mux, cpu->step); 54 if (ret) 55 return ret; 56 57 /* reprogram PLL */ 58 ret = clk_set_rate(cpu->pll, rate); 59 if (ret) { 60 clk_set_parent(cpu->mux, cpu->pll); 61 return ret; 62 } 63 /* switch back to PLL clock */ 64 clk_set_parent(cpu->mux, cpu->pll); 65 66 /* Ensure the divider is what we expect */ 67 clk_set_rate(cpu->div, rate); 68 69 return 0; 70 } 71 72 static const struct clk_ops clk_cpu_ops = { 73 .recalc_rate = clk_cpu_recalc_rate, 74 .round_rate = clk_cpu_round_rate, 75 .set_rate = clk_cpu_set_rate, 76 }; 77 78 struct clk *imx_clk_cpu(const char *name, const char *parent_name, 79 struct clk *div, struct clk *mux, struct clk *pll, 80 struct clk *step) 81 { 82 struct clk_cpu *cpu; 83 struct clk *clk; 84 struct clk_init_data init; 85 86 cpu = kzalloc(sizeof(*cpu), GFP_KERNEL); 87 if (!cpu) 88 return ERR_PTR(-ENOMEM); 89 90 cpu->div = div; 91 cpu->mux = mux; 92 cpu->pll = pll; 93 cpu->step = step; 94 95 init.name = name; 96 init.ops = &clk_cpu_ops; 97 init.flags = CLK_IS_CRITICAL; 98 init.parent_names = &parent_name; 99 init.num_parents = 1; 100 101 cpu->hw.init = &init; 102 103 clk = clk_register(NULL, &cpu->hw); 104 if (IS_ERR(clk)) 105 kfree(cpu); 106 107 return clk; 108 } 109