Commit 5f592bb9 authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'for-2.6.31' of...

Merge branch 'for-2.6.31' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6 into topic/asoc
parents dd4a4164 81a4275b
...@@ -5286,7 +5286,7 @@ P: Liam Girdwood ...@@ -5286,7 +5286,7 @@ P: Liam Girdwood
M: lrg@slimlogic.co.uk M: lrg@slimlogic.co.uk
P: Mark Brown P: Mark Brown
M: broonie@opensource.wolfsonmicro.com M: broonie@opensource.wolfsonmicro.com
T: git git://opensource.wolfsonmicro.com/linux-2.6-asoc T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git
L: alsa-devel@alsa-project.org (subscribers-only) L: alsa-devel@alsa-project.org (subscribers-only)
W: http://alsa-project.org/main/index.php/ASoC W: http://alsa-project.org/main/index.php/ASoC
S: Supported S: Supported
......
/*
* <mach/asp.h> - DaVinci Audio Serial Port support
*/
#ifndef __ASM_ARCH_DAVINCI_ASP_H
#define __ASM_ARCH_DAVINCI_ASP_H
#include <mach/irqs.h>
/* Bases of register banks */
#define DAVINCI_ASP0_BASE 0x01E02000
#define DAVINCI_ASP1_BASE 0x01E04000
/* EDMA channels */
#define DAVINCI_DMA_ASP0_TX 2
#define DAVINCI_DMA_ASP0_RX 3
#define DAVINCI_DMA_ASP1_TX 8
#define DAVINCI_DMA_ASP1_RX 9
/* Interrupts */
#define DAVINCI_ASP0_RX_INT IRQ_MBRINT
#define DAVINCI_ASP0_TX_INT IRQ_MBXINT
#define DAVINCI_ASP1_RX_INT IRQ_MBRINT
#define DAVINCI_ASP1_TX_INT IRQ_MBXINT
#endif /* __ASM_ARCH_DAVINCI_ASP_H */
...@@ -79,7 +79,8 @@ struct snd_pcm_substream; ...@@ -79,7 +79,8 @@ struct snd_pcm_substream;
#define SND_SOC_CLOCK_OUT 1 #define SND_SOC_CLOCK_OUT 1
#define SND_SOC_STD_AC97_FMTS (SNDRV_PCM_FMTBIT_S16_LE |\ #define SND_SOC_STD_AC97_FMTS (SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S32_LE) SNDRV_PCM_FMTBIT_S32_LE |\
SNDRV_PCM_FMTBIT_S32_BE)
struct snd_soc_dai_ops; struct snd_soc_dai_ops;
struct snd_soc_dai; struct snd_soc_dai;
......
...@@ -585,6 +585,8 @@ static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) ...@@ -585,6 +585,8 @@ static int wm9712_reset(struct snd_soc_codec *codec, int try_warm)
} }
soc_ac97_ops.reset(codec->ac97); soc_ac97_ops.reset(codec->ac97);
if (soc_ac97_ops.warm_reset)
soc_ac97_ops.warm_reset(codec->ac97);
if (ac97_read(codec, 0) != wm9712_reg[0]) if (ac97_read(codec, 0) != wm9712_reg[0])
goto err; goto err;
return 0; return 0;
......
...@@ -10,13 +10,14 @@ config SND_DAVINCI_SOC_I2S ...@@ -10,13 +10,14 @@ config SND_DAVINCI_SOC_I2S
tristate tristate
config SND_DAVINCI_SOC_EVM config SND_DAVINCI_SOC_EVM
tristate "SoC Audio support for DaVinci EVM" tristate "SoC Audio support for DaVinci DM6446 or DM355 EVM"
depends on SND_DAVINCI_SOC && MACH_DAVINCI_EVM depends on SND_DAVINCI_SOC
depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM
select SND_DAVINCI_SOC_I2S select SND_DAVINCI_SOC_I2S
select SND_SOC_TLV320AIC3X select SND_SOC_TLV320AIC3X
help help
Say Y if you want to add support for SoC audio on TI Say Y if you want to add support for SoC audio on TI
DaVinci EVM platform. DaVinci DM6446 or DM355 EVM platforms.
config SND_DAVINCI_SOC_SFFSDR config SND_DAVINCI_SOC_SFFSDR
tristate "SoC Audio support for SFFSDR" tristate "SoC Audio support for SFFSDR"
......
...@@ -20,7 +20,11 @@ ...@@ -20,7 +20,11 @@
#include <sound/soc-dapm.h> #include <sound/soc-dapm.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <mach/hardware.h> #include <asm/mach-types.h>
#include <mach/asp.h>
#include <mach/edma.h>
#include <mach/mux.h>
#include "../codecs/tlv320aic3x.h" #include "../codecs/tlv320aic3x.h"
#include "davinci-pcm.h" #include "davinci-pcm.h"
...@@ -150,7 +154,7 @@ static struct snd_soc_card snd_soc_card_evm = { ...@@ -150,7 +154,7 @@ static struct snd_soc_card snd_soc_card_evm = {
/* evm audio private data */ /* evm audio private data */
static struct aic3x_setup_data evm_aic3x_setup = { static struct aic3x_setup_data evm_aic3x_setup = {
.i2c_bus = 0, .i2c_bus = 1,
.i2c_address = 0x1b, .i2c_address = 0x1b,
}; };
...@@ -161,36 +165,73 @@ static struct snd_soc_device evm_snd_devdata = { ...@@ -161,36 +165,73 @@ static struct snd_soc_device evm_snd_devdata = {
.codec_data = &evm_aic3x_setup, .codec_data = &evm_aic3x_setup,
}; };
/* DM6446 EVM uses ASP0; line-out is a pair of RCA jacks */
static struct resource evm_snd_resources[] = { static struct resource evm_snd_resources[] = {
{ {
.start = DAVINCI_MCBSP_BASE, .start = DAVINCI_ASP0_BASE,
.end = DAVINCI_MCBSP_BASE + SZ_8K - 1, .end = DAVINCI_ASP0_BASE + SZ_8K - 1,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, },
}; };
static struct evm_snd_platform_data evm_snd_data = { static struct evm_snd_platform_data evm_snd_data = {
.tx_dma_ch = DM644X_DMACH_MCBSP_TX, .tx_dma_ch = DAVINCI_DMA_ASP0_TX,
.rx_dma_ch = DM644X_DMACH_MCBSP_RX, .rx_dma_ch = DAVINCI_DMA_ASP0_RX,
};
/* DM335 EVM uses ASP1; line-out is a stereo mini-jack */
static struct resource dm335evm_snd_resources[] = {
{
.start = DAVINCI_ASP1_BASE,
.end = DAVINCI_ASP1_BASE + SZ_8K - 1,
.flags = IORESOURCE_MEM,
},
};
static struct evm_snd_platform_data dm335evm_snd_data = {
.tx_dma_ch = DAVINCI_DMA_ASP1_TX,
.rx_dma_ch = DAVINCI_DMA_ASP1_RX,
}; };
static struct platform_device *evm_snd_device; static struct platform_device *evm_snd_device;
static int __init evm_init(void) static int __init evm_init(void)
{ {
struct resource *resources;
unsigned num_resources;
struct evm_snd_platform_data *data;
int index;
int ret; int ret;
evm_snd_device = platform_device_alloc("soc-audio", 0); if (machine_is_davinci_evm()) {
davinci_cfg_reg(DM644X_MCBSP);
resources = evm_snd_resources;
num_resources = ARRAY_SIZE(evm_snd_resources);
data = &evm_snd_data;
index = 0;
} else if (machine_is_davinci_dm355_evm()) {
/* we don't use ASP1 IRQs, or we'd need to mux them ... */
davinci_cfg_reg(DM355_EVT8_ASP1_TX);
davinci_cfg_reg(DM355_EVT9_ASP1_RX);
resources = dm335evm_snd_resources;
num_resources = ARRAY_SIZE(dm335evm_snd_resources);
data = &dm335evm_snd_data;
index = 1;
} else
return -EINVAL;
evm_snd_device = platform_device_alloc("soc-audio", index);
if (!evm_snd_device) if (!evm_snd_device)
return -ENOMEM; return -ENOMEM;
platform_set_drvdata(evm_snd_device, &evm_snd_devdata); platform_set_drvdata(evm_snd_device, &evm_snd_devdata);
evm_snd_devdata.dev = &evm_snd_device->dev; evm_snd_devdata.dev = &evm_snd_device->dev;
platform_device_add_data(evm_snd_device, &evm_snd_data, platform_device_add_data(evm_snd_device, data, sizeof(*data));
sizeof(evm_snd_data));
ret = platform_device_add_resources(evm_snd_device, evm_snd_resources, ret = platform_device_add_resources(evm_snd_device, resources,
ARRAY_SIZE(evm_snd_resources)); num_resources);
if (ret) { if (ret) {
platform_device_put(evm_snd_device); platform_device_put(evm_snd_device);
return ret; return ret;
......
...@@ -24,6 +24,26 @@ ...@@ -24,6 +24,26 @@
#include "davinci-pcm.h" #include "davinci-pcm.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_DRR_REG 0x00
#define DAVINCI_MCBSP_DXR_REG 0x04 #define DAVINCI_MCBSP_DXR_REG 0x04
#define DAVINCI_MCBSP_SPCR_REG 0x08 #define DAVINCI_MCBSP_SPCR_REG 0x08
...@@ -421,7 +441,7 @@ static int davinci_i2s_probe(struct platform_device *pdev, ...@@ -421,7 +441,7 @@ static int davinci_i2s_probe(struct platform_device *pdev,
{ {
struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_card *card = socdev->card; struct snd_soc_card *card = socdev->card;
struct snd_soc_dai *cpu_dai = card->dai_link[pdev->id].cpu_dai; struct snd_soc_dai *cpu_dai = card->dai_link->cpu_dai;
struct davinci_mcbsp_dev *dev; struct davinci_mcbsp_dev *dev;
struct resource *mem, *ioarea; struct resource *mem, *ioarea;
struct evm_snd_platform_data *pdata; struct evm_snd_platform_data *pdata;
...@@ -448,7 +468,7 @@ static int davinci_i2s_probe(struct platform_device *pdev, ...@@ -448,7 +468,7 @@ static int davinci_i2s_probe(struct platform_device *pdev,
cpu_dai->private_data = dev; cpu_dai->private_data = dev;
dev->clk = clk_get(&pdev->dev, "McBSPCLK"); dev->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(dev->clk)) { if (IS_ERR(dev->clk)) {
ret = -ENODEV; ret = -ENODEV;
goto err_free_mem; goto err_free_mem;
...@@ -483,7 +503,7 @@ static void davinci_i2s_remove(struct platform_device *pdev, ...@@ -483,7 +503,7 @@ static void davinci_i2s_remove(struct platform_device *pdev,
{ {
struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_card *card = socdev->card; struct snd_soc_card *card = socdev->card;
struct snd_soc_dai *cpu_dai = card->dai_link[pdev->id].cpu_dai; struct snd_soc_dai *cpu_dai = card->dai_link->cpu_dai;
struct davinci_mcbsp_dev *dev = cpu_dai->private_data; struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
struct resource *mem; struct resource *mem;
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <sound/soc.h> #include <sound/soc.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <mach/edma.h>
#include "davinci-pcm.h" #include "davinci-pcm.h"
...@@ -51,7 +52,7 @@ struct davinci_runtime_data { ...@@ -51,7 +52,7 @@ struct davinci_runtime_data {
spinlock_t lock; spinlock_t lock;
int period; /* current DMA period */ int period; /* current DMA period */
int master_lch; /* Master DMA channel */ int master_lch; /* Master DMA channel */
int slave_lch; /* Slave DMA channel */ int slave_lch; /* linked parameter RAM reload slot */
struct davinci_pcm_dma_params *params; /* DMA params */ struct davinci_pcm_dma_params *params; /* DMA params */
}; };
...@@ -90,18 +91,18 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) ...@@ -90,18 +91,18 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
dst_bidx = data_type; dst_bidx = data_type;
} }
davinci_set_dma_src_params(lch, src, INCR, W8BIT); edma_set_src(lch, src, INCR, W8BIT);
davinci_set_dma_dest_params(lch, dst, INCR, W8BIT); edma_set_dest(lch, dst, INCR, W8BIT);
davinci_set_dma_src_index(lch, src_bidx, 0); edma_set_src_index(lch, src_bidx, 0);
davinci_set_dma_dest_index(lch, dst_bidx, 0); edma_set_dest_index(lch, dst_bidx, 0);
davinci_set_dma_transfer_params(lch, data_type, count, 1, 0, ASYNC); edma_set_transfer_params(lch, data_type, count, 1, 0, ASYNC);
prtd->period++; prtd->period++;
if (unlikely(prtd->period >= runtime->periods)) if (unlikely(prtd->period >= runtime->periods))
prtd->period = 0; prtd->period = 0;
} }
static void davinci_pcm_dma_irq(int lch, u16 ch_status, void *data) static void davinci_pcm_dma_irq(unsigned lch, u16 ch_status, void *data)
{ {
struct snd_pcm_substream *substream = data; struct snd_pcm_substream *substream = data;
struct davinci_runtime_data *prtd = substream->runtime->private_data; struct davinci_runtime_data *prtd = substream->runtime->private_data;
...@@ -125,7 +126,7 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream) ...@@ -125,7 +126,7 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
struct davinci_runtime_data *prtd = substream->runtime->private_data; struct davinci_runtime_data *prtd = substream->runtime->private_data;
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct davinci_pcm_dma_params *dma_data = rtd->dai->cpu_dai->dma_data; struct davinci_pcm_dma_params *dma_data = rtd->dai->cpu_dai->dma_data;
int tcc = TCC_ANY; struct edmacc_param p_ram;
int ret; int ret;
if (!dma_data) if (!dma_data)
...@@ -134,22 +135,34 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream) ...@@ -134,22 +135,34 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
prtd->params = dma_data; prtd->params = dma_data;
/* Request master DMA channel */ /* Request master DMA channel */
ret = davinci_request_dma(prtd->params->channel, prtd->params->name, ret = edma_alloc_channel(prtd->params->channel,
davinci_pcm_dma_irq, substream, davinci_pcm_dma_irq, substream,
&prtd->master_lch, &tcc, EVENTQ_0); EVENTQ_0);
if (ret) if (ret < 0)
return ret; return ret;
prtd->master_lch = ret;
/* Request slave DMA channel */ /* Request parameter RAM reload slot */
ret = davinci_request_dma(PARAM_ANY, "Link", ret = edma_alloc_slot(EDMA_SLOT_ANY);
NULL, NULL, &prtd->slave_lch, &tcc, EVENTQ_0); if (ret < 0) {
if (ret) { edma_free_channel(prtd->master_lch);
davinci_free_dma(prtd->master_lch);
return ret; return ret;
} }
prtd->slave_lch = ret;
/* Link slave DMA channel in loopback */ /* Issue transfer completion IRQ when the channel completes a
davinci_dma_link_lch(prtd->slave_lch, prtd->slave_lch); * transfer, then always reload from the same slot (by a kind
* of loopback link). The completion IRQ handler will update
* the reload slot with a new buffer.
*
* REVISIT save p_ram here after setting up everything except
* the buffer and its length (ccnt) ... use it as a template
* so davinci_pcm_enqueue_dma() takes less time in IRQ.
*/
edma_read_slot(prtd->slave_lch, &p_ram);
p_ram.opt |= TCINTEN | EDMA_TCC(prtd->master_lch);
p_ram.link_bcntrld = prtd->slave_lch << 5;
edma_write_slot(prtd->slave_lch, &p_ram);
return 0; return 0;
} }
...@@ -165,12 +178,12 @@ static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ...@@ -165,12 +178,12 @@ static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
davinci_start_dma(prtd->master_lch); edma_start(prtd->master_lch);
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
davinci_stop_dma(prtd->master_lch); edma_stop(prtd->master_lch);
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
...@@ -185,14 +198,14 @@ static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ...@@ -185,14 +198,14 @@ static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
static int davinci_pcm_prepare(struct snd_pcm_substream *substream) static int davinci_pcm_prepare(struct snd_pcm_substream *substream)
{ {
struct davinci_runtime_data *prtd = substream->runtime->private_data; struct davinci_runtime_data *prtd = substream->runtime->private_data;
struct paramentry_descriptor temp; struct edmacc_param temp;
prtd->period = 0; prtd->period = 0;
davinci_pcm_enqueue_dma(substream); davinci_pcm_enqueue_dma(substream);
/* Get slave channel dma params for master channel startup */ /* Copy self-linked parameter RAM entry into master channel */
davinci_get_dma_params(prtd->slave_lch, &temp); edma_read_slot(prtd->slave_lch, &temp);
davinci_set_dma_params(prtd->master_lch, &temp); edma_write_slot(prtd->master_lch, &temp);
return 0; return 0;
} }
...@@ -208,7 +221,7 @@ davinci_pcm_pointer(struct snd_pcm_substream *substream) ...@@ -208,7 +221,7 @@ davinci_pcm_pointer(struct snd_pcm_substream *substream)
spin_lock(&prtd->lock); spin_lock(&prtd->lock);
davinci_dma_getposition(prtd->master_lch, &src, &dst); edma_get_position(prtd->master_lch, &src, &dst);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
count = src - runtime->dma_addr; count = src - runtime->dma_addr;
else else
...@@ -253,10 +266,10 @@ static int davinci_pcm_close(struct snd_pcm_substream *substream) ...@@ -253,10 +266,10 @@ static int davinci_pcm_close(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
struct davinci_runtime_data *prtd = runtime->private_data; struct davinci_runtime_data *prtd = runtime->private_data;
davinci_dma_unlink_lch(prtd->slave_lch, prtd->slave_lch); edma_unlink(prtd->slave_lch);
davinci_free_dma(prtd->slave_lch); edma_free_slot(prtd->slave_lch);
davinci_free_dma(prtd->master_lch); edma_free_channel(prtd->master_lch);
kfree(prtd); kfree(prtd);
......
...@@ -39,6 +39,14 @@ config SND_OMAP_SOC_OMAP2EVM ...@@ -39,6 +39,14 @@ config SND_OMAP_SOC_OMAP2EVM
help help
Say Y if you want to add support for SoC audio on the omap2evm board. Say Y if you want to add support for SoC audio on the omap2evm board.
config SND_OMAP_SOC_OMAP3EVM
tristate "SoC Audio support for OMAP3EVM board"
depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3EVM
select SND_OMAP_SOC_MCBSP
select SND_SOC_TWL4030
help
Say Y if you want to add support for SoC audio on the omap3evm board.
config SND_OMAP_SOC_SDP3430 config SND_OMAP_SOC_SDP3430
tristate "SoC Audio support for Texas Instruments SDP3430" tristate "SoC Audio support for Texas Instruments SDP3430"
depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP
......
...@@ -10,6 +10,7 @@ snd-soc-n810-objs := n810.o ...@@ -10,6 +10,7 @@ snd-soc-n810-objs := n810.o
snd-soc-osk5912-objs := osk5912.o snd-soc-osk5912-objs := osk5912.o
snd-soc-overo-objs := overo.o snd-soc-overo-objs := overo.o
snd-soc-omap2evm-objs := omap2evm.o snd-soc-omap2evm-objs := omap2evm.o
snd-soc-omap3evm-objs := omap3evm.o
snd-soc-sdp3430-objs := sdp3430.o snd-soc-sdp3430-objs := sdp3430.o
snd-soc-omap3pandora-objs := omap3pandora.o snd-soc-omap3pandora-objs := omap3pandora.o
snd-soc-omap3beagle-objs := omap3beagle.o snd-soc-omap3beagle-objs := omap3beagle.o
...@@ -18,6 +19,7 @@ obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o ...@@ -18,6 +19,7 @@ obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o
obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o
obj-$(CONFIG_MACH_OMAP3EVM) += snd-soc-omap3evm.o
obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o
/*
* omap3evm.c -- ALSA SoC support for OMAP3 EVM
*
* Author: Anuj Aggarwal <anuj.aggarwal@ti.com>
*
* Based on sound/soc/omap/beagle.c by Steve Sakoman
*
* Copyright (C) 2008 Texas Instruments, Incorporated
*
* 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 version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
* whether express or implied; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
#include <mach/mcbsp.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
#include "../codecs/twl4030.h"
static int omap3evm_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_dai *codec_dai = rtd->dai->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
int ret;
/* Set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai,
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM);
if (ret < 0) {
printk(KERN_ERR "Can't set codec DAI configuration\n");
return ret;
}
/* Set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai,
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM);
if (ret < 0) {
printk(KERN_ERR "Can't set cpu DAI configuration\n");
return ret;
}
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
SND_SOC_CLOCK_IN);
if (ret < 0) {
printk(KERN_ERR "Can't set codec system clock\n");
return ret;
}
return 0;
}
static struct snd_soc_ops omap3evm_ops = {
.hw_params = omap3evm_hw_params,
};
/* Digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link omap3evm_dai = {
.name = "TWL4030",
.stream_name = "TWL4030",
.cpu_dai = &omap_mcbsp_dai[0],
.codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
.ops = &omap3evm_ops,
};
/* Audio machine driver */
static struct snd_soc_card snd_soc_omap3evm = {
.name = "omap3evm",
.platform = &omap_soc_platform,
.dai_link = &omap3evm_dai,
.num_links = 1,
};
/* Audio subsystem */
static struct snd_soc_device omap3evm_snd_devdata = {
.card = &snd_soc_omap3evm,
.codec_dev = &soc_codec_dev_twl4030,
};
static struct platform_device *omap3evm_snd_device;
static int __init omap3evm_soc_init(void)
{
int ret;
if (!machine_is_omap3evm()) {
pr_err("Not OMAP3 EVM!\n");
return -ENODEV;
}
pr_info("OMAP3 EVM SoC init\n");
omap3evm_snd_device = platform_device_alloc("soc-audio", -1);
if (!omap3evm_snd_device) {
printk(KERN_ERR "Platform device allocation failed\n");
return -ENOMEM;
}
platform_set_drvdata(omap3evm_snd_device, &omap3evm_snd_devdata);
omap3evm_snd_devdata.dev = &omap3evm_snd_device->dev;
*(unsigned int *)omap3evm_dai.cpu_dai->private_data = 1;
ret = platform_device_add(omap3evm_snd_device);
if (ret)
goto err1;
return 0;
err1:
printk(KERN_ERR "Unable to add platform device\n");
platform_device_put(omap3evm_snd_device);
return ret;
}
static void __exit omap3evm_soc_exit(void)
{
platform_device_unregister(omap3evm_snd_device);
}
module_init(omap3evm_soc_init);
module_exit(omap3evm_soc_exit);
MODULE_AUTHOR("Anuj Aggarwal <anuj.aggarwal@ti.com>");
MODULE_DESCRIPTION("ALSA SoC OMAP3 EVM");
MODULE_LICENSE("GPLv2");
...@@ -106,10 +106,8 @@ static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream, ...@@ -106,10 +106,8 @@ static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream,
if (IS_ERR(clk_i2s)) if (IS_ERR(clk_i2s))
return PTR_ERR(clk_i2s); return PTR_ERR(clk_i2s);
if (!cpu_dai->active) { if (!cpu_dai->active)
SACR0 |= SACR0_RST;
SACR0 = 0; SACR0 = 0;
}
return 0; return 0;
} }
...@@ -178,9 +176,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, ...@@ -178,9 +176,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
/* is port used by another stream */ /* is port used by another stream */
if (!(SACR0 & SACR0_ENB)) { if (!(SACR0 & SACR0_ENB)) {
SACR0 = 0; SACR0 = 0;
SACR1 = 0;
if (pxa_i2s.master) if (pxa_i2s.master)
SACR0 |= SACR0_BCKD; SACR0 |= SACR0_BCKD;
...@@ -226,6 +222,10 @@ static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -226,6 +222,10 @@ static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
SACR1 &= ~SACR1_DRPL;
else
SACR1 &= ~SACR1_DREC;
SACR0 |= SACR0_ENB; SACR0 |= SACR0_ENB;
break; break;
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
...@@ -252,21 +252,16 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream, ...@@ -252,21 +252,16 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream,
SAIMR &= ~SAIMR_RFS; SAIMR &= ~SAIMR_RFS;
} }
if (SACR1 & (SACR1_DREC | SACR1_DRPL)) { if ((SACR1 & (SACR1_DREC | SACR1_DRPL)) == (SACR1_DREC | SACR1_DRPL)) {
SACR0 &= ~SACR0_ENB; SACR0 &= ~SACR0_ENB;
pxa_i2s_wait(); pxa_i2s_wait();
clk_disable(clk_i2s); clk_disable(clk_i2s);
} }
clk_put(clk_i2s);
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai) static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai)
{ {
if (!dai->active)
return 0;
/* store registers */ /* store registers */
pxa_i2s.sacr0 = SACR0; pxa_i2s.sacr0 = SACR0;
pxa_i2s.sacr1 = SACR1; pxa_i2s.sacr1 = SACR1;
...@@ -281,16 +276,14 @@ static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai) ...@@ -281,16 +276,14 @@ static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai)
static int pxa2xx_i2s_resume(struct snd_soc_dai *dai) static int pxa2xx_i2s_resume(struct snd_soc_dai *dai)
{ {
if (!dai->active)
return 0;
pxa_i2s_wait(); pxa_i2s_wait();
SACR0 = pxa_i2s.sacr0 &= ~SACR0_ENB; SACR0 = pxa_i2s.sacr0 & ~SACR0_ENB;
SACR1 = pxa_i2s.sacr1; SACR1 = pxa_i2s.sacr1;
SAIMR = pxa_i2s.saimr; SAIMR = pxa_i2s.saimr;
SADIV = pxa_i2s.sadiv; SADIV = pxa_i2s.sadiv;
SACR0 |= SACR0_ENB;
SACR0 = pxa_i2s.sacr0;
return 0; return 0;
} }
...@@ -347,6 +340,19 @@ static int pxa2xx_i2s_probe(struct platform_device *dev) ...@@ -347,6 +340,19 @@ static int pxa2xx_i2s_probe(struct platform_device *dev)
if (ret != 0) if (ret != 0)
clk_put(clk_i2s); clk_put(clk_i2s);
/*
* PXA Developer's Manual:
* If SACR0[ENB] is toggled in the middle of a normal operation,
* the SACR0[RST] bit must also be set and cleared to reset all
* I2S controller registers.
*/
SACR0 = SACR0_RST;
SACR0 = 0;
/* Make sure RPL and REC are disabled */
SACR1 = SACR1_DRPL | SACR1_DREC;
/* Along with FIFO servicing */
SAIMR &= ~(SAIMR_RFS | SAIMR_TFS);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment