0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/module.h>
0014 #include <linux/delay.h>
0015 #include <linux/clk.h>
0016 #include <linux/io.h>
0017
0018 #include <sound/soc.h>
0019 #include <sound/pcm_params.h>
0020
0021 #include "regs-i2s-v2.h"
0022 #include "s3c-i2s-v2.h"
0023
0024 #define S3C2412_I2S_DEBUG_CON 0
0025
0026 static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
0027 {
0028 return snd_soc_dai_get_drvdata(cpu_dai);
0029 }
0030
0031 #define bit_set(v, b) (((v) & (b)) ? 1 : 0)
0032
0033 #if S3C2412_I2S_DEBUG_CON
0034 static void dbg_showcon(const char *fn, u32 con)
0035 {
0036 printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn,
0037 bit_set(con, S3C2412_IISCON_LRINDEX),
0038 bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY),
0039 bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY),
0040 bit_set(con, S3C2412_IISCON_TXFIFO_FULL),
0041 bit_set(con, S3C2412_IISCON_RXFIFO_FULL));
0042
0043 printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n",
0044 fn,
0045 bit_set(con, S3C2412_IISCON_TXDMA_PAUSE),
0046 bit_set(con, S3C2412_IISCON_RXDMA_PAUSE),
0047 bit_set(con, S3C2412_IISCON_TXCH_PAUSE),
0048 bit_set(con, S3C2412_IISCON_RXCH_PAUSE));
0049 printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn,
0050 bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE),
0051 bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE),
0052 bit_set(con, S3C2412_IISCON_IIS_ACTIVE));
0053 }
0054 #else
0055 static inline void dbg_showcon(const char *fn, u32 con)
0056 {
0057 }
0058 #endif
0059
0060
0061 static void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
0062 {
0063 void __iomem *regs = i2s->regs;
0064 u32 fic, con, mod;
0065
0066 pr_debug("%s(%d)\n", __func__, on);
0067
0068 fic = readl(regs + S3C2412_IISFIC);
0069 con = readl(regs + S3C2412_IISCON);
0070 mod = readl(regs + S3C2412_IISMOD);
0071
0072 pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
0073
0074 if (on) {
0075 con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
0076 con &= ~S3C2412_IISCON_TXDMA_PAUSE;
0077 con &= ~S3C2412_IISCON_TXCH_PAUSE;
0078
0079 switch (mod & S3C2412_IISMOD_MODE_MASK) {
0080 case S3C2412_IISMOD_MODE_TXONLY:
0081 case S3C2412_IISMOD_MODE_TXRX:
0082
0083 break;
0084
0085 case S3C2412_IISMOD_MODE_RXONLY:
0086 mod &= ~S3C2412_IISMOD_MODE_MASK;
0087 mod |= S3C2412_IISMOD_MODE_TXRX;
0088 break;
0089
0090 default:
0091 dev_err(i2s->dev, "TXEN: Invalid MODE %x in IISMOD\n",
0092 mod & S3C2412_IISMOD_MODE_MASK);
0093 break;
0094 }
0095
0096 writel(con, regs + S3C2412_IISCON);
0097 writel(mod, regs + S3C2412_IISMOD);
0098 } else {
0099
0100
0101
0102
0103
0104 con |= S3C2412_IISCON_TXDMA_PAUSE;
0105 con |= S3C2412_IISCON_TXCH_PAUSE;
0106 con &= ~S3C2412_IISCON_TXDMA_ACTIVE;
0107
0108 switch (mod & S3C2412_IISMOD_MODE_MASK) {
0109 case S3C2412_IISMOD_MODE_TXRX:
0110 mod &= ~S3C2412_IISMOD_MODE_MASK;
0111 mod |= S3C2412_IISMOD_MODE_RXONLY;
0112 break;
0113
0114 case S3C2412_IISMOD_MODE_TXONLY:
0115 mod &= ~S3C2412_IISMOD_MODE_MASK;
0116 con &= ~S3C2412_IISCON_IIS_ACTIVE;
0117 break;
0118
0119 default:
0120 dev_err(i2s->dev, "TXDIS: Invalid MODE %x in IISMOD\n",
0121 mod & S3C2412_IISMOD_MODE_MASK);
0122 break;
0123 }
0124
0125 writel(mod, regs + S3C2412_IISMOD);
0126 writel(con, regs + S3C2412_IISCON);
0127 }
0128
0129 fic = readl(regs + S3C2412_IISFIC);
0130 dbg_showcon(__func__, con);
0131 pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
0132 }
0133
0134 static void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
0135 {
0136 void __iomem *regs = i2s->regs;
0137 u32 fic, con, mod;
0138
0139 pr_debug("%s(%d)\n", __func__, on);
0140
0141 fic = readl(regs + S3C2412_IISFIC);
0142 con = readl(regs + S3C2412_IISCON);
0143 mod = readl(regs + S3C2412_IISMOD);
0144
0145 pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
0146
0147 if (on) {
0148 con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
0149 con &= ~S3C2412_IISCON_RXDMA_PAUSE;
0150 con &= ~S3C2412_IISCON_RXCH_PAUSE;
0151
0152 switch (mod & S3C2412_IISMOD_MODE_MASK) {
0153 case S3C2412_IISMOD_MODE_TXRX:
0154 case S3C2412_IISMOD_MODE_RXONLY:
0155
0156 break;
0157
0158 case S3C2412_IISMOD_MODE_TXONLY:
0159 mod &= ~S3C2412_IISMOD_MODE_MASK;
0160 mod |= S3C2412_IISMOD_MODE_TXRX;
0161 break;
0162
0163 default:
0164 dev_err(i2s->dev, "RXEN: Invalid MODE %x in IISMOD\n",
0165 mod & S3C2412_IISMOD_MODE_MASK);
0166 }
0167
0168 writel(mod, regs + S3C2412_IISMOD);
0169 writel(con, regs + S3C2412_IISCON);
0170 } else {
0171
0172
0173 con &= ~S3C2412_IISCON_RXDMA_ACTIVE;
0174 con |= S3C2412_IISCON_RXDMA_PAUSE;
0175 con |= S3C2412_IISCON_RXCH_PAUSE;
0176
0177 switch (mod & S3C2412_IISMOD_MODE_MASK) {
0178 case S3C2412_IISMOD_MODE_RXONLY:
0179 con &= ~S3C2412_IISCON_IIS_ACTIVE;
0180 mod &= ~S3C2412_IISMOD_MODE_MASK;
0181 break;
0182
0183 case S3C2412_IISMOD_MODE_TXRX:
0184 mod &= ~S3C2412_IISMOD_MODE_MASK;
0185 mod |= S3C2412_IISMOD_MODE_TXONLY;
0186 break;
0187
0188 default:
0189 dev_err(i2s->dev, "RXDIS: Invalid MODE %x in IISMOD\n",
0190 mod & S3C2412_IISMOD_MODE_MASK);
0191 }
0192
0193 writel(con, regs + S3C2412_IISCON);
0194 writel(mod, regs + S3C2412_IISMOD);
0195 }
0196
0197 fic = readl(regs + S3C2412_IISFIC);
0198 pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
0199 }
0200
0201 #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
0202
0203
0204
0205
0206
0207 static int s3c2412_snd_lrsync(struct s3c_i2sv2_info *i2s)
0208 {
0209 u32 iiscon;
0210 unsigned long loops = msecs_to_loops(5);
0211
0212 pr_debug("Entered %s\n", __func__);
0213
0214 while (--loops) {
0215 iiscon = readl(i2s->regs + S3C2412_IISCON);
0216 if (iiscon & S3C2412_IISCON_LRINDEX)
0217 break;
0218
0219 cpu_relax();
0220 }
0221
0222 if (!loops) {
0223 printk(KERN_ERR "%s: timeout\n", __func__);
0224 return -ETIMEDOUT;
0225 }
0226
0227 return 0;
0228 }
0229
0230
0231
0232
0233 static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
0234 unsigned int fmt)
0235 {
0236 struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
0237 u32 iismod;
0238
0239 pr_debug("Entered %s\n", __func__);
0240
0241 iismod = readl(i2s->regs + S3C2412_IISMOD);
0242 pr_debug("hw_params r: IISMOD: %x \n", iismod);
0243
0244 switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
0245 case SND_SOC_DAIFMT_BC_FC:
0246 i2s->master = 0;
0247 iismod |= S3C2412_IISMOD_SLAVE;
0248 break;
0249 case SND_SOC_DAIFMT_BP_FP:
0250 i2s->master = 1;
0251 iismod &= ~S3C2412_IISMOD_SLAVE;
0252 break;
0253 default:
0254 pr_err("unknown master/slave format\n");
0255 return -EINVAL;
0256 }
0257
0258 iismod &= ~S3C2412_IISMOD_SDF_MASK;
0259
0260 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
0261 case SND_SOC_DAIFMT_RIGHT_J:
0262 iismod |= S3C2412_IISMOD_LR_RLOW;
0263 iismod |= S3C2412_IISMOD_SDF_MSB;
0264 break;
0265 case SND_SOC_DAIFMT_LEFT_J:
0266 iismod |= S3C2412_IISMOD_LR_RLOW;
0267 iismod |= S3C2412_IISMOD_SDF_LSB;
0268 break;
0269 case SND_SOC_DAIFMT_I2S:
0270 iismod &= ~S3C2412_IISMOD_LR_RLOW;
0271 iismod |= S3C2412_IISMOD_SDF_IIS;
0272 break;
0273 default:
0274 pr_err("Unknown data format\n");
0275 return -EINVAL;
0276 }
0277
0278 writel(iismod, i2s->regs + S3C2412_IISMOD);
0279 pr_debug("hw_params w: IISMOD: %x \n", iismod);
0280 return 0;
0281 }
0282
0283 static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
0284 struct snd_pcm_hw_params *params,
0285 struct snd_soc_dai *dai)
0286 {
0287 struct s3c_i2sv2_info *i2s = to_info(dai);
0288 struct snd_dmaengine_dai_dma_data *dma_data;
0289 u32 iismod;
0290
0291 pr_debug("Entered %s\n", __func__);
0292
0293 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0294 dma_data = i2s->dma_playback;
0295 else
0296 dma_data = i2s->dma_capture;
0297
0298 snd_soc_dai_set_dma_data(dai, substream, dma_data);
0299
0300
0301 iismod = readl(i2s->regs + S3C2412_IISMOD);
0302 pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
0303
0304 iismod &= ~S3C64XX_IISMOD_BLC_MASK;
0305
0306 switch (params_width(params)) {
0307 case 8:
0308 iismod |= S3C64XX_IISMOD_BLC_8BIT;
0309 break;
0310 case 16:
0311 break;
0312 case 24:
0313 iismod |= S3C64XX_IISMOD_BLC_24BIT;
0314 break;
0315 }
0316
0317 writel(iismod, i2s->regs + S3C2412_IISMOD);
0318 pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
0319
0320 return 0;
0321 }
0322
0323 static int s3c_i2sv2_set_sysclk(struct snd_soc_dai *cpu_dai,
0324 int clk_id, unsigned int freq, int dir)
0325 {
0326 struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
0327 u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
0328
0329 pr_debug("Entered %s\n", __func__);
0330 pr_debug("%s r: IISMOD: %x\n", __func__, iismod);
0331
0332 switch (clk_id) {
0333 case S3C_I2SV2_CLKSRC_PCLK:
0334 iismod &= ~S3C2412_IISMOD_IMS_SYSMUX;
0335 break;
0336
0337 case S3C_I2SV2_CLKSRC_AUDIOBUS:
0338 iismod |= S3C2412_IISMOD_IMS_SYSMUX;
0339 break;
0340
0341 case S3C_I2SV2_CLKSRC_CDCLK:
0342
0343 if (!(i2s->feature & S3C_FEATURE_CDCLKCON))
0344 return -EINVAL;
0345
0346 switch (dir) {
0347 case SND_SOC_CLOCK_IN:
0348 iismod |= S3C64XX_IISMOD_CDCLKCON;
0349 break;
0350 case SND_SOC_CLOCK_OUT:
0351 iismod &= ~S3C64XX_IISMOD_CDCLKCON;
0352 break;
0353 default:
0354 return -EINVAL;
0355 }
0356 break;
0357
0358 default:
0359 return -EINVAL;
0360 }
0361
0362 writel(iismod, i2s->regs + S3C2412_IISMOD);
0363 pr_debug("%s w: IISMOD: %x\n", __func__, iismod);
0364
0365 return 0;
0366 }
0367
0368 static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
0369 struct snd_soc_dai *dai)
0370 {
0371 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0372 struct s3c_i2sv2_info *i2s = to_info(asoc_rtd_to_cpu(rtd, 0));
0373 int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
0374 unsigned long irqs;
0375 int ret = 0;
0376
0377 pr_debug("Entered %s\n", __func__);
0378
0379 switch (cmd) {
0380 case SNDRV_PCM_TRIGGER_START:
0381
0382
0383 writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH,
0384 i2s->regs + S3C2412_IISFIC);
0385
0386
0387 writel(0x0, i2s->regs + S3C2412_IISFIC);
0388
0389 fallthrough;
0390
0391 case SNDRV_PCM_TRIGGER_RESUME:
0392 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0393 if (!i2s->master) {
0394 ret = s3c2412_snd_lrsync(i2s);
0395 if (ret)
0396 goto exit_err;
0397 }
0398
0399 local_irq_save(irqs);
0400
0401 if (capture)
0402 s3c2412_snd_rxctrl(i2s, 1);
0403 else
0404 s3c2412_snd_txctrl(i2s, 1);
0405
0406 local_irq_restore(irqs);
0407
0408 break;
0409
0410 case SNDRV_PCM_TRIGGER_STOP:
0411 case SNDRV_PCM_TRIGGER_SUSPEND:
0412 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0413 local_irq_save(irqs);
0414
0415 if (capture)
0416 s3c2412_snd_rxctrl(i2s, 0);
0417 else
0418 s3c2412_snd_txctrl(i2s, 0);
0419
0420 local_irq_restore(irqs);
0421 break;
0422 default:
0423 ret = -EINVAL;
0424 break;
0425 }
0426
0427 exit_err:
0428 return ret;
0429 }
0430
0431
0432
0433
0434 static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
0435 int div_id, int div)
0436 {
0437 struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
0438 u32 reg;
0439
0440 pr_debug("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
0441
0442 switch (div_id) {
0443 case S3C_I2SV2_DIV_BCLK:
0444 switch (div) {
0445 case 16:
0446 div = S3C2412_IISMOD_BCLK_16FS;
0447 break;
0448
0449 case 32:
0450 div = S3C2412_IISMOD_BCLK_32FS;
0451 break;
0452
0453 case 24:
0454 div = S3C2412_IISMOD_BCLK_24FS;
0455 break;
0456
0457 case 48:
0458 div = S3C2412_IISMOD_BCLK_48FS;
0459 break;
0460
0461 default:
0462 return -EINVAL;
0463 }
0464
0465 reg = readl(i2s->regs + S3C2412_IISMOD);
0466 reg &= ~S3C2412_IISMOD_BCLK_MASK;
0467 writel(reg | div, i2s->regs + S3C2412_IISMOD);
0468
0469 pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
0470 break;
0471
0472 case S3C_I2SV2_DIV_RCLK:
0473 switch (div) {
0474 case 256:
0475 div = S3C2412_IISMOD_RCLK_256FS;
0476 break;
0477
0478 case 384:
0479 div = S3C2412_IISMOD_RCLK_384FS;
0480 break;
0481
0482 case 512:
0483 div = S3C2412_IISMOD_RCLK_512FS;
0484 break;
0485
0486 case 768:
0487 div = S3C2412_IISMOD_RCLK_768FS;
0488 break;
0489
0490 default:
0491 return -EINVAL;
0492 }
0493
0494 reg = readl(i2s->regs + S3C2412_IISMOD);
0495 reg &= ~S3C2412_IISMOD_RCLK_MASK;
0496 writel(reg | div, i2s->regs + S3C2412_IISMOD);
0497 pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
0498 break;
0499
0500 case S3C_I2SV2_DIV_PRESCALER:
0501 if (div >= 0) {
0502 writel((div << 8) | S3C2412_IISPSR_PSREN,
0503 i2s->regs + S3C2412_IISPSR);
0504 } else {
0505 writel(0x0, i2s->regs + S3C2412_IISPSR);
0506 }
0507 pr_debug("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR));
0508 break;
0509
0510 default:
0511 return -EINVAL;
0512 }
0513
0514 return 0;
0515 }
0516
0517 static snd_pcm_sframes_t s3c2412_i2s_delay(struct snd_pcm_substream *substream,
0518 struct snd_soc_dai *dai)
0519 {
0520 struct s3c_i2sv2_info *i2s = to_info(dai);
0521 u32 reg = readl(i2s->regs + S3C2412_IISFIC);
0522 snd_pcm_sframes_t delay;
0523
0524 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0525 delay = S3C2412_IISFIC_TXCOUNT(reg);
0526 else
0527 delay = S3C2412_IISFIC_RXCOUNT(reg);
0528
0529 return delay;
0530 }
0531
0532 struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai)
0533 {
0534 struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
0535 u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
0536
0537 if (iismod & S3C2412_IISMOD_IMS_SYSMUX)
0538 return i2s->iis_cclk;
0539 else
0540 return i2s->iis_pclk;
0541 }
0542 EXPORT_SYMBOL_GPL(s3c_i2sv2_get_clock);
0543
0544
0545 static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 };
0546
0547 int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
0548 unsigned int *fstab,
0549 unsigned int rate, struct clk *clk)
0550 {
0551 unsigned long clkrate = clk_get_rate(clk);
0552 unsigned int div;
0553 unsigned int fsclk;
0554 unsigned int actual;
0555 unsigned int fs;
0556 unsigned int fsdiv;
0557 signed int deviation = 0;
0558 unsigned int best_fs = 0;
0559 unsigned int best_div = 0;
0560 unsigned int best_rate = 0;
0561 unsigned int best_deviation = INT_MAX;
0562
0563 pr_debug("Input clock rate %ldHz\n", clkrate);
0564
0565 if (fstab == NULL)
0566 fstab = iis_fs_tab;
0567
0568 for (fs = 0; fs < ARRAY_SIZE(iis_fs_tab); fs++) {
0569 fsdiv = iis_fs_tab[fs];
0570
0571 fsclk = clkrate / fsdiv;
0572 div = fsclk / rate;
0573
0574 if ((fsclk % rate) > (rate / 2))
0575 div++;
0576
0577 if (div <= 1)
0578 continue;
0579
0580 actual = clkrate / (fsdiv * div);
0581 deviation = actual - rate;
0582
0583 printk(KERN_DEBUG "%ufs: div %u => result %u, deviation %d\n",
0584 fsdiv, div, actual, deviation);
0585
0586 deviation = abs(deviation);
0587
0588 if (deviation < best_deviation) {
0589 best_fs = fsdiv;
0590 best_div = div;
0591 best_rate = actual;
0592 best_deviation = deviation;
0593 }
0594
0595 if (deviation == 0)
0596 break;
0597 }
0598
0599 printk(KERN_DEBUG "best: fs=%u, div=%u, rate=%u\n",
0600 best_fs, best_div, best_rate);
0601
0602 info->fs_div = best_fs;
0603 info->clk_div = best_div;
0604
0605 return 0;
0606 }
0607 EXPORT_SYMBOL_GPL(s3c_i2sv2_iis_calc_rate);
0608
0609 int s3c_i2sv2_probe(struct snd_soc_dai *dai,
0610 struct s3c_i2sv2_info *i2s)
0611 {
0612 struct device *dev = dai->dev;
0613 unsigned int iismod;
0614
0615 i2s->dev = dev;
0616
0617
0618 snd_soc_dai_set_drvdata(dai, i2s);
0619
0620 i2s->iis_pclk = clk_get(dev, "iis");
0621 if (IS_ERR(i2s->iis_pclk)) {
0622 dev_err(dev, "failed to get iis_clock\n");
0623 return -ENOENT;
0624 }
0625
0626 clk_prepare_enable(i2s->iis_pclk);
0627
0628
0629
0630 iismod = readl(i2s->regs + S3C2412_IISMOD);
0631 iismod |= S3C2412_IISMOD_MODE_TXRX;
0632 writel(iismod, i2s->regs + S3C2412_IISMOD);
0633 s3c2412_snd_txctrl(i2s, 0);
0634 s3c2412_snd_rxctrl(i2s, 0);
0635
0636 return 0;
0637 }
0638 EXPORT_SYMBOL_GPL(s3c_i2sv2_probe);
0639
0640 void s3c_i2sv2_cleanup(struct snd_soc_dai *dai,
0641 struct s3c_i2sv2_info *i2s)
0642 {
0643 clk_disable_unprepare(i2s->iis_pclk);
0644 clk_put(i2s->iis_pclk);
0645 i2s->iis_pclk = NULL;
0646 }
0647 EXPORT_SYMBOL_GPL(s3c_i2sv2_cleanup);
0648
0649 int s3c_i2sv2_register_component(struct device *dev, int id,
0650 const struct snd_soc_component_driver *cmp_drv,
0651 struct snd_soc_dai_driver *dai_drv)
0652 {
0653 struct snd_soc_dai_ops *ops = (struct snd_soc_dai_ops *)dai_drv->ops;
0654
0655 ops->trigger = s3c2412_i2s_trigger;
0656 if (!ops->hw_params)
0657 ops->hw_params = s3c_i2sv2_hw_params;
0658 ops->set_fmt = s3c2412_i2s_set_fmt;
0659 ops->set_clkdiv = s3c2412_i2s_set_clkdiv;
0660 ops->set_sysclk = s3c_i2sv2_set_sysclk;
0661
0662
0663 if (!ops->delay)
0664 ops->delay = s3c2412_i2s_delay;
0665
0666 return devm_snd_soc_register_component(dev, cmp_drv, dai_drv, 1);
0667 }
0668 EXPORT_SYMBOL_GPL(s3c_i2sv2_register_component);
0669
0670 MODULE_LICENSE("GPL");