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 102int clk_enable(struct clk *clk) 103{ 104 if (unlikely(!clk_good(clk))) 105 return -1; 106 107 if (clk->enable) 108 return clk->enable(clk); 109 110 return -1; 111} 112EXPORT_SYMBOL(clk_enable); 113 114void clk_disable(struct clk *clk) 115{ 116 if (unlikely(!clk_good(clk))) 117 return; 118 119 if (clk->disable) 120 clk->disable(clk); 121} 122EXPORT_SYMBOL(clk_disable); 123 124int clk_activate(struct clk *clk) 125{ 126 if (unlikely(!clk_good(clk))) 127 return -1; 128 129 if (clk->activate) 130 return clk->activate(clk); 131 132 return -1; 133} 134EXPORT_SYMBOL(clk_activate); 135 136void clk_deactivate(struct clk *clk) 137{ 138 if (unlikely(!clk_good(clk))) 139 return; 140 141 if (clk->deactivate) 142 clk->deactivate(clk); 143} 144EXPORT_SYMBOL(clk_deactivate); 145 146struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) 147{ 148 return NULL; 149} 150 151static inline u32 get_counter_resolution(void) 152{ 153 u32 res; 154 155 __asm__ __volatile__( 156 ".set push\n" 157 ".set mips32r2\n" 158 "rdhwr %0, $3\n" 159 ".set pop\n" 160 : "=&r" (res) 161 : /* no input */ 162 : "memory"); 163 164 return res; 165} 166 167void __init plat_time_init(void) 168{ 169 struct clk *clk; 170 171 ltq_soc_init(); 172 173 clk = clk_get_cpu(); 174 mips_hpt_frequency = clk_get_rate(clk) / get_counter_resolution(); 175 write_c0_compare(read_c0_count()); 176 pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); 177 clk_put(clk); 178} 179