Commit eaff2ae7 authored by Philipp Zabel's avatar Philipp Zabel Committed by Jaroslav Kysela
Browse files

[ALSA] soc - ASoC 0.13 pxa2xx i2s driver



This patch updates the pxa2xx I2S driver to the new API in ASoC 0.13.
Changes:-
o Removed DAI capabilities matching code in favour of manual matching in
the machine drivers.
o Added DAI operations for codec and CPU interfaces.
o Removed config_sysclk() function and struct snd_soc_clock_info. No
longer needed as clocking is now configured manually in the machine
drivers. Also removed other clocking data from structures.
o Added pxa2xx-i2s.h header

Signed-off-by: default avatarPhilipp Zabel <philipp.zabel@gmail.com>
Signed-off-by: default avatarLiam Girdwood <lg@opensource.wolfsonmicro.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarJaroslav Kysela <perex@suse.cz>
parent c8044274
Loading
Loading
Loading
Loading
+82 −118
Original line number Diff line number Diff line
@@ -29,11 +29,7 @@
#include <asm/arch/audio.h>

#include "pxa2xx-pcm.h"

/* used to disable sysclk if external crystal is used */
static int extclk;
module_param(extclk, int, 0);
MODULE_PARM_DESC(extclk, "set to 1 to disable pxa2xx i2s sysclk");
#include "pxa2xx-i2s.h"

struct pxa_i2s_port {
	u32 sadiv;
@@ -41,97 +37,10 @@ struct pxa_i2s_port {
	u32 sacr1;
	u32 saimr;
	int master;
	u32 fmt;
};
static struct pxa_i2s_port pxa_i2s;

#define PXA_I2S_DAIFMT \
	(SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF)

#define PXA_I2S_DIR \
	(SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)

#define PXA_I2S_RATES \
	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
	SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)

/* priv is divider */
static struct snd_soc_dai_mode pxa2xx_i2s_modes[] = {
	/* pxa2xx I2S frame and clock master modes */
	{
		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
		.pcmrate = SNDRV_PCM_RATE_8000,
		.pcmdir = PXA_I2S_DIR,
		.flags = SND_SOC_DAI_BFS_DIV,
		.fs = 256,
		.bfs = SND_SOC_FSBD(4),
		.priv = 0x48,
	},
	{
		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
		.pcmrate = SNDRV_PCM_RATE_11025,
		.pcmdir = PXA_I2S_DIR,
		.flags = SND_SOC_DAI_BFS_DIV,
		.fs = 256,
		.bfs = SND_SOC_FSBD(4),
		.priv = 0x34,
	},
	{
		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
		.pcmrate = SNDRV_PCM_RATE_16000,
		.pcmdir = PXA_I2S_DIR,
		.flags = SND_SOC_DAI_BFS_DIV,
		.fs = 256,
		.bfs = SND_SOC_FSBD(4),
		.priv = 0x24,
	},
	{
		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
		.pcmrate = SNDRV_PCM_RATE_22050,
		.pcmdir = PXA_I2S_DIR,
		.flags = SND_SOC_DAI_BFS_DIV,
		.fs = 256,
		.bfs = SND_SOC_FSBD(4),
		.priv = 0x1a,
	},
	{
		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
		.pcmrate = SNDRV_PCM_RATE_44100,
		.pcmdir = PXA_I2S_DIR,
		.flags = SND_SOC_DAI_BFS_DIV,
		.fs = 256,
		.bfs = SND_SOC_FSBD(4),
		.priv = 0xd,
	},
	{
		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
		.pcmrate = SNDRV_PCM_RATE_48000,
		.pcmdir = PXA_I2S_DIR,
		.flags = SND_SOC_DAI_BFS_DIV,
		.fs = 256,
		.bfs = SND_SOC_FSBD(4),
		.priv = 0xc,
	},

	/* pxa2xx I2S frame master and clock slave mode */
	{
		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBM_CFS,
		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
		.pcmrate = PXA_I2S_RATES,
		.pcmdir = PXA_I2S_DIR,
		.fs = SND_SOC_FS_ALL,
		.flags = SND_SOC_DAI_BFS_RATE,
		.bfs = 64,
		.priv = 0x48,
	},
};

