Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
clock-dclk.c
Go to the documentation of this file.
1 /* linux/arch/arm/plat-s3c24xx/clock-dclk.c
2  *
3  * Copyright (c) 2004-2008 Simtec Electronics
4  * Ben Dooks <[email protected]>
5  * http://armlinux.simtec.co.uk/
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  * S3C24XX - definitions for DCLK and CLKOUT registers
12  */
13 
14 #include <linux/kernel.h>
15 #include <linux/errno.h>
16 #include <linux/clk.h>
17 #include <linux/io.h>
18 
19 #include <mach/regs-clock.h>
20 #include <mach/regs-gpio.h>
21 
22 #include <plat/clock.h>
23 #include <plat/cpu.h>
24 
25 /* clocks that could be registered by external code */
26 
27 static int s3c24xx_dclk_enable(struct clk *clk, int enable)
28 {
29  unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
30 
31  if (enable)
32  dclkcon |= clk->ctrlbit;
33  else
34  dclkcon &= ~clk->ctrlbit;
35 
36  __raw_writel(dclkcon, S3C24XX_DCLKCON);
37 
38  return 0;
39 }
40 
41 static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
42 {
43  unsigned long dclkcon;
44  unsigned int uclk;
45 
46  if (parent == &clk_upll)
47  uclk = 1;
48  else if (parent == &clk_p)
49  uclk = 0;
50  else
51  return -EINVAL;
52 
53  clk->parent = parent;
54 
55  dclkcon = __raw_readl(S3C24XX_DCLKCON);
56 
57  if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
58  if (uclk)
59  dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK;
60  else
61  dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK;
62  } else {
63  if (uclk)
64  dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK;
65  else
66  dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
67  }
68 
69  __raw_writel(dclkcon, S3C24XX_DCLKCON);
70 
71  return 0;
72 }
73 static unsigned long s3c24xx_calc_div(struct clk *clk, unsigned long rate)
74 {
75  unsigned long div;
76 
77  if ((rate == 0) || !clk->parent)
78  return 0;
79 
80  div = clk_get_rate(clk->parent) / rate;
81  if (div < 2)
82  div = 2;
83  else if (div > 16)
84  div = 16;
85 
86  return div;
87 }
88 
89 static unsigned long s3c24xx_round_dclk_rate(struct clk *clk,
90  unsigned long rate)
91 {
92  unsigned long div = s3c24xx_calc_div(clk, rate);
93 
94  if (div == 0)
95  return 0;
96 
97  return clk_get_rate(clk->parent) / div;
98 }
99 
100 static int s3c24xx_set_dclk_rate(struct clk *clk, unsigned long rate)
101 {
102  unsigned long mask, data, div = s3c24xx_calc_div(clk, rate);
103 
104  if (div == 0)
105  return -EINVAL;
106 
107  if (clk == &s3c24xx_dclk0) {
110  data = S3C2410_DCLKCON_DCLK0_DIV(div) |
111  S3C2410_DCLKCON_DCLK0_CMP((div + 1) / 2);
112  } else if (clk == &s3c24xx_dclk1) {
115  data = S3C2410_DCLKCON_DCLK1_DIV(div) |
116  S3C2410_DCLKCON_DCLK1_CMP((div + 1) / 2);
117  } else
118  return -EINVAL;
119 
120  clk->rate = clk_get_rate(clk->parent) / div;
121  __raw_writel(((__raw_readl(S3C24XX_DCLKCON) & ~mask) | data),
123  return clk->rate;
124 }
125 static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent)
126 {
127  unsigned long mask;
128  unsigned long source;
129 
130  /* calculate the MISCCR setting for the clock */
131 
132  if (parent == &clk_mpll)
133  source = S3C2410_MISCCR_CLK0_MPLL;
134  else if (parent == &clk_upll)
135  source = S3C2410_MISCCR_CLK0_UPLL;
136  else if (parent == &clk_f)
137  source = S3C2410_MISCCR_CLK0_FCLK;
138  else if (parent == &clk_h)
139  source = S3C2410_MISCCR_CLK0_HCLK;
140  else if (parent == &clk_p)
141  source = S3C2410_MISCCR_CLK0_PCLK;
142  else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0)
143  source = S3C2410_MISCCR_CLK0_DCLK0;
144  else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1)
145  source = S3C2410_MISCCR_CLK0_DCLK0;
146  else
147  return -EINVAL;
148 
149  clk->parent = parent;
150 
151  if (clk == &s3c24xx_clkout0)
153  else {
154  source <<= 4;
156  }
157 
158  s3c2410_modify_misccr(mask, source);
159  return 0;
160 }
161 
162 /* external clock definitions */
163 
164 static struct clk_ops dclk_ops = {
165  .set_parent = s3c24xx_dclk_setparent,
166  .set_rate = s3c24xx_set_dclk_rate,
167  .round_rate = s3c24xx_round_dclk_rate,
168 };
169 
170 struct clk s3c24xx_dclk0 = {
171  .name = "dclk0",
172  .ctrlbit = S3C2410_DCLKCON_DCLK0EN,
173  .enable = s3c24xx_dclk_enable,
174  .ops = &dclk_ops,
175 };
176 
177 struct clk s3c24xx_dclk1 = {
178  .name = "dclk1",
179  .ctrlbit = S3C2410_DCLKCON_DCLK1EN,
180  .enable = s3c24xx_dclk_enable,
181  .ops = &dclk_ops,
182 };
183 
184 static struct clk_ops clkout_ops = {
185  .set_parent = s3c24xx_clkout_setparent,
186 };
187 
188 struct clk s3c24xx_clkout0 = {
189  .name = "clkout0",
190  .ops = &clkout_ops,
191 };
192 
193 struct clk s3c24xx_clkout1 = {
194  .name = "clkout1",
195  .ops = &clkout_ops,
196 };