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