From 66e0ed154cfb916b83e3f0074f7cd197effaab39 Mon Sep 17 00:00:00 2001 From: Ravindra Lokhande Date: Thu, 30 Dec 2010 19:29:54 +0530 Subject: [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 Tested-by: Ravindra Lokhande Reviewed-by: Bharat Nihalani Tested-by: Bharat Nihalani --- sound/soc/tegra/tegra_i2s.c | 317 ++++++++++++++++++++++++++++------- sound/soc/tegra/tegra_pcm.c | 106 ++---------- sound/soc/tegra/tegra_soc.h | 6 +- sound/soc/tegra/tegra_soc_controls.c | 67 ++++---- sound/soc/tegra/tegra_soc_wm8903.c | 31 ++-- 5 files changed, 335 insertions(+), 192 deletions(-) (limited to 'sound') 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, -- cgit v1.2.3