Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
clock.c
Go to the documentation of this file.
1 /*
2  * Clock management for AT32AP CPUs
3  *
4  * Copyright (C) 2006 Atmel Corporation
5  *
6  * Based on arch/arm/mach-at91/clock.c
7  * Copyright (C) 2005 David Brownell
8  * Copyright (C) 2005 Ivan Kokshaysky
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  */
14 #include <linux/clk.h>
15 #include <linux/err.h>
16 #include <linux/export.h>
17 #include <linux/device.h>
18 #include <linux/string.h>
19 #include <linux/list.h>
20 
21 #include <mach/chip.h>
22 
23 #include "clock.h"
24 
25 /* at32 clock list */
26 static LIST_HEAD(at32_clock_list);
27 
28 static DEFINE_SPINLOCK(clk_lock);
29 static DEFINE_SPINLOCK(clk_list_lock);
30 
31 void at32_clk_register(struct clk *clk)
32 {
33  spin_lock(&clk_list_lock);
34  /* add the new item to the end of the list */
35  list_add_tail(&clk->list, &at32_clock_list);
36  spin_unlock(&clk_list_lock);
37 }
38 
39 static struct clk *__clk_get(struct device *dev, const char *id)
40 {
41  struct clk *clk;
42 
43  list_for_each_entry(clk, &at32_clock_list, list) {
44  if (clk->dev == dev && strcmp(id, clk->name) == 0) {
45  return clk;
46  }
47  }
48 
49  return ERR_PTR(-ENOENT);
50 }
51 
52 struct clk *clk_get(struct device *dev, const char *id)
53 {
54  struct clk *clk;
55 
56  spin_lock(&clk_list_lock);
57  clk = __clk_get(dev, id);
58  spin_unlock(&clk_list_lock);
59 
60  return clk;
61 }
62 
64 
65 void clk_put(struct clk *clk)
66 {
67  /* clocks are static for now, we can't free them */
68 }
70 
71 static void __clk_enable(struct clk *clk)
72 {
73  if (clk->parent)
74  __clk_enable(clk->parent);
75  if (clk->users++ == 0 && clk->mode)
76  clk->mode(clk, 1);
77 }
78 
79 int clk_enable(struct clk *clk)
80 {
81  unsigned long flags;
82 
83  spin_lock_irqsave(&clk_lock, flags);
84  __clk_enable(clk);
85  spin_unlock_irqrestore(&clk_lock, flags);
86 
87  return 0;
88 }
90 
91 static void __clk_disable(struct clk *clk)
92 {
93  if (clk->users == 0) {
94  printk(KERN_ERR "%s: mismatched disable\n", clk->name);
95  WARN_ON(1);
96  return;
97  }
98 
99  if (--clk->users == 0 && clk->mode)
100  clk->mode(clk, 0);
101  if (clk->parent)
102  __clk_disable(clk->parent);
103 }
104 
105 void clk_disable(struct clk *clk)
106 {
107  unsigned long flags;
108 
109  spin_lock_irqsave(&clk_lock, flags);
110  __clk_disable(clk);
111  spin_unlock_irqrestore(&clk_lock, flags);
112 }
114 
115 unsigned long clk_get_rate(struct clk *clk)
116 {
117  unsigned long flags;
118  unsigned long rate;
119 
120  spin_lock_irqsave(&clk_lock, flags);
121  rate = clk->get_rate(clk);
122  spin_unlock_irqrestore(&clk_lock, flags);
123 
124  return rate;
125 }
127 
128 long clk_round_rate(struct clk *clk, unsigned long rate)
129 {
130  unsigned long flags, actual_rate;
131 
132  if (!clk->set_rate)
133  return -ENOSYS;
134 
135  spin_lock_irqsave(&clk_lock, flags);
136  actual_rate = clk->set_rate(clk, rate, 0);
137  spin_unlock_irqrestore(&clk_lock, flags);
138 
139  return actual_rate;
140 }
142 
143 int clk_set_rate(struct clk *clk, unsigned long rate)
144 {
145  unsigned long flags;
146  long ret;
147 
148  if (!clk->set_rate)
149  return -ENOSYS;
150 
151  spin_lock_irqsave(&clk_lock, flags);
152  ret = clk->set_rate(clk, rate, 1);
153  spin_unlock_irqrestore(&clk_lock, flags);
154 
155  return (ret < 0) ? ret : 0;
156 }
158 
159 int clk_set_parent(struct clk *clk, struct clk *parent)
160 {
161  unsigned long flags;
162  int ret;
163 
164  if (!clk->set_parent)
165  return -ENOSYS;
166 
167  spin_lock_irqsave(&clk_lock, flags);
168  ret = clk->set_parent(clk, parent);
169  spin_unlock_irqrestore(&clk_lock, flags);
170 
171  return ret;
172 }
174 
175 struct clk *clk_get_parent(struct clk *clk)
176 {
177  return clk->parent;
178 }
180 
181 
182 
183 #ifdef CONFIG_DEBUG_FS
184 
185 /* /sys/kernel/debug/at32ap_clk */
186 
187 #include <linux/io.h>
188 #include <linux/debugfs.h>
189 #include <linux/seq_file.h>
190 #include "pm.h"
191 
192 
193 #define NEST_DELTA 2
194 #define NEST_MAX 6
195 
196 struct clkinf {
197  struct seq_file *s;
198  unsigned nest;
199 };
200 
201 static void
202 dump_clock(struct clk *parent, struct clkinf *r)
203 {
204  unsigned nest = r->nest;
205  char buf[16 + NEST_MAX];
206  struct clk *clk;
207  unsigned i;
208 
209  /* skip clocks coupled to devices that aren't registered */
210  if (parent->dev && !dev_name(parent->dev) && !parent->users)
211  return;
212 
213  /* <nest spaces> name <pad to end> */
214  memset(buf, ' ', sizeof(buf) - 1);
215  buf[sizeof(buf) - 1] = 0;
216  i = strlen(parent->name);
217  memcpy(buf + nest, parent->name,
218  min(i, (unsigned)(sizeof(buf) - 1 - nest)));
219 
220  seq_printf(r->s, "%s%c users=%2d %-3s %9ld Hz",
221  buf, parent->set_parent ? '*' : ' ',
222  parent->users,
223  parent->users ? "on" : "off", /* NOTE: not-paranoid!! */
224  clk_get_rate(parent));
225  if (parent->dev)
226  seq_printf(r->s, ", for %s", dev_name(parent->dev));
227  seq_printf(r->s, "\n");
228 
229  /* cost of this scan is small, but not linear... */
230  r->nest = nest + NEST_DELTA;
231 
232  list_for_each_entry(clk, &at32_clock_list, list) {
233  if (clk->parent == parent)
234  dump_clock(clk, r);
235  }
236  r->nest = nest;
237 }
238 
239 static int clk_show(struct seq_file *s, void *unused)
240 {
241  struct clkinf r;
242  int i;
243  struct clk *clk;
244 
245  /* show all the power manager registers */
246  seq_printf(s, "MCCTRL = %8x\n", pm_readl(MCCTRL));
247  seq_printf(s, "CKSEL = %8x\n", pm_readl(CKSEL));
248  seq_printf(s, "CPUMASK = %8x\n", pm_readl(CPU_MASK));
249  seq_printf(s, "HSBMASK = %8x\n", pm_readl(HSB_MASK));
250  seq_printf(s, "PBAMASK = %8x\n", pm_readl(PBA_MASK));
251  seq_printf(s, "PBBMASK = %8x\n", pm_readl(PBB_MASK));
252  seq_printf(s, "PLL0 = %8x\n", pm_readl(PLL0));
253  seq_printf(s, "PLL1 = %8x\n", pm_readl(PLL1));
254  seq_printf(s, "IMR = %8x\n", pm_readl(IMR));
255  for (i = 0; i < 8; i++) {
256  if (i == 5)
257  continue;
258  seq_printf(s, "GCCTRL%d = %8x\n", i, pm_readl(GCCTRL(i)));
259  }
260 
261  seq_printf(s, "\n");
262 
263  r.s = s;
264  r.nest = 0;
265  /* protected from changes on the list while dumping */
266  spin_lock(&clk_list_lock);
267 
268  /* show clock tree as derived from the three oscillators */
269  clk = __clk_get(NULL, "osc32k");
270  dump_clock(clk, &r);
271  clk_put(clk);
272 
273  clk = __clk_get(NULL, "osc0");
274  dump_clock(clk, &r);
275  clk_put(clk);
276 
277  clk = __clk_get(NULL, "osc1");
278  dump_clock(clk, &r);
279  clk_put(clk);
280 
281  spin_unlock(&clk_list_lock);
282 
283  return 0;
284 }
285 
286 static int clk_open(struct inode *inode, struct file *file)
287 {
288  return single_open(file, clk_show, NULL);
289 }
290 
291 static const struct file_operations clk_operations = {
292  .open = clk_open,
293  .read = seq_read,
294  .llseek = seq_lseek,
295  .release = single_release,
296 };
297 
298 static int __init clk_debugfs_init(void)
299 {
300  (void) debugfs_create_file("at32ap_clk", S_IFREG | S_IRUGO,
301  NULL, NULL, &clk_operations);
302 
303  return 0;
304 }
305 postcore_initcall(clk_debugfs_init);
306 
307 #endif