cregit-Linux how code gets into the kernel

Release 4.7 sound/soc/davinci/davinci-i2s.c

/*
 * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor
 *
 * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
 * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
 *
 * DT support   (c) 2016 Petr Kulhavy, Barix AG <petr@barix.com>
 *              based on davinci-mcasp.c DT support
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * TODO:
 * on DA850 implement HW FIFOs instead of DMA into DXR and DRR registers
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/platform_data/davinci_asp.h>

#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>

#include "edma-pcm.h"
#include "davinci-i2s.h"


/*
 * NOTE:  terminology here is confusing.
 *
 *  - This driver supports the "Audio Serial Port" (ASP),
 *    found on dm6446, dm355, and other DaVinci chips.
 *
 *  - But it labels it a "Multi-channel Buffered Serial Port"
 *    (McBSP) as on older chips like the dm642 ... which was
 *    backward-compatible, possibly explaining that confusion.
 *
 *  - OMAP chips have a controller called McBSP, which is
 *    incompatible with the DaVinci flavor of McBSP.
 *
 *  - Newer DaVinci chips have a controller called McASP,
 *    incompatible with ASP and with either McBSP.
 *
 * In short:  this uses ASP to implement I2S, not McBSP.
 * And it won't be the only DaVinci implemention of I2S.
 */

#define DAVINCI_MCBSP_DRR_REG	0x00

#define DAVINCI_MCBSP_DXR_REG	0x04

#define DAVINCI_MCBSP_SPCR_REG	0x08

#define DAVINCI_MCBSP_RCR_REG	0x0c

#define DAVINCI_MCBSP_XCR_REG	0x10

#define DAVINCI_MCBSP_SRGR_REG	0x14

#define DAVINCI_MCBSP_PCR_REG	0x24


#define DAVINCI_MCBSP_SPCR_RRST		(1 << 0)

#define DAVINCI_MCBSP_SPCR_RINTM(v)	((v) << 4)

#define DAVINCI_MCBSP_SPCR_XRST		(1 << 16)

#define DAVINCI_MCBSP_SPCR_XINTM(v)	((v) << 20)

#define DAVINCI_MCBSP_SPCR_GRST		(1 << 22)

#define DAVINCI_MCBSP_SPCR_FRST		(1 << 23)

#define DAVINCI_MCBSP_SPCR_FREE		(1 << 25)


#define DAVINCI_MCBSP_RCR_RWDLEN1(v)	((v) << 5)

#define DAVINCI_MCBSP_RCR_RFRLEN1(v)	((v) << 8)

#define DAVINCI_MCBSP_RCR_RDATDLY(v)	((v) << 16)

#define DAVINCI_MCBSP_RCR_RFIG		(1 << 18)

#define DAVINCI_MCBSP_RCR_RWDLEN2(v)	((v) << 21)

#define DAVINCI_MCBSP_RCR_RFRLEN2(v)	((v) << 24)

#define DAVINCI_MCBSP_RCR_RPHASE	BIT(31)


#define DAVINCI_MCBSP_XCR_XWDLEN1(v)	((v) << 5)

#define DAVINCI_MCBSP_XCR_XFRLEN1(v)	((v) << 8)

#define DAVINCI_MCBSP_XCR_XDATDLY(v)	((v) << 16)

#define DAVINCI_MCBSP_XCR_XFIG		(1 << 18)

#define DAVINCI_MCBSP_XCR_XWDLEN2(v)	((v) << 21)

#define DAVINCI_MCBSP_XCR_XFRLEN2(v)	((v) << 24)

#define DAVINCI_MCBSP_XCR_XPHASE	BIT(31)


#define DAVINCI_MCBSP_SRGR_FWID(v)	((v) << 8)

#define DAVINCI_MCBSP_SRGR_FPER(v)	((v) << 16)

#define DAVINCI_MCBSP_SRGR_FSGM		(1 << 28)

