OMAP: McBSP: implement functional clock switching via clock framework
[pandora-kernel.git] / arch / arm / mach-omap2 / mcbsp.c
1 /*
2  * linux/arch/arm/mach-omap2/mcbsp.c
3  *
4  * Copyright (C) 2008 Instituto Nokia de Tecnologia
5  * Contact: Eduardo Valentin <eduardo.valentin@indt.org.br>
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  * Multichannel mode not supported.
12  */
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/clk.h>
16 #include <linux/err.h>
17 #include <linux/io.h>
18 #include <linux/platform_device.h>
19 #include <linux/slab.h>
20
21 #include <mach/irqs.h>
22 #include <plat/dma.h>
23 #include <plat/cpu.h>
24 #include <plat/mcbsp.h>
25 #include <plat/control.h>
26
27 /* McBSP internal signal muxing functions */
28
29 void omap2_mcbsp1_mux_clkr_src(u8 mux)
30 {
31         u32 v;
32
33         v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
34         if (mux == CLKR_SRC_CLKR)
35                 v &= OMAP2_MCBSP1_CLKR_MASK;
36         else if (mux == CLKR_SRC_CLKX)
37                 v |= OMAP2_MCBSP1_CLKR_MASK;
38         omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
39 }
40 EXPORT_SYMBOL(omap2_mcbsp1_mux_clkr_src);
41
42 void omap2_mcbsp1_mux_fsr_src(u8 mux)
43 {
44         u32 v;
45
46         v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
47         if (mux == FSR_SRC_FSR)
48                 v &= OMAP2_MCBSP1_FSR_MASK;
49         else if (mux == FSR_SRC_FSX)
50                 v |= OMAP2_MCBSP1_FSR_MASK;
51         omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
52 }
53 EXPORT_SYMBOL(omap2_mcbsp1_mux_fsr_src);
54
55 /* McBSP CLKS source switching function */
56
57 int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id)
58 {
59         struct omap_mcbsp *mcbsp;
60         struct clk *fck_src;
61         char *fck_src_name;
62         int r;
63
64         if (!omap_mcbsp_check_valid_id(id)) {
65                 pr_err("%s: Invalid id (%d)\n", __func__, id + 1);
66                 return -EINVAL;
67         }
68         mcbsp = id_to_mcbsp_ptr(id);
69
70         if (fck_src_id == MCBSP_CLKS_PAD_SRC)
71                 fck_src_name = "pad_fck";
72         else if (fck_src_id == MCBSP_CLKS_PRCM_SRC)
73                 fck_src_name = "prcm_fck";
74         else
75                 return -EINVAL;
76
77         fck_src = clk_get(mcbsp->dev, fck_src_name);
78         if (IS_ERR_OR_NULL(fck_src)) {
79                 pr_err("omap-mcbsp: %s: could not clk_get() %s\n", "clks",
80                        fck_src_name);
81                 return -EINVAL;
82         }
83
84         clk_disable(mcbsp->fclk);
85
86         r = clk_set_parent(mcbsp->fclk, fck_src);
87         if (IS_ERR_VALUE(r)) {
88                 pr_err("omap-mcbsp: %s: could not clk_set_parent() to %s\n",
89                        "clks", fck_src_name);
90                 clk_put(fck_src);
91                 return -EINVAL;
92         }
93
94         clk_enable(mcbsp->fclk);
95
96         clk_put(fck_src);
97
98         return 0;
99 }
100 EXPORT_SYMBOL(omap2_mcbsp_set_clks_src);
101
102
103 /* Platform data */
104
105 #ifdef CONFIG_ARCH_OMAP2420
106 static struct omap_mcbsp_platform_data omap2420_mcbsp_pdata[] = {
107         {
108                 .phys_base      = OMAP24XX_MCBSP1_BASE,
109                 .dma_rx_sync    = OMAP24XX_DMA_MCBSP1_RX,
110                 .dma_tx_sync    = OMAP24XX_DMA_MCBSP1_TX,
111                 .rx_irq         = INT_24XX_MCBSP1_IRQ_RX,
112                 .tx_irq         = INT_24XX_MCBSP1_IRQ_TX,
113         },
114         {
115                 .phys_base      = OMAP24XX_MCBSP2_BASE,
116                 .dma_rx_sync    = OMAP24XX_DMA_MCBSP2_RX,
117                 .dma_tx_sync    = OMAP24XX_DMA_MCBSP2_TX,
118                 .rx_irq         = INT_24XX_MCBSP2_IRQ_RX,
119                 .tx_irq         = INT_24XX_MCBSP2_IRQ_TX,
120         },
121 };
122 #define OMAP2420_MCBSP_PDATA_SZ         ARRAY_SIZE(omap2420_mcbsp_pdata)
123 #define OMAP2420_MCBSP_REG_NUM          (OMAP_MCBSP_REG_RCCR / sizeof(u32) + 1)
124 #else
125 #define omap2420_mcbsp_pdata            NULL
126 #define OMAP2420_MCBSP_PDATA_SZ         0
127 #define OMAP2420_MCBSP_REG_NUM          0
128 #endif
129
130 #ifdef CONFIG_ARCH_OMAP2430
131 static struct omap_mcbsp_platform_data omap2430_mcbsp_pdata[] = {
132         {
133                 .phys_base      = OMAP24XX_MCBSP1_BASE,
134                 .dma_rx_sync    = OMAP24XX_DMA_MCBSP1_RX,
135                 .dma_tx_sync    = OMAP24XX_DMA_MCBSP1_TX,
136                 .rx_irq         = INT_24XX_MCBSP1_IRQ_RX,
137                 .tx_irq         = INT_24XX_MCBSP1_IRQ_TX,
138         },
139         {
140                 .phys_base      = OMAP24XX_MCBSP2_BASE,
141                 .dma_rx_sync    = OMAP24XX_DMA_MCBSP2_RX,
142                 .dma_tx_sync    = OMAP24XX_DMA_MCBSP2_TX,
143                 .rx_irq         = INT_24XX_MCBSP2_IRQ_RX,
144                 .tx_irq         = INT_24XX_MCBSP2_IRQ_TX,
145         },
146         {
147                 .phys_base      = OMAP2430_MCBSP3_BASE,
148                 .dma_rx_sync    = OMAP24XX_DMA_MCBSP3_RX,
149                 .dma_tx_sync    = OMAP24XX_DMA_MCBSP3_TX,
150                 .rx_irq         = INT_24XX_MCBSP3_IRQ_RX,
151                 .tx_irq         = INT_24XX_MCBSP3_IRQ_TX,
152         },
153         {
154                 .phys_base      = OMAP2430_MCBSP4_BASE,
155                 .dma_rx_sync    = OMAP24XX_DMA_MCBSP4_RX,
156                 .dma_tx_sync    = OMAP24XX_DMA_MCBSP4_TX,
157                 .rx_irq         = INT_24XX_MCBSP4_IRQ_RX,
158                 .tx_irq         = INT_24XX_MCBSP4_IRQ_TX,
159         },
160         {
161                 .phys_base      = OMAP2430_MCBSP5_BASE,
162                 .dma_rx_sync    = OMAP24XX_DMA_MCBSP5_RX,
163                 .dma_tx_sync    = OMAP24XX_DMA_MCBSP5_TX,
164                 .rx_irq         = INT_24XX_MCBSP5_IRQ_RX,
165                 .tx_irq         = INT_24XX_MCBSP5_IRQ_TX,
166         },
167 };
168 #define OMAP2430_MCBSP_PDATA_SZ         ARRAY_SIZE(omap2430_mcbsp_pdata)
169 #define OMAP2430_MCBSP_REG_NUM          (OMAP_MCBSP_REG_RCCR / sizeof(u32) + 1)
170 #else
171 #define omap2430_mcbsp_pdata            NULL
172 #define OMAP2430_MCBSP_PDATA_SZ         0
173 #define OMAP2430_MCBSP_REG_NUM          0
174 #endif
175
176 #ifdef CONFIG_ARCH_OMAP3
177 static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
178         {
179                 .phys_base      = OMAP34XX_MCBSP1_BASE,
180                 .dma_rx_sync    = OMAP24XX_DMA_MCBSP1_RX,
181                 .dma_tx_sync    = OMAP24XX_DMA_MCBSP1_TX,
182                 .rx_irq         = INT_24XX_MCBSP1_IRQ_RX,
183                 .tx_irq         = INT_24XX_MCBSP1_IRQ_TX,
184                 .buffer_size    = 0x80, /* The FIFO has 128 locations */
185         },
186         {
187                 .phys_base      = OMAP34XX_MCBSP2_BASE,
188                 .phys_base_st   = OMAP34XX_MCBSP2_ST_BASE,
189                 .dma_rx_sync    = OMAP24XX_DMA_MCBSP2_RX,
190                 .dma_tx_sync    = OMAP24XX_DMA_MCBSP2_TX,
191                 .rx_irq         = INT_24XX_MCBSP2_IRQ_RX,
192                 .tx_irq         = INT_24XX_MCBSP2_IRQ_TX,
193                 .buffer_size    = 0x500, /* The FIFO has 1024 + 256 locations */
194         },
195         {
196                 .phys_base      = OMAP34XX_MCBSP3_BASE,
197                 .phys_base_st   = OMAP34XX_MCBSP3_ST_BASE,
198                 .dma_rx_sync    = OMAP24XX_DMA_MCBSP3_RX,
199                 .dma_tx_sync    = OMAP24XX_DMA_MCBSP3_TX,
200                 .rx_irq         = INT_24XX_MCBSP3_IRQ_RX,
201                 .tx_irq         = INT_24XX_MCBSP3_IRQ_TX,
202                 .buffer_size    = 0x80, /* The FIFO has 128 locations */
203         },
204         {
205                 .phys_base      = OMAP34XX_MCBSP4_BASE,
206                 .dma_rx_sync    = OMAP24XX_DMA_MCBSP4_RX,
207                 .dma_tx_sync    = OMAP24XX_DMA_MCBSP4_TX,
208                 .rx_irq         = INT_24XX_MCBSP4_IRQ_RX,
209                 .tx_irq         = INT_24XX_MCBSP4_IRQ_TX,
210                 .buffer_size    = 0x80, /* The FIFO has 128 locations */
211         },
212         {
213                 .phys_base      = OMAP34XX_MCBSP5_BASE,
214                 .dma_rx_sync    = OMAP24XX_DMA_MCBSP5_RX,
215                 .dma_tx_sync    = OMAP24XX_DMA_MCBSP5_TX,
216                 .rx_irq         = INT_24XX_MCBSP5_IRQ_RX,
217                 .tx_irq         = INT_24XX_MCBSP5_IRQ_TX,
218                 .buffer_size    = 0x80, /* The FIFO has 128 locations */
219         },
220 };
221 #define OMAP34XX_MCBSP_PDATA_SZ         ARRAY_SIZE(omap34xx_mcbsp_pdata)
222 #define OMAP34XX_MCBSP_REG_NUM          (OMAP_MCBSP_REG_RCCR / sizeof(u32) + 1)
223 #else
224 #define omap34xx_mcbsp_pdata            NULL
225 #define OMAP34XX_MCBSP_PDATA_SZ         0
226 #define OMAP34XX_MCBSP_REG_NUM          0
227 #endif
228
229 static struct omap_mcbsp_platform_data omap44xx_mcbsp_pdata[] = {
230         {
231                 .phys_base      = OMAP44XX_MCBSP1_BASE,
232                 .dma_rx_sync    = OMAP44XX_DMA_MCBSP1_RX,
233                 .dma_tx_sync    = OMAP44XX_DMA_MCBSP1_TX,
234                 .tx_irq         = OMAP44XX_IRQ_MCBSP1,
235         },
236         {
237                 .phys_base      = OMAP44XX_MCBSP2_BASE,
238                 .dma_rx_sync    = OMAP44XX_DMA_MCBSP2_RX,
239                 .dma_tx_sync    = OMAP44XX_DMA_MCBSP2_TX,
240                 .tx_irq         = OMAP44XX_IRQ_MCBSP2,
241                 /* XXX .ops ? */
242         },
243         {
244                 .phys_base      = OMAP44XX_MCBSP3_BASE,
245                 .dma_rx_sync    = OMAP44XX_DMA_MCBSP3_RX,
246                 .dma_tx_sync    = OMAP44XX_DMA_MCBSP3_TX,
247                 .tx_irq         = OMAP44XX_IRQ_MCBSP3,
248                 /* XXX .ops ? */
249         },
250         {
251                 .phys_base      = OMAP44XX_MCBSP4_BASE,
252                 .dma_rx_sync    = OMAP44XX_DMA_MCBSP4_RX,
253                 .dma_tx_sync    = OMAP44XX_DMA_MCBSP4_TX,
254                 .tx_irq         = OMAP44XX_IRQ_MCBSP4,
255                 /* XXX .ops ? */
256         },
257 };
258 #define OMAP44XX_MCBSP_PDATA_SZ         ARRAY_SIZE(omap44xx_mcbsp_pdata)
259 #define OMAP44XX_MCBSP_REG_NUM          (OMAP_MCBSP_REG_RCCR / sizeof(u32) + 1)
260
261 static int __init omap2_mcbsp_init(void)
262 {
263         if (cpu_is_omap2420()) {
264                 omap_mcbsp_count = OMAP2420_MCBSP_PDATA_SZ;
265                 omap_mcbsp_cache_size = OMAP2420_MCBSP_REG_NUM * sizeof(u16);
266         } else if (cpu_is_omap2430()) {
267                 omap_mcbsp_count = OMAP2430_MCBSP_PDATA_SZ;
268                 omap_mcbsp_cache_size = OMAP2430_MCBSP_REG_NUM * sizeof(u32);
269         } else if (cpu_is_omap34xx()) {
270                 omap_mcbsp_count = OMAP34XX_MCBSP_PDATA_SZ;
271                 omap_mcbsp_cache_size = OMAP34XX_MCBSP_REG_NUM * sizeof(u32);
272         } else if (cpu_is_omap44xx()) {
273                 omap_mcbsp_count = OMAP44XX_MCBSP_PDATA_SZ;
274                 omap_mcbsp_cache_size = OMAP44XX_MCBSP_REG_NUM * sizeof(u32);
275         }
276
277         mcbsp_ptr = kzalloc(omap_mcbsp_count * sizeof(struct omap_mcbsp *),
278                                                                 GFP_KERNEL);
279         if (!mcbsp_ptr)
280                 return -ENOMEM;
281
282         if (cpu_is_omap2420())
283                 omap_mcbsp_register_board_cfg(omap2420_mcbsp_pdata,
284                                                 OMAP2420_MCBSP_PDATA_SZ);
285         if (cpu_is_omap2430())
286                 omap_mcbsp_register_board_cfg(omap2430_mcbsp_pdata,
287                                                 OMAP2430_MCBSP_PDATA_SZ);
288         if (cpu_is_omap34xx())
289                 omap_mcbsp_register_board_cfg(omap34xx_mcbsp_pdata,
290                                                 OMAP34XX_MCBSP_PDATA_SZ);
291         if (cpu_is_omap44xx())
292                 omap_mcbsp_register_board_cfg(omap44xx_mcbsp_pdata,
293                                                 OMAP44XX_MCBSP_PDATA_SZ);
294
295         return omap_mcbsp_init();
296 }
297 arch_initcall(omap2_mcbsp_init);