1 /* 2 * arch/sh/kernel/cpu/sh4/clock-sh7757.c 3 * 4 * SH7757 support for the clock framework 5 * 6 * Copyright (C) 2009 Renesas Solutions Corp. 7 * 8 * This file is subject to the terms and conditions of the GNU General Public 9 * License. See the file "COPYING" in the main directory of this archive 10 * for more details. 11 */ 12 #include <linux/init.h> 13 #include <linux/kernel.h> 14 #include <linux/io.h> 15 #include <asm/clkdev.h> 16 #include <asm/clock.h> 17 #include <asm/freq.h> 18 19 static int ifc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1, 20 16, 1, 1, 32, 1, 1, 1, 1 }; 21 static int sfc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1, 22 16, 1, 1, 32, 1, 1, 1, 1 }; 23 static int bfc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1, 24 16, 1, 1, 32, 1, 1, 1, 1 }; 25 static int p1fc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1, 26 16, 1, 1, 32, 1, 1, 1, 1 }; 27 28 static void master_clk_init(struct clk *clk) 29 { 30 clk->rate = CONFIG_SH_PCLK_FREQ * 16; 31 } 32 33 static struct clk_ops sh7757_master_clk_ops = { 34 .init = master_clk_init, 35 }; 36 37 static void module_clk_recalc(struct clk *clk) 38 { 39 int idx = __raw_readl(FRQCR) & 0x0000000f; 40 clk->rate = clk->parent->rate / p1fc_divisors[idx]; 41 } 42 43 static struct clk_ops sh7757_module_clk_ops = { 44 .recalc = module_clk_recalc, 45 }; 46 47 static void bus_clk_recalc(struct clk *clk) 48 { 49 int idx = (__raw_readl(FRQCR) >> 8) & 0x0000000f; 50 clk->rate = clk->parent->rate / bfc_divisors[idx]; 51 } 52 53 static struct clk_ops sh7757_bus_clk_ops = { 54 .recalc = bus_clk_recalc, 55 }; 56 57 static void cpu_clk_recalc(struct clk *clk) 58 { 59 int idx = (__raw_readl(FRQCR) >> 20) & 0x0000000f; 60 clk->rate = clk->parent->rate / ifc_divisors[idx]; 61 } 62 63 static struct clk_ops sh7757_cpu_clk_ops = { 64 .recalc = cpu_clk_recalc, 65 }; 66 67 static struct clk_ops *sh7757_clk_ops[] = { 68 &sh7757_master_clk_ops, 69 &sh7757_module_clk_ops, 70 &sh7757_bus_clk_ops, 71 &sh7757_cpu_clk_ops, 72 }; 73 74 void __init arch_init_clk_ops(struct clk_ops **ops, int idx) 75 { 76 if (idx < ARRAY_SIZE(sh7757_clk_ops)) 77 *ops = sh7757_clk_ops[idx]; 78 } 79 80 static void shyway_clk_recalc(struct clk *clk) 81 { 82 int idx = (__raw_readl(FRQCR) >> 12) & 0x0000000f; 83 clk->rate = clk->parent->rate / sfc_divisors[idx]; 84 } 85 86 static struct clk_ops sh7757_shyway_clk_ops = { 87 .recalc = shyway_clk_recalc, 88 }; 89 90 static struct clk sh7757_shyway_clk = { 91 .flags = CLK_ENABLE_ON_INIT, 92 .ops = &sh7757_shyway_clk_ops, 93 }; 94 95 /* 96 * Additional sh7757-specific on-chip clocks that aren't already part of the 97 * clock framework 98 */ 99 static struct clk *sh7757_onchip_clocks[] = { 100 &sh7757_shyway_clk, 101 }; 102 103 #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk } 104 105 static struct clk_lookup lookups[] = { 106 /* main clocks */ 107 CLKDEV_CON_ID("shyway_clk", &sh7757_shyway_clk), 108 }; 109 110 static int __init sh7757_clk_init(void) 111 { 112 struct clk *clk = clk_get(NULL, "master_clk"); 113 int i; 114 115 for (i = 0; i < ARRAY_SIZE(sh7757_onchip_clocks); i++) { 116 struct clk *clkp = sh7757_onchip_clocks[i]; 117 118 clkp->parent = clk; 119 clk_register(clkp); 120 clk_enable(clkp); 121 } 122 123 /* 124 * Now that we have the rest of the clocks registered, we need to 125 * force the parent clock to propagate so that these clocks will 126 * automatically figure out their rate. We cheat by handing the 127 * parent clock its current rate and forcing child propagation. 128 */ 129 clk_set_rate(clk, clk_get_rate(clk)); 130 131 clk_put(clk); 132 133 clkdev_add_table(lookups, ARRAY_SIZE(lookups)); 134 135 return 0; 136 } 137 138 arch_initcall(sh7757_clk_init); 139 140