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[3]; 30 31 void clkdev_add_static(unsigned long cpu, unsigned long fpi, unsigned long io) 32 { 33 cpu_clk_generic[0].rate = cpu; 34 cpu_clk_generic[1].rate = fpi; 35 cpu_clk_generic[2].rate = io; 36 } 37 38 struct clk *clk_get_cpu(void) 39 { 40 return &cpu_clk_generic[0]; 41 } 42 43 struct clk *clk_get_fpi(void) 44 { 45 return &cpu_clk_generic[1]; 46 } 47 EXPORT_SYMBOL_GPL(clk_get_fpi); 48 49 struct clk *clk_get_io(void) 50 { 51 return &cpu_clk_generic[2]; 52 } 53 54 static inline int clk_good(struct clk *clk) 55 { 56 return clk && !IS_ERR(clk); 57 } 58 59 unsigned long clk_get_rate(struct clk *clk) 60 { 61 if (unlikely(!clk_good(clk))) 62 return 0; 63 64 if (clk->rate != 0) 65 return clk->rate; 66 67 if (clk->get_rate != NULL) 68 return clk->get_rate(); 69 70 return 0; 71 } 72 EXPORT_SYMBOL(clk_get_rate); 73 74 int clk_set_rate(struct clk *clk, unsigned long rate) 75 { 76 if (unlikely(!clk_good(clk))) 77 return 0; 78 if (clk->rates && *clk->rates) { 79 unsigned long *r = clk->rates; 80 81 while (*r && (*r != rate)) 82 r++; 83 if (!*r) { 84 pr_err("clk %s.%s: trying to set invalid rate %ld\n", 85 clk->cl.dev_id, clk->cl.con_id, rate); 86 return -1; 87 } 88 } 89 clk->rate = rate; 90 return 0; 91 } 92 EXPORT_SYMBOL(clk_set_rate); 93 94 int clk_enable(struct clk *clk) 95 { 96 if (unlikely(!clk_good(clk))) 97 return -1; 98 99 if (clk->enable) 100 return clk->enable(clk); 101 102 return -1; 103 } 104 EXPORT_SYMBOL(clk_enable); 105 106 void clk_disable(struct clk *clk) 107 { 108 if (unlikely(!clk_good(clk))) 109 return; 110 111 if (clk->disable) 112 clk->disable(clk); 113 } 114 EXPORT_SYMBOL(clk_disable); 115 116 int clk_activate(struct clk *clk) 117 { 118 if (unlikely(!clk_good(clk))) 119 return -1; 120 121 if (clk->activate) 122 return clk->activate(clk); 123 124 return -1; 125 } 126 EXPORT_SYMBOL(clk_activate); 127 128 void clk_deactivate(struct clk *clk) 129 { 130 if (unlikely(!clk_good(clk))) 131 return; 132 133 if (clk->deactivate) 134 clk->deactivate(clk); 135 } 136 EXPORT_SYMBOL(clk_deactivate); 137 138 static inline u32 get_counter_resolution(void) 139 { 140 u32 res; 141 142 __asm__ __volatile__( 143 ".set push\n" 144 ".set mips32r2\n" 145 "rdhwr %0, $3\n" 146 ".set pop\n" 147 : "=&r" (res) 148 : /* no input */ 149 : "memory"); 150 151 return res; 152 } 153 154 void __init plat_time_init(void) 155 { 156 struct clk *clk; 157 158 ltq_soc_init(); 159 160 clk = clk_get_cpu(); 161 mips_hpt_frequency = clk_get_rate(clk) / get_counter_resolution(); 162 write_c0_compare(read_c0_count()); 163 pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); 164 clk_put(clk); 165 } 166