aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/s3c24xx/Kconfig3
-rw-r--r--sound/soc/s3c24xx/Makefile2
-rw-r--r--sound/soc/s3c24xx/i2s.c1256
-rw-r--r--sound/soc/s3c24xx/i2s.h29
4 files changed, 1290 insertions, 0 deletions
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 226f831d46f7..ec870baf6d7a 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -41,6 +41,9 @@ config SND_S5P_SOC_SPDIF
41 tristate 41 tristate
42 select SND_SOC_SPDIF 42 select SND_SOC_SPDIF
43 43
44config SND_SAMSUNG_I2S
45 tristate
46
44config SND_S3C24XX_SOC_NEO1973_WM8753 47config SND_S3C24XX_SOC_NEO1973_WM8753
45 tristate "SoC I2S Audio support for NEO1973 - WM8753" 48 tristate "SoC I2S Audio support for NEO1973 - WM8753"
46 depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA01 49 depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA01
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 93de2a00df1f..1d6fc0736102 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -8,6 +8,7 @@ snd-soc-s3c64xx-i2s-v4-objs := s3c64xx-i2s-v4.o
8snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o 8snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
9snd-soc-samsung-spdif-objs := spdif.o 9snd-soc-samsung-spdif-objs := spdif.o
10snd-soc-pcm-objs := pcm.o 10snd-soc-pcm-objs := pcm.o
11snd-soc-i2s-objs := i2s.o
11 12
12obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o 13obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
13obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o 14obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
@@ -18,6 +19,7 @@ obj-$(CONFIG_SND_S3C64XX_SOC_I2S_V4) += snd-soc-s3c64xx-i2s-v4.o
18obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o 19obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
19obj-$(CONFIG_SND_S5P_SOC_SPDIF) += snd-soc-samsung-spdif.o 20obj-$(CONFIG_SND_S5P_SOC_SPDIF) += snd-soc-samsung-spdif.o
20obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-pcm.o 21obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-pcm.o
22obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o
21 23
22# S3C24XX Machine Support 24# S3C24XX Machine Support
23snd-soc-jive-wm8750-objs := jive_wm8750.o 25snd-soc-jive-wm8750-objs := jive_wm8750.o
diff --git a/sound/soc/s3c24xx/i2s.c b/sound/soc/s3c24xx/i2s.c
new file mode 100644
index 000000000000..7e6ddfab76b1
--- /dev/null
+++ b/sound/soc/s3c24xx/i2s.c
@@ -0,0 +1,1256 @@
1/* sound/soc/s3c24xx/i2s.c
2 *
3 * ALSA SoC Audio Layer - Samsung I2S Controller driver
4 *
5 * Copyright (c) 2010 Samsung Electronics Co. Ltd.
6 * Jaswinder Singh <jassi.brar@samsung.com>
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
13#include <linux/delay.h>
14#include <linux/slab.h>
15#include <linux/clk.h>
16#include <linux/io.h>
17
18#include <sound/pcm.h>
19#include <sound/pcm_params.h>
20#include <sound/soc.h>
21
22#include <plat/audio.h>
23
24#include "dma.h"
25#include "i2s.h"
26
27#define I2SCON 0x0
28#define I2SMOD 0x4
29#define I2SFIC 0x8
30#define I2SPSR 0xc
31#define I2STXD 0x10
32#define I2SRXD 0x14
33#define I2SFICS 0x18
34#define I2STXDS 0x1c
35
36#define CON_RSTCLR (1 << 31)
37#define CON_FRXOFSTATUS (1 << 26)
38#define CON_FRXORINTEN (1 << 25)
39#define CON_FTXSURSTAT (1 << 24)
40#define CON_FTXSURINTEN (1 << 23)
41#define CON_TXSDMA_PAUSE (1 << 20)
42#define CON_TXSDMA_ACTIVE (1 << 18)
43
44#define CON_FTXURSTATUS (1 << 17)
45#define CON_FTXURINTEN (1 << 16)
46#define CON_TXFIFO2_EMPTY (1 << 15)
47#define CON_TXFIFO1_EMPTY (1 << 14)
48#define CON_TXFIFO2_FULL (1 << 13)
49#define CON_TXFIFO1_FULL (1 << 12)
50
51#define CON_LRINDEX (1 << 11)
52#define CON_TXFIFO_EMPTY (1 << 10)
53#define CON_RXFIFO_EMPTY (1 << 9)
54#define CON_TXFIFO_FULL (1 << 8)
55#define CON_RXFIFO_FULL (1 << 7)
56#define CON_TXDMA_PAUSE (1 << 6)
57#define CON_RXDMA_PAUSE (1 << 5)
58#define CON_TXCH_PAUSE (1 << 4)
59#define CON_RXCH_PAUSE (1 << 3)
60#define CON_TXDMA_ACTIVE (1 << 2)
61#define CON_RXDMA_ACTIVE (1 << 1)
62#define CON_ACTIVE (1 << 0)
63
64#define MOD_OPCLK_CDCLK_OUT (0 << 30)
65#define MOD_OPCLK_CDCLK_IN (1 << 30)
66#define MOD_OPCLK_BCLK_OUT (2 << 30)
67#define MOD_OPCLK_PCLK (3 << 30)
68#define MOD_OPCLK_MASK (3 << 30)
69#define MOD_TXS_IDMA (1 << 28) /* Sec_TXFIFO use I-DMA */
70
71#define MOD_BLCS_SHIFT 26
72#define MOD_BLCS_16BIT (0 << MOD_BLCS_SHIFT)
73#define MOD_BLCS_8BIT (1 << MOD_BLCS_SHIFT)
74#define MOD_BLCS_24BIT (2 << MOD_BLCS_SHIFT)
75#define MOD_BLCS_MASK (3 << MOD_BLCS_SHIFT)
76#define MOD_BLCP_SHIFT 24
77#define MOD_BLCP_16BIT (0 << MOD_BLCP_SHIFT)
78#define MOD_BLCP_8BIT (1 << MOD_BLCP_SHIFT)
79#define MOD_BLCP_24BIT (2 << MOD_BLCP_SHIFT)
80#define MOD_BLCP_MASK (3 << MOD_BLCP_SHIFT)
81
82#define MOD_C2DD_HHALF (1 << 21) /* Discard Higher-half */
83#define MOD_C2DD_LHALF (1 << 20) /* Discard Lower-half */
84#define MOD_C1DD_HHALF (1 << 19)
85#define MOD_C1DD_LHALF (1 << 18)
86#define MOD_DC2_EN (1 << 17)
87#define MOD_DC1_EN (1 << 16)
88#define MOD_BLC_16BIT (0 << 13)
89#define MOD_BLC_8BIT (1 << 13)
90#define MOD_BLC_24BIT (2 << 13)
91#define MOD_BLC_MASK (3 << 13)
92
93#define MOD_IMS_SYSMUX (1 << 10)
94#define MOD_SLAVE (1 << 11)
95#define MOD_TXONLY (0 << 8)
96#define MOD_RXONLY (1 << 8)
97#define MOD_TXRX (2 << 8)
98#define MOD_MASK (3 << 8)
99#define MOD_LR_LLOW (0 << 7)
100#define MOD_LR_RLOW (1 << 7)
101#define MOD_SDF_IIS (0 << 5)
102#define MOD_SDF_MSB (1 << 5)
103#define MOD_SDF_LSB (2 << 5)
104#define MOD_SDF_MASK (3 << 5)
105#define MOD_RCLK_256FS (0 << 3)
106#define MOD_RCLK_512FS (1 << 3)
107#define MOD_RCLK_384FS (2 << 3)
108#define MOD_RCLK_768FS (3 << 3)
109#define MOD_RCLK_MASK (3 << 3)
110#define MOD_BCLK_32FS (0 << 1)
111#define MOD_BCLK_48FS (1 << 1)
112#define MOD_BCLK_16FS (2 << 1)
113#define MOD_BCLK_24FS (3 << 1)
114#define MOD_BCLK_MASK (3 << 1)
115#define MOD_8BIT (1 << 0)
116
117#define MOD_CDCLKCON (1 << 12)
118
119#define PSR_PSREN (1 << 15)
120
121#define FIC_TX2COUNT(x) (((x) >> 24) & 0xf)
122#define FIC_TX1COUNT(x) (((x) >> 16) & 0xf)
123
124#define FIC_TXFLUSH (1 << 15)
125#define FIC_RXFLUSH (1 << 7)
126#define FIC_TXCOUNT(x) (((x) >> 8) & 0xf)
127#define FIC_RXCOUNT(x) (((x) >> 0) & 0xf)
128#define FICS_TXCOUNT(x) (((x) >> 8) & 0x7f)
129
130#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
131
132struct i2s_dai {
133 /* Platform device for this DAI */
134 struct platform_device *pdev;
135 /* IOREMAP'd SFRs */
136 void __iomem *addr;
137 /* Physical base address of SFRs */
138 u32 base;
139 /* Rate of RCLK source clock */
140 unsigned long rclk_srcrate;
141 /* Frame Clock */
142 unsigned frmclk;
143 /*
144 * Specifically requested RCLK,BCLK by MACHINE Driver.
145 * 0 indicates CPU driver is free to choose any value.
146 */
147 unsigned rfs, bfs;
148 /* I2S Controller's core clock */
149 struct clk *clk;
150 /* Clock for generating I2S signals */
151 struct clk *op_clk;
152 /* Array of clock names for op_clk */
153 const char **src_clk;
154 /* Pointer to the Primary_Fifo if this is Sec_Fifo, NULL otherwise */
155 struct i2s_dai *pri_dai;
156 /* Pointer to the Secondary_Fifo if it has one, NULL otherwise */
157 struct i2s_dai *sec_dai;
158#define DAI_OPENED (1 << 0) /* Dai is opened */
159#define DAI_MANAGER (1 << 1) /* Dai is the manager */
160 unsigned mode;
161 /* Driver for this DAI */
162 struct snd_soc_dai_driver i2s_dai_drv;
163 /* DMA parameters */
164 struct s3c_dma_params dma_playback;
165 struct s3c_dma_params dma_capture;
166 u32 quirks;
167 u32 suspend_i2smod;
168 u32 suspend_i2scon;
169 u32 suspend_i2spsr;
170};
171
172/* Lock for cross i/f checks */
173static DEFINE_SPINLOCK(lock);
174
175/* If this is the 'overlay' stereo DAI */
176static inline bool is_secondary(struct i2s_dai *i2s)
177{
178 return i2s->pri_dai ? true : false;
179}
180
181/* If operating in SoC-Slave mode */
182static inline bool is_slave(struct i2s_dai *i2s)
183{
184 return (readl(i2s->addr + I2SMOD) & MOD_SLAVE) ? true : false;
185}
186
187/* If this interface of the controller is transmitting data */
188static inline bool tx_active(struct i2s_dai *i2s)
189{
190 u32 active;
191
192 if (!i2s)
193 return false;
194
195 active = readl(i2s->addr + I2SMOD);
196
197 if (is_secondary(i2s))
198 active &= CON_TXSDMA_ACTIVE;
199 else
200 active &= CON_TXDMA_ACTIVE;
201
202 return active ? true : false;
203}
204
205/* If the other interface of the controller is transmitting data */
206static inline bool other_tx_active(struct i2s_dai *i2s)
207{
208 struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
209
210 return tx_active(other);
211}
212
213/* If any interface of the controller is transmitting data */
214static inline bool any_tx_active(struct i2s_dai *i2s)
215{
216 return tx_active(i2s) || other_tx_active(i2s);
217}
218
219/* If this interface of the controller is receiving data */
220static inline bool rx_active(struct i2s_dai *i2s)
221{
222 u32 active;
223
224 if (!i2s)
225 return false;
226
227 active = readl(i2s->addr + I2SMOD) & CON_RXDMA_ACTIVE;
228
229 return active ? true : false;
230}
231
232/* If the other interface of the controller is receiving data */
233static inline bool other_rx_active(struct i2s_dai *i2s)
234{
235 struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
236
237 return rx_active(other);
238}
239
240/* If any interface of the controller is receiving data */
241static inline bool any_rx_active(struct i2s_dai *i2s)
242{
243 return rx_active(i2s) || other_rx_active(i2s);
244}
245
246/* If the other DAI is transmitting or receiving data */
247static inline bool other_active(struct i2s_dai *i2s)
248{
249 return other_rx_active(i2s) || other_tx_active(i2s);
250}
251
252/* If this DAI is transmitting or receiving data */
253static inline bool this_active(struct i2s_dai *i2s)
254{
255 return tx_active(i2s) || rx_active(i2s);
256}
257
258/* If the controller is active anyway */
259static inline bool any_active(struct i2s_dai *i2s)
260{
261 return this_active(i2s) || other_active(i2s);
262}
263
264static inline struct i2s_dai *to_info(struct snd_soc_dai *dai)
265{
266 return snd_soc_dai_get_drvdata(dai);
267}
268
269static inline bool is_opened(struct i2s_dai *i2s)
270{
271 if (i2s && (i2s->mode & DAI_OPENED))
272 return true;
273 else
274 return false;
275}
276
277static inline bool is_manager(struct i2s_dai *i2s)
278{
279 if (is_opened(i2s) && (i2s->mode & DAI_MANAGER))
280 return true;
281 else
282 return false;
283}
284
285/* Read RCLK of I2S (in multiples of LRCLK) */
286static inline unsigned get_rfs(struct i2s_dai *i2s)
287{
288 u32 rfs = (readl(i2s->addr + I2SMOD) >> 3) & 0x3;
289
290 switch (rfs) {
291 case 3: return 768;
292 case 2: return 384;
293 case 1: return 512;
294 default: return 256;
295 }
296}
297
298/* Write RCLK of I2S (in multiples of LRCLK) */
299static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
300{
301 u32 mod = readl(i2s->addr + I2SMOD);
302
303 mod &= ~MOD_RCLK_MASK;
304
305 switch (rfs) {
306 case 768:
307 mod |= MOD_RCLK_768FS;
308 break;
309 case 512:
310 mod |= MOD_RCLK_512FS;
311 break;
312 case 384:
313 mod |= MOD_RCLK_384FS;
314 break;
315 default:
316 mod |= MOD_RCLK_256FS;
317 break;
318 }
319
320 writel(mod, i2s->addr + I2SMOD);
321}
322
323/* Read Bit-Clock of I2S (in multiples of LRCLK) */
324static inline unsigned get_bfs(struct i2s_dai *i2s)
325{
326 u32 bfs = (readl(i2s->addr + I2SMOD) >> 1) & 0x3;
327
328 switch (bfs) {
329 case 3: return 24;
330 case 2: return 16;
331 case 1: return 48;
332 default: return 32;
333 }
334}
335
336/* Write Bit-Clock of I2S (in multiples of LRCLK) */
337static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs)
338{
339 u32 mod = readl(i2s->addr + I2SMOD);
340
341 mod &= ~MOD_BCLK_MASK;
342
343 switch (bfs) {
344 case 48:
345 mod |= MOD_BCLK_48FS;
346 break;
347 case 32:
348 mod |= MOD_BCLK_32FS;
349 break;
350 case 24:
351 mod |= MOD_BCLK_24FS;
352 break;
353 case 16:
354 mod |= MOD_BCLK_16FS;
355 break;
356 default:
357 dev_err(&i2s->pdev->dev, "Wrong BCLK Divider!\n");
358 return;
359 }
360
361 writel(mod, i2s->addr + I2SMOD);
362}
363
364/* Sample-Size */
365static inline int get_blc(struct i2s_dai *i2s)
366{
367 int blc = readl(i2s->addr + I2SMOD);
368
369 blc = (blc >> 13) & 0x3;
370
371 switch (blc) {
372 case 2: return 24;
373 case 1: return 8;
374 default: return 16;
375 }
376}
377
378/* TX Channel Control */
379static void i2s_txctrl(struct i2s_dai *i2s, int on)
380{
381 void __iomem *addr = i2s->addr;
382 u32 con = readl(addr + I2SCON);
383 u32 mod = readl(addr + I2SMOD) & ~MOD_MASK;
384
385 if (on) {
386 con |= CON_ACTIVE;
387 con &= ~CON_TXCH_PAUSE;
388
389 if (is_secondary(i2s)) {
390 con |= CON_TXSDMA_ACTIVE;
391 con &= ~CON_TXSDMA_PAUSE;
392 } else {
393 con |= CON_TXDMA_ACTIVE;
394 con &= ~CON_TXDMA_PAUSE;
395 }
396
397 if (any_rx_active(i2s))
398 mod |= MOD_TXRX;
399 else
400 mod |= MOD_TXONLY;
401 } else {
402 if (is_secondary(i2s)) {
403 con |= CON_TXSDMA_PAUSE;
404 con &= ~CON_TXSDMA_ACTIVE;
405 } else {
406 con |= CON_TXDMA_PAUSE;
407 con &= ~CON_TXDMA_ACTIVE;
408 }
409
410 if (other_tx_active(i2s)) {
411 writel(con, addr + I2SCON);
412 return;
413 }
414
415 con |= CON_TXCH_PAUSE;
416
417 if (any_rx_active(i2s))
418 mod |= MOD_RXONLY;
419 else
420 con &= ~CON_ACTIVE;
421 }
422
423 writel(mod, addr + I2SMOD);
424 writel(con, addr + I2SCON);
425}
426
427/* RX Channel Control */
428static void i2s_rxctrl(struct i2s_dai *i2s, int on)
429{
430 void __iomem *addr = i2s->addr;
431 u32 con = readl(addr + I2SCON);
432 u32 mod = readl(addr + I2SMOD) & ~MOD_MASK;
433
434 if (on) {
435 con |= CON_RXDMA_ACTIVE | CON_ACTIVE;
436 con &= ~(CON_RXDMA_PAUSE | CON_RXCH_PAUSE);
437
438 if (any_tx_active(i2s))
439 mod |= MOD_TXRX;
440 else
441 mod |= MOD_RXONLY;
442 } else {
443 con |= CON_RXDMA_PAUSE | CON_RXCH_PAUSE;
444 con &= ~CON_RXDMA_ACTIVE;
445
446 if (any_tx_active(i2s))
447 mod |= MOD_TXONLY;
448 else
449 con &= ~CON_ACTIVE;
450 }
451
452 writel(mod, addr + I2SMOD);
453 writel(con, addr + I2SCON);
454}
455
456/* Flush FIFO of an interface */
457static inline void i2s_fifo(struct i2s_dai *i2s, u32 flush)
458{
459 void __iomem *fic;
460 u32 val;
461
462 if (!i2s)
463 return;
464
465 if (is_secondary(i2s))
466 fic = i2s->addr + I2SFICS;
467 else
468 fic = i2s->addr + I2SFIC;
469
470 /* Flush the FIFO */
471 writel(readl(fic) | flush, fic);
472
473 /* Be patient */
474 val = msecs_to_loops(1) / 1000; /* 1 usec */
475 while (--val)
476 cpu_relax();
477
478 writel(readl(fic) & ~flush, fic);
479}
480
481static int i2s_set_sysclk(struct snd_soc_dai *dai,
482 int clk_id, unsigned int rfs, int dir)
483{
484 struct i2s_dai *i2s = to_info(dai);
485 struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
486 u32 mod = readl(i2s->addr + I2SMOD);
487
488 switch (clk_id) {
489 case SAMSUNG_I2S_CDCLK:
490 /* Shouldn't matter in GATING(CLOCK_IN) mode */
491 if (dir == SND_SOC_CLOCK_IN)
492 rfs = 0;
493
494 if ((rfs && other->rfs && (other->rfs != rfs)) ||
495 (any_active(i2s) &&
496 (((dir == SND_SOC_CLOCK_IN)
497 && !(mod & MOD_CDCLKCON)) ||
498 ((dir == SND_SOC_CLOCK_OUT)
499 && (mod & MOD_CDCLKCON))))) {
500 dev_err(&i2s->pdev->dev,
501 "%s:%d Other DAI busy\n", __func__, __LINE__);
502 return -EAGAIN;
503 }
504
505 if (dir == SND_SOC_CLOCK_IN)
506 mod |= MOD_CDCLKCON;
507 else
508 mod &= ~MOD_CDCLKCON;
509
510 i2s->rfs = rfs;
511 break;
512
513 case SAMSUNG_I2S_RCLKSRC_0: /* clock corrsponding to IISMOD[10] := 0 */
514 case SAMSUNG_I2S_RCLKSRC_1: /* clock corrsponding to IISMOD[10] := 1 */
515 if ((i2s->quirks & QUIRK_NO_MUXPSR)
516 || (clk_id == SAMSUNG_I2S_RCLKSRC_0))
517 clk_id = 0;
518 else
519 clk_id = 1;
520
521 if (!any_active(i2s)) {
522 if (i2s->op_clk) {
523 if ((clk_id && !(mod & MOD_IMS_SYSMUX)) ||
524 (!clk_id && (mod & MOD_IMS_SYSMUX))) {
525 clk_disable(i2s->op_clk);
526 clk_put(i2s->op_clk);
527 } else {
528 return 0;
529 }
530 }
531
532 i2s->op_clk = clk_get(&i2s->pdev->dev,
533 i2s->src_clk[clk_id]);
534 clk_enable(i2s->op_clk);
535 i2s->rclk_srcrate = clk_get_rate(i2s->op_clk);
536
537 /* Over-ride the other's */
538 if (other) {
539 other->op_clk = i2s->op_clk;
540 other->rclk_srcrate = i2s->rclk_srcrate;
541 }
542 } else if ((!clk_id && (mod & MOD_IMS_SYSMUX))
543 || (clk_id && !(mod & MOD_IMS_SYSMUX))) {
544 dev_err(&i2s->pdev->dev,
545 "%s:%d Other DAI busy\n", __func__, __LINE__);
546 return -EAGAIN;
547 } else {
548 /* Call can't be on the active DAI */
549 i2s->op_clk = other->op_clk;
550 i2s->rclk_srcrate = other->rclk_srcrate;
551 return 0;
552 }
553
554 if (clk_id == 0)
555 mod &= ~MOD_IMS_SYSMUX;
556 else
557 mod |= MOD_IMS_SYSMUX;
558 break;
559
560 default:
561 dev_err(&i2s->pdev->dev, "We don't serve that!\n");
562 return -EINVAL;
563 }
564
565 writel(mod, i2s->addr + I2SMOD);
566
567 return 0;
568}
569
570static int i2s_set_fmt(struct snd_soc_dai *dai,
571 unsigned int fmt)
572{
573 struct i2s_dai *i2s = to_info(dai);
574 u32 mod = readl(i2s->addr + I2SMOD);
575 u32 tmp = 0;
576
577 /* Format is priority */
578 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
579 case SND_SOC_DAIFMT_RIGHT_J:
580 tmp |= MOD_LR_RLOW;
581 tmp |= MOD_SDF_MSB;
582 break;
583 case SND_SOC_DAIFMT_LEFT_J:
584 tmp |= MOD_LR_RLOW;
585 tmp |= MOD_SDF_LSB;
586 break;
587 case SND_SOC_DAIFMT_I2S:
588 tmp |= MOD_SDF_IIS;
589 break;
590 default:
591 dev_err(&i2s->pdev->dev, "Format not supported\n");
592 return -EINVAL;
593 }
594
595 /*
596 * INV flag is relative to the FORMAT flag - if set it simply
597 * flips the polarity specified by the Standard
598 */
599 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
600 case SND_SOC_DAIFMT_NB_NF:
601 break;
602 case SND_SOC_DAIFMT_NB_IF:
603 if (tmp & MOD_LR_RLOW)
604 tmp &= ~MOD_LR_RLOW;
605 else
606 tmp |= MOD_LR_RLOW;
607 break;
608 default:
609 dev_err(&i2s->pdev->dev, "Polarity not supported\n");
610 return -EINVAL;
611 }
612
613 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
614 case SND_SOC_DAIFMT_CBM_CFM:
615 tmp |= MOD_SLAVE;
616 break;
617 case SND_SOC_DAIFMT_CBS_CFS:
618 /* Set default source clock in Master mode */
619 if (i2s->rclk_srcrate == 0)
620 i2s_set_sysclk(dai, SAMSUNG_I2S_RCLKSRC_0,
621 0, SND_SOC_CLOCK_IN);
622 break;
623 default:
624 dev_err(&i2s->pdev->dev, "master/slave format not supported\n");
625 return -EINVAL;
626 }
627
628 if (any_active(i2s) &&
629 ((mod & (MOD_SDF_MASK | MOD_LR_RLOW
630 | MOD_SLAVE)) != tmp)) {
631 dev_err(&i2s->pdev->dev,
632 "%s:%d Other DAI busy\n", __func__, __LINE__);
633 return -EAGAIN;
634 }
635
636 mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE);
637 mod |= tmp;
638 writel(mod, i2s->addr + I2SMOD);
639
640 return 0;
641}
642
643static int i2s_hw_params(struct snd_pcm_substream *substream,
644 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
645{
646 struct i2s_dai *i2s = to_info(dai);
647 u32 mod = readl(i2s->addr + I2SMOD);
648
649 if (!is_secondary(i2s))
650 mod &= ~(MOD_DC2_EN | MOD_DC1_EN);
651
652 switch (params_channels(params)) {
653 case 6:
654 mod |= MOD_DC2_EN;
655 case 4:
656 mod |= MOD_DC1_EN;
657 break;
658 case 2:
659 break;
660 default:
661 dev_err(&i2s->pdev->dev, "%d channels not supported\n",
662 params_channels(params));
663 return -EINVAL;
664 }
665
666 if (is_secondary(i2s))
667 mod &= ~MOD_BLCS_MASK;
668 else
669 mod &= ~MOD_BLCP_MASK;
670
671 if (is_manager(i2s))
672 mod &= ~MOD_BLC_MASK;
673
674 switch (params_format(params)) {
675 case SNDRV_PCM_FORMAT_S8:
676 if (is_secondary(i2s))
677 mod |= MOD_BLCS_8BIT;
678 else
679 mod |= MOD_BLCP_8BIT;
680 if (is_manager(i2s))
681 mod |= MOD_BLC_8BIT;
682 break;
683 case SNDRV_PCM_FORMAT_S16_LE:
684 if (is_secondary(i2s))
685 mod |= MOD_BLCS_16BIT;
686 else
687 mod |= MOD_BLCP_16BIT;
688 if (is_manager(i2s))
689 mod |= MOD_BLC_16BIT;
690 break;
691 case SNDRV_PCM_FORMAT_S24_LE:
692 if (is_secondary(i2s))
693 mod |= MOD_BLCS_24BIT;
694 else
695 mod |= MOD_BLCP_24BIT;
696 if (is_manager(i2s))
697 mod |= MOD_BLC_24BIT;
698 break;
699 default:
700 dev_err(&i2s->pdev->dev, "Format(%d) not supported\n",
701 params_format(params));
702 return -EINVAL;
703 }
704 writel(mod, i2s->addr + I2SMOD);
705
706 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
707 snd_soc_dai_set_dma_data(dai, substream,
708 (void *)&i2s->dma_playback);
709 else
710 snd_soc_dai_set_dma_data(dai, substream,
711 (void *)&i2s->dma_capture);
712
713 i2s->frmclk = params_rate(params);
714
715 return 0;
716}
717
718/* We set constraints on the substream acc to the version of I2S */
719static int i2s_startup(struct snd_pcm_substream *substream,
720 struct snd_soc_dai *dai)
721{
722 struct i2s_dai *i2s = to_info(dai);
723 struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
724 unsigned long flags;
725
726 spin_lock_irqsave(&lock, flags);
727
728 i2s->mode |= DAI_OPENED;
729
730 if (is_manager(other))
731 i2s->mode &= ~DAI_MANAGER;
732 else
733 i2s->mode |= DAI_MANAGER;
734
735 /* Enforce set_sysclk in Master mode */
736 i2s->rclk_srcrate = 0;
737
738 spin_unlock_irqrestore(&lock, flags);
739
740 return 0;
741}
742
743static void i2s_shutdown(struct snd_pcm_substream *substream,
744 struct snd_soc_dai *dai)
745{
746 struct i2s_dai *i2s = to_info(dai);
747 struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
748 unsigned long flags;
749
750 spin_lock_irqsave(&lock, flags);
751
752 i2s->mode &= ~DAI_OPENED;
753 i2s->mode &= ~DAI_MANAGER;
754
755 if (is_opened(other))
756 other->mode |= DAI_MANAGER;
757
758 /* Reset any constraint on RFS and BFS */
759 i2s->rfs = 0;
760 i2s->bfs = 0;
761
762 spin_unlock_irqrestore(&lock, flags);
763
764 /* Gate CDCLK by default */
765 if (!is_opened(other))
766 i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
767 0, SND_SOC_CLOCK_IN);
768}
769
770static int config_setup(struct i2s_dai *i2s)
771{
772 struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
773 unsigned rfs, bfs, blc;
774 u32 psr;
775
776 blc = get_blc(i2s);
777
778 bfs = i2s->bfs;
779
780 if (!bfs && other)
781 bfs = other->bfs;
782
783 /* Select least possible multiple(2) if no constraint set */
784 if (!bfs)
785 bfs = blc * 2;
786
787 rfs = i2s->rfs;
788
789 if (!rfs && other)
790 rfs = other->rfs;
791
792 if ((rfs == 256 || rfs == 512) && (blc == 24)) {
793 dev_err(&i2s->pdev->dev,
794 "%d-RFS not supported for 24-blc\n", rfs);
795 return -EINVAL;
796 }
797
798 if (!rfs) {
799 if (bfs == 16 || bfs == 32)
800 rfs = 256;
801 else
802 rfs = 384;
803 }
804
805 /* If already setup and running */
806 if (any_active(i2s) && (get_rfs(i2s) != rfs || get_bfs(i2s) != bfs)) {
807 dev_err(&i2s->pdev->dev,
808 "%s:%d Other DAI busy\n", __func__, __LINE__);
809 return -EAGAIN;
810 }
811
812 /* Don't bother RFS, BFS & PSR in Slave mode */
813 if (is_slave(i2s))
814 return 0;
815
816 set_bfs(i2s, bfs);
817 set_rfs(i2s, rfs);
818
819 if (!(i2s->quirks & QUIRK_NO_MUXPSR)) {
820 psr = i2s->rclk_srcrate / i2s->frmclk / rfs;
821 writel(((psr - 1) << 8) | PSR_PSREN, i2s->addr + I2SPSR);
822 dev_dbg(&i2s->pdev->dev,
823 "RCLK_SRC=%luHz PSR=%u, RCLK=%dfs, BCLK=%dfs\n",
824 i2s->rclk_srcrate, psr, rfs, bfs);
825 }
826
827 return 0;
828}
829
830static int i2s_trigger(struct snd_pcm_substream *substream,
831 int cmd, struct snd_soc_dai *dai)
832{
833 int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
834 struct snd_soc_pcm_runtime *rtd = substream->private_data;
835 struct i2s_dai *i2s = to_info(rtd->cpu_dai);
836 unsigned long flags;
837
838 switch (cmd) {
839 case SNDRV_PCM_TRIGGER_START:
840 case SNDRV_PCM_TRIGGER_RESUME:
841 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
842 local_irq_save(flags);
843
844 if (capture)
845 i2s_fifo(i2s, FIC_RXFLUSH);
846 else
847 i2s_fifo(i2s, FIC_TXFLUSH);
848
849 if (config_setup(i2s)) {
850 local_irq_restore(flags);
851 return -EINVAL;
852 }
853
854 if (capture)
855 i2s_rxctrl(i2s, 1);
856 else
857 i2s_txctrl(i2s, 1);
858
859 local_irq_restore(flags);
860 break;
861 case SNDRV_PCM_TRIGGER_STOP:
862 case SNDRV_PCM_TRIGGER_SUSPEND:
863 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
864 local_irq_save(flags);
865
866 if (capture)
867 i2s_rxctrl(i2s, 0);
868 else
869 i2s_txctrl(i2s, 0);
870
871 local_irq_restore(flags);
872 break;
873 }
874
875 return 0;
876}
877
878static int i2s_set_clkdiv(struct snd_soc_dai *dai,
879 int div_id, int div)
880{
881 struct i2s_dai *i2s = to_info(dai);
882 struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
883
884 switch (div_id) {
885 case SAMSUNG_I2S_DIV_BCLK:
886 if ((any_active(i2s) && div && (get_bfs(i2s) != div))
887 || (other && other->bfs && (other->bfs != div))) {
888 dev_err(&i2s->pdev->dev,
889 "%s:%d Other DAI busy\n", __func__, __LINE__);
890 return -EAGAIN;
891 }
892 i2s->bfs = div;
893 break;
894 default:
895 dev_err(&i2s->pdev->dev,
896 "Invalid clock divider(%d)\n", div_id);
897 return -EINVAL;
898 }
899
900 return 0;
901}
902
903static snd_pcm_sframes_t
904i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
905{
906 struct i2s_dai *i2s = to_info(dai);
907 u32 reg = readl(i2s->addr + I2SFIC);
908 snd_pcm_sframes_t delay;
909
910 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
911 delay = FIC_RXCOUNT(reg);
912 else if (is_secondary(i2s))
913 delay = FICS_TXCOUNT(readl(i2s->addr + I2SFICS));
914 else
915 delay = FIC_TXCOUNT(reg);
916
917 return delay;
918}
919
920#ifdef CONFIG_PM
921static int i2s_suspend(struct snd_soc_dai *dai)
922{
923 struct i2s_dai *i2s = to_info(dai);
924
925 if (dai->active) {
926 i2s->suspend_i2smod = readl(i2s->addr + I2SMOD);
927 i2s->suspend_i2scon = readl(i2s->addr + I2SCON);
928 i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR);
929 }
930
931 return 0;
932}
933
934static int i2s_resume(struct snd_soc_dai *dai)
935{
936 struct i2s_dai *i2s = to_info(dai);
937
938 if (dai->active) {
939 writel(i2s->suspend_i2scon, i2s->addr + I2SCON);
940 writel(i2s->suspend_i2smod, i2s->addr + I2SMOD);
941 writel(i2s->suspend_i2spsr, i2s->addr + I2SPSR);
942 }
943
944 return 0;
945}
946#else
947#define i2s_suspend NULL
948#define i2s_resume NULL
949#endif
950
951static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
952{
953 struct i2s_dai *i2s = to_info(dai);
954 struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
955
956 if (other && other->clk) /* If this is probe on secondary */
957 goto probe_exit;
958
959 i2s->addr = ioremap(i2s->base, 0x100);
960 if (i2s->addr == NULL) {
961 dev_err(&i2s->pdev->dev, "cannot ioremap registers\n");
962 return -ENXIO;
963 }
964
965 i2s->clk = clk_get(&i2s->pdev->dev, "iis");
966 if (IS_ERR(i2s->clk)) {
967 dev_err(&i2s->pdev->dev, "failed to get i2s_clock\n");
968 iounmap(i2s->addr);
969 return -ENOENT;
970 }
971 clk_enable(i2s->clk);
972
973 if (other) {
974 other->addr = i2s->addr;
975 other->clk = i2s->clk;
976 }
977
978 if (i2s->quirks & QUIRK_NEED_RSTCLR)
979 writel(CON_RSTCLR, i2s->addr + I2SCON);
980
981probe_exit:
982 /* Reset any constraint on RFS and BFS */
983 i2s->rfs = 0;
984 i2s->bfs = 0;
985 i2s_txctrl(i2s, 0);
986 i2s_rxctrl(i2s, 0);
987 i2s_fifo(i2s, FIC_TXFLUSH);
988 i2s_fifo(other, FIC_TXFLUSH);
989 i2s_fifo(i2s, FIC_RXFLUSH);
990
991 /* Gate CDCLK by default */
992 if (!is_opened(other))
993 i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
994 0, SND_SOC_CLOCK_IN);
995
996 return 0;
997}
998
999static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
1000{
1001 struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai);
1002 struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
1003
1004 if (!other || !other->clk) {
1005
1006 if (i2s->quirks & QUIRK_NEED_RSTCLR)
1007 writel(0, i2s->addr + I2SCON);
1008
1009 clk_disable(i2s->clk);
1010 clk_put(i2s->clk);
1011
1012 iounmap(i2s->addr);
1013 }
1014
1015 i2s->clk = NULL;
1016
1017 return 0;
1018}
1019
1020static struct snd_soc_dai_ops samsung_i2s_dai_ops = {
1021 .trigger = i2s_trigger,
1022 .hw_params = i2s_hw_params,
1023 .set_fmt = i2s_set_fmt,
1024 .set_clkdiv = i2s_set_clkdiv,
1025 .set_sysclk = i2s_set_sysclk,
1026 .startup = i2s_startup,
1027 .shutdown = i2s_shutdown,
1028 .delay = i2s_delay,
1029};
1030
1031#define SAMSUNG_I2S_RATES SNDRV_PCM_RATE_8000_96000
1032
1033#define SAMSUNG_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \
1034 SNDRV_PCM_FMTBIT_S16_LE | \
1035 SNDRV_PCM_FMTBIT_S24_LE)
1036
1037static __devinit
1038struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
1039{
1040 struct i2s_dai *i2s;
1041
1042 i2s = kzalloc(sizeof(struct i2s_dai), GFP_KERNEL);
1043 if (i2s == NULL)
1044 return NULL;
1045
1046 i2s->pdev = pdev;
1047 i2s->pri_dai = NULL;
1048 i2s->sec_dai = NULL;
1049 i2s->i2s_dai_drv.symmetric_rates = 1;
1050 i2s->i2s_dai_drv.probe = samsung_i2s_dai_probe;
1051 i2s->i2s_dai_drv.remove = samsung_i2s_dai_remove;
1052 i2s->i2s_dai_drv.ops = &samsung_i2s_dai_ops;
1053 i2s->i2s_dai_drv.suspend = i2s_suspend;
1054 i2s->i2s_dai_drv.resume = i2s_resume;
1055 i2s->i2s_dai_drv.playback.channels_min = 2;
1056 i2s->i2s_dai_drv.playback.channels_max = 2;
1057 i2s->i2s_dai_drv.playback.rates = SAMSUNG_I2S_RATES;
1058 i2s->i2s_dai_drv.playback.formats = SAMSUNG_I2S_FMTS;
1059
1060 if (!sec) {
1061 i2s->i2s_dai_drv.capture.channels_min = 2;
1062 i2s->i2s_dai_drv.capture.channels_max = 2;
1063 i2s->i2s_dai_drv.capture.rates = SAMSUNG_I2S_RATES;
1064 i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS;
1065 } else { /* Create a new platform_device for Secondary */
1066 i2s->pdev = platform_device_register_resndata(NULL,
1067 pdev->name, pdev->id + SAMSUNG_I2S_SECOFF,
1068 NULL, 0, NULL, 0);
1069 if (IS_ERR(i2s->pdev)) {
1070 kfree(i2s);
1071 return NULL;
1072 }
1073 }
1074
1075 /* Pre-assign snd_soc_dai_set_drvdata */
1076 dev_set_drvdata(&i2s->pdev->dev, i2s);
1077
1078 return i2s;
1079}
1080
1081static __devinit int samsung_i2s_probe(struct platform_device *pdev)
1082{
1083 u32 dma_pl_chan, dma_cp_chan, dma_pl_sec_chan;
1084 struct i2s_dai *pri_dai, *sec_dai = NULL;
1085 struct s3c_audio_pdata *i2s_pdata;
1086 struct samsung_i2s *i2s_cfg;
1087 struct resource *res;
1088 u32 regs_base, quirks;
1089 int ret = 0;
1090
1091 /* Call during Seconday interface registration */
1092 if (pdev->id >= SAMSUNG_I2S_SECOFF) {
1093 sec_dai = dev_get_drvdata(&pdev->dev);
1094 snd_soc_register_dai(&sec_dai->pdev->dev,
1095 &sec_dai->i2s_dai_drv);
1096 return 0;
1097 }
1098
1099 i2s_pdata = pdev->dev.platform_data;
1100 if (i2s_pdata == NULL) {
1101 dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n");
1102 return -EINVAL;
1103 }
1104
1105 res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
1106 if (!res) {
1107 dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n");
1108 return -ENXIO;
1109 }
1110 dma_pl_chan = res->start;
1111
1112 res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
1113 if (!res) {
1114 dev_err(&pdev->dev, "Unable to get I2S-RX dma resource\n");
1115 return -ENXIO;
1116 }
1117 dma_cp_chan = res->start;
1118
1119 res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
1120 if (res)
1121 dma_pl_sec_chan = res->start;
1122 else
1123 dma_pl_sec_chan = 0;
1124
1125 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1126 if (!res) {
1127 dev_err(&pdev->dev, "Unable to get I2S SFR address\n");
1128 return -ENXIO;
1129 }
1130
1131 if (!request_mem_region(res->start, resource_size(res),
1132 "samsung-i2s")) {
1133 dev_err(&pdev->dev, "Unable to request SFR region\n");
1134 return -EBUSY;
1135 }
1136 regs_base = res->start;
1137
1138 i2s_cfg = &i2s_pdata->type.i2s;
1139 quirks = i2s_cfg->quirks;
1140
1141 pri_dai = i2s_alloc_dai(pdev, false);
1142 if (!pri_dai) {
1143 dev_err(&pdev->dev, "Unable to alloc I2S_pri\n");
1144 ret = -ENOMEM;
1145 goto err1;
1146 }
1147
1148 pri_dai->dma_playback.dma_addr = regs_base + I2STXD;
1149 pri_dai->dma_capture.dma_addr = regs_base + I2SRXD;
1150 pri_dai->dma_playback.client =
1151 (struct s3c2410_dma_client *)&pri_dai->dma_playback;
1152 pri_dai->dma_capture.client =
1153 (struct s3c2410_dma_client *)&pri_dai->dma_capture;
1154 pri_dai->dma_playback.channel = dma_pl_chan;
1155 pri_dai->dma_capture.channel = dma_cp_chan;
1156 pri_dai->src_clk = i2s_cfg->src_clk;
1157 pri_dai->dma_playback.dma_size = 4;
1158 pri_dai->dma_capture.dma_size = 4;
1159 pri_dai->base = regs_base;
1160 pri_dai->quirks = quirks;
1161
1162 if (quirks & QUIRK_PRI_6CHAN)
1163 pri_dai->i2s_dai_drv.playback.channels_max = 6;
1164
1165 if (quirks & QUIRK_SEC_DAI) {
1166 sec_dai = i2s_alloc_dai(pdev, true);
1167 if (!sec_dai) {
1168 dev_err(&pdev->dev, "Unable to alloc I2S_sec\n");
1169 ret = -ENOMEM;
1170 goto err2;
1171 }
1172 sec_dai->dma_playback.dma_addr = regs_base + I2STXDS;
1173 sec_dai->dma_playback.client =
1174 (struct s3c2410_dma_client *)&sec_dai->dma_playback;
1175 /* Use iDMA always if SysDMA not provided */
1176 sec_dai->dma_playback.channel = dma_pl_sec_chan ? : -1;
1177 sec_dai->src_clk = i2s_cfg->src_clk;
1178 sec_dai->dma_playback.dma_size = 4;
1179 sec_dai->base = regs_base;
1180 sec_dai->quirks = quirks;
1181 sec_dai->pri_dai = pri_dai;
1182 pri_dai->sec_dai = sec_dai;
1183 }
1184
1185 if (i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
1186 dev_err(&pdev->dev, "Unable to configure gpio\n");
1187 ret = -EINVAL;
1188 goto err3;
1189 }
1190
1191 snd_soc_register_dai(&pri_dai->pdev->dev, &pri_dai->i2s_dai_drv);
1192
1193 return 0;
1194err3:
1195 kfree(sec_dai);
1196err2:
1197 kfree(pri_dai);
1198err1:
1199 release_mem_region(regs_base, resource_size(res));
1200
1201 return ret;
1202}
1203
1204static __devexit int samsung_i2s_remove(struct platform_device *pdev)
1205{
1206 struct i2s_dai *i2s, *other;
1207
1208 i2s = dev_get_drvdata(&pdev->dev);
1209 other = i2s->pri_dai ? : i2s->sec_dai;
1210
1211 if (other) {
1212 other->pri_dai = NULL;
1213 other->sec_dai = NULL;
1214 } else {
1215 struct resource *res;
1216 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1217 if (res)
1218 release_mem_region(res->start, resource_size(res));
1219 }
1220
1221 i2s->pri_dai = NULL;
1222 i2s->sec_dai = NULL;
1223
1224 kfree(i2s);
1225
1226 snd_soc_unregister_dai(&pdev->dev);
1227
1228 return 0;
1229}
1230
1231static struct platform_driver samsung_i2s_driver = {
1232 .probe = samsung_i2s_probe,
1233 .remove = samsung_i2s_remove,
1234 .driver = {
1235 .name = "samsung-i2s",
1236 .owner = THIS_MODULE,
1237 },
1238};
1239
1240static int __init samsung_i2s_init(void)
1241{
1242 return platform_driver_register(&samsung_i2s_driver);
1243}
1244module_init(samsung_i2s_init);
1245
1246static void __exit samsung_i2s_exit(void)
1247{
1248 platform_driver_unregister(&samsung_i2s_driver);
1249}
1250module_exit(samsung_i2s_exit);
1251
1252/* Module information */
1253MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
1254MODULE_DESCRIPTION("Samsung I2S Interface");
1255MODULE_ALIAS("platform:samsung-i2s");
1256MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/i2s.h b/sound/soc/s3c24xx/i2s.h
new file mode 100644
index 000000000000..d3180b37dc10
--- /dev/null
+++ b/sound/soc/s3c24xx/i2s.h
@@ -0,0 +1,29 @@
1/* sound/soc/s3c24xx/i2s.h
2 *
3 * ALSA SoC Audio Layer - Samsung I2S Controller driver
4 *
5 * Copyright (c) 2010 Samsung Electronics Co. Ltd.
6 * Jaswinder Singh <jassi.brar@samsung.com>
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
13#ifndef __SND_SOC_SAMSUNG_I2S_H
14#define __SND_SOC_SAMSUNG_I2S_H
15
16/*
17 * Maximum number of I2S blocks that any SoC can have.
18 * The secondary interface of a CPU dai(if there exists any),
19 * is indexed at [cpu-dai's ID + SAMSUNG_I2S_SECOFF]
20 */
21#define SAMSUNG_I2S_SECOFF 4
22
23#define SAMSUNG_I2S_DIV_BCLK 1
24
25#define SAMSUNG_I2S_RCLKSRC_0 0
26#define SAMSUNG_I2S_RCLKSRC_1 1
27#define SAMSUNG_I2S_CDCLK 2
28
29#endif /* __SND_SOC_SAMSUNG_I2S_H */