1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2f2055e14SPeter Ujfalusi /* 3f2055e14SPeter Ujfalusi * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor 4f2055e14SPeter Ujfalusi * 5f2055e14SPeter Ujfalusi * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> 6f2055e14SPeter Ujfalusi * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> 7f2055e14SPeter Ujfalusi * 8f2055e14SPeter Ujfalusi * DT support (c) 2016 Petr Kulhavy, Barix AG <petr@barix.com> 9f2055e14SPeter Ujfalusi * based on davinci-mcasp.c DT support 10f2055e14SPeter Ujfalusi * 11f2055e14SPeter Ujfalusi * TODO: 12f2055e14SPeter Ujfalusi * on DA850 implement HW FIFOs instead of DMA into DXR and DRR registers 13f2055e14SPeter Ujfalusi */ 14f2055e14SPeter Ujfalusi 15f2055e14SPeter Ujfalusi #include <linux/init.h> 16f2055e14SPeter Ujfalusi #include <linux/module.h> 17f2055e14SPeter Ujfalusi #include <linux/device.h> 18f2055e14SPeter Ujfalusi #include <linux/slab.h> 19f2055e14SPeter Ujfalusi #include <linux/delay.h> 20f2055e14SPeter Ujfalusi #include <linux/io.h> 21f2055e14SPeter Ujfalusi #include <linux/clk.h> 22f2055e14SPeter Ujfalusi #include <linux/platform_data/davinci_asp.h> 23f2055e14SPeter Ujfalusi 24f2055e14SPeter Ujfalusi #include <sound/core.h> 25f2055e14SPeter Ujfalusi #include <sound/pcm.h> 26f2055e14SPeter Ujfalusi #include <sound/pcm_params.h> 27f2055e14SPeter Ujfalusi #include <sound/initval.h> 28f2055e14SPeter Ujfalusi #include <sound/soc.h> 29f2055e14SPeter Ujfalusi #include <sound/dmaengine_pcm.h> 30f2055e14SPeter Ujfalusi 31f2055e14SPeter Ujfalusi #include "edma-pcm.h" 32f2055e14SPeter Ujfalusi #include "davinci-i2s.h" 33f2055e14SPeter Ujfalusi 34f2055e14SPeter Ujfalusi #define DRV_NAME "davinci-i2s" 35f2055e14SPeter Ujfalusi 36f2055e14SPeter Ujfalusi /* 37f2055e14SPeter Ujfalusi * NOTE: terminology here is confusing. 38f2055e14SPeter Ujfalusi * 39f2055e14SPeter Ujfalusi * - This driver supports the "Audio Serial Port" (ASP), 40f2055e14SPeter Ujfalusi * found on dm6446, dm355, and other DaVinci chips. 41f2055e14SPeter Ujfalusi * 42f2055e14SPeter Ujfalusi * - But it labels it a "Multi-channel Buffered Serial Port" 43f2055e14SPeter Ujfalusi * (McBSP) as on older chips like the dm642 ... which was 44f2055e14SPeter Ujfalusi * backward-compatible, possibly explaining that confusion. 45f2055e14SPeter Ujfalusi * 46f2055e14SPeter Ujfalusi * - OMAP chips have a controller called McBSP, which is 47f2055e14SPeter Ujfalusi * incompatible with the DaVinci flavor of McBSP. 48f2055e14SPeter Ujfalusi * 49f2055e14SPeter Ujfalusi * - Newer DaVinci chips have a controller called McASP, 50f2055e14SPeter Ujfalusi * incompatible with ASP and with either McBSP. 51f2055e14SPeter Ujfalusi * 52f2055e14SPeter Ujfalusi * In short: this uses ASP to implement I2S, not McBSP. 53f2055e14SPeter Ujfalusi * And it won't be the only DaVinci implemention of I2S. 54f2055e14SPeter Ujfalusi */ 55f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_DRR_REG 0x00 56f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_DXR_REG 0x04 57f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SPCR_REG 0x08 58f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_RCR_REG 0x0c 59f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_XCR_REG 0x10 60f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SRGR_REG 0x14 61f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_REG 0x24 62f2055e14SPeter Ujfalusi 63f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SPCR_RRST (1 << 0) 64f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SPCR_RINTM(v) ((v) << 4) 65f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SPCR_XRST (1 << 16) 66f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SPCR_XINTM(v) ((v) << 20) 67f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SPCR_GRST (1 << 22) 68f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SPCR_FRST (1 << 23) 69f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SPCR_FREE (1 << 25) 70f2055e14SPeter Ujfalusi 71f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_RCR_RWDLEN1(v) ((v) << 5) 72f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_RCR_RFRLEN1(v) ((v) << 8) 73f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_RCR_RDATDLY(v) ((v) << 16) 74f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_RCR_RFIG (1 << 18) 75f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_RCR_RWDLEN2(v) ((v) << 21) 76f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_RCR_RFRLEN2(v) ((v) << 24) 77f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_RCR_RPHASE BIT(31) 78f2055e14SPeter Ujfalusi 79f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_XCR_XWDLEN1(v) ((v) << 5) 80f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_XCR_XFRLEN1(v) ((v) << 8) 81f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_XCR_XDATDLY(v) ((v) << 16) 82f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_XCR_XFIG (1 << 18) 83f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_XCR_XWDLEN2(v) ((v) << 21) 84f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_XCR_XFRLEN2(v) ((v) << 24) 85f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_XCR_XPHASE BIT(31) 86f2055e14SPeter Ujfalusi 87f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SRGR_FWID(v) ((v) << 8) 88f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SRGR_FPER(v) ((v) << 16) 89f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SRGR_FSGM (1 << 28) 90f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SRGR_CLKSM BIT(29) 91f2055e14SPeter Ujfalusi 92f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_CLKRP (1 << 0) 93f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_CLKXP (1 << 1) 94f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_FSRP (1 << 2) 95f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_FSXP (1 << 3) 96f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_SCLKME (1 << 7) 97f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_CLKRM (1 << 8) 98f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_CLKXM (1 << 9) 99f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_FSRM (1 << 10) 100f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_FSXM (1 << 11) 101f2055e14SPeter Ujfalusi 102f2055e14SPeter Ujfalusi enum { 103f2055e14SPeter Ujfalusi DAVINCI_MCBSP_WORD_8 = 0, 104f2055e14SPeter Ujfalusi DAVINCI_MCBSP_WORD_12, 105f2055e14SPeter Ujfalusi DAVINCI_MCBSP_WORD_16, 106f2055e14SPeter Ujfalusi DAVINCI_MCBSP_WORD_20, 107f2055e14SPeter Ujfalusi DAVINCI_MCBSP_WORD_24, 108f2055e14SPeter Ujfalusi DAVINCI_MCBSP_WORD_32, 109f2055e14SPeter Ujfalusi }; 110f2055e14SPeter Ujfalusi 111f2055e14SPeter Ujfalusi static const unsigned char data_type[SNDRV_PCM_FORMAT_S32_LE + 1] = { 112f2055e14SPeter Ujfalusi [SNDRV_PCM_FORMAT_S8] = 1, 113f2055e14SPeter Ujfalusi [SNDRV_PCM_FORMAT_S16_LE] = 2, 114f2055e14SPeter Ujfalusi [SNDRV_PCM_FORMAT_S32_LE] = 4, 115f2055e14SPeter Ujfalusi }; 116f2055e14SPeter Ujfalusi 117f2055e14SPeter Ujfalusi static const unsigned char asp_word_length[SNDRV_PCM_FORMAT_S32_LE + 1] = { 118f2055e14SPeter Ujfalusi [SNDRV_PCM_FORMAT_S8] = DAVINCI_MCBSP_WORD_8, 119f2055e14SPeter Ujfalusi [SNDRV_PCM_FORMAT_S16_LE] = DAVINCI_MCBSP_WORD_16, 120f2055e14SPeter Ujfalusi [SNDRV_PCM_FORMAT_S32_LE] = DAVINCI_MCBSP_WORD_32, 121f2055e14SPeter Ujfalusi }; 122f2055e14SPeter Ujfalusi 123f2055e14SPeter Ujfalusi static const unsigned char double_fmt[SNDRV_PCM_FORMAT_S32_LE + 1] = { 124f2055e14SPeter Ujfalusi [SNDRV_PCM_FORMAT_S8] = SNDRV_PCM_FORMAT_S16_LE, 125f2055e14SPeter Ujfalusi [SNDRV_PCM_FORMAT_S16_LE] = SNDRV_PCM_FORMAT_S32_LE, 126f2055e14SPeter Ujfalusi }; 127f2055e14SPeter Ujfalusi 128f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev { 129f2055e14SPeter Ujfalusi struct device *dev; 130f2055e14SPeter Ujfalusi struct snd_dmaengine_dai_dma_data dma_data[2]; 131f2055e14SPeter Ujfalusi int dma_request[2]; 132f2055e14SPeter Ujfalusi void __iomem *base; 133f2055e14SPeter Ujfalusi #define MOD_DSP_A 0 134f2055e14SPeter Ujfalusi #define MOD_DSP_B 1 135f2055e14SPeter Ujfalusi int mode; 136f2055e14SPeter Ujfalusi u32 pcr; 137f2055e14SPeter Ujfalusi struct clk *clk; 138f2055e14SPeter Ujfalusi /* 139f2055e14SPeter Ujfalusi * Combining both channels into 1 element will at least double the 140f2055e14SPeter Ujfalusi * amount of time between servicing the dma channel, increase 141f2055e14SPeter Ujfalusi * effiency, and reduce the chance of overrun/underrun. But, 142f2055e14SPeter Ujfalusi * it will result in the left & right channels being swapped. 143f2055e14SPeter Ujfalusi * 144f2055e14SPeter Ujfalusi * If relabeling the left and right channels is not possible, 145f2055e14SPeter Ujfalusi * you may want to let the codec know to swap them back. 146f2055e14SPeter Ujfalusi * 147f2055e14SPeter Ujfalusi * It may allow x10 the amount of time to service dma requests, 148f2055e14SPeter Ujfalusi * if the codec is master and is using an unnecessarily fast bit clock 149f2055e14SPeter Ujfalusi * (ie. tlvaic23b), independent of the sample rate. So, having an 150f2055e14SPeter Ujfalusi * entire frame at once means it can be serviced at the sample rate 151f2055e14SPeter Ujfalusi * instead of the bit clock rate. 152f2055e14SPeter Ujfalusi * 153f2055e14SPeter Ujfalusi * In the now unlikely case that an underrun still 154f2055e14SPeter Ujfalusi * occurs, both the left and right samples will be repeated 155f2055e14SPeter Ujfalusi * so that no pops are heard, and the left and right channels 156f2055e14SPeter Ujfalusi * won't end up being swapped because of the underrun. 157f2055e14SPeter Ujfalusi */ 158f2055e14SPeter Ujfalusi unsigned enable_channel_combine:1; 159f2055e14SPeter Ujfalusi 160f2055e14SPeter Ujfalusi unsigned int fmt; 161f2055e14SPeter Ujfalusi int clk_div; 162f2055e14SPeter Ujfalusi int clk_input_pin; 163f2055e14SPeter Ujfalusi bool i2s_accurate_sck; 164f2055e14SPeter Ujfalusi }; 165f2055e14SPeter Ujfalusi 166f2055e14SPeter Ujfalusi static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev, 167f2055e14SPeter Ujfalusi int reg, u32 val) 168f2055e14SPeter Ujfalusi { 169f2055e14SPeter Ujfalusi __raw_writel(val, dev->base + reg); 170f2055e14SPeter Ujfalusi } 171f2055e14SPeter Ujfalusi 172f2055e14SPeter Ujfalusi static inline u32 davinci_mcbsp_read_reg(struct davinci_mcbsp_dev *dev, int reg) 173f2055e14SPeter Ujfalusi { 174f2055e14SPeter Ujfalusi return __raw_readl(dev->base + reg); 175f2055e14SPeter Ujfalusi } 176f2055e14SPeter Ujfalusi 177f2055e14SPeter Ujfalusi static void toggle_clock(struct davinci_mcbsp_dev *dev, int playback) 178f2055e14SPeter Ujfalusi { 179f2055e14SPeter Ujfalusi u32 m = playback ? DAVINCI_MCBSP_PCR_CLKXP : DAVINCI_MCBSP_PCR_CLKRP; 180f2055e14SPeter Ujfalusi /* The clock needs to toggle to complete reset. 181f2055e14SPeter Ujfalusi * So, fake it by toggling the clk polarity. 182f2055e14SPeter Ujfalusi */ 183f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, dev->pcr ^ m); 184f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, dev->pcr); 185f2055e14SPeter Ujfalusi } 186f2055e14SPeter Ujfalusi 187f2055e14SPeter Ujfalusi static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev, 188f2055e14SPeter Ujfalusi struct snd_pcm_substream *substream) 189f2055e14SPeter Ujfalusi { 190f2055e14SPeter Ujfalusi int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 191f2055e14SPeter Ujfalusi u32 spcr; 192f2055e14SPeter Ujfalusi u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST; 193f2055e14SPeter Ujfalusi 194f2055e14SPeter Ujfalusi /* Enable transmitter or receiver */ 195f2055e14SPeter Ujfalusi spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); 196f2055e14SPeter Ujfalusi spcr |= mask; 197f2055e14SPeter Ujfalusi 198f2055e14SPeter Ujfalusi if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM)) { 199f2055e14SPeter Ujfalusi /* Start frame sync */ 200f2055e14SPeter Ujfalusi spcr |= DAVINCI_MCBSP_SPCR_FRST; 201f2055e14SPeter Ujfalusi } 202f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); 203f2055e14SPeter Ujfalusi } 204f2055e14SPeter Ujfalusi 205f2055e14SPeter Ujfalusi static void davinci_mcbsp_stop(struct davinci_mcbsp_dev *dev, int playback) 206f2055e14SPeter Ujfalusi { 207f2055e14SPeter Ujfalusi u32 spcr; 208f2055e14SPeter Ujfalusi 209f2055e14SPeter Ujfalusi /* Reset transmitter/receiver and sample rate/frame sync generators */ 210f2055e14SPeter Ujfalusi spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); 211f2055e14SPeter Ujfalusi spcr &= ~(DAVINCI_MCBSP_SPCR_GRST | DAVINCI_MCBSP_SPCR_FRST); 212f2055e14SPeter Ujfalusi spcr &= playback ? ~DAVINCI_MCBSP_SPCR_XRST : ~DAVINCI_MCBSP_SPCR_RRST; 213f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); 214f2055e14SPeter Ujfalusi toggle_clock(dev, playback); 215f2055e14SPeter Ujfalusi } 216f2055e14SPeter Ujfalusi 217f2055e14SPeter Ujfalusi #define DEFAULT_BITPERSAMPLE 16 218f2055e14SPeter Ujfalusi 219f2055e14SPeter Ujfalusi static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, 220f2055e14SPeter Ujfalusi unsigned int fmt) 221f2055e14SPeter Ujfalusi { 222f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); 223f2055e14SPeter Ujfalusi unsigned int pcr; 224f2055e14SPeter Ujfalusi unsigned int srgr; 225f2055e14SPeter Ujfalusi bool inv_fs = false; 226f2055e14SPeter Ujfalusi /* Attention srgr is updated by hw_params! */ 227f2055e14SPeter Ujfalusi srgr = DAVINCI_MCBSP_SRGR_FSGM | 228f2055e14SPeter Ujfalusi DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) | 229f2055e14SPeter Ujfalusi DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1); 230f2055e14SPeter Ujfalusi 231f2055e14SPeter Ujfalusi dev->fmt = fmt; 232f2055e14SPeter Ujfalusi /* set master/slave audio interface */ 233563ff63dSCharles Keepax switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 234563ff63dSCharles Keepax case SND_SOC_DAIFMT_BP_FP: 235f2055e14SPeter Ujfalusi /* cpu is master */ 236f2055e14SPeter Ujfalusi pcr = DAVINCI_MCBSP_PCR_FSXM | 237f2055e14SPeter Ujfalusi DAVINCI_MCBSP_PCR_FSRM | 238f2055e14SPeter Ujfalusi DAVINCI_MCBSP_PCR_CLKXM | 239f2055e14SPeter Ujfalusi DAVINCI_MCBSP_PCR_CLKRM; 240f2055e14SPeter Ujfalusi break; 241563ff63dSCharles Keepax case SND_SOC_DAIFMT_BC_FP: 242f2055e14SPeter Ujfalusi pcr = DAVINCI_MCBSP_PCR_FSRM | DAVINCI_MCBSP_PCR_FSXM; 243f2055e14SPeter Ujfalusi /* 244f2055e14SPeter Ujfalusi * Selection of the clock input pin that is the 245f2055e14SPeter Ujfalusi * input for the Sample Rate Generator. 246f2055e14SPeter Ujfalusi * McBSP FSR and FSX are driven by the Sample Rate 247f2055e14SPeter Ujfalusi * Generator. 248f2055e14SPeter Ujfalusi */ 249f2055e14SPeter Ujfalusi switch (dev->clk_input_pin) { 250f2055e14SPeter Ujfalusi case MCBSP_CLKS: 251f2055e14SPeter Ujfalusi pcr |= DAVINCI_MCBSP_PCR_CLKXM | 252f2055e14SPeter Ujfalusi DAVINCI_MCBSP_PCR_CLKRM; 253f2055e14SPeter Ujfalusi break; 254f2055e14SPeter Ujfalusi case MCBSP_CLKR: 255f2055e14SPeter Ujfalusi pcr |= DAVINCI_MCBSP_PCR_SCLKME; 256f2055e14SPeter Ujfalusi break; 257f2055e14SPeter Ujfalusi default: 258f2055e14SPeter Ujfalusi dev_err(dev->dev, "bad clk_input_pin\n"); 259f2055e14SPeter Ujfalusi return -EINVAL; 260f2055e14SPeter Ujfalusi } 261f2055e14SPeter Ujfalusi 262f2055e14SPeter Ujfalusi break; 263563ff63dSCharles Keepax case SND_SOC_DAIFMT_BC_FC: 264f2055e14SPeter Ujfalusi /* codec is master */ 265f2055e14SPeter Ujfalusi pcr = 0; 266f2055e14SPeter Ujfalusi break; 267f2055e14SPeter Ujfalusi default: 268f2055e14SPeter Ujfalusi printk(KERN_ERR "%s:bad master\n", __func__); 269f2055e14SPeter Ujfalusi return -EINVAL; 270f2055e14SPeter Ujfalusi } 271f2055e14SPeter Ujfalusi 272f2055e14SPeter Ujfalusi /* interface format */ 273f2055e14SPeter Ujfalusi switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 274f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_I2S: 275f2055e14SPeter Ujfalusi /* Davinci doesn't support TRUE I2S, but some codecs will have 276f2055e14SPeter Ujfalusi * the left and right channels contiguous. This allows 277f2055e14SPeter Ujfalusi * dsp_a mode to be used with an inverted normal frame clk. 278f2055e14SPeter Ujfalusi * If your codec is master and does not have contiguous 279f2055e14SPeter Ujfalusi * channels, then you will have sound on only one channel. 280f2055e14SPeter Ujfalusi * Try using a different mode, or codec as slave. 281f2055e14SPeter Ujfalusi * 282f2055e14SPeter Ujfalusi * The TLV320AIC33 is an example of a codec where this works. 283f2055e14SPeter Ujfalusi * It has a variable bit clock frequency allowing it to have 284f2055e14SPeter Ujfalusi * valid data on every bit clock. 285f2055e14SPeter Ujfalusi * 286f2055e14SPeter Ujfalusi * The TLV320AIC23 is an example of a codec where this does not 287f2055e14SPeter Ujfalusi * work. It has a fixed bit clock frequency with progressively 288f2055e14SPeter Ujfalusi * more empty bit clock slots between channels as the sample 289f2055e14SPeter Ujfalusi * rate is lowered. 290f2055e14SPeter Ujfalusi */ 291f2055e14SPeter Ujfalusi inv_fs = true; 292df561f66SGustavo A. R. Silva fallthrough; 293f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_DSP_A: 294f2055e14SPeter Ujfalusi dev->mode = MOD_DSP_A; 295f2055e14SPeter Ujfalusi break; 296f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_DSP_B: 297f2055e14SPeter Ujfalusi dev->mode = MOD_DSP_B; 298f2055e14SPeter Ujfalusi break; 299f2055e14SPeter Ujfalusi default: 300f2055e14SPeter Ujfalusi printk(KERN_ERR "%s:bad format\n", __func__); 301f2055e14SPeter Ujfalusi return -EINVAL; 302f2055e14SPeter Ujfalusi } 303f2055e14SPeter Ujfalusi 304f2055e14SPeter Ujfalusi switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 305f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_NB_NF: 306f2055e14SPeter Ujfalusi /* CLKRP Receive clock polarity, 307f2055e14SPeter Ujfalusi * 1 - sampled on rising edge of CLKR 308f2055e14SPeter Ujfalusi * valid on rising edge 309f2055e14SPeter Ujfalusi * CLKXP Transmit clock polarity, 310f2055e14SPeter Ujfalusi * 1 - clocked on falling edge of CLKX 311f2055e14SPeter Ujfalusi * valid on rising edge 312f2055e14SPeter Ujfalusi * FSRP Receive frame sync pol, 0 - active high 313f2055e14SPeter Ujfalusi * FSXP Transmit frame sync pol, 0 - active high 314f2055e14SPeter Ujfalusi */ 315f2055e14SPeter Ujfalusi pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP); 316f2055e14SPeter Ujfalusi break; 317f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_IB_IF: 318f2055e14SPeter Ujfalusi /* CLKRP Receive clock polarity, 319f2055e14SPeter Ujfalusi * 0 - sampled on falling edge of CLKR 320f2055e14SPeter Ujfalusi * valid on falling edge 321f2055e14SPeter Ujfalusi * CLKXP Transmit clock polarity, 322f2055e14SPeter Ujfalusi * 0 - clocked on rising edge of CLKX 323f2055e14SPeter Ujfalusi * valid on falling edge 324f2055e14SPeter Ujfalusi * FSRP Receive frame sync pol, 1 - active low 325f2055e14SPeter Ujfalusi * FSXP Transmit frame sync pol, 1 - active low 326f2055e14SPeter Ujfalusi */ 327f2055e14SPeter Ujfalusi pcr |= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP); 328f2055e14SPeter Ujfalusi break; 329f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_NB_IF: 330f2055e14SPeter Ujfalusi /* CLKRP Receive clock polarity, 331f2055e14SPeter Ujfalusi * 1 - sampled on rising edge of CLKR 332f2055e14SPeter Ujfalusi * valid on rising edge 333f2055e14SPeter Ujfalusi * CLKXP Transmit clock polarity, 334f2055e14SPeter Ujfalusi * 1 - clocked on falling edge of CLKX 335f2055e14SPeter Ujfalusi * valid on rising edge 336f2055e14SPeter Ujfalusi * FSRP Receive frame sync pol, 1 - active low 337f2055e14SPeter Ujfalusi * FSXP Transmit frame sync pol, 1 - active low 338f2055e14SPeter Ujfalusi */ 339f2055e14SPeter Ujfalusi pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP | 340f2055e14SPeter Ujfalusi DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP); 341f2055e14SPeter Ujfalusi break; 342f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_IB_NF: 343f2055e14SPeter Ujfalusi /* CLKRP Receive clock polarity, 344f2055e14SPeter Ujfalusi * 0 - sampled on falling edge of CLKR 345f2055e14SPeter Ujfalusi * valid on falling edge 346f2055e14SPeter Ujfalusi * CLKXP Transmit clock polarity, 347f2055e14SPeter Ujfalusi * 0 - clocked on rising edge of CLKX 348f2055e14SPeter Ujfalusi * valid on falling edge 349f2055e14SPeter Ujfalusi * FSRP Receive frame sync pol, 0 - active high 350f2055e14SPeter Ujfalusi * FSXP Transmit frame sync pol, 0 - active high 351f2055e14SPeter Ujfalusi */ 352f2055e14SPeter Ujfalusi break; 353f2055e14SPeter Ujfalusi default: 354f2055e14SPeter Ujfalusi return -EINVAL; 355f2055e14SPeter Ujfalusi } 356f2055e14SPeter Ujfalusi if (inv_fs == true) 357f2055e14SPeter Ujfalusi pcr ^= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP); 358f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); 359f2055e14SPeter Ujfalusi dev->pcr = pcr; 360f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, pcr); 361f2055e14SPeter Ujfalusi return 0; 362f2055e14SPeter Ujfalusi } 363f2055e14SPeter Ujfalusi 364f2055e14SPeter Ujfalusi static int davinci_i2s_dai_set_clkdiv(struct snd_soc_dai *cpu_dai, 365f2055e14SPeter Ujfalusi int div_id, int div) 366f2055e14SPeter Ujfalusi { 367f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); 368f2055e14SPeter Ujfalusi 369f2055e14SPeter Ujfalusi if (div_id != DAVINCI_MCBSP_CLKGDV) 370f2055e14SPeter Ujfalusi return -ENODEV; 371f2055e14SPeter Ujfalusi 372f2055e14SPeter Ujfalusi dev->clk_div = div; 373f2055e14SPeter Ujfalusi return 0; 374f2055e14SPeter Ujfalusi } 375f2055e14SPeter Ujfalusi 376f2055e14SPeter Ujfalusi static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, 377f2055e14SPeter Ujfalusi struct snd_pcm_hw_params *params, 378f2055e14SPeter Ujfalusi struct snd_soc_dai *dai) 379f2055e14SPeter Ujfalusi { 380f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); 381f2055e14SPeter Ujfalusi struct snd_interval *i = NULL; 382f2055e14SPeter Ujfalusi int mcbsp_word_length, master; 383f2055e14SPeter Ujfalusi unsigned int rcr, xcr, srgr, clk_div, freq, framesize; 384f2055e14SPeter Ujfalusi u32 spcr; 385f2055e14SPeter Ujfalusi snd_pcm_format_t fmt; 386f2055e14SPeter Ujfalusi unsigned element_cnt = 1; 387f2055e14SPeter Ujfalusi 388f2055e14SPeter Ujfalusi /* general line settings */ 389f2055e14SPeter Ujfalusi spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); 390f2055e14SPeter Ujfalusi if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 391f2055e14SPeter Ujfalusi spcr |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE; 392f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); 393f2055e14SPeter Ujfalusi } else { 394f2055e14SPeter Ujfalusi spcr |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE; 395f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); 396f2055e14SPeter Ujfalusi } 397f2055e14SPeter Ujfalusi 398563ff63dSCharles Keepax master = dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; 399f2055e14SPeter Ujfalusi fmt = params_format(params); 400f2055e14SPeter Ujfalusi mcbsp_word_length = asp_word_length[fmt]; 401f2055e14SPeter Ujfalusi 402f2055e14SPeter Ujfalusi switch (master) { 403563ff63dSCharles Keepax case SND_SOC_DAIFMT_BP_FP: 404f2055e14SPeter Ujfalusi freq = clk_get_rate(dev->clk); 405f2055e14SPeter Ujfalusi srgr = DAVINCI_MCBSP_SRGR_FSGM | 406f2055e14SPeter Ujfalusi DAVINCI_MCBSP_SRGR_CLKSM; 407f2055e14SPeter Ujfalusi srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 408f2055e14SPeter Ujfalusi 8 - 1); 409f2055e14SPeter Ujfalusi if (dev->i2s_accurate_sck) { 410f2055e14SPeter Ujfalusi clk_div = 256; 411f2055e14SPeter Ujfalusi do { 412f2055e14SPeter Ujfalusi framesize = (freq / (--clk_div)) / 413f2055e14SPeter Ujfalusi params->rate_num * 414f2055e14SPeter Ujfalusi params->rate_den; 415f2055e14SPeter Ujfalusi } while (((framesize < 33) || (framesize > 4095)) && 416f2055e14SPeter Ujfalusi (clk_div)); 417f2055e14SPeter Ujfalusi clk_div--; 418f2055e14SPeter Ujfalusi srgr |= DAVINCI_MCBSP_SRGR_FPER(framesize - 1); 419f2055e14SPeter Ujfalusi } else { 420f2055e14SPeter Ujfalusi /* symmetric waveforms */ 421f2055e14SPeter Ujfalusi clk_div = freq / (mcbsp_word_length * 16) / 422f2055e14SPeter Ujfalusi params->rate_num * params->rate_den; 423f2055e14SPeter Ujfalusi srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length * 424f2055e14SPeter Ujfalusi 16 - 1); 425f2055e14SPeter Ujfalusi } 426f2055e14SPeter Ujfalusi clk_div &= 0xFF; 427f2055e14SPeter Ujfalusi srgr |= clk_div; 428f2055e14SPeter Ujfalusi break; 429563ff63dSCharles Keepax case SND_SOC_DAIFMT_BC_FP: 430f2055e14SPeter Ujfalusi srgr = DAVINCI_MCBSP_SRGR_FSGM; 431f2055e14SPeter Ujfalusi clk_div = dev->clk_div - 1; 432f2055e14SPeter Ujfalusi srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 8 - 1); 433f2055e14SPeter Ujfalusi srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length * 16 - 1); 434f2055e14SPeter Ujfalusi clk_div &= 0xFF; 435f2055e14SPeter Ujfalusi srgr |= clk_div; 436f2055e14SPeter Ujfalusi break; 437563ff63dSCharles Keepax case SND_SOC_DAIFMT_BC_FC: 438f2055e14SPeter Ujfalusi /* Clock and frame sync given from external sources */ 439f2055e14SPeter Ujfalusi i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); 440f2055e14SPeter Ujfalusi srgr = DAVINCI_MCBSP_SRGR_FSGM; 441f2055e14SPeter Ujfalusi srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1); 442f2055e14SPeter Ujfalusi pr_debug("%s - %d FWID set: re-read srgr = %X\n", 443f2055e14SPeter Ujfalusi __func__, __LINE__, snd_interval_value(i) - 1); 444f2055e14SPeter Ujfalusi 445f2055e14SPeter Ujfalusi i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS); 446f2055e14SPeter Ujfalusi srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1); 447f2055e14SPeter Ujfalusi break; 448f2055e14SPeter Ujfalusi default: 449f2055e14SPeter Ujfalusi return -EINVAL; 450f2055e14SPeter Ujfalusi } 451f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); 452f2055e14SPeter Ujfalusi 453f2055e14SPeter Ujfalusi rcr = DAVINCI_MCBSP_RCR_RFIG; 454f2055e14SPeter Ujfalusi xcr = DAVINCI_MCBSP_XCR_XFIG; 455f2055e14SPeter Ujfalusi if (dev->mode == MOD_DSP_B) { 456f2055e14SPeter Ujfalusi rcr |= DAVINCI_MCBSP_RCR_RDATDLY(0); 457f2055e14SPeter Ujfalusi xcr |= DAVINCI_MCBSP_XCR_XDATDLY(0); 458f2055e14SPeter Ujfalusi } else { 459f2055e14SPeter Ujfalusi rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1); 460f2055e14SPeter Ujfalusi xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1); 461f2055e14SPeter Ujfalusi } 462f2055e14SPeter Ujfalusi /* Determine xfer data type */ 463f2055e14SPeter Ujfalusi fmt = params_format(params); 464f2055e14SPeter Ujfalusi if ((fmt > SNDRV_PCM_FORMAT_S32_LE) || !data_type[fmt]) { 465f2055e14SPeter Ujfalusi printk(KERN_WARNING "davinci-i2s: unsupported PCM format\n"); 466f2055e14SPeter Ujfalusi return -EINVAL; 467f2055e14SPeter Ujfalusi } 468f2055e14SPeter Ujfalusi 469f2055e14SPeter Ujfalusi if (params_channels(params) == 2) { 470f2055e14SPeter Ujfalusi element_cnt = 2; 471f2055e14SPeter Ujfalusi if (double_fmt[fmt] && dev->enable_channel_combine) { 472f2055e14SPeter Ujfalusi element_cnt = 1; 473f2055e14SPeter Ujfalusi fmt = double_fmt[fmt]; 474f2055e14SPeter Ujfalusi } 475f2055e14SPeter Ujfalusi switch (master) { 476563ff63dSCharles Keepax case SND_SOC_DAIFMT_BP_FP: 477563ff63dSCharles Keepax case SND_SOC_DAIFMT_BP_FC: 478f2055e14SPeter Ujfalusi rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(0); 479f2055e14SPeter Ujfalusi xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(0); 480f2055e14SPeter Ujfalusi rcr |= DAVINCI_MCBSP_RCR_RPHASE; 481f2055e14SPeter Ujfalusi xcr |= DAVINCI_MCBSP_XCR_XPHASE; 482f2055e14SPeter Ujfalusi break; 483563ff63dSCharles Keepax case SND_SOC_DAIFMT_BC_FC: 484563ff63dSCharles Keepax case SND_SOC_DAIFMT_BC_FP: 485f2055e14SPeter Ujfalusi rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(element_cnt - 1); 486f2055e14SPeter Ujfalusi xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(element_cnt - 1); 487f2055e14SPeter Ujfalusi break; 488f2055e14SPeter Ujfalusi default: 489f2055e14SPeter Ujfalusi return -EINVAL; 490f2055e14SPeter Ujfalusi } 491f2055e14SPeter Ujfalusi } 492f2055e14SPeter Ujfalusi mcbsp_word_length = asp_word_length[fmt]; 493f2055e14SPeter Ujfalusi 494f2055e14SPeter Ujfalusi switch (master) { 495563ff63dSCharles Keepax case SND_SOC_DAIFMT_BP_FP: 496563ff63dSCharles Keepax case SND_SOC_DAIFMT_BP_FC: 497f2055e14SPeter Ujfalusi rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(0); 498f2055e14SPeter Ujfalusi xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(0); 499f2055e14SPeter Ujfalusi break; 500563ff63dSCharles Keepax case SND_SOC_DAIFMT_BC_FC: 501563ff63dSCharles Keepax case SND_SOC_DAIFMT_BC_FP: 502f2055e14SPeter Ujfalusi rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1); 503f2055e14SPeter Ujfalusi xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1); 504f2055e14SPeter Ujfalusi break; 505f2055e14SPeter Ujfalusi default: 506f2055e14SPeter Ujfalusi return -EINVAL; 507f2055e14SPeter Ujfalusi } 508f2055e14SPeter Ujfalusi 509f2055e14SPeter Ujfalusi rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | 510f2055e14SPeter Ujfalusi DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length); 511f2055e14SPeter Ujfalusi xcr |= DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | 512f2055e14SPeter Ujfalusi DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length); 513f2055e14SPeter Ujfalusi 514f2055e14SPeter Ujfalusi if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 515f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr); 516f2055e14SPeter Ujfalusi else 517f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr); 518f2055e14SPeter Ujfalusi 519f2055e14SPeter Ujfalusi pr_debug("%s - %d srgr=%X\n", __func__, __LINE__, srgr); 520f2055e14SPeter Ujfalusi pr_debug("%s - %d xcr=%X\n", __func__, __LINE__, xcr); 521f2055e14SPeter Ujfalusi pr_debug("%s - %d rcr=%X\n", __func__, __LINE__, rcr); 522f2055e14SPeter Ujfalusi return 0; 523f2055e14SPeter Ujfalusi } 524f2055e14SPeter Ujfalusi 525f2055e14SPeter Ujfalusi static int davinci_i2s_prepare(struct snd_pcm_substream *substream, 526f2055e14SPeter Ujfalusi struct snd_soc_dai *dai) 527f2055e14SPeter Ujfalusi { 528f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); 529f2055e14SPeter Ujfalusi int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 530a2dc6f82SPeter Ujfalusi u32 spcr; 531a2dc6f82SPeter Ujfalusi u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST; 532a2dc6f82SPeter Ujfalusi 533f2055e14SPeter Ujfalusi davinci_mcbsp_stop(dev, playback); 534a2dc6f82SPeter Ujfalusi 535a2dc6f82SPeter Ujfalusi spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); 536a2dc6f82SPeter Ujfalusi if (spcr & mask) { 537a2dc6f82SPeter Ujfalusi /* start off disabled */ 538a2dc6f82SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, 539a2dc6f82SPeter Ujfalusi spcr & ~mask); 540a2dc6f82SPeter Ujfalusi toggle_clock(dev, playback); 541a2dc6f82SPeter Ujfalusi } 542a2dc6f82SPeter Ujfalusi if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM | 543a2dc6f82SPeter Ujfalusi DAVINCI_MCBSP_PCR_CLKXM | DAVINCI_MCBSP_PCR_CLKRM)) { 544a2dc6f82SPeter Ujfalusi /* Start the sample generator */ 545a2dc6f82SPeter Ujfalusi spcr |= DAVINCI_MCBSP_SPCR_GRST; 546a2dc6f82SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); 547a2dc6f82SPeter Ujfalusi } 548a2dc6f82SPeter Ujfalusi 549a2dc6f82SPeter Ujfalusi if (playback) { 550a2dc6f82SPeter Ujfalusi /* Enable the transmitter */ 551a2dc6f82SPeter Ujfalusi spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); 552a2dc6f82SPeter Ujfalusi spcr |= DAVINCI_MCBSP_SPCR_XRST; 553a2dc6f82SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); 554a2dc6f82SPeter Ujfalusi 555a2dc6f82SPeter Ujfalusi /* wait for any unexpected frame sync error to occur */ 556a2dc6f82SPeter Ujfalusi udelay(100); 557a2dc6f82SPeter Ujfalusi 558a2dc6f82SPeter Ujfalusi /* Disable the transmitter to clear any outstanding XSYNCERR */ 559a2dc6f82SPeter Ujfalusi spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); 560a2dc6f82SPeter Ujfalusi spcr &= ~DAVINCI_MCBSP_SPCR_XRST; 561a2dc6f82SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); 562a2dc6f82SPeter Ujfalusi toggle_clock(dev, playback); 563a2dc6f82SPeter Ujfalusi } 564a2dc6f82SPeter Ujfalusi 565f2055e14SPeter Ujfalusi return 0; 566f2055e14SPeter Ujfalusi } 567f2055e14SPeter Ujfalusi 568f2055e14SPeter Ujfalusi static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, 569f2055e14SPeter Ujfalusi struct snd_soc_dai *dai) 570f2055e14SPeter Ujfalusi { 571f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); 572f2055e14SPeter Ujfalusi int ret = 0; 573f2055e14SPeter Ujfalusi int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 574f2055e14SPeter Ujfalusi 575f2055e14SPeter Ujfalusi switch (cmd) { 576f2055e14SPeter Ujfalusi case SNDRV_PCM_TRIGGER_START: 577f2055e14SPeter Ujfalusi case SNDRV_PCM_TRIGGER_RESUME: 578f2055e14SPeter Ujfalusi case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 579f2055e14SPeter Ujfalusi davinci_mcbsp_start(dev, substream); 580f2055e14SPeter Ujfalusi break; 581f2055e14SPeter Ujfalusi case SNDRV_PCM_TRIGGER_STOP: 582f2055e14SPeter Ujfalusi case SNDRV_PCM_TRIGGER_SUSPEND: 583f2055e14SPeter Ujfalusi case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 584f2055e14SPeter Ujfalusi davinci_mcbsp_stop(dev, playback); 585f2055e14SPeter Ujfalusi break; 586f2055e14SPeter Ujfalusi default: 587f2055e14SPeter Ujfalusi ret = -EINVAL; 588f2055e14SPeter Ujfalusi } 589f2055e14SPeter Ujfalusi return ret; 590f2055e14SPeter Ujfalusi } 591f2055e14SPeter Ujfalusi 592f2055e14SPeter Ujfalusi static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, 593f2055e14SPeter Ujfalusi struct snd_soc_dai *dai) 594f2055e14SPeter Ujfalusi { 595f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); 596f2055e14SPeter Ujfalusi int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 597f2055e14SPeter Ujfalusi davinci_mcbsp_stop(dev, playback); 598f2055e14SPeter Ujfalusi } 599f2055e14SPeter Ujfalusi 600f2055e14SPeter Ujfalusi #define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000 6012231b2c6SPeter Ujfalusi #define DAVINCI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 6022231b2c6SPeter Ujfalusi SNDRV_PCM_FMTBIT_S32_LE) 603f2055e14SPeter Ujfalusi 604f2055e14SPeter Ujfalusi static const struct snd_soc_dai_ops davinci_i2s_dai_ops = { 605f2055e14SPeter Ujfalusi .shutdown = davinci_i2s_shutdown, 606f2055e14SPeter Ujfalusi .prepare = davinci_i2s_prepare, 607f2055e14SPeter Ujfalusi .trigger = davinci_i2s_trigger, 608f2055e14SPeter Ujfalusi .hw_params = davinci_i2s_hw_params, 6099ff18360SCharles Keepax .set_fmt = davinci_i2s_set_dai_fmt, 610f2055e14SPeter Ujfalusi .set_clkdiv = davinci_i2s_dai_set_clkdiv, 611f2055e14SPeter Ujfalusi 612f2055e14SPeter Ujfalusi }; 613f2055e14SPeter Ujfalusi 614f2055e14SPeter Ujfalusi static int davinci_i2s_dai_probe(struct snd_soc_dai *dai) 615f2055e14SPeter Ujfalusi { 616f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); 617*2abde57fSKuninori Morimoto int stream; 618f2055e14SPeter Ujfalusi 619*2abde57fSKuninori Morimoto for_each_pcm_streams(stream) 620*2abde57fSKuninori Morimoto snd_soc_dai_dma_data_set(dai, stream, &dev->dma_data[stream]); 621f2055e14SPeter Ujfalusi 622f2055e14SPeter Ujfalusi return 0; 623f2055e14SPeter Ujfalusi } 624f2055e14SPeter Ujfalusi 625f2055e14SPeter Ujfalusi static struct snd_soc_dai_driver davinci_i2s_dai = { 626f2055e14SPeter Ujfalusi .probe = davinci_i2s_dai_probe, 627f2055e14SPeter Ujfalusi .playback = { 628f2055e14SPeter Ujfalusi .channels_min = 2, 629f2055e14SPeter Ujfalusi .channels_max = 2, 630f2055e14SPeter Ujfalusi .rates = DAVINCI_I2S_RATES, 6312231b2c6SPeter Ujfalusi .formats = DAVINCI_I2S_FORMATS, 6322231b2c6SPeter Ujfalusi }, 633f2055e14SPeter Ujfalusi .capture = { 634f2055e14SPeter Ujfalusi .channels_min = 2, 635f2055e14SPeter Ujfalusi .channels_max = 2, 636f2055e14SPeter Ujfalusi .rates = DAVINCI_I2S_RATES, 6372231b2c6SPeter Ujfalusi .formats = DAVINCI_I2S_FORMATS, 6382231b2c6SPeter Ujfalusi }, 639f2055e14SPeter Ujfalusi .ops = &davinci_i2s_dai_ops, 640f2055e14SPeter Ujfalusi 641f2055e14SPeter Ujfalusi }; 642f2055e14SPeter Ujfalusi 643f2055e14SPeter Ujfalusi static const struct snd_soc_component_driver davinci_i2s_component = { 644f2055e14SPeter Ujfalusi .name = DRV_NAME, 64539c84e77SCharles Keepax .legacy_dai_naming = 1, 646f2055e14SPeter Ujfalusi }; 647f2055e14SPeter Ujfalusi 648f2055e14SPeter Ujfalusi static int davinci_i2s_probe(struct platform_device *pdev) 649f2055e14SPeter Ujfalusi { 650f2055e14SPeter Ujfalusi struct snd_dmaengine_dai_dma_data *dma_data; 651f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev *dev; 652f2055e14SPeter Ujfalusi struct resource *mem, *res; 653f2055e14SPeter Ujfalusi void __iomem *io_base; 654f2055e14SPeter Ujfalusi int *dma; 655f2055e14SPeter Ujfalusi int ret; 656f2055e14SPeter Ujfalusi 657f2055e14SPeter Ujfalusi mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); 658f2055e14SPeter Ujfalusi if (!mem) { 659f2055e14SPeter Ujfalusi dev_warn(&pdev->dev, 660f2055e14SPeter Ujfalusi "\"mpu\" mem resource not found, using index 0\n"); 661f2055e14SPeter Ujfalusi mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 662f2055e14SPeter Ujfalusi if (!mem) { 663f2055e14SPeter Ujfalusi dev_err(&pdev->dev, "no mem resource?\n"); 664f2055e14SPeter Ujfalusi return -ENODEV; 665f2055e14SPeter Ujfalusi } 666f2055e14SPeter Ujfalusi } 667f2055e14SPeter Ujfalusi 668f2055e14SPeter Ujfalusi io_base = devm_ioremap_resource(&pdev->dev, mem); 669f2055e14SPeter Ujfalusi if (IS_ERR(io_base)) 670f2055e14SPeter Ujfalusi return PTR_ERR(io_base); 671f2055e14SPeter Ujfalusi 672f2055e14SPeter Ujfalusi dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcbsp_dev), 673f2055e14SPeter Ujfalusi GFP_KERNEL); 674f2055e14SPeter Ujfalusi if (!dev) 675f2055e14SPeter Ujfalusi return -ENOMEM; 676f2055e14SPeter Ujfalusi 677f2055e14SPeter Ujfalusi dev->base = io_base; 678f2055e14SPeter Ujfalusi 679f2055e14SPeter Ujfalusi /* setup DMA, first TX, then RX */ 680f2055e14SPeter Ujfalusi dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; 681f2055e14SPeter Ujfalusi dma_data->addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG); 682f2055e14SPeter Ujfalusi 683f2055e14SPeter Ujfalusi res = platform_get_resource(pdev, IORESOURCE_DMA, 0); 684f2055e14SPeter Ujfalusi if (res) { 685f2055e14SPeter Ujfalusi dma = &dev->dma_request[SNDRV_PCM_STREAM_PLAYBACK]; 686f2055e14SPeter Ujfalusi *dma = res->start; 687f2055e14SPeter Ujfalusi dma_data->filter_data = dma; 688f2055e14SPeter Ujfalusi } else if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { 689f2055e14SPeter Ujfalusi dma_data->filter_data = "tx"; 690f2055e14SPeter Ujfalusi } else { 691f2055e14SPeter Ujfalusi dev_err(&pdev->dev, "Missing DMA tx resource\n"); 692f2055e14SPeter Ujfalusi return -ENODEV; 693f2055e14SPeter Ujfalusi } 694f2055e14SPeter Ujfalusi 695f2055e14SPeter Ujfalusi dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]; 696f2055e14SPeter Ujfalusi dma_data->addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DRR_REG); 697f2055e14SPeter Ujfalusi 698f2055e14SPeter Ujfalusi res = platform_get_resource(pdev, IORESOURCE_DMA, 1); 699f2055e14SPeter Ujfalusi if (res) { 700f2055e14SPeter Ujfalusi dma = &dev->dma_request[SNDRV_PCM_STREAM_CAPTURE]; 701f2055e14SPeter Ujfalusi *dma = res->start; 702f2055e14SPeter Ujfalusi dma_data->filter_data = dma; 703f2055e14SPeter Ujfalusi } else if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { 704f2055e14SPeter Ujfalusi dma_data->filter_data = "rx"; 705f2055e14SPeter Ujfalusi } else { 706f2055e14SPeter Ujfalusi dev_err(&pdev->dev, "Missing DMA rx resource\n"); 707f2055e14SPeter Ujfalusi return -ENODEV; 708f2055e14SPeter Ujfalusi } 709f2055e14SPeter Ujfalusi 710f2055e14SPeter Ujfalusi dev->clk = clk_get(&pdev->dev, NULL); 711f2055e14SPeter Ujfalusi if (IS_ERR(dev->clk)) 712f2055e14SPeter Ujfalusi return -ENODEV; 713ed7c9fefSJiasheng Jiang ret = clk_enable(dev->clk); 714ed7c9fefSJiasheng Jiang if (ret) 715ed7c9fefSJiasheng Jiang goto err_put_clk; 716f2055e14SPeter Ujfalusi 717f2055e14SPeter Ujfalusi dev->dev = &pdev->dev; 718f2055e14SPeter Ujfalusi dev_set_drvdata(&pdev->dev, dev); 719f2055e14SPeter Ujfalusi 720f2055e14SPeter Ujfalusi ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component, 721f2055e14SPeter Ujfalusi &davinci_i2s_dai, 1); 722f2055e14SPeter Ujfalusi if (ret != 0) 723f2055e14SPeter Ujfalusi goto err_release_clk; 724f2055e14SPeter Ujfalusi 725f2055e14SPeter Ujfalusi ret = edma_pcm_platform_register(&pdev->dev); 726f2055e14SPeter Ujfalusi if (ret) { 727f2055e14SPeter Ujfalusi dev_err(&pdev->dev, "register PCM failed: %d\n", ret); 728f2055e14SPeter Ujfalusi goto err_unregister_component; 729f2055e14SPeter Ujfalusi } 730f2055e14SPeter Ujfalusi 731f2055e14SPeter Ujfalusi return 0; 732f2055e14SPeter Ujfalusi 733f2055e14SPeter Ujfalusi err_unregister_component: 734f2055e14SPeter Ujfalusi snd_soc_unregister_component(&pdev->dev); 735f2055e14SPeter Ujfalusi err_release_clk: 736f2055e14SPeter Ujfalusi clk_disable(dev->clk); 737ed7c9fefSJiasheng Jiang err_put_clk: 738f2055e14SPeter Ujfalusi clk_put(dev->clk); 739f2055e14SPeter Ujfalusi return ret; 740f2055e14SPeter Ujfalusi } 741f2055e14SPeter Ujfalusi 742f2055e14SPeter Ujfalusi static int davinci_i2s_remove(struct platform_device *pdev) 743f2055e14SPeter Ujfalusi { 744f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev); 745f2055e14SPeter Ujfalusi 746f2055e14SPeter Ujfalusi snd_soc_unregister_component(&pdev->dev); 747f2055e14SPeter Ujfalusi 748f2055e14SPeter Ujfalusi clk_disable(dev->clk); 749f2055e14SPeter Ujfalusi clk_put(dev->clk); 750f2055e14SPeter Ujfalusi dev->clk = NULL; 751f2055e14SPeter Ujfalusi 752f2055e14SPeter Ujfalusi return 0; 753f2055e14SPeter Ujfalusi } 754f2055e14SPeter Ujfalusi 7554bad6ec5SKrzysztof Kozlowski static const struct of_device_id davinci_i2s_match[] __maybe_unused = { 756f2055e14SPeter Ujfalusi { .compatible = "ti,da850-mcbsp" }, 757f2055e14SPeter Ujfalusi {}, 758f2055e14SPeter Ujfalusi }; 759f2055e14SPeter Ujfalusi MODULE_DEVICE_TABLE(of, davinci_i2s_match); 760f2055e14SPeter Ujfalusi 761f2055e14SPeter Ujfalusi static struct platform_driver davinci_mcbsp_driver = { 762f2055e14SPeter Ujfalusi .probe = davinci_i2s_probe, 763f2055e14SPeter Ujfalusi .remove = davinci_i2s_remove, 764f2055e14SPeter Ujfalusi .driver = { 765f2055e14SPeter Ujfalusi .name = "davinci-mcbsp", 766f2055e14SPeter Ujfalusi .of_match_table = of_match_ptr(davinci_i2s_match), 767f2055e14SPeter Ujfalusi }, 768f2055e14SPeter Ujfalusi }; 769f2055e14SPeter Ujfalusi 770f2055e14SPeter Ujfalusi module_platform_driver(davinci_mcbsp_driver); 771f2055e14SPeter Ujfalusi 772f2055e14SPeter Ujfalusi MODULE_AUTHOR("Vladimir Barinov"); 773f2055e14SPeter Ujfalusi MODULE_DESCRIPTION("TI DAVINCI I2S (McBSP) SoC Interface"); 774f2055e14SPeter Ujfalusi MODULE_LICENSE("GPL"); 775