]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/arm/plat-s3c24xx/clock-dclk.c
ASoC: Merge dai_ops factor out
[karo-tx-linux.git] / arch / arm / plat-s3c24xx / clock-dclk.c
1 /* linux/arch/arm/plat-s3c24xx/clock-dclk.c
2  *
3  * Copyright (c) 2004,2008 Simtec Electronics
4  *      Ben Dooks <ben@simtec.co.uk>
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 #include <mach/hardware.h>
22
23 #include <plat/clock.h>
24 #include <plat/cpu.h>
25
26 /* clocks that could be registered by external code */
27
28 static int s3c24xx_dclk_enable(struct clk *clk, int enable)
29 {
30         unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
31
32         if (enable)
33                 dclkcon |= clk->ctrlbit;
34         else
35                 dclkcon &= ~clk->ctrlbit;
36
37         __raw_writel(dclkcon, S3C24XX_DCLKCON);
38
39         return 0;
40 }
41
42 static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
43 {
44         unsigned long dclkcon;
45         unsigned int uclk;
46
47         if (parent == &clk_upll)
48                 uclk = 1;
49         else if (parent == &clk_p)
50                 uclk = 0;
51         else
52                 return -EINVAL;
53
54         clk->parent = parent;
55
56         dclkcon = __raw_readl(S3C24XX_DCLKCON);
57
58         if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
59                 if (uclk)
60                         dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK;
61                 else
62                         dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK;
63         } else {
64                 if (uclk)
65                         dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK;
66                 else
67                         dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
68         }
69
70         __raw_writel(dclkcon, S3C24XX_DCLKCON);
71
72         return 0;
73 }
74 static unsigned long s3c24xx_calc_div(struct clk *clk, unsigned long rate)
75 {
76         unsigned long div;
77
78         if ((rate == 0) || !clk->parent)
79                 return 0;
80
81         div = clk_get_rate(clk->parent) / rate;
82         if (div < 2)
83                 div = 2;
84         else if (div > 16)
85                 div = 16;
86
87         return div;
88 }
89
90 static unsigned long s3c24xx_round_dclk_rate(struct clk *clk,
91         unsigned long rate)
92 {
93         unsigned long div = s3c24xx_calc_div(clk, rate);
94
95         if (div == 0)
96                 return 0;
97
98         return clk_get_rate(clk->parent) / div;
99 }
100
101 static int s3c24xx_set_dclk_rate(struct clk *clk, unsigned long rate)
102 {
103         unsigned long mask, data, div = s3c24xx_calc_div(clk, rate);
104
105         if (div == 0)
106                 return -EINVAL;
107
108         if (clk == &s3c24xx_dclk0) {
109                 mask = S3C2410_DCLKCON_DCLK0_DIV_MASK |
110                         S3C2410_DCLKCON_DCLK0_CMP_MASK;
111                 data = S3C2410_DCLKCON_DCLK0_DIV(div) |
112                         S3C2410_DCLKCON_DCLK0_CMP((div + 1) / 2);
113         } else if (clk == &s3c24xx_dclk1) {
114                 mask = S3C2410_DCLKCON_DCLK1_DIV_MASK |
115                         S3C2410_DCLKCON_DCLK1_CMP_MASK;
116                 data = S3C2410_DCLKCON_DCLK1_DIV(div) |
117                         S3C2410_DCLKCON_DCLK1_CMP((div + 1) / 2);
118         } else
119                 return -EINVAL;
120
121         clk->rate = clk_get_rate(clk->parent) / div;
122         __raw_writel(((__raw_readl(S3C24XX_DCLKCON) & ~mask) | data),
123                 S3C24XX_DCLKCON);
124         return clk->rate;
125 }
126 static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent)
127 {
128         unsigned long mask;
129         unsigned long source;
130
131         /* calculate the MISCCR setting for the clock */
132
133         if (parent == &clk_xtal)
134                 source = S3C2410_MISCCR_CLK0_MPLL;
135         else if (parent == &clk_upll)
136                 source = S3C2410_MISCCR_CLK0_UPLL;
137         else if (parent == &clk_f)
138                 source = S3C2410_MISCCR_CLK0_FCLK;
139         else if (parent == &clk_h)
140                 source = S3C2410_MISCCR_CLK0_HCLK;
141         else if (parent == &clk_p)
142                 source = S3C2410_MISCCR_CLK0_PCLK;
143         else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0)
144                 source = S3C2410_MISCCR_CLK0_DCLK0;
145         else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1)
146                 source = S3C2410_MISCCR_CLK0_DCLK0;
147         else
148                 return -EINVAL;
149
150         clk->parent = parent;
151
152         if (clk == &s3c24xx_clkout0)
153                 mask = S3C2410_MISCCR_CLK0_MASK;
154         else {
155                 source <<= 4;
156                 mask = S3C2410_MISCCR_CLK1_MASK;
157         }
158
159         s3c2410_modify_misccr(mask, source);
160         return 0;
161 }
162
163 /* external clock definitions */
164
165 struct clk s3c24xx_dclk0 = {
166         .name           = "dclk0",
167         .id             = -1,
168         .ctrlbit        = S3C2410_DCLKCON_DCLK0EN,
169         .enable         = s3c24xx_dclk_enable,
170         .set_parent     = s3c24xx_dclk_setparent,
171         .set_rate       = s3c24xx_set_dclk_rate,
172         .round_rate     = s3c24xx_round_dclk_rate,
173 };
174
175 struct clk s3c24xx_dclk1 = {
176         .name           = "dclk1",
177         .id             = -1,
178         .ctrlbit        = S3C2410_DCLKCON_DCLK1EN,
179         .enable         = s3c24xx_dclk_enable,
180         .set_parent     = s3c24xx_dclk_setparent,
181         .set_rate       = s3c24xx_set_dclk_rate,
182         .round_rate     = s3c24xx_round_dclk_rate,
183 };
184
185 struct clk s3c24xx_clkout0 = {
186         .name           = "clkout0",
187         .id             = -1,
188         .set_parent     = s3c24xx_clkout_setparent,
189 };
190
191 struct clk s3c24xx_clkout1 = {
192         .name           = "clkout1",
193         .id             = -1,
194         .set_parent     = s3c24xx_clkout_setparent,
195 };