root/sound/soc/samsung/pcm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. s3c_pcm_snd_txctrl
  2. s3c_pcm_snd_rxctrl
  3. s3c_pcm_trigger
  4. s3c_pcm_hw_params
  5. s3c_pcm_set_fmt
  6. s3c_pcm_set_clkdiv
  7. s3c_pcm_set_sysclk
  8. s3c_pcm_dai_probe
  9. s3c_pcm_dev_probe
  10. s3c_pcm_dev_remove

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

/* [<][>][^][v][top][bottom][index][help] */