[alsa-devel] [PATCH] AC97 atmel: add support for AT91(common with AVR32).
This patch add AC97 support for ATMEL AT91 boards, using the AVR32 code. It is based on Takashi git tree(sound-2.6/for-next).
Regards, Sedji
Signed-off-by: Sedji Gaouaou sedji.gaouaou@atmel.com --- sound/atmel/Kconfig | 2 +- sound/atmel/ac97c.c | 364 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 268 insertions(+), 98 deletions(-)
diff --git a/sound/atmel/Kconfig b/sound/atmel/Kconfig index 6c228a9..94de43a 100644 --- a/sound/atmel/Kconfig +++ b/sound/atmel/Kconfig @@ -12,7 +12,7 @@ config SND_ATMEL_AC97C tristate "Atmel AC97 Controller (AC97C) driver" select SND_PCM select SND_AC97_CODEC - depends on DW_DMAC && AVR32 + depends on (DW_DMAC && AVR32) || ARCH_AT91 help ALSA sound driver for the Atmel AC97 controller.
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 0c0f877..379d7ea 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -13,6 +13,7 @@ #include <linux/device.h> #include <linux/dmaengine.h> #include <linux/dma-mapping.h> +#include <linux/atmel_pdc.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/module.h> @@ -31,6 +32,10 @@
#include <linux/dw_dmac.h>
+#include <mach/cpu.h> +#include <mach/hardware.h> +#include <mach/gpio.h> + #include "ac97c.h"
enum { @@ -63,6 +68,7 @@ struct atmel_ac97c { u64 cur_format; unsigned int cur_rate; unsigned long flags; + int period; /* Serialize access to opened variable */ spinlock_t lock; void __iomem *regs; @@ -167,6 +173,7 @@ static int atmel_ac97c_playback_open(struct snd_pcm_substream *substream) mutex_lock(&opened_mutex); chip->opened++; runtime->hw = atmel_ac97c_hw; + chip->period = 0; if (chip->cur_rate) { runtime->hw.rate_min = chip->cur_rate; runtime->hw.rate_max = chip->cur_rate; @@ -186,6 +193,7 @@ static int atmel_ac97c_capture_open(struct snd_pcm_substream *substream) mutex_lock(&opened_mutex); chip->opened++; runtime->hw = atmel_ac97c_hw; + chip->period = 0; if (chip->cur_rate) { runtime->hw.rate_min = chip->cur_rate; runtime->hw.rate_max = chip->cur_rate; @@ -239,12 +247,14 @@ static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream,
retval = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); - if (retval < 0) - return retval; - /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ - if (retval == 1) - if (test_and_clear_bit(DMA_TX_READY, &chip->flags)) - dw_dma_cyclic_free(chip->dma.tx_chan); + if(cpu_is_at32ap7000()) { + if (retval < 0) + return retval; + /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ + if (retval == 1) + if (test_and_clear_bit(DMA_TX_READY, &chip->flags)) + dw_dma_cyclic_free(chip->dma.tx_chan); + }
/* Set restrictions to params. */ mutex_lock(&opened_mutex); @@ -263,12 +273,14 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
retval = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); - if (retval < 0) - return retval; - /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ - if (retval == 1) - if (test_and_clear_bit(DMA_RX_READY, &chip->flags)) - dw_dma_cyclic_free(chip->dma.rx_chan); + if(cpu_is_at32ap7000()) { + if (retval < 0) + return retval; + /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ + if (retval == 1) + if (test_and_clear_bit(DMA_RX_READY, &chip->flags)) + dw_dma_cyclic_free(chip->dma.rx_chan); + }
/* Set restrictions to params. */ mutex_lock(&opened_mutex); @@ -282,16 +294,20 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream, static int atmel_ac97c_playback_hw_free(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); - if (test_and_clear_bit(DMA_TX_READY, &chip->flags)) - dw_dma_cyclic_free(chip->dma.tx_chan); + if(cpu_is_at32ap7000()) { + if (test_and_clear_bit(DMA_TX_READY, &chip->flags)) + dw_dma_cyclic_free(chip->dma.tx_chan); + } return snd_pcm_lib_free_pages(substream); }
static int atmel_ac97c_capture_hw_free(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); - if (test_and_clear_bit(DMA_RX_READY, &chip->flags)) - dw_dma_cyclic_free(chip->dma.rx_chan); + if(cpu_is_at32ap7000()) { + if (test_and_clear_bit(DMA_RX_READY, &chip->flags)) + dw_dma_cyclic_free(chip->dma.rx_chan); + } return snd_pcm_lib_free_pages(substream); }
@@ -299,6 +315,7 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; + int block_size = frames_to_bytes(runtime, runtime->period_size); unsigned long word = ac97c_readl(chip, OCA); int retval;
@@ -324,7 +341,9 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
switch (runtime->format) { case SNDRV_PCM_FORMAT_S16_LE: - word |= AC97C_CMR_CEM_LITTLE; + if(cpu_is_at32ap7000()) { + word |= AC97C_CMR_CEM_LITTLE; + } break; case SNDRV_PCM_FORMAT_S16_BE: /* fall through */ word &= ~(AC97C_CMR_CEM_LITTLE); @@ -363,9 +382,18 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n", runtime->rate);
- if (!test_bit(DMA_TX_READY, &chip->flags)) - retval = atmel_ac97c_prepare_dma(chip, substream, - DMA_TO_DEVICE); + if(cpu_is_at32ap7000()) { + if (!test_bit(DMA_TX_READY, &chip->flags)) + retval = atmel_ac97c_prepare_dma(chip, substream, + DMA_TO_DEVICE); + } else { + /* Initialize and start the PDC */ + writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR); + writel(block_size / 2, chip->regs + ATMEL_PDC_TCR); + writel(runtime->dma_addr + block_size, + chip->regs + ATMEL_PDC_TNPR); + writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR); + }
return retval; } @@ -374,6 +402,7 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; + int block_size = frames_to_bytes(runtime, runtime->period_size); unsigned long word = ac97c_readl(chip, ICA); int retval;
@@ -415,11 +444,15 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) word |= AC97C_CSR_OVRUN;
ac97c_writel(chip, CAMR, word); - /* Enable channel A event interrupt */ word = ac97c_readl(chip, IMR); word |= AC97C_SR_CAEVT; - ac97c_writel(chip, IER, word); + ac97c_writel(chip, IER, /*word*/AC97C_SR_CAEVT); + + /* Enable channel A event interrupt */ + /*word = ac97c_readl(chip, IMR); + word |= AC97C_SR_CAEVT; + ac97c_writel(chip, IER, word);*/
/* set variable rate if needed */ if (runtime->rate != 48000) { @@ -438,9 +471,18 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n", runtime->rate);
- if (!test_bit(DMA_RX_READY, &chip->flags)) - retval = atmel_ac97c_prepare_dma(chip, substream, - DMA_FROM_DEVICE); + if(cpu_is_at32ap7000()) { + if (!test_bit(DMA_RX_READY, &chip->flags)) + retval = atmel_ac97c_prepare_dma(chip, substream, + DMA_FROM_DEVICE); + } else { + /* Initialize and start the PDC */ + writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR); + writel(block_size / 2, chip->regs + ATMEL_PDC_RCR); + writel(runtime->dma_addr + block_size, + chip->regs + ATMEL_PDC_RNPR); + writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR); + }
return retval; } @@ -449,7 +491,7 @@ static int atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); - unsigned long camr; + unsigned long camr, ptcr = 0; int retval = 0;
camr = ac97c_readl(chip, CAMR); @@ -458,15 +500,23 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ case SNDRV_PCM_TRIGGER_START: - retval = dw_dma_cyclic_start(chip->dma.tx_chan); - if (retval) - goto out; - camr |= AC97C_CMR_CENA; + if(cpu_is_at32ap7000()) { + retval = dw_dma_cyclic_start(chip->dma.tx_chan); + if (retval) + goto out; + } else { + ptcr = ATMEL_PDC_TXTEN; + } + camr |= AC97C_CMR_CENA | AC97C_CSR_ENDTX; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ case SNDRV_PCM_TRIGGER_STOP: - dw_dma_cyclic_stop(chip->dma.tx_chan); + if(cpu_is_at32ap7000()) { + dw_dma_cyclic_stop(chip->dma.tx_chan); + } else { + ptcr = ATMEL_PDC_TXTDIS; + } if (chip->opened <= 1) camr &= ~AC97C_CMR_CENA; break; @@ -476,6 +526,8 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) }
ac97c_writel(chip, CAMR, camr); + if(!cpu_is_at32ap7000()) + writel(ptcr, chip->regs + ATMEL_PDC_PTCR); out: return retval; } @@ -484,7 +536,7 @@ static int atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); - unsigned long camr; + unsigned long camr, ptcr = 0; int retval = 0;
camr = ac97c_readl(chip, CAMR); @@ -493,15 +545,24 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ case SNDRV_PCM_TRIGGER_START: - retval = dw_dma_cyclic_start(chip->dma.rx_chan); - if (retval) - goto out; + if(cpu_is_at32ap7000()) { + retval = dw_dma_cyclic_start(chip->dma.rx_chan); + if (retval) + goto out; + } else { + ptcr = ATMEL_PDC_RXTEN; + } camr |= AC97C_CMR_CENA; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ case SNDRV_PCM_TRIGGER_STOP: - dw_dma_cyclic_stop(chip->dma.rx_chan); + if(cpu_is_at32ap7000()) { + dw_dma_cyclic_stop(chip->dma.rx_chan); + } + else { + ptcr = ATMEL_PDC_RXTDIS; + } if (chip->opened <= 1) camr &= ~AC97C_CMR_CENA; break; @@ -511,6 +572,8 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) }
ac97c_writel(chip, CAMR, camr); + if(!cpu_is_at32ap7000()) + writel(ptcr, chip->regs + ATMEL_PDC_PTCR); out: return retval; } @@ -523,7 +586,11 @@ atmel_ac97c_playback_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t frames; unsigned long bytes;
- bytes = dw_dma_get_src_addr(chip->dma.tx_chan); + if(cpu_is_at32ap7000()) { + bytes = dw_dma_get_src_addr(chip->dma.tx_chan); + } else { + bytes = readl(chip->regs + ATMEL_PDC_TPR); + } bytes -= runtime->dma_addr;
frames = bytes_to_frames(runtime, bytes); @@ -540,7 +607,11 @@ atmel_ac97c_capture_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t frames; unsigned long bytes;
- bytes = dw_dma_get_dst_addr(chip->dma.rx_chan); + if(cpu_is_at32ap7000()) { + bytes = dw_dma_get_dst_addr(chip->dma.rx_chan); + } else { + bytes = readl(chip->regs + ATMEL_PDC_RPR); + } bytes -= runtime->dma_addr;
frames = bytes_to_frames(runtime, bytes); @@ -578,20 +649,66 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) u32 sr = ac97c_readl(chip, SR); u32 casr = ac97c_readl(chip, CASR); u32 cosr = ac97c_readl(chip, COSR); + u32 camr = ac97c_readl(chip, CAMR);
if (sr & AC97C_SR_CAEVT) { - dev_info(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n", + struct snd_pcm_runtime *runtime; + int offset, next_period, block_size; + dev_dbg(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n", casr & AC97C_CSR_OVRUN ? " OVRUN" : "", casr & AC97C_CSR_RXRDY ? " RXRDY" : "", casr & AC97C_CSR_UNRUN ? " UNRUN" : "", casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "", casr & AC97C_CSR_TXRDY ? " TXRDY" : "", !casr ? " NONE" : ""); + if(!cpu_is_at32ap7000()) { + if ((casr & camr) & AC97C_CSR_ENDTX) { + runtime = chip->playback_substream->runtime; + block_size = frames_to_bytes(runtime, + runtime->period_size); + chip->period++; + + if (chip->period == runtime->periods) + chip->period = 0; + next_period = chip->period + 1; + if (next_period == runtime->periods) + next_period = 0; + + offset = block_size * next_period; + + writel(runtime->dma_addr + offset, + chip->regs + ATMEL_PDC_TNPR); + writel(block_size / 2, + chip->regs + ATMEL_PDC_TNCR); + + snd_pcm_period_elapsed(chip->playback_substream); + } + if ((casr & camr) & AC97C_CSR_ENDRX) { + runtime = chip->capture_substream->runtime; + block_size = frames_to_bytes(runtime, + runtime->period_size); + chip->period++; + + if (chip->period == runtime->periods) + chip->period = 0; + next_period = chip->period + 1; + if (next_period == runtime->periods) + next_period = 0; + + offset = block_size * next_period; + + writel(runtime->dma_addr + offset, + chip->regs + ATMEL_PDC_RNPR); + writel(block_size / 2, + chip->regs + ATMEL_PDC_RNCR); + snd_pcm_period_elapsed(chip->capture_substream); + } + } retval = IRQ_HANDLED; }
if (sr & AC97C_SR_COEVT) { - dev_info(&chip->pdev->dev, "codec channel event%s%s%s%s%s\n", + dev_dbg(&chip->pdev->dev, "codec channel event%s%s%s%s%s\n", cosr & AC97C_CSR_OVRUN ? " OVRUN" : "", cosr & AC97C_CSR_RXRDY ? " RXRDY" : "", cosr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "", @@ -608,15 +725,50 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) return retval; }
+static struct ac97_pcm at91_ac97_pcm_defs[] __devinitdata = { + /* Playback */ + { + .exclusive = 1, + .r = { { + .slots = ((1 << AC97_SLOT_PCM_LEFT) + | (1 << AC97_SLOT_PCM_RIGHT)), + } }, + }, + /* PCM in */ + { + .stream = 1, + .exclusive = 1, + .r = { { + .slots = ((1 << AC97_SLOT_PCM_LEFT) + | (1 << AC97_SLOT_PCM_RIGHT)), + } } + }, + /* Mic in */ + { + .stream = 1, + .exclusive = 1, + .r = { { + .slots = (1<<AC97_SLOT_MIC), + } } + }, +}; + static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip) { struct snd_pcm *pcm; struct snd_pcm_hardware hw = atmel_ac97c_hw; - int capture, playback, retval; + int capture, playback, retval, err;
capture = test_bit(DMA_RX_CHAN_PRESENT, &chip->flags); playback = test_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
+ if(!cpu_is_at32ap7000()) { + err = snd_ac97_pcm_assign(chip->ac97_bus, + ARRAY_SIZE(at91_ac97_pcm_defs), + at91_ac97_pcm_defs); + if (err) + return err; + } retval = snd_pcm_new(chip->card, chip->card->shortname, chip->pdev->id, playback, capture, &pcm); if (retval) @@ -775,7 +927,12 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) return -ENXIO; }
- pclk = clk_get(&pdev->dev, "pclk"); + if(cpu_is_at32ap7000()) { + pclk = clk_get(&pdev->dev, "pclk"); + } else { + pclk = clk_get(&pdev->dev, "ac97_clk"); + } + if (IS_ERR(pclk)) { dev_dbg(&pdev->dev, "no peripheral clock\n"); return PTR_ERR(pclk); @@ -844,44 +1001,51 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) goto err_ac97_bus; }
- if (pdata->rx_dws.dma_dev) { - struct dw_dma_slave *dws = &pdata->rx_dws; - dma_cap_mask_t mask; + if(cpu_is_at32ap7000()) { + if (pdata->rx_dws.dma_dev) { + struct dw_dma_slave *dws = &pdata->rx_dws; + dma_cap_mask_t mask;
- dws->rx_reg = regs->start + AC97C_CARHR + 2; + dws->rx_reg = regs->start + AC97C_CARHR + 2;
- dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask);
- chip->dma.rx_chan = dma_request_channel(mask, filter, dws); + chip->dma.rx_chan = dma_request_channel(mask, filter, dws);
- dev_info(&chip->pdev->dev, "using %s for DMA RX\n", + dev_info(&chip->pdev->dev, "using %s for DMA RX\n", dev_name(&chip->dma.rx_chan->dev->device)); - set_bit(DMA_RX_CHAN_PRESENT, &chip->flags); - } + set_bit(DMA_RX_CHAN_PRESENT, &chip->flags); + }
- if (pdata->tx_dws.dma_dev) { - struct dw_dma_slave *dws = &pdata->tx_dws; - dma_cap_mask_t mask; + if (pdata->tx_dws.dma_dev) { + struct dw_dma_slave *dws = &pdata->tx_dws; + dma_cap_mask_t mask;
- dws->tx_reg = regs->start + AC97C_CATHR + 2; + dws->tx_reg = regs->start + AC97C_CATHR + 2;
- dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask);
- chip->dma.tx_chan = dma_request_channel(mask, filter, dws); + chip->dma.tx_chan = dma_request_channel(mask, filter, dws);
- dev_info(&chip->pdev->dev, "using %s for DMA TX\n", - dev_name(&chip->dma.tx_chan->dev->device)); - set_bit(DMA_TX_CHAN_PRESENT, &chip->flags); - } + dev_info(&chip->pdev->dev, "using %s for DMA TX\n", + dev_name(&chip->dma.tx_chan->dev->device)); + set_bit(DMA_TX_CHAN_PRESENT, &chip->flags); + }
- if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) && - !test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) { - dev_dbg(&pdev->dev, "DMA not available\n"); - retval = -ENODEV; - goto err_dma; - } + if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) && + !test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) { + dev_dbg(&pdev->dev, "DMA not available\n"); + retval = -ENODEV; + goto err_dma; + } + } else { + /* Just pretend that we have DMA channel(for at91 i is actually + * the PDC */ + set_bit(DMA_RX_CHAN_PRESENT, &chip->flags); + set_bit(DMA_TX_CHAN_PRESENT, &chip->flags); + }
retval = atmel_ac97c_pcm_new(chip); if (retval) { @@ -897,20 +1061,22 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, card);
- dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p\n", - chip->regs); + dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p, irq = %d\n", + chip->regs, irq);
return 0;
err_dma: - if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) - dma_release_channel(chip->dma.rx_chan); - if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) - dma_release_channel(chip->dma.tx_chan); - clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags); - clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags); - chip->dma.rx_chan = NULL; - chip->dma.tx_chan = NULL; + if(cpu_is_at32ap7000()) { + if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) + dma_release_channel(chip->dma.rx_chan); + if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) + dma_release_channel(chip->dma.tx_chan); + clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags); + clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags); + chip->dma.rx_chan = NULL; + chip->dma.tx_chan = NULL; + } err_ac97_bus: snd_card_set_dev(card, NULL);
@@ -934,12 +1100,13 @@ static int atmel_ac97c_suspend(struct platform_device *pdev, pm_message_t msg) struct snd_card *card = platform_get_drvdata(pdev); struct atmel_ac97c *chip = card->private_data;
- if (test_bit(DMA_RX_READY, &chip->flags)) - dw_dma_cyclic_stop(chip->dma.rx_chan); - if (test_bit(DMA_TX_READY, &chip->flags)) - dw_dma_cyclic_stop(chip->dma.tx_chan); + if(cpu_is_at32ap7000()) { + if (test_bit(DMA_RX_READY, &chip->flags)) + dw_dma_cyclic_stop(chip->dma.rx_chan); + if (test_bit(DMA_TX_READY, &chip->flags)) + dw_dma_cyclic_stop(chip->dma.tx_chan); + } clk_disable(chip->pclk); - return 0; }
@@ -949,11 +1116,12 @@ static int atmel_ac97c_resume(struct platform_device *pdev) struct atmel_ac97c *chip = card->private_data;
clk_enable(chip->pclk); - if (test_bit(DMA_RX_READY, &chip->flags)) - dw_dma_cyclic_start(chip->dma.rx_chan); - if (test_bit(DMA_TX_READY, &chip->flags)) - dw_dma_cyclic_start(chip->dma.tx_chan); - + if(cpu_is_at32ap7000()) { + if (test_bit(DMA_RX_READY, &chip->flags)) + dw_dma_cyclic_start(chip->dma.rx_chan); + if (test_bit(DMA_TX_READY, &chip->flags)) + dw_dma_cyclic_start(chip->dma.tx_chan); + } return 0; } #else @@ -978,14 +1146,16 @@ static int __devexit atmel_ac97c_remove(struct platform_device *pdev) iounmap(chip->regs); free_irq(chip->irq, chip);
- if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) - dma_release_channel(chip->dma.rx_chan); - if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) - dma_release_channel(chip->dma.tx_chan); - clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags); - clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags); - chip->dma.rx_chan = NULL; - chip->dma.tx_chan = NULL; + if(cpu_is_at32ap7000()) { + if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) + dma_release_channel(chip->dma.rx_chan); + if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) + dma_release_channel(chip->dma.tx_chan); + clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags); + clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags); + chip->dma.rx_chan = NULL; + chip->dma.tx_chan = NULL; + }
snd_card_set_dev(card, NULL); snd_card_free(card);
At Fri, 10 Jul 2009 11:08:37 +0200, Sedji Gaouaou wrote:
This patch add AC97 support for ATMEL AT91 boards, using the AVR32 code. It is based on Takashi git tree(sound-2.6/for-next).
Thanks. The changes look almost fine. Some comments below.
@@ -167,6 +173,7 @@ static int atmel_ac97c_playback_open(struct snd_pcm_substream *substream) mutex_lock(&opened_mutex); chip->opened++; runtime->hw = atmel_ac97c_hw;
- chip->period = 0;
Shouldn't be this initialized rather in the prepare callback?
@@ -239,12 +247,14 @@ static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream,
retval = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
- if (retval < 0)
return retval;
- /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
- if (retval == 1)
if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.tx_chan);
- if(cpu_is_at32ap7000()) {
Put a space after if.
if (retval < 0)
return retval;
The error check should be independent from the cpu type.
@@ -324,7 +341,9 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
switch (runtime->format) { case SNDRV_PCM_FORMAT_S16_LE:
word |= AC97C_CMR_CEM_LITTLE;
if(cpu_is_at32ap7000()) {
word |= AC97C_CMR_CEM_LITTLE;
}
No need braces here. Better to run $LINUX/scripts/checkpatch.pl once and fix warnings suggested there.
thanks,
Takashi
This patch add AC97 support for ATMEL AT91 boards, using the AVR32 code. It is based on Takashi git tree(sound-2.6/for-next).
Regards, Sedji
Signed-off-by: Sedji Gaouaou sedji.gaouaou@atmel.com --- sound/atmel/Kconfig | 2 +- sound/atmel/ac97c.c | 353 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 261 insertions(+), 94 deletions(-)
diff --git a/sound/atmel/Kconfig b/sound/atmel/Kconfig index 6c228a9..94de43a 100644 --- a/sound/atmel/Kconfig +++ b/sound/atmel/Kconfig @@ -12,7 +12,7 @@ config SND_ATMEL_AC97C tristate "Atmel AC97 Controller (AC97C) driver" select SND_PCM select SND_AC97_CODEC - depends on DW_DMAC && AVR32 + depends on (DW_DMAC && AVR32) || ARCH_AT91 help ALSA sound driver for the Atmel AC97 controller.
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 0c0f877..3c83b8a 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -13,6 +13,7 @@ #include <linux/device.h> #include <linux/dmaengine.h> #include <linux/dma-mapping.h> +#include <linux/atmel_pdc.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/module.h> @@ -31,6 +32,10 @@
#include <linux/dw_dmac.h>
+#include <mach/cpu.h> +#include <mach/hardware.h> +#include <mach/gpio.h> + #include "ac97c.h"
enum { @@ -63,6 +68,7 @@ struct atmel_ac97c { u64 cur_format; unsigned int cur_rate; unsigned long flags; + int period; /* Serialize access to opened variable */ spinlock_t lock; void __iomem *regs; @@ -241,10 +247,13 @@ static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream, params_buffer_bytes(hw_params)); if (retval < 0) return retval; - /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ - if (retval == 1) - if (test_and_clear_bit(DMA_TX_READY, &chip->flags)) - dw_dma_cyclic_free(chip->dma.tx_chan); + + if (cpu_is_at32ap7000()) { + /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ + if (retval == 1) + if (test_and_clear_bit(DMA_TX_READY, &chip->flags)) + dw_dma_cyclic_free(chip->dma.tx_chan); + }
/* Set restrictions to params. */ mutex_lock(&opened_mutex); @@ -263,12 +272,14 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
retval = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); - if (retval < 0) - return retval; - /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ - if (retval == 1) - if (test_and_clear_bit(DMA_RX_READY, &chip->flags)) - dw_dma_cyclic_free(chip->dma.rx_chan); + if (cpu_is_at32ap7000()) { + if (retval < 0) + return retval; + /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ + if (retval == 1) + if (test_and_clear_bit(DMA_RX_READY, &chip->flags)) + dw_dma_cyclic_free(chip->dma.rx_chan); + }
/* Set restrictions to params. */ mutex_lock(&opened_mutex); @@ -282,16 +293,20 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream, static int atmel_ac97c_playback_hw_free(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); - if (test_and_clear_bit(DMA_TX_READY, &chip->flags)) - dw_dma_cyclic_free(chip->dma.tx_chan); + if (cpu_is_at32ap7000()) { + if (test_and_clear_bit(DMA_TX_READY, &chip->flags)) + dw_dma_cyclic_free(chip->dma.tx_chan); + } return snd_pcm_lib_free_pages(substream); }
static int atmel_ac97c_capture_hw_free(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); - if (test_and_clear_bit(DMA_RX_READY, &chip->flags)) - dw_dma_cyclic_free(chip->dma.rx_chan); + if (cpu_is_at32ap7000()) { + if (test_and_clear_bit(DMA_RX_READY, &chip->flags)) + dw_dma_cyclic_free(chip->dma.rx_chan); + } return snd_pcm_lib_free_pages(substream); }
@@ -299,9 +314,11 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; + int block_size = frames_to_bytes(runtime, runtime->period_size); unsigned long word = ac97c_readl(chip, OCA); int retval;
+ chip->period = 0; word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
/* assign channels to AC97C channel A */ @@ -324,7 +341,8 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
switch (runtime->format) { case SNDRV_PCM_FORMAT_S16_LE: - word |= AC97C_CMR_CEM_LITTLE; + if (cpu_is_at32ap7000()) + word |= AC97C_CMR_CEM_LITTLE; break; case SNDRV_PCM_FORMAT_S16_BE: /* fall through */ word &= ~(AC97C_CMR_CEM_LITTLE); @@ -363,9 +381,18 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n", runtime->rate);
- if (!test_bit(DMA_TX_READY, &chip->flags)) - retval = atmel_ac97c_prepare_dma(chip, substream, - DMA_TO_DEVICE); + if (cpu_is_at32ap7000()) { + if (!test_bit(DMA_TX_READY, &chip->flags)) + retval = atmel_ac97c_prepare_dma(chip, substream, + DMA_TO_DEVICE); + } else { + /* Initialize and start the PDC */ + writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR); + writel(block_size / 2, chip->regs + ATMEL_PDC_TCR); + writel(runtime->dma_addr + block_size, + chip->regs + ATMEL_PDC_TNPR); + writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR); + }
return retval; } @@ -374,9 +401,11 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; + int block_size = frames_to_bytes(runtime, runtime->period_size); unsigned long word = ac97c_readl(chip, ICA); int retval;
+ chip->period = 0; word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
/* assign channels to AC97C channel A */ @@ -415,11 +444,15 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) word |= AC97C_CSR_OVRUN;
ac97c_writel(chip, CAMR, word); - /* Enable channel A event interrupt */ word = ac97c_readl(chip, IMR); word |= AC97C_SR_CAEVT; - ac97c_writel(chip, IER, word); + ac97c_writel(chip, IER, /*word*/AC97C_SR_CAEVT); + + /* Enable channel A event interrupt */ + /*word = ac97c_readl(chip, IMR); + word |= AC97C_SR_CAEVT; + ac97c_writel(chip, IER, word);*/
/* set variable rate if needed */ if (runtime->rate != 48000) { @@ -438,9 +471,18 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n", runtime->rate);
- if (!test_bit(DMA_RX_READY, &chip->flags)) - retval = atmel_ac97c_prepare_dma(chip, substream, - DMA_FROM_DEVICE); + if (cpu_is_at32ap7000()) { + if (!test_bit(DMA_RX_READY, &chip->flags)) + retval = atmel_ac97c_prepare_dma(chip, substream, + DMA_FROM_DEVICE); + } else { + /* Initialize and start the PDC */ + writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR); + writel(block_size / 2, chip->regs + ATMEL_PDC_RCR); + writel(runtime->dma_addr + block_size, + chip->regs + ATMEL_PDC_RNPR); + writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR); + }
return retval; } @@ -449,7 +491,7 @@ static int atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); - unsigned long camr; + unsigned long camr, ptcr = 0; int retval = 0;
camr = ac97c_readl(chip, CAMR); @@ -458,15 +500,22 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ case SNDRV_PCM_TRIGGER_START: - retval = dw_dma_cyclic_start(chip->dma.tx_chan); - if (retval) - goto out; - camr |= AC97C_CMR_CENA; + if (cpu_is_at32ap7000()) { + retval = dw_dma_cyclic_start(chip->dma.tx_chan); + if (retval) + goto out; + } else { + ptcr = ATMEL_PDC_TXTEN; + } + camr |= AC97C_CMR_CENA | AC97C_CSR_ENDTX; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ case SNDRV_PCM_TRIGGER_STOP: - dw_dma_cyclic_stop(chip->dma.tx_chan); + if (cpu_is_at32ap7000()) + dw_dma_cyclic_stop(chip->dma.tx_chan); + else + ptcr = ATMEL_PDC_TXTDIS; if (chip->opened <= 1) camr &= ~AC97C_CMR_CENA; break; @@ -476,6 +525,8 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) }
ac97c_writel(chip, CAMR, camr); + if (!cpu_is_at32ap7000()) + writel(ptcr, chip->regs + ATMEL_PDC_PTCR); out: return retval; } @@ -484,7 +535,7 @@ static int atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); - unsigned long camr; + unsigned long camr, ptcr = 0; int retval = 0;
camr = ac97c_readl(chip, CAMR); @@ -493,15 +544,21 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ case SNDRV_PCM_TRIGGER_START: - retval = dw_dma_cyclic_start(chip->dma.rx_chan); - if (retval) - goto out; + if (cpu_is_at32ap7000()) + retval = dw_dma_cyclic_start(chip->dma.rx_chan); + if (retval) + goto out; + else + ptcr = ATMEL_PDC_RXTEN; camr |= AC97C_CMR_CENA; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ case SNDRV_PCM_TRIGGER_STOP: - dw_dma_cyclic_stop(chip->dma.rx_chan); + if (cpu_is_at32ap7000()) + dw_dma_cyclic_stop(chip->dma.rx_chan); + else + ptcr = ATMEL_PDC_RXTDIS; if (chip->opened <= 1) camr &= ~AC97C_CMR_CENA; break; @@ -511,6 +568,8 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) }
ac97c_writel(chip, CAMR, camr); + if (!cpu_is_at32ap7000()) + writel(ptcr, chip->regs + ATMEL_PDC_PTCR); out: return retval; } @@ -523,7 +582,10 @@ atmel_ac97c_playback_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t frames; unsigned long bytes;
- bytes = dw_dma_get_src_addr(chip->dma.tx_chan); + if (cpu_is_at32ap7000()) + bytes = dw_dma_get_src_addr(chip->dma.tx_chan); + else + bytes = readl(chip->regs + ATMEL_PDC_TPR); bytes -= runtime->dma_addr;
frames = bytes_to_frames(runtime, bytes); @@ -540,7 +602,10 @@ atmel_ac97c_capture_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t frames; unsigned long bytes;
- bytes = dw_dma_get_dst_addr(chip->dma.rx_chan); + if (cpu_is_at32ap7000()) + bytes = dw_dma_get_dst_addr(chip->dma.rx_chan); + else + bytes = readl(chip->regs + ATMEL_PDC_RPR); bytes -= runtime->dma_addr;
frames = bytes_to_frames(runtime, bytes); @@ -578,20 +643,67 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) u32 sr = ac97c_readl(chip, SR); u32 casr = ac97c_readl(chip, CASR); u32 cosr = ac97c_readl(chip, COSR); + u32 camr = ac97c_readl(chip, CAMR);
if (sr & AC97C_SR_CAEVT) { - dev_info(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n", + struct snd_pcm_runtime *runtime; + int offset, next_period, block_size; + dev_dbg(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n", casr & AC97C_CSR_OVRUN ? " OVRUN" : "", casr & AC97C_CSR_RXRDY ? " RXRDY" : "", casr & AC97C_CSR_UNRUN ? " UNRUN" : "", casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "", casr & AC97C_CSR_TXRDY ? " TXRDY" : "", !casr ? " NONE" : ""); + if (!cpu_is_at32ap7000()) { + if ((casr & camr) & AC97C_CSR_ENDTX) { + runtime = chip->playback_substream->runtime; + block_size = frames_to_bytes(runtime, + runtime->period_size); + chip->period++; + + if (chip->period == runtime->periods) + chip->period = 0; + next_period = chip->period + 1; + if (next_period == runtime->periods) + next_period = 0; + + offset = block_size * next_period; + + writel(runtime->dma_addr + offset, + chip->regs + ATMEL_PDC_TNPR); + writel(block_size / 2, + chip->regs + ATMEL_PDC_TNCR); + + snd_pcm_period_elapsed( + chip->playback_substream); + } + if ((casr & camr) & AC97C_CSR_ENDRX) { + runtime = chip->capture_substream->runtime; + block_size = frames_to_bytes(runtime, + runtime->period_size); + chip->period++; + + if (chip->period == runtime->periods) + chip->period = 0; + next_period = chip->period + 1; + if (next_period == runtime->periods) + next_period = 0; + + offset = block_size * next_period; + + writel(runtime->dma_addr + offset, + chip->regs + ATMEL_PDC_RNPR); + writel(block_size / 2, + chip->regs + ATMEL_PDC_RNCR); + snd_pcm_period_elapsed(chip->capture_substream); + } + } retval = IRQ_HANDLED; }
if (sr & AC97C_SR_COEVT) { - dev_info(&chip->pdev->dev, "codec channel event%s%s%s%s%s\n", + dev_dbg(&chip->pdev->dev, "codec channel event%s%s%s%s%s\n", cosr & AC97C_CSR_OVRUN ? " OVRUN" : "", cosr & AC97C_CSR_RXRDY ? " RXRDY" : "", cosr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "", @@ -608,15 +720,50 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) return retval; }
+static struct ac97_pcm at91_ac97_pcm_defs[] __devinitdata = { + /* Playback */ + { + .exclusive = 1, + .r = { { + .slots = ((1 << AC97_SLOT_PCM_LEFT) + | (1 << AC97_SLOT_PCM_RIGHT)), + } }, + }, + /* PCM in */ + { + .stream = 1, + .exclusive = 1, + .r = { { + .slots = ((1 << AC97_SLOT_PCM_LEFT) + | (1 << AC97_SLOT_PCM_RIGHT)), + } } + }, + /* Mic in */ + { + .stream = 1, + .exclusive = 1, + .r = { { + .slots = (1<<AC97_SLOT_MIC), + } } + }, +}; + static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip) { struct snd_pcm *pcm; struct snd_pcm_hardware hw = atmel_ac97c_hw; - int capture, playback, retval; + int capture, playback, retval, err;
capture = test_bit(DMA_RX_CHAN_PRESENT, &chip->flags); playback = test_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
+ if (!cpu_is_at32ap7000()) { + err = snd_ac97_pcm_assign(chip->ac97_bus, + ARRAY_SIZE(at91_ac97_pcm_defs), + at91_ac97_pcm_defs); + if (err) + return err; + } retval = snd_pcm_new(chip->card, chip->card->shortname, chip->pdev->id, playback, capture, &pcm); if (retval) @@ -775,7 +922,12 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) return -ENXIO; }
- pclk = clk_get(&pdev->dev, "pclk"); + if (cpu_is_at32ap7000()) { + pclk = clk_get(&pdev->dev, "pclk"); + } else { + pclk = clk_get(&pdev->dev, "ac97_clk"); + } + if (IS_ERR(pclk)) { dev_dbg(&pdev->dev, "no peripheral clock\n"); return PTR_ERR(pclk); @@ -844,43 +996,52 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) goto err_ac97_bus; }
- if (pdata->rx_dws.dma_dev) { - struct dw_dma_slave *dws = &pdata->rx_dws; - dma_cap_mask_t mask; + if (cpu_is_at32ap7000()) { + if (pdata->rx_dws.dma_dev) { + struct dw_dma_slave *dws = &pdata->rx_dws; + dma_cap_mask_t mask;
- dws->rx_reg = regs->start + AC97C_CARHR + 2; + dws->rx_reg = regs->start + AC97C_CARHR + 2;
- dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask);
- chip->dma.rx_chan = dma_request_channel(mask, filter, dws); + chip->dma.rx_chan = dma_request_channel(mask, filter, + dws);
- dev_info(&chip->pdev->dev, "using %s for DMA RX\n", + dev_info(&chip->pdev->dev, "using %s for DMA RX\n", dev_name(&chip->dma.rx_chan->dev->device)); - set_bit(DMA_RX_CHAN_PRESENT, &chip->flags); - } + set_bit(DMA_RX_CHAN_PRESENT, &chip->flags); + }
- if (pdata->tx_dws.dma_dev) { - struct dw_dma_slave *dws = &pdata->tx_dws; - dma_cap_mask_t mask; + if (pdata->tx_dws.dma_dev) { + struct dw_dma_slave *dws = &pdata->tx_dws; + dma_cap_mask_t mask;
- dws->tx_reg = regs->start + AC97C_CATHR + 2; + dws->tx_reg = regs->start + AC97C_CATHR + 2;
- dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask);
- chip->dma.tx_chan = dma_request_channel(mask, filter, dws); + chip->dma.tx_chan = dma_request_channel(mask, filter, + dws);
- dev_info(&chip->pdev->dev, "using %s for DMA TX\n", + dev_info(&chip->pdev->dev, "using %s for DMA TX\n", dev_name(&chip->dma.tx_chan->dev->device)); - set_bit(DMA_TX_CHAN_PRESENT, &chip->flags); - } + set_bit(DMA_TX_CHAN_PRESENT, &chip->flags); + }
- if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) && - !test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) { - dev_dbg(&pdev->dev, "DMA not available\n"); - retval = -ENODEV; - goto err_dma; + if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) && + !test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) { + dev_dbg(&pdev->dev, "DMA not available\n"); + retval = -ENODEV; + goto err_dma; + } + } else { + /* Just pretend that we have DMA channel(for at91 i is actually + * the PDC */ + set_bit(DMA_RX_CHAN_PRESENT, &chip->flags); + set_bit(DMA_TX_CHAN_PRESENT, &chip->flags); }
retval = atmel_ac97c_pcm_new(chip); @@ -897,20 +1058,22 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, card);
- dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p\n", - chip->regs); + dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p, irq = %d\n", + chip->regs, irq);
return 0;
err_dma: - if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) - dma_release_channel(chip->dma.rx_chan); - if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) - dma_release_channel(chip->dma.tx_chan); - clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags); - clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags); - chip->dma.rx_chan = NULL; - chip->dma.tx_chan = NULL; + if (cpu_is_at32ap7000()) { + if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) + dma_release_channel(chip->dma.rx_chan); + if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) + dma_release_channel(chip->dma.tx_chan); + clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags); + clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags); + chip->dma.rx_chan = NULL; + chip->dma.tx_chan = NULL; + } err_ac97_bus: snd_card_set_dev(card, NULL);
@@ -934,12 +1097,13 @@ static int atmel_ac97c_suspend(struct platform_device *pdev, pm_message_t msg) struct snd_card *card = platform_get_drvdata(pdev); struct atmel_ac97c *chip = card->private_data;
- if (test_bit(DMA_RX_READY, &chip->flags)) - dw_dma_cyclic_stop(chip->dma.rx_chan); - if (test_bit(DMA_TX_READY, &chip->flags)) - dw_dma_cyclic_stop(chip->dma.tx_chan); + if (cpu_is_at32ap7000()) { + if (test_bit(DMA_RX_READY, &chip->flags)) + dw_dma_cyclic_stop(chip->dma.rx_chan); + if (test_bit(DMA_TX_READY, &chip->flags)) + dw_dma_cyclic_stop(chip->dma.tx_chan); + } clk_disable(chip->pclk); - return 0; }
@@ -949,11 +1113,12 @@ static int atmel_ac97c_resume(struct platform_device *pdev) struct atmel_ac97c *chip = card->private_data;
clk_enable(chip->pclk); - if (test_bit(DMA_RX_READY, &chip->flags)) - dw_dma_cyclic_start(chip->dma.rx_chan); - if (test_bit(DMA_TX_READY, &chip->flags)) - dw_dma_cyclic_start(chip->dma.tx_chan); - + if (cpu_is_at32ap7000()) { + if (test_bit(DMA_RX_READY, &chip->flags)) + dw_dma_cyclic_start(chip->dma.rx_chan); + if (test_bit(DMA_TX_READY, &chip->flags)) + dw_dma_cyclic_start(chip->dma.tx_chan); + } return 0; } #else @@ -978,14 +1143,16 @@ static int __devexit atmel_ac97c_remove(struct platform_device *pdev) iounmap(chip->regs); free_irq(chip->irq, chip);
- if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) - dma_release_channel(chip->dma.rx_chan); - if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) - dma_release_channel(chip->dma.tx_chan); - clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags); - clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags); - chip->dma.rx_chan = NULL; - chip->dma.tx_chan = NULL; + if (cpu_is_at32ap7000()) { + if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) + dma_release_channel(chip->dma.rx_chan); + if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) + dma_release_channel(chip->dma.tx_chan); + clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags); + clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags); + chip->dma.rx_chan = NULL; + chip->dma.tx_chan = NULL; + }
snd_card_set_dev(card, NULL); snd_card_free(card);
At Fri, 10 Jul 2009 14:37:41 +0200, Sedji Gaouaou wrote:
@@ -493,15 +544,21 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ case SNDRV_PCM_TRIGGER_START:
retval = dw_dma_cyclic_start(chip->dma.rx_chan);
if (retval)
goto out;
if (cpu_is_at32ap7000())
Missing brace?
retval = dw_dma_cyclic_start(chip->dma.rx_chan);
if (retval)
goto out;
else
ptcr = ATMEL_PDC_RXTEN;
Takashi
This patch add AC97 support for ATMEL AT91 boards, using the AVR32 code. It is based on Takashi git tree(sound-2.6/for-next).
Regards, Sedji
Signed-off-by: Sedji Gaouaou sedji.gaouaou@atmel.com --- sound/atmel/Kconfig | 2 +- sound/atmel/ac97c.c | 354 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 262 insertions(+), 94 deletions(-)
diff --git a/sound/atmel/Kconfig b/sound/atmel/Kconfig index 6c228a9..94de43a 100644 --- a/sound/atmel/Kconfig +++ b/sound/atmel/Kconfig @@ -12,7 +12,7 @@ config SND_ATMEL_AC97C tristate "Atmel AC97 Controller (AC97C) driver" select SND_PCM select SND_AC97_CODEC - depends on DW_DMAC && AVR32 + depends on (DW_DMAC && AVR32) || ARCH_AT91 help ALSA sound driver for the Atmel AC97 controller.
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 0c0f877..54d1365 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -13,6 +13,7 @@ #include <linux/device.h> #include <linux/dmaengine.h> #include <linux/dma-mapping.h> +#include <linux/atmel_pdc.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/module.h> @@ -31,6 +32,10 @@
#include <linux/dw_dmac.h>
+#include <mach/cpu.h> +#include <mach/hardware.h> +#include <mach/gpio.h> + #include "ac97c.h"
enum { @@ -63,6 +68,7 @@ struct atmel_ac97c { u64 cur_format; unsigned int cur_rate; unsigned long flags; + int period; /* Serialize access to opened variable */ spinlock_t lock; void __iomem *regs; @@ -241,10 +247,13 @@ static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream, params_buffer_bytes(hw_params)); if (retval < 0) return retval; - /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ - if (retval == 1) - if (test_and_clear_bit(DMA_TX_READY, &chip->flags)) - dw_dma_cyclic_free(chip->dma.tx_chan); + + if (cpu_is_at32ap7000()) { + /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ + if (retval == 1) + if (test_and_clear_bit(DMA_TX_READY, &chip->flags)) + dw_dma_cyclic_free(chip->dma.tx_chan); + }
/* Set restrictions to params. */ mutex_lock(&opened_mutex); @@ -263,12 +272,14 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
retval = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); - if (retval < 0) - return retval; - /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ - if (retval == 1) - if (test_and_clear_bit(DMA_RX_READY, &chip->flags)) - dw_dma_cyclic_free(chip->dma.rx_chan); + if (cpu_is_at32ap7000()) { + if (retval < 0) + return retval; + /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ + if (retval == 1) + if (test_and_clear_bit(DMA_RX_READY, &chip->flags)) + dw_dma_cyclic_free(chip->dma.rx_chan); + }
/* Set restrictions to params. */ mutex_lock(&opened_mutex); @@ -282,16 +293,20 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream, static int atmel_ac97c_playback_hw_free(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); - if (test_and_clear_bit(DMA_TX_READY, &chip->flags)) - dw_dma_cyclic_free(chip->dma.tx_chan); + if (cpu_is_at32ap7000()) { + if (test_and_clear_bit(DMA_TX_READY, &chip->flags)) + dw_dma_cyclic_free(chip->dma.tx_chan); + } return snd_pcm_lib_free_pages(substream); }
static int atmel_ac97c_capture_hw_free(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); - if (test_and_clear_bit(DMA_RX_READY, &chip->flags)) - dw_dma_cyclic_free(chip->dma.rx_chan); + if (cpu_is_at32ap7000()) { + if (test_and_clear_bit(DMA_RX_READY, &chip->flags)) + dw_dma_cyclic_free(chip->dma.rx_chan); + } return snd_pcm_lib_free_pages(substream); }
@@ -299,9 +314,11 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; + int block_size = frames_to_bytes(runtime, runtime->period_size); unsigned long word = ac97c_readl(chip, OCA); int retval;
+ chip->period = 0; word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
/* assign channels to AC97C channel A */ @@ -324,7 +341,8 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
switch (runtime->format) { case SNDRV_PCM_FORMAT_S16_LE: - word |= AC97C_CMR_CEM_LITTLE; + if (cpu_is_at32ap7000()) + word |= AC97C_CMR_CEM_LITTLE; break; case SNDRV_PCM_FORMAT_S16_BE: /* fall through */ word &= ~(AC97C_CMR_CEM_LITTLE); @@ -363,9 +381,18 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n", runtime->rate);
- if (!test_bit(DMA_TX_READY, &chip->flags)) - retval = atmel_ac97c_prepare_dma(chip, substream, - DMA_TO_DEVICE); + if (cpu_is_at32ap7000()) { + if (!test_bit(DMA_TX_READY, &chip->flags)) + retval = atmel_ac97c_prepare_dma(chip, substream, + DMA_TO_DEVICE); + } else { + /* Initialize and start the PDC */ + writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR); + writel(block_size / 2, chip->regs + ATMEL_PDC_TCR); + writel(runtime->dma_addr + block_size, + chip->regs + ATMEL_PDC_TNPR); + writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR); + }
return retval; } @@ -374,9 +401,11 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; + int block_size = frames_to_bytes(runtime, runtime->period_size); unsigned long word = ac97c_readl(chip, ICA); int retval;
+ chip->period = 0; word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
/* assign channels to AC97C channel A */ @@ -415,11 +444,15 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) word |= AC97C_CSR_OVRUN;
ac97c_writel(chip, CAMR, word); - /* Enable channel A event interrupt */ word = ac97c_readl(chip, IMR); word |= AC97C_SR_CAEVT; - ac97c_writel(chip, IER, word); + ac97c_writel(chip, IER, /*word*/AC97C_SR_CAEVT); + + /* Enable channel A event interrupt */ + /*word = ac97c_readl(chip, IMR); + word |= AC97C_SR_CAEVT; + ac97c_writel(chip, IER, word);*/
/* set variable rate if needed */ if (runtime->rate != 48000) { @@ -438,9 +471,18 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n", runtime->rate);
- if (!test_bit(DMA_RX_READY, &chip->flags)) - retval = atmel_ac97c_prepare_dma(chip, substream, - DMA_FROM_DEVICE); + if (cpu_is_at32ap7000()) { + if (!test_bit(DMA_RX_READY, &chip->flags)) + retval = atmel_ac97c_prepare_dma(chip, substream, + DMA_FROM_DEVICE); + } else { + /* Initialize and start the PDC */ + writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR); + writel(block_size / 2, chip->regs + ATMEL_PDC_RCR); + writel(runtime->dma_addr + block_size, + chip->regs + ATMEL_PDC_RNPR); + writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR); + }
return retval; } @@ -449,7 +491,7 @@ static int atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); - unsigned long camr; + unsigned long camr, ptcr = 0; int retval = 0;
camr = ac97c_readl(chip, CAMR); @@ -458,15 +500,22 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ case SNDRV_PCM_TRIGGER_START: - retval = dw_dma_cyclic_start(chip->dma.tx_chan); - if (retval) - goto out; - camr |= AC97C_CMR_CENA; + if (cpu_is_at32ap7000()) { + retval = dw_dma_cyclic_start(chip->dma.tx_chan); + if (retval) + goto out; + } else { + ptcr = ATMEL_PDC_TXTEN; + } + camr |= AC97C_CMR_CENA | AC97C_CSR_ENDTX; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ case SNDRV_PCM_TRIGGER_STOP: - dw_dma_cyclic_stop(chip->dma.tx_chan); + if (cpu_is_at32ap7000()) + dw_dma_cyclic_stop(chip->dma.tx_chan); + else + ptcr = ATMEL_PDC_TXTDIS; if (chip->opened <= 1) camr &= ~AC97C_CMR_CENA; break; @@ -476,6 +525,8 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) }
ac97c_writel(chip, CAMR, camr); + if (!cpu_is_at32ap7000()) + writel(ptcr, chip->regs + ATMEL_PDC_PTCR); out: return retval; } @@ -484,7 +535,7 @@ static int atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); - unsigned long camr; + unsigned long camr, ptcr = 0; int retval = 0;
camr = ac97c_readl(chip, CAMR); @@ -493,15 +544,22 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ case SNDRV_PCM_TRIGGER_START: - retval = dw_dma_cyclic_start(chip->dma.rx_chan); - if (retval) - goto out; + if (cpu_is_at32ap7000()) { + retval = dw_dma_cyclic_start(chip->dma.rx_chan); + if (retval) + goto out; + } else { + ptcr = ATMEL_PDC_RXTEN; + } camr |= AC97C_CMR_CENA; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ case SNDRV_PCM_TRIGGER_STOP: - dw_dma_cyclic_stop(chip->dma.rx_chan); + if (cpu_is_at32ap7000()) + dw_dma_cyclic_stop(chip->dma.rx_chan); + else + ptcr = ATMEL_PDC_RXTDIS; if (chip->opened <= 1) camr &= ~AC97C_CMR_CENA; break; @@ -511,6 +569,8 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) }
ac97c_writel(chip, CAMR, camr); + if (!cpu_is_at32ap7000()) + writel(ptcr, chip->regs + ATMEL_PDC_PTCR); out: return retval; } @@ -523,7 +583,10 @@ atmel_ac97c_playback_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t frames; unsigned long bytes;
- bytes = dw_dma_get_src_addr(chip->dma.tx_chan); + if (cpu_is_at32ap7000()) + bytes = dw_dma_get_src_addr(chip->dma.tx_chan); + else + bytes = readl(chip->regs + ATMEL_PDC_TPR); bytes -= runtime->dma_addr;
frames = bytes_to_frames(runtime, bytes); @@ -540,7 +603,10 @@ atmel_ac97c_capture_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t frames; unsigned long bytes;
- bytes = dw_dma_get_dst_addr(chip->dma.rx_chan); + if (cpu_is_at32ap7000()) + bytes = dw_dma_get_dst_addr(chip->dma.rx_chan); + else + bytes = readl(chip->regs + ATMEL_PDC_RPR); bytes -= runtime->dma_addr;
frames = bytes_to_frames(runtime, bytes); @@ -578,20 +644,67 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) u32 sr = ac97c_readl(chip, SR); u32 casr = ac97c_readl(chip, CASR); u32 cosr = ac97c_readl(chip, COSR); + u32 camr = ac97c_readl(chip, CAMR);
if (sr & AC97C_SR_CAEVT) { - dev_info(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n", + struct snd_pcm_runtime *runtime; + int offset, next_period, block_size; + dev_dbg(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n", casr & AC97C_CSR_OVRUN ? " OVRUN" : "", casr & AC97C_CSR_RXRDY ? " RXRDY" : "", casr & AC97C_CSR_UNRUN ? " UNRUN" : "", casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "", casr & AC97C_CSR_TXRDY ? " TXRDY" : "", !casr ? " NONE" : ""); + if (!cpu_is_at32ap7000()) { + if ((casr & camr) & AC97C_CSR_ENDTX) { + runtime = chip->playback_substream->runtime; + block_size = frames_to_bytes(runtime, + runtime->period_size); + chip->period++; + + if (chip->period == runtime->periods) + chip->period = 0; + next_period = chip->period + 1; + if (next_period == runtime->periods) + next_period = 0; + + offset = block_size * next_period; + + writel(runtime->dma_addr + offset, + chip->regs + ATMEL_PDC_TNPR); + writel(block_size / 2, + chip->regs + ATMEL_PDC_TNCR); + + snd_pcm_period_elapsed( + chip->playback_substream); + } + if ((casr & camr) & AC97C_CSR_ENDRX) { + runtime = chip->capture_substream->runtime; + block_size = frames_to_bytes(runtime, + runtime->period_size); + chip->period++; + + if (chip->period == runtime->periods) + chip->period = 0; + next_period = chip->period + 1; + if (next_period == runtime->periods) + next_period = 0; + + offset = block_size * next_period; + + writel(runtime->dma_addr + offset, + chip->regs + ATMEL_PDC_RNPR); + writel(block_size / 2, + chip->regs + ATMEL_PDC_RNCR); + snd_pcm_period_elapsed(chip->capture_substream); + } + } retval = IRQ_HANDLED; }
if (sr & AC97C_SR_COEVT) { - dev_info(&chip->pdev->dev, "codec channel event%s%s%s%s%s\n", + dev_dbg(&chip->pdev->dev, "codec channel event%s%s%s%s%s\n", cosr & AC97C_CSR_OVRUN ? " OVRUN" : "", cosr & AC97C_CSR_RXRDY ? " RXRDY" : "", cosr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "", @@ -608,15 +721,50 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) return retval; }
+static struct ac97_pcm at91_ac97_pcm_defs[] __devinitdata = { + /* Playback */ + { + .exclusive = 1, + .r = { { + .slots = ((1 << AC97_SLOT_PCM_LEFT) + | (1 << AC97_SLOT_PCM_RIGHT)), + } }, + }, + /* PCM in */ + { + .stream = 1, + .exclusive = 1, + .r = { { + .slots = ((1 << AC97_SLOT_PCM_LEFT) + | (1 << AC97_SLOT_PCM_RIGHT)), + } } + }, + /* Mic in */ + { + .stream = 1, + .exclusive = 1, + .r = { { + .slots = (1<<AC97_SLOT_MIC), + } } + }, +}; + static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip) { struct snd_pcm *pcm; struct snd_pcm_hardware hw = atmel_ac97c_hw; - int capture, playback, retval; + int capture, playback, retval, err;
capture = test_bit(DMA_RX_CHAN_PRESENT, &chip->flags); playback = test_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
+ if (!cpu_is_at32ap7000()) { + err = snd_ac97_pcm_assign(chip->ac97_bus, + ARRAY_SIZE(at91_ac97_pcm_defs), + at91_ac97_pcm_defs); + if (err) + return err; + } retval = snd_pcm_new(chip->card, chip->card->shortname, chip->pdev->id, playback, capture, &pcm); if (retval) @@ -775,7 +923,12 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) return -ENXIO; }
- pclk = clk_get(&pdev->dev, "pclk"); + if (cpu_is_at32ap7000()) { + pclk = clk_get(&pdev->dev, "pclk"); + } else { + pclk = clk_get(&pdev->dev, "ac97_clk"); + } + if (IS_ERR(pclk)) { dev_dbg(&pdev->dev, "no peripheral clock\n"); return PTR_ERR(pclk); @@ -844,43 +997,52 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) goto err_ac97_bus; }
- if (pdata->rx_dws.dma_dev) { - struct dw_dma_slave *dws = &pdata->rx_dws; - dma_cap_mask_t mask; + if (cpu_is_at32ap7000()) { + if (pdata->rx_dws.dma_dev) { + struct dw_dma_slave *dws = &pdata->rx_dws; + dma_cap_mask_t mask;
- dws->rx_reg = regs->start + AC97C_CARHR + 2; + dws->rx_reg = regs->start + AC97C_CARHR + 2;
- dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask);
- chip->dma.rx_chan = dma_request_channel(mask, filter, dws); + chip->dma.rx_chan = dma_request_channel(mask, filter, + dws);
- dev_info(&chip->pdev->dev, "using %s for DMA RX\n", + dev_info(&chip->pdev->dev, "using %s for DMA RX\n", dev_name(&chip->dma.rx_chan->dev->device)); - set_bit(DMA_RX_CHAN_PRESENT, &chip->flags); - } + set_bit(DMA_RX_CHAN_PRESENT, &chip->flags); + }
- if (pdata->tx_dws.dma_dev) { - struct dw_dma_slave *dws = &pdata->tx_dws; - dma_cap_mask_t mask; + if (pdata->tx_dws.dma_dev) { + struct dw_dma_slave *dws = &pdata->tx_dws; + dma_cap_mask_t mask;
- dws->tx_reg = regs->start + AC97C_CATHR + 2; + dws->tx_reg = regs->start + AC97C_CATHR + 2;
- dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask);
- chip->dma.tx_chan = dma_request_channel(mask, filter, dws); + chip->dma.tx_chan = dma_request_channel(mask, filter, + dws);
- dev_info(&chip->pdev->dev, "using %s for DMA TX\n", + dev_info(&chip->pdev->dev, "using %s for DMA TX\n", dev_name(&chip->dma.tx_chan->dev->device)); - set_bit(DMA_TX_CHAN_PRESENT, &chip->flags); - } + set_bit(DMA_TX_CHAN_PRESENT, &chip->flags); + }
- if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) && - !test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) { - dev_dbg(&pdev->dev, "DMA not available\n"); - retval = -ENODEV; - goto err_dma; + if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) && + !test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) { + dev_dbg(&pdev->dev, "DMA not available\n"); + retval = -ENODEV; + goto err_dma; + } + } else { + /* Just pretend that we have DMA channel(for at91 i is actually + * the PDC */ + set_bit(DMA_RX_CHAN_PRESENT, &chip->flags); + set_bit(DMA_TX_CHAN_PRESENT, &chip->flags); }
retval = atmel_ac97c_pcm_new(chip); @@ -897,20 +1059,22 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, card);
- dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p\n", - chip->regs); + dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p, irq = %d\n", + chip->regs, irq);
return 0;
err_dma: - if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) - dma_release_channel(chip->dma.rx_chan); - if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) - dma_release_channel(chip->dma.tx_chan); - clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags); - clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags); - chip->dma.rx_chan = NULL; - chip->dma.tx_chan = NULL; + if (cpu_is_at32ap7000()) { + if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) + dma_release_channel(chip->dma.rx_chan); + if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) + dma_release_channel(chip->dma.tx_chan); + clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags); + clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags); + chip->dma.rx_chan = NULL; + chip->dma.tx_chan = NULL; + } err_ac97_bus: snd_card_set_dev(card, NULL);
@@ -934,12 +1098,13 @@ static int atmel_ac97c_suspend(struct platform_device *pdev, pm_message_t msg) struct snd_card *card = platform_get_drvdata(pdev); struct atmel_ac97c *chip = card->private_data;
- if (test_bit(DMA_RX_READY, &chip->flags)) - dw_dma_cyclic_stop(chip->dma.rx_chan); - if (test_bit(DMA_TX_READY, &chip->flags)) - dw_dma_cyclic_stop(chip->dma.tx_chan); + if (cpu_is_at32ap7000()) { + if (test_bit(DMA_RX_READY, &chip->flags)) + dw_dma_cyclic_stop(chip->dma.rx_chan); + if (test_bit(DMA_TX_READY, &chip->flags)) + dw_dma_cyclic_stop(chip->dma.tx_chan); + } clk_disable(chip->pclk); - return 0; }
@@ -949,11 +1114,12 @@ static int atmel_ac97c_resume(struct platform_device *pdev) struct atmel_ac97c *chip = card->private_data;
clk_enable(chip->pclk); - if (test_bit(DMA_RX_READY, &chip->flags)) - dw_dma_cyclic_start(chip->dma.rx_chan); - if (test_bit(DMA_TX_READY, &chip->flags)) - dw_dma_cyclic_start(chip->dma.tx_chan); - + if (cpu_is_at32ap7000()) { + if (test_bit(DMA_RX_READY, &chip->flags)) + dw_dma_cyclic_start(chip->dma.rx_chan); + if (test_bit(DMA_TX_READY, &chip->flags)) + dw_dma_cyclic_start(chip->dma.tx_chan); + } return 0; } #else @@ -978,14 +1144,16 @@ static int __devexit atmel_ac97c_remove(struct platform_device *pdev) iounmap(chip->regs); free_irq(chip->irq, chip);
- if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) - dma_release_channel(chip->dma.rx_chan); - if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) - dma_release_channel(chip->dma.tx_chan); - clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags); - clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags); - chip->dma.rx_chan = NULL; - chip->dma.tx_chan = NULL; + if (cpu_is_at32ap7000()) { + if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) + dma_release_channel(chip->dma.rx_chan); + if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) + dma_release_channel(chip->dma.tx_chan); + clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags); + clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags); + chip->dma.rx_chan = NULL; + chip->dma.tx_chan = NULL; + }
snd_card_set_dev(card, NULL); snd_card_free(card);
Hi,
I was wondering what is the status of this patch?
Regards, Sedji
Sedji Gaouaou a écrit :
This patch add AC97 support for ATMEL AT91 boards, using the AVR32 code. It is based on Takashi git tree(sound-2.6/for-next).
Regards, Sedji
Signed-off-by: Sedji Gaouaou sedji.gaouaou@atmel.com
sound/atmel/Kconfig | 2 +- sound/atmel/ac97c.c | 354 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 262 insertions(+), 94 deletions(-)
diff --git a/sound/atmel/Kconfig b/sound/atmel/Kconfig index 6c228a9..94de43a 100644 --- a/sound/atmel/Kconfig +++ b/sound/atmel/Kconfig @@ -12,7 +12,7 @@ config SND_ATMEL_AC97C tristate "Atmel AC97 Controller (AC97C) driver" select SND_PCM select SND_AC97_CODEC
- depends on DW_DMAC && AVR32
- depends on (DW_DMAC && AVR32) || ARCH_AT91 help ALSA sound driver for the Atmel AC97 controller.
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 0c0f877..54d1365 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -13,6 +13,7 @@ #include <linux/device.h> #include <linux/dmaengine.h> #include <linux/dma-mapping.h> +#include <linux/atmel_pdc.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/module.h> @@ -31,6 +32,10 @@
#include <linux/dw_dmac.h>
+#include <mach/cpu.h> +#include <mach/hardware.h> +#include <mach/gpio.h>
#include "ac97c.h"
enum { @@ -63,6 +68,7 @@ struct atmel_ac97c { u64 cur_format; unsigned int cur_rate; unsigned long flags;
- int period; /* Serialize access to opened variable */ spinlock_t lock; void __iomem *regs;
@@ -241,10 +247,13 @@ static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream, params_buffer_bytes(hw_params)); if (retval < 0) return retval;
- /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
- if (retval == 1)
if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.tx_chan);
if (cpu_is_at32ap7000()) {
/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
if (retval == 1)
if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.tx_chan);
}
/* Set restrictions to params. */ mutex_lock(&opened_mutex);
@@ -263,12 +272,14 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
retval = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
- if (retval < 0)
return retval;
- /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
- if (retval == 1)
if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.rx_chan);
if (cpu_is_at32ap7000()) {
if (retval < 0)
return retval;
/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
if (retval == 1)
if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.rx_chan);
}
/* Set restrictions to params. */ mutex_lock(&opened_mutex);
@@ -282,16 +293,20 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream, static int atmel_ac97c_playback_hw_free(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
- if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.tx_chan);
- if (cpu_is_at32ap7000()) {
if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.tx_chan);
- } return snd_pcm_lib_free_pages(substream);
}
static int atmel_ac97c_capture_hw_free(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
- if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.rx_chan);
- if (cpu_is_at32ap7000()) {
if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.rx_chan);
- } return snd_pcm_lib_free_pages(substream);
}
@@ -299,9 +314,11 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime;
int block_size = frames_to_bytes(runtime, runtime->period_size); unsigned long word = ac97c_readl(chip, OCA); int retval;
chip->period = 0; word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
/* assign channels to AC97C channel A */
@@ -324,7 +341,8 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
switch (runtime->format) { case SNDRV_PCM_FORMAT_S16_LE:
word |= AC97C_CMR_CEM_LITTLE;
if (cpu_is_at32ap7000())
break; case SNDRV_PCM_FORMAT_S16_BE: /* fall through */ word &= ~(AC97C_CMR_CEM_LITTLE);word |= AC97C_CMR_CEM_LITTLE;
@@ -363,9 +381,18 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n", runtime->rate);
- if (!test_bit(DMA_TX_READY, &chip->flags))
retval = atmel_ac97c_prepare_dma(chip, substream,
DMA_TO_DEVICE);
if (cpu_is_at32ap7000()) {
if (!test_bit(DMA_TX_READY, &chip->flags))
retval = atmel_ac97c_prepare_dma(chip, substream,
DMA_TO_DEVICE);
} else {
/* Initialize and start the PDC */
writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR);
writel(block_size / 2, chip->regs + ATMEL_PDC_TCR);
writel(runtime->dma_addr + block_size,
chip->regs + ATMEL_PDC_TNPR);
writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR);
}
return retval;
} @@ -374,9 +401,11 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime;
int block_size = frames_to_bytes(runtime, runtime->period_size); unsigned long word = ac97c_readl(chip, ICA); int retval;
chip->period = 0; word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
/* assign channels to AC97C channel A */
@@ -415,11 +444,15 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) word |= AC97C_CSR_OVRUN;
ac97c_writel(chip, CAMR, word);
- /* Enable channel A event interrupt */ word = ac97c_readl(chip, IMR); word |= AC97C_SR_CAEVT;
- ac97c_writel(chip, IER, word);
ac97c_writel(chip, IER, /*word*/AC97C_SR_CAEVT);
/* Enable channel A event interrupt */
/*word = ac97c_readl(chip, IMR);
word |= AC97C_SR_CAEVT;
ac97c_writel(chip, IER, word);*/
/* set variable rate if needed */ if (runtime->rate != 48000) {
@@ -438,9 +471,18 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n", runtime->rate);
- if (!test_bit(DMA_RX_READY, &chip->flags))
retval = atmel_ac97c_prepare_dma(chip, substream,
DMA_FROM_DEVICE);
if (cpu_is_at32ap7000()) {
if (!test_bit(DMA_RX_READY, &chip->flags))
retval = atmel_ac97c_prepare_dma(chip, substream,
DMA_FROM_DEVICE);
} else {
/* Initialize and start the PDC */
writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR);
writel(block_size / 2, chip->regs + ATMEL_PDC_RCR);
writel(runtime->dma_addr + block_size,
chip->regs + ATMEL_PDC_RNPR);
writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR);
}
return retval;
} @@ -449,7 +491,7 @@ static int atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
- unsigned long camr;
unsigned long camr, ptcr = 0; int retval = 0;
camr = ac97c_readl(chip, CAMR);
@@ -458,15 +500,22 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ case SNDRV_PCM_TRIGGER_START:
retval = dw_dma_cyclic_start(chip->dma.tx_chan);
if (retval)
goto out;
camr |= AC97C_CMR_CENA;
if (cpu_is_at32ap7000()) {
retval = dw_dma_cyclic_start(chip->dma.tx_chan);
if (retval)
goto out;
} else {
ptcr = ATMEL_PDC_TXTEN;
}
break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ case SNDRV_PCM_TRIGGER_STOP:camr |= AC97C_CMR_CENA | AC97C_CSR_ENDTX;
dw_dma_cyclic_stop(chip->dma.tx_chan);
if (cpu_is_at32ap7000())
dw_dma_cyclic_stop(chip->dma.tx_chan);
else
if (chip->opened <= 1) camr &= ~AC97C_CMR_CENA; break;ptcr = ATMEL_PDC_TXTDIS;
@@ -476,6 +525,8 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) }
ac97c_writel(chip, CAMR, camr);
- if (!cpu_is_at32ap7000())
writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
out: return retval; } @@ -484,7 +535,7 @@ static int atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
- unsigned long camr;
unsigned long camr, ptcr = 0; int retval = 0;
camr = ac97c_readl(chip, CAMR);
@@ -493,15 +544,22 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ case SNDRV_PCM_TRIGGER_START:
retval = dw_dma_cyclic_start(chip->dma.rx_chan);
if (retval)
goto out;
if (cpu_is_at32ap7000()) {
retval = dw_dma_cyclic_start(chip->dma.rx_chan);
if (retval)
goto out;
} else {
ptcr = ATMEL_PDC_RXTEN;
camr |= AC97C_CMR_CENA; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ case SNDRV_PCM_TRIGGER_STOP:}
dw_dma_cyclic_stop(chip->dma.rx_chan);
if (cpu_is_at32ap7000())
dw_dma_cyclic_stop(chip->dma.rx_chan);
else
if (chip->opened <= 1) camr &= ~AC97C_CMR_CENA; break;ptcr = ATMEL_PDC_RXTDIS;
@@ -511,6 +569,8 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) }
ac97c_writel(chip, CAMR, camr);
- if (!cpu_is_at32ap7000())
writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
out: return retval; } @@ -523,7 +583,10 @@ atmel_ac97c_playback_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t frames; unsigned long bytes;
- bytes = dw_dma_get_src_addr(chip->dma.tx_chan);
if (cpu_is_at32ap7000())
bytes = dw_dma_get_src_addr(chip->dma.tx_chan);
else
bytes = readl(chip->regs + ATMEL_PDC_TPR);
bytes -= runtime->dma_addr;
frames = bytes_to_frames(runtime, bytes);
@@ -540,7 +603,10 @@ atmel_ac97c_capture_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t frames; unsigned long bytes;
- bytes = dw_dma_get_dst_addr(chip->dma.rx_chan);
if (cpu_is_at32ap7000())
bytes = dw_dma_get_dst_addr(chip->dma.rx_chan);
else
bytes = readl(chip->regs + ATMEL_PDC_RPR);
bytes -= runtime->dma_addr;
frames = bytes_to_frames(runtime, bytes);
@@ -578,20 +644,67 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) u32 sr = ac97c_readl(chip, SR); u32 casr = ac97c_readl(chip, CASR); u32 cosr = ac97c_readl(chip, COSR);
u32 camr = ac97c_readl(chip, CAMR);
if (sr & AC97C_SR_CAEVT) {
dev_info(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n",
struct snd_pcm_runtime *runtime;
int offset, next_period, block_size;
dev_dbg(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n", casr & AC97C_CSR_OVRUN ? " OVRUN" : "", casr & AC97C_CSR_RXRDY ? " RXRDY" : "", casr & AC97C_CSR_UNRUN ? " UNRUN" : "", casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "", casr & AC97C_CSR_TXRDY ? " TXRDY" : "", !casr ? " NONE" : "");
if (!cpu_is_at32ap7000()) {
if ((casr & camr) & AC97C_CSR_ENDTX) {
runtime = chip->playback_substream->runtime;
block_size = frames_to_bytes(runtime,
runtime->period_size);
chip->period++;
if (chip->period == runtime->periods)
chip->period = 0;
next_period = chip->period + 1;
if (next_period == runtime->periods)
next_period = 0;
offset = block_size * next_period;
writel(runtime->dma_addr + offset,
chip->regs + ATMEL_PDC_TNPR);
writel(block_size / 2,
chip->regs + ATMEL_PDC_TNCR);
snd_pcm_period_elapsed(
chip->playback_substream);
}
if ((casr & camr) & AC97C_CSR_ENDRX) {
runtime = chip->capture_substream->runtime;
block_size = frames_to_bytes(runtime,
runtime->period_size);
chip->period++;
if (chip->period == runtime->periods)
chip->period = 0;
next_period = chip->period + 1;
if (next_period == runtime->periods)
next_period = 0;
offset = block_size * next_period;
writel(runtime->dma_addr + offset,
chip->regs + ATMEL_PDC_RNPR);
writel(block_size / 2,
chip->regs + ATMEL_PDC_RNCR);
snd_pcm_period_elapsed(chip->capture_substream);
}
}
retval = IRQ_HANDLED; }
if (sr & AC97C_SR_COEVT) {
dev_info(&chip->pdev->dev, "codec channel event%s%s%s%s%s\n",
dev_dbg(&chip->pdev->dev, "codec channel event%s%s%s%s%s\n", cosr & AC97C_CSR_OVRUN ? " OVRUN" : "", cosr & AC97C_CSR_RXRDY ? " RXRDY" : "", cosr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
@@ -608,15 +721,50 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) return retval; }
+static struct ac97_pcm at91_ac97_pcm_defs[] __devinitdata = {
- /* Playback */
- {
.exclusive = 1,
.r = { {
.slots = ((1 << AC97_SLOT_PCM_LEFT)
| (1 << AC97_SLOT_PCM_RIGHT)),
} },
- },
- /* PCM in */
- {
.stream = 1,
.exclusive = 1,
.r = { {
.slots = ((1 << AC97_SLOT_PCM_LEFT)
| (1 << AC97_SLOT_PCM_RIGHT)),
} }
- },
- /* Mic in */
- {
.stream = 1,
.exclusive = 1,
.r = { {
.slots = (1<<AC97_SLOT_MIC),
} }
- },
+};
static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip) { struct snd_pcm *pcm; struct snd_pcm_hardware hw = atmel_ac97c_hw;
- int capture, playback, retval;
int capture, playback, retval, err;
capture = test_bit(DMA_RX_CHAN_PRESENT, &chip->flags); playback = test_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
if (!cpu_is_at32ap7000()) {
err = snd_ac97_pcm_assign(chip->ac97_bus,
ARRAY_SIZE(at91_ac97_pcm_defs),
at91_ac97_pcm_defs);
if (err)
return err;
} retval = snd_pcm_new(chip->card, chip->card->shortname, chip->pdev->id, playback, capture, &pcm); if (retval)
@@ -775,7 +923,12 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) return -ENXIO; }
- pclk = clk_get(&pdev->dev, "pclk");
- if (cpu_is_at32ap7000()) {
pclk = clk_get(&pdev->dev, "pclk");
- } else {
pclk = clk_get(&pdev->dev, "ac97_clk");
- }
- if (IS_ERR(pclk)) { dev_dbg(&pdev->dev, "no peripheral clock\n"); return PTR_ERR(pclk);
@@ -844,43 +997,52 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) goto err_ac97_bus; }
- if (pdata->rx_dws.dma_dev) {
struct dw_dma_slave *dws = &pdata->rx_dws;
dma_cap_mask_t mask;
- if (cpu_is_at32ap7000()) {
if (pdata->rx_dws.dma_dev) {
struct dw_dma_slave *dws = &pdata->rx_dws;
dma_cap_mask_t mask;
dws->rx_reg = regs->start + AC97C_CARHR + 2;
dws->rx_reg = regs->start + AC97C_CARHR + 2;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
chip->dma.rx_chan = dma_request_channel(mask, filter, dws);
chip->dma.rx_chan = dma_request_channel(mask, filter,
dws);
dev_info(&chip->pdev->dev, "using %s for DMA RX\n",
dev_info(&chip->pdev->dev, "using %s for DMA RX\n", dev_name(&chip->dma.rx_chan->dev->device));
set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
- }
set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
}
- if (pdata->tx_dws.dma_dev) {
struct dw_dma_slave *dws = &pdata->tx_dws;
dma_cap_mask_t mask;
if (pdata->tx_dws.dma_dev) {
struct dw_dma_slave *dws = &pdata->tx_dws;
dma_cap_mask_t mask;
dws->tx_reg = regs->start + AC97C_CATHR + 2;
dws->tx_reg = regs->start + AC97C_CATHR + 2;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
chip->dma.tx_chan = dma_request_channel(mask, filter, dws);
chip->dma.tx_chan = dma_request_channel(mask, filter,
dws);
dev_info(&chip->pdev->dev, "using %s for DMA TX\n",
dev_info(&chip->pdev->dev, "using %s for DMA TX\n", dev_name(&chip->dma.tx_chan->dev->device));
set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
- }
set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
}
- if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) &&
!test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) {
dev_dbg(&pdev->dev, "DMA not available\n");
retval = -ENODEV;
goto err_dma;
if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) &&
!test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) {
dev_dbg(&pdev->dev, "DMA not available\n");
retval = -ENODEV;
goto err_dma;
}
} else {
/* Just pretend that we have DMA channel(for at91 i is actually
* the PDC */
set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
}
retval = atmel_ac97c_pcm_new(chip);
@@ -897,20 +1059,22 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, card);
- dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p\n",
chip->regs);
dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p, irq = %d\n",
chip->regs, irq);
return 0;
err_dma:
- if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.rx_chan);
- if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.tx_chan);
- clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
- clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
- chip->dma.rx_chan = NULL;
- chip->dma.tx_chan = NULL;
- if (cpu_is_at32ap7000()) {
if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.rx_chan);
if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.tx_chan);
clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
chip->dma.rx_chan = NULL;
chip->dma.tx_chan = NULL;
- }
err_ac97_bus: snd_card_set_dev(card, NULL);
@@ -934,12 +1098,13 @@ static int atmel_ac97c_suspend(struct platform_device *pdev, pm_message_t msg) struct snd_card *card = platform_get_drvdata(pdev); struct atmel_ac97c *chip = card->private_data;
- if (test_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_stop(chip->dma.rx_chan);
- if (test_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_stop(chip->dma.tx_chan);
- if (cpu_is_at32ap7000()) {
if (test_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_stop(chip->dma.rx_chan);
if (test_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_stop(chip->dma.tx_chan);
- } clk_disable(chip->pclk);
- return 0;
}
@@ -949,11 +1114,12 @@ static int atmel_ac97c_resume(struct platform_device *pdev) struct atmel_ac97c *chip = card->private_data;
clk_enable(chip->pclk);
- if (test_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_start(chip->dma.rx_chan);
- if (test_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_start(chip->dma.tx_chan);
- if (cpu_is_at32ap7000()) {
if (test_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_start(chip->dma.rx_chan);
if (test_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_start(chip->dma.tx_chan);
- } return 0;
} #else @@ -978,14 +1144,16 @@ static int __devexit atmel_ac97c_remove(struct platform_device *pdev) iounmap(chip->regs); free_irq(chip->irq, chip);
- if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.rx_chan);
- if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.tx_chan);
- clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
- clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
- chip->dma.rx_chan = NULL;
- chip->dma.tx_chan = NULL;
if (cpu_is_at32ap7000()) {
if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.rx_chan);
if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.tx_chan);
clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
chip->dma.rx_chan = NULL;
chip->dma.tx_chan = NULL;
}
snd_card_set_dev(card, NULL); snd_card_free(card);
At Thu, 06 Aug 2009 15:48:27 +0200, Sedji Gaouaou wrote:
Hi,
I was wondering what is the status of this patch?
Well, it's not clear who will take which patches.
Are other changes like the one in at91 side already merged in linux-arm tree? If so, I'll apply only ac97-atmel patch.
thanks,
Takashi
Regards, Sedji
Sedji Gaouaou a écrit :
This patch add AC97 support for ATMEL AT91 boards, using the AVR32 code. It is based on Takashi git tree(sound-2.6/for-next).
Regards, Sedji
Signed-off-by: Sedji Gaouaou sedji.gaouaou@atmel.com
sound/atmel/Kconfig | 2 +- sound/atmel/ac97c.c | 354 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 262 insertions(+), 94 deletions(-)
diff --git a/sound/atmel/Kconfig b/sound/atmel/Kconfig index 6c228a9..94de43a 100644 --- a/sound/atmel/Kconfig +++ b/sound/atmel/Kconfig @@ -12,7 +12,7 @@ config SND_ATMEL_AC97C tristate "Atmel AC97 Controller (AC97C) driver" select SND_PCM select SND_AC97_CODEC
- depends on DW_DMAC && AVR32
- depends on (DW_DMAC && AVR32) || ARCH_AT91 help ALSA sound driver for the Atmel AC97 controller.
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 0c0f877..54d1365 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -13,6 +13,7 @@ #include <linux/device.h> #include <linux/dmaengine.h> #include <linux/dma-mapping.h> +#include <linux/atmel_pdc.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/module.h> @@ -31,6 +32,10 @@
#include <linux/dw_dmac.h>
+#include <mach/cpu.h> +#include <mach/hardware.h> +#include <mach/gpio.h>
#include "ac97c.h"
enum { @@ -63,6 +68,7 @@ struct atmel_ac97c { u64 cur_format; unsigned int cur_rate; unsigned long flags;
- int period; /* Serialize access to opened variable */ spinlock_t lock; void __iomem *regs;
@@ -241,10 +247,13 @@ static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream, params_buffer_bytes(hw_params)); if (retval < 0) return retval;
- /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
- if (retval == 1)
if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.tx_chan);
if (cpu_is_at32ap7000()) {
/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
if (retval == 1)
if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.tx_chan);
}
/* Set restrictions to params. */ mutex_lock(&opened_mutex);
@@ -263,12 +272,14 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
retval = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
- if (retval < 0)
return retval;
- /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
- if (retval == 1)
if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.rx_chan);
if (cpu_is_at32ap7000()) {
if (retval < 0)
return retval;
/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
if (retval == 1)
if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.rx_chan);
}
/* Set restrictions to params. */ mutex_lock(&opened_mutex);
@@ -282,16 +293,20 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream, static int atmel_ac97c_playback_hw_free(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
- if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.tx_chan);
- if (cpu_is_at32ap7000()) {
if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.tx_chan);
- } return snd_pcm_lib_free_pages(substream);
}
static int atmel_ac97c_capture_hw_free(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
- if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.rx_chan);
- if (cpu_is_at32ap7000()) {
if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_free(chip->dma.rx_chan);
- } return snd_pcm_lib_free_pages(substream);
}
@@ -299,9 +314,11 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime;
int block_size = frames_to_bytes(runtime, runtime->period_size); unsigned long word = ac97c_readl(chip, OCA); int retval;
chip->period = 0; word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
/* assign channels to AC97C channel A */
@@ -324,7 +341,8 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
switch (runtime->format) { case SNDRV_PCM_FORMAT_S16_LE:
word |= AC97C_CMR_CEM_LITTLE;
if (cpu_is_at32ap7000())
break; case SNDRV_PCM_FORMAT_S16_BE: /* fall through */ word &= ~(AC97C_CMR_CEM_LITTLE);word |= AC97C_CMR_CEM_LITTLE;
@@ -363,9 +381,18 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n", runtime->rate);
- if (!test_bit(DMA_TX_READY, &chip->flags))
retval = atmel_ac97c_prepare_dma(chip, substream,
DMA_TO_DEVICE);
if (cpu_is_at32ap7000()) {
if (!test_bit(DMA_TX_READY, &chip->flags))
retval = atmel_ac97c_prepare_dma(chip, substream,
DMA_TO_DEVICE);
} else {
/* Initialize and start the PDC */
writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR);
writel(block_size / 2, chip->regs + ATMEL_PDC_TCR);
writel(runtime->dma_addr + block_size,
chip->regs + ATMEL_PDC_TNPR);
writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR);
}
return retval;
} @@ -374,9 +401,11 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime;
int block_size = frames_to_bytes(runtime, runtime->period_size); unsigned long word = ac97c_readl(chip, ICA); int retval;
chip->period = 0; word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
/* assign channels to AC97C channel A */
@@ -415,11 +444,15 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) word |= AC97C_CSR_OVRUN;
ac97c_writel(chip, CAMR, word);
- /* Enable channel A event interrupt */ word = ac97c_readl(chip, IMR); word |= AC97C_SR_CAEVT;
- ac97c_writel(chip, IER, word);
ac97c_writel(chip, IER, /*word*/AC97C_SR_CAEVT);
/* Enable channel A event interrupt */
/*word = ac97c_readl(chip, IMR);
word |= AC97C_SR_CAEVT;
ac97c_writel(chip, IER, word);*/
/* set variable rate if needed */ if (runtime->rate != 48000) {
@@ -438,9 +471,18 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n", runtime->rate);
- if (!test_bit(DMA_RX_READY, &chip->flags))
retval = atmel_ac97c_prepare_dma(chip, substream,
DMA_FROM_DEVICE);
if (cpu_is_at32ap7000()) {
if (!test_bit(DMA_RX_READY, &chip->flags))
retval = atmel_ac97c_prepare_dma(chip, substream,
DMA_FROM_DEVICE);
} else {
/* Initialize and start the PDC */
writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR);
writel(block_size / 2, chip->regs + ATMEL_PDC_RCR);
writel(runtime->dma_addr + block_size,
chip->regs + ATMEL_PDC_RNPR);
writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR);
}
return retval;
} @@ -449,7 +491,7 @@ static int atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
- unsigned long camr;
unsigned long camr, ptcr = 0; int retval = 0;
camr = ac97c_readl(chip, CAMR);
@@ -458,15 +500,22 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ case SNDRV_PCM_TRIGGER_START:
retval = dw_dma_cyclic_start(chip->dma.tx_chan);
if (retval)
goto out;
camr |= AC97C_CMR_CENA;
if (cpu_is_at32ap7000()) {
retval = dw_dma_cyclic_start(chip->dma.tx_chan);
if (retval)
goto out;
} else {
ptcr = ATMEL_PDC_TXTEN;
}
break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ case SNDRV_PCM_TRIGGER_STOP:camr |= AC97C_CMR_CENA | AC97C_CSR_ENDTX;
dw_dma_cyclic_stop(chip->dma.tx_chan);
if (cpu_is_at32ap7000())
dw_dma_cyclic_stop(chip->dma.tx_chan);
else
if (chip->opened <= 1) camr &= ~AC97C_CMR_CENA; break;ptcr = ATMEL_PDC_TXTDIS;
@@ -476,6 +525,8 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) }
ac97c_writel(chip, CAMR, camr);
- if (!cpu_is_at32ap7000())
writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
out: return retval; } @@ -484,7 +535,7 @@ static int atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
- unsigned long camr;
unsigned long camr, ptcr = 0; int retval = 0;
camr = ac97c_readl(chip, CAMR);
@@ -493,15 +544,22 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ case SNDRV_PCM_TRIGGER_START:
retval = dw_dma_cyclic_start(chip->dma.rx_chan);
if (retval)
goto out;
if (cpu_is_at32ap7000()) {
retval = dw_dma_cyclic_start(chip->dma.rx_chan);
if (retval)
goto out;
} else {
ptcr = ATMEL_PDC_RXTEN;
camr |= AC97C_CMR_CENA; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ case SNDRV_PCM_TRIGGER_STOP:}
dw_dma_cyclic_stop(chip->dma.rx_chan);
if (cpu_is_at32ap7000())
dw_dma_cyclic_stop(chip->dma.rx_chan);
else
if (chip->opened <= 1) camr &= ~AC97C_CMR_CENA; break;ptcr = ATMEL_PDC_RXTDIS;
@@ -511,6 +569,8 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) }
ac97c_writel(chip, CAMR, camr);
- if (!cpu_is_at32ap7000())
writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
out: return retval; } @@ -523,7 +583,10 @@ atmel_ac97c_playback_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t frames; unsigned long bytes;
- bytes = dw_dma_get_src_addr(chip->dma.tx_chan);
if (cpu_is_at32ap7000())
bytes = dw_dma_get_src_addr(chip->dma.tx_chan);
else
bytes = readl(chip->regs + ATMEL_PDC_TPR);
bytes -= runtime->dma_addr;
frames = bytes_to_frames(runtime, bytes);
@@ -540,7 +603,10 @@ atmel_ac97c_capture_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t frames; unsigned long bytes;
- bytes = dw_dma_get_dst_addr(chip->dma.rx_chan);
if (cpu_is_at32ap7000())
bytes = dw_dma_get_dst_addr(chip->dma.rx_chan);
else
bytes = readl(chip->regs + ATMEL_PDC_RPR);
bytes -= runtime->dma_addr;
frames = bytes_to_frames(runtime, bytes);
@@ -578,20 +644,67 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) u32 sr = ac97c_readl(chip, SR); u32 casr = ac97c_readl(chip, CASR); u32 cosr = ac97c_readl(chip, COSR);
u32 camr = ac97c_readl(chip, CAMR);
if (sr & AC97C_SR_CAEVT) {
dev_info(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n",
struct snd_pcm_runtime *runtime;
int offset, next_period, block_size;
dev_dbg(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n", casr & AC97C_CSR_OVRUN ? " OVRUN" : "", casr & AC97C_CSR_RXRDY ? " RXRDY" : "", casr & AC97C_CSR_UNRUN ? " UNRUN" : "", casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "", casr & AC97C_CSR_TXRDY ? " TXRDY" : "", !casr ? " NONE" : "");
if (!cpu_is_at32ap7000()) {
if ((casr & camr) & AC97C_CSR_ENDTX) {
runtime = chip->playback_substream->runtime;
block_size = frames_to_bytes(runtime,
runtime->period_size);
chip->period++;
if (chip->period == runtime->periods)
chip->period = 0;
next_period = chip->period + 1;
if (next_period == runtime->periods)
next_period = 0;
offset = block_size * next_period;
writel(runtime->dma_addr + offset,
chip->regs + ATMEL_PDC_TNPR);
writel(block_size / 2,
chip->regs + ATMEL_PDC_TNCR);
snd_pcm_period_elapsed(
chip->playback_substream);
}
if ((casr & camr) & AC97C_CSR_ENDRX) {
runtime = chip->capture_substream->runtime;
block_size = frames_to_bytes(runtime,
runtime->period_size);
chip->period++;
if (chip->period == runtime->periods)
chip->period = 0;
next_period = chip->period + 1;
if (next_period == runtime->periods)
next_period = 0;
offset = block_size * next_period;
writel(runtime->dma_addr + offset,
chip->regs + ATMEL_PDC_RNPR);
writel(block_size / 2,
chip->regs + ATMEL_PDC_RNCR);
snd_pcm_period_elapsed(chip->capture_substream);
}
}
retval = IRQ_HANDLED; }
if (sr & AC97C_SR_COEVT) {
dev_info(&chip->pdev->dev, "codec channel event%s%s%s%s%s\n",
dev_dbg(&chip->pdev->dev, "codec channel event%s%s%s%s%s\n", cosr & AC97C_CSR_OVRUN ? " OVRUN" : "", cosr & AC97C_CSR_RXRDY ? " RXRDY" : "", cosr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
@@ -608,15 +721,50 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) return retval; }
+static struct ac97_pcm at91_ac97_pcm_defs[] __devinitdata = {
- /* Playback */
- {
.exclusive = 1,
.r = { {
.slots = ((1 << AC97_SLOT_PCM_LEFT)
| (1 << AC97_SLOT_PCM_RIGHT)),
} },
- },
- /* PCM in */
- {
.stream = 1,
.exclusive = 1,
.r = { {
.slots = ((1 << AC97_SLOT_PCM_LEFT)
| (1 << AC97_SLOT_PCM_RIGHT)),
} }
- },
- /* Mic in */
- {
.stream = 1,
.exclusive = 1,
.r = { {
.slots = (1<<AC97_SLOT_MIC),
} }
- },
+};
static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip) { struct snd_pcm *pcm; struct snd_pcm_hardware hw = atmel_ac97c_hw;
- int capture, playback, retval;
int capture, playback, retval, err;
capture = test_bit(DMA_RX_CHAN_PRESENT, &chip->flags); playback = test_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
if (!cpu_is_at32ap7000()) {
err = snd_ac97_pcm_assign(chip->ac97_bus,
ARRAY_SIZE(at91_ac97_pcm_defs),
at91_ac97_pcm_defs);
if (err)
return err;
} retval = snd_pcm_new(chip->card, chip->card->shortname, chip->pdev->id, playback, capture, &pcm); if (retval)
@@ -775,7 +923,12 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) return -ENXIO; }
- pclk = clk_get(&pdev->dev, "pclk");
- if (cpu_is_at32ap7000()) {
pclk = clk_get(&pdev->dev, "pclk");
- } else {
pclk = clk_get(&pdev->dev, "ac97_clk");
- }
- if (IS_ERR(pclk)) { dev_dbg(&pdev->dev, "no peripheral clock\n"); return PTR_ERR(pclk);
@@ -844,43 +997,52 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) goto err_ac97_bus; }
- if (pdata->rx_dws.dma_dev) {
struct dw_dma_slave *dws = &pdata->rx_dws;
dma_cap_mask_t mask;
- if (cpu_is_at32ap7000()) {
if (pdata->rx_dws.dma_dev) {
struct dw_dma_slave *dws = &pdata->rx_dws;
dma_cap_mask_t mask;
dws->rx_reg = regs->start + AC97C_CARHR + 2;
dws->rx_reg = regs->start + AC97C_CARHR + 2;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
chip->dma.rx_chan = dma_request_channel(mask, filter, dws);
chip->dma.rx_chan = dma_request_channel(mask, filter,
dws);
dev_info(&chip->pdev->dev, "using %s for DMA RX\n",
dev_info(&chip->pdev->dev, "using %s for DMA RX\n", dev_name(&chip->dma.rx_chan->dev->device));
set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
- }
set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
}
- if (pdata->tx_dws.dma_dev) {
struct dw_dma_slave *dws = &pdata->tx_dws;
dma_cap_mask_t mask;
if (pdata->tx_dws.dma_dev) {
struct dw_dma_slave *dws = &pdata->tx_dws;
dma_cap_mask_t mask;
dws->tx_reg = regs->start + AC97C_CATHR + 2;
dws->tx_reg = regs->start + AC97C_CATHR + 2;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
chip->dma.tx_chan = dma_request_channel(mask, filter, dws);
chip->dma.tx_chan = dma_request_channel(mask, filter,
dws);
dev_info(&chip->pdev->dev, "using %s for DMA TX\n",
dev_info(&chip->pdev->dev, "using %s for DMA TX\n", dev_name(&chip->dma.tx_chan->dev->device));
set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
- }
set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
}
- if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) &&
!test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) {
dev_dbg(&pdev->dev, "DMA not available\n");
retval = -ENODEV;
goto err_dma;
if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) &&
!test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) {
dev_dbg(&pdev->dev, "DMA not available\n");
retval = -ENODEV;
goto err_dma;
}
} else {
/* Just pretend that we have DMA channel(for at91 i is actually
* the PDC */
set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
}
retval = atmel_ac97c_pcm_new(chip);
@@ -897,20 +1059,22 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, card);
- dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p\n",
chip->regs);
dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p, irq = %d\n",
chip->regs, irq);
return 0;
err_dma:
- if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.rx_chan);
- if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.tx_chan);
- clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
- clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
- chip->dma.rx_chan = NULL;
- chip->dma.tx_chan = NULL;
- if (cpu_is_at32ap7000()) {
if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.rx_chan);
if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.tx_chan);
clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
chip->dma.rx_chan = NULL;
chip->dma.tx_chan = NULL;
- }
err_ac97_bus: snd_card_set_dev(card, NULL);
@@ -934,12 +1098,13 @@ static int atmel_ac97c_suspend(struct platform_device *pdev, pm_message_t msg) struct snd_card *card = platform_get_drvdata(pdev); struct atmel_ac97c *chip = card->private_data;
- if (test_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_stop(chip->dma.rx_chan);
- if (test_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_stop(chip->dma.tx_chan);
- if (cpu_is_at32ap7000()) {
if (test_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_stop(chip->dma.rx_chan);
if (test_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_stop(chip->dma.tx_chan);
- } clk_disable(chip->pclk);
- return 0;
}
@@ -949,11 +1114,12 @@ static int atmel_ac97c_resume(struct platform_device *pdev) struct atmel_ac97c *chip = card->private_data;
clk_enable(chip->pclk);
- if (test_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_start(chip->dma.rx_chan);
- if (test_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_start(chip->dma.tx_chan);
- if (cpu_is_at32ap7000()) {
if (test_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_start(chip->dma.rx_chan);
if (test_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_start(chip->dma.tx_chan);
- } return 0;
} #else @@ -978,14 +1144,16 @@ static int __devexit atmel_ac97c_remove(struct platform_device *pdev) iounmap(chip->regs); free_irq(chip->irq, chip);
- if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.rx_chan);
- if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.tx_chan);
- clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
- clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
- chip->dma.rx_chan = NULL;
- chip->dma.tx_chan = NULL;
if (cpu_is_at32ap7000()) {
if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.rx_chan);
if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
dma_release_channel(chip->dma.tx_chan);
clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
chip->dma.rx_chan = NULL;
chip->dma.tx_chan = NULL;
}
snd_card_set_dev(card, NULL); snd_card_free(card);
Hi,
I have submited the board part to the arm-linux patch traking system: http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=5640
I'll keep you inform if it is applied or not, so you can add the ac97 part to your git, is that ok for you?
Regards, Sedji
Takashi Iwai a écrit :
At Thu, 06 Aug 2009 15:48:27 +0200, Sedji Gaouaou wrote:
Hi,
I was wondering what is the status of this patch?
Well, it's not clear who will take which patches.
Are other changes like the one in at91 side already merged in linux-arm tree? If so, I'll apply only ac97-atmel patch.
thanks,
Takashi
At Fri, 07 Aug 2009 09:38:44 +0200, Sedji Gaouaou wrote:
Hi,
I have submited the board part to the arm-linux patch traking system: http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=5640
I'll keep you inform if it is applied or not, so you can add the ac97 part to your git, is that ok for you?
Fair enough.
thanks,
Takashi
Regards, Sedji
Takashi Iwai a écrit :
At Thu, 06 Aug 2009 15:48:27 +0200, Sedji Gaouaou wrote:
Hi,
I was wondering what is the status of this patch?
Well, it's not clear who will take which patches.
Are other changes like the one in at91 side already merged in linux-arm tree? If so, I'll apply only ac97-atmel patch.
thanks,
Takashi
Hi Takashi,
Just a quick e-mail to let you know that Russel has applied the "board" patch regarding the AC97 on AT91(http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=5640).
So you can apply to your tree the rest of the patch.
Regards, Sedji
Takashi Iwai a écrit :
At Fri, 07 Aug 2009 09:38:44 +0200, Sedji Gaouaou wrote:
Hi,
I have submited the board part to the arm-linux patch traking system: http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=5640
I'll keep you inform if it is applied or not, so you can add the ac97 part to your git, is that ok for you?
Fair enough.
thanks,
Takashi
Regards, Sedji
Takashi Iwai a écrit :
At Thu, 06 Aug 2009 15:48:27 +0200, Sedji Gaouaou wrote:
Hi,
I was wondering what is the status of this patch?
Well, it's not clear who will take which patches.
Are other changes like the one in at91 side already merged in linux-arm tree? If so, I'll apply only ac97-atmel patch.
thanks,
Takashi
participants (2)
-
Sedji Gaouaou
-
Takashi Iwai