From 3e7cc3d3d1c435f83533b8bf2cf1833855be2901 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 12 Oct 2006 14:28:10 +0200 Subject: [ALSA] ASoC pxa2xx I2S support This patch adds pxa2xx I2S ASoC audio support. Features:- o Supports playback/capture o 16 bit PCM o 8k - 96k sample rates o Supports master and slave mode. From: Liam Girdwood Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/pxa2xx-i2s.c | 306 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 306 insertions(+) create mode 100644 sound/soc/pxa/pxa2xx-i2s.c (limited to 'sound/soc/pxa/pxa2xx-i2s.c') diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c new file mode 100644 index 00000000000..c3b7a4bb7bd --- /dev/null +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -0,0 +1,306 @@ +/* + * pxa2xx-i2s.c -- ALSA Soc Audio Layer + * + * Copyright 2005 Wolfson Microelectronics PLC. + * Author: Liam Girdwood + * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision history + * 12th Aug 2005 Initial version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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"); + +struct pxa_i2s_port { + u32 sadiv; + u32 sacr0; + u32 sacr1; + u32 saimr; + int master; +}; +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 */ + {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), + SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_8000, PXA_I2S_DIR, + SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0x48}, + {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), + SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_11025, PXA_I2S_DIR, + SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0x34}, + {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), + SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_16000, PXA_I2S_DIR, + SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0x24}, + {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), + SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_22050, PXA_I2S_DIR, + SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0x1a}, + {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), + SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_44100, PXA_I2S_DIR, + SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0xd}, + {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), + SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_48000, PXA_I2S_DIR, + SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0xc}, + + /* pxa2xx I2S frame master and clock slave mode */ + {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBM_CFS, SND_SOC_DAITDM_LRDW(0,0), + SNDRV_PCM_FMTBIT_S16_LE, PXA_I2S_RATES, PXA_I2S_DIR, 0, + SND_SOC_FS_ALL, SND_SOC_FSB(64), 0x48}, + +}; + +static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = { + .name = "I2S PCM Stereo out", + .dev_addr = __PREG(SADR), + .drcmr = &DRCMRTXSADR, + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST32 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = { + .name = "I2S PCM Stereo in", + .dev_addr = __PREG(SADR), + .drcmr = &DRCMRRXSADR, + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST32 | DCMD_WIDTH4, +}; + +static struct pxa2xx_gpio gpio_bus[] = { + { /* I2S SoC Slave */ + .rx = GPIO29_SDATA_IN_I2S_MD, + .tx = GPIO30_SDATA_OUT_I2S_MD, + .clk = GPIO28_BITCLK_IN_I2S_MD, + .frm = GPIO31_SYNC_I2S_MD, + }, + { /* I2S SoC Master */ +#ifdef CONFIG_PXA27x + .sys = GPIO113_I2S_SYSCLK_MD, +#else + .sys = GPIO32_SYSCLK_I2S_MD, +#endif + .rx = GPIO29_SDATA_IN_I2S_MD, + .tx = GPIO30_SDATA_OUT_I2S_MD, + .clk = GPIO28_BITCLK_OUT_I2S_MD, + .frm = GPIO31_SYNC_I2S_MD, + }, +}; + +static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + if (!rtd->cpu_dai->active) { + SACR0 |= SACR0_RST; + SACR0 = 0; + } + + return 0; +} + +/* wait for I2S controller to be ready */ +static int pxa_i2s_wait(void) +{ + int i; + + /* flush the Rx FIFO */ + for(i = 0; i < 16; i++) + SADR; + 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; + + pxa_i2s.master = 0; + if (rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CBS_CFS) + pxa_i2s.master = 1; + + if (pxa_i2s.master && !extclk) + pxa_gpio_mode(gpio_bus[pxa_i2s.master].sys); + + 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); + pxa_gpio_mode(gpio_bus[pxa_i2s.master].clk); + pxa_set_cken(CKEN8_I2S, 1); + pxa_i2s_wait(); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + rtd->cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out; + else + rtd->cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in; + + /* is port used by another stream */ + if (!(SACR0 & SACR0_ENB)) { + + SACR0 = 0; + SACR1 = 0; + if (pxa_i2s.master) + 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; + } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + SAIMR |= SAIMR_TFS; + else + SAIMR |= SAIMR_RFS; + + SADIV = rtd->cpu_dai->dai_runtime.priv; + return 0; +} + +static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd) +{ + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + SACR0 |= SACR0_ENB; + break; + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + SACR1 |= SACR1_DRPL; + SAIMR &= ~SAIMR_TFS; + } else { + SACR1 |= SACR1_DREC; + SAIMR &= ~SAIMR_RFS; + } + + if (SACR1 & (SACR1_DREC | SACR1_DRPL)) { + SACR0 &= ~SACR0_ENB; + pxa_i2s_wait(); + pxa_set_cken(CKEN8_I2S, 0); + } +} + +#ifdef CONFIG_PM +static int pxa2xx_i2s_suspend(struct platform_device *dev, + struct snd_soc_cpu_dai *dai) +{ + if (!dai->active) + return 0; + + /* store registers */ + pxa_i2s.sacr0 = SACR0; + pxa_i2s.sacr1 = SACR1; + pxa_i2s.saimr = SAIMR; + pxa_i2s.sadiv = SADIV; + + /* deactivate link */ + SACR0 &= ~SACR0_ENB; + pxa_i2s_wait(); + return 0; +} + +static int pxa2xx_i2s_resume(struct platform_device *pdev, + struct snd_soc_cpu_dai *dai) +{ + if (!dai->active) + return 0; + + pxa_i2s_wait(); + + SACR0 = pxa_i2s.sacr0 &= ~SACR0_ENB; + SACR1 = pxa_i2s.sacr1; + SAIMR = pxa_i2s.saimr; + SADIV = pxa_i2s.sadiv; + SACR0 |= SACR0_ENB; + + return 0; +} + +#else +#define pxa2xx_i2s_suspend NULL +#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; +} + +struct snd_soc_cpu_dai pxa_i2s_dai = { + .name = "pxa2xx-i2s", + .id = 0, + .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,}, + .capture = { + .channels_min = 2, + .channels_max = 2,}, + .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,}, +}; + +EXPORT_SYMBOL_GPL(pxa_i2s_dai); + +/* Module information */ +MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); +MODULE_DESCRIPTION("pxa2xx I2S SoC Interface"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 527541f9a8a83eedb4d732657dbfdcd2c4ca8bb4 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 13 Oct 2006 12:33:56 +0200 Subject: [ALSA] ASoC DAI capabilities labelling This patch suggested by Takashi changes the DAI capabilities definitions in pxa-i2s.c, at91rm9200-i2s.c, wm8731.c, wm8750.c and wm9712.c to use a label = value style. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/pxa2xx-i2s.c | 91 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 22 deletions(-) (limited to 'sound/soc/pxa/pxa2xx-i2s.c') diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index c3b7a4bb7bd..db2310f87fb 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -58,30 +58,77 @@ static struct pxa_i2s_port pxa_i2s; /* priv is divider */ static struct snd_soc_dai_mode pxa2xx_i2s_modes[] = { /* pxa2xx I2S frame and clock master modes */ - {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), - SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_8000, PXA_I2S_DIR, - SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0x48}, - {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), - SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_11025, PXA_I2S_DIR, - SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0x34}, - {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), - SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_16000, PXA_I2S_DIR, - SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0x24}, - {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), - SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_22050, PXA_I2S_DIR, - SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0x1a}, - {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), - SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_44100, PXA_I2S_DIR, - SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0xd}, - {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), - SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_48000, PXA_I2S_DIR, - SND_SOC_DAI_BFS_DIV, 256, SND_SOC_FSBD(4), 0xc}, + { + .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 */ - {PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBM_CFS, SND_SOC_DAITDM_LRDW(0,0), - SNDRV_PCM_FMTBIT_S16_LE, PXA_I2S_RATES, PXA_I2S_DIR, 0, - SND_SOC_FS_ALL, SND_SOC_FSB(64), 0x48}, - + { + .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, + .bfs = SND_SOC_FSB(64), + .priv = 0x48, + }, }; static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = { -- cgit v1.2.3 From b3b9c1cbb35125f7e43a323ebe89e7a74e3c1ac2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 13 Oct 2006 20:09:59 +0200 Subject: [ALSA] Remove trailing whitespaces from soc/* files Remove trailing whitespaces from soc/* files added by the conversion to C99-style initialization. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/pxa2xx-i2s.c | 58 +++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'sound/soc/pxa/pxa2xx-i2s.c') diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index db2310f87fb..99f1da32744 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -60,61 +60,61 @@ 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, + .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), + .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, + .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), + .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, + .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), + .fs = 256, + .bfs = SND_SOC_FSBD(4), .priv = 0x24, }, { .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .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), + .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, + .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), + .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, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmrate = SNDRV_PCM_RATE_48000, .pcmdir = PXA_I2S_DIR, - .flags = SND_SOC_DAI_BFS_DIV, - .fs = 256, + .flags = SND_SOC_DAI_BFS_DIV, + .fs = 256, .bfs = SND_SOC_FSBD(4), .priv = 0xc, }, @@ -122,11 +122,11 @@ static struct snd_soc_dai_mode pxa2xx_i2s_modes[] = { /* pxa2xx I2S frame master and clock slave mode */ { .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBM_CFS, - .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, + .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, .pcmrate = PXA_I2S_RATES, .pcmdir = PXA_I2S_DIR, - .fs = SND_SOC_FS_ALL, - .bfs = SND_SOC_FSB(64), + .fs = SND_SOC_FS_ALL, + .bfs = SND_SOC_FSB(64), .priv = 0x48, }, }; -- cgit v1.2.3 From a71a468a50f1385855e28864e26251b02df829bb Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 19 Oct 2006 20:35:56 +0200 Subject: [ALSA] ASoC: Add support for BCLK based on (Rate * Chn * Word Size) This patch adds support for the DAI BCLK to be generated by multiplying Rate * Channels * Word Size (RCW). This now gives 3 options for BCLK clocking and synchronisation :- 1. BCLK = Rate * x 2. BCLK = MCLK / x 3. BCLK = Rate * Chn * Word Size. (New) Changes:- o Add support for RCW generation of BCLK o Update Documentation to include RCW. o Update DAI documentation for label = value DAI modes. o Add RCW support to wm8731, wm8750 and pxa2xx-i2s drivers. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/pxa2xx-i2s.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/soc/pxa/pxa2xx-i2s.c') diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 99f1da32744..98b167fe68e 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -126,7 +126,8 @@ static struct snd_soc_dai_mode pxa2xx_i2s_modes[] = { .pcmrate = PXA_I2S_RATES, .pcmdir = PXA_I2S_DIR, .fs = SND_SOC_FS_ALL, - .bfs = SND_SOC_FSB(64), + .flags = SND_SOC_DAI_BFS_RATE, + .bfs = 64, .priv = 0x48, }, }; -- cgit v1.2.3 From eaff2ae702f937020bfde96eea552caae3815784 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 2 Feb 2007 17:20:40 +0100 Subject: [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: Philipp Zabel Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/soc/pxa/pxa2xx-i2s.c | 200 +++++++++++++++++++-------------------------- 1 file changed, 82 insertions(+), 118 deletions(-) (limited to 'sound/soc/pxa/pxa2xx-i2s.c') diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 98b167fe68e..575a6137c04 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -29,11 +29,7 @@ #include #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; +} - if (pxa_i2s.master && !extclk) +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 && 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); -- cgit v1.2.3