1/* 2 * This program is free software; you can redistribute it and/or modify it 3 * under the terms of the GNU General Public License version 2 as published 4 * by the Free Software Foundation. 5 * 6 * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> 7 * Copyright (C) 2010 John Crispin <blogic@openwrt.org> 8 */ 9#include <linux/io.h> 10#include <linux/export.h> 11#include <linux/init.h> 12#include <linux/kernel.h> 13#include <linux/types.h> 14#include <linux/clk.h> 15#include <linux/clkdev.h> 16#include <linux/err.h> 17#include <linux/list.h> 18 19#include <asm/time.h> 20#include <asm/irq.h> 21#include <asm/div64.h> 22 23#include <lantiq_soc.h> 24 25#include "clk.h" 26#include "prom.h" 27 28/* lantiq socs have 3 static clocks */ 29static struct clk cpu_clk_generic[4]; 30 31void clkdev_add_static(unsigned long cpu, unsigned long fpi, 32 unsigned long io, unsigned long ppe) 33{ 34 cpu_clk_generic[0].rate = cpu; 35 cpu_clk_generic[1].rate = fpi; 36 cpu_clk_generic[2].rate = io; 37 cpu_clk_generic[3].rate = ppe; 38} 39 40struct clk *clk_get_cpu(void) 41{ 42 return &cpu_clk_generic[0]; 43} 44 45struct clk *clk_get_fpi(void) 46{ 47 return &cpu_clk_generic[1]; 48} 49EXPORT_SYMBOL_GPL(clk_get_fpi); 50 51struct clk *clk_get_io(void) 52{ 53 return &cpu_clk_generic[2]; 54} 55 56struct clk *clk_get_ppe(void) 57{ 58 return &cpu_clk_generic[3]; 59} 60EXPORT_SYMBOL_GPL(clk_get_ppe); 61 62static inline int clk_good(struct clk *clk) 63{ 64 return clk && !IS_ERR(clk); 65} 66 67unsigned long clk_get_rate(struct clk *clk) 68{ 69 if (unlikely(!clk_good(clk))) 70 return 0; 71 72 if (clk->rate != 0) 73 return clk->rate; 74 75 if (clk->get_rate != NULL) 76 return clk->get_rate(); 77 78 return 0; 79} 80EXPORT_SYMBOL(clk_get_rate); 81 82int clk_set_rate(struct clk *clk, unsigned long rate) 83{ 84 if (unlikely(!clk_good(clk))) 85 return 0; 86 if (clk->rates && *clk->rates) { 87 unsigned long *r = clk->rates; 88 89 while (*r && (*r != rate)) 90 r++; 91 if (!*r) { 92 pr_err("clk %s.%s: trying to set invalid rate %ld\n", 93 clk->cl.dev_id, clk->cl.con_id, rate); 94 return -1; 95 } 96 } 97 clk->rate = rate; 98 return 0; 99} 100EXPORT_SYMBOL(clk_set_rate); 101 102long clk_round_rate(struct clk *clk, unsigned long rate) 103{ 104 if (unlikely(!clk_good(clk))) 105 return 0; 106 if (clk->rates && *clk->rates) { 107 unsigned long *r = clk->rates; 108 109 while (*r && (*r != rate)) 110 r++; 111 if (!*r) { 112 return clk->rate; 113 } 114 } 115 return rate; 116} 117EXPORT_SYMBOL(clk_round_rate); 118 119int clk_enable(struct clk *clk) 120{ 121 if (unlikely(!clk_good(clk))) 122 return -1; 123 124 if (clk->enable) 125 return clk->enable(clk); 126 127 return -1; 128} 129EXPORT_SYMBOL(clk_enable); 130 131void clk_disable(struct clk *clk) 132{ 133 if (unlikely(!clk_good(clk))) 134 return; 135 136 if (clk->disable) 137 clk->disable(clk); 138} 139EXPORT_SYMBOL(clk_disable); 140 141int clk_activate(struct clk *clk) 142{ 143 if (unlikely(!clk_good(clk))) 144 return -1; 145 146 if (clk->activate) 147 return clk->activate(clk); 148 149 return -1; 150} 151EXPORT_SYMBOL(clk_activate); 152 153void clk_deactivate(struct clk *clk) 154{ 155 if (unlikely(!clk_good(clk))) 156 return; 157 158 if (clk->deactivate) 159 clk->deactivate(clk); 160} 161EXPORT_SYMBOL(clk_deactivate); 162 163struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) 164{ 165 return NULL; 166} 167 168static inline u32 get_counter_resolution(void) 169{ 170 u32 res; 171 172 __asm__ __volatile__( 173 ".set push\n" 174 ".set mips32r2\n" 175 "rdhwr %0, $3\n" 176 ".set pop\n" 177 : "=&r" (res) 178 : /* no input */ 179 : "memory"); 180 181 return res; 182} 183 184void __init plat_time_init(void) 185{ 186 struct clk *clk; 187 188 ltq_soc_init(); 189 190 clk = clk_get_cpu(); 191 mips_hpt_frequency = clk_get_rate(clk) / get_counter_resolution(); 192 write_c0_compare(read_c0_count()); 193 pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); 194 clk_put(clk); 195} 196