0001
0002
0003
0004
0005
0006
0007 #include <linux/io.h>
0008 #include <linux/export.h>
0009 #include <linux/init.h>
0010 #include <linux/kernel.h>
0011 #include <linux/types.h>
0012 #include <linux/clk.h>
0013 #include <linux/clkdev.h>
0014 #include <linux/err.h>
0015 #include <linux/list.h>
0016
0017 #include <asm/time.h>
0018 #include <asm/irq.h>
0019 #include <asm/div64.h>
0020
0021 #include <lantiq_soc.h>
0022
0023 #include "clk.h"
0024 #include "prom.h"
0025
0026
0027 static struct clk cpu_clk_generic[4];
0028
0029 void clkdev_add_static(unsigned long cpu, unsigned long fpi,
0030 unsigned long io, unsigned long ppe)
0031 {
0032 cpu_clk_generic[0].rate = cpu;
0033 cpu_clk_generic[1].rate = fpi;
0034 cpu_clk_generic[2].rate = io;
0035 cpu_clk_generic[3].rate = ppe;
0036 }
0037
0038 struct clk *clk_get_cpu(void)
0039 {
0040 return &cpu_clk_generic[0];
0041 }
0042
0043 struct clk *clk_get_fpi(void)
0044 {
0045 return &cpu_clk_generic[1];
0046 }
0047 EXPORT_SYMBOL_GPL(clk_get_fpi);
0048
0049 struct clk *clk_get_io(void)
0050 {
0051 return &cpu_clk_generic[2];
0052 }
0053 EXPORT_SYMBOL_GPL(clk_get_io);
0054
0055 struct clk *clk_get_ppe(void)
0056 {
0057 return &cpu_clk_generic[3];
0058 }
0059 EXPORT_SYMBOL_GPL(clk_get_ppe);
0060
0061 static inline int clk_good(struct clk *clk)
0062 {
0063 return clk && !IS_ERR(clk);
0064 }
0065
0066 unsigned long clk_get_rate(struct clk *clk)
0067 {
0068 if (unlikely(!clk_good(clk)))
0069 return 0;
0070
0071 if (clk->rate != 0)
0072 return clk->rate;
0073
0074 if (clk->get_rate != NULL)
0075 return clk->get_rate();
0076
0077 return 0;
0078 }
0079 EXPORT_SYMBOL(clk_get_rate);
0080
0081 int clk_set_rate(struct clk *clk, unsigned long rate)
0082 {
0083 if (unlikely(!clk_good(clk)))
0084 return 0;
0085 if (clk->rates && *clk->rates) {
0086 unsigned long *r = clk->rates;
0087
0088 while (*r && (*r != rate))
0089 r++;
0090 if (!*r) {
0091 pr_err("clk %s.%s: trying to set invalid rate %ld\n",
0092 clk->cl.dev_id, clk->cl.con_id, rate);
0093 return -1;
0094 }
0095 }
0096 clk->rate = rate;
0097 return 0;
0098 }
0099 EXPORT_SYMBOL(clk_set_rate);
0100
0101 long clk_round_rate(struct clk *clk, unsigned long rate)
0102 {
0103 if (unlikely(!clk_good(clk)))
0104 return 0;
0105 if (clk->rates && *clk->rates) {
0106 unsigned long *r = clk->rates;
0107
0108 while (*r && (*r != rate))
0109 r++;
0110 if (!*r) {
0111 return clk->rate;
0112 }
0113 }
0114 return rate;
0115 }
0116 EXPORT_SYMBOL(clk_round_rate);
0117
0118 int clk_enable(struct clk *clk)
0119 {
0120 if (unlikely(!clk_good(clk)))
0121 return -1;
0122
0123 if (clk->enable)
0124 return clk->enable(clk);
0125
0126 return -1;
0127 }
0128 EXPORT_SYMBOL(clk_enable);
0129
0130 void clk_disable(struct clk *clk)
0131 {
0132 if (unlikely(!clk_good(clk)))
0133 return;
0134
0135 if (clk->disable)
0136 clk->disable(clk);
0137 }
0138 EXPORT_SYMBOL(clk_disable);
0139
0140 int clk_activate(struct clk *clk)
0141 {
0142 if (unlikely(!clk_good(clk)))
0143 return -1;
0144
0145 if (clk->activate)
0146 return clk->activate(clk);
0147
0148 return -1;
0149 }
0150 EXPORT_SYMBOL(clk_activate);
0151
0152 void clk_deactivate(struct clk *clk)
0153 {
0154 if (unlikely(!clk_good(clk)))
0155 return;
0156
0157 if (clk->deactivate)
0158 clk->deactivate(clk);
0159 }
0160 EXPORT_SYMBOL(clk_deactivate);
0161
0162 struct clk *clk_get_parent(struct clk *clk)
0163 {
0164 return NULL;
0165 }
0166 EXPORT_SYMBOL(clk_get_parent);
0167
0168 int clk_set_parent(struct clk *clk, struct clk *parent)
0169 {
0170 return 0;
0171 }
0172 EXPORT_SYMBOL(clk_set_parent);
0173
0174 static inline u32 get_counter_resolution(void)
0175 {
0176 u32 res;
0177
0178 __asm__ __volatile__(
0179 ".set push\n"
0180 ".set mips32r2\n"
0181 "rdhwr %0, $3\n"
0182 ".set pop\n"
0183 : "=&r" (res)
0184 :
0185 : "memory");
0186
0187 return res;
0188 }
0189
0190 void __init plat_time_init(void)
0191 {
0192 struct clk *clk;
0193
0194 ltq_soc_init();
0195
0196 clk = clk_get_cpu();
0197 mips_hpt_frequency = clk_get_rate(clk) / get_counter_resolution();
0198 write_c0_compare(read_c0_count());
0199 pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000);
0200 clk_put(clk);
0201 }