aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/s3c24xx/s3c-i2s-v2.c
diff options
context:
space:
mode:
authorBen Dooks <ben@simtec.co.uk>2009-03-03 19:49:30 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-03-06 08:37:08 -0500
commitdc85447b196a683784eb85654c436fd58c3e2ed1 (patch)
treefa4bfa4ddcea242060294ab5db8be598973e31ea /sound/soc/s3c24xx/s3c-i2s-v2.c
parent3093e48c48b69ccc06a1f78ffe7ece7ee2ee09ef (diff)
ASoC: Split s3c2412-i2s.c into core and SoC specific parts
The S3C2412 I2S (IIS) interface is replicated on further Samsung SoC parts in a broadly compatible way, so split the common code out into a core called s3c-i2s-v2.[ch] so that the newer SoCs such as the S3C6410 can make use of it. As such, all the original s3c2412 functions are currently being left with their original names, and will be renamed later in the series. Signed-off-by: Ben Dooks <ben@simtec.co.uk> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/s3c24xx/s3c-i2s-v2.c')
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.c645
1 files changed, 645 insertions, 0 deletions
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c
new file mode 100644
index 000000000000..43262e1e8f98
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.c
@@ -0,0 +1,645 @@
1/* sound/soc/s3c24xx/s3c-i2c-v2.c
2 *
3 * ALSA Soc Audio Layer - I2S core for newer Samsung SoCs.
4 *
5 * Copyright (c) 2006 Wolfson Microelectronics PLC.
6 * Graeme Gregory graeme.gregory@wolfsonmicro.com
7 * linux@wolfsonmicro.com
8 *
9 * Copyright (c) 2008, 2007, 2004-2005 Simtec Electronics
10 * http://armlinux.simtec.co.uk/
11 * Ben Dooks <ben@simtec.co.uk>
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version.
17 */
18
19#include <linux/init.h>
20#include <linux/module.h>
21#include <linux/device.h>
22#include <linux/delay.h>
23#include <linux/clk.h>
24#include <linux/kernel.h>
25#include <linux/io.h>
26
27#include <sound/core.h>
28#include <sound/pcm.h>
29#include <sound/pcm_params.h>
30#include <sound/initval.h>
31#include <sound/soc.h>
32
33#include <plat/regs-s3c2412-iis.h>
34
35#include <plat/audio.h>
36#include <mach/dma.h>
37
38#include "s3c-i2s-v2.h"
39
40#define S3C2412_I2S_DEBUG_CON 0
41#define S3C2412_I2S_DEBUG 0
42
43#if S3C2412_I2S_DEBUG
44#define DBG(x...) printk(KERN_INFO x)
45#else
46#define DBG(x...) do { } while (0)
47#endif
48
49static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
50{
51 return cpu_dai->private_data;
52}
53
54#define bit_set(v, b) (((v) & (b)) ? 1 : 0)
55
56#if S3C2412_I2S_DEBUG_CON
57static void dbg_showcon(const char *fn, u32 con)
58{
59 printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn,
60 bit_set(con, S3C2412_IISCON_LRINDEX),
61 bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY),
62 bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY),
63 bit_set(con, S3C2412_IISCON_TXFIFO_FULL),
64 bit_set(con, S3C2412_IISCON_RXFIFO_FULL));
65
66 printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n",
67 fn,
68 bit_set(con, S3C2412_IISCON_TXDMA_PAUSE),
69 bit_set(con, S3C2412_IISCON_RXDMA_PAUSE),
70 bit_set(con, S3C2412_IISCON_TXCH_PAUSE),
71 bit_set(con, S3C2412_IISCON_RXCH_PAUSE));
72 printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn,
73 bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE),
74 bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE),
75 bit_set(con, S3C2412_IISCON_IIS_ACTIVE));
76}
77#else
78static inline void dbg_showcon(const char *fn, u32 con)
79{
80}
81#endif
82
83
84/* Turn on or off the transmission path. */
85void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
86{
87 void __iomem *regs = i2s->regs;
88 u32 fic, con, mod;
89
90 DBG("%s(%d)\n", __func__, on);
91
92 fic = readl(regs + S3C2412_IISFIC);
93 con = readl(regs + S3C2412_IISCON);
94 mod = readl(regs + S3C2412_IISMOD);
95
96 DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
97
98 if (on) {
99 con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
100 con &= ~S3C2412_IISCON_TXDMA_PAUSE;
101 con &= ~S3C2412_IISCON_TXCH_PAUSE;
102
103 switch (mod & S3C2412_IISMOD_MODE_MASK) {
104 case S3C2412_IISMOD_MODE_TXONLY:
105 case S3C2412_IISMOD_MODE_TXRX:
106 /* do nothing, we are in the right mode */
107 break;
108
109 case S3C2412_IISMOD_MODE_RXONLY:
110 mod &= ~S3C2412_IISMOD_MODE_MASK;
111 mod |= S3C2412_IISMOD_MODE_TXRX;
112 break;
113
114 default:
115 dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n");
116 }
117
118 writel(con, regs + S3C2412_IISCON);
119 writel(mod, regs + S3C2412_IISMOD);
120 } else {
121 /* Note, we do not have any indication that the FIFO problems
122 * tha the S3C2410/2440 had apply here, so we should be able
123 * to disable the DMA and TX without resetting the FIFOS.
124 */
125
126 con |= S3C2412_IISCON_TXDMA_PAUSE;
127 con |= S3C2412_IISCON_TXCH_PAUSE;
128 con &= ~S3C2412_IISCON_TXDMA_ACTIVE;
129
130 switch (mod & S3C2412_IISMOD_MODE_MASK) {
131 case S3C2412_IISMOD_MODE_TXRX:
132 mod &= ~S3C2412_IISMOD_MODE_MASK;
133 mod |= S3C2412_IISMOD_MODE_RXONLY;
134 break;
135
136 case S3C2412_IISMOD_MODE_TXONLY:
137 mod &= ~S3C2412_IISMOD_MODE_MASK;
138 con &= ~S3C2412_IISCON_IIS_ACTIVE;
139 break;
140
141 default:
142 dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n");
143 }
144
145 writel(mod, regs + S3C2412_IISMOD);
146 writel(con, regs + S3C2412_IISCON);
147 }
148
149 fic = readl(regs + S3C2412_IISFIC);
150 dbg_showcon(__func__, con);
151 DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
152}
153EXPORT_SYMBOL_GPL(s3c2412_snd_txctrl);
154
155void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
156{
157 void __iomem *regs = i2s->regs;
158 u32 fic, con, mod;
159
160 DBG("%s(%d)\n", __func__, on);
161
162 fic = readl(regs + S3C2412_IISFIC);
163 con = readl(regs + S3C2412_IISCON);
164 mod = readl(regs + S3C2412_IISMOD);
165
166 DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
167
168 if (on) {
169 con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
170 con &= ~S3C2412_IISCON_RXDMA_PAUSE;
171 con &= ~S3C2412_IISCON_RXCH_PAUSE;
172
173 switch (mod & S3C2412_IISMOD_MODE_MASK) {
174 case S3C2412_IISMOD_MODE_TXRX:
175 case S3C2412_IISMOD_MODE_RXONLY:
176 /* do nothing, we are in the right mode */
177 break;
178
179 case S3C2412_IISMOD_MODE_TXONLY:
180 mod &= ~S3C2412_IISMOD_MODE_MASK;
181 mod |= S3C2412_IISMOD_MODE_TXRX;
182 break;
183
184 default:
185 dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
186 }
187
188 writel(mod, regs + S3C2412_IISMOD);
189 writel(con, regs + S3C2412_IISCON);
190 } else {
191 /* See txctrl notes on FIFOs. */
192
193 con &= ~S3C2412_IISCON_RXDMA_ACTIVE;
194 con |= S3C2412_IISCON_RXDMA_PAUSE;
195 con |= S3C2412_IISCON_RXCH_PAUSE;
196
197 switch (mod & S3C2412_IISMOD_MODE_MASK) {
198 case S3C2412_IISMOD_MODE_RXONLY:
199 con &= ~S3C2412_IISCON_IIS_ACTIVE;
200 mod &= ~S3C2412_IISMOD_MODE_MASK;
201 break;
202
203 case S3C2412_IISMOD_MODE_TXRX:
204 mod &= ~S3C2412_IISMOD_MODE_MASK;
205 mod |= S3C2412_IISMOD_MODE_TXONLY;
206 break;
207
208 default:
209 dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
210 }
211
212 writel(con, regs + S3C2412_IISCON);
213 writel(mod, regs + S3C2412_IISMOD);
214 }
215
216 fic = readl(regs + S3C2412_IISFIC);
217 DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
218}
219EXPORT_SYMBOL_GPL(s3c2412_snd_rxctrl);
220
221/*
222 * Wait for the LR signal to allow synchronisation to the L/R clock
223 * from the codec. May only be needed for slave mode.
224 */
225static int s3c2412_snd_lrsync(struct s3c_i2sv2_info *i2s)
226{
227 u32 iiscon;
228 unsigned long timeout = jiffies + msecs_to_jiffies(5);
229
230 DBG("Entered %s\n", __func__);
231
232 while (1) {
233 iiscon = readl(i2s->regs + S3C2412_IISCON);
234 if (iiscon & S3C2412_IISCON_LRINDEX)
235 break;
236
237 if (timeout < jiffies) {
238 printk(KERN_ERR "%s: timeout\n", __func__);
239 return -ETIMEDOUT;
240 }
241 }
242
243 return 0;
244}
245
246/*
247 * Set S3C2412 I2S DAI format
248 */
249static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
250 unsigned int fmt)
251{
252 struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
253 u32 iismod;
254
255 DBG("Entered %s\n", __func__);
256
257 iismod = readl(i2s->regs + S3C2412_IISMOD);
258 DBG("hw_params r: IISMOD: %x \n", iismod);
259
260#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
261#define IISMOD_MASTER_MASK S3C2412_IISMOD_MASTER_MASK
262#define IISMOD_SLAVE S3C2412_IISMOD_SLAVE
263#define IISMOD_MASTER S3C2412_IISMOD_MASTER_INTERNAL
264#endif
265
266#if defined(CONFIG_PLAT_S3C64XX)
267/* From Rev1.1 datasheet, we have two master and two slave modes:
268 * IMS[11:10]:
269 * 00 = master mode, fed from PCLK
270 * 01 = master mode, fed from CLKAUDIO
271 * 10 = slave mode, using PCLK
272 * 11 = slave mode, using I2SCLK
273 */
274#define IISMOD_MASTER_MASK (1 << 11)
275#define IISMOD_SLAVE (1 << 11)
276#define IISMOD_MASTER (0x0)
277#endif
278
279 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
280 case SND_SOC_DAIFMT_CBM_CFM:
281 i2s->master = 0;
282 iismod &= ~IISMOD_MASTER_MASK;
283 iismod |= IISMOD_SLAVE;
284 break;
285 case SND_SOC_DAIFMT_CBS_CFS:
286 i2s->master = 1;
287 iismod &= ~IISMOD_MASTER_MASK;
288 iismod |= IISMOD_MASTER;
289 break;
290 default:
291 DBG("unknwon master/slave format\n");
292 return -EINVAL;
293 }
294
295 iismod &= ~S3C2412_IISMOD_SDF_MASK;
296
297 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
298 case SND_SOC_DAIFMT_RIGHT_J:
299 iismod |= S3C2412_IISMOD_SDF_MSB;
300 break;
301 case SND_SOC_DAIFMT_LEFT_J:
302 iismod |= S3C2412_IISMOD_SDF_LSB;
303 break;
304 case SND_SOC_DAIFMT_I2S:
305 iismod |= S3C2412_IISMOD_SDF_IIS;
306 break;
307 default:
308 DBG("Unknown data format\n");
309 return -EINVAL;
310 }
311
312 writel(iismod, i2s->regs + S3C2412_IISMOD);
313 DBG("hw_params w: IISMOD: %x \n", iismod);
314 return 0;
315}
316
317static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
318 struct snd_pcm_hw_params *params,
319 struct snd_soc_dai *socdai)
320{
321 struct snd_soc_pcm_runtime *rtd = substream->private_data;
322 struct snd_soc_dai_link *dai = rtd->dai;
323 struct s3c_i2sv2_info *i2s = to_info(dai->cpu_dai);
324 u32 iismod;
325
326 DBG("Entered %s\n", __func__);
327
328 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
329 dai->cpu_dai->dma_data = i2s->dma_playback;
330 else
331 dai->cpu_dai->dma_data = i2s->dma_capture;
332
333 /* Working copies of register */
334 iismod = readl(i2s->regs + S3C2412_IISMOD);
335 DBG("%s: r: IISMOD: %x\n", __func__, iismod);
336
337 switch (params_format(params)) {
338 case SNDRV_PCM_FORMAT_S8:
339 iismod |= S3C2412_IISMOD_8BIT;
340 break;
341 case SNDRV_PCM_FORMAT_S16_LE:
342 iismod &= ~S3C2412_IISMOD_8BIT;
343 break;
344 }
345
346 writel(iismod, i2s->regs + S3C2412_IISMOD);
347 DBG("%s: w: IISMOD: %x\n", __func__, iismod);
348 return 0;
349}
350
351static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
352 struct snd_soc_dai *dai)
353{
354 struct snd_soc_pcm_runtime *rtd = substream->private_data;
355 struct s3c_i2sv2_info *i2s = to_info(rtd->dai->cpu_dai);
356 int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
357 unsigned long irqs;
358 int ret = 0;
359
360 DBG("Entered %s\n", __func__);
361
362 switch (cmd) {
363 case SNDRV_PCM_TRIGGER_START:
364 /* On start, ensure that the FIFOs are cleared and reset. */
365
366 writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH,
367 i2s->regs + S3C2412_IISFIC);
368
369 /* clear again, just in case */
370 writel(0x0, i2s->regs + S3C2412_IISFIC);
371
372 case SNDRV_PCM_TRIGGER_RESUME:
373 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
374 if (!i2s->master) {
375 ret = s3c2412_snd_lrsync(i2s);
376 if (ret)
377 goto exit_err;
378 }
379
380 local_irq_save(irqs);
381
382 if (capture)
383 s3c2412_snd_rxctrl(i2s, 1);
384 else
385 s3c2412_snd_txctrl(i2s, 1);
386
387 local_irq_restore(irqs);
388 break;
389
390 case SNDRV_PCM_TRIGGER_STOP:
391 case SNDRV_PCM_TRIGGER_SUSPEND:
392 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
393 local_irq_save(irqs);
394
395 if (capture)
396 s3c2412_snd_rxctrl(i2s, 0);
397 else
398 s3c2412_snd_txctrl(i2s, 0);
399
400 local_irq_restore(irqs);
401 break;
402 default:
403 ret = -EINVAL;
404 break;
405 }
406
407exit_err:
408 return ret;
409}
410
411/*
412 * Set S3C2412 Clock dividers
413 */
414static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
415 int div_id, int div)
416{
417 struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
418 u32 reg;
419
420 DBG("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
421
422 switch (div_id) {
423 case S3C_I2SV2_DIV_BCLK:
424 reg = readl(i2s->regs + S3C2412_IISMOD);
425 reg &= ~S3C2412_IISMOD_BCLK_MASK;
426 writel(reg | div, i2s->regs + S3C2412_IISMOD);
427
428 DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
429 break;
430
431 case S3C_I2SV2_DIV_RCLK:
432 if (div > 3) {
433 /* convert value to bit field */
434
435 switch (div) {
436 case 256:
437 div = S3C2412_IISMOD_RCLK_256FS;
438 break;
439
440 case 384:
441 div = S3C2412_IISMOD_RCLK_384FS;
442 break;
443
444 case 512:
445 div = S3C2412_IISMOD_RCLK_512FS;
446 break;
447
448 case 768:
449 div = S3C2412_IISMOD_RCLK_768FS;
450 break;
451
452 default:
453 return -EINVAL;
454 }
455 }
456
457 reg = readl(i2s->regs + S3C2412_IISMOD);
458 reg &= ~S3C2412_IISMOD_RCLK_MASK;
459 writel(reg | div, i2s->regs + S3C2412_IISMOD);
460 DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
461 break;
462
463 case S3C_I2SV2_DIV_PRESCALER:
464 if (div >= 0) {
465 writel((div << 8) | S3C2412_IISPSR_PSREN,
466 i2s->regs + S3C2412_IISPSR);
467 } else {
468 writel(0x0, i2s->regs + S3C2412_IISPSR);
469 }
470 DBG("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR));
471 break;
472
473 default:
474 return -EINVAL;
475 }
476
477 return 0;
478}
479
480/* default table of all avaialable root fs divisors */
481static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 };
482
483int s3c2412_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
484 unsigned int *fstab,
485 unsigned int rate, struct clk *clk)
486{
487 unsigned long clkrate = clk_get_rate(clk);
488 unsigned int div;
489 unsigned int fsclk;
490 unsigned int actual;
491 unsigned int fs;
492 unsigned int fsdiv;
493 signed int deviation = 0;
494 unsigned int best_fs = 0;
495 unsigned int best_div = 0;
496 unsigned int best_rate = 0;
497 unsigned int best_deviation = INT_MAX;
498
499 if (fstab == NULL)
500 fstab = iis_fs_tab;
501
502 for (fs = 0; fs < ARRAY_SIZE(iis_fs_tab); fs++) {
503 fsdiv = iis_fs_tab[fs];
504
505 fsclk = clkrate / fsdiv;
506 div = fsclk / rate;
507
508 if ((fsclk % rate) > (rate / 2))
509 div++;
510
511 if (div <= 1)
512 continue;
513
514 actual = clkrate / (fsdiv * div);
515 deviation = actual - rate;
516
517 printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n",
518 fsdiv, div, actual, deviation);
519
520 deviation = abs(deviation);
521
522 if (deviation < best_deviation) {
523 best_fs = fsdiv;
524 best_div = div;
525 best_rate = actual;
526 best_deviation = deviation;
527 }
528
529 if (deviation == 0)
530 break;
531 }
532
533 printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n",
534 best_fs, best_div, best_rate);
535
536 info->fs_div = best_fs;
537 info->clk_div = best_div;
538
539 return 0;
540}
541EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate);
542
543int s3c_i2sv2_probe(struct platform_device *pdev,
544 struct snd_soc_dai *dai,
545 struct s3c_i2sv2_info *i2s,
546 unsigned long base)
547{
548 struct device *dev = &pdev->dev;
549
550 i2s->dev = dev;
551
552 /* record our i2s structure for later use in the callbacks */
553 dai->private_data = i2s;
554
555 i2s->regs = ioremap(base, 0x100);
556 if (i2s->regs == NULL) {
557 dev_err(dev, "cannot ioremap registers\n");
558 return -ENXIO;
559 }
560
561 i2s->iis_pclk = clk_get(dev, "iis");
562 if (i2s->iis_pclk == NULL) {
563 DBG("failed to get iis_clock\n");
564 iounmap(i2s->regs);
565 return -ENOENT;
566 }
567
568 clk_enable(i2s->iis_pclk);
569
570 s3c2412_snd_txctrl(i2s, 0);
571 s3c2412_snd_rxctrl(i2s, 0);
572
573 return 0;
574}
575
576EXPORT_SYMBOL_GPL(s3c_i2sv2_probe);
577
578#ifdef CONFIG_PM
579static int s3c2412_i2s_suspend(struct snd_soc_dai *dai)
580{
581 struct s3c_i2sv2_info *i2s = to_info(dai);
582 u32 iismod;
583
584 if (dai->active) {
585 i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
586 i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
587 i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
588
589 /* some basic suspend checks */
590
591 iismod = readl(i2s->regs + S3C2412_IISMOD);
592
593 if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
594 pr_warning("%s: RXDMA active?\n", __func__);
595
596 if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
597 pr_warning("%s: TXDMA active?\n", __func__);
598
599 if (iismod & S3C2412_IISCON_IIS_ACTIVE)
600 pr_warning("%s: IIS active\n", __func__);
601 }
602
603 return 0;
604}
605
606static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
607{
608 struct s3c_i2sv2_info *i2s = to_info(dai);
609
610 pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n",
611 dai->active, i2s->suspend_iismod, i2s->suspend_iiscon);
612
613 if (dai->active) {
614 writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
615 writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
616 writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
617
618 writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
619 i2s->regs + S3C2412_IISFIC);
620
621 ndelay(250);
622 writel(0x0, i2s->regs + S3C2412_IISFIC);
623 }
624
625 return 0;
626}
627#else
628#define s3c2412_i2s_suspend NULL
629#define s3c2412_i2s_resume NULL
630#endif
631
632int s3c_i2sv2_register_dai(struct snd_soc_dai *dai)
633{
634 dai->ops.trigger = s3c2412_i2s_trigger;
635 dai->ops.hw_params = s3c2412_i2s_hw_params;
636 dai->ops.set_fmt = s3c2412_i2s_set_fmt;
637 dai->ops.set_clkdiv = s3c2412_i2s_set_clkdiv;
638
639 dai->suspend = s3c2412_i2s_suspend;
640 dai->resume = s3c2412_i2s_resume;
641
642 return snd_soc_register_dai(dai);
643}
644
645EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai);