Commit | Line | Data |
---|---|---|
5e1c5ff4 TL |
1 | /* |
2 | * linux/arch/arm/plat-omap/mcbsp.c | |
3 | * | |
4 | * Copyright (C) 2004 Nokia Corporation | |
5 | * Author: Samuel Ortiz <samuel.ortiz@nokia.com> | |
6 | * | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | * | |
12 | * Multichannel mode not supported. | |
13 | */ | |
14 | ||
15 | #include <linux/module.h> | |
16 | #include <linux/init.h> | |
17 | #include <linux/device.h> | |
18 | #include <linux/wait.h> | |
19 | #include <linux/completion.h> | |
20 | #include <linux/interrupt.h> | |
21 | #include <linux/err.h> | |
f8ce2547 | 22 | #include <linux/clk.h> |
04fbf6a2 | 23 | #include <linux/delay.h> |
5e1c5ff4 | 24 | |
5e1c5ff4 TL |
25 | #include <asm/io.h> |
26 | #include <asm/irq.h> | |
27 | ||
28 | #include <asm/arch/dma.h> | |
29 | #include <asm/arch/mux.h> | |
30 | #include <asm/arch/irqs.h> | |
92105bb7 | 31 | #include <asm/arch/dsp_common.h> |
5e1c5ff4 TL |
32 | #include <asm/arch/mcbsp.h> |
33 | ||
5e1c5ff4 TL |
34 | #ifdef CONFIG_MCBSP_DEBUG |
35 | #define DBG(x...) printk(x) | |
36 | #else | |
120db2cb | 37 | #define DBG(x...) do { } while (0) |
5e1c5ff4 TL |
38 | #endif |
39 | ||
40 | struct omap_mcbsp { | |
41 | u32 io_base; | |
42 | u8 id; | |
43 | u8 free; | |
44 | omap_mcbsp_word_length rx_word_length; | |
45 | omap_mcbsp_word_length tx_word_length; | |
46 | ||
120db2cb | 47 | omap_mcbsp_io_type_t io_type; /* IRQ or poll */ |
5e1c5ff4 TL |
48 | /* IRQ based TX/RX */ |
49 | int rx_irq; | |
50 | int tx_irq; | |
51 | ||
52 | /* DMA stuff */ | |
53 | u8 dma_rx_sync; | |
54 | short dma_rx_lch; | |
55 | u8 dma_tx_sync; | |
56 | short dma_tx_lch; | |
57 | ||
58 | /* Completion queues */ | |
59 | struct completion tx_irq_completion; | |
60 | struct completion rx_irq_completion; | |
61 | struct completion tx_dma_completion; | |
62 | struct completion rx_dma_completion; | |
63 | ||
64 | spinlock_t lock; | |
65 | }; | |
66 | ||
67 | static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT]; | |
120db2cb | 68 | #ifdef CONFIG_ARCH_OMAP1 |
5e1c5ff4 TL |
69 | static struct clk *mcbsp_dsp_ck = 0; |
70 | static struct clk *mcbsp_api_ck = 0; | |
bb13b5fd | 71 | static struct clk *mcbsp_dspxor_ck = 0; |
120db2cb TL |
72 | #endif |
73 | #ifdef CONFIG_ARCH_OMAP2 | |
74 | static struct clk *mcbsp1_ick = 0; | |
75 | static struct clk *mcbsp1_fck = 0; | |
76 | static struct clk *mcbsp2_ick = 0; | |
77 | static struct clk *mcbsp2_fck = 0; | |
120db2cb | 78 | #endif |
5e1c5ff4 TL |
79 | |
80 | static void omap_mcbsp_dump_reg(u8 id) | |
81 | { | |
82 | DBG("**** MCBSP%d regs ****\n", mcbsp[id].id); | |
83 | DBG("DRR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DRR2)); | |
84 | DBG("DRR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DRR1)); | |
85 | DBG("DXR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DXR2)); | |
86 | DBG("DXR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DXR1)); | |
87 | DBG("SPCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR2)); | |
88 | DBG("SPCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR1)); | |
89 | DBG("RCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, RCR2)); | |
90 | DBG("RCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, RCR1)); | |
91 | DBG("XCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, XCR2)); | |
92 | DBG("XCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, XCR1)); | |
93 | DBG("SRGR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR2)); | |
94 | DBG("SRGR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR1)); | |
95 | DBG("PCR0: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, PCR0)); | |
96 | DBG("***********************\n"); | |
97 | } | |
98 | ||
0cd61b68 | 99 | static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id) |
5e1c5ff4 TL |
100 | { |
101 | struct omap_mcbsp * mcbsp_tx = (struct omap_mcbsp *)(dev_id); | |
102 | ||
103 | DBG("TX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2)); | |
104 | ||
105 | complete(&mcbsp_tx->tx_irq_completion); | |
106 | return IRQ_HANDLED; | |
107 | } | |
108 | ||
0cd61b68 | 109 | static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id) |
5e1c5ff4 TL |
110 | { |
111 | struct omap_mcbsp * mcbsp_rx = (struct omap_mcbsp *)(dev_id); | |
112 | ||
113 | DBG("RX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR2)); | |
114 | ||
115 | complete(&mcbsp_rx->rx_irq_completion); | |
116 | return IRQ_HANDLED; | |
117 | } | |
118 | ||
5e1c5ff4 TL |
119 | static void omap_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data) |
120 | { | |
121 | struct omap_mcbsp * mcbsp_dma_tx = (struct omap_mcbsp *)(data); | |
122 | ||
123 | DBG("TX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_tx->io_base, SPCR2)); | |
124 | ||
125 | /* We can free the channels */ | |
126 | omap_free_dma(mcbsp_dma_tx->dma_tx_lch); | |
127 | mcbsp_dma_tx->dma_tx_lch = -1; | |
128 | ||
129 | complete(&mcbsp_dma_tx->tx_dma_completion); | |
130 | } | |
131 | ||
132 | static void omap_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data) | |
133 | { | |
134 | struct omap_mcbsp * mcbsp_dma_rx = (struct omap_mcbsp *)(data); | |
135 | ||
136 | DBG("RX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_rx->io_base, SPCR2)); | |
137 | ||
138 | /* We can free the channels */ | |
139 | omap_free_dma(mcbsp_dma_rx->dma_rx_lch); | |
140 | mcbsp_dma_rx->dma_rx_lch = -1; | |
141 | ||
142 | complete(&mcbsp_dma_rx->rx_dma_completion); | |
143 | } | |
144 | ||
145 | ||
146 | /* | |
147 | * omap_mcbsp_config simply write a config to the | |
148 | * appropriate McBSP. | |
149 | * You either call this function or set the McBSP registers | |
150 | * by yourself before calling omap_mcbsp_start(). | |
151 | */ | |
152 | ||
153 | void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config) | |
154 | { | |
155 | u32 io_base = mcbsp[id].io_base; | |
156 | ||
157 | DBG("OMAP-McBSP: McBSP%d io_base: 0x%8x\n", id+1, io_base); | |
158 | ||
159 | /* We write the given config */ | |
160 | OMAP_MCBSP_WRITE(io_base, SPCR2, config->spcr2); | |
161 | OMAP_MCBSP_WRITE(io_base, SPCR1, config->spcr1); | |
162 | OMAP_MCBSP_WRITE(io_base, RCR2, config->rcr2); | |
163 | OMAP_MCBSP_WRITE(io_base, RCR1, config->rcr1); | |
164 | OMAP_MCBSP_WRITE(io_base, XCR2, config->xcr2); | |
165 | OMAP_MCBSP_WRITE(io_base, XCR1, config->xcr1); | |
166 | OMAP_MCBSP_WRITE(io_base, SRGR2, config->srgr2); | |
167 | OMAP_MCBSP_WRITE(io_base, SRGR1, config->srgr1); | |
168 | OMAP_MCBSP_WRITE(io_base, MCR2, config->mcr2); | |
169 | OMAP_MCBSP_WRITE(io_base, MCR1, config->mcr1); | |
170 | OMAP_MCBSP_WRITE(io_base, PCR0, config->pcr0); | |
171 | } | |
172 | ||
173 | ||
174 | ||
175 | static int omap_mcbsp_check(unsigned int id) | |
176 | { | |
177 | if (cpu_is_omap730()) { | |
178 | if (id > OMAP_MAX_MCBSP_COUNT - 1) { | |
179 | printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1); | |
180 | return -1; | |
181 | } | |
182 | return 0; | |
183 | } | |
184 | ||
120db2cb | 185 | if (cpu_is_omap15xx() || cpu_is_omap16xx() || cpu_is_omap24xx()) { |
5e1c5ff4 TL |
186 | if (id > OMAP_MAX_MCBSP_COUNT) { |
187 | printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1); | |
188 | return -1; | |
189 | } | |
190 | return 0; | |
191 | } | |
192 | ||
193 | return -1; | |
194 | } | |
195 | ||
120db2cb | 196 | #ifdef CONFIG_ARCH_OMAP1 |
5e1c5ff4 TL |
197 | static void omap_mcbsp_dsp_request(void) |
198 | { | |
120db2cb | 199 | if (cpu_is_omap15xx() || cpu_is_omap16xx()) { |
30ff720b TL |
200 | clk_enable(mcbsp_dsp_ck); |
201 | clk_enable(mcbsp_api_ck); | |
5e1c5ff4 TL |
202 | |
203 | /* enable 12MHz clock to mcbsp 1 & 3 */ | |
30ff720b | 204 | clk_enable(mcbsp_dspxor_ck); |
92105bb7 TL |
205 | |
206 | /* | |
207 | * DSP external peripheral reset | |
208 | * FIXME: This should be moved to dsp code | |
209 | */ | |
5e1c5ff4 TL |
210 | __raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1 << 1, |
211 | DSP_RSTCT2); | |
212 | } | |
213 | } | |
214 | ||
215 | static void omap_mcbsp_dsp_free(void) | |
216 | { | |
120db2cb | 217 | if (cpu_is_omap15xx() || cpu_is_omap16xx()) { |
30ff720b TL |
218 | clk_disable(mcbsp_dspxor_ck); |
219 | clk_disable(mcbsp_dsp_ck); | |
220 | clk_disable(mcbsp_api_ck); | |
bb13b5fd | 221 | } |
5e1c5ff4 | 222 | } |
120db2cb TL |
223 | #endif |
224 | ||
225 | #ifdef CONFIG_ARCH_OMAP2 | |
226 | static void omap2_mcbsp2_mux_setup(void) | |
227 | { | |
56a25641 SMK |
228 | if (cpu_is_omap2420()) { |
229 | omap_cfg_reg(Y15_24XX_MCBSP2_CLKX); | |
230 | omap_cfg_reg(R14_24XX_MCBSP2_FSX); | |
231 | omap_cfg_reg(W15_24XX_MCBSP2_DR); | |
232 | omap_cfg_reg(V15_24XX_MCBSP2_DX); | |
233 | omap_cfg_reg(V14_24XX_GPIO117); | |
234 | } | |
235 | /* | |
236 | * Need to add MUX settings for OMAP 2430 SDP | |
237 | */ | |
120db2cb TL |
238 | } |
239 | #endif | |
240 | ||
241 | /* | |
242 | * We can choose between IRQ based or polled IO. | |
243 | * This needs to be called before omap_mcbsp_request(). | |
244 | */ | |
245 | int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type) | |
246 | { | |
247 | if (omap_mcbsp_check(id) < 0) | |
248 | return -EINVAL; | |
249 | ||
250 | spin_lock(&mcbsp[id].lock); | |
251 | ||
252 | if (!mcbsp[id].free) { | |
253 | printk (KERN_ERR "OMAP-McBSP: McBSP%d is currently in use\n", id + 1); | |
254 | spin_unlock(&mcbsp[id].lock); | |
255 | return -EINVAL; | |
256 | } | |
257 | ||
258 | mcbsp[id].io_type = io_type; | |
259 | ||
260 | spin_unlock(&mcbsp[id].lock); | |
261 | ||
262 | return 0; | |
263 | } | |
5e1c5ff4 | 264 | |
5e1c5ff4 TL |
265 | int omap_mcbsp_request(unsigned int id) |
266 | { | |
267 | int err; | |
268 | ||
269 | if (omap_mcbsp_check(id) < 0) | |
270 | return -EINVAL; | |
271 | ||
120db2cb | 272 | #ifdef CONFIG_ARCH_OMAP1 |
5e1c5ff4 TL |
273 | /* |
274 | * On 1510, 1610 and 1710, McBSP1 and McBSP3 | |
275 | * are DSP public peripherals. | |
276 | */ | |
277 | if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3) | |
278 | omap_mcbsp_dsp_request(); | |
120db2cb TL |
279 | #endif |
280 | ||
281 | #ifdef CONFIG_ARCH_OMAP2 | |
282 | if (cpu_is_omap24xx()) { | |
283 | if (id == OMAP_MCBSP1) { | |
284 | clk_enable(mcbsp1_ick); | |
285 | clk_enable(mcbsp1_fck); | |
286 | } else { | |
287 | clk_enable(mcbsp2_ick); | |
288 | clk_enable(mcbsp2_fck); | |
289 | } | |
290 | } | |
291 | #endif | |
5e1c5ff4 TL |
292 | |
293 | spin_lock(&mcbsp[id].lock); | |
294 | if (!mcbsp[id].free) { | |
295 | printk (KERN_ERR "OMAP-McBSP: McBSP%d is currently in use\n", id + 1); | |
296 | spin_unlock(&mcbsp[id].lock); | |
297 | return -1; | |
298 | } | |
299 | ||
300 | mcbsp[id].free = 0; | |
301 | spin_unlock(&mcbsp[id].lock); | |
302 | ||
120db2cb TL |
303 | if (mcbsp[id].io_type == OMAP_MCBSP_IRQ_IO) { |
304 | /* We need to get IRQs here */ | |
305 | err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler, 0, | |
306 | "McBSP", | |
307 | (void *) (&mcbsp[id])); | |
308 | if (err != 0) { | |
309 | printk(KERN_ERR "OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d\n", | |
310 | mcbsp[id].tx_irq, mcbsp[id].id); | |
311 | return err; | |
312 | } | |
5e1c5ff4 | 313 | |
120db2cb | 314 | init_completion(&(mcbsp[id].tx_irq_completion)); |
5e1c5ff4 TL |
315 | |
316 | ||
120db2cb TL |
317 | err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler, 0, |
318 | "McBSP", | |
319 | (void *) (&mcbsp[id])); | |
320 | if (err != 0) { | |
321 | printk(KERN_ERR "OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d\n", | |
322 | mcbsp[id].rx_irq, mcbsp[id].id); | |
323 | free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id])); | |
324 | return err; | |
325 | } | |
326 | ||
327 | init_completion(&(mcbsp[id].rx_irq_completion)); | |
5e1c5ff4 TL |
328 | } |
329 | ||
5e1c5ff4 TL |
330 | return 0; |
331 | ||
332 | } | |
333 | ||
334 | void omap_mcbsp_free(unsigned int id) | |
335 | { | |
336 | if (omap_mcbsp_check(id) < 0) | |
337 | return; | |
338 | ||
120db2cb TL |
339 | #ifdef CONFIG_ARCH_OMAP1 |
340 | if (cpu_class_is_omap1()) { | |
341 | if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3) | |
342 | omap_mcbsp_dsp_free(); | |
343 | } | |
344 | #endif | |
345 | ||
346 | #ifdef CONFIG_ARCH_OMAP2 | |
347 | if (cpu_is_omap24xx()) { | |
348 | if (id == OMAP_MCBSP1) { | |
349 | clk_disable(mcbsp1_ick); | |
350 | clk_disable(mcbsp1_fck); | |
351 | } else { | |
352 | clk_disable(mcbsp2_ick); | |
353 | clk_disable(mcbsp2_fck); | |
354 | } | |
355 | } | |
356 | #endif | |
5e1c5ff4 TL |
357 | |
358 | spin_lock(&mcbsp[id].lock); | |
359 | if (mcbsp[id].free) { | |
360 | printk (KERN_ERR "OMAP-McBSP: McBSP%d was not reserved\n", id + 1); | |
361 | spin_unlock(&mcbsp[id].lock); | |
362 | return; | |
363 | } | |
364 | ||
365 | mcbsp[id].free = 1; | |
366 | spin_unlock(&mcbsp[id].lock); | |
367 | ||
120db2cb TL |
368 | if (mcbsp[id].io_type == OMAP_MCBSP_IRQ_IO) { |
369 | /* Free IRQs */ | |
370 | free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id])); | |
371 | free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id])); | |
372 | } | |
5e1c5ff4 TL |
373 | } |
374 | ||
375 | /* | |
376 | * Here we start the McBSP, by enabling the sample | |
377 | * generator, both transmitter and receivers, | |
378 | * and the frame sync. | |
379 | */ | |
380 | void omap_mcbsp_start(unsigned int id) | |
381 | { | |
382 | u32 io_base; | |
383 | u16 w; | |
384 | ||
385 | if (omap_mcbsp_check(id) < 0) | |
386 | return; | |
387 | ||
388 | io_base = mcbsp[id].io_base; | |
389 | ||
390 | mcbsp[id].rx_word_length = ((OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7); | |
391 | mcbsp[id].tx_word_length = ((OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7); | |
392 | ||
393 | /* Start the sample generator */ | |
394 | w = OMAP_MCBSP_READ(io_base, SPCR2); | |
395 | OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6)); | |
396 | ||
397 | /* Enable transmitter and receiver */ | |
398 | w = OMAP_MCBSP_READ(io_base, SPCR2); | |
399 | OMAP_MCBSP_WRITE(io_base, SPCR2, w | 1); | |
400 | ||
401 | w = OMAP_MCBSP_READ(io_base, SPCR1); | |
402 | OMAP_MCBSP_WRITE(io_base, SPCR1, w | 1); | |
403 | ||
404 | udelay(100); | |
405 | ||
406 | /* Start frame sync */ | |
407 | w = OMAP_MCBSP_READ(io_base, SPCR2); | |
408 | OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7)); | |
409 | ||
410 | /* Dump McBSP Regs */ | |
411 | omap_mcbsp_dump_reg(id); | |
412 | ||
413 | } | |
414 | ||
415 | void omap_mcbsp_stop(unsigned int id) | |
416 | { | |
417 | u32 io_base; | |
418 | u16 w; | |
419 | ||
420 | if (omap_mcbsp_check(id) < 0) | |
421 | return; | |
422 | ||
423 | io_base = mcbsp[id].io_base; | |
424 | ||
425 | /* Reset transmitter */ | |
426 | w = OMAP_MCBSP_READ(io_base, SPCR2); | |
427 | OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1)); | |
428 | ||
429 | /* Reset receiver */ | |
430 | w = OMAP_MCBSP_READ(io_base, SPCR1); | |
431 | OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(1)); | |
432 | ||
433 | /* Reset the sample rate generator */ | |
434 | w = OMAP_MCBSP_READ(io_base, SPCR2); | |
435 | OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6)); | |
436 | } | |
437 | ||
438 | ||
bb13b5fd TL |
439 | /* polled mcbsp i/o operations */ |
440 | int omap_mcbsp_pollwrite(unsigned int id, u16 buf) | |
441 | { | |
442 | u32 base = mcbsp[id].io_base; | |
443 | writew(buf, base + OMAP_MCBSP_REG_DXR1); | |
444 | /* if frame sync error - clear the error */ | |
445 | if (readw(base + OMAP_MCBSP_REG_SPCR2) & XSYNC_ERR) { | |
446 | /* clear error */ | |
447 | writew(readw(base + OMAP_MCBSP_REG_SPCR2) & (~XSYNC_ERR), | |
448 | base + OMAP_MCBSP_REG_SPCR2); | |
449 | /* resend */ | |
450 | return -1; | |
451 | } else { | |
452 | /* wait for transmit confirmation */ | |
453 | int attemps = 0; | |
454 | while (!(readw(base + OMAP_MCBSP_REG_SPCR2) & XRDY)) { | |
455 | if (attemps++ > 1000) { | |
456 | writew(readw(base + OMAP_MCBSP_REG_SPCR2) & | |
457 | (~XRST), | |
458 | base + OMAP_MCBSP_REG_SPCR2); | |
459 | udelay(10); | |
460 | writew(readw(base + OMAP_MCBSP_REG_SPCR2) | | |
461 | (XRST), | |
462 | base + OMAP_MCBSP_REG_SPCR2); | |
463 | udelay(10); | |
464 | printk(KERN_ERR | |
465 | " Could not write to McBSP Register\n"); | |
466 | return -2; | |
467 | } | |
468 | } | |
469 | } | |
470 | return 0; | |
471 | } | |
472 | ||
473 | int omap_mcbsp_pollread(unsigned int id, u16 * buf) | |
474 | { | |
475 | u32 base = mcbsp[id].io_base; | |
476 | /* if frame sync error - clear the error */ | |
477 | if (readw(base + OMAP_MCBSP_REG_SPCR1) & RSYNC_ERR) { | |
478 | /* clear error */ | |
479 | writew(readw(base + OMAP_MCBSP_REG_SPCR1) & (~RSYNC_ERR), | |
480 | base + OMAP_MCBSP_REG_SPCR1); | |
481 | /* resend */ | |
482 | return -1; | |
483 | } else { | |
484 | /* wait for recieve confirmation */ | |
485 | int attemps = 0; | |
486 | while (!(readw(base + OMAP_MCBSP_REG_SPCR1) & RRDY)) { | |
487 | if (attemps++ > 1000) { | |
488 | writew(readw(base + OMAP_MCBSP_REG_SPCR1) & | |
489 | (~RRST), | |
490 | base + OMAP_MCBSP_REG_SPCR1); | |
491 | udelay(10); | |
492 | writew(readw(base + OMAP_MCBSP_REG_SPCR1) | | |
493 | (RRST), | |
494 | base + OMAP_MCBSP_REG_SPCR1); | |
495 | udelay(10); | |
496 | printk(KERN_ERR | |
497 | " Could not read from McBSP Register\n"); | |
498 | return -2; | |
499 | } | |
500 | } | |
501 | } | |
502 | *buf = readw(base + OMAP_MCBSP_REG_DRR1); | |
503 | return 0; | |
504 | } | |
505 | ||
5e1c5ff4 TL |
506 | /* |
507 | * IRQ based word transmission. | |
508 | */ | |
509 | void omap_mcbsp_xmit_word(unsigned int id, u32 word) | |
510 | { | |
511 | u32 io_base; | |
512 | omap_mcbsp_word_length word_length = mcbsp[id].tx_word_length; | |
513 | ||
514 | if (omap_mcbsp_check(id) < 0) | |
515 | return; | |
516 | ||
517 | io_base = mcbsp[id].io_base; | |
518 | ||
519 | wait_for_completion(&(mcbsp[id].tx_irq_completion)); | |
520 | ||
521 | if (word_length > OMAP_MCBSP_WORD_16) | |
522 | OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16); | |
523 | OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff); | |
524 | } | |
525 | ||
526 | u32 omap_mcbsp_recv_word(unsigned int id) | |
527 | { | |
528 | u32 io_base; | |
529 | u16 word_lsb, word_msb = 0; | |
530 | omap_mcbsp_word_length word_length = mcbsp[id].rx_word_length; | |
531 | ||
532 | if (omap_mcbsp_check(id) < 0) | |
533 | return -EINVAL; | |
534 | ||
535 | io_base = mcbsp[id].io_base; | |
536 | ||
537 | wait_for_completion(&(mcbsp[id].rx_irq_completion)); | |
538 | ||
539 | if (word_length > OMAP_MCBSP_WORD_16) | |
540 | word_msb = OMAP_MCBSP_READ(io_base, DRR2); | |
541 | word_lsb = OMAP_MCBSP_READ(io_base, DRR1); | |
542 | ||
543 | return (word_lsb | (word_msb << 16)); | |
544 | } | |
545 | ||
546 | ||
120db2cb TL |
547 | int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word) |
548 | { | |
549 | u32 io_base = mcbsp[id].io_base; | |
550 | omap_mcbsp_word_length tx_word_length = mcbsp[id].tx_word_length; | |
551 | omap_mcbsp_word_length rx_word_length = mcbsp[id].rx_word_length; | |
552 | u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0; | |
553 | ||
554 | if (tx_word_length != rx_word_length) | |
555 | return -EINVAL; | |
556 | ||
557 | /* First we wait for the transmitter to be ready */ | |
558 | spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); | |
559 | while (!(spcr2 & XRDY)) { | |
560 | spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); | |
561 | if (attempts++ > 1000) { | |
562 | /* We must reset the transmitter */ | |
563 | OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 & (~XRST)); | |
564 | udelay(10); | |
565 | OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST); | |
566 | udelay(10); | |
567 | printk("McBSP transmitter not ready\n"); | |
568 | return -EAGAIN; | |
569 | } | |
570 | } | |
571 | ||
572 | /* Now we can push the data */ | |
573 | if (tx_word_length > OMAP_MCBSP_WORD_16) | |
574 | OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16); | |
575 | OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff); | |
576 | ||
577 | /* We wait for the receiver to be ready */ | |
578 | spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); | |
579 | while (!(spcr1 & RRDY)) { | |
580 | spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); | |
581 | if (attempts++ > 1000) { | |
582 | /* We must reset the receiver */ | |
583 | OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 & (~RRST)); | |
584 | udelay(10); | |
585 | OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST); | |
586 | udelay(10); | |
587 | printk("McBSP receiver not ready\n"); | |
588 | return -EAGAIN; | |
589 | } | |
590 | } | |
591 | ||
592 | /* Receiver is ready, let's read the dummy data */ | |
593 | if (rx_word_length > OMAP_MCBSP_WORD_16) | |
594 | word_msb = OMAP_MCBSP_READ(io_base, DRR2); | |
595 | word_lsb = OMAP_MCBSP_READ(io_base, DRR1); | |
596 | ||
597 | return 0; | |
598 | } | |
599 | ||
600 | int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 * word) | |
601 | { | |
602 | u32 io_base = mcbsp[id].io_base, clock_word = 0; | |
603 | omap_mcbsp_word_length tx_word_length = mcbsp[id].tx_word_length; | |
604 | omap_mcbsp_word_length rx_word_length = mcbsp[id].rx_word_length; | |
605 | u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0; | |
606 | ||
607 | if (tx_word_length != rx_word_length) | |
608 | return -EINVAL; | |
609 | ||
610 | /* First we wait for the transmitter to be ready */ | |
611 | spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); | |
612 | while (!(spcr2 & XRDY)) { | |
613 | spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); | |
614 | if (attempts++ > 1000) { | |
615 | /* We must reset the transmitter */ | |
616 | OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 & (~XRST)); | |
617 | udelay(10); | |
618 | OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST); | |
619 | udelay(10); | |
620 | printk("McBSP transmitter not ready\n"); | |
621 | return -EAGAIN; | |
622 | } | |
623 | } | |
624 | ||
625 | /* We first need to enable the bus clock */ | |
626 | if (tx_word_length > OMAP_MCBSP_WORD_16) | |
627 | OMAP_MCBSP_WRITE(io_base, DXR2, clock_word >> 16); | |
628 | OMAP_MCBSP_WRITE(io_base, DXR1, clock_word & 0xffff); | |
629 | ||
630 | /* We wait for the receiver to be ready */ | |
631 | spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); | |
632 | while (!(spcr1 & RRDY)) { | |
633 | spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); | |
634 | if (attempts++ > 1000) { | |
635 | /* We must reset the receiver */ | |
636 | OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 & (~RRST)); | |
637 | udelay(10); | |
638 | OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST); | |
639 | udelay(10); | |
640 | printk("McBSP receiver not ready\n"); | |
641 | return -EAGAIN; | |
642 | } | |
643 | } | |
644 | ||
645 | /* Receiver is ready, there is something for us */ | |
646 | if (rx_word_length > OMAP_MCBSP_WORD_16) | |
647 | word_msb = OMAP_MCBSP_READ(io_base, DRR2); | |
648 | word_lsb = OMAP_MCBSP_READ(io_base, DRR1); | |
649 | ||
650 | word[0] = (word_lsb | (word_msb << 16)); | |
651 | ||
652 | return 0; | |
653 | } | |
654 | ||
655 | ||
5e1c5ff4 TL |
656 | /* |
657 | * Simple DMA based buffer rx/tx routines. | |
658 | * Nothing fancy, just a single buffer tx/rx through DMA. | |
659 | * The DMA resources are released once the transfer is done. | |
660 | * For anything fancier, you should use your own customized DMA | |
661 | * routines and callbacks. | |
662 | */ | |
663 | int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length) | |
664 | { | |
665 | int dma_tx_ch; | |
120db2cb TL |
666 | int src_port = 0; |
667 | int dest_port = 0; | |
668 | int sync_dev = 0; | |
5e1c5ff4 TL |
669 | |
670 | if (omap_mcbsp_check(id) < 0) | |
671 | return -EINVAL; | |
672 | ||
673 | if (omap_request_dma(mcbsp[id].dma_tx_sync, "McBSP TX", omap_mcbsp_tx_dma_callback, | |
674 | &mcbsp[id], | |
675 | &dma_tx_ch)) { | |
676 | printk("OMAP-McBSP: Unable to request DMA channel for McBSP%d TX. Trying IRQ based TX\n", id+1); | |
677 | return -EAGAIN; | |
678 | } | |
679 | mcbsp[id].dma_tx_lch = dma_tx_ch; | |
680 | ||
681 | DBG("TX DMA on channel %d\n", dma_tx_ch); | |
682 | ||
683 | init_completion(&(mcbsp[id].tx_dma_completion)); | |
684 | ||
120db2cb TL |
685 | if (cpu_class_is_omap1()) { |
686 | src_port = OMAP_DMA_PORT_TIPB; | |
687 | dest_port = OMAP_DMA_PORT_EMIFF; | |
688 | } | |
689 | if (cpu_is_omap24xx()) | |
690 | sync_dev = mcbsp[id].dma_tx_sync; | |
691 | ||
5e1c5ff4 TL |
692 | omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch, |
693 | OMAP_DMA_DATA_TYPE_S16, | |
694 | length >> 1, 1, | |
1a8bfa1e | 695 | OMAP_DMA_SYNC_ELEMENT, |
120db2cb | 696 | sync_dev, 0); |
5e1c5ff4 TL |
697 | |
698 | omap_set_dma_dest_params(mcbsp[id].dma_tx_lch, | |
120db2cb | 699 | src_port, |
5e1c5ff4 | 700 | OMAP_DMA_AMODE_CONSTANT, |
1a8bfa1e TL |
701 | mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1, |
702 | 0, 0); | |
5e1c5ff4 TL |
703 | |
704 | omap_set_dma_src_params(mcbsp[id].dma_tx_lch, | |
120db2cb | 705 | dest_port, |
5e1c5ff4 | 706 | OMAP_DMA_AMODE_POST_INC, |
1a8bfa1e TL |
707 | buffer, |
708 | 0, 0); | |
5e1c5ff4 TL |
709 | |
710 | omap_start_dma(mcbsp[id].dma_tx_lch); | |
711 | wait_for_completion(&(mcbsp[id].tx_dma_completion)); | |
712 | return 0; | |
713 | } | |
714 | ||
715 | ||
716 | int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length) | |
717 | { | |
718 | int dma_rx_ch; | |
120db2cb TL |
719 | int src_port = 0; |
720 | int dest_port = 0; | |
721 | int sync_dev = 0; | |
5e1c5ff4 TL |
722 | |
723 | if (omap_mcbsp_check(id) < 0) | |
724 | return -EINVAL; | |
725 | ||
726 | if (omap_request_dma(mcbsp[id].dma_rx_sync, "McBSP RX", omap_mcbsp_rx_dma_callback, | |
727 | &mcbsp[id], | |
728 | &dma_rx_ch)) { | |
729 | printk("Unable to request DMA channel for McBSP%d RX. Trying IRQ based RX\n", id+1); | |
730 | return -EAGAIN; | |
731 | } | |
732 | mcbsp[id].dma_rx_lch = dma_rx_ch; | |
733 | ||
734 | DBG("RX DMA on channel %d\n", dma_rx_ch); | |
735 | ||
736 | init_completion(&(mcbsp[id].rx_dma_completion)); | |
737 | ||
120db2cb TL |
738 | if (cpu_class_is_omap1()) { |
739 | src_port = OMAP_DMA_PORT_TIPB; | |
740 | dest_port = OMAP_DMA_PORT_EMIFF; | |
741 | } | |
742 | if (cpu_is_omap24xx()) | |
743 | sync_dev = mcbsp[id].dma_rx_sync; | |
744 | ||
5e1c5ff4 TL |
745 | omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch, |
746 | OMAP_DMA_DATA_TYPE_S16, | |
747 | length >> 1, 1, | |
1a8bfa1e | 748 | OMAP_DMA_SYNC_ELEMENT, |
120db2cb | 749 | sync_dev, 0); |
5e1c5ff4 TL |
750 | |
751 | omap_set_dma_src_params(mcbsp[id].dma_rx_lch, | |
120db2cb | 752 | src_port, |
5e1c5ff4 | 753 | OMAP_DMA_AMODE_CONSTANT, |
1a8bfa1e TL |
754 | mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1, |
755 | 0, 0); | |
5e1c5ff4 TL |
756 | |
757 | omap_set_dma_dest_params(mcbsp[id].dma_rx_lch, | |
120db2cb | 758 | dest_port, |
5e1c5ff4 | 759 | OMAP_DMA_AMODE_POST_INC, |
1a8bfa1e TL |
760 | buffer, |
761 | 0, 0); | |
5e1c5ff4 TL |
762 | |
763 | omap_start_dma(mcbsp[id].dma_rx_lch); | |
764 | wait_for_completion(&(mcbsp[id].rx_dma_completion)); | |
765 | return 0; | |
766 | } | |
767 | ||
768 | ||
769 | /* | |
770 | * SPI wrapper. | |
771 | * Since SPI setup is much simpler than the generic McBSP one, | |
772 | * this wrapper just need an omap_mcbsp_spi_cfg structure as an input. | |
773 | * Once this is done, you can call omap_mcbsp_start(). | |
774 | */ | |
775 | void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg) | |
776 | { | |
777 | struct omap_mcbsp_reg_cfg mcbsp_cfg; | |
778 | ||
779 | if (omap_mcbsp_check(id) < 0) | |
780 | return; | |
781 | ||
782 | memset(&mcbsp_cfg, 0, sizeof(struct omap_mcbsp_reg_cfg)); | |
783 | ||
784 | /* SPI has only one frame */ | |
785 | mcbsp_cfg.rcr1 |= (RWDLEN1(spi_cfg->word_length) | RFRLEN1(0)); | |
786 | mcbsp_cfg.xcr1 |= (XWDLEN1(spi_cfg->word_length) | XFRLEN1(0)); | |
787 | ||
788 | /* Clock stop mode */ | |
789 | if (spi_cfg->clk_stp_mode == OMAP_MCBSP_CLK_STP_MODE_NO_DELAY) | |
790 | mcbsp_cfg.spcr1 |= (1 << 12); | |
791 | else | |
792 | mcbsp_cfg.spcr1 |= (3 << 11); | |
793 | ||
794 | /* Set clock parities */ | |
795 | if (spi_cfg->rx_clock_polarity == OMAP_MCBSP_CLK_RISING) | |
796 | mcbsp_cfg.pcr0 |= CLKRP; | |
797 | else | |
798 | mcbsp_cfg.pcr0 &= ~CLKRP; | |
799 | ||
800 | if (spi_cfg->tx_clock_polarity == OMAP_MCBSP_CLK_RISING) | |
801 | mcbsp_cfg.pcr0 &= ~CLKXP; | |
802 | else | |
803 | mcbsp_cfg.pcr0 |= CLKXP; | |
804 | ||
805 | /* Set SCLKME to 0 and CLKSM to 1 */ | |
806 | mcbsp_cfg.pcr0 &= ~SCLKME; | |
807 | mcbsp_cfg.srgr2 |= CLKSM; | |
808 | ||
809 | /* Set FSXP */ | |
810 | if (spi_cfg->fsx_polarity == OMAP_MCBSP_FS_ACTIVE_HIGH) | |
811 | mcbsp_cfg.pcr0 &= ~FSXP; | |
812 | else | |
813 | mcbsp_cfg.pcr0 |= FSXP; | |
814 | ||
815 | if (spi_cfg->spi_mode == OMAP_MCBSP_SPI_MASTER) { | |
816 | mcbsp_cfg.pcr0 |= CLKXM; | |
817 | mcbsp_cfg.srgr1 |= CLKGDV(spi_cfg->clk_div -1); | |
818 | mcbsp_cfg.pcr0 |= FSXM; | |
819 | mcbsp_cfg.srgr2 &= ~FSGM; | |
820 | mcbsp_cfg.xcr2 |= XDATDLY(1); | |
821 | mcbsp_cfg.rcr2 |= RDATDLY(1); | |
822 | } | |
823 | else { | |
824 | mcbsp_cfg.pcr0 &= ~CLKXM; | |
825 | mcbsp_cfg.srgr1 |= CLKGDV(1); | |
826 | mcbsp_cfg.pcr0 &= ~FSXM; | |
827 | mcbsp_cfg.xcr2 &= ~XDATDLY(3); | |
828 | mcbsp_cfg.rcr2 &= ~RDATDLY(3); | |
829 | } | |
830 | ||
831 | mcbsp_cfg.xcr2 &= ~XPHASE; | |
832 | mcbsp_cfg.rcr2 &= ~RPHASE; | |
833 | ||
834 | omap_mcbsp_config(id, &mcbsp_cfg); | |
835 | } | |
836 | ||
837 | ||
838 | /* | |
839 | * McBSP1 and McBSP3 are directly mapped on 1610 and 1510. | |
840 | * 730 has only 2 McBSP, and both of them are MPU peripherals. | |
841 | */ | |
842 | struct omap_mcbsp_info { | |
843 | u32 virt_base; | |
844 | u8 dma_rx_sync, dma_tx_sync; | |
845 | u16 rx_irq, tx_irq; | |
846 | }; | |
847 | ||
848 | #ifdef CONFIG_ARCH_OMAP730 | |
849 | static const struct omap_mcbsp_info mcbsp_730[] = { | |
850 | [0] = { .virt_base = io_p2v(OMAP730_MCBSP1_BASE), | |
851 | .dma_rx_sync = OMAP_DMA_MCBSP1_RX, | |
852 | .dma_tx_sync = OMAP_DMA_MCBSP1_TX, | |
853 | .rx_irq = INT_730_McBSP1RX, | |
854 | .tx_irq = INT_730_McBSP1TX }, | |
855 | [1] = { .virt_base = io_p2v(OMAP730_MCBSP2_BASE), | |
856 | .dma_rx_sync = OMAP_DMA_MCBSP3_RX, | |
857 | .dma_tx_sync = OMAP_DMA_MCBSP3_TX, | |
858 | .rx_irq = INT_730_McBSP2RX, | |
859 | .tx_irq = INT_730_McBSP2TX }, | |
860 | }; | |
861 | #endif | |
862 | ||
1a8bfa1e | 863 | #ifdef CONFIG_ARCH_OMAP15XX |
5e1c5ff4 TL |
864 | static const struct omap_mcbsp_info mcbsp_1510[] = { |
865 | [0] = { .virt_base = OMAP1510_MCBSP1_BASE, | |
866 | .dma_rx_sync = OMAP_DMA_MCBSP1_RX, | |
867 | .dma_tx_sync = OMAP_DMA_MCBSP1_TX, | |
868 | .rx_irq = INT_McBSP1RX, | |
869 | .tx_irq = INT_McBSP1TX }, | |
870 | [1] = { .virt_base = io_p2v(OMAP1510_MCBSP2_BASE), | |
871 | .dma_rx_sync = OMAP_DMA_MCBSP2_RX, | |
872 | .dma_tx_sync = OMAP_DMA_MCBSP2_TX, | |
873 | .rx_irq = INT_1510_SPI_RX, | |
874 | .tx_irq = INT_1510_SPI_TX }, | |
875 | [2] = { .virt_base = OMAP1510_MCBSP3_BASE, | |
876 | .dma_rx_sync = OMAP_DMA_MCBSP3_RX, | |
877 | .dma_tx_sync = OMAP_DMA_MCBSP3_TX, | |
878 | .rx_irq = INT_McBSP3RX, | |
879 | .tx_irq = INT_McBSP3TX }, | |
880 | }; | |
881 | #endif | |
882 | ||
883 | #if defined(CONFIG_ARCH_OMAP16XX) | |
884 | static const struct omap_mcbsp_info mcbsp_1610[] = { | |
885 | [0] = { .virt_base = OMAP1610_MCBSP1_BASE, | |
886 | .dma_rx_sync = OMAP_DMA_MCBSP1_RX, | |
887 | .dma_tx_sync = OMAP_DMA_MCBSP1_TX, | |
888 | .rx_irq = INT_McBSP1RX, | |
889 | .tx_irq = INT_McBSP1TX }, | |
890 | [1] = { .virt_base = io_p2v(OMAP1610_MCBSP2_BASE), | |
891 | .dma_rx_sync = OMAP_DMA_MCBSP2_RX, | |
892 | .dma_tx_sync = OMAP_DMA_MCBSP2_TX, | |
893 | .rx_irq = INT_1610_McBSP2_RX, | |
894 | .tx_irq = INT_1610_McBSP2_TX }, | |
895 | [2] = { .virt_base = OMAP1610_MCBSP3_BASE, | |
896 | .dma_rx_sync = OMAP_DMA_MCBSP3_RX, | |
897 | .dma_tx_sync = OMAP_DMA_MCBSP3_TX, | |
898 | .rx_irq = INT_McBSP3RX, | |
899 | .tx_irq = INT_McBSP3TX }, | |
900 | }; | |
901 | #endif | |
902 | ||
120db2cb TL |
903 | #if defined(CONFIG_ARCH_OMAP24XX) |
904 | static const struct omap_mcbsp_info mcbsp_24xx[] = { | |
905 | [0] = { .virt_base = IO_ADDRESS(OMAP24XX_MCBSP1_BASE), | |
906 | .dma_rx_sync = OMAP24XX_DMA_MCBSP1_RX, | |
907 | .dma_tx_sync = OMAP24XX_DMA_MCBSP1_TX, | |
908 | .rx_irq = INT_24XX_MCBSP1_IRQ_RX, | |
909 | .tx_irq = INT_24XX_MCBSP1_IRQ_TX, | |
910 | }, | |
911 | [1] = { .virt_base = IO_ADDRESS(OMAP24XX_MCBSP2_BASE), | |
912 | .dma_rx_sync = OMAP24XX_DMA_MCBSP2_RX, | |
913 | .dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX, | |
914 | .rx_irq = INT_24XX_MCBSP2_IRQ_RX, | |
915 | .tx_irq = INT_24XX_MCBSP2_IRQ_TX, | |
916 | }, | |
917 | }; | |
918 | #endif | |
919 | ||
5e1c5ff4 TL |
920 | static int __init omap_mcbsp_init(void) |
921 | { | |
922 | int mcbsp_count = 0, i; | |
923 | static const struct omap_mcbsp_info *mcbsp_info; | |
924 | ||
925 | printk("Initializing OMAP McBSP system\n"); | |
926 | ||
120db2cb | 927 | #ifdef CONFIG_ARCH_OMAP1 |
5e1c5ff4 TL |
928 | mcbsp_dsp_ck = clk_get(0, "dsp_ck"); |
929 | if (IS_ERR(mcbsp_dsp_ck)) { | |
930 | printk(KERN_ERR "mcbsp: could not acquire dsp_ck handle.\n"); | |
931 | return PTR_ERR(mcbsp_dsp_ck); | |
932 | } | |
933 | mcbsp_api_ck = clk_get(0, "api_ck"); | |
bb13b5fd | 934 | if (IS_ERR(mcbsp_api_ck)) { |
5e1c5ff4 TL |
935 | printk(KERN_ERR "mcbsp: could not acquire api_ck handle.\n"); |
936 | return PTR_ERR(mcbsp_api_ck); | |
937 | } | |
bb13b5fd TL |
938 | mcbsp_dspxor_ck = clk_get(0, "dspxor_ck"); |
939 | if (IS_ERR(mcbsp_dspxor_ck)) { | |
940 | printk(KERN_ERR "mcbsp: could not acquire dspxor_ck handle.\n"); | |
941 | return PTR_ERR(mcbsp_dspxor_ck); | |
942 | } | |
120db2cb TL |
943 | #endif |
944 | #ifdef CONFIG_ARCH_OMAP2 | |
945 | mcbsp1_ick = clk_get(0, "mcbsp1_ick"); | |
946 | if (IS_ERR(mcbsp1_ick)) { | |
947 | printk(KERN_ERR "mcbsp: could not acquire mcbsp1_ick handle.\n"); | |
948 | return PTR_ERR(mcbsp1_ick); | |
949 | } | |
950 | mcbsp1_fck = clk_get(0, "mcbsp1_fck"); | |
951 | if (IS_ERR(mcbsp1_fck)) { | |
952 | printk(KERN_ERR "mcbsp: could not acquire mcbsp1_fck handle.\n"); | |
953 | return PTR_ERR(mcbsp1_fck); | |
954 | } | |
955 | mcbsp2_ick = clk_get(0, "mcbsp2_ick"); | |
956 | if (IS_ERR(mcbsp2_ick)) { | |
957 | printk(KERN_ERR "mcbsp: could not acquire mcbsp2_ick handle.\n"); | |
958 | return PTR_ERR(mcbsp2_ick); | |
959 | } | |
960 | mcbsp2_fck = clk_get(0, "mcbsp2_fck"); | |
961 | if (IS_ERR(mcbsp2_fck)) { | |
962 | printk(KERN_ERR "mcbsp: could not acquire mcbsp2_fck handle.\n"); | |
963 | return PTR_ERR(mcbsp2_fck); | |
964 | } | |
965 | #endif | |
5e1c5ff4 TL |
966 | |
967 | #ifdef CONFIG_ARCH_OMAP730 | |
968 | if (cpu_is_omap730()) { | |
969 | mcbsp_info = mcbsp_730; | |
970 | mcbsp_count = ARRAY_SIZE(mcbsp_730); | |
971 | } | |
972 | #endif | |
1a8bfa1e | 973 | #ifdef CONFIG_ARCH_OMAP15XX |
120db2cb | 974 | if (cpu_is_omap15xx()) { |
5e1c5ff4 TL |
975 | mcbsp_info = mcbsp_1510; |
976 | mcbsp_count = ARRAY_SIZE(mcbsp_1510); | |
977 | } | |
978 | #endif | |
979 | #if defined(CONFIG_ARCH_OMAP16XX) | |
bb13b5fd | 980 | if (cpu_is_omap16xx()) { |
5e1c5ff4 TL |
981 | mcbsp_info = mcbsp_1610; |
982 | mcbsp_count = ARRAY_SIZE(mcbsp_1610); | |
983 | } | |
120db2cb TL |
984 | #endif |
985 | #if defined(CONFIG_ARCH_OMAP24XX) | |
986 | if (cpu_is_omap24xx()) { | |
987 | mcbsp_info = mcbsp_24xx; | |
988 | mcbsp_count = ARRAY_SIZE(mcbsp_24xx); | |
120db2cb | 989 | omap2_mcbsp2_mux_setup(); |
120db2cb | 990 | } |
5e1c5ff4 TL |
991 | #endif |
992 | for (i = 0; i < OMAP_MAX_MCBSP_COUNT ; i++) { | |
993 | if (i >= mcbsp_count) { | |
994 | mcbsp[i].io_base = 0; | |
995 | mcbsp[i].free = 0; | |
996 | continue; | |
997 | } | |
998 | mcbsp[i].id = i + 1; | |
999 | mcbsp[i].free = 1; | |
1000 | mcbsp[i].dma_tx_lch = -1; | |
1001 | mcbsp[i].dma_rx_lch = -1; | |
1002 | ||
1003 | mcbsp[i].io_base = mcbsp_info[i].virt_base; | |
120db2cb | 1004 | mcbsp[i].io_type = OMAP_MCBSP_IRQ_IO; /* Default I/O is IRQ based */ |
5e1c5ff4 TL |
1005 | mcbsp[i].tx_irq = mcbsp_info[i].tx_irq; |
1006 | mcbsp[i].rx_irq = mcbsp_info[i].rx_irq; | |
1007 | mcbsp[i].dma_rx_sync = mcbsp_info[i].dma_rx_sync; | |
1008 | mcbsp[i].dma_tx_sync = mcbsp_info[i].dma_tx_sync; | |
1009 | spin_lock_init(&mcbsp[i].lock); | |
1010 | } | |
1011 | ||
1012 | return 0; | |
1013 | } | |
1014 | ||
5e1c5ff4 TL |
1015 | arch_initcall(omap_mcbsp_init); |
1016 | ||
1017 | EXPORT_SYMBOL(omap_mcbsp_config); | |
1018 | EXPORT_SYMBOL(omap_mcbsp_request); | |
120db2cb | 1019 | EXPORT_SYMBOL(omap_mcbsp_set_io_type); |
5e1c5ff4 TL |
1020 | EXPORT_SYMBOL(omap_mcbsp_free); |
1021 | EXPORT_SYMBOL(omap_mcbsp_start); | |
1022 | EXPORT_SYMBOL(omap_mcbsp_stop); | |
1023 | EXPORT_SYMBOL(omap_mcbsp_xmit_word); | |
1024 | EXPORT_SYMBOL(omap_mcbsp_recv_word); | |
1025 | EXPORT_SYMBOL(omap_mcbsp_xmit_buffer); | |
1026 | EXPORT_SYMBOL(omap_mcbsp_recv_buffer); | |
120db2cb TL |
1027 | EXPORT_SYMBOL(omap_mcbsp_spi_master_xmit_word_poll); |
1028 | EXPORT_SYMBOL(omap_mcbsp_spi_master_recv_word_poll); | |
5e1c5ff4 | 1029 | EXPORT_SYMBOL(omap_mcbsp_set_spi_mode); |