|
@@ -15,7 +15,7 @@
|
|
|
#include <linux/module.h>
|
|
|
#include <linux/platform_device.h>
|
|
|
#include <linux/dmaengine.h>
|
|
|
-#include <linux/dma/pxa-dma.h>
|
|
|
+#include <linux/dma-mapping.h>
|
|
|
|
|
|
#include <sound/core.h>
|
|
|
#include <sound/pcm.h>
|
|
@@ -27,8 +27,6 @@
|
|
|
#include <mach/regs-ac97.h>
|
|
|
#include <mach/audio.h>
|
|
|
|
|
|
-#include "pxa2xx-pcm.h"
|
|
|
-
|
|
|
static void pxa2xx_ac97_legacy_reset(struct snd_ac97 *ac97)
|
|
|
{
|
|
|
if (!pxa2xx_ac97_try_cold_reset())
|
|
@@ -63,51 +61,46 @@ static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
|
|
|
.reset = pxa2xx_ac97_legacy_reset,
|
|
|
};
|
|
|
|
|
|
-static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_out = {
|
|
|
- .addr = __PREG(PCDR),
|
|
|
- .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
|
|
|
- .chan_name = "pcm_pcm_stereo_out",
|
|
|
- .maxburst = 32,
|
|
|
-};
|
|
|
-
|
|
|
-static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_in = {
|
|
|
- .addr = __PREG(PCDR),
|
|
|
- .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
|
|
|
- .chan_name = "pcm_pcm_stereo_in",
|
|
|
- .maxburst = 32,
|
|
|
-};
|
|
|
-
|
|
|
static struct snd_pcm *pxa2xx_ac97_pcm;
|
|
|
static struct snd_ac97 *pxa2xx_ac97_ac97;
|
|
|
|
|
|
-static int pxa2xx_ac97_pcm_startup(struct snd_pcm_substream *substream)
|
|
|
+static int pxa2xx_ac97_pcm_open(struct snd_pcm_substream *substream)
|
|
|
{
|
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
|
pxa2xx_audio_ops_t *platform_ops;
|
|
|
- int r;
|
|
|
+ int ret, i;
|
|
|
+
|
|
|
+ ret = __pxa2xx_pcm_open(substream);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
|
|
|
runtime->hw.channels_min = 2;
|
|
|
runtime->hw.channels_max = 2;
|
|
|
|
|
|
- r = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
|
|
|
- AC97_RATES_FRONT_DAC : AC97_RATES_ADC;
|
|
|
- runtime->hw.rates = pxa2xx_ac97_ac97->rates[r];
|
|
|
+ i = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
|
|
|
+ AC97_RATES_FRONT_DAC : AC97_RATES_ADC;
|
|
|
+ runtime->hw.rates = pxa2xx_ac97_ac97->rates[i];
|
|
|
snd_pcm_limit_hw_rates(runtime);
|
|
|
|
|
|
- platform_ops = substream->pcm->card->dev->platform_data;
|
|
|
- if (platform_ops && platform_ops->startup)
|
|
|
- return platform_ops->startup(substream, platform_ops->priv);
|
|
|
- else
|
|
|
- return 0;
|
|
|
+ platform_ops = substream->pcm->card->dev->platform_data;
|
|
|
+ if (platform_ops && platform_ops->startup) {
|
|
|
+ ret = platform_ops->startup(substream, platform_ops->priv);
|
|
|
+ if (ret < 0)
|
|
|
+ __pxa2xx_pcm_close(substream);
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
-static void pxa2xx_ac97_pcm_shutdown(struct snd_pcm_substream *substream)
|
|
|
+static int pxa2xx_ac97_pcm_close(struct snd_pcm_substream *substream)
|
|
|
{
|
|
|
pxa2xx_audio_ops_t *platform_ops;
|
|
|
|
|
|
- platform_ops = substream->pcm->card->dev->platform_data;
|
|
|
+ platform_ops = substream->pcm->card->dev->platform_data;
|
|
|
if (platform_ops && platform_ops->shutdown)
|
|
|
platform_ops->shutdown(substream, platform_ops->priv);
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static int pxa2xx_ac97_pcm_prepare(struct snd_pcm_substream *substream)
|
|
@@ -115,17 +108,15 @@ static int pxa2xx_ac97_pcm_prepare(struct snd_pcm_substream *substream)
|
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
|
int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
|
|
|
AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = __pxa2xx_pcm_prepare(substream);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
return snd_ac97_set_rate(pxa2xx_ac97_ac97, reg, runtime->rate);
|
|
|
}
|
|
|
|
|
|
-static struct pxa2xx_pcm_client pxa2xx_ac97_pcm_client = {
|
|
|
- .playback_params = &pxa2xx_ac97_pcm_out,
|
|
|
- .capture_params = &pxa2xx_ac97_pcm_in,
|
|
|
- .startup = pxa2xx_ac97_pcm_startup,
|
|
|
- .shutdown = pxa2xx_ac97_pcm_shutdown,
|
|
|
- .prepare = pxa2xx_ac97_pcm_prepare,
|
|
|
-};
|
|
|
-
|
|
|
#ifdef CONFIG_PM_SLEEP
|
|
|
|
|
|
static int pxa2xx_ac97_do_suspend(struct snd_card *card)
|
|
@@ -183,6 +174,53 @@ static int pxa2xx_ac97_resume(struct device *dev)
|
|
|
static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, pxa2xx_ac97_suspend, pxa2xx_ac97_resume);
|
|
|
#endif
|
|
|
|
|
|
+static const struct snd_pcm_ops pxa2xx_pcm_ops = {
|
|
|
+ .open = pxa2xx_ac97_pcm_open,
|
|
|
+ .close = pxa2xx_ac97_pcm_close,
|
|
|
+ .ioctl = snd_pcm_lib_ioctl,
|
|
|
+ .hw_params = __pxa2xx_pcm_hw_params,
|
|
|
+ .hw_free = __pxa2xx_pcm_hw_free,
|
|
|
+ .prepare = pxa2xx_ac97_pcm_prepare,
|
|
|
+ .trigger = pxa2xx_pcm_trigger,
|
|
|
+ .pointer = pxa2xx_pcm_pointer,
|
|
|
+ .mmap = pxa2xx_pcm_mmap,
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+static int pxa2xx_ac97_pcm_new(struct snd_card *card)
|
|
|
+{
|
|
|
+ struct snd_pcm *pcm;
|
|
|
+ int stream, ret;
|
|
|
+
|
|
|
+ ret = snd_pcm_new(card, "PXA2xx-PCM", 0, 1, 1, &pcm);
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ pcm->private_free = pxa2xx_pcm_free_dma_buffers;
|
|
|
+
|
|
|
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ stream = SNDRV_PCM_STREAM_PLAYBACK;
|
|
|
+ snd_pcm_set_ops(pcm, stream, &pxa2xx_pcm_ops);
|
|
|
+ ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ stream = SNDRV_PCM_STREAM_CAPTURE;
|
|
|
+ snd_pcm_set_ops(pcm, stream, &pxa2xx_pcm_ops);
|
|
|
+ ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ pxa2xx_ac97_pcm = pcm;
|
|
|
+ ret = 0;
|
|
|
+
|
|
|
+ out:
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static int pxa2xx_ac97_probe(struct platform_device *dev)
|
|
|
{
|
|
|
struct snd_card *card;
|
|
@@ -204,7 +242,7 @@ static int pxa2xx_ac97_probe(struct platform_device *dev)
|
|
|
|
|
|
strlcpy(card->driver, dev->dev.driver->name, sizeof(card->driver));
|
|
|
|
|
|
- ret = pxa2xx_pcm_new(card, &pxa2xx_ac97_pcm_client, &pxa2xx_ac97_pcm);
|
|
|
+ ret = pxa2xx_ac97_pcm_new(card);
|
|
|
if (ret)
|
|
|
goto err;
|
|
|
|