#define DAVINCI_MCBSP_SRGR_CLKSM	BIT(29)


#define DAVINCI_MCBSP_PCR_CLKRP		(1 << 0)

#define DAVINCI_MCBSP_PCR_CLKXP		(1 << 1)

#define DAVINCI_MCBSP_PCR_FSRP		(1 << 2)

#define DAVINCI_MCBSP_PCR_FSXP		(1 << 3)

#define DAVINCI_MCBSP_PCR_SCLKME	(1 << 7)

#define DAVINCI_MCBSP_PCR_CLKRM		(1 << 8)

#define DAVINCI_MCBSP_PCR_CLKXM		(1 << 9)

#define DAVINCI_MCBSP_PCR_FSRM		(1 << 10)

#define DAVINCI_MCBSP_PCR_FSXM		(1 << 11)

enum {
	
DAVINCI_MCBSP_WORD_8 = 0,
	
DAVINCI_MCBSP_WORD_12,
	
DAVINCI_MCBSP_WORD_16,
	
DAVINCI_MCBSP_WORD_20,
	
DAVINCI_MCBSP_WORD_24,
	
DAVINCI_MCBSP_WORD_32,
};


static const unsigned char data_type[SNDRV_PCM_FORMAT_S32_LE + 1] = {
	[SNDRV_PCM_FORMAT_S8]		= 1,
	[SNDRV_PCM_FORMAT_S16_LE]	= 2,
	[SNDRV_PCM_FORMAT_S32_LE]	= 4,
};


static const unsigned char asp_word_length[SNDRV_PCM_FORMAT_S32_LE + 1] = {
	[SNDRV_PCM_FORMAT_S8]		= DAVINCI_MCBSP_WORD_8,
	[SNDRV_PCM_FORMAT_S16_LE]	= DAVINCI_MCBSP_WORD_16,
	[SNDRV_PCM_FORMAT_S32_LE]	= DAVINCI_MCBSP_WORD_32,
};


static const unsigned char double_fmt[SNDRV_PCM_FORMAT_S32_LE + 1] = {
	[SNDRV_PCM_FORMAT_S8]		= SNDRV_PCM_FORMAT_S16_LE,
	[SNDRV_PCM_FORMAT_S16_LE]	= SNDRV_PCM_FORMAT_S32_LE,
};


struct davinci_mcbsp_dev {
	
struct device *dev;
	
struct snd_dmaengine_dai_dma_data dma_data[2];
	
int dma_request[2];
	
void __iomem			*base;

#define MOD_DSP_A	0

#define MOD_DSP_B	1
	
int				mode;
	
u32				pcr;
	
struct clk			*clk;
	/*
         * Combining both channels into 1 element will at least double the
         * amount of time between servicing the dma channel, increase
         * effiency, and reduce the chance of overrun/underrun. But,
         * it will result in the left & right channels being swapped.
         *
         * If relabeling the left and right channels is not possible,
         * you may want to let the codec know to swap them back.
         *
         * It may allow x10 the amount of time to service dma requests,
         * if the codec is master and is using an unnecessarily fast bit clock
         * (ie. tlvaic23b), independent of the sample rate. So, having an
         * entire frame at once means it can be serviced at the sample rate
         * instead of the bit clock rate.
         *
         * In the now unlikely case that an underrun still
         * occurs, both the left and right samples will be repeated
         * so that no pops are heard, and the left and right channels
         * won't end up being swapped because of the underrun.
         */
	
unsigned enable_channel_combine:1;

	
unsigned int fmt;
	
int clk_div;
	
int clk_input_pin;
	
bool i2s_accurate_sck;
};


static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev, int reg, u32 val) { __raw_writel(val, dev->base + reg); }

Contributors

PersonTokensPropCommitsCommitProp
vladimir barinovvladimir barinov29100.00%1100.00%
Total29100.00%1100.00%


static inline u32 davinci_mcbsp_read_reg(struct davinci_mcbsp_dev *dev, int reg) { return __raw_readl(dev->base + reg); }

