Merge commit 'v2.6.39-rc3' into for-2.6.39
[pandora-kernel.git] / sound / soc / samsung / pcm.c
1 /* sound/soc/samsung/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/clk.h>
15 #include <linux/io.h>
16
17 #include <sound/soc.h>
18 #include <sound/pcm_params.h>
19
20 #include <plat/audio.h>
21 #include <plat/dma.h>
22
23 #include "dma.h"
24 #include "pcm.h"
25
26 /*Register Offsets */
27 #define S3C_PCM_CTL             0x00
28 #define S3C_PCM_CLKCTL          0x04
29 #define S3C_PCM_TXFIFO          0x08
30 #define S3C_PCM_RXFIFO          0x0C
31 #define S3C_PCM_IRQCTL          0x10
32 #define S3C_PCM_IRQSTAT         0x14
33 #define S3C_PCM_FIFOSTAT        0x18
34 #define S3C_PCM_CLRINT          0x20
35
36 /* PCM_CTL Bit-Fields */
37 #define S3C_PCM_CTL_TXDIPSTICK_MASK     0x3f
38 #define S3C_PCM_CTL_TXDIPSTICK_SHIFT    13
39 #define S3C_PCM_CTL_RXDIPSTICK_MASK     0x3f
40 #define S3C_PCM_CTL_RXDIPSTICK_SHIFT    7
41 #define S3C_PCM_CTL_TXDMA_EN            (0x1 << 6)
42 #define S3C_PCM_CTL_RXDMA_EN            (0x1 << 5)
43 #define S3C_PCM_CTL_TXMSB_AFTER_FSYNC   (0x1 << 4)
44 #define S3C_PCM_CTL_RXMSB_AFTER_FSYNC   (0x1 << 3)
45 #define S3C_PCM_CTL_TXFIFO_EN           (0x1 << 2)
46 #define S3C_PCM_CTL_RXFIFO_EN           (0x1 << 1)
47 #define S3C_PCM_CTL_ENABLE              (0x1 << 0)
48
49 /* PCM_CLKCTL Bit-Fields */
50 #define S3C_PCM_CLKCTL_SERCLK_EN        (0x1 << 19)
51 #define S3C_PCM_CLKCTL_SERCLKSEL_PCLK   (0x1 << 18)
52 #define S3C_PCM_CLKCTL_SCLKDIV_MASK     0x1ff
53 #define S3C_PCM_CLKCTL_SYNCDIV_MASK     0x1ff
54 #define S3C_PCM_CLKCTL_SCLKDIV_SHIFT    9
55 #define S3C_PCM_CLKCTL_SYNCDIV_SHIFT    0
56
57 /* PCM_TXFIFO Bit-Fields */
58 #define S3C_PCM_TXFIFO_DVALID   (0x1 << 16)
59 #define S3C_PCM_TXFIFO_DATA_MSK (0xffff << 0)
60
61 /* PCM_RXFIFO Bit-Fields */
62 #define S3C_PCM_RXFIFO_DVALID   (0x1 << 16)
63 #define S3C_PCM_RXFIFO_DATA_MSK (0xffff << 0)
64
65 /* PCM_IRQCTL Bit-Fields */
66 #define S3C_PCM_IRQCTL_IRQEN            (0x1 << 14)
67 #define S3C_PCM_IRQCTL_WRDEN            (0x1 << 12)
68 #define S3C_PCM_IRQCTL_TXEMPTYEN        (0x1 << 11)
69 #define S3C_PCM_IRQCTL_TXALMSTEMPTYEN   (0x1 << 10)
70 #define S3C_PCM_IRQCTL_TXFULLEN         (0x1 << 9)
71 #define S3C_PCM_IRQCTL_TXALMSTFULLEN    (0x1 << 8)
72 #define S3C_PCM_IRQCTL_TXSTARVEN        (0x1 << 7)
73 #define S3C_PCM_IRQCTL_TXERROVRFLEN     (0x1 << 6)
74 #define S3C_PCM_IRQCTL_RXEMPTEN         (0x1 << 5)
75 #define S3C_PCM_IRQCTL_RXALMSTEMPTEN    (0x1 << 4)
76 #define S3C_PCM_IRQCTL_RXFULLEN         (0x1 << 3)
77 #define S3C_PCM_IRQCTL_RXALMSTFULLEN    (0x1 << 2)
78 #define S3C_PCM_IRQCTL_RXSTARVEN        (0x1 << 1)
79 #define S3C_PCM_IRQCTL_RXERROVRFLEN     (0x1 << 0)
80
81 /* PCM_IRQSTAT Bit-Fields */
82 #define S3C_PCM_IRQSTAT_IRQPND          (0x1 << 13)
83 #define S3C_PCM_IRQSTAT_WRD_XFER        (0x1 << 12)
84 #define S3C_PCM_IRQSTAT_TXEMPTY         (0x1 << 11)
85 #define S3C_PCM_IRQSTAT_TXALMSTEMPTY    (0x1 << 10)
86 #define S3C_PCM_IRQSTAT_TXFULL          (0x1 << 9)
87 #define S3C_PCM_IRQSTAT_TXALMSTFULL     (0x1 << 8)
88 #define S3C_PCM_IRQSTAT_TXSTARV         (0x1 << 7)
89 #define S3C_PCM_IRQSTAT_TXERROVRFL      (0x1 << 6)
90 #define S3C_PCM_IRQSTAT_RXEMPT          (0x1 << 5)
91 #define S3C_PCM_IRQSTAT_RXALMSTEMPT     (0x1 << 4)
92 #define S3C_PCM_IRQSTAT_RXFULL          (0x1 << 3)
93 #define S3C_PCM_IRQSTAT_RXALMSTFULL     (0x1 << 2)
94 #define S3C_PCM_IRQSTAT_RXSTARV         (0x1 << 1)
95 #define S3C_PCM_IRQSTAT_RXERROVRFL      (0x1 << 0)
96
97 /* PCM_FIFOSTAT Bit-Fields */
98 #define S3C_PCM_FIFOSTAT_TXCNT_MSK              (0x3f << 14)
99 #define S3C_PCM_FIFOSTAT_TXFIFOEMPTY            (0x1 << 13)
100 #define S3C_PCM_FIFOSTAT_TXFIFOALMSTEMPTY       (0x1 << 12)
101 #define S3C_PCM_FIFOSTAT_TXFIFOFULL             (0x1 << 11)
102 #define S3C_PCM_FIFOSTAT_TXFIFOALMSTFULL        (0x1 << 10)
103 #define S3C_PCM_FIFOSTAT_RXCNT_MSK              (0x3f << 4)
104 #define S3C_PCM_FIFOSTAT_RXFIFOEMPTY            (0x1 << 3)
105 #define S3C_PCM_FIFOSTAT_RXFIFOALMSTEMPTY       (0x1 << 2)
106 #define S3C_PCM_FIFOSTAT_RXFIFOFULL             (0x1 << 1)
107 #define S3C_PCM_FIFOSTAT_RXFIFOALMSTFULL        (0x1 << 0)
108
109 /**
110  * struct s3c_pcm_info - S3C PCM Controller information
111  * @dev: The parent device passed to use from the probe.
112  * @regs: The pointer to the device register block.
113  * @dma_playback: DMA information for playback channel.
114  * @dma_capture: DMA information for capture channel.
115  */
116 struct s3c_pcm_info {
117         spinlock_t lock;
118         struct device   *dev;
119         void __iomem    *regs;
120
121         unsigned int sclk_per_fs;
122
123         /* Whether to keep PCMSCLK enabled even when idle(no active xfer) */
124         unsigned int idleclk;
125
126         struct clk      *pclk;
127         struct clk      *cclk;
128
129         struct s3c_dma_params   *dma_playback;
130         struct s3c_dma_params   *dma_capture;
131 };
132
133 static struct s3c2410_dma_client s3c_pcm_dma_client_out = {
134         .name           = "PCM Stereo out"
135 };
136
137 static struct s3c2410_dma_client s3c_pcm_dma_client_in = {
138         .name           = "PCM Stereo in"
139 };
140
141 static struct s3c_dma_params s3c_pcm_stereo_out[] = {
142         [0] = {
143                 .client         = &s3c_pcm_dma_client_out,
144                 .dma_size       = 4,
145         },
146         [1] = {
147                 .client         = &s3c_pcm_dma_client_out,
148                 .dma_size       = 4,
149         },
150 };
151
152 static struct s3c_dma_params s3c_pcm_stereo_in[] = {
153         [0] = {
154                 .client         = &s3c_pcm_dma_client_in,
155                 .dma_size       = 4,
156         },
157         [1] = {
158                 .client         = &s3c_pcm_dma_client_in,
159                 .dma_size       = 4,
160         },
161 };
162
163 static struct s3c_pcm_info s3c_pcm[2];
164
165 static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
166 {
167         void __iomem *regs = pcm->regs;
168         u32 ctl, clkctl;
169
170         clkctl = readl(regs + S3C_PCM_CLKCTL);
171         ctl = readl(regs + S3C_PCM_CTL);
172         ctl &= ~(S3C_PCM_CTL_TXDIPSTICK_MASK
173                          << S3C_PCM_CTL_TXDIPSTICK_SHIFT);
174
175         if (on) {
176                 ctl |= S3C_PCM_CTL_TXDMA_EN;
177                 ctl |= S3C_PCM_CTL_TXFIFO_EN;
178                 ctl |= S3C_PCM_CTL_ENABLE;
179                 ctl |= (0x4<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
180                 clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
181         } else {
182                 ctl &= ~S3C_PCM_CTL_TXDMA_EN;
183                 ctl &= ~S3C_PCM_CTL_TXFIFO_EN;
184
185                 if (!(ctl & S3C_PCM_CTL_RXFIFO_EN)) {
186                         ctl &= ~S3C_PCM_CTL_ENABLE;
187                         if (!pcm->idleclk)
188                                 clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
189                 }
190         }
191
192         writel(clkctl, regs + S3C_PCM_CLKCTL);
193         writel(ctl, regs + S3C_PCM_CTL);
194 }
195
196 static void s3c_pcm_snd_rxctrl(struct s3c_pcm_info *pcm, int on)
197 {
198         void __iomem *regs = pcm->regs;
199         u32 ctl, clkctl;
200
201         ctl = readl(regs + S3C_PCM_CTL);
202         clkctl = readl(regs + S3C_PCM_CLKCTL);
203         ctl &= ~(S3C_PCM_CTL_RXDIPSTICK_MASK
204                          << S3C_PCM_CTL_RXDIPSTICK_SHIFT);
205
206         if (on) {
207                 ctl |= S3C_PCM_CTL_RXDMA_EN;
208                 ctl |= S3C_PCM_CTL_RXFIFO_EN;
209                 ctl |= S3C_PCM_CTL_ENABLE;
210                 ctl |= (0x20<<S3C_PCM_CTL_RXDIPSTICK_SHIFT);
211                 clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
212         } else {
213                 ctl &= ~S3C_PCM_CTL_RXDMA_EN;
214                 ctl &= ~S3C_PCM_CTL_RXFIFO_EN;
215
216                 if (!(ctl & S3C_PCM_CTL_TXFIFO_EN)) {
217                         ctl &= ~S3C_PCM_CTL_ENABLE;
218                         if (!pcm->idleclk)
219                                 clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
220                 }
221         }
222
223         writel(clkctl, regs + S3C_PCM_CLKCTL);
224         writel(ctl, regs + S3C_PCM_CTL);
225 }
226
227 static int s3c_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
228                                struct snd_soc_dai *dai)
229 {
230         struct snd_soc_pcm_runtime *rtd = substream->private_data;
231         struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
232         unsigned long flags;
233
234         dev_dbg(pcm->dev, "Entered %s\n", __func__);
235
236         switch (cmd) {
237         case SNDRV_PCM_TRIGGER_START:
238         case SNDRV_PCM_TRIGGER_RESUME:
239         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
240                 spin_lock_irqsave(&pcm->lock, flags);
241
242                 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
243                         s3c_pcm_snd_rxctrl(pcm, 1);
244                 else
245                         s3c_pcm_snd_txctrl(pcm, 1);
246
247                 spin_unlock_irqrestore(&pcm->lock, flags);
248                 break;
249
250         case SNDRV_PCM_TRIGGER_STOP:
251         case SNDRV_PCM_TRIGGER_SUSPEND:
252         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
253                 spin_lock_irqsave(&pcm->lock, flags);
254
255                 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
256                         s3c_pcm_snd_rxctrl(pcm, 0);
257                 else
258                         s3c_pcm_snd_txctrl(pcm, 0);
259
260                 spin_unlock_irqrestore(&pcm->lock, flags);
261                 break;
262
263         default:
264                 return -EINVAL;
265         }
266
267         return 0;
268 }
269
270 static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
271                                  struct snd_pcm_hw_params *params,
272                                  struct snd_soc_dai *socdai)
273 {
274         struct snd_soc_pcm_runtime *rtd = substream->private_data;
275         struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
276         struct s3c_dma_params *dma_data;
277         void __iomem *regs = pcm->regs;
278         struct clk *clk;
279         int sclk_div, sync_div;
280         unsigned long flags;
281         u32 clkctl;
282
283         dev_dbg(pcm->dev, "Entered %s\n", __func__);
284
285         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
286                 dma_data = pcm->dma_playback;
287         else
288                 dma_data = pcm->dma_capture;
289
290         snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
291
292         /* Strictly check for sample size */
293         switch (params_format(params)) {
294         case SNDRV_PCM_FORMAT_S16_LE:
295                 break;
296         default:
297                 return -EINVAL;
298         }
299
300         spin_lock_irqsave(&pcm->lock, flags);
301
302         /* Get hold of the PCMSOURCE_CLK */
303         clkctl = readl(regs + S3C_PCM_CLKCTL);
304         if (clkctl & S3C_PCM_CLKCTL_SERCLKSEL_PCLK)
305                 clk = pcm->pclk;
306         else
307                 clk = pcm->cclk;
308
309         /* Set the SCLK divider */
310         sclk_div = clk_get_rate(clk) / pcm->sclk_per_fs /
311                                         params_rate(params) / 2 - 1;
312
313         clkctl &= ~(S3C_PCM_CLKCTL_SCLKDIV_MASK
314                         << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
315         clkctl |= ((sclk_div & S3C_PCM_CLKCTL_SCLKDIV_MASK)
316                         << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
317
318         /* Set the SYNC divider */
319         sync_div = pcm->sclk_per_fs - 1;
320
321         clkctl &= ~(S3C_PCM_CLKCTL_SYNCDIV_MASK
322                                 << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
323         clkctl |= ((sync_div & S3C_PCM_CLKCTL_SYNCDIV_MASK)
324                                 << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
325
326         writel(clkctl, regs + S3C_PCM_CLKCTL);
327
328         spin_unlock_irqrestore(&pcm->lock, flags);
329
330         dev_dbg(pcm->dev, "PCMSOURCE_CLK-%lu SCLK=%ufs SCLK_DIV=%d SYNC_DIV=%d\n",
331                                 clk_get_rate(clk), pcm->sclk_per_fs,
332                                 sclk_div, sync_div);
333
334         return 0;
335 }
336
337 static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
338                                unsigned int fmt)
339 {
340         struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
341         void __iomem *regs = pcm->regs;
342         unsigned long flags;
343         int ret = 0;
344         u32 ctl;
345
346         dev_dbg(pcm->dev, "Entered %s\n", __func__);
347
348         spin_lock_irqsave(&pcm->lock, flags);
349
350         ctl = readl(regs + S3C_PCM_CTL);
351
352         switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
353         case SND_SOC_DAIFMT_IB_NF:
354                 /* Nothing to do, IB_NF by default */
355                 break;
356         default:
357                 dev_err(pcm->dev, "Unsupported clock inversion!\n");
358                 ret = -EINVAL;
359                 goto exit;
360         }
361
362         switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
363         case SND_SOC_DAIFMT_CBS_CFS:
364                 /* Nothing to do, Master by default */
365                 break;
366         default:
367                 dev_err(pcm->dev, "Unsupported master/slave format!\n");
368                 ret = -EINVAL;
369                 goto exit;
370         }
371
372         switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
373         case SND_SOC_DAIFMT_CONT:
374                 pcm->idleclk = 1;
375                 break;
376         case SND_SOC_DAIFMT_GATED:
377                 pcm->idleclk = 0;
378                 break;
379         default:
380                 dev_err(pcm->dev, "Invalid Clock gating request!\n");
381                 ret = -EINVAL;
382                 goto exit;
383         }
384
385         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
386         case SND_SOC_DAIFMT_DSP_A:
387                 ctl |= S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
388                 ctl |= S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
389                 break;
390         case SND_SOC_DAIFMT_DSP_B:
391                 ctl &= ~S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
392                 ctl &= ~S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
393                 break;
394         default:
395                 dev_err(pcm->dev, "Unsupported data format!\n");
396                 ret = -EINVAL;
397                 goto exit;
398         }
399
400         writel(ctl, regs + S3C_PCM_CTL);
401
402 exit:
403         spin_unlock_irqrestore(&pcm->lock, flags);
404
405         return ret;
406 }
407
408 static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
409                                                 int div_id, int div)
410 {
411         struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
412
413         switch (div_id) {
414         case S3C_PCM_SCLK_PER_FS:
415                 pcm->sclk_per_fs = div;
416                 break;
417
418         default:
419                 return -EINVAL;
420         }
421
422         return 0;
423 }
424
425 static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai,
426                                   int clk_id, unsigned int freq, int dir)
427 {
428         struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
429         void __iomem *regs = pcm->regs;
430         u32 clkctl = readl(regs + S3C_PCM_CLKCTL);
431
432         switch (clk_id) {
433         case S3C_PCM_CLKSRC_PCLK:
434                 clkctl |= S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
435                 break;
436
437         case S3C_PCM_CLKSRC_MUX:
438                 clkctl &= ~S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
439
440                 if (clk_get_rate(pcm->cclk) != freq)
441                         clk_set_rate(pcm->cclk, freq);
442
443                 break;
444
445         default:
446                 return -EINVAL;
447         }
448
449         writel(clkctl, regs + S3C_PCM_CLKCTL);
450
451         return 0;
452 }
453
454 static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
455         .set_sysclk     = s3c_pcm_set_sysclk,
456         .set_clkdiv     = s3c_pcm_set_clkdiv,
457         .trigger        = s3c_pcm_trigger,
458         .hw_params      = s3c_pcm_hw_params,
459         .set_fmt        = s3c_pcm_set_fmt,
460 };
461
462 #define S3C_PCM_RATES  SNDRV_PCM_RATE_8000_96000
463
464 #define S3C_PCM_DAI_DECLARE                     \
465         .symmetric_rates = 1,                                   \
466         .ops = &s3c_pcm_dai_ops,                                \
467         .playback = {                                           \
468                 .channels_min   = 2,                            \
469                 .channels_max   = 2,                            \
470                 .rates          = S3C_PCM_RATES,                \
471                 .formats        = SNDRV_PCM_FMTBIT_S16_LE,      \
472         },                                                      \
473         .capture = {                                            \
474                 .channels_min   = 2,                            \
475                 .channels_max   = 2,                            \
476                 .rates          = S3C_PCM_RATES,                \
477                 .formats        = SNDRV_PCM_FMTBIT_S16_LE,      \
478         }
479
480 struct snd_soc_dai_driver s3c_pcm_dai[] = {
481         [0] = {
482                 .name   = "samsung-pcm.0",
483                 S3C_PCM_DAI_DECLARE,
484         },
485         [1] = {
486                 .name   = "samsung-pcm.1",
487                 S3C_PCM_DAI_DECLARE,
488         },
489 };
490 EXPORT_SYMBOL_GPL(s3c_pcm_dai);
491
492 static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
493 {
494         struct s3c_pcm_info *pcm;
495         struct resource *mem_res, *dmatx_res, *dmarx_res;
496         struct s3c_audio_pdata *pcm_pdata;
497         int ret;
498
499         /* Check for valid device index */
500         if ((pdev->id < 0) || pdev->id >= ARRAY_SIZE(s3c_pcm)) {
501                 dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
502                 return -EINVAL;
503         }
504
505         pcm_pdata = pdev->dev.platform_data;
506
507         /* Check for availability of necessary resource */
508         dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
509         if (!dmatx_res) {
510                 dev_err(&pdev->dev, "Unable to get PCM-TX dma resource\n");
511                 return -ENXIO;
512         }
513
514         dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
515         if (!dmarx_res) {
516                 dev_err(&pdev->dev, "Unable to get PCM-RX dma resource\n");
517                 return -ENXIO;
518         }
519
520         mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
521         if (!mem_res) {
522                 dev_err(&pdev->dev, "Unable to get register resource\n");
523                 return -ENXIO;
524         }
525
526         if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) {
527                 dev_err(&pdev->dev, "Unable to configure gpio\n");
528                 return -EINVAL;
529         }
530
531         pcm = &s3c_pcm[pdev->id];
532         pcm->dev = &pdev->dev;
533
534         spin_lock_init(&pcm->lock);
535
536         /* Default is 128fs */
537         pcm->sclk_per_fs = 128;
538
539         pcm->cclk = clk_get(&pdev->dev, "audio-bus");
540         if (IS_ERR(pcm->cclk)) {
541                 dev_err(&pdev->dev, "failed to get audio-bus\n");
542                 ret = PTR_ERR(pcm->cclk);
543                 goto err1;
544         }
545         clk_enable(pcm->cclk);
546
547         /* record our pcm structure for later use in the callbacks */
548         dev_set_drvdata(&pdev->dev, pcm);
549
550         if (!request_mem_region(mem_res->start,
551                                 resource_size(mem_res), "samsung-pcm")) {
552                 dev_err(&pdev->dev, "Unable to request register region\n");
553                 ret = -EBUSY;
554                 goto err2;
555         }
556
557         pcm->regs = ioremap(mem_res->start, 0x100);
558         if (pcm->regs == NULL) {
559                 dev_err(&pdev->dev, "cannot ioremap registers\n");
560                 ret = -ENXIO;
561                 goto err3;
562         }
563
564         pcm->pclk = clk_get(&pdev->dev, "pcm");
565         if (IS_ERR(pcm->pclk)) {
566                 dev_err(&pdev->dev, "failed to get pcm_clock\n");
567                 ret = -ENOENT;
568                 goto err4;
569         }
570         clk_enable(pcm->pclk);
571
572         ret = snd_soc_register_dai(&pdev->dev, &s3c_pcm_dai[pdev->id]);
573         if (ret != 0) {
574                 dev_err(&pdev->dev, "failed to get pcm_clock\n");
575                 goto err5;
576         }
577
578         s3c_pcm_stereo_in[pdev->id].dma_addr = mem_res->start
579                                                         + S3C_PCM_RXFIFO;
580         s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start
581                                                         + S3C_PCM_TXFIFO;
582
583         s3c_pcm_stereo_in[pdev->id].channel = dmarx_res->start;
584         s3c_pcm_stereo_out[pdev->id].channel = dmatx_res->start;
585
586         pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id];
587         pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id];
588
589         return 0;
590
591 err5:
592         clk_disable(pcm->pclk);
593         clk_put(pcm->pclk);
594 err4:
595         iounmap(pcm->regs);
596 err3:
597         release_mem_region(mem_res->start, resource_size(mem_res));
598 err2:
599         clk_disable(pcm->cclk);
600         clk_put(pcm->cclk);
601 err1:
602         return ret;
603 }
604
605 static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev)
606 {
607         struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id];
608         struct resource *mem_res;
609
610         snd_soc_unregister_dai(&pdev->dev);
611
612         iounmap(pcm->regs);
613
614         mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
615         release_mem_region(mem_res->start, resource_size(mem_res));
616
617         clk_disable(pcm->cclk);
618         clk_disable(pcm->pclk);
619         clk_put(pcm->pclk);
620         clk_put(pcm->cclk);
621
622         return 0;
623 }
624
625 static struct platform_driver s3c_pcm_driver = {
626         .probe  = s3c_pcm_dev_probe,
627         .remove = s3c_pcm_dev_remove,
628         .driver = {
629                 .name = "samsung-pcm",
630                 .owner = THIS_MODULE,
631         },
632 };
633
634 static int __init s3c_pcm_init(void)
635 {
636         return platform_driver_register(&s3c_pcm_driver);
637 }
638 module_init(s3c_pcm_init);
639
640 static void __exit s3c_pcm_exit(void)
641 {
642         platform_driver_unregister(&s3c_pcm_driver);
643 }
644 module_exit(s3c_pcm_exit);
645
646 /* Module information */
647 MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
648 MODULE_DESCRIPTION("S3C PCM Controller Driver");
649 MODULE_LICENSE("GPL");
650 MODULE_ALIAS("platform:samsung-pcm");