From 0c6062a8ff717b721e18f0954d09467af6e1aed9 Mon Sep 17 00:00:00 2001 From: Chris Fries Date: Thu, 14 Oct 2010 16:31:52 -0500 Subject: [PATCH] [ARM] tegra_i2s_audio: allow different DMA bus widths Added separate APB DMA bus-width controls depending on the audio bus format. Signed-off-by: Iliyan Malchev --- arch/arm/mach-tegra/include/mach/audio.h | 2 ++ arch/arm/mach-tegra/tegra_i2s_audio.c | 40 +++++++++++++++++++----- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-tegra/include/mach/audio.h b/arch/arm/mach-tegra/include/mach/audio.h index 6e1af87a2ef9..6a6b5d08833d 100644 --- a/arch/arm/mach-tegra/include/mach/audio.h +++ b/arch/arm/mach-tegra/include/mach/audio.h @@ -41,6 +41,8 @@ struct tegra_audio_platform_data { int mode; /* I2S, LJM, RJM, etc. */ int fifo_fmt; int bit_size; + int i2s_bus_width; /* 32-bit for 16-bit packed I2S */ + int dsp_bus_width; /* 16-bit for DSP data format */ void *driver_data; }; diff --git a/arch/arm/mach-tegra/tegra_i2s_audio.c b/arch/arm/mach-tegra/tegra_i2s_audio.c index 47830789a74a..dc6e5597a438 100644 --- a/arch/arm/mach-tegra/tegra_i2s_audio.c +++ b/arch/arm/mach-tegra/tegra_i2s_audio.c @@ -835,7 +835,10 @@ static void setup_dma_tx_request(struct tegra_dma_req *req, req->to_memory = false; req->dest_addr = i2s_get_fifo_phy_base(ads->i2s_phys, I2S_FIFO_TX); req->dest_wrap = 4; - req->dest_bus_width = 16; + if (ads->bit_format == TEGRA_AUDIO_BIT_FORMAT_DSP) + req->dest_bus_width = ads->pdata->dsp_bus_width; + else + req->dest_bus_width = ads->pdata->i2s_bus_width; req->source_bus_width = 32; req->source_wrap = 0; req->req_sel = ads->dma_req_sel; @@ -854,7 +857,10 @@ static void setup_dma_rx_request(struct tegra_dma_req *req, req->to_memory = true; req->source_addr = i2s_get_fifo_phy_base(ads->i2s_phys, I2S_FIFO_RX); req->source_wrap = 4; - req->source_bus_width = 16; + if (ads->bit_format == TEGRA_AUDIO_BIT_FORMAT_DSP) + req->source_bus_width = ads->pdata->dsp_bus_width; + else + req->source_bus_width = ads->pdata->i2s_bus_width; req->dest_bus_width = 32; req->dest_wrap = 0; req->req_sel = ads->dma_req_sel; @@ -1375,15 +1381,20 @@ static long tegra_audio_ioctl(struct file *file, int rc = 0; struct audio_driver_state *ads = ads_from_misc_ctl(file); unsigned int mode; + bool dma_restart = false; + + mutex_lock(&ads->out.lock); + mutex_lock(&ads->in.lock); switch (cmd) { case TEGRA_AUDIO_SET_BIT_FORMAT: if (copy_from_user(&mode, (const void __user *)arg, sizeof(mode))) { rc = -EFAULT; - break; + goto done; } - switch(mode) { + dma_restart = (mode != ads->bit_format); + switch (mode) { case TEGRA_AUDIO_BIT_FORMAT_DEFAULT: i2s_set_bit_format(ads->i2s_base, ads->pdata->mode); ads->bit_format = mode; @@ -1395,16 +1406,31 @@ static long tegra_audio_ioctl(struct file *file, default: pr_err("%s: Invald PCM mode %d", __func__, mode); rc = -EINVAL; - break; + goto done; } break; case TEGRA_AUDIO_GET_BIT_FORMAT: if (copy_to_user((void __user *)arg, &ads->bit_format, - sizeof(mode))) { + sizeof(mode))) rc = -EFAULT; + goto done; + } + + if (dma_restart && ads->using_dma) { + pr_debug("%s: Restarting DMA due to configuration change.\n", + __func__); + if (kfifo_len(&ads->out.fifo) || ads->in.active) { + pr_err("%s: dma busy, cannot restart.\n", __func__); + rc = -EBUSY; + goto done; } - break; + sound_ops->tear_down(ads); + sound_ops->setup(ads); } + +done: + mutex_unlock(&ads->in.lock); + mutex_unlock(&ads->out.lock); return rc; } -- 2.34.1