0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <linux/init.h>
0016 #include <linux/module.h>
0017 #include <linux/device.h>
0018 #include <linux/slab.h>
0019 #include <linux/delay.h>
0020 #include <linux/io.h>
0021 #include <linux/clk.h>
0022 #include <linux/platform_data/davinci_asp.h>
0023
0024 #include <sound/core.h>
0025 #include <sound/pcm.h>
0026 #include <sound/pcm_params.h>
0027 #include <sound/initval.h>
0028 #include <sound/soc.h>
0029 #include <sound/dmaengine_pcm.h>
0030
0031 #include "edma-pcm.h"
0032 #include "davinci-i2s.h"
0033
0034 #define DRV_NAME "davinci-i2s"
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055 #define DAVINCI_MCBSP_DRR_REG 0x00
0056 #define DAVINCI_MCBSP_DXR_REG 0x04
0057 #define DAVINCI_MCBSP_SPCR_REG 0x08
0058 #define DAVINCI_MCBSP_RCR_REG 0x0c
0059 #define DAVINCI_MCBSP_XCR_REG 0x10
0060 #define DAVINCI_MCBSP_SRGR_REG 0x14
0061 #define DAVINCI_MCBSP_PCR_REG 0x24
0062
0063 #define DAVINCI_MCBSP_SPCR_RRST (1 << 0)
0064 #define DAVINCI_MCBSP_SPCR_RINTM(v) ((v) << 4)
0065 #define DAVINCI_MCBSP_SPCR_XRST (1 << 16)
0066 #define DAVINCI_MCBSP_SPCR_XINTM(v) ((v) << 20)
0067 #define DAVINCI_MCBSP_SPCR_GRST (1 << 22)
0068 #define DAVINCI_MCBSP_SPCR_FRST (1 << 23)
0069 #define DAVINCI_MCBSP_SPCR_FREE (1 << 25)
0070
0071 #define DAVINCI_MCBSP_RCR_RWDLEN1(v) ((v) << 5)
0072 #define DAVINCI_MCBSP_RCR_RFRLEN1(v) ((v) << 8)
0073 #define DAVINCI_MCBSP_RCR_RDATDLY(v) ((v) << 16)
0074 #define DAVINCI_MCBSP_RCR_RFIG (1 << 18)
0075 #define DAVINCI_MCBSP_RCR_RWDLEN2(v) ((v) << 21)
0076 #define DAVINCI_MCBSP_RCR_RFRLEN2(v) ((v) << 24)
0077 #define DAVINCI_MCBSP_RCR_RPHASE BIT(31)
0078
0079 #define DAVINCI_MCBSP_XCR_XWDLEN1(v) ((v) << 5)
0080 #define DAVINCI_MCBSP_XCR_XFRLEN1(v) ((v) << 8)
0081 #define DAVINCI_MCBSP_XCR_XDATDLY(v) ((v) << 16)
0082 #define DAVINCI_MCBSP_XCR_XFIG (1 << 18)
0083 #define DAVINCI_MCBSP_XCR_XWDLEN2(v) ((v) << 21)
0084 #define DAVINCI_MCBSP_XCR_XFRLEN2(v) ((v) << 24)
0085 #define DAVINCI_MCBSP_XCR_XPHASE BIT(31)
0086
0087 #define DAVINCI_MCBSP_SRGR_FWID(v) ((v) << 8)
0088 #define DAVINCI_MCBSP_SRGR_FPER(v) ((v) << 16)
0089 #define DAVINCI_MCBSP_SRGR_FSGM (1 << 28)
0090 #define DAVINCI_MCBSP_SRGR_CLKSM BIT(29)
0091
0092 #define DAVINCI_MCBSP_PCR_CLKRP (1 << 0)
0093 #define DAVINCI_MCBSP_PCR_CLKXP (1 << 1)
0094 #define DAVINCI_MCBSP_PCR_FSRP (1 << 2)
0095 #define DAVINCI_MCBSP_PCR_FSXP (1 << 3)
0096 #define DAVINCI_MCBSP_PCR_SCLKME (1 << 7)
0097 #define DAVINCI_MCBSP_PCR_CLKRM (1 << 8)
0098 #define DAVINCI_MCBSP_PCR_CLKXM (1 << 9)
0099 #define DAVINCI_MCBSP_PCR_FSRM (1 << 10)
0100 #define DAVINCI_MCBSP_PCR_FSXM (1 << 11)
0101
0102 enum {
0103 DAVINCI_MCBSP_WORD_8 = 0,
0104 DAVINCI_MCBSP_WORD_12,
0105 DAVINCI_MCBSP_WORD_16,
0106 DAVINCI_MCBSP_WORD_20,
0107 DAVINCI_MCBSP_WORD_24,
0108 DAVINCI_MCBSP_WORD_32,
0109 };
0110
0111 static const unsigned char data_type[SNDRV_PCM_FORMAT_S32_LE + 1] = {
0112 [SNDRV_PCM_FORMAT_S8] = 1,
0113 [SNDRV_PCM_FORMAT_S16_LE] = 2,
0114 [SNDRV_PCM_FORMAT_S32_LE] = 4,
0115 };
0116
0117 static const unsigned char asp_word_length[SNDRV_PCM_FORMAT_S32_LE + 1] = {
0118 [SNDRV_PCM_FORMAT_S8] = DAVINCI_MCBSP_WORD_8,
0119 [SNDRV_PCM_FORMAT_S16_LE] = DAVINCI_MCBSP_WORD_16,
0120 [SNDRV_PCM_FORMAT_S32_LE] = DAVINCI_MCBSP_WORD_32,
0121 };
0122
0123 static const unsigned char double_fmt[SNDRV_PCM_FORMAT_S32_LE + 1] = {
0124 [SNDRV_PCM_FORMAT_S8] = SNDRV_PCM_FORMAT_S16_LE,
0125 [SNDRV_PCM_FORMAT_S16_LE] = SNDRV_PCM_FORMAT_S32_LE,
0126 };
0127
0128 struct davinci_mcbsp_dev {
0129 struct device *dev;
0130 struct snd_dmaengine_dai_dma_data dma_data[2];
0131 int dma_request[2];
0132 void __iomem *base;
0133 #define MOD_DSP_A 0
0134 #define MOD_DSP_B 1
0135 int mode;
0136 u32 pcr;
0137 struct clk *clk;
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158 unsigned enable_channel_combine:1;
0159
0160 unsigned int fmt;
0161 int clk_div;
0162 int clk_input_pin;
0163 bool i2s_accurate_sck;
0164 };
0165
0166 static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev,
0167 int reg, u32 val)
0168 {
0169 __raw_writel(val, dev->base + reg);
0170 }
0171
0172 static inline u32 davinci_mcbsp_read_reg(struct davinci_mcbsp_dev *dev, int reg)
0173 {
0174 return __raw_readl(dev->base + reg);
0175 }
0176
0177 static void toggle_clock(struct davinci_mcbsp_dev *dev, int playback)
0178 {
0179 u32 m = playback ? DAVINCI_MCBSP_PCR_CLKXP : DAVINCI_MCBSP_PCR_CLKRP;
0180
0181
0182
0183 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, dev->pcr ^ m);
0184 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, dev->pcr);
0185 }
0186
0187 static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev,
0188 struct snd_pcm_substream *substream)
0189 {
0190 int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
0191 u32 spcr;
0192 u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST;
0193
0194
0195 spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
0196 spcr |= mask;
0197
0198 if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM)) {
0199
0200 spcr |= DAVINCI_MCBSP_SPCR_FRST;
0201 }
0202 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
0203 }
0204
0205 static void davinci_mcbsp_stop(struct davinci_mcbsp_dev *dev, int playback)
0206 {
0207 u32 spcr;
0208
0209
0210 spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
0211 spcr &= ~(DAVINCI_MCBSP_SPCR_GRST | DAVINCI_MCBSP_SPCR_FRST);
0212 spcr &= playback ? ~DAVINCI_MCBSP_SPCR_XRST : ~DAVINCI_MCBSP_SPCR_RRST;
0213 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
0214 toggle_clock(dev, playback);
0215 }
0216
0217 #define DEFAULT_BITPERSAMPLE 16
0218
0219 static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
0220 unsigned int fmt)
0221 {
0222 struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
0223 unsigned int pcr;
0224 unsigned int srgr;
0225 bool inv_fs = false;
0226
0227 srgr = DAVINCI_MCBSP_SRGR_FSGM |
0228 DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) |
0229 DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1);
0230
0231 dev->fmt = fmt;
0232
0233 switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
0234 case SND_SOC_DAIFMT_BP_FP:
0235
0236 pcr = DAVINCI_MCBSP_PCR_FSXM |
0237 DAVINCI_MCBSP_PCR_FSRM |
0238 DAVINCI_MCBSP_PCR_CLKXM |
0239 DAVINCI_MCBSP_PCR_CLKRM;
0240 break;
0241 case SND_SOC_DAIFMT_BC_FP:
0242 pcr = DAVINCI_MCBSP_PCR_FSRM | DAVINCI_MCBSP_PCR_FSXM;
0243
0244
0245
0246
0247
0248
0249 switch (dev->clk_input_pin) {
0250 case MCBSP_CLKS:
0251 pcr |= DAVINCI_MCBSP_PCR_CLKXM |
0252 DAVINCI_MCBSP_PCR_CLKRM;
0253 break;
0254 case MCBSP_CLKR:
0255 pcr |= DAVINCI_MCBSP_PCR_SCLKME;
0256 break;
0257 default:
0258 dev_err(dev->dev, "bad clk_input_pin\n");
0259 return -EINVAL;
0260 }
0261
0262 break;
0263 case SND_SOC_DAIFMT_BC_FC:
0264
0265 pcr = 0;
0266 break;
0267 default:
0268 printk(KERN_ERR "%s:bad master\n", __func__);
0269 return -EINVAL;
0270 }
0271
0272
0273 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
0274 case SND_SOC_DAIFMT_I2S:
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291 inv_fs = true;
0292 fallthrough;
0293 case SND_SOC_DAIFMT_DSP_A:
0294 dev->mode = MOD_DSP_A;
0295 break;
0296 case SND_SOC_DAIFMT_DSP_B:
0297 dev->mode = MOD_DSP_B;
0298 break;
0299 default:
0300 printk(KERN_ERR "%s:bad format\n", __func__);
0301 return -EINVAL;
0302 }
0303
0304 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
0305 case SND_SOC_DAIFMT_NB_NF:
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315 pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP);
0316 break;
0317 case SND_SOC_DAIFMT_IB_IF:
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327 pcr |= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP);
0328 break;
0329 case SND_SOC_DAIFMT_NB_IF:
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339 pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP |
0340 DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP);
0341 break;
0342 case SND_SOC_DAIFMT_IB_NF:
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352 break;
0353 default:
0354 return -EINVAL;
0355 }
0356 if (inv_fs == true)
0357 pcr ^= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP);
0358 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr);
0359 dev->pcr = pcr;
0360 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, pcr);
0361 return 0;
0362 }
0363
0364 static int davinci_i2s_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
0365 int div_id, int div)
0366 {
0367 struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
0368
0369 if (div_id != DAVINCI_MCBSP_CLKGDV)
0370 return -ENODEV;
0371
0372 dev->clk_div = div;
0373 return 0;
0374 }
0375
0376 static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
0377 struct snd_pcm_hw_params *params,
0378 struct snd_soc_dai *dai)
0379 {
0380 struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
0381 struct snd_interval *i = NULL;
0382 int mcbsp_word_length, master;
0383 unsigned int rcr, xcr, srgr, clk_div, freq, framesize;
0384 u32 spcr;
0385 snd_pcm_format_t fmt;
0386 unsigned element_cnt = 1;
0387
0388
0389 spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
0390 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
0391 spcr |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE;
0392 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
0393 } else {
0394 spcr |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE;
0395 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
0396 }
0397
0398 master = dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
0399 fmt = params_format(params);
0400 mcbsp_word_length = asp_word_length[fmt];
0401
0402 switch (master) {
0403 case SND_SOC_DAIFMT_BP_FP:
0404 freq = clk_get_rate(dev->clk);
0405 srgr = DAVINCI_MCBSP_SRGR_FSGM |
0406 DAVINCI_MCBSP_SRGR_CLKSM;
0407 srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length *
0408 8 - 1);
0409 if (dev->i2s_accurate_sck) {
0410 clk_div = 256;
0411 do {
0412 framesize = (freq / (--clk_div)) /
0413 params->rate_num *
0414 params->rate_den;
0415 } while (((framesize < 33) || (framesize > 4095)) &&
0416 (clk_div));
0417 clk_div--;
0418 srgr |= DAVINCI_MCBSP_SRGR_FPER(framesize - 1);
0419 } else {
0420
0421 clk_div = freq / (mcbsp_word_length * 16) /
0422 params->rate_num * params->rate_den;
0423 srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length *
0424 16 - 1);
0425 }
0426 clk_div &= 0xFF;
0427 srgr |= clk_div;
0428 break;
0429 case SND_SOC_DAIFMT_BC_FP:
0430 srgr = DAVINCI_MCBSP_SRGR_FSGM;
0431 clk_div = dev->clk_div - 1;
0432 srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 8 - 1);
0433 srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length * 16 - 1);
0434 clk_div &= 0xFF;
0435 srgr |= clk_div;
0436 break;
0437 case SND_SOC_DAIFMT_BC_FC:
0438
0439 i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
0440 srgr = DAVINCI_MCBSP_SRGR_FSGM;
0441 srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1);
0442 pr_debug("%s - %d FWID set: re-read srgr = %X\n",
0443 __func__, __LINE__, snd_interval_value(i) - 1);
0444
0445 i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS);
0446 srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1);
0447 break;
0448 default:
0449 return -EINVAL;
0450 }
0451 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr);
0452
0453 rcr = DAVINCI_MCBSP_RCR_RFIG;
0454 xcr = DAVINCI_MCBSP_XCR_XFIG;
0455 if (dev->mode == MOD_DSP_B) {
0456 rcr |= DAVINCI_MCBSP_RCR_RDATDLY(0);
0457 xcr |= DAVINCI_MCBSP_XCR_XDATDLY(0);
0458 } else {
0459 rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1);
0460 xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1);
0461 }
0462
0463 fmt = params_format(params);
0464 if ((fmt > SNDRV_PCM_FORMAT_S32_LE) || !data_type[fmt]) {
0465 printk(KERN_WARNING "davinci-i2s: unsupported PCM format\n");
0466 return -EINVAL;
0467 }
0468
0469 if (params_channels(params) == 2) {
0470 element_cnt = 2;
0471 if (double_fmt[fmt] && dev->enable_channel_combine) {
0472 element_cnt = 1;
0473 fmt = double_fmt[fmt];
0474 }
0475 switch (master) {
0476 case SND_SOC_DAIFMT_BP_FP:
0477 case SND_SOC_DAIFMT_BP_FC:
0478 rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(0);
0479 xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(0);
0480 rcr |= DAVINCI_MCBSP_RCR_RPHASE;
0481 xcr |= DAVINCI_MCBSP_XCR_XPHASE;
0482 break;
0483 case SND_SOC_DAIFMT_BC_FC:
0484 case SND_SOC_DAIFMT_BC_FP:
0485 rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(element_cnt - 1);
0486 xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(element_cnt - 1);
0487 break;
0488 default:
0489 return -EINVAL;
0490 }
0491 }
0492 mcbsp_word_length = asp_word_length[fmt];
0493
0494 switch (master) {
0495 case SND_SOC_DAIFMT_BP_FP:
0496 case SND_SOC_DAIFMT_BP_FC:
0497 rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(0);
0498 xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(0);
0499 break;
0500 case SND_SOC_DAIFMT_BC_FC:
0501 case SND_SOC_DAIFMT_BC_FP:
0502 rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1);
0503 xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1);
0504 break;
0505 default:
0506 return -EINVAL;
0507 }
0508
0509 rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) |
0510 DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length);
0511 xcr |= DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) |
0512 DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length);
0513
0514 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0515 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr);
0516 else
0517 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr);
0518
0519 pr_debug("%s - %d srgr=%X\n", __func__, __LINE__, srgr);
0520 pr_debug("%s - %d xcr=%X\n", __func__, __LINE__, xcr);
0521 pr_debug("%s - %d rcr=%X\n", __func__, __LINE__, rcr);
0522 return 0;
0523 }
0524
0525 static int davinci_i2s_prepare(struct snd_pcm_substream *substream,
0526 struct snd_soc_dai *dai)
0527 {
0528 struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
0529 int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
0530 u32 spcr;
0531 u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST;
0532
0533 davinci_mcbsp_stop(dev, playback);
0534
0535 spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
0536 if (spcr & mask) {
0537
0538 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG,
0539 spcr & ~mask);
0540 toggle_clock(dev, playback);
0541 }
0542 if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM |
0543 DAVINCI_MCBSP_PCR_CLKXM | DAVINCI_MCBSP_PCR_CLKRM)) {
0544
0545 spcr |= DAVINCI_MCBSP_SPCR_GRST;
0546 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
0547 }
0548
0549 if (playback) {
0550
0551 spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
0552 spcr |= DAVINCI_MCBSP_SPCR_XRST;
0553 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
0554
0555
0556 udelay(100);
0557
0558
0559 spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
0560 spcr &= ~DAVINCI_MCBSP_SPCR_XRST;
0561 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
0562 toggle_clock(dev, playback);
0563 }
0564
0565 return 0;
0566 }
0567
0568 static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
0569 struct snd_soc_dai *dai)
0570 {
0571 struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
0572 int ret = 0;
0573 int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
0574
0575 switch (cmd) {
0576 case SNDRV_PCM_TRIGGER_START:
0577 case SNDRV_PCM_TRIGGER_RESUME:
0578 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0579 davinci_mcbsp_start(dev, substream);
0580 break;
0581 case SNDRV_PCM_TRIGGER_STOP:
0582 case SNDRV_PCM_TRIGGER_SUSPEND:
0583 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0584 davinci_mcbsp_stop(dev, playback);
0585 break;
0586 default:
0587 ret = -EINVAL;
0588 }
0589 return ret;
0590 }
0591
0592 static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
0593 struct snd_soc_dai *dai)
0594 {
0595 struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
0596 int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
0597 davinci_mcbsp_stop(dev, playback);
0598 }
0599
0600 #define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000
0601 #define DAVINCI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
0602 SNDRV_PCM_FMTBIT_S32_LE)
0603
0604 static const struct snd_soc_dai_ops davinci_i2s_dai_ops = {
0605 .shutdown = davinci_i2s_shutdown,
0606 .prepare = davinci_i2s_prepare,
0607 .trigger = davinci_i2s_trigger,
0608 .hw_params = davinci_i2s_hw_params,
0609 .set_fmt = davinci_i2s_set_dai_fmt,
0610 .set_clkdiv = davinci_i2s_dai_set_clkdiv,
0611
0612 };
0613
0614 static int davinci_i2s_dai_probe(struct snd_soc_dai *dai)
0615 {
0616 struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
0617
0618 dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
0619 dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE];
0620
0621 return 0;
0622 }
0623
0624 static struct snd_soc_dai_driver davinci_i2s_dai = {
0625 .probe = davinci_i2s_dai_probe,
0626 .playback = {
0627 .channels_min = 2,
0628 .channels_max = 2,
0629 .rates = DAVINCI_I2S_RATES,
0630 .formats = DAVINCI_I2S_FORMATS,
0631 },
0632 .capture = {
0633 .channels_min = 2,
0634 .channels_max = 2,
0635 .rates = DAVINCI_I2S_RATES,
0636 .formats = DAVINCI_I2S_FORMATS,
0637 },
0638 .ops = &davinci_i2s_dai_ops,
0639
0640 };
0641
0642 static const struct snd_soc_component_driver davinci_i2s_component = {
0643 .name = DRV_NAME,
0644 .legacy_dai_naming = 1,
0645 };
0646
0647 static int davinci_i2s_probe(struct platform_device *pdev)
0648 {
0649 struct snd_dmaengine_dai_dma_data *dma_data;
0650 struct davinci_mcbsp_dev *dev;
0651 struct resource *mem, *res;
0652 void __iomem *io_base;
0653 int *dma;
0654 int ret;
0655
0656 mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
0657 if (!mem) {
0658 dev_warn(&pdev->dev,
0659 "\"mpu\" mem resource not found, using index 0\n");
0660 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0661 if (!mem) {
0662 dev_err(&pdev->dev, "no mem resource?\n");
0663 return -ENODEV;
0664 }
0665 }
0666
0667 io_base = devm_ioremap_resource(&pdev->dev, mem);
0668 if (IS_ERR(io_base))
0669 return PTR_ERR(io_base);
0670
0671 dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcbsp_dev),
0672 GFP_KERNEL);
0673 if (!dev)
0674 return -ENOMEM;
0675
0676 dev->base = io_base;
0677
0678
0679 dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
0680 dma_data->addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG);
0681
0682 res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
0683 if (res) {
0684 dma = &dev->dma_request[SNDRV_PCM_STREAM_PLAYBACK];
0685 *dma = res->start;
0686 dma_data->filter_data = dma;
0687 } else if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
0688 dma_data->filter_data = "tx";
0689 } else {
0690 dev_err(&pdev->dev, "Missing DMA tx resource\n");
0691 return -ENODEV;
0692 }
0693
0694 dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE];
0695 dma_data->addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DRR_REG);
0696
0697 res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
0698 if (res) {
0699 dma = &dev->dma_request[SNDRV_PCM_STREAM_CAPTURE];
0700 *dma = res->start;
0701 dma_data->filter_data = dma;
0702 } else if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
0703 dma_data->filter_data = "rx";
0704 } else {
0705 dev_err(&pdev->dev, "Missing DMA rx resource\n");
0706 return -ENODEV;
0707 }
0708
0709 dev->clk = clk_get(&pdev->dev, NULL);
0710 if (IS_ERR(dev->clk))
0711 return -ENODEV;
0712 ret = clk_enable(dev->clk);
0713 if (ret)
0714 goto err_put_clk;
0715
0716 dev->dev = &pdev->dev;
0717 dev_set_drvdata(&pdev->dev, dev);
0718
0719 ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component,
0720 &davinci_i2s_dai, 1);
0721 if (ret != 0)
0722 goto err_release_clk;
0723
0724 ret = edma_pcm_platform_register(&pdev->dev);
0725 if (ret) {
0726 dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
0727 goto err_unregister_component;
0728 }
0729
0730 return 0;
0731
0732 err_unregister_component:
0733 snd_soc_unregister_component(&pdev->dev);
0734 err_release_clk:
0735 clk_disable(dev->clk);
0736 err_put_clk:
0737 clk_put(dev->clk);
0738 return ret;
0739 }
0740
0741 static int davinci_i2s_remove(struct platform_device *pdev)
0742 {
0743 struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev);
0744
0745 snd_soc_unregister_component(&pdev->dev);
0746
0747 clk_disable(dev->clk);
0748 clk_put(dev->clk);
0749 dev->clk = NULL;
0750
0751 return 0;
0752 }
0753
0754 static const struct of_device_id davinci_i2s_match[] __maybe_unused = {
0755 { .compatible = "ti,da850-mcbsp" },
0756 {},
0757 };
0758 MODULE_DEVICE_TABLE(of, davinci_i2s_match);
0759
0760 static struct platform_driver davinci_mcbsp_driver = {
0761 .probe = davinci_i2s_probe,
0762 .remove = davinci_i2s_remove,
0763 .driver = {
0764 .name = "davinci-mcbsp",
0765 .of_match_table = of_match_ptr(davinci_i2s_match),
0766 },
0767 };
0768
0769 module_platform_driver(davinci_mcbsp_driver);
0770
0771 MODULE_AUTHOR("Vladimir Barinov");
0772 MODULE_DESCRIPTION("TI DAVINCI I2S (McBSP) SoC Interface");
0773 MODULE_LICENSE("GPL");