]> git.itanic.dy.fi Git - linux-stable/blob - arch/mips/lantiq/clk.c
7a623684d9b5ed415e167af74e0b9af22ea5d74c
[linux-stable] / arch / mips / lantiq / clk.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *
4  * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com>
5  * Copyright (C) 2010 John Crispin <john@phrozen.org>
6  */
7 #include <linux/io.h>
8 #include <linux/export.h>
9 #include <linux/init.h>
10 #include <linux/kernel.h>
11 #include <linux/types.h>
12 #include <linux/clk.h>
13 #include <linux/clkdev.h>
14 #include <linux/err.h>
15 #include <linux/list.h>
16
17 #include <asm/time.h>
18 #include <asm/irq.h>
19 #include <asm/div64.h>
20
21 #include <lantiq_soc.h>
22
23 #include "clk.h"
24 #include "prom.h"
25
26 /* lantiq socs have 3 static clocks */
27 static struct clk cpu_clk_generic[4];
28
29 void clkdev_add_static(unsigned long cpu, unsigned long fpi,
30                         unsigned long io, unsigned long ppe)
31 {
32         cpu_clk_generic[0].rate = cpu;
33         cpu_clk_generic[1].rate = fpi;
34         cpu_clk_generic[2].rate = io;
35         cpu_clk_generic[3].rate = ppe;
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 struct clk *clk_get_ppe(void)
55 {
56         return &cpu_clk_generic[3];
57 }
58 EXPORT_SYMBOL_GPL(clk_get_ppe);
59
60 static inline int clk_good(struct clk *clk)
61 {
62         return clk && !IS_ERR(clk);
63 }
64
65 unsigned long clk_get_rate(struct clk *clk)
66 {
67         if (unlikely(!clk_good(clk)))
68                 return 0;
69
70         if (clk->rate != 0)
71                 return clk->rate;
72
73         if (clk->get_rate != NULL)
74                 return clk->get_rate();
75
76         return 0;
77 }
78 EXPORT_SYMBOL(clk_get_rate);
79
80 int clk_set_rate(struct clk *clk, unsigned long rate)
81 {
82         if (unlikely(!clk_good(clk)))
83                 return 0;
84         if (clk->rates && *clk->rates) {
85                 unsigned long *r = clk->rates;
86
87                 while (*r && (*r != rate))
88                         r++;
89                 if (!*r) {
90                         pr_err("clk %s.%s: trying to set invalid rate %ld\n",
91                                 clk->cl.dev_id, clk->cl.con_id, rate);
92                         return -1;
93                 }
94         }
95         clk->rate = rate;
96         return 0;
97 }
98 EXPORT_SYMBOL(clk_set_rate);
99
100 long clk_round_rate(struct clk *clk, unsigned long rate)
101 {
102         if (unlikely(!clk_good(clk)))
103                 return 0;
104         if (clk->rates && *clk->rates) {
105                 unsigned long *r = clk->rates;
106
107                 while (*r && (*r != rate))
108                         r++;
109                 if (!*r) {
110                         return clk->rate;
111                 }
112         }
113         return rate;
114 }
115 EXPORT_SYMBOL(clk_round_rate);
116
117 int clk_enable(struct clk *clk)
118 {
119         if (unlikely(!clk_good(clk)))
120                 return -1;
121
122         if (clk->enable)
123                 return clk->enable(clk);
124
125         return -1;
126 }
127 EXPORT_SYMBOL(clk_enable);
128
129 void clk_disable(struct clk *clk)
130 {
131         if (unlikely(!clk_good(clk)))
132                 return;
133
134         if (clk->disable)
135                 clk->disable(clk);
136 }
137 EXPORT_SYMBOL(clk_disable);
138
139 int clk_activate(struct clk *clk)
140 {
141         if (unlikely(!clk_good(clk)))
142                 return -1;
143
144         if (clk->activate)
145                 return clk->activate(clk);
146
147         return -1;
148 }
149 EXPORT_SYMBOL(clk_activate);
150
151 void clk_deactivate(struct clk *clk)
152 {
153         if (unlikely(!clk_good(clk)))
154                 return;
155
156         if (clk->deactivate)
157                 clk->deactivate(clk);
158 }
159 EXPORT_SYMBOL(clk_deactivate);
160
161 struct clk *clk_get_parent(struct clk *clk)
162 {
163         return NULL;
164 }
165 EXPORT_SYMBOL(clk_get_parent);
166
167 int clk_set_parent(struct clk *clk, struct clk *parent)
168 {
169         return 0;
170 }
171 EXPORT_SYMBOL(clk_set_parent);
172
173 static inline u32 get_counter_resolution(void)
174 {
175         u32 res;
176
177         __asm__ __volatile__(
178                 ".set   push\n"
179                 ".set   mips32r2\n"
180                 "rdhwr  %0, $3\n"
181                 ".set pop\n"
182                 : "=&r" (res)
183                 : /* no input */
184                 : "memory");
185
186         return res;
187 }
188
189 void __init plat_time_init(void)
190 {
191         struct clk *clk;
192
193         ltq_soc_init();
194
195         clk = clk_get_cpu();
196         mips_hpt_frequency = clk_get_rate(clk) / get_counter_resolution();
197         write_c0_compare(read_c0_count());
198         pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000);
199         clk_put(clk);
200 }