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 19static int ifc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1, 20 16, 1, 1, 32, 1, 1, 1, 1 }; 21static int sfc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1, 22 16, 1, 1, 32, 1, 1, 1, 1 }; 23static int bfc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1, 24 16, 1, 1, 32, 1, 1, 1, 1 }; 25static int p1fc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1, 26 16, 1, 1, 32, 1, 1, 1, 1 }; 27 28static void master_clk_init(struct clk *clk) 29{ 30 clk->rate = CONFIG_SH_PCLK_FREQ * 16; 31} 32 33static struct clk_ops sh7757_master_clk_ops = { 34 .init = master_clk_init, 35}; 36 37static 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 43static struct clk_ops sh7757_module_clk_ops = { 44 .recalc = module_clk_recalc, 45}; 46 47static 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 53static struct clk_ops sh7757_bus_clk_ops = { 54 .recalc = bus_clk_recalc, 55}; 56 57static 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 63static struct clk_ops sh7757_cpu_clk_ops = { 64 .recalc = cpu_clk_recalc, 65}; 66 67static 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 74void __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 80static 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 86static struct clk_ops sh7757_shyway_clk_ops = { 87 .recalc = shyway_clk_recalc, 88}; 89 90static 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 */ 99static struct clk *sh7757_onchip_clocks[] = { 100 &sh7757_shyway_clk, 101}; 102 103#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk } 104 105static struct clk_lookup lookups[] = { 106 /* main clocks */ 107 CLKDEV_CON_ID("shyway_clk", &sh7757_shyway_clk), 108}; 109 110static 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 138arch_initcall(sh7757_clk_init); 139