sound/soc/atmel/atmel-i2s.c

Source file repositories/reference/linux-study-clean/sound/soc/atmel/atmel-i2s.c

File Facts

System
Linux kernel
Corpus path
sound/soc/atmel/atmel-i2s.c
Extension
.c
Size
20158 bytes
Lines
743
Domain
Driver Families
Bucket
sound/soc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct atmel_i2s_gck_param {
	int		fs;
	unsigned long	mck;
	int		imckdiv;
	int		imckfs;
};

#define I2S_MCK_12M288		12288000UL
#define I2S_MCK_11M2896		11289600UL
#define I2S_MCK_6M144		6144000UL

/* mck = (32 * (imckfs+1) / (imckdiv+1)) * fs */
static const struct atmel_i2s_gck_param gck_params[] = {
	/* mck = 6.144Mhz */
	{  8000, I2S_MCK_6M144,  1, 47},	/* mck =  768 fs */

	/* mck = 12.288MHz */
	{ 16000, I2S_MCK_12M288, 1, 47},	/* mck =  768 fs */
	{ 24000, I2S_MCK_12M288, 3, 63},	/* mck =  512 fs */
	{ 32000, I2S_MCK_12M288, 3, 47},	/* mck =  384 fs */
	{ 48000, I2S_MCK_12M288, 7, 63},	/* mck =  256 fs */
	{ 64000, I2S_MCK_12M288, 7, 47},	/* mck =  192 fs */
	{ 96000, I2S_MCK_12M288, 7, 31},	/* mck =  128 fs */
	{192000, I2S_MCK_12M288, 7, 15},	/* mck =   64 fs */

	/* mck = 11.2896MHz */
	{ 11025, I2S_MCK_11M2896, 1, 63},	/* mck = 1024 fs */
	{ 22050, I2S_MCK_11M2896, 3, 63},	/* mck =  512 fs */
	{ 44100, I2S_MCK_11M2896, 7, 63},	/* mck =  256 fs */
	{ 88200, I2S_MCK_11M2896, 7, 31},	/* mck =  128 fs */
	{176400, I2S_MCK_11M2896, 7, 15},	/* mck =   64 fs */
};

struct atmel_i2s_dev;

struct atmel_i2s_caps {
	int	(*mck_init)(struct atmel_i2s_dev *, struct device_node *np);
};

struct atmel_i2s_dev {
	struct device				*dev;
	struct regmap				*regmap;
	struct clk				*pclk;
	struct clk				*gclk;
	struct snd_dmaengine_dai_dma_data	playback;
	struct snd_dmaengine_dai_dma_data	capture;
	unsigned int				fmt;
	const struct atmel_i2s_gck_param	*gck_param;
	const struct atmel_i2s_caps		*caps;
	int					clk_use_no;
};

static irqreturn_t atmel_i2s_interrupt(int irq, void *dev_id)
{
	struct atmel_i2s_dev *dev = dev_id;
	unsigned int sr, imr, pending, ch, mask;
	irqreturn_t ret = IRQ_NONE;

	regmap_read(dev->regmap, ATMEL_I2SC_SR, &sr);
	regmap_read(dev->regmap, ATMEL_I2SC_IMR, &imr);
	pending = sr & imr;

	if (!pending)
		return IRQ_NONE;

	if (pending & ATMEL_I2SC_INT_RXOR) {
		mask = ATMEL_I2SC_SR_RXOR;

		for (ch = 0; ch < ATMEL_I2SC_MAX_TDM_CHANNELS; ++ch) {
			if (sr & ATMEL_I2SC_SR_RXORCH(ch)) {
				mask |= ATMEL_I2SC_SR_RXORCH(ch);
				dev_err(dev->dev,
					"RX overrun on channel %d\n", ch);
			}
		}
		regmap_write(dev->regmap, ATMEL_I2SC_SCR, mask);
		ret = IRQ_HANDLED;
	}

	if (pending & ATMEL_I2SC_INT_TXUR) {
		mask = ATMEL_I2SC_SR_TXUR;

		for (ch = 0; ch < ATMEL_I2SC_MAX_TDM_CHANNELS; ++ch) {
			if (sr & ATMEL_I2SC_SR_TXURCH(ch)) {
				mask |= ATMEL_I2SC_SR_TXURCH(ch);
				dev_err(dev->dev,
					"TX underrun on channel %d\n", ch);
			}
		}
		regmap_write(dev->regmap, ATMEL_I2SC_SCR, mask);

Annotation

Implementation Notes