Contributors

PersonTokensPropCommitsCommitProp
vladimir barinovvladimir barinov25100.00%1100.00%
Total25100.00%1100.00%


static void toggle_clock(struct davinci_mcbsp_dev *dev, int playback) { u32 m = playback ? DAVINCI_MCBSP_PCR_CLKXP : DAVINCI_MCBSP_PCR_CLKRP; /* The clock needs to toggle to complete reset. * So, fake it by toggling the clk polarity. */ davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, dev->pcr ^ m); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, dev->pcr); }

Contributors

PersonTokensPropCommitsCommitProp
troy kiskytroy kisky48100.00%1100.00%
Total48100.00%1100.00%


static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev, struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_platform *platform = rtd->platform; int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); u32 spcr; u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST; spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); if (spcr & mask) { /* start off disabled */ davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr & ~mask); toggle_clock(dev, playback); } if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM | DAVINCI_MCBSP_PCR_CLKXM | DAVINCI_MCBSP_PCR_CLKRM)) { /* Start the sample generator */ spcr |= DAVINCI_MCBSP_SPCR_GRST; davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); } if (playback) { /* Stop the DMA to avoid data loss */ /* while the transmitter is out of reset to handle XSYNCERR */ if (platform->driver->ops->trigger) { int ret = platform->driver->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP); if (ret < 0) printk(KERN_DEBUG "Playback DMA stop failed\n"); } /* Enable the transmitter */ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); spcr |= DAVINCI_MCBSP_SPCR_XRST; davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); /* wait for any unexpected frame sync error to occur */ udelay(100); /* Disable the transmitter to clear any outstanding XSYNCERR */ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); spcr &= ~DAVINCI_MCBSP_SPCR_XRST; davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); toggle_clock(dev, playback); /* Restart the DMA */ if (platform->driver->ops->trigger) { int ret = platform->driver->ops->trigger(substream, SNDRV_PCM_TRIGGER_START); if (ret < 0) printk(KERN_DEBUG "Playback DMA start failed\n"); } } /* Enable transmitter or receiver */ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); spcr |= mask; if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM)) { /* Start frame sync */ spcr |= DAVINCI_MCBSP_SPCR_FRST; } davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); }

Contributors

PersonTokensPropCommitsCommitProp
naresh medisettynaresh medisetty13341.96%111.11%
troy kiskytroy kisky12138.17%555.56%
vladimir barinovvladimir barinov4915.46%111.11%
liam girdwoodliam girdwood134.10%111.11%
mark brownmark brown10.32%111.11%
Total317100.00%9100.00%


static void davinci_mcbsp_stop(struct davinci_mcbsp_dev *dev, int playback) { u32 spcr; /* Reset transmitter/receiver and sample rate/frame sync generators */ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); spcr &= ~(DAVINCI_MCBSP_SPCR_GRST | DAVINCI_MCBSP_SPCR_FRST); spcr &= playback ? ~DAVINCI_MCBSP_SPCR_XRST : ~DAVINCI_MCBSP_SPCR_RRST; davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); toggle_clock(dev, playback); }

Contributors

PersonTokensPropCommitsCommitProp
vladimir barinovvladimir barinov3353.23%125.00%
troy kiskytroy kisky2946.77%375.00%
Total62100.00%4100.00%