static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = {
	.name			= "I2S PCM Stereo out",
	.dev_addr		= __PREG(SADR),
@@ -171,8 +80,9 @@ static struct pxa2xx_gpio gpio_bus[] = {
static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;

	if (!rtd->cpu_dai->active) {
	if (!cpu_dai->active) {
		SACR0 |= SACR0_RST;
		SACR0 = 0;
	}
@@ -191,18 +101,50 @@ static int pxa_i2s_wait(void)
	return 0;
}

static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
				struct snd_pcm_hw_params *params)
static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai,
		unsigned int fmt)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	/* interface format */
	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_I2S:
		pxa_i2s.fmt = 0;
		break;
	case SND_SOC_DAIFMT_LEFT_J:
		pxa_i2s.fmt = SACR1_AMSL;
		break;
	}

	pxa_i2s.master = 0;
	if (rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CBS_CFS)
	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
	case SND_SOC_DAIFMT_CBS_CFS:
		pxa_i2s.master = 1;
		break;
	case SND_SOC_DAIFMT_CBM_CFS:
		pxa_i2s.master = 0;
		break;
	default:
		break;
	}
	return 0;
}

static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai,
		int clk_id, unsigned int freq, int dir)
{
	if (clk_id != PXA2XX_I2S_SYSCLK)
		return -ENODEV;

	if (pxa_i2s.master && !extclk)
	if (pxa_i2s.master && dir == SND_SOC_CLOCK_OUT)
		pxa_gpio_mode(gpio_bus[pxa_i2s.master].sys);

	return 0;
}

static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
				struct snd_pcm_hw_params *params)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;

	pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx);
	pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx);
	pxa_gpio_mode(gpio_bus[pxa_i2s.master].frm);
@@ -211,9 +153,9 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
	pxa_i2s_wait();

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		rtd->cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out;
		cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out;
	else
		rtd->cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in;
		cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in;

	/* is port used by another stream */
	if (!(SACR0 & SACR0_ENB)) {
@@ -224,16 +166,37 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
			SACR0 |= SACR0_BCKD;

		SACR0 |= SACR0_RFTH(14) | SACR0_TFTH(1);

		if (rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_LEFT_J)
			SACR1 |= SACR1_AMSL;
		SACR1 |= pxa_i2s.fmt;
	}
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		SAIMR |= SAIMR_TFS;
	else
		SAIMR |= SAIMR_RFS;

	SADIV = rtd->cpu_dai->dai_runtime.priv;
	switch (params_rate(params)) {
	case 8000:
		SADIV = 0x48;
		break;
	case 11025:
		SADIV = 0x34;
		break;
	case 16000:
		SADIV = 0x24;
		break;
	case 22050:
		SADIV = 0x1a;
		break;
	case 44100:
		SADIV = 0xd;
		break;
	case 48000:
		SADIV = 0xc;
		break;
	case 96000: /* not in manual and possibly slightly inaccurate */
		SADIV = 0x6;
		break;
	}

	return 0;
}

@@ -316,12 +279,9 @@ static int pxa2xx_i2s_resume(struct platform_device *pdev,
#define pxa2xx_i2s_resume	NULL
#endif

/* pxa2xx I2S sysclock is always 256 FS */
static unsigned int pxa_i2s_config_sysclk(struct snd_soc_cpu_dai *iface,
	struct snd_soc_clock_info *info, unsigned int clk)
{
	return info->rate << 8;
}
#define PXA2XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)

struct snd_soc_cpu_dai pxa_i2s_dai = {
	.name = "pxa2xx-i2s",
@@ -329,21 +289,25 @@ struct snd_soc_cpu_dai pxa_i2s_dai = {
	.type = SND_SOC_DAI_I2S,
	.suspend = pxa2xx_i2s_suspend,
	.resume = pxa2xx_i2s_resume,
	.config_sysclk = pxa_i2s_config_sysclk,
	.playback = {
		.channels_min = 2,
		.channels_max = 2,},
		.channels_max = 2,
		.rates = PXA2XX_I2S_RATES,
		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
	.capture = {
		.channels_min = 2,
		.channels_max = 2,},
		.channels_max = 2,
		.rates = PXA2XX_I2S_RATES,
		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
	.ops = {
		.startup = pxa2xx_i2s_startup,
		.shutdown = pxa2xx_i2s_shutdown,
		.trigger = pxa2xx_i2s_trigger,
		.hw_params = pxa2xx_i2s_hw_params,},
	.caps = {
		.num_modes = ARRAY_SIZE(pxa2xx_i2s_modes),
		.mode = pxa2xx_i2s_modes,},
	.dai_ops = {
		.set_fmt = pxa2xx_i2s_set_dai_fmt,
		.set_sysclk = pxa2xx_i2s_set_dai_sysclk,
	},
};

EXPORT_SYMBOL_GPL(pxa_i2s_dai);
+20 −0
Original line number Diff line number Diff line
/*
 * linux/sound/arm/pxa2xx-i2s.h
 *
 * 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.
 */

#ifndef _PXA2XX_I2S_H
#define _PXA2XX_I2S_H

/* pxa2xx DAI ID's */
#define PXA2XX_DAI_I2S			0

/* I2S clock */
#define PXA2XX_I2S_SYSCLK		0

extern struct snd_soc_cpu_dai pxa_i2s_dai;

#endif