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 */ 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 int 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 } 112 EXPORT_SYMBOL(clk_enable); 113 114 void clk_disable(struct clk *clk) 115 { 116 if (unlikely(!clk_good(clk))) 117 return; 118 119 if (clk->disable) 120 clk->disable(clk); 121 } 122 EXPORT_SYMBOL(clk_disable); 123 124 int 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 } 134 EXPORT_SYMBOL(clk_activate); 135 136 void clk_deactivate(struct clk *clk) 137 { 138 if (unlikely(!clk_good(clk))) 139 return; 140 141 if (clk->deactivate) 142 clk->deactivate(clk); 143 } 144 EXPORT_SYMBOL(clk_deactivate); 145 146 struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) 147 { 148 return NULL; 149 } 150 151 static 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 167 void __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