#define DEFAULT_BITPERSAMPLE 16
static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); unsigned int pcr; unsigned int srgr; bool inv_fs = false; /* Attention srgr is updated by hw_params! */ srgr = DAVINCI_MCBSP_SRGR_FSGM | DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) | DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1); dev->fmt = fmt; /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: /* cpu is master */ pcr = DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM | DAVINCI_MCBSP_PCR_CLKXM | DAVINCI_MCBSP_PCR_CLKRM; break; case SND_SOC_DAIFMT_CBM_CFS: pcr = DAVINCI_MCBSP_PCR_FSRM | DAVINCI_MCBSP_PCR_FSXM; /* * Selection of the clock input pin that is the * input for the Sample Rate Generator. * McBSP FSR and FSX are driven by the Sample Rate * Generator. */ switch (dev->clk_input_pin) { case MCBSP_CLKS: pcr |= DAVINCI_MCBSP_PCR_CLKXM | DAVINCI_MCBSP_PCR_CLKRM; break; case MCBSP_CLKR: pcr |= DAVINCI_MCBSP_PCR_SCLKME; break; default: dev_err(dev->dev, "bad clk_input_pin\n"); return -EINVAL; } break; case SND_SOC_DAIFMT_CBM_CFM: /* codec is master */ pcr = 0; break; default: printk(KERN_ERR "%s:bad master\n", __func__); return -EINVAL; } /* interface format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: /* Davinci doesn't support TRUE I2S, but some codecs will have * the left and right channels contiguous. This allows * dsp_a mode to be used with an inverted normal frame clk. * If your codec is master and does not have contiguous * channels, then you will have sound on only one channel. * Try using a different mode, or codec as slave. * * The TLV320AIC33 is an example of a codec where this works. * It has a variable bit clock frequency allowing it to have * valid data on every bit clock. * * The TLV320AIC23 is an example of a codec where this does not * work. It has a fixed bit clock frequency with progressively * more empty bit clock slots between channels as the sample * rate is lowered. */ inv_fs = true; case SND_SOC_DAIFMT_DSP_A: dev->mode = MOD_DSP_A; break; case SND_SOC_DAIFMT_DSP_B: dev->mode = MOD_DSP_B; break; default: printk(KERN_ERR "%s:bad format\n", __func__); return -EINVAL; } switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: /* CLKRP Receive clock polarity, * 1 - sampled on rising edge of CLKR * valid on rising edge * CLKXP Transmit clock polarity, * 1 - clocked on falling edge of CLKX * valid on rising edge * FSRP Receive frame sync pol, 0 - active high * FSXP Transmit frame sync pol, 0 - active high */ pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP); break; case SND_SOC_DAIFMT_IB_IF: /* CLKRP Receive clock polarity, * 0 - sampled on falling edge of CLKR * valid on falling edge * CLKXP Transmit clock polarity, * 0 - clocked on rising edge of CLKX * valid on falling edge * FSRP Receive frame sync pol, 1 - active low * FSXP Transmit frame sync pol, 1 - active low */ pcr |= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP); break; case SND_SOC_DAIFMT_NB_IF: /* CLKRP Receive clock polarity, * 1 - sampled on rising edge of CLKR * valid on rising edge * CLKXP Transmit clock polarity, * 1 - clocked on falling edge of CLKX * valid on rising edge * FSRP Receive frame sync pol, 1 - active low * FSXP Transmit frame sync pol, 1 - active low */ pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP | DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP); break; case SND_SOC_DAIFMT_IB_NF: /* CLKRP Receive clock polarity, * 0 - sampled on falling edge of CLKR * valid on falling edge * CLKXP Transmit clock polarity, * 0 - clocked on rising edge of CLKX * valid on falling edge * FSRP Receive frame sync pol, 0 - active high * FSXP Transmit frame sync pol, 0 - active high */ break; default: return -EINVAL; } if (inv_fs == true) pcr ^= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); dev->pcr = pcr; davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, pcr); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
troy kiskytroy kisky15850.32%646.15%
vladimir barinovvladimir barinov5517.52%17.69%
raffaele recalcatiraffaele recalcati4815.29%215.38%
hugo villeneuvehugo villeneuve278.60%17.69%
jarkko nikulajarkko nikula227.01%17.69%
liam girdwoodliam girdwood41.27%215.38%
Total314100.00%13100.00%


