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 struct snd_soc_pcm_runtime *rtd = substream->private_data; 191f2055e14SPeter Ujfalusi struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); 192f2055e14SPeter Ujfalusi int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 193f2055e14SPeter Ujfalusi u32 spcr; 194f2055e14SPeter Ujfalusi u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST; 195f2055e14SPeter Ujfalusi spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); 196f2055e14SPeter Ujfalusi if (spcr & mask) { 197f2055e14SPeter Ujfalusi /* start off disabled */ 198f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, 199f2055e14SPeter Ujfalusi spcr & ~mask); 200f2055e14SPeter Ujfalusi toggle_clock(dev, playback); 201f2055e14SPeter Ujfalusi } 202f2055e14SPeter Ujfalusi if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM | 203f2055e14SPeter Ujfalusi DAVINCI_MCBSP_PCR_CLKXM | DAVINCI_MCBSP_PCR_CLKRM)) { 204f2055e14SPeter Ujfalusi /* Start the sample generator */ 205f2055e14SPeter Ujfalusi spcr |= DAVINCI_MCBSP_SPCR_GRST; 206f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); 207f2055e14SPeter Ujfalusi } 208f2055e14SPeter Ujfalusi 209f2055e14SPeter Ujfalusi if (playback) { 210f2055e14SPeter Ujfalusi /* Stop the DMA to avoid data loss */ 211f2055e14SPeter Ujfalusi /* while the transmitter is out of reset to handle XSYNCERR */ 212f2055e14SPeter Ujfalusi if (component->driver->ops->trigger) { 213f2055e14SPeter Ujfalusi int ret = component->driver->ops->trigger(substream, 214f2055e14SPeter Ujfalusi SNDRV_PCM_TRIGGER_STOP); 215f2055e14SPeter Ujfalusi if (ret < 0) 216f2055e14SPeter Ujfalusi printk(KERN_DEBUG "Playback DMA stop failed\n"); 217f2055e14SPeter Ujfalusi } 218f2055e14SPeter Ujfalusi 219f2055e14SPeter Ujfalusi /* Enable the transmitter */ 220f2055e14SPeter Ujfalusi spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); 221f2055e14SPeter Ujfalusi spcr |= DAVINCI_MCBSP_SPCR_XRST; 222f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); 223f2055e14SPeter Ujfalusi 224f2055e14SPeter Ujfalusi /* wait for any unexpected frame sync error to occur */ 225f2055e14SPeter Ujfalusi udelay(100); 226f2055e14SPeter Ujfalusi 227f2055e14SPeter Ujfalusi /* Disable the transmitter to clear any outstanding XSYNCERR */ 228f2055e14SPeter Ujfalusi spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); 229f2055e14SPeter Ujfalusi spcr &= ~DAVINCI_MCBSP_SPCR_XRST; 230f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); 231f2055e14SPeter Ujfalusi toggle_clock(dev, playback); 232f2055e14SPeter Ujfalusi 233f2055e14SPeter Ujfalusi /* Restart the DMA */ 234f2055e14SPeter Ujfalusi if (component->driver->ops->trigger) { 235f2055e14SPeter Ujfalusi int ret = component->driver->ops->trigger(substream, 236f2055e14SPeter Ujfalusi SNDRV_PCM_TRIGGER_START); 237f2055e14SPeter Ujfalusi if (ret < 0) 238f2055e14SPeter Ujfalusi printk(KERN_DEBUG "Playback DMA start failed\n"); 239f2055e14SPeter Ujfalusi } 240f2055e14SPeter Ujfalusi } 241f2055e14SPeter Ujfalusi 242f2055e14SPeter Ujfalusi /* Enable transmitter or receiver */ 243f2055e14SPeter Ujfalusi spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); 244f2055e14SPeter Ujfalusi spcr |= mask; 245f2055e14SPeter Ujfalusi 246f2055e14SPeter Ujfalusi if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM)) { 247f2055e14SPeter Ujfalusi /* Start frame sync */ 248f2055e14SPeter Ujfalusi spcr |= DAVINCI_MCBSP_SPCR_FRST; 249f2055e14SPeter Ujfalusi } 250f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); 251f2055e14SPeter Ujfalusi } 252f2055e14SPeter Ujfalusi 253f2055e14SPeter Ujfalusi static void davinci_mcbsp_stop(struct davinci_mcbsp_dev *dev, int playback) 254f2055e14SPeter Ujfalusi { 255f2055e14SPeter Ujfalusi u32 spcr; 256f2055e14SPeter Ujfalusi 257f2055e14SPeter Ujfalusi /* Reset transmitter/receiver and sample rate/frame sync generators */ 258f2055e14SPeter Ujfalusi spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); 259f2055e14SPeter Ujfalusi spcr &= ~(DAVINCI_MCBSP_SPCR_GRST | DAVINCI_MCBSP_SPCR_FRST); 260f2055e14SPeter Ujfalusi spcr &= playback ? ~DAVINCI_MCBSP_SPCR_XRST : ~DAVINCI_MCBSP_SPCR_RRST; 261f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); 262f2055e14SPeter Ujfalusi toggle_clock(dev, playback); 263f2055e14SPeter Ujfalusi } 264f2055e14SPeter Ujfalusi 265f2055e14SPeter Ujfalusi #define DEFAULT_BITPERSAMPLE 16 266f2055e14SPeter Ujfalusi 267f2055e14SPeter Ujfalusi static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, 268f2055e14SPeter Ujfalusi unsigned int fmt) 269f2055e14SPeter Ujfalusi { 270f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); 271f2055e14SPeter Ujfalusi unsigned int pcr; 272f2055e14SPeter Ujfalusi unsigned int srgr; 273f2055e14SPeter Ujfalusi bool inv_fs = false; 274f2055e14SPeter Ujfalusi /* Attention srgr is updated by hw_params! */ 275f2055e14SPeter Ujfalusi srgr = DAVINCI_MCBSP_SRGR_FSGM | 276f2055e14SPeter Ujfalusi DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) | 277f2055e14SPeter Ujfalusi DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1); 278f2055e14SPeter Ujfalusi 279f2055e14SPeter Ujfalusi dev->fmt = fmt; 280f2055e14SPeter Ujfalusi /* set master/slave audio interface */ 281f2055e14SPeter Ujfalusi switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 282f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_CBS_CFS: 283f2055e14SPeter Ujfalusi /* cpu is master */ 284f2055e14SPeter Ujfalusi pcr = DAVINCI_MCBSP_PCR_FSXM | 285f2055e14SPeter Ujfalusi DAVINCI_MCBSP_PCR_FSRM | 286f2055e14SPeter Ujfalusi DAVINCI_MCBSP_PCR_CLKXM | 287f2055e14SPeter Ujfalusi DAVINCI_MCBSP_PCR_CLKRM; 288f2055e14SPeter Ujfalusi break; 289f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_CBM_CFS: 290f2055e14SPeter Ujfalusi pcr = DAVINCI_MCBSP_PCR_FSRM | DAVINCI_MCBSP_PCR_FSXM; 291f2055e14SPeter Ujfalusi /* 292f2055e14SPeter Ujfalusi * Selection of the clock input pin that is the 293f2055e14SPeter Ujfalusi * input for the Sample Rate Generator. 294f2055e14SPeter Ujfalusi * McBSP FSR and FSX are driven by the Sample Rate 295f2055e14SPeter Ujfalusi * Generator. 296f2055e14SPeter Ujfalusi */ 297f2055e14SPeter Ujfalusi switch (dev->clk_input_pin) { 298f2055e14SPeter Ujfalusi case MCBSP_CLKS: 299f2055e14SPeter Ujfalusi pcr |= DAVINCI_MCBSP_PCR_CLKXM | 300f2055e14SPeter Ujfalusi DAVINCI_MCBSP_PCR_CLKRM; 301f2055e14SPeter Ujfalusi break; 302f2055e14SPeter Ujfalusi case MCBSP_CLKR: 303f2055e14SPeter Ujfalusi pcr |= DAVINCI_MCBSP_PCR_SCLKME; 304f2055e14SPeter Ujfalusi break; 305f2055e14SPeter Ujfalusi default: 306f2055e14SPeter Ujfalusi dev_err(dev->dev, "bad clk_input_pin\n"); 307f2055e14SPeter Ujfalusi return -EINVAL; 308f2055e14SPeter Ujfalusi } 309f2055e14SPeter Ujfalusi 310f2055e14SPeter Ujfalusi break; 311f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_CBM_CFM: 312f2055e14SPeter Ujfalusi /* codec is master */ 313f2055e14SPeter Ujfalusi pcr = 0; 314f2055e14SPeter Ujfalusi break; 315f2055e14SPeter Ujfalusi default: 316f2055e14SPeter Ujfalusi printk(KERN_ERR "%s:bad master\n", __func__); 317f2055e14SPeter Ujfalusi return -EINVAL; 318f2055e14SPeter Ujfalusi } 319f2055e14SPeter Ujfalusi 320f2055e14SPeter Ujfalusi /* interface format */ 321f2055e14SPeter Ujfalusi switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 322f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_I2S: 323f2055e14SPeter Ujfalusi /* Davinci doesn't support TRUE I2S, but some codecs will have 324f2055e14SPeter Ujfalusi * the left and right channels contiguous. This allows 325f2055e14SPeter Ujfalusi * dsp_a mode to be used with an inverted normal frame clk. 326f2055e14SPeter Ujfalusi * If your codec is master and does not have contiguous 327f2055e14SPeter Ujfalusi * channels, then you will have sound on only one channel. 328f2055e14SPeter Ujfalusi * Try using a different mode, or codec as slave. 329f2055e14SPeter Ujfalusi * 330f2055e14SPeter Ujfalusi * The TLV320AIC33 is an example of a codec where this works. 331f2055e14SPeter Ujfalusi * It has a variable bit clock frequency allowing it to have 332f2055e14SPeter Ujfalusi * valid data on every bit clock. 333f2055e14SPeter Ujfalusi * 334f2055e14SPeter Ujfalusi * The TLV320AIC23 is an example of a codec where this does not 335f2055e14SPeter Ujfalusi * work. It has a fixed bit clock frequency with progressively 336f2055e14SPeter Ujfalusi * more empty bit clock slots between channels as the sample 337f2055e14SPeter Ujfalusi * rate is lowered. 338f2055e14SPeter Ujfalusi */ 339f2055e14SPeter Ujfalusi inv_fs = true; 340f2055e14SPeter Ujfalusi /* fall through */ 341f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_DSP_A: 342f2055e14SPeter Ujfalusi dev->mode = MOD_DSP_A; 343f2055e14SPeter Ujfalusi break; 344f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_DSP_B: 345f2055e14SPeter Ujfalusi dev->mode = MOD_DSP_B; 346f2055e14SPeter Ujfalusi break; 347f2055e14SPeter Ujfalusi default: 348f2055e14SPeter Ujfalusi printk(KERN_ERR "%s:bad format\n", __func__); 349f2055e14SPeter Ujfalusi return -EINVAL; 350f2055e14SPeter Ujfalusi } 351f2055e14SPeter Ujfalusi 352f2055e14SPeter Ujfalusi switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 353f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_NB_NF: 354f2055e14SPeter Ujfalusi /* CLKRP Receive clock polarity, 355f2055e14SPeter Ujfalusi * 1 - sampled on rising edge of CLKR 356f2055e14SPeter Ujfalusi * valid on rising edge 357f2055e14SPeter Ujfalusi * CLKXP Transmit clock polarity, 358f2055e14SPeter Ujfalusi * 1 - clocked on falling edge of CLKX 359f2055e14SPeter Ujfalusi * valid on rising edge 360f2055e14SPeter Ujfalusi * FSRP Receive frame sync pol, 0 - active high 361f2055e14SPeter Ujfalusi * FSXP Transmit frame sync pol, 0 - active high 362f2055e14SPeter Ujfalusi */ 363f2055e14SPeter Ujfalusi pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP); 364f2055e14SPeter Ujfalusi break; 365f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_IB_IF: 366f2055e14SPeter Ujfalusi /* CLKRP Receive clock polarity, 367f2055e14SPeter Ujfalusi * 0 - sampled on falling edge of CLKR 368f2055e14SPeter Ujfalusi * valid on falling edge 369f2055e14SPeter Ujfalusi * CLKXP Transmit clock polarity, 370f2055e14SPeter Ujfalusi * 0 - clocked on rising edge of CLKX 371f2055e14SPeter Ujfalusi * valid on falling edge 372f2055e14SPeter Ujfalusi * FSRP Receive frame sync pol, 1 - active low 373f2055e14SPeter Ujfalusi * FSXP Transmit frame sync pol, 1 - active low 374f2055e14SPeter Ujfalusi */ 375f2055e14SPeter Ujfalusi pcr |= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP); 376f2055e14SPeter Ujfalusi break; 377f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_NB_IF: 378f2055e14SPeter Ujfalusi /* CLKRP Receive clock polarity, 379f2055e14SPeter Ujfalusi * 1 - sampled on rising edge of CLKR 380f2055e14SPeter Ujfalusi * valid on rising edge 381f2055e14SPeter Ujfalusi * CLKXP Transmit clock polarity, 382f2055e14SPeter Ujfalusi * 1 - clocked on falling edge of CLKX 383f2055e14SPeter Ujfalusi * valid on rising edge 384f2055e14SPeter Ujfalusi * FSRP Receive frame sync pol, 1 - active low 385f2055e14SPeter Ujfalusi * FSXP Transmit frame sync pol, 1 - active low 386f2055e14SPeter Ujfalusi */ 387f2055e14SPeter Ujfalusi pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP | 388f2055e14SPeter Ujfalusi DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP); 389f2055e14SPeter Ujfalusi break; 390f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_IB_NF: 391f2055e14SPeter Ujfalusi /* CLKRP Receive clock polarity, 392f2055e14SPeter Ujfalusi * 0 - sampled on falling edge of CLKR 393f2055e14SPeter Ujfalusi * valid on falling edge 394f2055e14SPeter Ujfalusi * CLKXP Transmit clock polarity, 395f2055e14SPeter Ujfalusi * 0 - clocked on rising edge of CLKX 396f2055e14SPeter Ujfalusi * valid on falling edge 397f2055e14SPeter Ujfalusi * FSRP Receive frame sync pol, 0 - active high 398f2055e14SPeter Ujfalusi * FSXP Transmit frame sync pol, 0 - active high 399f2055e14SPeter Ujfalusi */ 400f2055e14SPeter Ujfalusi break; 401f2055e14SPeter Ujfalusi default: 402f2055e14SPeter Ujfalusi return -EINVAL; 403f2055e14SPeter Ujfalusi } 404f2055e14SPeter Ujfalusi if (inv_fs == true) 405f2055e14SPeter Ujfalusi pcr ^= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP); 406f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); 407f2055e14SPeter Ujfalusi dev->pcr = pcr; 408f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, pcr); 409f2055e14SPeter Ujfalusi return 0; 410f2055e14SPeter Ujfalusi } 411f2055e14SPeter Ujfalusi 412f2055e14SPeter Ujfalusi static int davinci_i2s_dai_set_clkdiv(struct snd_soc_dai *cpu_dai, 413f2055e14SPeter Ujfalusi int div_id, int div) 414f2055e14SPeter Ujfalusi { 415f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); 416f2055e14SPeter Ujfalusi 417f2055e14SPeter Ujfalusi if (div_id != DAVINCI_MCBSP_CLKGDV) 418f2055e14SPeter Ujfalusi return -ENODEV; 419f2055e14SPeter Ujfalusi 420f2055e14SPeter Ujfalusi dev->clk_div = div; 421f2055e14SPeter Ujfalusi return 0; 422f2055e14SPeter Ujfalusi } 423f2055e14SPeter Ujfalusi 424f2055e14SPeter Ujfalusi static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, 425f2055e14SPeter Ujfalusi struct snd_pcm_hw_params *params, 426f2055e14SPeter Ujfalusi struct snd_soc_dai *dai) 427f2055e14SPeter Ujfalusi { 428f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); 429f2055e14SPeter Ujfalusi struct snd_interval *i = NULL; 430f2055e14SPeter Ujfalusi int mcbsp_word_length, master; 431f2055e14SPeter Ujfalusi unsigned int rcr, xcr, srgr, clk_div, freq, framesize; 432f2055e14SPeter Ujfalusi u32 spcr; 433f2055e14SPeter Ujfalusi snd_pcm_format_t fmt; 434f2055e14SPeter Ujfalusi unsigned element_cnt = 1; 435f2055e14SPeter Ujfalusi 436f2055e14SPeter Ujfalusi /* general line settings */ 437f2055e14SPeter Ujfalusi spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); 438f2055e14SPeter Ujfalusi if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 439f2055e14SPeter Ujfalusi spcr |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE; 440f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); 441f2055e14SPeter Ujfalusi } else { 442f2055e14SPeter Ujfalusi spcr |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE; 443f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); 444f2055e14SPeter Ujfalusi } 445f2055e14SPeter Ujfalusi 446f2055e14SPeter Ujfalusi master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK; 447f2055e14SPeter Ujfalusi fmt = params_format(params); 448f2055e14SPeter Ujfalusi mcbsp_word_length = asp_word_length[fmt]; 449f2055e14SPeter Ujfalusi 450f2055e14SPeter Ujfalusi switch (master) { 451f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_CBS_CFS: 452f2055e14SPeter Ujfalusi freq = clk_get_rate(dev->clk); 453f2055e14SPeter Ujfalusi srgr = DAVINCI_MCBSP_SRGR_FSGM | 454f2055e14SPeter Ujfalusi DAVINCI_MCBSP_SRGR_CLKSM; 455f2055e14SPeter Ujfalusi srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 456f2055e14SPeter Ujfalusi 8 - 1); 457f2055e14SPeter Ujfalusi if (dev->i2s_accurate_sck) { 458f2055e14SPeter Ujfalusi clk_div = 256; 459f2055e14SPeter Ujfalusi do { 460f2055e14SPeter Ujfalusi framesize = (freq / (--clk_div)) / 461f2055e14SPeter Ujfalusi params->rate_num * 462f2055e14SPeter Ujfalusi params->rate_den; 463f2055e14SPeter Ujfalusi } while (((framesize < 33) || (framesize > 4095)) && 464f2055e14SPeter Ujfalusi (clk_div)); 465f2055e14SPeter Ujfalusi clk_div--; 466f2055e14SPeter Ujfalusi srgr |= DAVINCI_MCBSP_SRGR_FPER(framesize - 1); 467f2055e14SPeter Ujfalusi } else { 468f2055e14SPeter Ujfalusi /* symmetric waveforms */ 469f2055e14SPeter Ujfalusi clk_div = freq / (mcbsp_word_length * 16) / 470f2055e14SPeter Ujfalusi params->rate_num * params->rate_den; 471f2055e14SPeter Ujfalusi srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length * 472f2055e14SPeter Ujfalusi 16 - 1); 473f2055e14SPeter Ujfalusi } 474f2055e14SPeter Ujfalusi clk_div &= 0xFF; 475f2055e14SPeter Ujfalusi srgr |= clk_div; 476f2055e14SPeter Ujfalusi break; 477f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_CBM_CFS: 478f2055e14SPeter Ujfalusi srgr = DAVINCI_MCBSP_SRGR_FSGM; 479f2055e14SPeter Ujfalusi clk_div = dev->clk_div - 1; 480f2055e14SPeter Ujfalusi srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 8 - 1); 481f2055e14SPeter Ujfalusi srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length * 16 - 1); 482f2055e14SPeter Ujfalusi clk_div &= 0xFF; 483f2055e14SPeter Ujfalusi srgr |= clk_div; 484f2055e14SPeter Ujfalusi break; 485f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_CBM_CFM: 486f2055e14SPeter Ujfalusi /* Clock and frame sync given from external sources */ 487f2055e14SPeter Ujfalusi i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); 488f2055e14SPeter Ujfalusi srgr = DAVINCI_MCBSP_SRGR_FSGM; 489f2055e14SPeter Ujfalusi srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1); 490f2055e14SPeter Ujfalusi pr_debug("%s - %d FWID set: re-read srgr = %X\n", 491f2055e14SPeter Ujfalusi __func__, __LINE__, snd_interval_value(i) - 1); 492f2055e14SPeter Ujfalusi 493f2055e14SPeter Ujfalusi i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS); 494f2055e14SPeter Ujfalusi srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1); 495f2055e14SPeter Ujfalusi break; 496f2055e14SPeter Ujfalusi default: 497f2055e14SPeter Ujfalusi return -EINVAL; 498f2055e14SPeter Ujfalusi } 499f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); 500f2055e14SPeter Ujfalusi 501f2055e14SPeter Ujfalusi rcr = DAVINCI_MCBSP_RCR_RFIG; 502f2055e14SPeter Ujfalusi xcr = DAVINCI_MCBSP_XCR_XFIG; 503f2055e14SPeter Ujfalusi if (dev->mode == MOD_DSP_B) { 504f2055e14SPeter Ujfalusi rcr |= DAVINCI_MCBSP_RCR_RDATDLY(0); 505f2055e14SPeter Ujfalusi xcr |= DAVINCI_MCBSP_XCR_XDATDLY(0); 506f2055e14SPeter Ujfalusi } else { 507f2055e14SPeter Ujfalusi rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1); 508f2055e14SPeter Ujfalusi xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1); 509f2055e14SPeter Ujfalusi } 510f2055e14SPeter Ujfalusi /* Determine xfer data type */ 511f2055e14SPeter Ujfalusi fmt = params_format(params); 512f2055e14SPeter Ujfalusi if ((fmt > SNDRV_PCM_FORMAT_S32_LE) || !data_type[fmt]) { 513f2055e14SPeter Ujfalusi printk(KERN_WARNING "davinci-i2s: unsupported PCM format\n"); 514f2055e14SPeter Ujfalusi return -EINVAL; 515f2055e14SPeter Ujfalusi } 516f2055e14SPeter Ujfalusi 517f2055e14SPeter Ujfalusi if (params_channels(params) == 2) { 518f2055e14SPeter Ujfalusi element_cnt = 2; 519f2055e14SPeter Ujfalusi if (double_fmt[fmt] && dev->enable_channel_combine) { 520f2055e14SPeter Ujfalusi element_cnt = 1; 521f2055e14SPeter Ujfalusi fmt = double_fmt[fmt]; 522f2055e14SPeter Ujfalusi } 523f2055e14SPeter Ujfalusi switch (master) { 524f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_CBS_CFS: 525f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_CBS_CFM: 526f2055e14SPeter Ujfalusi rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(0); 527f2055e14SPeter Ujfalusi xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(0); 528f2055e14SPeter Ujfalusi rcr |= DAVINCI_MCBSP_RCR_RPHASE; 529f2055e14SPeter Ujfalusi xcr |= DAVINCI_MCBSP_XCR_XPHASE; 530f2055e14SPeter Ujfalusi break; 531f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_CBM_CFM: 532f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_CBM_CFS: 533f2055e14SPeter Ujfalusi rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(element_cnt - 1); 534f2055e14SPeter Ujfalusi xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(element_cnt - 1); 535f2055e14SPeter Ujfalusi break; 536f2055e14SPeter Ujfalusi default: 537f2055e14SPeter Ujfalusi return -EINVAL; 538f2055e14SPeter Ujfalusi } 539f2055e14SPeter Ujfalusi } 540f2055e14SPeter Ujfalusi mcbsp_word_length = asp_word_length[fmt]; 541f2055e14SPeter Ujfalusi 542f2055e14SPeter Ujfalusi switch (master) { 543f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_CBS_CFS: 544f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_CBS_CFM: 545f2055e14SPeter Ujfalusi rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(0); 546f2055e14SPeter Ujfalusi xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(0); 547f2055e14SPeter Ujfalusi break; 548f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_CBM_CFM: 549f2055e14SPeter Ujfalusi case SND_SOC_DAIFMT_CBM_CFS: 550f2055e14SPeter Ujfalusi rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1); 551f2055e14SPeter Ujfalusi xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1); 552f2055e14SPeter Ujfalusi break; 553f2055e14SPeter Ujfalusi default: 554f2055e14SPeter Ujfalusi return -EINVAL; 555f2055e14SPeter Ujfalusi } 556f2055e14SPeter Ujfalusi 557f2055e14SPeter Ujfalusi rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | 558f2055e14SPeter Ujfalusi DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length); 559f2055e14SPeter Ujfalusi xcr |= DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | 560f2055e14SPeter Ujfalusi DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length); 561f2055e14SPeter Ujfalusi 562f2055e14SPeter Ujfalusi if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 563f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr); 564f2055e14SPeter Ujfalusi else 565f2055e14SPeter Ujfalusi davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr); 566f2055e14SPeter Ujfalusi 567f2055e14SPeter Ujfalusi pr_debug("%s - %d srgr=%X\n", __func__, __LINE__, srgr); 568f2055e14SPeter Ujfalusi pr_debug("%s - %d xcr=%X\n", __func__, __LINE__, xcr); 569f2055e14SPeter Ujfalusi pr_debug("%s - %d rcr=%X\n", __func__, __LINE__, rcr); 570f2055e14SPeter Ujfalusi return 0; 571f2055e14SPeter Ujfalusi } 572f2055e14SPeter Ujfalusi 573f2055e14SPeter Ujfalusi static int davinci_i2s_prepare(struct snd_pcm_substream *substream, 574f2055e14SPeter Ujfalusi struct snd_soc_dai *dai) 575f2055e14SPeter Ujfalusi { 576f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); 577f2055e14SPeter Ujfalusi int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 578f2055e14SPeter Ujfalusi davinci_mcbsp_stop(dev, playback); 579f2055e14SPeter Ujfalusi return 0; 580f2055e14SPeter Ujfalusi } 581f2055e14SPeter Ujfalusi 582f2055e14SPeter Ujfalusi static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, 583f2055e14SPeter Ujfalusi struct snd_soc_dai *dai) 584f2055e14SPeter Ujfalusi { 585f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); 586f2055e14SPeter Ujfalusi int ret = 0; 587f2055e14SPeter Ujfalusi int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 588f2055e14SPeter Ujfalusi 589f2055e14SPeter Ujfalusi switch (cmd) { 590f2055e14SPeter Ujfalusi case SNDRV_PCM_TRIGGER_START: 591f2055e14SPeter Ujfalusi case SNDRV_PCM_TRIGGER_RESUME: 592f2055e14SPeter Ujfalusi case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 593f2055e14SPeter Ujfalusi davinci_mcbsp_start(dev, substream); 594f2055e14SPeter Ujfalusi break; 595f2055e14SPeter Ujfalusi case SNDRV_PCM_TRIGGER_STOP: 596f2055e14SPeter Ujfalusi case SNDRV_PCM_TRIGGER_SUSPEND: 597f2055e14SPeter Ujfalusi case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 598f2055e14SPeter Ujfalusi davinci_mcbsp_stop(dev, playback); 599f2055e14SPeter Ujfalusi break; 600f2055e14SPeter Ujfalusi default: 601f2055e14SPeter Ujfalusi ret = -EINVAL; 602f2055e14SPeter Ujfalusi } 603f2055e14SPeter Ujfalusi return ret; 604f2055e14SPeter Ujfalusi } 605f2055e14SPeter Ujfalusi 606f2055e14SPeter Ujfalusi static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, 607f2055e14SPeter Ujfalusi struct snd_soc_dai *dai) 608f2055e14SPeter Ujfalusi { 609f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); 610f2055e14SPeter Ujfalusi int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 611f2055e14SPeter Ujfalusi davinci_mcbsp_stop(dev, playback); 612f2055e14SPeter Ujfalusi } 613f2055e14SPeter Ujfalusi 614f2055e14SPeter Ujfalusi #define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000 615*2231b2c6SPeter Ujfalusi #define DAVINCI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 616*2231b2c6SPeter Ujfalusi SNDRV_PCM_FMTBIT_S32_LE) 617f2055e14SPeter Ujfalusi 618f2055e14SPeter Ujfalusi static const struct snd_soc_dai_ops davinci_i2s_dai_ops = { 619f2055e14SPeter Ujfalusi .shutdown = davinci_i2s_shutdown, 620f2055e14SPeter Ujfalusi .prepare = davinci_i2s_prepare, 621f2055e14SPeter Ujfalusi .trigger = davinci_i2s_trigger, 622f2055e14SPeter Ujfalusi .hw_params = davinci_i2s_hw_params, 623f2055e14SPeter Ujfalusi .set_fmt = davinci_i2s_set_dai_fmt, 624f2055e14SPeter Ujfalusi .set_clkdiv = davinci_i2s_dai_set_clkdiv, 625f2055e14SPeter Ujfalusi 626f2055e14SPeter Ujfalusi }; 627f2055e14SPeter Ujfalusi 628f2055e14SPeter Ujfalusi static int davinci_i2s_dai_probe(struct snd_soc_dai *dai) 629f2055e14SPeter Ujfalusi { 630f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); 631f2055e14SPeter Ujfalusi 632f2055e14SPeter Ujfalusi dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; 633f2055e14SPeter Ujfalusi dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]; 634f2055e14SPeter Ujfalusi 635f2055e14SPeter Ujfalusi return 0; 636f2055e14SPeter Ujfalusi } 637f2055e14SPeter Ujfalusi 638f2055e14SPeter Ujfalusi static struct snd_soc_dai_driver davinci_i2s_dai = { 639f2055e14SPeter Ujfalusi .probe = davinci_i2s_dai_probe, 640f2055e14SPeter Ujfalusi .playback = { 641f2055e14SPeter Ujfalusi .channels_min = 2, 642f2055e14SPeter Ujfalusi .channels_max = 2, 643f2055e14SPeter Ujfalusi .rates = DAVINCI_I2S_RATES, 644*2231b2c6SPeter Ujfalusi .formats = DAVINCI_I2S_FORMATS, 645*2231b2c6SPeter Ujfalusi }, 646f2055e14SPeter Ujfalusi .capture = { 647f2055e14SPeter Ujfalusi .channels_min = 2, 648f2055e14SPeter Ujfalusi .channels_max = 2, 649f2055e14SPeter Ujfalusi .rates = DAVINCI_I2S_RATES, 650*2231b2c6SPeter Ujfalusi .formats = DAVINCI_I2S_FORMATS, 651*2231b2c6SPeter Ujfalusi }, 652f2055e14SPeter Ujfalusi .ops = &davinci_i2s_dai_ops, 653f2055e14SPeter Ujfalusi 654f2055e14SPeter Ujfalusi }; 655f2055e14SPeter Ujfalusi 656f2055e14SPeter Ujfalusi static const struct snd_soc_component_driver davinci_i2s_component = { 657f2055e14SPeter Ujfalusi .name = DRV_NAME, 658f2055e14SPeter Ujfalusi }; 659f2055e14SPeter Ujfalusi 660f2055e14SPeter Ujfalusi static int davinci_i2s_probe(struct platform_device *pdev) 661f2055e14SPeter Ujfalusi { 662f2055e14SPeter Ujfalusi struct snd_dmaengine_dai_dma_data *dma_data; 663f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev *dev; 664f2055e14SPeter Ujfalusi struct resource *mem, *res; 665f2055e14SPeter Ujfalusi void __iomem *io_base; 666f2055e14SPeter Ujfalusi int *dma; 667f2055e14SPeter Ujfalusi int ret; 668f2055e14SPeter Ujfalusi 669f2055e14SPeter Ujfalusi mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); 670f2055e14SPeter Ujfalusi if (!mem) { 671f2055e14SPeter Ujfalusi dev_warn(&pdev->dev, 672f2055e14SPeter Ujfalusi "\"mpu\" mem resource not found, using index 0\n"); 673f2055e14SPeter Ujfalusi mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 674f2055e14SPeter Ujfalusi if (!mem) { 675f2055e14SPeter Ujfalusi dev_err(&pdev->dev, "no mem resource?\n"); 676f2055e14SPeter Ujfalusi return -ENODEV; 677f2055e14SPeter Ujfalusi } 678f2055e14SPeter Ujfalusi } 679f2055e14SPeter Ujfalusi 680f2055e14SPeter Ujfalusi io_base = devm_ioremap_resource(&pdev->dev, mem); 681f2055e14SPeter Ujfalusi if (IS_ERR(io_base)) 682f2055e14SPeter Ujfalusi return PTR_ERR(io_base); 683f2055e14SPeter Ujfalusi 684f2055e14SPeter Ujfalusi dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcbsp_dev), 685f2055e14SPeter Ujfalusi GFP_KERNEL); 686f2055e14SPeter Ujfalusi if (!dev) 687f2055e14SPeter Ujfalusi return -ENOMEM; 688f2055e14SPeter Ujfalusi 689f2055e14SPeter Ujfalusi dev->base = io_base; 690f2055e14SPeter Ujfalusi 691f2055e14SPeter Ujfalusi /* setup DMA, first TX, then RX */ 692f2055e14SPeter Ujfalusi dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; 693f2055e14SPeter Ujfalusi dma_data->addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG); 694f2055e14SPeter Ujfalusi 695f2055e14SPeter Ujfalusi res = platform_get_resource(pdev, IORESOURCE_DMA, 0); 696f2055e14SPeter Ujfalusi if (res) { 697f2055e14SPeter Ujfalusi dma = &dev->dma_request[SNDRV_PCM_STREAM_PLAYBACK]; 698f2055e14SPeter Ujfalusi *dma = res->start; 699f2055e14SPeter Ujfalusi dma_data->filter_data = dma; 700f2055e14SPeter Ujfalusi } else if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { 701f2055e14SPeter Ujfalusi dma_data->filter_data = "tx"; 702f2055e14SPeter Ujfalusi } else { 703f2055e14SPeter Ujfalusi dev_err(&pdev->dev, "Missing DMA tx resource\n"); 704f2055e14SPeter Ujfalusi return -ENODEV; 705f2055e14SPeter Ujfalusi } 706f2055e14SPeter Ujfalusi 707f2055e14SPeter Ujfalusi dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]; 708f2055e14SPeter Ujfalusi dma_data->addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DRR_REG); 709f2055e14SPeter Ujfalusi 710f2055e14SPeter Ujfalusi res = platform_get_resource(pdev, IORESOURCE_DMA, 1); 711f2055e14SPeter Ujfalusi if (res) { 712f2055e14SPeter Ujfalusi dma = &dev->dma_request[SNDRV_PCM_STREAM_CAPTURE]; 713f2055e14SPeter Ujfalusi *dma = res->start; 714f2055e14SPeter Ujfalusi dma_data->filter_data = dma; 715f2055e14SPeter Ujfalusi } else if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { 716f2055e14SPeter Ujfalusi dma_data->filter_data = "rx"; 717f2055e14SPeter Ujfalusi } else { 718f2055e14SPeter Ujfalusi dev_err(&pdev->dev, "Missing DMA rx resource\n"); 719f2055e14SPeter Ujfalusi return -ENODEV; 720f2055e14SPeter Ujfalusi } 721f2055e14SPeter Ujfalusi 722f2055e14SPeter Ujfalusi dev->clk = clk_get(&pdev->dev, NULL); 723f2055e14SPeter Ujfalusi if (IS_ERR(dev->clk)) 724f2055e14SPeter Ujfalusi return -ENODEV; 725f2055e14SPeter Ujfalusi clk_enable(dev->clk); 726f2055e14SPeter Ujfalusi 727f2055e14SPeter Ujfalusi dev->dev = &pdev->dev; 728f2055e14SPeter Ujfalusi dev_set_drvdata(&pdev->dev, dev); 729f2055e14SPeter Ujfalusi 730f2055e14SPeter Ujfalusi ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component, 731f2055e14SPeter Ujfalusi &davinci_i2s_dai, 1); 732f2055e14SPeter Ujfalusi if (ret != 0) 733f2055e14SPeter Ujfalusi goto err_release_clk; 734f2055e14SPeter Ujfalusi 735f2055e14SPeter Ujfalusi ret = edma_pcm_platform_register(&pdev->dev); 736f2055e14SPeter Ujfalusi if (ret) { 737f2055e14SPeter Ujfalusi dev_err(&pdev->dev, "register PCM failed: %d\n", ret); 738f2055e14SPeter Ujfalusi goto err_unregister_component; 739f2055e14SPeter Ujfalusi } 740f2055e14SPeter Ujfalusi 741f2055e14SPeter Ujfalusi return 0; 742f2055e14SPeter Ujfalusi 743f2055e14SPeter Ujfalusi err_unregister_component: 744f2055e14SPeter Ujfalusi snd_soc_unregister_component(&pdev->dev); 745f2055e14SPeter Ujfalusi err_release_clk: 746f2055e14SPeter Ujfalusi clk_disable(dev->clk); 747f2055e14SPeter Ujfalusi clk_put(dev->clk); 748f2055e14SPeter Ujfalusi return ret; 749f2055e14SPeter Ujfalusi } 750f2055e14SPeter Ujfalusi 751f2055e14SPeter Ujfalusi static int davinci_i2s_remove(struct platform_device *pdev) 752f2055e14SPeter Ujfalusi { 753f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev); 754f2055e14SPeter Ujfalusi 755f2055e14SPeter Ujfalusi snd_soc_unregister_component(&pdev->dev); 756f2055e14SPeter Ujfalusi 757f2055e14SPeter Ujfalusi clk_disable(dev->clk); 758f2055e14SPeter Ujfalusi clk_put(dev->clk); 759f2055e14SPeter Ujfalusi dev->clk = NULL; 760f2055e14SPeter Ujfalusi 761f2055e14SPeter Ujfalusi return 0; 762f2055e14SPeter Ujfalusi } 763f2055e14SPeter Ujfalusi 764f2055e14SPeter Ujfalusi static const struct of_device_id davinci_i2s_match[] = { 765f2055e14SPeter Ujfalusi { .compatible = "ti,da850-mcbsp" }, 766f2055e14SPeter Ujfalusi {}, 767f2055e14SPeter Ujfalusi }; 768f2055e14SPeter Ujfalusi MODULE_DEVICE_TABLE(of, davinci_i2s_match); 769f2055e14SPeter Ujfalusi 770f2055e14SPeter Ujfalusi static struct platform_driver davinci_mcbsp_driver = { 771f2055e14SPeter Ujfalusi .probe = davinci_i2s_probe, 772f2055e14SPeter Ujfalusi .remove = davinci_i2s_remove, 773f2055e14SPeter Ujfalusi .driver = { 774f2055e14SPeter Ujfalusi .name = "davinci-mcbsp", 775f2055e14SPeter Ujfalusi .of_match_table = of_match_ptr(davinci_i2s_match), 776f2055e14SPeter Ujfalusi }, 777f2055e14SPeter Ujfalusi }; 778f2055e14SPeter Ujfalusi 779f2055e14SPeter Ujfalusi module_platform_driver(davinci_mcbsp_driver); 780f2055e14SPeter Ujfalusi 781f2055e14SPeter Ujfalusi MODULE_AUTHOR("Vladimir Barinov"); 782f2055e14SPeter Ujfalusi MODULE_DESCRIPTION("TI DAVINCI I2S (McBSP) SoC Interface"); 783f2055e14SPeter Ujfalusi MODULE_LICENSE("GPL"); 784