aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorJassi Brar <jassi.brar@samsung.com>2009-11-17 02:54:03 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-11-18 08:35:05 -0500
commit357a1db94ecc5b3d605574b164d288cd7dbf8dbd (patch)
treed0a9e691c963dc42c1ca95035633350b14bc29a0 /sound/soc
parentacf1aef9ecb289f7ed42b25ed55463b2cbb48ce2 (diff)
ASoC: Added the CPU driver for PCM controllers
Signed-off-by: Jassi Brar <jassi.brar@samsung.com> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/s3c24xx/Kconfig3
-rw-r--r--sound/soc/s3c24xx/Makefile2
-rw-r--r--sound/soc/s3c24xx/s3c-pcm.c552
-rw-r--r--sound/soc/s3c24xx/s3c-pcm.h123
4 files changed, 680 insertions, 0 deletions
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index d7912f1e4627..b489f1ae103d 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -24,6 +24,9 @@ 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_S3C_SOC_PCM
28 tristate
29
27config SND_S3C2443_SOC_AC97 30config SND_S3C2443_SOC_AC97
28 tristate 31 tristate
29 select S3C2410_DMA 32 select S3C2410_DMA
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index ff0a10536efc..b744657733d7 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -5,6 +5,7 @@ snd-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-s3c2443-ac97-objs := s3c2443-ac97.o 6snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o
7snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o 7snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
8snd-soc-s3c-pcm-objs := s3c-pcm.o
8 9
9obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o 10obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
10obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o 11obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
@@ -12,6 +13,7 @@ obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o
12obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o 13obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
13obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o 14obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o
14obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o 15obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
16obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-s3c-pcm.o
15 17
16# S3C24XX Machine Support 18# S3C24XX Machine Support
17snd-soc-jive-wm8750-objs := jive_wm8750.o 19snd-soc-jive-wm8750-objs := jive_wm8750.o
diff --git a/sound/soc/s3c24xx/s3c-pcm.c b/sound/soc/s3c24xx/s3c-pcm.c
new file mode 100644
index 000000000000..9e61a7c2d9ac
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c-pcm.c
@@ -0,0 +1,552 @@
1/* sound/soc/s3c24xx/s3c-pcm.c
2 *
3 * ALSA SoC Audio Layer - S3C PCM-Controller driver
4 *
5 * Copyright (c) 2009 Samsung Electronics Co. Ltd
6 * Author: Jaswinder Singh <jassi.brar@samsung.com>
7 * based upon I2S drivers by Ben Dooks.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/init.h>
15#include <linux/module.h>
16#include <linux/device.h>
17#include <linux/delay.h>
18#include <linux/clk.h>
19#include <linux/kernel.h>
20#include <linux/gpio.h>
21#include <linux/io.h>
22
23#include <sound/core.h>
24#include <sound/pcm.h>
25#include <sound/pcm_params.h>
26#include <sound/initval.h>
27#include <sound/soc.h>
28
29#include <plat/audio.h>
30#include <plat/dma.h>
31
32#include "s3c-dma.h"
33#include "s3c-pcm.h"
34
35static struct s3c2410_dma_client s3c_pcm_dma_client_out = {
36 .name = "PCM Stereo out"
37};
38
39static struct s3c2410_dma_client s3c_pcm_dma_client_in = {
40 .name = "PCM Stereo in"
41};
42
43static struct s3c_dma_params s3c_pcm_stereo_out[] = {
44 [0] = {
45 .client = &s3c_pcm_dma_client_out,
46 .dma_size = 4,
47 },
48 [1] = {
49 .client = &s3c_pcm_dma_client_out,
50 .dma_size = 4,
51 },
52};
53
54static struct s3c_dma_params s3c_pcm_stereo_in[] = {
55 [0] = {
56 .client = &s3c_pcm_dma_client_in,
57 .dma_size = 4,
58 },
59 [1] = {
60 .client = &s3c_pcm_dma_client_in,
61 .dma_size = 4,
62 },
63};
64
65static struct s3c_pcm_info s3c_pcm[2];
66
67static inline struct s3c_pcm_info *to_info(struct snd_soc_dai *cpu_dai)
68{
69 return cpu_dai->private_data;
70}
71
72static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
73{
74 void __iomem *regs = pcm->regs;
75 u32 ctl, clkctl;
76
77 clkctl = readl(regs + S3C_PCM_CLKCTL);
78 ctl = readl(regs + S3C_PCM_CTL);
79 ctl &= ~(S3C_PCM_CTL_TXDIPSTICK_MASK
80 << S3C_PCM_CTL_TXDIPSTICK_SHIFT);
81
82 if (on) {
83 ctl |= S3C_PCM_CTL_TXDMA_EN;
84 ctl |= S3C_PCM_CTL_TXFIFO_EN;
85 ctl |= S3C_PCM_CTL_ENABLE;
86 ctl |= (0x20<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
87 clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
88 } else {
89 ctl &= ~S3C_PCM_CTL_TXDMA_EN;
90 ctl &= ~S3C_PCM_CTL_TXFIFO_EN;
91
92 if (!(ctl & S3C_PCM_CTL_RXFIFO_EN)) {
93 ctl &= ~S3C_PCM_CTL_ENABLE;
94 if (!pcm->idleclk)
95 clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
96 }
97 }
98
99 writel(clkctl, regs + S3C_PCM_CLKCTL);
100 writel(ctl, regs + S3C_PCM_CTL);
101}
102
103static void s3c_pcm_snd_rxctrl(struct s3c_pcm_info *pcm, int on)
104{
105 void __iomem *regs = pcm->regs;
106 u32 ctl, clkctl;
107
108 ctl = readl(regs + S3C_PCM_CTL);
109 clkctl = readl(regs + S3C_PCM_CLKCTL);
110
111 if (on) {
112 ctl |= S3C_PCM_CTL_RXDMA_EN;
113 ctl |= S3C_PCM_CTL_RXFIFO_EN;
114 ctl |= S3C_PCM_CTL_ENABLE;
115 clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
116 } else {
117 ctl &= ~S3C_PCM_CTL_RXDMA_EN;
118 ctl &= ~S3C_PCM_CTL_RXFIFO_EN;
119
120 if (!(ctl & S3C_PCM_CTL_TXFIFO_EN)) {
121 ctl &= ~S3C_PCM_CTL_ENABLE;
122 if (!pcm->idleclk)
123 clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
124 }
125 }
126
127 writel(clkctl, regs + S3C_PCM_CLKCTL);
128 writel(ctl, regs + S3C_PCM_CTL);
129}
130
131static int s3c_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
132 struct snd_soc_dai *dai)
133{
134 struct snd_soc_pcm_runtime *rtd = substream->private_data;
135 struct s3c_pcm_info *pcm = to_info(rtd->dai->cpu_dai);
136 unsigned long flags;
137
138 dev_dbg(pcm->dev, "Entered %s\n", __func__);
139
140 switch (cmd) {
141 case SNDRV_PCM_TRIGGER_START:
142 case SNDRV_PCM_TRIGGER_RESUME:
143 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
144 spin_lock_irqsave(&pcm->lock, flags);
145
146 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
147 s3c_pcm_snd_rxctrl(pcm, 1);
148 else
149 s3c_pcm_snd_txctrl(pcm, 1);
150
151 spin_unlock_irqrestore(&pcm->lock, flags);
152 break;
153
154 case SNDRV_PCM_TRIGGER_STOP:
155 case SNDRV_PCM_TRIGGER_SUSPEND:
156 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
157 spin_lock_irqsave(&pcm->lock, flags);
158
159 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
160 s3c_pcm_snd_rxctrl(pcm, 0);
161 else
162 s3c_pcm_snd_txctrl(pcm, 0);
163
164 spin_unlock_irqrestore(&pcm->lock, flags);
165 break;
166
167 default:
168 return -EINVAL;
169 }
170
171 return 0;
172}
173
174static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
175 struct snd_pcm_hw_params *params,
176 struct snd_soc_dai *socdai)
177{
178 struct snd_soc_pcm_runtime *rtd = substream->private_data;
179 struct snd_soc_dai_link *dai = rtd->dai;
180 struct s3c_pcm_info *pcm = to_info(dai->cpu_dai);
181 void __iomem *regs = pcm->regs;
182 struct clk *clk;
183 int sclk_div, sync_div;
184 unsigned long flags;
185 u32 clkctl;
186
187 dev_dbg(pcm->dev, "Entered %s\n", __func__);
188
189 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
190 dai->cpu_dai->dma_data = pcm->dma_playback;
191 else
192 dai->cpu_dai->dma_data = pcm->dma_capture;
193
194 /* Strictly check for sample size */
195 switch (params_format(params)) {
196 case SNDRV_PCM_FORMAT_S16_LE:
197 break;
198 default:
199 return -EINVAL;
200 }
201
202 spin_lock_irqsave(&pcm->lock, flags);
203
204 /* Get hold of the PCMSOURCE_CLK */
205 clkctl = readl(regs + S3C_PCM_CLKCTL);
206 if (clkctl & S3C_PCM_CLKCTL_SERCLKSEL_PCLK)
207 clk = pcm->pclk;
208 else
209 clk = pcm->cclk;
210
211 /* Set the SCLK divider */
212 sclk_div = clk_get_rate(clk) / pcm->sclk_per_fs /
213 params_rate(params) / 2 - 1;
214
215 clkctl &= ~(S3C_PCM_CLKCTL_SCLKDIV_MASK
216 << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
217 clkctl |= ((sclk_div & S3C_PCM_CLKCTL_SCLKDIV_MASK)
218 << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
219
220 /* Set the SYNC divider */
221 sync_div = pcm->sclk_per_fs - 1;
222
223 clkctl &= ~(S3C_PCM_CLKCTL_SYNCDIV_MASK
224 << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
225 clkctl |= ((sync_div & S3C_PCM_CLKCTL_SYNCDIV_MASK)
226 << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
227
228 writel(clkctl, regs + S3C_PCM_CLKCTL);
229
230 spin_unlock_irqrestore(&pcm->lock, flags);
231
232 dev_dbg(pcm->dev, "PCMSOURCE_CLK-%lu SCLK=%ufs \
233 SCLK_DIV=%d SYNC_DIV=%d\n",
234 clk_get_rate(clk), pcm->sclk_per_fs,
235 sclk_div, sync_div);
236
237 return 0;
238}
239
240static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
241 unsigned int fmt)
242{
243 struct s3c_pcm_info *pcm = to_info(cpu_dai);
244 void __iomem *regs = pcm->regs;
245 unsigned long flags;
246 int ret = 0;
247 u32 ctl;
248
249 dev_dbg(pcm->dev, "Entered %s\n", __func__);
250
251 spin_lock_irqsave(&pcm->lock, flags);
252
253 ctl = readl(regs + S3C_PCM_CTL);
254
255 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
256 case SND_SOC_DAIFMT_NB_NF:
257 /* Nothing to do, NB_NF by default */
258 break;
259 default:
260 dev_err(pcm->dev, "Unsupported clock inversion!\n");
261 ret = -EINVAL;
262 goto exit;
263 }
264
265 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
266 case SND_SOC_DAIFMT_CBS_CFS:
267 /* Nothing to do, Master by default */
268 break;
269 default:
270 dev_err(pcm->dev, "Unsupported master/slave format!\n");
271 ret = -EINVAL;
272 goto exit;
273 }
274
275 switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
276 case SND_SOC_DAIFMT_CONT:
277 pcm->idleclk = 1;
278 break;
279 case SND_SOC_DAIFMT_GATED:
280 pcm->idleclk = 0;
281 break;
282 default:
283 dev_err(pcm->dev, "Invalid Clock gating request!\n");
284 ret = -EINVAL;
285 goto exit;
286 }
287
288 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
289 case SND_SOC_DAIFMT_DSP_A:
290 ctl |= S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
291 ctl |= S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
292 break;
293 case SND_SOC_DAIFMT_DSP_B:
294 ctl &= ~S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
295 ctl &= ~S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
296 break;
297 default:
298 dev_err(pcm->dev, "Unsupported data format!\n");
299 ret = -EINVAL;
300 goto exit;
301 }
302
303 writel(ctl, regs + S3C_PCM_CTL);
304
305exit:
306 spin_unlock_irqrestore(&pcm->lock, flags);
307
308 return ret;
309}
310
311static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
312 int div_id, int div)
313{
314 struct s3c_pcm_info *pcm = to_info(cpu_dai);
315
316 switch (div_id) {
317 case S3C_PCM_SCLK_PER_FS:
318 pcm->sclk_per_fs = div;
319 break;
320
321 default:
322 return -EINVAL;
323 }
324
325 return 0;
326}
327
328static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai,
329 int clk_id, unsigned int freq, int dir)
330{
331 struct s3c_pcm_info *pcm = to_info(cpu_dai);
332 void __iomem *regs = pcm->regs;
333 u32 clkctl = readl(regs + S3C_PCM_CLKCTL);
334
335 switch (clk_id) {
336 case S3C_PCM_CLKSRC_PCLK:
337 clkctl |= S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
338 break;
339
340 case S3C_PCM_CLKSRC_MUX:
341 clkctl &= ~S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
342
343 if (clk_get_rate(pcm->cclk) != freq)
344 clk_set_rate(pcm->cclk, freq);
345
346 break;
347
348 default:
349 return -EINVAL;
350 }
351
352 writel(clkctl, regs + S3C_PCM_CLKCTL);
353
354 return 0;
355}
356
357static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
358 .set_sysclk = s3c_pcm_set_sysclk,
359 .set_clkdiv = s3c_pcm_set_clkdiv,
360 .trigger = s3c_pcm_trigger,
361 .hw_params = s3c_pcm_hw_params,
362 .set_fmt = s3c_pcm_set_fmt,
363};
364
365#define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000
366
367#define S3C_PCM_DECLARE(n) \
368{ \
369 .name = "samsung-pcm", \
370 .id = (n), \
371 .symmetric_rates = 1, \
372 .ops = &s3c_pcm_dai_ops, \
373 .playback = { \
374 .channels_min = 2, \
375 .channels_max = 2, \
376 .rates = S3C_PCM_RATES, \
377 .formats = SNDRV_PCM_FMTBIT_S16_LE, \
378 }, \
379 .capture = { \
380 .channels_min = 2, \
381 .channels_max = 2, \
382 .rates = S3C_PCM_RATES, \
383 .formats = SNDRV_PCM_FMTBIT_S16_LE, \
384 }, \
385}
386
387struct snd_soc_dai s3c_pcm_dai[] = {
388 S3C_PCM_DECLARE(0),
389 S3C_PCM_DECLARE(1),
390};
391EXPORT_SYMBOL_GPL(s3c_pcm_dai);
392
393static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
394{
395 struct s3c_pcm_info *pcm;
396 struct snd_soc_dai *dai;
397 struct resource *mem_res, *dmatx_res, *dmarx_res;
398 struct s3c_audio_pdata *pcm_pdata;
399 int ret;
400
401 /* Check for valid device index */
402 if ((pdev->id < 0) || pdev->id >= ARRAY_SIZE(s3c_pcm)) {
403 dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
404 return -EINVAL;
405 }
406
407 pcm_pdata = pdev->dev.platform_data;
408
409 /* Check for availability of necessary resource */
410 dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
411 if (!dmatx_res) {
412 dev_err(&pdev->dev, "Unable to get PCM-TX dma resource\n");
413 return -ENXIO;
414 }
415
416 dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
417 if (!dmarx_res) {
418 dev_err(&pdev->dev, "Unable to get PCM-RX dma resource\n");
419 return -ENXIO;
420 }
421
422 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
423 if (!mem_res) {
424 dev_err(&pdev->dev, "Unable to get register resource\n");
425 return -ENXIO;
426 }
427
428 if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) {
429 dev_err(&pdev->dev, "Unable to configure gpio\n");
430 return -EINVAL;
431 }
432
433 pcm = &s3c_pcm[pdev->id];
434 pcm->dev = &pdev->dev;
435
436 spin_lock_init(&pcm->lock);
437
438 dai = &s3c_pcm_dai[pdev->id];
439 dai->dev = &pdev->dev;
440
441 /* Default is 128fs */
442 pcm->sclk_per_fs = 128;
443
444 pcm->cclk = clk_get(&pdev->dev, "audio-bus");
445 if (IS_ERR(pcm->cclk)) {
446 dev_err(&pdev->dev, "failed to get audio-bus\n");
447 ret = PTR_ERR(pcm->cclk);
448 goto err1;
449 }
450 clk_enable(pcm->cclk);
451
452 /* record our pcm structure for later use in the callbacks */
453 dai->private_data = pcm;
454
455 if (!request_mem_region(mem_res->start,
456 resource_size(mem_res), "samsung-pcm")) {
457 dev_err(&pdev->dev, "Unable to request register region\n");
458 ret = -EBUSY;
459 goto err2;
460 }
461
462 pcm->regs = ioremap(mem_res->start, 0x100);
463 if (pcm->regs == NULL) {
464 dev_err(&pdev->dev, "cannot ioremap registers\n");
465 ret = -ENXIO;
466 goto err3;
467 }
468
469 pcm->pclk = clk_get(&pdev->dev, "pcm");
470 if (IS_ERR(pcm->pclk)) {
471 dev_err(&pdev->dev, "failed to get pcm_clock\n");
472 ret = -ENOENT;
473 goto err4;
474 }
475 clk_enable(pcm->pclk);
476
477 ret = snd_soc_register_dai(dai);
478 if (ret != 0) {
479 dev_err(&pdev->dev, "failed to get pcm_clock\n");
480 goto err5;
481 }
482
483 s3c_pcm_stereo_in[pdev->id].dma_addr = mem_res->start
484 + S3C_PCM_RXFIFO;
485 s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start
486 + S3C_PCM_TXFIFO;
487
488 s3c_pcm_stereo_in[pdev->id].channel = dmarx_res->start;
489 s3c_pcm_stereo_out[pdev->id].channel = dmatx_res->start;
490
491 pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id];
492 pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id];
493
494 return 0;
495
496err5:
497 clk_disable(pcm->pclk);
498 clk_put(pcm->pclk);
499err4:
500 iounmap(pcm->regs);
501err3:
502 release_mem_region(mem_res->start, resource_size(mem_res));
503err2:
504 clk_disable(pcm->cclk);
505 clk_put(pcm->cclk);
506err1:
507 return ret;
508}
509
510static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev)
511{
512 struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id];
513 struct resource *mem_res;
514
515 iounmap(pcm->regs);
516
517 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
518 release_mem_region(mem_res->start, resource_size(mem_res));
519
520 clk_disable(pcm->cclk);
521 clk_disable(pcm->pclk);
522 clk_put(pcm->pclk);
523 clk_put(pcm->cclk);
524
525 return 0;
526}
527
528static struct platform_driver s3c_pcm_driver = {
529 .probe = s3c_pcm_dev_probe,
530 .remove = s3c_pcm_dev_remove,
531 .driver = {
532 .name = "samsung-pcm",
533 .owner = THIS_MODULE,
534 },
535};
536
537static int __init s3c_pcm_init(void)
538{
539 return platform_driver_register(&s3c_pcm_driver);
540}
541module_init(s3c_pcm_init);
542
543static void __exit s3c_pcm_exit(void)
544{
545 platform_driver_unregister(&s3c_pcm_driver);
546}
547module_exit(s3c_pcm_exit);
548
549/* Module information */
550MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
551MODULE_DESCRIPTION("S3C PCM Controller Driver");
552MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c-pcm.h b/sound/soc/s3c24xx/s3c-pcm.h
new file mode 100644
index 000000000000..69ff9971692f
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c-pcm.h
@@ -0,0 +1,123 @@
1/* sound/soc/s3c24xx/s3c-pcm.h
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 as
5 * published by the Free Software Foundation.
6 *
7 */
8
9#ifndef __S3C_PCM_H
10#define __S3C_PCM_H __FILE__
11
12/*Register Offsets */
13#define S3C_PCM_CTL (0x00)
14#define S3C_PCM_CLKCTL (0x04)
15#define S3C_PCM_TXFIFO (0x08)
16#define S3C_PCM_RXFIFO (0x0C)
17#define S3C_PCM_IRQCTL (0x10)
18#define S3C_PCM_IRQSTAT (0x14)
19#define S3C_PCM_FIFOSTAT (0x18)
20#define S3C_PCM_CLRINT (0x20)
21
22/* PCM_CTL Bit-Fields */
23#define S3C_PCM_CTL_TXDIPSTICK_MASK (0x3f)
24#define S3C_PCM_CTL_TXDIPSTICK_SHIFT (13)
25#define S3C_PCM_CTL_RXDIPSTICK_MSK (0x3f<<7)
26#define S3C_PCM_CTL_TXDMA_EN (0x1<<6)
27#define S3C_PCM_CTL_RXDMA_EN (0x1<<5)
28#define S3C_PCM_CTL_TXMSB_AFTER_FSYNC (0x1<<4)
29#define S3C_PCM_CTL_RXMSB_AFTER_FSYNC (0x1<<3)
30#define S3C_PCM_CTL_TXFIFO_EN (0x1<<2)
31#define S3C_PCM_CTL_RXFIFO_EN (0x1<<1)
32#define S3C_PCM_CTL_ENABLE (0x1<<0)
33
34/* PCM_CLKCTL Bit-Fields */
35#define S3C_PCM_CLKCTL_SERCLK_EN (0x1<<19)
36#define S3C_PCM_CLKCTL_SERCLKSEL_PCLK (0x1<<18)
37#define S3C_PCM_CLKCTL_SCLKDIV_MASK (0x1ff)
38#define S3C_PCM_CLKCTL_SYNCDIV_MASK (0x1ff)
39#define S3C_PCM_CLKCTL_SCLKDIV_SHIFT (9)
40#define S3C_PCM_CLKCTL_SYNCDIV_SHIFT (0)
41
42/* PCM_TXFIFO Bit-Fields */
43#define S3C_PCM_TXFIFO_DVALID (0x1<<16)
44#define S3C_PCM_TXFIFO_DATA_MSK (0xffff<<0)
45
46/* PCM_RXFIFO Bit-Fields */
47#define S3C_PCM_RXFIFO_DVALID (0x1<<16)
48#define S3C_PCM_RXFIFO_DATA_MSK (0xffff<<0)
49
50/* PCM_IRQCTL Bit-Fields */
51#define S3C_PCM_IRQCTL_IRQEN (0x1<<14)
52#define S3C_PCM_IRQCTL_WRDEN (0x1<<12)
53#define S3C_PCM_IRQCTL_TXEMPTYEN (0x1<<11)
54#define S3C_PCM_IRQCTL_TXALMSTEMPTYEN (0x1<<10)
55#define S3C_PCM_IRQCTL_TXFULLEN (0x1<<9)
56#define S3C_PCM_IRQCTL_TXALMSTFULLEN (0x1<<8)
57#define S3C_PCM_IRQCTL_TXSTARVEN (0x1<<7)
58#define S3C_PCM_IRQCTL_TXERROVRFLEN (0x1<<6)
59#define S3C_PCM_IRQCTL_RXEMPTEN (0x1<<5)
60#define S3C_PCM_IRQCTL_RXALMSTEMPTEN (0x1<<4)
61#define S3C_PCM_IRQCTL_RXFULLEN (0x1<<3)
62#define S3C_PCM_IRQCTL_RXALMSTFULLEN (0x1<<2)
63#define S3C_PCM_IRQCTL_RXSTARVEN (0x1<<1)
64#define S3C_PCM_IRQCTL_RXERROVRFLEN (0x1<<0)
65
66/* PCM_IRQSTAT Bit-Fields */
67#define S3C_PCM_IRQSTAT_IRQPND (0x1<<13)
68#define S3C_PCM_IRQSTAT_WRD_XFER (0x1<<12)
69#define S3C_PCM_IRQSTAT_TXEMPTY (0x1<<11)
70#define S3C_PCM_IRQSTAT_TXALMSTEMPTY (0x1<<10)
71#define S3C_PCM_IRQSTAT_TXFULL (0x1<<9)
72#define S3C_PCM_IRQSTAT_TXALMSTFULL (0x1<<8)
73#define S3C_PCM_IRQSTAT_TXSTARV (0x1<<7)
74#define S3C_PCM_IRQSTAT_TXERROVRFL (0x1<<6)
75#define S3C_PCM_IRQSTAT_RXEMPT (0x1<<5)
76#define S3C_PCM_IRQSTAT_RXALMSTEMPT (0x1<<4)
77#define S3C_PCM_IRQSTAT_RXFULL (0x1<<3)
78#define S3C_PCM_IRQSTAT_RXALMSTFULL (0x1<<2)
79#define S3C_PCM_IRQSTAT_RXSTARV (0x1<<1)
80#define S3C_PCM_IRQSTAT_RXERROVRFL (0x1<<0)
81
82/* PCM_FIFOSTAT Bit-Fields */
83#define S3C_PCM_FIFOSTAT_TXCNT_MSK (0x3f<<14)
84#define S3C_PCM_FIFOSTAT_TXFIFOEMPTY (0x1<<13)
85#define S3C_PCM_FIFOSTAT_TXFIFOALMSTEMPTY (0x1<<12)
86#define S3C_PCM_FIFOSTAT_TXFIFOFULL (0x1<<11)
87#define S3C_PCM_FIFOSTAT_TXFIFOALMSTFULL (0x1<<10)
88#define S3C_PCM_FIFOSTAT_RXCNT_MSK (0x3f<<4)
89#define S3C_PCM_FIFOSTAT_RXFIFOEMPTY (0x1<<3)
90#define S3C_PCM_FIFOSTAT_RXFIFOALMSTEMPTY (0x1<<2)
91#define S3C_PCM_FIFOSTAT_RXFIFOFULL (0x1<<1)
92#define S3C_PCM_FIFOSTAT_RXFIFOALMSTFULL (0x1<<0)
93
94#define S3C_PCM_CLKSRC_PCLK 0
95#define S3C_PCM_CLKSRC_MUX 1
96
97#define S3C_PCM_SCLK_PER_FS 0
98
99/**
100 * struct s3c_pcm_info - S3C PCM Controller information
101 * @dev: The parent device passed to use from the probe.
102 * @regs: The pointer to the device register block.
103 * @dma_playback: DMA information for playback channel.
104 * @dma_capture: DMA information for capture channel.
105 */
106struct s3c_pcm_info {
107 spinlock_t lock;
108 struct device *dev;
109 void __iomem *regs;
110
111 unsigned int sclk_per_fs;
112
113 /* Whether to keep PCMSCLK enabled even when idle(no active xfer) */
114 unsigned int idleclk;
115
116 struct clk *pclk;
117 struct clk *cclk;
118
119 struct s3c_dma_params *dma_playback;
120 struct s3c_dma_params *dma_capture;
121};
122
123#endif /* __S3C_PCM_H */