static int davinci_i2s_dai_set_clkdiv(struct snd_soc_dai *cpu_dai, int div_id, int div) { struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); if (div_id != DAVINCI_MCBSP_CLKGDV) return -ENODEV; dev->clk_div = div; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
raffaele recalcatiraffaele recalcati4393.48%150.00%
liam girdwoodliam girdwood36.52%150.00%
Total46100.00%2100.00%


static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); struct snd_interval *i = NULL; int mcbsp_word_length, master; unsigned int rcr, xcr, srgr, clk_div, freq, framesize; u32 spcr; snd_pcm_format_t fmt; unsigned element_cnt = 1; /* general line settings */ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { spcr |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE; davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); } else { spcr |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE; davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); } master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK; fmt = params_format(params); mcbsp_word_length = asp_word_length[fmt]; switch (master) { case SND_SOC_DAIFMT_CBS_CFS: freq = clk_get_rate(dev->clk); srgr = DAVINCI_MCBSP_SRGR_FSGM | DAVINCI_MCBSP_SRGR_CLKSM; srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 8 - 1); if (dev->i2s_accurate_sck) { clk_div = 256; do { framesize = (freq / (--clk_div)) / params->rate_num * params->rate_den; } while (((framesize < 33) || (framesize > 4095)) && (clk_div)); clk_div--; srgr |= DAVINCI_MCBSP_SRGR_FPER(framesize - 1); } else { /* symmetric waveforms */ clk_div = freq / (mcbsp_word_length * 16) / params->rate_num * params->rate_den; srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length * 16 - 1); } clk_div &= 0xFF; srgr |= clk_div; break; case SND_SOC_DAIFMT_CBM_CFS: srgr = DAVINCI_MCBSP_SRGR_FSGM; clk_div = dev->clk_div - 1; srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 8 - 1); srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length * 16 - 1); clk_div &= 0xFF; srgr |= clk_div; break; case SND_SOC_DAIFMT_CBM_CFM: /* Clock and frame sync given from external sources */ i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); srgr = DAVINCI_MCBSP_SRGR_FSGM; srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1); pr_debug("%s - %d FWID set: re-read srgr = %X\n", __func__, __LINE__, snd_interval_value(i) - 1); i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS); srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1); break; default: return -EINVAL; } davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); rcr = DAVINCI_MCBSP_RCR_RFIG; xcr = DAVINCI_MCBSP_XCR_XFIG; if (dev->mode == MOD_DSP_B) { rcr |= DAVINCI_MCBSP_RCR_RDATDLY(0); xcr |= DAVINCI_MCBSP_XCR_XDATDLY(0); } else { rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1); xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1); } /* Determine xfer data type */ fmt = params_format(params); if ((fmt > SNDRV_PCM_FORMAT_S32_LE) || !data_type[fmt]) { printk(KERN_WARNING "davinci-i2s: unsupported PCM format\n"); return -EINVAL; } if (params_channels(params) == 2) { element_cnt = 2; if (double_fmt[fmt] && dev->enable_channel_combine) { element_cnt = 1; fmt = double_fmt[fmt]; } switch (master) { case SND_SOC_DAIFMT_CBS_CFS: case SND_SOC_DAIFMT_CBS_CFM: rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(0); xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(0); rcr |= DAVINCI_MCBSP_RCR_RPHASE; xcr |= DAVINCI_MCBSP_XCR_XPHASE; break; case SND_SOC_DAIFMT_CBM_CFM: case SND_SOC_DAIFMT_CBM_CFS: rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(element_cnt - 1); xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(element_cnt - 1); break; default: return -EINVAL; } } mcbsp_word_length = asp_word_length[fmt]; switch (master) { case SND_SOC_DAIFMT_CBS_CFS: case SND_SOC_DAIFMT_CBS_CFM: rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(0); xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(0); break; case SND_SOC_DAIFMT_CBM_CFM: case SND_SOC_DAIFMT_CBM_CFS: rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1); xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1); break; default: return -EINVAL; } rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length); xcr |= DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr); else davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr); pr_debug("%s - %d srgr=%X\n", __func__, __LINE__, srgr); pr_debug("%s - %d xcr=%X\n", __func__, __LINE__, xcr); pr_debug("%s - %d rcr=%X\n", __func__, __LINE__, rcr); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
raffaele recalcatiraffaele recalcati38350.53%216.67%
troy kiskytroy kisky17923.61%541.67%
vladimir barinovvladimir barinov15119.92%18.33%
naresh medisettynaresh medisetty364.75%18.33%
mark brownmark brown50.66%18.33%
liam girdwoodliam girdwood30.40%18.33%
jean delvarejean delvare10.13%18.33%
Total758100.00%12100.00%


