aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/s3c24xx/s3c2412-i2s.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/s3c2412-i2s.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/s3c2412-i2s.c')
-rw-r--r--sound/soc/s3c24xx/s3c2412-i2s.c596
1 files changed, 18 insertions, 578 deletions
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c
index 3297698ff294..5099d9396676 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.c
+++ b/sound/soc/s3c24xx/s3c2412-i2s.c
@@ -33,7 +33,7 @@
33 33
34#include <plat/regs-s3c2412-iis.h> 34#include <plat/regs-s3c2412-iis.h>
35 35
36#include <mach/regs-gpio.h> 36#include <plat/regs-gpio.h>
37#include <plat/audio.h> 37#include <plat/audio.h>
38#include <mach/dma.h> 38#include <mach/dma.h>
39 39
@@ -41,7 +41,6 @@
41#include "s3c2412-i2s.h" 41#include "s3c2412-i2s.h"
42 42
43#define S3C2412_I2S_DEBUG 0 43#define S3C2412_I2S_DEBUG 0
44#define S3C2412_I2S_DEBUG_CON 0
45 44
46#if S3C2412_I2S_DEBUG 45#if S3C2412_I2S_DEBUG
47#define DBG(x...) printk(KERN_INFO x) 46#define DBG(x...) printk(KERN_INFO x)
@@ -71,431 +70,7 @@ static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_in = {
71 .dma_size = 4, 70 .dma_size = 4,
72}; 71};
73 72
74struct s3c2412_i2s_info { 73static struct s3c_i2sv2_info s3c2412_i2s;
75 struct device *dev;
76 void __iomem *regs;
77 struct clk *iis_clk;
78 struct clk *iis_pclk;
79 struct clk *iis_cclk;
80
81 u32 suspend_iismod;
82 u32 suspend_iiscon;
83 u32 suspend_iispsr;
84};
85
86static struct s3c2412_i2s_info s3c2412_i2s;
87
88#define bit_set(v, b) (((v) & (b)) ? 1 : 0)
89
90#if S3C2412_I2S_DEBUG_CON
91static void dbg_showcon(const char *fn, u32 con)
92{
93 printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn,
94 bit_set(con, S3C2412_IISCON_LRINDEX),
95 bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY),
96 bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY),
97 bit_set(con, S3C2412_IISCON_TXFIFO_FULL),
98 bit_set(con, S3C2412_IISCON_RXFIFO_FULL));
99
100 printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n",
101 fn,
102 bit_set(con, S3C2412_IISCON_TXDMA_PAUSE),
103 bit_set(con, S3C2412_IISCON_RXDMA_PAUSE),
104 bit_set(con, S3C2412_IISCON_TXCH_PAUSE),
105 bit_set(con, S3C2412_IISCON_RXCH_PAUSE));
106 printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn,
107 bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE),
108 bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE),
109 bit_set(con, S3C2412_IISCON_IIS_ACTIVE));
110}
111#else
112static inline void dbg_showcon(const char *fn, u32 con)
113{
114}
115#endif
116
117/* Turn on or off the transmission path. */
118static void s3c2412_snd_txctrl(int on)
119{
120 struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
121 void __iomem *regs = i2s->regs;
122 u32 fic, con, mod;
123
124 DBG("%s(%d)\n", __func__, on);
125
126 fic = readl(regs + S3C2412_IISFIC);
127 con = readl(regs + S3C2412_IISCON);
128 mod = readl(regs + S3C2412_IISMOD);
129
130 DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
131
132 if (on) {
133 con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
134 con &= ~S3C2412_IISCON_TXDMA_PAUSE;
135 con &= ~S3C2412_IISCON_TXCH_PAUSE;
136
137 switch (mod & S3C2412_IISMOD_MODE_MASK) {
138 case S3C2412_IISMOD_MODE_TXONLY:
139 case S3C2412_IISMOD_MODE_TXRX:
140 /* do nothing, we are in the right mode */
141 break;
142
143 case S3C2412_IISMOD_MODE_RXONLY:
144 mod &= ~S3C2412_IISMOD_MODE_MASK;
145 mod |= S3C2412_IISMOD_MODE_TXRX;
146 break;
147
148 default:
149 dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n");
150 }
151
152 writel(con, regs + S3C2412_IISCON);
153 writel(mod, regs + S3C2412_IISMOD);
154 } else {
155 /* Note, we do not have any indication that the FIFO problems
156 * tha the S3C2410/2440 had apply here, so we should be able
157 * to disable the DMA and TX without resetting the FIFOS.
158 */
159
160 con |= S3C2412_IISCON_TXDMA_PAUSE;
161 con |= S3C2412_IISCON_TXCH_PAUSE;
162 con &= ~S3C2412_IISCON_TXDMA_ACTIVE;
163
164 switch (mod & S3C2412_IISMOD_MODE_MASK) {
165 case S3C2412_IISMOD_MODE_TXRX:
166 mod &= ~S3C2412_IISMOD_MODE_MASK;
167 mod |= S3C2412_IISMOD_MODE_RXONLY;
168 break;
169
170 case S3C2412_IISMOD_MODE_TXONLY:
171 mod &= ~S3C2412_IISMOD_MODE_MASK;
172 con &= ~S3C2412_IISCON_IIS_ACTIVE;
173 break;
174
175 default:
176 dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n");
177 }
178
179 writel(mod, regs + S3C2412_IISMOD);
180 writel(con, regs + S3C2412_IISCON);
181 }
182
183 fic = readl(regs + S3C2412_IISFIC);
184 dbg_showcon(__func__, con);
185 DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
186}
187
188static void s3c2412_snd_rxctrl(int on)
189{
190 struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
191 void __iomem *regs = i2s->regs;
192 u32 fic, con, mod;
193
194 DBG("%s(%d)\n", __func__, on);
195
196 fic = readl(regs + S3C2412_IISFIC);
197 con = readl(regs + S3C2412_IISCON);
198 mod = readl(regs + S3C2412_IISMOD);
199
200 DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
201
202 if (on) {
203 con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
204 con &= ~S3C2412_IISCON_RXDMA_PAUSE;
205 con &= ~S3C2412_IISCON_RXCH_PAUSE;
206
207 switch (mod & S3C2412_IISMOD_MODE_MASK) {
208 case S3C2412_IISMOD_MODE_TXRX:
209 case S3C2412_IISMOD_MODE_RXONLY:
210 /* do nothing, we are in the right mode */
211 break;
212
213 case S3C2412_IISMOD_MODE_TXONLY:
214 mod &= ~S3C2412_IISMOD_MODE_MASK;
215 mod |= S3C2412_IISMOD_MODE_TXRX;
216 break;
217
218 default:
219 dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
220 }
221
222 writel(mod, regs + S3C2412_IISMOD);
223 writel(con, regs + S3C2412_IISCON);
224 } else {
225 /* See txctrl notes on FIFOs. */
226
227 con &= ~S3C2412_IISCON_RXDMA_ACTIVE;
228 con |= S3C2412_IISCON_RXDMA_PAUSE;
229 con |= S3C2412_IISCON_RXCH_PAUSE;
230
231 switch (mod & S3C2412_IISMOD_MODE_MASK) {
232 case S3C2412_IISMOD_MODE_RXONLY:
233 con &= ~S3C2412_IISCON_IIS_ACTIVE;
234 mod &= ~S3C2412_IISMOD_MODE_MASK;
235 break;
236
237 case S3C2412_IISMOD_MODE_TXRX:
238 mod &= ~S3C2412_IISMOD_MODE_MASK;
239 mod |= S3C2412_IISMOD_MODE_TXONLY;
240 break;
241
242 default:
243 dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
244 }
245
246 writel(con, regs + S3C2412_IISCON);
247 writel(mod, regs + S3C2412_IISMOD);
248 }
249
250 fic = readl(regs + S3C2412_IISFIC);
251 DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
252}
253
254
255/*
256 * Wait for the LR signal to allow synchronisation to the L/R clock
257 * from the codec. May only be needed for slave mode.
258 */
259static int s3c2412_snd_lrsync(void)
260{
261 u32 iiscon;
262 unsigned long timeout = jiffies + msecs_to_jiffies(5);
263
264 DBG("Entered %s\n", __func__);
265
266 while (1) {
267 iiscon = readl(s3c2412_i2s.regs + S3C2412_IISCON);
268 if (iiscon & S3C2412_IISCON_LRINDEX)
269 break;
270
271 if (timeout < jiffies) {
272 printk(KERN_ERR "%s: timeout\n", __func__);
273 return -ETIMEDOUT;
274 }
275 }
276
277 return 0;
278}
279
280/*
281 * Check whether CPU is the master or slave
282 */
283static inline int s3c2412_snd_is_clkmaster(void)
284{
285 u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
286
287 DBG("Entered %s\n", __func__);
288
289 iismod &= S3C2412_IISMOD_MASTER_MASK;
290 return !(iismod == S3C2412_IISMOD_SLAVE);
291}
292
293/*
294 * Set S3C2412 I2S DAI format
295 */
296static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
297 unsigned int fmt)
298{
299 u32 iismod;
300
301
302 DBG("Entered %s\n", __func__);
303
304 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
305 DBG("hw_params r: IISMOD: %x \n", iismod);
306
307 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
308 case SND_SOC_DAIFMT_CBM_CFM:
309 iismod &= ~S3C2412_IISMOD_MASTER_MASK;
310 iismod |= S3C2412_IISMOD_SLAVE;
311 break;
312 case SND_SOC_DAIFMT_CBS_CFS:
313 iismod &= ~S3C2412_IISMOD_MASTER_MASK;
314 iismod |= S3C2412_IISMOD_MASTER_INTERNAL;
315 break;
316 default:
317 DBG("unknwon master/slave format\n");
318 return -EINVAL;
319 }
320
321 iismod &= ~S3C2412_IISMOD_SDF_MASK;
322
323 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
324 case SND_SOC_DAIFMT_RIGHT_J:
325 iismod |= S3C2412_IISMOD_SDF_MSB;
326 break;
327 case SND_SOC_DAIFMT_LEFT_J:
328 iismod |= S3C2412_IISMOD_SDF_LSB;
329 break;
330 case SND_SOC_DAIFMT_I2S:
331 iismod |= S3C2412_IISMOD_SDF_IIS;
332 break;
333 default:
334 DBG("Unknown data format\n");
335 return -EINVAL;
336 }
337
338 writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD);
339 DBG("hw_params w: IISMOD: %x \n", iismod);
340 return 0;
341}
342
343static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
344 struct snd_pcm_hw_params *params,
345 struct snd_soc_dai *dai)
346{
347 struct snd_soc_pcm_runtime *rtd = substream->private_data;
348 u32 iismod;
349
350 DBG("Entered %s\n", __func__);
351
352 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
353 rtd->dai->cpu_dai->dma_data = &s3c2412_i2s_pcm_stereo_out;
354 else
355 rtd->dai->cpu_dai->dma_data = &s3c2412_i2s_pcm_stereo_in;
356
357 /* Working copies of register */
358 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
359 DBG("%s: r: IISMOD: %x\n", __func__, iismod);
360
361 switch (params_format(params)) {
362 case SNDRV_PCM_FORMAT_S8:
363 iismod |= S3C2412_IISMOD_8BIT;
364 break;
365 case SNDRV_PCM_FORMAT_S16_LE:
366 iismod &= ~S3C2412_IISMOD_8BIT;
367 break;
368 }
369
370 writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD);
371 DBG("%s: w: IISMOD: %x\n", __func__, iismod);
372 return 0;
373}
374
375static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
376 struct snd_soc_dai *dai)
377{
378 int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
379 unsigned long irqs;
380 int ret = 0;
381
382 DBG("Entered %s\n", __func__);
383
384 switch (cmd) {
385 case SNDRV_PCM_TRIGGER_START:
386 /* On start, ensure that the FIFOs are cleared and reset. */
387
388 writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH,
389 s3c2412_i2s.regs + S3C2412_IISFIC);
390
391 /* clear again, just in case */
392 writel(0x0, s3c2412_i2s.regs + S3C2412_IISFIC);
393
394 case SNDRV_PCM_TRIGGER_RESUME:
395 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
396 if (!s3c2412_snd_is_clkmaster()) {
397 ret = s3c2412_snd_lrsync();
398 if (ret)
399 goto exit_err;
400 }
401
402 local_irq_save(irqs);
403
404 if (capture)
405 s3c2412_snd_rxctrl(1);
406 else
407 s3c2412_snd_txctrl(1);
408
409 local_irq_restore(irqs);
410 break;
411
412 case SNDRV_PCM_TRIGGER_STOP:
413 case SNDRV_PCM_TRIGGER_SUSPEND:
414 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
415 local_irq_save(irqs);
416
417 if (capture)
418 s3c2412_snd_rxctrl(0);
419 else
420 s3c2412_snd_txctrl(0);
421
422 local_irq_restore(irqs);
423 break;
424 default:
425 ret = -EINVAL;
426 break;
427 }
428
429exit_err:
430 return ret;
431}
432
433/* default table of all avaialable root fs divisors */
434static unsigned int s3c2412_iis_fs[] = { 256, 512, 384, 768, 0 };
435
436int s3c2412_iis_calc_rate(struct s3c2412_rate_calc *info,
437 unsigned int *fstab,
438 unsigned int rate, struct clk *clk)
439{
440 unsigned long clkrate = clk_get_rate(clk);
441 unsigned int div;
442 unsigned int fsclk;
443 unsigned int actual;
444 unsigned int fs;
445 unsigned int fsdiv;
446 signed int deviation = 0;
447 unsigned int best_fs = 0;
448 unsigned int best_div = 0;
449 unsigned int best_rate = 0;
450 unsigned int best_deviation = INT_MAX;
451
452
453 if (fstab == NULL)
454 fstab = s3c2412_iis_fs;
455
456 for (fs = 0;; fs++) {
457 fsdiv = s3c2412_iis_fs[fs];
458
459 if (fsdiv == 0)
460 break;
461
462 fsclk = clkrate / fsdiv;
463 div = fsclk / rate;
464
465 if ((fsclk % rate) > (rate / 2))
466 div++;
467
468 if (div <= 1)
469 continue;
470
471 actual = clkrate / (fsdiv * div);
472 deviation = actual - rate;
473
474 printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n",
475 fsdiv, div, actual, deviation);
476
477 deviation = abs(deviation);
478
479 if (deviation < best_deviation) {
480 best_fs = fsdiv;
481 best_div = div;
482 best_rate = actual;
483 best_deviation = deviation;
484 }
485
486 if (deviation == 0)
487 break;
488 }
489
490 printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n",
491 best_fs, best_div, best_rate);
492
493 info->fs_div = best_fs;
494 info->clk_div = best_div;
495
496 return 0;
497}
498EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate);
499 74
500/* 75/*
501 * Set S3C2412 Clock source 76 * Set S3C2412 Clock source
@@ -510,10 +85,12 @@ static int s3c2412_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
510 85
511 switch (clk_id) { 86 switch (clk_id) {
512 case S3C2412_CLKSRC_PCLK: 87 case S3C2412_CLKSRC_PCLK:
88 s3c2412_i2s.master = 1;
513 iismod &= ~S3C2412_IISMOD_MASTER_MASK; 89 iismod &= ~S3C2412_IISMOD_MASTER_MASK;
514 iismod |= S3C2412_IISMOD_MASTER_INTERNAL; 90 iismod |= S3C2412_IISMOD_MASTER_INTERNAL;
515 break; 91 break;
516 case S3C2412_CLKSRC_I2SCLK: 92 case S3C2412_CLKSRC_I2SCLK:
93 s3c2412_i2s.master = 0;
517 iismod &= ~S3C2412_IISMOD_MASTER_MASK; 94 iismod &= ~S3C2412_IISMOD_MASTER_MASK;
518 iismod |= S3C2412_IISMOD_MASTER_EXTERNAL; 95 iismod |= S3C2412_IISMOD_MASTER_EXTERNAL;
519 break; 96 break;
@@ -525,74 +102,6 @@ static int s3c2412_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
525 return 0; 102 return 0;
526} 103}
527 104
528/*
529 * Set S3C2412 Clock dividers
530 */
531static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
532 int div_id, int div)
533{
534 struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
535 u32 reg;
536
537 DBG("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
538
539 switch (div_id) {
540 case S3C2412_DIV_BCLK:
541 reg = readl(i2s->regs + S3C2412_IISMOD);
542 reg &= ~S3C2412_IISMOD_BCLK_MASK;
543 writel(reg | div, i2s->regs + S3C2412_IISMOD);
544
545 DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
546 break;
547
548 case S3C2412_DIV_RCLK:
549 if (div > 3) {
550 /* convert value to bit field */
551
552 switch (div) {
553 case 256:
554 div = S3C2412_IISMOD_RCLK_256FS;
555 break;
556
557 case 384:
558 div = S3C2412_IISMOD_RCLK_384FS;
559 break;
560
561 case 512:
562 div = S3C2412_IISMOD_RCLK_512FS;
563 break;
564
565 case 768:
566 div = S3C2412_IISMOD_RCLK_768FS;
567 break;
568
569 default:
570 return -EINVAL;
571 }
572 }
573
574 reg = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
575 reg &= ~S3C2412_IISMOD_RCLK_MASK;
576 writel(reg | div, i2s->regs + S3C2412_IISMOD);
577 DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
578 break;
579
580 case S3C2412_DIV_PRESCALER:
581 if (div >= 0) {
582 writel((div << 8) | S3C2412_IISPSR_PSREN,
583 i2s->regs + S3C2412_IISPSR);
584 } else {
585 writel(0x0, i2s->regs + S3C2412_IISPSR);
586 }
587 DBG("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR));
588 break;
589
590 default:
591 return -EINVAL;
592 }
593
594 return 0;
595}
596 105
597struct clk *s3c2412_get_iisclk(void) 106struct clk *s3c2412_get_iisclk(void)
598{ 107{
@@ -604,20 +113,16 @@ EXPORT_SYMBOL_GPL(s3c2412_get_iisclk);
604static int s3c2412_i2s_probe(struct platform_device *pdev, 113static int s3c2412_i2s_probe(struct platform_device *pdev,
605 struct snd_soc_dai *dai) 114 struct snd_soc_dai *dai)
606{ 115{
607 DBG("Entered %s\n", __func__); 116 int ret;
608 117
609 s3c2412_i2s.dev = &pdev->dev; 118 DBG("Entered %s\n", __func__);
610 119
611 s3c2412_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100); 120 ret = s3c_i2sv2_probe(pdev, dai, &s3c2412_i2s, S3C2410_PA_IIS);
612 if (s3c2412_i2s.regs == NULL) 121 if (ret)
613 return -ENXIO; 122 return ret;
614 123
615 s3c2412_i2s.iis_pclk = clk_get(&pdev->dev, "iis"); 124 s3c2412_i2s.dma_capture = &s3c2412_i2s_pcm_stereo_in;
616 if (s3c2412_i2s.iis_pclk == NULL) { 125 s3c2412_i2s.dma_playback = &s3c2412_i2s_pcm_stereo_out;
617 DBG("failed to get iis_clock\n");
618 iounmap(s3c2412_i2s.regs);
619 return -ENODEV;
620 }
621 126
622 s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk"); 127 s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk");
623 if (s3c2412_i2s.iis_cclk == NULL) { 128 if (s3c2412_i2s.iis_cclk == NULL) {
@@ -626,12 +131,12 @@ static int s3c2412_i2s_probe(struct platform_device *pdev,
626 return -ENODEV; 131 return -ENODEV;
627 } 132 }
628 133
629 clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll")); 134 /* Set MPLL as the source for IIS CLK */
630 135
631 clk_enable(s3c2412_i2s.iis_pclk); 136 clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll"));
632 clk_enable(s3c2412_i2s.iis_cclk); 137 clk_enable(s3c2412_i2s.iis_cclk);
633 138
634 s3c2412_i2s.iis_clk = s3c2412_i2s.iis_pclk; 139 s3c2412_i2s.iis_cclk = s3c2412_i2s.iis_pclk;
635 140
636 /* Configure the I2S pins in correct mode */ 141 /* Configure the I2S pins in correct mode */
637 s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK); 142 s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK);
@@ -640,78 +145,18 @@ static int s3c2412_i2s_probe(struct platform_device *pdev,
640 s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI); 145 s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);
641 s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO); 146 s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);
642 147
643 s3c2412_snd_txctrl(0);
644 s3c2412_snd_rxctrl(0);
645
646 return 0;
647}
648
649#ifdef CONFIG_PM
650static int s3c2412_i2s_suspend(struct snd_soc_dai *dai)
651{
652 struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
653 u32 iismod;
654
655 if (dai->active) {
656 i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
657 i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
658 i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
659
660 /* some basic suspend checks */
661
662 iismod = readl(i2s->regs + S3C2412_IISMOD);
663
664 if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
665 pr_warning("%s: RXDMA active?\n", __func__);
666
667 if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
668 pr_warning("%s: TXDMA active?\n", __func__);
669
670 if (iismod & S3C2412_IISCON_IIS_ACTIVE)
671 pr_warning("%s: IIS active\n", __func__);
672 }
673
674 return 0; 148 return 0;
675} 149}
676 150
677static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
678{
679 struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
680
681 pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n",
682 dai->active, i2s->suspend_iismod, i2s->suspend_iiscon);
683
684 if (dai->active) {
685 writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
686 writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
687 writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
688
689 writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
690 i2s->regs + S3C2412_IISFIC);
691
692 ndelay(250);
693 writel(0x0, i2s->regs + S3C2412_IISFIC);
694
695 }
696
697 return 0;
698}
699#else
700#define s3c2412_i2s_suspend NULL
701#define s3c2412_i2s_resume NULL
702#endif /* CONFIG_PM */
703
704#define S3C2412_I2S_RATES \ 151#define S3C2412_I2S_RATES \
705 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ 152 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
706 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 153 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
707 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) 154 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
708 155
709struct snd_soc_dai s3c2412_i2s_dai = { 156struct snd_soc_dai s3c2412_i2s_dai = {
710 .name = "s3c2412-i2s", 157 .name = "s3c2412-i2s",
711 .id = 0, 158 .id = 0,
712 .probe = s3c2412_i2s_probe, 159 .probe = s3c2412_i2s_probe,
713 .suspend = s3c2412_i2s_suspend,
714 .resume = s3c2412_i2s_resume,
715 .playback = { 160 .playback = {
716 .channels_min = 2, 161 .channels_min = 2,
717 .channels_max = 2, 162 .channels_max = 2,
@@ -725,10 +170,6 @@ struct snd_soc_dai s3c2412_i2s_dai = {
725 .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE, 170 .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
726 }, 171 },
727 .ops = { 172 .ops = {
728 .trigger = s3c2412_i2s_trigger,
729 .hw_params = s3c2412_i2s_hw_params,
730 .set_fmt = s3c2412_i2s_set_fmt,
731 .set_clkdiv = s3c2412_i2s_set_clkdiv,
732 .set_sysclk = s3c2412_i2s_set_sysclk, 173 .set_sysclk = s3c2412_i2s_set_sysclk,
733 }, 174 },
734}; 175};
@@ -736,7 +177,7 @@ EXPORT_SYMBOL_GPL(s3c2412_i2s_dai);
736 177
737static int __init s3c2412_i2s_init(void) 178static int __init s3c2412_i2s_init(void)
738{ 179{
739 return snd_soc_register_dai(&s3c2412_i2s_dai); 180 return s3c_i2sv2_register_dai(&s3c2412_i2s_dai);
740} 181}
741module_init(s3c2412_i2s_init); 182module_init(s3c2412_i2s_init);
742 183
@@ -746,7 +187,6 @@ static void __exit s3c2412_i2s_exit(void)
746} 187}
747module_exit(s3c2412_i2s_exit); 188module_exit(s3c2412_i2s_exit);
748 189
749
750/* Module information */ 190/* Module information */
751MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); 191MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
752MODULE_DESCRIPTION("S3C2412 I2S SoC Interface"); 192MODULE_DESCRIPTION("S3C2412 I2S SoC Interface");