From: Chris Fries <C.Fries@motorola.com>
Date: Thu, 14 Oct 2010 21:31:52 +0000 (-0500)
Subject: [ARM] tegra_i2s_audio: allow different DMA bus widths
X-Git-Tag: firefly_0821_release~9833^2~152^2~4
X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=0c6062a8ff717b721e18f0954d09467af6e1aed9;p=firefly-linux-kernel-4.4.55.git

[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 <malchev@google.com>
---

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;
 }