static int davinci_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); davinci_mcbsp_stop(dev, playback); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
troy kiskytroy kisky4493.62%150.00%
liam girdwoodliam girdwood36.38%150.00%
Total47100.00%2100.00%


static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); int ret = 0; int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: davinci_mcbsp_start(dev, substream); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: davinci_mcbsp_stop(dev, playback); break; default: ret = -EINVAL; } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
vladimir barinovvladimir barinov6367.02%125.00%
troy kiskytroy kisky2324.47%125.00%
mark brownmark brown55.32%125.00%
liam girdwoodliam girdwood33.19%125.00%
Total94100.00%4100.00%


static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); davinci_mcbsp_stop(dev, playback); }

Contributors

PersonTokensPropCommitsCommitProp
troy kiskytroy kisky4193.18%150.00%
liam girdwoodliam girdwood36.82%150.00%
Total44100.00%2100.00%

#define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000 static const struct snd_soc_dai_ops davinci_i2s_dai_ops = { .shutdown = davinci_i2s_shutdown, .prepare = davinci_i2s_prepare, .trigger = davinci_i2s_trigger, .hw_params = davinci_i2s_hw_params, .set_fmt = davinci_i2s_set_dai_fmt, .set_clkdiv = davinci_i2s_dai_set_clkdiv, };
static int davinci_i2s_dai_probe(struct snd_soc_dai *dai) { struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
peter ujfalusipeter ujfalusi48100.00%1100.00%
Total48100.00%1100.00%

static struct snd_soc_dai_driver davinci_i2s_dai = { .probe = davinci_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, .rates = DAVINCI_I2S_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .capture = { .channels_min = 2, .channels_max = 2, .rates = DAVINCI_I2S_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = &davinci_i2s_dai_ops, }; static const struct snd_soc_component_driver davinci_i2s_component = { .name = "davinci-i2s", };
static int davinci_i2s_probe(struct platform_device *pdev) { struct snd_dmaengine_dai_dma_data *dma_data; struct davinci_mcbsp_dev *dev; struct resource *mem, *res; void __iomem *io_base; int *dma; int ret; mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); if (!mem) { dev_warn(&pdev->dev, "\"mpu\" mem resource not found, using index 0\n"); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { dev_err(&pdev->dev, "no mem resource?\n"); return -ENODEV; } } io_base = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(io_base)) return PTR_ERR(io_base); dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcbsp_dev), GFP_KERNEL); if (!dev) return -ENOMEM; dev->base = io_base; /* setup DMA, first TX, then RX */ dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; dma_data->addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG); res = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (res) { dma = &dev->dma_request[SNDRV_PCM_STREAM_PLAYBACK]; *dma = res->start; dma_data->filter_data = dma; } else if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { dma_data->filter_data = "tx"; } else { dev_err(&pdev->dev, "Missing DMA tx resource\n"); return -ENODEV; } dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]; dma_data->addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DRR_REG); res = platform_get_resource(pdev, IORESOURCE_DMA, 1); if (res) { dma = &dev->dma_request[SNDRV_PCM_STREAM_CAPTURE]; *dma = res->start; dma_data->filter_data = dma; } else if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { dma_data->filter_data = "rx"; } else { dev_err(&pdev->dev, "Missing DMA rx resource\n"); return -ENODEV; } dev->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) return -ENODEV; clk_enable(dev->clk); dev->dev = &pdev->dev; dev_set_drvdata(&pdev->dev, dev); ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component, &davinci_i2s_dai, 1); if (ret != 0) goto err_release_clk; ret = edma_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "register PCM failed: %d\n", ret); goto err_unregister_component; } return 0; err_unregister_component: snd_soc_unregister_component(&pdev->dev); err_release_clk: clk_disable(dev->clk); clk_put(dev->clk); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
petr kulhavypetr kulhavy19938.94%16.67%
vladimir barinovvladimir barinov9017.61%16.67%
chaithrika at ti.comchaithrika at ti.com6813.31%16.67%
hebbar gururajahebbar gururaja377.24%16.67%
peter ujfalusipeter ujfalusi356.85%16.67%
vaibhav bediavaibhav bedia193.72%213.33%
axel linaxel lin152.94%16.67%
julia lawalljulia lawall142.74%16.67%
liam girdwoodliam girdwood122.35%16.67%
kuninori morimotokuninori morimoto91.76%16.67%
raffaele recalcatiraffaele recalcati71.37%16.67%
sekhar norisekhar nori30.59%16.67%
troy kiskytroy kisky20.39%16.67%
daniel mackdaniel mack10.20%16.67%
Total511100.00%15100.00%


