summaryrefslogtreecommitdiff
path: root/sound/soc/tegra
diff options
context:
space:
mode:
authorRavindra Lokhande <rlokhande@nvidia.com>2010-12-30 19:29:54 +0530
committerBharat Nihalani <bnihalani@nvidia.com>2011-01-17 22:05:17 -0800
commit66e0ed154cfb916b83e3f0074f7cd197effaab39 (patch)
tree973b8be01ecc070d5b6944625d0a2e4dde0f08e3 /sound/soc/tegra
parent67f82f5a597622bd0b7384862c71b901580be265 (diff)
[tegra ALSA] add support for second i2s
-Added support for second i2s device. -Moved i2s related code to tegra_i2s.c -Added second i2s device in board file. Change-Id: Ifa659dbceda840a15b445ea997882a2d3ef8ca50 Reviewed-on: http://git-master/r/14726 Reviewed-by: Ravindra Lokhande <rlokhande@nvidia.com> Tested-by: Ravindra Lokhande <rlokhande@nvidia.com> Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com> Tested-by: Bharat Nihalani <bnihalani@nvidia.com>
Diffstat (limited to 'sound/soc/tegra')
-rw-r--r--sound/soc/tegra/tegra_i2s.c317
-rw-r--r--sound/soc/tegra/tegra_pcm.c106
-rw-r--r--sound/soc/tegra/tegra_soc.h6
-rw-r--r--sound/soc/tegra/tegra_soc_controls.c67
-rw-r--r--sound/soc/tegra/tegra_soc_wm8903.c31
5 files changed, 335 insertions, 192 deletions
diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c
index 25587d8420df..97034b19e318 100644
--- a/sound/soc/tegra/tegra_i2s.c
+++ b/sound/soc/tegra/tegra_i2s.c
@@ -19,7 +19,89 @@
#include "tegra_soc.h"
-struct snd_soc_dai tegra_i2s_dai;
+/* i2s controller */
+struct tegra_i2s_info {
+ struct platform_device *pdev;
+ struct tegra_audio_platform_data *pdata;
+ struct clk *i2s_clk;
+ struct clk *dap_mclk;
+ phys_addr_t i2s_phys;
+ void __iomem *i2s_base;
+
+ unsigned long dma_req_sel;
+
+ int irq;
+ /* Control for whole I2S (Data format, etc.) */
+ unsigned int bit_format;
+ struct i2s_runtime_data i2s_regs;
+};
+
+
+int setup_dma_request(struct snd_pcm_substream *substream,
+ struct tegra_dma_req *req,
+ void (*dma_callback)(struct tegra_dma_req *req),
+ void *dma_data)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct tegra_i2s_info *info = cpu_dai->private_data;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ req->to_memory = false;
+ req->dest_addr =
+ i2s_get_fifo_phy_base(cpu_dai->id, I2S_FIFO_TX);
+ req->dest_wrap = 4;
+ req->source_wrap = 0;
+ } else {
+ req->to_memory = true;
+ req->source_addr =
+ i2s_get_fifo_phy_base(cpu_dai->id, I2S_FIFO_RX);
+ req->dest_wrap = 0;
+ req->source_wrap = 4;
+ }
+
+ req->complete = dma_callback;
+ req->dev = dma_data;
+ req->source_bus_width = 32;
+ req->dest_bus_width = 32;
+ req->req_sel = info->dma_req_sel;
+
+ return 0;
+}
+
+
+/* playback */
+static inline void start_i2s_playback(struct snd_soc_dai *cpu_dai)
+{
+ i2s_fifo_set_attention_level(cpu_dai->id, I2S_FIFO_TX,
+ I2S_FIFO_ATN_LVL_FOUR_SLOTS);
+ i2s_fifo_enable(cpu_dai->id, I2S_FIFO_TX, 1);
+}
+
+static inline void stop_i2s_playback(struct snd_soc_dai *cpu_dai)
+{
+ i2s_set_fifo_irq_on_err(cpu_dai->id, I2S_FIFO_TX, 0);
+ i2s_set_fifo_irq_on_qe(cpu_dai->id, I2S_FIFO_TX, 0);
+ i2s_fifo_enable(cpu_dai->id, I2S_FIFO_TX, 0);
+ while (i2s_get_status(cpu_dai->id) & I2S_I2S_FIFO_TX_BUSY);
+}
+
+/* recording */
+static inline void start_i2s_capture(struct snd_soc_dai *cpu_dai)
+{
+ i2s_fifo_set_attention_level(cpu_dai->id, I2S_FIFO_RX,
+ I2S_FIFO_ATN_LVL_FOUR_SLOTS);
+ i2s_fifo_enable(cpu_dai->id, I2S_FIFO_RX, 1);
+}
+
+static inline void stop_i2s_capture(struct snd_soc_dai *cpu_dai)
+{
+ i2s_set_fifo_irq_on_err(cpu_dai->id, I2S_FIFO_RX, 0);
+ i2s_set_fifo_irq_on_qe(cpu_dai->id, I2S_FIFO_RX, 0);
+ i2s_fifo_enable(cpu_dai->id, I2S_FIFO_RX, 0);
+ while (i2s_get_status(cpu_dai->id) & I2S_I2S_FIFO_RX_BUSY);
+}
+
static int tegra_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
@@ -27,8 +109,9 @@ static int tegra_i2s_hw_params(struct snd_pcm_substream *substream,
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct tegra_runtime_data *prtd = runtime->private_data;
- int ret=0;
+ int ret = 0;
int val;
+ unsigned int i2s_id = dai->id;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
@@ -45,7 +128,7 @@ static int tegra_i2s_hw_params(struct snd_pcm_substream *substream,
goto err;
}
- i2s_set_bit_size(I2S_IFC, val);
+ i2s_set_bit_size(i2s_id, val);
switch (params_rate(params)) {
case 8000:
@@ -61,8 +144,8 @@ static int tegra_i2s_hw_params(struct snd_pcm_substream *substream,
goto err;
}
- i2s_set_channel_bit_count(I2S_IFC, val, clk_get_rate(prtd->i2s_clk));
- tegra_i2s_dai.private_data = (void *)prtd;
+ i2s_set_channel_bit_count(i2s_id, val, clk_get_rate(prtd->i2s_clk));
+
return 0;
err:
@@ -75,6 +158,7 @@ static int tegra_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
{
int val1;
int val2;
+ unsigned int i2s_id = cpu_dai->id;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
@@ -91,7 +175,7 @@ static int tegra_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
return -EINVAL;
}
- i2s_set_master(I2S_IFC, val1);
+ i2s_set_master(i2s_id, val1);
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_A:
@@ -118,8 +202,8 @@ static int tegra_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
return -EINVAL;
}
- i2s_set_bit_format(I2S_IFC,val1);
- i2s_set_left_right_control_polarity(I2S_IFC,val2);
+ i2s_set_bit_format(i2s_id,val1);
+ i2s_set_left_right_control_polarity(i2s_id,val2);
/* Clock inversion */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -176,11 +260,20 @@ static int tegra_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ start_i2s_playback(dai);
+ else
+ start_i2s_capture(dai);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ stop_i2s_playback(dai);
+ else
+ stop_i2s_capture(dai);
break;
default:
ret = -EINVAL;
@@ -190,17 +283,21 @@ static int tegra_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
}
#ifdef CONFIG_PM
-int tegra_i2s_suspend(struct snd_soc_dai *i2s_dai)
+int tegra_i2s_suspend(struct snd_soc_dai *cpu_dai)
{
- struct tegra_runtime_data *prtd = tegra_i2s_dai.private_data;
- i2s_get_all_regs(I2S_IFC, &prtd->i2s_regs);
+ struct tegra_i2s_info *info = cpu_dai->private_data;
+
+ i2s_get_all_regs(cpu_dai->id, &info->i2s_regs);
+
return 0;
}
-int tegra_i2s_resume(struct snd_soc_dai *i2s_dai)
+int tegra_i2s_resume(struct snd_soc_dai *cpu_dai)
{
- struct tegra_runtime_data *prtd = tegra_i2s_dai.private_data;
- i2s_set_all_regs(I2S_IFC, &prtd->i2s_regs);
+ struct tegra_i2s_info *info = cpu_dai->private_data;
+
+ i2s_set_all_regs(cpu_dai->id, &info->i2s_regs);
+
return 0;
}
@@ -218,37 +315,23 @@ static int tegra_i2s_startup(struct snd_pcm_substream *substream,
static void tegra_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+ return;
}
static int tegra_i2s_probe(struct platform_device *pdev,
struct snd_soc_dai *dai)
{
- /* DAC1 -> DAP1, DAC1 master, DAP2 bypass */
- i2s_enable_fifos(I2S_IFC, 0);
- i2s_set_left_right_control_polarity(I2S_IFC, 0); /* default */
- i2s_set_master(I2S_IFC, 1); /* set as master */
- i2s_set_fifo_mode(I2S_IFC, FIFO1, 1); /* FIFO1 is TX */
- i2s_set_fifo_mode(I2S_IFC, FIFO2, 0); /* FIFO2 is RX */
- i2s_set_bit_format(I2S_IFC, I2S_BIT_FORMAT_I2S);
- i2s_set_bit_size(I2S_IFC, I2S_BIT_SIZE_16);
- i2s_set_fifo_format(I2S_IFC, I2S_FIFO_PACKED);
- return 0;
-}
-
-static int tegra_i2s_driver_probe(struct platform_device *dev)
-{
- int ret;
-
- tegra_i2s_dai.dev = &dev->dev;
- tegra_i2s_dai.private_data = NULL;
- ret = snd_soc_register_dai(&tegra_i2s_dai);
- return ret;
-}
+ unsigned int i2s_id = dai->id;
+ i2s_enable_fifos(i2s_id, 0);
+ i2s_set_left_right_control_polarity(i2s_id, 0); /* default */
+ i2s_set_master(i2s_id, 1); /* set as master */
+ i2s_set_fifo_mode(i2s_id, FIFO1, 1); /* FIFO1 is TX */
+ i2s_set_fifo_mode(i2s_id, FIFO2, 0); /* FIFO2 is RX */
+ i2s_set_bit_format(i2s_id, I2S_BIT_FORMAT_I2S);
+ i2s_set_bit_size(i2s_id, I2S_BIT_SIZE_16);
+ i2s_set_fifo_format(i2s_id, I2S_FIFO_PACKED);
-static int __devexit tegra_i2s_driver_remove(struct platform_device *dev)
-{
- snd_soc_unregister_dai(&tegra_i2s_dai);
return 0;
}
@@ -256,33 +339,153 @@ static struct snd_soc_dai_ops tegra_i2s_dai_ops = {
.startup = tegra_i2s_startup,
.shutdown = tegra_i2s_shutdown,
.trigger = tegra_i2s_trigger,
- .hw_params = tegra_i2s_hw_params,
+ .hw_params = tegra_i2s_hw_params,
.set_fmt = tegra_i2s_set_dai_fmt,
.set_sysclk = tegra_i2s_set_dai_sysclk,
};
-struct snd_soc_dai tegra_i2s_dai = {
- .name = "tegra-i2s",
- .id = 0,
- .probe = tegra_i2s_probe,
- .suspend = tegra_i2s_suspend,
- .resume = tegra_i2s_resume,
- .playback = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = TEGRA_SAMPLE_RATES,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+struct snd_soc_dai tegra_i2s_dai[] = {
+ {
+ .name = "tegra-i2s-1",
+ .id = 0,
+ .probe = tegra_i2s_probe,
+ .suspend = tegra_i2s_suspend,
+ .resume = tegra_i2s_resume,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = TEGRA_SAMPLE_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = TEGRA_SAMPLE_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &tegra_i2s_dai_ops,
},
- .capture = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = TEGRA_SAMPLE_RATES,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ {
+ .name = "tegra-i2s-2",
+ .id = 1,
+ .probe = tegra_i2s_probe,
+ .suspend = tegra_i2s_suspend,
+ .resume = tegra_i2s_resume,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = TEGRA_SAMPLE_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = TEGRA_SAMPLE_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &tegra_i2s_dai_ops,
},
- .ops = &tegra_i2s_dai_ops,
};
EXPORT_SYMBOL_GPL(tegra_i2s_dai);
+static int tegra_i2s_driver_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ struct resource *res, *mem;
+ struct tegra_i2s_info *info;
+ int i = 0;
+
+ pr_info("%s\n", __func__);
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->pdev = pdev;
+ info->pdata = pdev->dev.platform_data;
+ info->pdata->driver_data = info;
+ BUG_ON(!info->pdata);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no mem resource!\n");
+ err = -ENODEV;
+ goto fail;
+ }
+
+ mem = request_mem_region(res->start, resource_size(res), pdev->name);
+ if (!mem) {
+ dev_err(&pdev->dev, "memory region already claimed!\n");
+ err = -EBUSY;
+ goto fail;
+ }
+
+ info->i2s_phys = res->start;
+ info->i2s_base = ioremap(res->start, res->end - res->start + 1);
+ if (!info->i2s_base) {
+ dev_err(&pdev->dev, "cannot remap iomem!\n");
+ err = -ENOMEM;
+ goto fail_release_mem;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no dma resource!\n");
+ err = -ENODEV;
+ goto fail_unmap_mem;
+ }
+ info->dma_req_sel = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no irq resource!\n");
+ err = -ENODEV;
+ goto fail_unmap_mem;
+ }
+ info->irq = res->start;
+
+ info->i2s_clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(info->i2s_clk)) {
+ err = PTR_ERR(info->i2s_clk);
+ goto fail_unmap_mem;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(tegra_i2s_dai); i++) {
+ if (tegra_i2s_dai[i].id == pdev->id) {
+ tegra_i2s_dai[i].dev = &pdev->dev;
+ tegra_i2s_dai[i].private_data = info;
+ err = snd_soc_register_dai(&tegra_i2s_dai[i]);
+ if (err)
+ goto fail_unmap_mem;
+ }
+ }
+
+ return 0;
+
+fail_unmap_mem:
+ iounmap(info->i2s_base);
+fail_release_mem:
+ release_mem_region(mem->start, resource_size(mem));
+fail:
+ kfree(info);
+ return err;
+}
+
+
+static int __devexit tegra_i2s_driver_remove(struct platform_device *pdev)
+{
+ struct tegra_i2s_info *info = tegra_i2s_dai[pdev->id].private_data;
+
+ if (info->i2s_base)
+ iounmap(info->i2s_base);
+
+ if (info)
+ kfree(info);
+
+ snd_soc_unregister_dai(&tegra_i2s_dai[pdev->id]);
+ return 0;
+}
+
static struct platform_driver tegra_i2s_driver = {
.probe = tegra_i2s_driver_probe,
.remove = __devexit_p(tegra_i2s_driver_remove),
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index 6aea653c2de1..5f413c1216e5 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -23,21 +23,6 @@
#define PLAYBACK_STARTED true
#define PLAYBACK_STOPPED false
-static void start_i2s_playback(void)
-{
- i2s_fifo_set_attention_level(I2S_IFC, I2S_FIFO_TX,
- I2S_FIFO_ATN_LVL_FOUR_SLOTS);
- i2s_fifo_enable(I2S_IFC, I2S_FIFO_TX, 1);
-}
-
-static void stop_i2s_playback(void)
-{
- i2s_set_fifo_irq_on_err(I2S_IFC, I2S_FIFO_TX, 0);
- i2s_set_fifo_irq_on_qe(I2S_IFC, I2S_FIFO_TX, 0);
- i2s_fifo_enable(I2S_IFC, I2S_FIFO_TX, 0);
- while (i2s_get_status(I2S_IFC) & I2S_I2S_FIFO_TX_BUSY);
-}
-
static void tegra_pcm_play(struct tegra_runtime_data *prtd)
{
static int reqid = 0;
@@ -75,51 +60,6 @@ static void tegra_pcm_play(struct tegra_runtime_data *prtd)
}
-static void dma_tx_complete_callback (struct tegra_dma_req *req)
-{
- struct tegra_runtime_data *prtd = (struct tegra_runtime_data *)req->dev;
- struct snd_pcm_substream *substream = prtd->substream;
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- if (++prtd->period_index >= runtime->periods) {
- prtd->period_index = 0;
- }
-
- if (prtd->dma_state != STATE_ABORT) {
- snd_pcm_period_elapsed(substream);
- tegra_pcm_play(prtd);
- }
-}
-
-static void setup_dma_tx_request(struct tegra_dma_req *req)
-{
- memset(req, 0, sizeof(*req));
- req->complete = dma_tx_complete_callback;
- req->to_memory = false;
- req->dest_addr = i2s_get_fifo_phy_base(I2S_IFC, I2S_FIFO_TX);
- req->dest_wrap = 4;
- req->source_bus_width = 32;
- req->source_wrap = 0;
- req->dest_bus_width = 32;
- req->req_sel = I2S_IFC ? 1 : 2; /* 1 = I2S2, 2 = I2S1 */
-}
-
-/* recording */
-static void start_i2s_capture(void)
-{
- i2s_fifo_set_attention_level(I2S_IFC, I2S_FIFO_RX,
- I2S_FIFO_ATN_LVL_FOUR_SLOTS);
- i2s_fifo_enable(I2S_IFC, I2S_FIFO_RX, 1);
-}
-
-static void stop_i2s_capture(void)
-{
- i2s_set_fifo_irq_on_err(I2S_IFC, I2S_FIFO_RX, 0);
- i2s_set_fifo_irq_on_qe(I2S_IFC, I2S_FIFO_RX, 0);
- i2s_fifo_enable(I2S_IFC, I2S_FIFO_RX, 0);
- while (i2s_get_status(I2S_IFC) & I2S_I2S_FIFO_RX_BUSY);
-}
-
static void tegra_pcm_capture(struct tegra_runtime_data *prtd)
{
static int reqid = 0;
@@ -157,7 +97,7 @@ static void tegra_pcm_capture(struct tegra_runtime_data *prtd)
}
-static void dma_rx_complete_callback(struct tegra_dma_req *req)
+static void dma_complete_callback (struct tegra_dma_req *req)
{
struct tegra_runtime_data *prtd = (struct tegra_runtime_data *)req->dev;
struct snd_pcm_substream *substream = prtd->substream;
@@ -169,23 +109,14 @@ static void dma_rx_complete_callback(struct tegra_dma_req *req)
if (prtd->dma_state != STATE_ABORT) {
snd_pcm_period_elapsed(substream);
- tegra_pcm_capture(prtd);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ tegra_pcm_play(prtd);
+ } else {
+ tegra_pcm_capture(prtd);
+ }
}
}
-static void setup_dma_rx_request(struct tegra_dma_req *req)
-{
- memset(req, 0, sizeof(*req));
- req->complete = dma_rx_complete_callback;
- req->to_memory = true;
- req->source_addr = i2s_get_fifo_phy_base(I2S_IFC, I2S_FIFO_RX);
- req->dest_wrap = 0;
- req->source_bus_width = 32;
- req->source_wrap = 4;
- req->dest_bus_width = 32;
- req->req_sel = I2S_IFC ? 1 : 2; /* 1 = I2S2, 2 = I2S1 */
-}
-
static const struct snd_pcm_hardware tegra_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED | \
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | \
@@ -238,14 +169,12 @@ static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
prtd->dma_state = STATE_INIT;
tegra_pcm_play(prtd); /* dma enqueue req1 */
tegra_pcm_play(prtd); /* dma enqueue req2 */
- start_i2s_playback();
} else if (prtd->state != STATE_INIT) {
/* start recording */
prtd->state = STATE_INIT;
prtd->dma_state = STATE_INIT;
tegra_pcm_capture(prtd); /* dma enqueue req1 */
tegra_pcm_capture(prtd); /* dma enqueue req2 */
- start_i2s_capture();
}
break;
case SNDRV_PCM_TRIGGER_STOP:
@@ -256,7 +185,6 @@ static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
tegra_dma_cancel(prtd->dma_chan);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (prtd->dma_chan) {
- stop_i2s_playback();
tegra_dma_dequeue_req(prtd->dma_chan,
&prtd->dma_req1);
tegra_dma_dequeue_req(prtd->dma_chan,
@@ -264,7 +192,6 @@ static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
}
} else {
if (prtd->dma_chan) {
- stop_i2s_capture();
tegra_dma_dequeue_req(prtd->dma_chan,
&prtd->dma_req1);
tegra_dma_dequeue_req(prtd->dma_chan,
@@ -337,16 +264,15 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream)
prtd->state = STATE_INVALID;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- setup_dma_tx_request(&prtd->dma_req1);
- setup_dma_tx_request(&prtd->dma_req2);
- } else {
- setup_dma_rx_request(&prtd->dma_req1);
- setup_dma_rx_request(&prtd->dma_req2);
- }
+ setup_dma_request(substream,
+ &prtd->dma_req1,
+ dma_complete_callback,
+ prtd);
- prtd->dma_req1.dev = prtd;
- prtd->dma_req2.dev = prtd;
+ setup_dma_request(substream,
+ &prtd->dma_req2,
+ dma_complete_callback,
+ prtd);
prtd->dma_chan = tegra_dma_allocate_channel(TEGRA_DMA_MODE_CONTINUOUS_DOUBLE);
if (IS_ERR(prtd->dma_chan)) {
@@ -394,10 +320,6 @@ static int tegra_pcm_close(struct snd_pcm_substream *substream)
prtd->dma_state = STATE_EXIT;
tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req1);
tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req2);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- stop_i2s_playback();
- else
- stop_i2s_capture();
tegra_dma_flush(prtd->dma_chan);
tegra_dma_free_channel(prtd->dma_chan);
prtd->dma_chan = NULL;
diff --git a/sound/soc/tegra/tegra_soc.h b/sound/soc/tegra/tegra_soc.h
index c9ef76acebc0..83b462779ce6 100644
--- a/sound/soc/tegra/tegra_soc.h
+++ b/sound/soc/tegra/tegra_soc.h
@@ -96,7 +96,6 @@ struct tegra_runtime_data {
struct clk *i2s_clk;
struct clk *dap_mclk;
struct clk *audio_sync_clk;
- struct i2s_runtime_data i2s_regs;
};
struct tegra_audio_data {
@@ -109,4 +108,9 @@ struct tegra_audio_data {
int tegra_controls_init(struct snd_soc_codec *codec);
void tegra_controls_exit(void);
+int setup_dma_request(struct snd_pcm_substream *substream,
+ struct tegra_dma_req *req,
+ void (*dma_callback)(struct tegra_dma_req *req),
+ void *dma_data);
+
#endif
diff --git a/sound/soc/tegra/tegra_soc_controls.c b/sound/soc/tegra/tegra_soc_controls.c
index a090740a3f7d..f73e80df751f 100644
--- a/sound/soc/tegra/tegra_soc_controls.c
+++ b/sound/soc/tegra/tegra_soc_controls.c
@@ -387,50 +387,53 @@ int tegra_controls_init(struct snd_soc_codec *codec)
{
int err;
- audio_data = kzalloc(sizeof(*audio_data), GFP_KERNEL);
if (!audio_data) {
- pr_err("failed to allocate tegra_audio_data \n");
- return -ENOMEM;
- }
+ audio_data = kzalloc(sizeof(*audio_data), GFP_KERNEL);
+ if (!audio_data) {
+ pr_err("failed to allocate tegra_audio_data \n");
+ return -ENOMEM;
+ }
- /* Add tegra specific controls */
- err = snd_soc_add_controls(codec, tegra_controls,
- ARRAY_SIZE(tegra_controls));
- if (err < 0)
- goto fail;
+ /* Add tegra specific controls */
+ err = snd_soc_add_controls(codec, tegra_controls,
+ ARRAY_SIZE(tegra_controls));
+ if (err < 0)
+ goto fail;
- /* Add tegra specific widgets */
- snd_soc_dapm_new_controls(codec, tegra_dapm_widgets,
- ARRAY_SIZE(tegra_dapm_widgets));
+ /* Add tegra specific widgets */
+ snd_soc_dapm_new_controls(codec, tegra_dapm_widgets,
+ ARRAY_SIZE(tegra_dapm_widgets));
- /* Set up tegra specific audio path audio_map */
- snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+ /* Set up tegra specific audio path audio_map */
+ snd_soc_dapm_add_routes(codec, audio_map,
+ ARRAY_SIZE(audio_map));
- audio_data->codec = codec;
- /* Add play route control */
- err = snd_ctl_add(codec->card,
+ audio_data->codec = codec;
+ /* Add play route control */
+ err = snd_ctl_add(codec->card,
snd_ctl_new1(&tegra_play_route_control, NULL));
- if (err < 0)
- goto fail;
+ if (err < 0)
+ goto fail;
- /* Add capture route control */
- err = snd_ctl_add(codec->card,
+ /* Add capture route control */
+ err = snd_ctl_add(codec->card,
snd_ctl_new1(&tegra_capture_route_control, NULL));
- if (err < 0)
- goto fail;
+ if (err < 0)
+ goto fail;
- /* Add call mode switch control */
- err = snd_ctl_add(codec->card,
+ /* Add call mode switch control */
+ err = snd_ctl_add(codec->card,
snd_ctl_new1(&tegra_call_mode_control, NULL));
- if (err < 0)
- goto fail;
+ if (err < 0)
+ goto fail;
- /* Default to HP output */
- tegra_jack_func = TEGRA_HP;
- tegra_spk_func = TEGRA_SPK_ON;
- tegra_ext_control(codec);
+ /* Default to HP output */
+ tegra_jack_func = TEGRA_HP;
+ tegra_spk_func = TEGRA_SPK_ON;
+ tegra_ext_control(codec);
- snd_soc_dapm_sync(codec);
+ snd_soc_dapm_sync(codec);
+ }
return 0;
fail:
diff --git a/sound/soc/tegra/tegra_soc_wm8903.c b/sound/soc/tegra/tegra_soc_wm8903.c
index c4fef53570ee..dc5103c36377 100644
--- a/sound/soc/tegra/tegra_soc_wm8903.c
+++ b/sound/soc/tegra/tegra_soc_wm8903.c
@@ -20,7 +20,7 @@
static struct platform_device *tegra_snd_device;
-extern struct snd_soc_dai tegra_i2s_dai;
+extern struct snd_soc_dai tegra_i2s_dai[];
extern struct snd_soc_platform tegra_soc_platform;
/* codec register values */
@@ -162,23 +162,34 @@ static int tegra_codec_init(struct snd_soc_codec *codec)
return tegra_controls_init(codec);
}
+static struct snd_soc_dai_link tegra_soc_dai[] = {
+ {
+ .name = "WM8903",
+ .stream_name = "WM8903 HiFi",
+ .cpu_dai = &tegra_i2s_dai[0],
+ .codec_dai = &wm8903_dai,
+ .init = tegra_codec_init,
+ .ops = &tegra_hifi_ops,
+ },
+ {
+ .name = "WM8903",
+ .stream_name = "WM8903 Voice",
+ .cpu_dai = &tegra_i2s_dai[1],
+ .codec_dai = &wm8903_dai,
+ .init = tegra_codec_init,
+ .ops = &tegra_hifi_ops,
+ },
-static struct snd_soc_dai_link tegra_soc_dai = {
- .name = "WM8903",
- .stream_name = "WM8903 HiFi",
- .cpu_dai = &tegra_i2s_dai,
- .codec_dai = &wm8903_dai,
- .init = tegra_codec_init,
- .ops = &tegra_hifi_ops,
};
static struct snd_soc_card tegra_snd_soc = {
.name = "tegra",
.platform = &tegra_soc_platform,
- .dai_link = &tegra_soc_dai,
- .num_links = 1,
+ .dai_link = tegra_soc_dai,
+ .num_links = ARRAY_SIZE(tegra_soc_dai),
};
+
static struct snd_soc_device tegra_snd_devdata = {
.card = &tegra_snd_soc,
.codec_dev = &soc_codec_dev_wm8903,