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 <john@phrozen.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 */ 29 static struct clk cpu_clk_generic[4]; 30 31 void 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 40 struct clk *clk_get_cpu(void) 41 { 42 return &cpu_clk_generic[0]; 43 } 44 45 struct clk *clk_get_fpi(void) 46 { 47 return &cpu_clk_generic[1]; 48 } 49 EXPORT_SYMBOL_GPL(clk_get_fpi); 50 51 struct clk *clk_get_io(void) 52 { 53 return &cpu_clk_generic[2]; 54 } 55 56 struct clk *clk_get_ppe(void) 57 { 58 return &cpu_clk_generic[3]; 59 } 60 EXPORT_SYMBOL_GPL(clk_get_ppe); 61 62 static inline int clk_good(struct clk *clk) 63 { 64 return clk && !IS_ERR(clk); 65 } 66 67 unsigned 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 } 80 EXPORT_SYMBOL(clk_get_rate); 81 82 int 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 } 100 EXPORT_SYMBOL(clk_set_rate); 101 102 long 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 } 117 EXPORT_SYMBOL(clk_round_rate); 118 119 int 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 } 129 EXPORT_SYMBOL(clk_enable); 130 131 void clk_disable(struct clk *clk) 132 { 133 if (unlikely(!clk_good(clk))) 134 return; 135 136 if (clk->disable) 137 clk->disable(clk); 138 } 139 EXPORT_SYMBOL(clk_disable); 140 141 int 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 } 151 EXPORT_SYMBOL(clk_activate); 152 153 void clk_deactivate(struct clk *clk) 154 { 155 if (unlikely(!clk_good(clk))) 156 return; 157 158 if (clk->deactivate) 159 clk->deactivate(clk); 160 } 161 EXPORT_SYMBOL(clk_deactivate); 162 163 static inline u32 get_counter_resolution(void) 164 { 165 u32 res; 166 167 __asm__ __volatile__( 168 ".set push\n" 169 ".set mips32r2\n" 170 "rdhwr %0, $3\n" 171 ".set pop\n" 172 : "=&r" (res) 173 : /* no input */ 174 : "memory"); 175 176 return res; 177 } 178 179 void __init plat_time_init(void) 180 { 181 struct clk *clk; 182 183 ltq_soc_init(); 184 185 clk = clk_get_cpu(); 186 mips_hpt_frequency = clk_get_rate(clk) / get_counter_resolution(); 187 write_c0_compare(read_c0_count()); 188 pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); 189 clk_put(clk); 190 } 191