1 /* 2 * arch/sh/kernel/cpu/sh4a/clock-sh7786.c 3 * 4 * SH7786 support for the clock framework 5 * 6 * Copyright (C) 2008, 2009 Renesas Solutions Corp. 7 * Kuninori Morimoto <morimoto.kuninori@renesas.com> 8 * 9 * Based on SH7785 10 * Copyright (C) 2007 Paul Mundt 11 * 12 * This file is subject to the terms and conditions of the GNU General Public 13 * License. See the file "COPYING" in the main directory of this archive 14 * for more details. 15 */ 16 #include <linux/init.h> 17 #include <linux/kernel.h> 18 #include <asm/clock.h> 19 #include <asm/freq.h> 20 #include <asm/io.h> 21 22 static int ifc_divisors[] = { 1, 2, 4, 1 }; 23 static int sfc_divisors[] = { 1, 1, 4, 1 }; 24 static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 1, 25 24, 32, 1, 1, 1, 1, 1, 1 }; 26 static int mfc_divisors[] = { 1, 1, 4, 1 }; 27 static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 16, 1, 28 24, 32, 1, 48, 1, 1, 1, 1 }; 29 30 static void master_clk_init(struct clk *clk) 31 { 32 clk->rate *= pfc_divisors[ctrl_inl(FRQMR1) & 0x000f]; 33 } 34 35 static struct clk_ops sh7786_master_clk_ops = { 36 .init = master_clk_init, 37 }; 38 39 static void module_clk_recalc(struct clk *clk) 40 { 41 int idx = (ctrl_inl(FRQMR1) & 0x000f); 42 clk->rate = clk->parent->rate / pfc_divisors[idx]; 43 } 44 45 static struct clk_ops sh7786_module_clk_ops = { 46 .recalc = module_clk_recalc, 47 }; 48 49 static void bus_clk_recalc(struct clk *clk) 50 { 51 int idx = ((ctrl_inl(FRQMR1) >> 16) & 0x000f); 52 clk->rate = clk->parent->rate / bfc_divisors[idx]; 53 } 54 55 static struct clk_ops sh7786_bus_clk_ops = { 56 .recalc = bus_clk_recalc, 57 }; 58 59 static void cpu_clk_recalc(struct clk *clk) 60 { 61 int idx = ((ctrl_inl(FRQMR1) >> 28) & 0x0003); 62 clk->rate = clk->parent->rate / ifc_divisors[idx]; 63 } 64 65 static struct clk_ops sh7786_cpu_clk_ops = { 66 .recalc = cpu_clk_recalc, 67 }; 68 69 static struct clk_ops *sh7786_clk_ops[] = { 70 &sh7786_master_clk_ops, 71 &sh7786_module_clk_ops, 72 &sh7786_bus_clk_ops, 73 &sh7786_cpu_clk_ops, 74 }; 75 76 void __init arch_init_clk_ops(struct clk_ops **ops, int idx) 77 { 78 if (idx < ARRAY_SIZE(sh7786_clk_ops)) 79 *ops = sh7786_clk_ops[idx]; 80 } 81 82 static void shyway_clk_recalc(struct clk *clk) 83 { 84 int idx = ((ctrl_inl(FRQMR1) >> 20) & 0x0003); 85 clk->rate = clk->parent->rate / sfc_divisors[idx]; 86 } 87 88 static struct clk_ops sh7786_shyway_clk_ops = { 89 .recalc = shyway_clk_recalc, 90 }; 91 92 static struct clk sh7786_shyway_clk = { 93 .name = "shyway_clk", 94 .flags = CLK_ALWAYS_ENABLED, 95 .ops = &sh7786_shyway_clk_ops, 96 }; 97 98 static void ddr_clk_recalc(struct clk *clk) 99 { 100 int idx = ((ctrl_inl(FRQMR1) >> 12) & 0x0003); 101 clk->rate = clk->parent->rate / mfc_divisors[idx]; 102 } 103 104 static struct clk_ops sh7786_ddr_clk_ops = { 105 .recalc = ddr_clk_recalc, 106 }; 107 108 static struct clk sh7786_ddr_clk = { 109 .name = "ddr_clk", 110 .flags = CLK_ALWAYS_ENABLED, 111 .ops = &sh7786_ddr_clk_ops, 112 }; 113 114 /* 115 * Additional SH7786-specific on-chip clocks that aren't already part of the 116 * clock framework 117 */ 118 static struct clk *sh7786_onchip_clocks[] = { 119 &sh7786_shyway_clk, 120 &sh7786_ddr_clk, 121 }; 122 123 static int __init sh7786_clk_init(void) 124 { 125 struct clk *clk = clk_get(NULL, "master_clk"); 126 int i; 127 128 for (i = 0; i < ARRAY_SIZE(sh7786_onchip_clocks); i++) { 129 struct clk *clkp = sh7786_onchip_clocks[i]; 130 131 clkp->parent = clk; 132 clk_register(clkp); 133 clk_enable(clkp); 134 } 135 136 /* 137 * Now that we have the rest of the clocks registered, we need to 138 * force the parent clock to propagate so that these clocks will 139 * automatically figure out their rate. We cheat by handing the 140 * parent clock its current rate and forcing child propagation. 141 */ 142 clk_set_rate(clk, clk_get_rate(clk)); 143 144 clk_put(clk); 145 146 return 0; 147 } 148 arch_initcall(sh7786_clk_init); 149