aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/s3c24xx
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/s3c24xx')
-rw-r--r--sound/soc/s3c24xx/Kconfig12
-rw-r--r--sound/soc/s3c24xx/Makefile2
-rw-r--r--sound/soc/s3c24xx/jive_wm8750.c7
-rw-r--r--sound/soc/s3c24xx/neo1973_gta02_wm8753.c8
-rw-r--r--sound/soc/s3c24xx/regs-i2s-v2.h115
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.c205
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.h15
-rw-r--r--sound/soc/s3c24xx/s3c2412-i2s.c77
-rw-r--r--sound/soc/s3c24xx/s3c2412-i2s.h6
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s-v4.c209
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s.c69
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s.h18
-rw-r--r--sound/soc/s3c24xx/smdk64xx_wm8580.c6
13 files changed, 533 insertions, 216 deletions
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 15fe57e5a232..2a7cc222d098 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -24,6 +24,11 @@ config SND_S3C64XX_SOC_I2S
24 select SND_S3C_I2SV2_SOC 24 select SND_S3C_I2SV2_SOC
25 select S3C64XX_DMA 25 select S3C64XX_DMA
26 26
27config SND_S3C64XX_SOC_I2S_V4
28 tristate
29 select SND_S3C_I2SV2_SOC
30 select S3C64XX_DMA
31
27config SND_S3C_SOC_PCM 32config SND_S3C_SOC_PCM
28 tristate 33 tristate
29 34
@@ -59,12 +64,11 @@ config SND_S3C24XX_SOC_JIVE_WM8750
59 64
60config SND_S3C64XX_SOC_WM8580 65config SND_S3C64XX_SOC_WM8580
61 tristate "SoC I2S Audio support for WM8580 on SMDK64XX" 66 tristate "SoC I2S Audio support for WM8580 on SMDK64XX"
62 depends on SND_S3C24XX_SOC && (MACH_SMDK6400 || MACH_SMDK6410) 67 depends on SND_S3C24XX_SOC && MACH_SMDK6410
63 depends on BROKEN
64 select SND_SOC_WM8580 68 select SND_SOC_WM8580
65 select SND_S3C64XX_SOC_I2S 69 select SND_S3C64XX_SOC_I2S_V4
66 help 70 help
67 Sat Y if you want to add support for SoC audio on the SMDK64XX. 71 Say Y if you want to add support for SoC audio on the SMDK6410.
68 72
69config SND_S3C24XX_SOC_SMDK2443_WM9710 73config SND_S3C24XX_SOC_SMDK2443_WM9710
70 tristate "SoC AC97 Audio support for SMDK2443 - WM9710" 74 tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index df071a376fa2..81d8dc503f87 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -4,6 +4,7 @@ snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
4snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o 4snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
5snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o 5snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o
6snd-soc-s3c-ac97-objs := s3c-ac97.o 6snd-soc-s3c-ac97-objs := s3c-ac97.o
7snd-soc-s3c64xx-i2s-v4-objs := s3c64xx-i2s-v4.o
7snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o 8snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
8snd-soc-s3c-pcm-objs := s3c-pcm.o 9snd-soc-s3c-pcm-objs := s3c-pcm.o
9 10
@@ -12,6 +13,7 @@ obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
12obj-$(CONFIG_SND_S3C_SOC_AC97) += snd-soc-s3c-ac97.o 13obj-$(CONFIG_SND_S3C_SOC_AC97) += snd-soc-s3c-ac97.o
13obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o 14obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
14obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o 15obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o
16obj-$(CONFIG_SND_S3C64XX_SOC_I2S_V4) += snd-soc-s3c64xx-i2s-v4.o
15obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o 17obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
16obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-s3c-pcm.o 18obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-s3c-pcm.o
17 19
diff --git a/sound/soc/s3c24xx/jive_wm8750.c b/sound/soc/s3c24xx/jive_wm8750.c
index 59dc2c6b56d9..8c108b121c10 100644
--- a/sound/soc/s3c24xx/jive_wm8750.c
+++ b/sound/soc/s3c24xx/jive_wm8750.c
@@ -70,7 +70,7 @@ static int jive_hw_params(struct snd_pcm_substream *substream,
70 } 70 }
71 71
72 s3c_i2sv2_iis_calc_rate(&div, NULL, params_rate(params), 72 s3c_i2sv2_iis_calc_rate(&div, NULL, params_rate(params),
73 s3c2412_get_iisclk()); 73 s3c_i2sv2_get_clock(cpu_dai));
74 74
75 /* set codec DAI configuration */ 75 /* set codec DAI configuration */
76 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | 76 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
@@ -152,15 +152,10 @@ static struct snd_soc_card snd_soc_machine_jive = {
152 .num_links = 1, 152 .num_links = 1,
153}; 153};
154 154
155/* jive audio private data */
156static struct wm8750_setup_data jive_wm8750_setup = {
157};
158
159/* jive audio subsystem */ 155/* jive audio subsystem */
160static struct snd_soc_device jive_snd_devdata = { 156static struct snd_soc_device jive_snd_devdata = {
161 .card = &snd_soc_machine_jive, 157 .card = &snd_soc_machine_jive,
162 .codec_dev = &soc_codec_dev_wm8750, 158 .codec_dev = &soc_codec_dev_wm8750,
163 .codec_data = &jive_wm8750_setup,
164}; 159};
165 160
166static struct platform_device *jive_snd_device; 161static struct platform_device *jive_snd_device;
diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
index dea83d30a5c9..209c25994c7e 100644
--- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
@@ -362,6 +362,14 @@ static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec)
362 snd_soc_dapm_disable_pin(codec, "Handset Mic"); 362 snd_soc_dapm_disable_pin(codec, "Handset Mic");
363 snd_soc_dapm_disable_pin(codec, "Handset Spk"); 363 snd_soc_dapm_disable_pin(codec, "Handset Spk");
364 364
365 /* allow audio paths from the GSM modem to run during suspend */
366 snd_soc_dapm_ignore_suspend(codec, "Stereo Out");
367 snd_soc_dapm_ignore_suspend(codec, "GSM Line Out");
368 snd_soc_dapm_ignore_suspend(codec, "GSM Line In");
369 snd_soc_dapm_ignore_suspend(codec, "Headset Mic");
370 snd_soc_dapm_ignore_suspend(codec, "Handset Mic");
371 snd_soc_dapm_ignore_suspend(codec, "Handset Spk");
372
365 snd_soc_dapm_sync(codec); 373 snd_soc_dapm_sync(codec);
366 374
367 return 0; 375 return 0;
diff --git a/sound/soc/s3c24xx/regs-i2s-v2.h b/sound/soc/s3c24xx/regs-i2s-v2.h
new file mode 100644
index 000000000000..5e5e5680580b
--- /dev/null
+++ b/sound/soc/s3c24xx/regs-i2s-v2.h
@@ -0,0 +1,115 @@
1/* linux/include/asm-arm/plat-s3c24xx/regs-s3c2412-iis.h
2 *
3 * Copyright 2007 Simtec Electronics <linux@simtec.co.uk>
4 * http://armlinux.simtec.co.uk/
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * S3C2412 IIS register definition
11*/
12
13#ifndef __ASM_ARCH_REGS_S3C2412_IIS_H
14#define __ASM_ARCH_REGS_S3C2412_IIS_H
15
16#define S3C2412_IISCON (0x00)
17#define S3C2412_IISMOD (0x04)
18#define S3C2412_IISFIC (0x08)
19#define S3C2412_IISPSR (0x0C)
20#define S3C2412_IISTXD (0x10)
21#define S3C2412_IISRXD (0x14)
22
23#define S5PC1XX_IISFICS 0x18
24#define S5PC1XX_IISTXDS 0x1C
25
26#define S5PC1XX_IISCON_SW_RST (1 << 31)
27#define S5PC1XX_IISCON_FRXOFSTATUS (1 << 26)
28#define S5PC1XX_IISCON_FRXORINTEN (1 << 25)
29#define S5PC1XX_IISCON_FTXSURSTAT (1 << 24)
30#define S5PC1XX_IISCON_FTXSURINTEN (1 << 23)
31#define S5PC1XX_IISCON_TXSDMAPAUSE (1 << 20)
32#define S5PC1XX_IISCON_TXSDMACTIVE (1 << 18)
33
34#define S3C64XX_IISCON_FTXURSTATUS (1 << 17)
35#define S3C64XX_IISCON_FTXURINTEN (1 << 16)
36#define S3C64XX_IISCON_TXFIFO2_EMPTY (1 << 15)
37#define S3C64XX_IISCON_TXFIFO1_EMPTY (1 << 14)
38#define S3C64XX_IISCON_TXFIFO2_FULL (1 << 13)
39#define S3C64XX_IISCON_TXFIFO1_FULL (1 << 12)
40
41#define S3C2412_IISCON_LRINDEX (1 << 11)
42#define S3C2412_IISCON_TXFIFO_EMPTY (1 << 10)
43#define S3C2412_IISCON_RXFIFO_EMPTY (1 << 9)
44#define S3C2412_IISCON_TXFIFO_FULL (1 << 8)
45#define S3C2412_IISCON_RXFIFO_FULL (1 << 7)
46#define S3C2412_IISCON_TXDMA_PAUSE (1 << 6)
47#define S3C2412_IISCON_RXDMA_PAUSE (1 << 5)
48#define S3C2412_IISCON_TXCH_PAUSE (1 << 4)
49#define S3C2412_IISCON_RXCH_PAUSE (1 << 3)
50#define S3C2412_IISCON_TXDMA_ACTIVE (1 << 2)
51#define S3C2412_IISCON_RXDMA_ACTIVE (1 << 1)
52#define S3C2412_IISCON_IIS_ACTIVE (1 << 0)
53
54#define S5PC1XX_IISMOD_OPCLK_CDCLK_OUT (0 << 30)
55#define S5PC1XX_IISMOD_OPCLK_CDCLK_IN (1 << 30)
56#define S5PC1XX_IISMOD_OPCLK_BCLK_OUT (2 << 30)
57#define S5PC1XX_IISMOD_OPCLK_PCLK (3 << 30)
58#define S5PC1XX_IISMOD_OPCLK_MASK (3 << 30)
59#define S5PC1XX_IISMOD_TXS_IDMA (1 << 28) /* Sec_TXFIFO use I-DMA */
60#define S5PC1XX_IISMOD_BLCS_MASK 0x3
61#define S5PC1XX_IISMOD_BLCS_SHIFT 26
62#define S5PC1XX_IISMOD_BLCP_MASK 0x3
63#define S5PC1XX_IISMOD_BLCP_SHIFT 24
64
65#define S3C64XX_IISMOD_C2DD_HHALF (1 << 21) /* Discard Higher-half */
66#define S3C64XX_IISMOD_C2DD_LHALF (1 << 20) /* Discard Lower-half */
67#define S3C64XX_IISMOD_C1DD_HHALF (1 << 19)
68#define S3C64XX_IISMOD_C1DD_LHALF (1 << 18)
69#define S3C64XX_IISMOD_DC2_EN (1 << 17)
70#define S3C64XX_IISMOD_DC1_EN (1 << 16)
71#define S3C64XX_IISMOD_BLC_16BIT (0 << 13)
72#define S3C64XX_IISMOD_BLC_8BIT (1 << 13)
73#define S3C64XX_IISMOD_BLC_24BIT (2 << 13)
74#define S3C64XX_IISMOD_BLC_MASK (3 << 13)
75
76#define S3C2412_IISMOD_IMS_SYSMUX (1 << 10)
77#define S3C2412_IISMOD_SLAVE (1 << 11)
78#define S3C2412_IISMOD_MODE_TXONLY (0 << 8)
79#define S3C2412_IISMOD_MODE_RXONLY (1 << 8)
80#define S3C2412_IISMOD_MODE_TXRX (2 << 8)
81#define S3C2412_IISMOD_MODE_MASK (3 << 8)
82#define S3C2412_IISMOD_LR_LLOW (0 << 7)
83#define S3C2412_IISMOD_LR_RLOW (1 << 7)
84#define S3C2412_IISMOD_SDF_IIS (0 << 5)
85#define S3C2412_IISMOD_SDF_MSB (1 << 5)
86#define S3C2412_IISMOD_SDF_LSB (2 << 5)
87#define S3C2412_IISMOD_SDF_MASK (3 << 5)
88#define S3C2412_IISMOD_RCLK_256FS (0 << 3)
89#define S3C2412_IISMOD_RCLK_512FS (1 << 3)
90#define S3C2412_IISMOD_RCLK_384FS (2 << 3)
91#define S3C2412_IISMOD_RCLK_768FS (3 << 3)
92#define S3C2412_IISMOD_RCLK_MASK (3 << 3)
93#define S3C2412_IISMOD_BCLK_32FS (0 << 1)
94#define S3C2412_IISMOD_BCLK_48FS (1 << 1)
95#define S3C2412_IISMOD_BCLK_16FS (2 << 1)
96#define S3C2412_IISMOD_BCLK_24FS (3 << 1)
97#define S3C2412_IISMOD_BCLK_MASK (3 << 1)
98#define S3C2412_IISMOD_8BIT (1 << 0)
99
100#define S3C64XX_IISMOD_CDCLKCON (1 << 12)
101
102#define S3C2412_IISPSR_PSREN (1 << 15)
103
104#define S3C64XX_IISFIC_TX2COUNT(x) (((x) >> 24) & 0xf)
105#define S3C64XX_IISFIC_TX1COUNT(x) (((x) >> 16) & 0xf)
106
107#define S3C2412_IISFIC_TXFLUSH (1 << 15)
108#define S3C2412_IISFIC_RXFLUSH (1 << 7)
109#define S3C2412_IISFIC_TXCOUNT(x) (((x) >> 8) & 0xf)
110#define S3C2412_IISFIC_RXCOUNT(x) (((x) >> 0) & 0xf)
111
112#define S5PC1XX_IISFICS_TXFLUSH (1 << 15)
113#define S5PC1XX_IISFICS_TXCOUNT(x) (((x) >> 8) & 0x7f)
114
115#endif /* __ASM_ARCH_REGS_S3C2412_IIS_H */
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c
index 88515946b6c0..13311c8cf965 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.c
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.c
@@ -16,24 +16,17 @@
16 * option) any later version. 16 * option) any later version.
17 */ 17 */
18 18
19#include <linux/init.h>
20#include <linux/module.h>
21#include <linux/device.h>
22#include <linux/delay.h> 19#include <linux/delay.h>
23#include <linux/clk.h> 20#include <linux/clk.h>
24#include <linux/kernel.h>
25#include <linux/io.h> 21#include <linux/io.h>
26 22
27#include <sound/core.h>
28#include <sound/pcm.h> 23#include <sound/pcm.h>
29#include <sound/pcm_params.h> 24#include <sound/pcm_params.h>
30#include <sound/initval.h>
31#include <sound/soc.h> 25#include <sound/soc.h>
32 26
33#include <plat/regs-s3c2412-iis.h>
34
35#include <mach/dma.h> 27#include <mach/dma.h>
36 28
29#include "regs-i2s-v2.h"
37#include "s3c-i2s-v2.h" 30#include "s3c-i2s-v2.h"
38#include "s3c-dma.h" 31#include "s3c-dma.h"
39 32
@@ -272,35 +265,14 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
272 iismod = readl(i2s->regs + S3C2412_IISMOD); 265 iismod = readl(i2s->regs + S3C2412_IISMOD);
273 pr_debug("hw_params r: IISMOD: %x \n", iismod); 266 pr_debug("hw_params r: IISMOD: %x \n", iismod);
274 267
275#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
276#define IISMOD_MASTER_MASK S3C2412_IISMOD_MASTER_MASK
277#define IISMOD_SLAVE S3C2412_IISMOD_SLAVE
278#define IISMOD_MASTER S3C2412_IISMOD_MASTER_INTERNAL
279#endif
280
281#if defined(CONFIG_PLAT_S3C64XX)
282/* From Rev1.1 datasheet, we have two master and two slave modes:
283 * IMS[11:10]:
284 * 00 = master mode, fed from PCLK
285 * 01 = master mode, fed from CLKAUDIO
286 * 10 = slave mode, using PCLK
287 * 11 = slave mode, using I2SCLK
288 */
289#define IISMOD_MASTER_MASK (1 << 11)
290#define IISMOD_SLAVE (1 << 11)
291#define IISMOD_MASTER (0 << 11)
292#endif
293
294 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 268 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
295 case SND_SOC_DAIFMT_CBM_CFM: 269 case SND_SOC_DAIFMT_CBM_CFM:
296 i2s->master = 0; 270 i2s->master = 0;
297 iismod &= ~IISMOD_MASTER_MASK; 271 iismod |= S3C2412_IISMOD_SLAVE;
298 iismod |= IISMOD_SLAVE;
299 break; 272 break;
300 case SND_SOC_DAIFMT_CBS_CFS: 273 case SND_SOC_DAIFMT_CBS_CFS:
301 i2s->master = 1; 274 i2s->master = 1;
302 iismod &= ~IISMOD_MASTER_MASK; 275 iismod &= ~S3C2412_IISMOD_SLAVE;
303 iismod |= IISMOD_MASTER;
304 break; 276 break;
305 default: 277 default:
306 pr_err("unknwon master/slave format\n"); 278 pr_err("unknwon master/slave format\n");
@@ -332,7 +304,7 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
332 return 0; 304 return 0;
333} 305}
334 306
335static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, 307static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
336 struct snd_pcm_hw_params *params, 308 struct snd_pcm_hw_params *params,
337 struct snd_soc_dai *socdai) 309 struct snd_soc_dai *socdai)
338{ 310{
@@ -355,37 +327,67 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
355 iismod = readl(i2s->regs + S3C2412_IISMOD); 327 iismod = readl(i2s->regs + S3C2412_IISMOD);
356 pr_debug("%s: r: IISMOD: %x\n", __func__, iismod); 328 pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
357 329
358#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) 330 iismod &= ~S3C64XX_IISMOD_BLC_MASK;
331 /* Sample size */
359 switch (params_format(params)) { 332 switch (params_format(params)) {
360 case SNDRV_PCM_FORMAT_S8: 333 case SNDRV_PCM_FORMAT_S8:
361 iismod |= S3C2412_IISMOD_8BIT; 334 iismod |= S3C64XX_IISMOD_BLC_8BIT;
362 break; 335 break;
363 case SNDRV_PCM_FORMAT_S16_LE: 336 case SNDRV_PCM_FORMAT_S16_LE:
364 iismod &= ~S3C2412_IISMOD_8BIT; 337 break;
338 case SNDRV_PCM_FORMAT_S24_LE:
339 iismod |= S3C64XX_IISMOD_BLC_24BIT;
365 break; 340 break;
366 } 341 }
367#endif
368 342
369#ifdef CONFIG_PLAT_S3C64XX 343 writel(iismod, i2s->regs + S3C2412_IISMOD);
370 iismod &= ~(S3C64XX_IISMOD_BLC_MASK | S3C2412_IISMOD_BCLK_MASK); 344 pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
371 /* Sample size */ 345
372 switch (params_format(params)) { 346 return 0;
373 case SNDRV_PCM_FORMAT_S8: 347}
374 /* 8 bit sample, 16fs BCLK */ 348
375 iismod |= (S3C64XX_IISMOD_BLC_8BIT | S3C2412_IISMOD_BCLK_16FS); 349static int s3c_i2sv2_set_sysclk(struct snd_soc_dai *cpu_dai,
350 int clk_id, unsigned int freq, int dir)
351{
352 struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
353 u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
354
355 pr_debug("Entered %s\n", __func__);
356 pr_debug("%s r: IISMOD: %x\n", __func__, iismod);
357
358 switch (clk_id) {
359 case S3C_I2SV2_CLKSRC_PCLK:
360 iismod &= ~S3C2412_IISMOD_IMS_SYSMUX;
376 break; 361 break;
377 case SNDRV_PCM_FORMAT_S16_LE: 362
378 /* 16 bit sample, 32fs BCLK */ 363 case S3C_I2SV2_CLKSRC_AUDIOBUS:
364 iismod |= S3C2412_IISMOD_IMS_SYSMUX;
379 break; 365 break;
380 case SNDRV_PCM_FORMAT_S24_LE: 366
381 /* 24 bit sample, 48fs BCLK */ 367 case S3C_I2SV2_CLKSRC_CDCLK:
382 iismod |= (S3C64XX_IISMOD_BLC_24BIT | S3C2412_IISMOD_BCLK_48FS); 368 /* Error if controller doesn't have the CDCLKCON bit */
369 if (!(i2s->feature & S3C_FEATURE_CDCLKCON))
370 return -EINVAL;
371
372 switch (dir) {
373 case SND_SOC_CLOCK_IN:
374 iismod |= S3C64XX_IISMOD_CDCLKCON;
375 break;
376 case SND_SOC_CLOCK_OUT:
377 iismod &= ~S3C64XX_IISMOD_CDCLKCON;
378 break;
379 default:
380 return -EINVAL;
381 }
383 break; 382 break;
383
384 default:
385 return -EINVAL;
384 } 386 }
385#endif
386 387
387 writel(iismod, i2s->regs + S3C2412_IISMOD); 388 writel(iismod, i2s->regs + S3C2412_IISMOD);
388 pr_debug("%s: w: IISMOD: %x\n", __func__, iismod); 389 pr_debug("%s w: IISMOD: %x\n", __func__, iismod);
390
389 return 0; 391 return 0;
390} 392}
391 393
@@ -472,29 +474,25 @@ static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
472 474
473 switch (div_id) { 475 switch (div_id) {
474 case S3C_I2SV2_DIV_BCLK: 476 case S3C_I2SV2_DIV_BCLK:
475 if (div > 3) { 477 switch (div) {
476 /* convert value to bit field */ 478 case 16:
477 479 div = S3C2412_IISMOD_BCLK_16FS;
478 switch (div) { 480 break;
479 case 16:
480 div = S3C2412_IISMOD_BCLK_16FS;
481 break;
482 481
483 case 32: 482 case 32:
484 div = S3C2412_IISMOD_BCLK_32FS; 483 div = S3C2412_IISMOD_BCLK_32FS;
485 break; 484 break;
486 485
487 case 24: 486 case 24:
488 div = S3C2412_IISMOD_BCLK_24FS; 487 div = S3C2412_IISMOD_BCLK_24FS;
489 break; 488 break;
490 489
491 case 48: 490 case 48:
492 div = S3C2412_IISMOD_BCLK_48FS; 491 div = S3C2412_IISMOD_BCLK_48FS;
493 break; 492 break;
494 493
495 default: 494 default:
496 return -EINVAL; 495 return -EINVAL;
497 }
498 } 496 }
499 497
500 reg = readl(i2s->regs + S3C2412_IISMOD); 498 reg = readl(i2s->regs + S3C2412_IISMOD);
@@ -505,29 +503,25 @@ static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
505 break; 503 break;
506 504
507 case S3C_I2SV2_DIV_RCLK: 505 case S3C_I2SV2_DIV_RCLK:
508 if (div > 3) { 506 switch (div) {
509 /* convert value to bit field */ 507 case 256:
510 508 div = S3C2412_IISMOD_RCLK_256FS;
511 switch (div) { 509 break;
512 case 256:
513 div = S3C2412_IISMOD_RCLK_256FS;
514 break;
515 510
516 case 384: 511 case 384:
517 div = S3C2412_IISMOD_RCLK_384FS; 512 div = S3C2412_IISMOD_RCLK_384FS;
518 break; 513 break;
519 514
520 case 512: 515 case 512:
521 div = S3C2412_IISMOD_RCLK_512FS; 516 div = S3C2412_IISMOD_RCLK_512FS;
522 break; 517 break;
523 518
524 case 768: 519 case 768:
525 div = S3C2412_IISMOD_RCLK_768FS; 520 div = S3C2412_IISMOD_RCLK_768FS;
526 break; 521 break;
527 522
528 default: 523 default:
529 return -EINVAL; 524 return -EINVAL;
530 }
531 } 525 }
532 526
533 reg = readl(i2s->regs + S3C2412_IISMOD); 527 reg = readl(i2s->regs + S3C2412_IISMOD);
@@ -553,6 +547,33 @@ static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
553 return 0; 547 return 0;
554} 548}
555 549
550static snd_pcm_sframes_t s3c2412_i2s_delay(struct snd_pcm_substream *substream,
551 struct snd_soc_dai *dai)
552{
553 struct s3c_i2sv2_info *i2s = to_info(dai);
554 u32 reg = readl(i2s->regs + S3C2412_IISFIC);
555 snd_pcm_sframes_t delay;
556
557 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
558 delay = S3C2412_IISFIC_TXCOUNT(reg);
559 else
560 delay = S3C2412_IISFIC_RXCOUNT(reg);
561
562 return delay;
563}
564
565struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai)
566{
567 struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
568 u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
569
570 if (iismod & S3C2412_IISMOD_IMS_SYSMUX)
571 return i2s->iis_cclk;
572 else
573 return i2s->iis_pclk;
574}
575EXPORT_SYMBOL_GPL(s3c_i2sv2_get_clock);
576
556/* default table of all avaialable root fs divisors */ 577/* default table of all avaialable root fs divisors */
557static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 }; 578static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 };
558 579
@@ -735,9 +756,15 @@ int s3c_i2sv2_register_dai(struct snd_soc_dai *dai)
735 struct snd_soc_dai_ops *ops = dai->ops; 756 struct snd_soc_dai_ops *ops = dai->ops;
736 757
737 ops->trigger = s3c2412_i2s_trigger; 758 ops->trigger = s3c2412_i2s_trigger;
738 ops->hw_params = s3c2412_i2s_hw_params; 759 if (!ops->hw_params)
760 ops->hw_params = s3c_i2sv2_hw_params;
739 ops->set_fmt = s3c2412_i2s_set_fmt; 761 ops->set_fmt = s3c2412_i2s_set_fmt;
740 ops->set_clkdiv = s3c2412_i2s_set_clkdiv; 762 ops->set_clkdiv = s3c2412_i2s_set_clkdiv;
763 ops->set_sysclk = s3c_i2sv2_set_sysclk;
764
765 /* Allow overriding by (for example) IISv4 */
766 if (!ops->delay)
767 ops->delay = s3c2412_i2s_delay;
741 768
742 dai->suspend = s3c2412_i2s_suspend; 769 dai->suspend = s3c2412_i2s_suspend;
743 dai->resume = s3c2412_i2s_resume; 770 dai->resume = s3c2412_i2s_resume;
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.h b/sound/soc/s3c24xx/s3c-i2s-v2.h
index ecf8eaaed1db..766f43a13d8b 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.h
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.h
@@ -25,10 +25,20 @@
25#define S3C_I2SV2_DIV_RCLK (2) 25#define S3C_I2SV2_DIV_RCLK (2)
26#define S3C_I2SV2_DIV_PRESCALER (3) 26#define S3C_I2SV2_DIV_PRESCALER (3)
27 27
28#define S3C_I2SV2_CLKSRC_PCLK 0
29#define S3C_I2SV2_CLKSRC_AUDIOBUS 1
30#define S3C_I2SV2_CLKSRC_CDCLK 2
31
32/* Set this flag for I2S controllers that have the bit IISMOD[12]
33 * bridge/break RCLK signal and external Xi2sCDCLK pin.
34 */
35#define S3C_FEATURE_CDCLKCON (1 << 0)
36
28/** 37/**
29 * struct s3c_i2sv2_info - S3C I2S-V2 information 38 * struct s3c_i2sv2_info - S3C I2S-V2 information
30 * @dev: The parent device passed to use from the probe. 39 * @dev: The parent device passed to use from the probe.
31 * @regs: The pointer to the device registe block. 40 * @regs: The pointer to the device registe block.
41 * @feature: Set of bit-flags indicating features of the controller.
32 * @master: True if the I2S core is the I2S bit clock master. 42 * @master: True if the I2S core is the I2S bit clock master.
33 * @dma_playback: DMA information for playback channel. 43 * @dma_playback: DMA information for playback channel.
34 * @dma_capture: DMA information for capture channel. 44 * @dma_capture: DMA information for capture channel.
@@ -43,9 +53,10 @@ struct s3c_i2sv2_info {
43 struct device *dev; 53 struct device *dev;
44 void __iomem *regs; 54 void __iomem *regs;
45 55
56 u32 feature;
57
46 struct clk *iis_pclk; 58 struct clk *iis_pclk;
47 struct clk *iis_cclk; 59 struct clk *iis_cclk;
48 struct clk *iis_clk;
49 60
50 unsigned char master; 61 unsigned char master;
51 62
@@ -57,6 +68,8 @@ struct s3c_i2sv2_info {
57 u32 suspend_iispsr; 68 u32 suspend_iispsr;
58}; 69};
59 70
71extern struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai);
72
60struct s3c_i2sv2_rate_calc { 73struct s3c_i2sv2_rate_calc {
61 unsigned int clk_div; /* for prescaler */ 74 unsigned int clk_div; /* for prescaler */
62 unsigned int fs_div; /* for root frame clock */ 75 unsigned int fs_div; /* for root frame clock */
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c
index 359e59346ba2..709adef9d043 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.c
+++ b/sound/soc/s3c24xx/s3c2412-i2s.c
@@ -32,12 +32,11 @@
32#include <sound/soc.h> 32#include <sound/soc.h>
33#include <mach/hardware.h> 33#include <mach/hardware.h>
34 34
35#include <plat/regs-s3c2412-iis.h>
36
37#include <mach/regs-gpio.h> 35#include <mach/regs-gpio.h>
38#include <mach/dma.h> 36#include <mach/dma.h>
39 37
40#include "s3c-dma.h" 38#include "s3c-dma.h"
39#include "regs-i2s-v2.h"
41#include "s3c2412-i2s.h" 40#include "s3c2412-i2s.h"
42 41
43#define S3C2412_I2S_DEBUG 0 42#define S3C2412_I2S_DEBUG 0
@@ -66,44 +65,11 @@ static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = {
66 65
67static struct s3c_i2sv2_info s3c2412_i2s; 66static struct s3c_i2sv2_info s3c2412_i2s;
68 67
69/* 68static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
70 * Set S3C2412 Clock source
71 */
72static int s3c2412_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
73 int clk_id, unsigned int freq, int dir)
74{ 69{
75 u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); 70 return cpu_dai->private_data;
76
77 pr_debug("%s(%p, %d, %u, %d)\n", __func__, cpu_dai, clk_id,
78 freq, dir);
79
80 switch (clk_id) {
81 case S3C2412_CLKSRC_PCLK:
82 s3c2412_i2s.master = 1;
83 iismod &= ~S3C2412_IISMOD_MASTER_MASK;
84 iismod |= S3C2412_IISMOD_MASTER_INTERNAL;
85 break;
86 case S3C2412_CLKSRC_I2SCLK:
87 s3c2412_i2s.master = 0;
88 iismod &= ~S3C2412_IISMOD_MASTER_MASK;
89 iismod |= S3C2412_IISMOD_MASTER_EXTERNAL;
90 break;
91 default:
92 return -EINVAL;
93 }
94
95 writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD);
96 return 0;
97} 71}
98 72
99
100struct clk *s3c2412_get_iisclk(void)
101{
102 return s3c2412_i2s.iis_clk;
103}
104EXPORT_SYMBOL_GPL(s3c2412_get_iisclk);
105
106
107static int s3c2412_i2s_probe(struct platform_device *pdev, 73static int s3c2412_i2s_probe(struct platform_device *pdev,
108 struct snd_soc_dai *dai) 74 struct snd_soc_dai *dai)
109{ 75{
@@ -142,13 +108,48 @@ static int s3c2412_i2s_probe(struct platform_device *pdev,
142 return 0; 108 return 0;
143} 109}
144 110
111static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
112 struct snd_pcm_hw_params *params,
113 struct snd_soc_dai *cpu_dai)
114{
115 struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
116 struct s3c_dma_params *dma_data;
117 u32 iismod;
118
119 pr_debug("Entered %s\n", __func__);
120
121 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
122 dma_data = i2s->dma_playback;
123 else
124 dma_data = i2s->dma_capture;
125
126 snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
127
128 iismod = readl(i2s->regs + S3C2412_IISMOD);
129 pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
130
131 switch (params_format(params)) {
132 case SNDRV_PCM_FORMAT_S8:
133 iismod |= S3C2412_IISMOD_8BIT;
134 break;
135 case SNDRV_PCM_FORMAT_S16_LE:
136 iismod &= ~S3C2412_IISMOD_8BIT;
137 break;
138 }
139
140 writel(iismod, i2s->regs + S3C2412_IISMOD);
141 pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
142
143 return 0;
144}
145
145#define S3C2412_I2S_RATES \ 146#define S3C2412_I2S_RATES \
146 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ 147 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
147 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 148 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
148 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) 149 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
149 150
150static struct snd_soc_dai_ops s3c2412_i2s_dai_ops = { 151static struct snd_soc_dai_ops s3c2412_i2s_dai_ops = {
151 .set_sysclk = s3c2412_i2s_set_sysclk, 152 .hw_params = s3c2412_i2s_hw_params,
152}; 153};
153 154
154struct snd_soc_dai s3c2412_i2s_dai = { 155struct snd_soc_dai s3c2412_i2s_dai = {
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.h b/sound/soc/s3c24xx/s3c2412-i2s.h
index 92848e54be16..0b5686b4d5c3 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.h
+++ b/sound/soc/s3c24xx/s3c2412-i2s.h
@@ -21,10 +21,8 @@
21#define S3C2412_DIV_RCLK S3C_I2SV2_DIV_RCLK 21#define S3C2412_DIV_RCLK S3C_I2SV2_DIV_RCLK
22#define S3C2412_DIV_PRESCALER S3C_I2SV2_DIV_PRESCALER 22#define S3C2412_DIV_PRESCALER S3C_I2SV2_DIV_PRESCALER
23 23
24#define S3C2412_CLKSRC_PCLK (0) 24#define S3C2412_CLKSRC_PCLK S3C_I2SV2_CLKSRC_PCLK
25#define S3C2412_CLKSRC_I2SCLK (1) 25#define S3C2412_CLKSRC_I2SCLK S3C_I2SV2_CLKSRC_AUDIOBUS
26
27extern struct clk *s3c2412_get_iisclk(void);
28 26
29extern struct snd_soc_dai s3c2412_i2s_dai; 27extern struct snd_soc_dai s3c2412_i2s_dai;
30 28
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s-v4.c b/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
new file mode 100644
index 000000000000..06db130030a1
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
@@ -0,0 +1,209 @@
1/* sound/soc/s3c24xx/s3c64xx-i2s-v4.c
2 *
3 * ALSA SoC Audio Layer - S3C64XX I2Sv4 driver
4 * Copyright (c) 2010 Samsung Electronics Co. Ltd
5 * Author: Jaswinder Singh <jassi.brar@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/clk.h>
13#include <linux/gpio.h>
14#include <linux/io.h>
15
16#include <sound/soc.h>
17#include <sound/pcm_params.h>
18
19#include <mach/gpio-bank-c.h>
20#include <mach/gpio-bank-h.h>
21#include <plat/gpio-cfg.h>
22
23#include <mach/map.h>
24#include <mach/dma.h>
25
26#include "s3c-dma.h"
27#include "regs-i2s-v2.h"
28#include "s3c64xx-i2s.h"
29
30static struct s3c2410_dma_client s3c64xx_dma_client_out = {
31 .name = "I2Sv4 PCM Stereo out"
32};
33
34static struct s3c2410_dma_client s3c64xx_dma_client_in = {
35 .name = "I2Sv4 PCM Stereo in"
36};
37
38static struct s3c_dma_params s3c64xx_i2sv4_pcm_stereo_out;
39static struct s3c_dma_params s3c64xx_i2sv4_pcm_stereo_in;
40static struct s3c_i2sv2_info s3c64xx_i2sv4;
41
42struct snd_soc_dai s3c64xx_i2s_v4_dai;
43EXPORT_SYMBOL_GPL(s3c64xx_i2s_v4_dai);
44
45static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
46{
47 return cpu_dai->private_data;
48}
49
50static int s3c64xx_i2sv4_probe(struct platform_device *pdev,
51 struct snd_soc_dai *dai)
52{
53 /* configure GPIO for i2s port */
54 s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C64XX_GPC4_I2S_V40_DO0);
55 s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C64XX_GPC5_I2S_V40_DO1);
56 s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C64XX_GPC7_I2S_V40_DO2);
57 s3c_gpio_cfgpin(S3C64XX_GPH(6), S3C64XX_GPH6_I2S_V40_BCLK);
58 s3c_gpio_cfgpin(S3C64XX_GPH(7), S3C64XX_GPH7_I2S_V40_CDCLK);
59 s3c_gpio_cfgpin(S3C64XX_GPH(8), S3C64XX_GPH8_I2S_V40_LRCLK);
60 s3c_gpio_cfgpin(S3C64XX_GPH(9), S3C64XX_GPH9_I2S_V40_DI);
61
62 return 0;
63}
64
65static int s3c_i2sv4_hw_params(struct snd_pcm_substream *substream,
66 struct snd_pcm_hw_params *params,
67 struct snd_soc_dai *cpu_dai)
68{
69 struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
70 struct s3c_dma_params *dma_data;
71 u32 iismod;
72
73 dev_dbg(cpu_dai->dev, "Entered %s\n", __func__);
74
75 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
76 dma_data = i2s->dma_playback;
77 else
78 dma_data = i2s->dma_capture;
79
80 snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
81
82 iismod = readl(i2s->regs + S3C2412_IISMOD);
83 dev_dbg(cpu_dai->dev, "%s: r: IISMOD: %x\n", __func__, iismod);
84
85 iismod &= ~S3C64XX_IISMOD_BLC_MASK;
86 switch (params_format(params)) {
87 case SNDRV_PCM_FORMAT_S8:
88 iismod |= S3C64XX_IISMOD_BLC_8BIT;
89 break;
90 case SNDRV_PCM_FORMAT_S16_LE:
91 break;
92 case SNDRV_PCM_FORMAT_S24_LE:
93 iismod |= S3C64XX_IISMOD_BLC_24BIT;
94 break;
95 }
96
97 writel(iismod, i2s->regs + S3C2412_IISMOD);
98 dev_dbg(cpu_dai->dev, "%s: w: IISMOD: %x\n", __func__, iismod);
99
100 return 0;
101}
102
103static struct snd_soc_dai_ops s3c64xx_i2sv4_dai_ops = {
104 .hw_params = s3c_i2sv4_hw_params,
105};
106
107static __devinit int s3c64xx_i2sv4_dev_probe(struct platform_device *pdev)
108{
109 struct s3c_i2sv2_info *i2s;
110 struct snd_soc_dai *dai;
111 int ret;
112
113 i2s = &s3c64xx_i2sv4;
114 dai = &s3c64xx_i2s_v4_dai;
115
116 if (dai->dev) {
117 dev_dbg(dai->dev, "%s: \
118 I2Sv4 instance already registered!\n", __func__);
119 return -EBUSY;
120 }
121
122 dai->dev = &pdev->dev;
123 dai->name = "s3c64xx-i2s-v4";
124 dai->id = 0;
125 dai->symmetric_rates = 1;
126 dai->playback.channels_min = 2;
127 dai->playback.channels_max = 2;
128 dai->playback.rates = S3C64XX_I2S_RATES;
129 dai->playback.formats = S3C64XX_I2S_FMTS;
130 dai->capture.channels_min = 2;
131 dai->capture.channels_max = 2;
132 dai->capture.rates = S3C64XX_I2S_RATES;
133 dai->capture.formats = S3C64XX_I2S_FMTS;
134 dai->probe = s3c64xx_i2sv4_probe;
135 dai->ops = &s3c64xx_i2sv4_dai_ops;
136
137 i2s->feature |= S3C_FEATURE_CDCLKCON;
138
139 i2s->dma_capture = &s3c64xx_i2sv4_pcm_stereo_in;
140 i2s->dma_playback = &s3c64xx_i2sv4_pcm_stereo_out;
141
142 i2s->dma_capture->channel = DMACH_HSI_I2SV40_RX;
143 i2s->dma_capture->dma_addr = S3C64XX_PA_IISV4 + S3C2412_IISRXD;
144 i2s->dma_playback->channel = DMACH_HSI_I2SV40_TX;
145 i2s->dma_playback->dma_addr = S3C64XX_PA_IISV4 + S3C2412_IISTXD;
146
147 i2s->dma_capture->client = &s3c64xx_dma_client_in;
148 i2s->dma_capture->dma_size = 4;
149 i2s->dma_playback->client = &s3c64xx_dma_client_out;
150 i2s->dma_playback->dma_size = 4;
151
152 i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus");
153 if (IS_ERR(i2s->iis_cclk)) {
154 dev_err(&pdev->dev, "failed to get audio-bus\n");
155 ret = PTR_ERR(i2s->iis_cclk);
156 goto err;
157 }
158
159 clk_enable(i2s->iis_cclk);
160
161 ret = s3c_i2sv2_probe(pdev, dai, i2s, 0);
162 if (ret)
163 goto err_clk;
164
165 ret = s3c_i2sv2_register_dai(dai);
166 if (ret != 0)
167 goto err_i2sv2;
168
169 return 0;
170
171err_i2sv2:
172 /* Not implemented for I2Sv2 core yet */
173err_clk:
174 clk_put(i2s->iis_cclk);
175err:
176 return ret;
177}
178
179static __devexit int s3c64xx_i2sv4_dev_remove(struct platform_device *pdev)
180{
181 dev_err(&pdev->dev, "Device removal not yet supported\n");
182 return 0;
183}
184
185static struct platform_driver s3c64xx_i2sv4_driver = {
186 .probe = s3c64xx_i2sv4_dev_probe,
187 .remove = s3c64xx_i2sv4_dev_remove,
188 .driver = {
189 .name = "s3c64xx-iis-v4",
190 .owner = THIS_MODULE,
191 },
192};
193
194static int __init s3c64xx_i2sv4_init(void)
195{
196 return platform_driver_register(&s3c64xx_i2sv4_driver);
197}
198module_init(s3c64xx_i2sv4_init);
199
200static void __exit s3c64xx_i2sv4_exit(void)
201{
202 platform_driver_unregister(&s3c64xx_i2sv4_driver);
203}
204module_exit(s3c64xx_i2sv4_exit);
205
206/* Module information */
207MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
208MODULE_DESCRIPTION("S3C64XX I2Sv4 SoC Interface");
209MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c
index a72c251401ac..1d85cb85a7d2 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.c
@@ -12,16 +12,12 @@
12 * published by the Free Software Foundation. 12 * published by the Free Software Foundation.
13 */ 13 */
14 14
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/device.h>
18#include <linux/clk.h> 15#include <linux/clk.h>
19#include <linux/gpio.h> 16#include <linux/gpio.h>
20#include <linux/io.h> 17#include <linux/io.h>
21 18
22#include <sound/soc.h> 19#include <sound/soc.h>
23 20
24#include <plat/regs-s3c2412-iis.h>
25#include <mach/gpio-bank-d.h> 21#include <mach/gpio-bank-d.h>
26#include <mach/gpio-bank-e.h> 22#include <mach/gpio-bank-e.h>
27#include <plat/gpio-cfg.h> 23#include <plat/gpio-cfg.h>
@@ -30,6 +26,7 @@
30#include <mach/dma.h> 26#include <mach/dma.h>
31 27
32#include "s3c-dma.h" 28#include "s3c-dma.h"
29#include "regs-i2s-v2.h"
33#include "s3c64xx-i2s.h" 30#include "s3c64xx-i2s.h"
34 31
35/* The value should be set to maximum of the total number 32/* The value should be set to maximum of the total number
@@ -57,55 +54,6 @@ static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
57 return cpu_dai->private_data; 54 return cpu_dai->private_data;
58} 55}
59 56
60static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
61 int clk_id, unsigned int freq, int dir)
62{
63 struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
64 u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
65
66 switch (clk_id) {
67 case S3C64XX_CLKSRC_PCLK:
68 iismod &= ~S3C64XX_IISMOD_IMS_SYSMUX;
69 break;
70
71 case S3C64XX_CLKSRC_MUX:
72 iismod |= S3C64XX_IISMOD_IMS_SYSMUX;
73 break;
74
75 case S3C64XX_CLKSRC_CDCLK:
76 switch (dir) {
77 case SND_SOC_CLOCK_IN:
78 iismod |= S3C64XX_IISMOD_CDCLKCON;
79 break;
80 case SND_SOC_CLOCK_OUT:
81 iismod &= ~S3C64XX_IISMOD_CDCLKCON;
82 break;
83 default:
84 return -EINVAL;
85 }
86 break;
87
88 default:
89 return -EINVAL;
90 }
91
92 writel(iismod, i2s->regs + S3C2412_IISMOD);
93
94 return 0;
95}
96
97struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai)
98{
99 struct s3c_i2sv2_info *i2s = to_info(dai);
100 u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
101
102 if (iismod & S3C64XX_IISMOD_IMS_SYSMUX)
103 return i2s->iis_cclk;
104 else
105 return i2s->iis_pclk;
106}
107EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock);
108
109static int s3c64xx_i2s_probe(struct platform_device *pdev, 57static int s3c64xx_i2s_probe(struct platform_device *pdev,
110 struct snd_soc_dai *dai) 58 struct snd_soc_dai *dai)
111{ 59{
@@ -130,18 +78,7 @@ static int s3c64xx_i2s_probe(struct platform_device *pdev,
130} 78}
131 79
132 80
133#define S3C64XX_I2S_RATES \ 81static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops;
134 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
135 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
136 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
137
138#define S3C64XX_I2S_FMTS \
139 (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
140 SNDRV_PCM_FMTBIT_S24_LE)
141
142static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops = {
143 .set_sysclk = s3c64xx_i2s_set_sysclk,
144};
145 82
146static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev) 83static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
147{ 84{
@@ -171,6 +108,8 @@ static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
171 dai->probe = s3c64xx_i2s_probe; 108 dai->probe = s3c64xx_i2s_probe;
172 dai->ops = &s3c64xx_i2s_dai_ops; 109 dai->ops = &s3c64xx_i2s_dai_ops;
173 110
111 i2s->feature |= S3C_FEATURE_CDCLKCON;
112
174 i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id]; 113 i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id];
175 i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id]; 114 i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id];
176 115
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h
index abe7253b55fc..7a40f43d1d51 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.h
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.h
@@ -23,12 +23,20 @@ struct clk;
23#define S3C64XX_DIV_RCLK S3C_I2SV2_DIV_RCLK 23#define S3C64XX_DIV_RCLK S3C_I2SV2_DIV_RCLK
24#define S3C64XX_DIV_PRESCALER S3C_I2SV2_DIV_PRESCALER 24#define S3C64XX_DIV_PRESCALER S3C_I2SV2_DIV_PRESCALER
25 25
26#define S3C64XX_CLKSRC_PCLK (0) 26#define S3C64XX_CLKSRC_PCLK S3C_I2SV2_CLKSRC_PCLK
27#define S3C64XX_CLKSRC_MUX (1) 27#define S3C64XX_CLKSRC_MUX S3C_I2SV2_CLKSRC_AUDIOBUS
28#define S3C64XX_CLKSRC_CDCLK (2) 28#define S3C64XX_CLKSRC_CDCLK S3C_I2SV2_CLKSRC_CDCLK
29 29
30extern struct snd_soc_dai s3c64xx_i2s_dai[]; 30#define S3C64XX_I2S_RATES \
31 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
32 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
33 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
34
35#define S3C64XX_I2S_FMTS \
36 (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
37 SNDRV_PCM_FMTBIT_S24_LE)
31 38
32extern struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai); 39extern struct snd_soc_dai s3c64xx_i2s_dai[];
40extern struct snd_soc_dai s3c64xx_i2s_v4_dai;
33 41
34#endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */ 42#endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */
diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c
index efe4901213a3..07e8e51d10d6 100644
--- a/sound/soc/s3c24xx/smdk64xx_wm8580.c
+++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c
@@ -22,8 +22,6 @@
22#include "s3c-dma.h" 22#include "s3c-dma.h"
23#include "s3c64xx-i2s.h" 23#include "s3c64xx-i2s.h"
24 24
25#define S3C64XX_I2S_V4 2
26
27/* SMDK64XX has a 12MHZ crystal attached to WM8580 */ 25/* SMDK64XX has a 12MHZ crystal attached to WM8580 */
28#define SMDK64XX_WM8580_FREQ 12000000 26#define SMDK64XX_WM8580_FREQ 12000000
29 27
@@ -215,7 +213,7 @@ static struct snd_soc_dai_link smdk64xx_dai[] = {
215{ /* Primary Playback i/f */ 213{ /* Primary Playback i/f */
216 .name = "WM8580 PAIF RX", 214 .name = "WM8580 PAIF RX",
217 .stream_name = "Playback", 215 .stream_name = "Playback",
218 .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4], 216 .cpu_dai = &s3c64xx_i2s_v4_dai,
219 .codec_dai = &wm8580_dai[WM8580_DAI_PAIFRX], 217 .codec_dai = &wm8580_dai[WM8580_DAI_PAIFRX],
220 .init = smdk64xx_wm8580_init_paifrx, 218 .init = smdk64xx_wm8580_init_paifrx,
221 .ops = &smdk64xx_ops, 219 .ops = &smdk64xx_ops,
@@ -223,7 +221,7 @@ static struct snd_soc_dai_link smdk64xx_dai[] = {
223{ /* Primary Capture i/f */ 221{ /* Primary Capture i/f */
224 .name = "WM8580 PAIF TX", 222 .name = "WM8580 PAIF TX",
225 .stream_name = "Capture", 223 .stream_name = "Capture",
226 .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4], 224 .cpu_dai = &s3c64xx_i2s_v4_dai,
227 .codec_dai = &wm8580_dai[WM8580_DAI_PAIFTX], 225 .codec_dai = &wm8580_dai[WM8580_DAI_PAIFTX],
228 .init = smdk64xx_wm8580_init_paiftx, 226 .init = smdk64xx_wm8580_init_paiftx,
229 .ops = &smdk64xx_ops, 227 .ops = &smdk64xx_ops,