static int davinci_i2s_remove(struct platform_device *pdev) { struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev); snd_soc_unregister_component(&pdev->dev); clk_disable(dev->clk); clk_put(dev->clk); dev->clk = NULL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
vladimir barinovvladimir barinov3665.45%125.00%
liam girdwoodliam girdwood1018.18%125.00%
chaithrika at ti.comchaithrika at ti.com814.55%125.00%
kuninori morimotokuninori morimoto11.82%125.00%
Total55100.00%4100.00%

static const struct of_device_id davinci_i2s_match[] = { { .compatible = "ti,da850-mcbsp" }, {}, }; MODULE_DEVICE_TABLE(of, davinci_i2s_match); static struct platform_driver davinci_mcbsp_driver = { .probe = davinci_i2s_probe, .remove = davinci_i2s_remove, .driver = { .name = "davinci-mcbsp", .of_match_table = of_match_ptr(davinci_i2s_match), }, }; module_platform_driver(davinci_mcbsp_driver); MODULE_AUTHOR("Vladimir Barinov"); MODULE_DESCRIPTION("TI DAVINCI I2S (McBSP) SoC Interface"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
vladimir barinovvladimir barinov80426.53%12.08%
troy kiskytroy kisky76525.24%1531.25%
raffaele recalcatiraffaele recalcati53317.58%36.25%
petr kulhavypetr kulhavy2337.69%12.08%
chaithrika at ti.comchaithrika at ti.com1695.58%12.08%
naresh medisettynaresh medisetty1695.58%24.17%
peter ujfalusipeter ujfalusi1003.30%12.08%
liam girdwoodliam girdwood561.85%24.17%
hebbar gururajahebbar gururaja401.32%24.17%
hugo villeneuvehugo villeneuve311.02%12.08%
mark brownmark brown240.79%48.33%
kuninori morimotokuninori morimoto230.76%12.08%
jarkko nikulajarkko nikula220.73%12.08%
vaibhav bediavaibhav bedia190.63%24.17%
axel linaxel lin160.53%24.17%
julia lawalljulia lawall140.46%12.08%
tejun heotejun heo30.10%12.08%
sekhar norisekhar nori30.10%12.08%
eric miaoeric miao20.07%12.08%
jean delvarejean delvare10.03%12.08%
david brownelldavid brownell10.03%12.08%
daniel mackdaniel mack10.03%12.08%
chris paulson-ellischris paulson-ellis10.03%12.08%
lars-peter clausenlars-peter clausen10.03%12.08%
Total3031100.00%48100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}