.resource = au1200_psc1_res,
};
+static struct platform_device db1200_stac_dev = {
+ .name = "ac97-codec",
+ .id = 1, /* on PSC1 */
+};
+
static struct platform_device *db1200_devs[] __initdata = {
NULL, /* PSC0, selected by S6.8 */
&db1200_ide_dev,
&db1200_rtc_dev,
&db1200_nand_dev,
&db1200_audio_dev,
+ &db1200_stac_dev,
};
static int __init db1200_dev_init(void)
static struct snd_soc_dai_link db1200_ac97_dai = {
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai_name = "au1xpsc-ac97",
.codec_dai_name = "ac97-hifi",
- .platform_name = "au1xpsc-pcm-audio",
- .codec_name = "ac97-codec",
+ .cpu_dai_name = "au1xpsc_ac97.1",
+ .platform_name = "au1xpsc-pcm.1",
+ .codec_name = "ac97-codec.1",
};
static struct snd_soc_card db1200_ac97_machine = {
static struct snd_soc_dai_link db1200_i2s_dai = {
.name = "WM8731",
.stream_name = "WM8731 PCM",
- .cpu_dai_name = "au1xpsc",
- .codec_dai_name = "wm8731-hifi"
- .platform_name = "au1xpsc-pcm-audio",
- .codec_name = "wm8731-codec.0-001a",
+ .codec_dai_name = "wm8731-hifi",
+ .cpu_dai_name = "au1xpsc_i2s.1",
+ .platform_name = "au1xpsc-pcm.1",
+ .codec_name = "wm8731-codec.0-001b",
.ops = &db1200_i2s_wm8731_ops,
};
int ret;
ret = -ENOMEM;
- db1200_asoc_dev = platform_device_alloc("soc-audio", -1);
+ db1200_asoc_dev = platform_device_alloc("soc-audio", 1); /* PSC1 */
if (!db1200_asoc_dev)
goto out;
*
* DMA glue for Au1x-PSC audio.
*
- * NOTE: all of these drivers can only work with a SINGLE instance
- * of a PSC. Multiple independent audio devices are impossible
- * with ASoC v1.
*/
int msbits;
};
-/* instance data. There can be only one, MacLeod!!!! */
-static struct au1xpsc_audio_dmadata *au1xpsc_audio_pcmdma[2];
-
/*
* These settings are somewhat okay, at least on my machine audio plays
* almost skip-free. Especially the 64kB buffer seems to help a LOT.
return 0;
}
+static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream *ss)
+{
+ struct snd_soc_pcm_runtime *rtd = ss->private_data;
+ struct au1xpsc_audio_dmadata *pcd =
+ snd_soc_platform_get_drvdata(rtd->platform);
+ return &pcd[SUBSTREAM_TYPE(ss)];
+}
+
static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
goto out;
stype = SUBSTREAM_TYPE(substream);
- pcd = au1xpsc_audio_pcmdma[stype];
+ pcd = to_dmadata(substream);
DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d "
"runtime->min_align %d\n",
static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
{
- struct au1xpsc_audio_dmadata *pcd =
- au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)];
+ struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream);
au1xxx_dbdma_reset(pcd->ddma_chan);
static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
- u32 c = au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->ddma_chan;
+ u32 c = to_dmadata(substream)->ddma_chan;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
static snd_pcm_uframes_t
au1xpsc_pcm_pointer(struct snd_pcm_substream *substream)
{
- return bytes_to_frames(substream->runtime,
- au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->pos);
+ return bytes_to_frames(substream->runtime, to_dmadata(substream)->pos);
}
static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
static int au1xpsc_pcm_close(struct snd_pcm_substream *substream)
{
- au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]);
+ au1x_pcm_dbdma_free(to_dmadata(substream));
return 0;
}
return 0;
}
-static int au1xpsc_pcm_probe(struct snd_soc_platform *platform)
-{
- if (!au1xpsc_audio_pcmdma[PCM_TX] || !au1xpsc_audio_pcmdma[PCM_RX])
- return -ENODEV;
-
- return 0;
-}
-
/* au1xpsc audio platform */
struct snd_soc_platform_driver au1xpsc_soc_platform = {
- .probe = au1xpsc_pcm_probe,
.ops = &au1xpsc_pcm_ops,
.pcm_new = au1xpsc_pcm_new,
.pcm_free = au1xpsc_pcm_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(au1xpsc_soc_platform);
static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
{
+ struct au1xpsc_audio_dmadata *dmadata;
struct resource *r;
int ret;
- if (au1xpsc_audio_pcmdma[PCM_TX] || au1xpsc_audio_pcmdma[PCM_RX])
- return -EBUSY;
-
- /* TX DMA */
- au1xpsc_audio_pcmdma[PCM_TX]
- = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
- if (!au1xpsc_audio_pcmdma[PCM_TX])
+ dmadata = kzalloc(2 * sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
+ if (!dmadata)
return -ENOMEM;
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
ret = -ENODEV;
goto out1;
}
- (au1xpsc_audio_pcmdma[PCM_TX])->ddma_id = r->start;
+ dmadata[PCM_TX].ddma_id = r->start;
/* RX DMA */
- au1xpsc_audio_pcmdma[PCM_RX]
- = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
- if (!au1xpsc_audio_pcmdma[PCM_RX])
- return -ENOMEM;
-
r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!r) {
ret = -ENODEV;
- goto out2;
+ goto out1;
}
- (au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start;
+ dmadata[PCM_RX].ddma_id = r->start;
+
+ platform_set_drvdata(pdev, dmadata);
ret = snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform);
if (!ret)
return ret;
-out2:
- kfree(au1xpsc_audio_pcmdma[PCM_RX]);
- au1xpsc_audio_pcmdma[PCM_RX] = NULL;
out1:
- kfree(au1xpsc_audio_pcmdma[PCM_TX]);
- au1xpsc_audio_pcmdma[PCM_TX] = NULL;
+ kfree(dmadata);
return ret;
}
static int __devexit au1xpsc_pcm_drvremove(struct platform_device *pdev)
{
- int i;
+ struct au1xpsc_audio_dmadata *dmadata = platform_get_drvdata(pdev);
snd_soc_unregister_platform(&pdev->dev);
-
- for (i = 0; i < 2; i++) {
- if (au1xpsc_audio_pcmdma[i]) {
- au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]);
- kfree(au1xpsc_audio_pcmdma[i]);
- au1xpsc_audio_pcmdma[i] = NULL;
- }
- }
+ kfree(dmadata);
return 0;
}
static struct platform_driver au1xpsc_pcm_driver = {
.driver = {
- .name = "au1xpsc-pcm-audio",
+ .name = "au1xpsc-pcm",
.owner = THIS_MODULE,
},
.probe = au1xpsc_pcm_drvprobe,
static int __init au1xpsc_audio_dbdma_load(void)
{
- au1xpsc_audio_pcmdma[PCM_TX] = NULL;
- au1xpsc_audio_pcmdma[PCM_RX] = NULL;
return platform_driver_register(&au1xpsc_pcm_driver);
}
res[1].start = res[1].end = id[1];
res[0].flags = res[1].flags = IORESOURCE_DMA;
- pd = platform_device_alloc("au1xpsc-pcm", -1);
+ pd = platform_device_alloc("au1xpsc-pcm", pdev->id);
if (!pd)
goto out;
*
* Au1xxx-PSC AC97 glue.
*
- * NOTE: all of these drivers can only work with a SINGLE instance
- * of a PSC. Multiple independent audio devices are impossible
- * with ASoC v1.
*/
#include <linux/init.h>
/* instance data. There can be only one, MacLeod!!!! */
static struct au1xpsc_audio_data *au1xpsc_ac97_workdata;
+#if 0
+
+/* this could theoretically work, but ac97->bus->card->private_data can be NULL
+ * when snd_ac97_mixer() is called; I don't know if the rest further down the
+ * chain are always valid either.
+ */
+static inline struct au1xpsc_audio_data *ac97_to_pscdata(struct snd_ac97 *x)
+{
+ struct snd_soc_card *c = x->bus->card->private_data;
+ return snd_soc_dai_get_drvdata(c->rtd->cpu_dai);
+}
+
+#else
+
+#define ac97_to_pscdata(x) au1xpsc_ac97_workdata
+
+#endif
+
/* AC97 controller reads codec register */
static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
unsigned short reg)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
unsigned short retry, tmo;
unsigned long data;
static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
unsigned short val)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
unsigned int tmo, retry;
au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
/* AC97 controller asserts a warm reset */
static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
au_writel(PSC_AC97RST_SNC, AC97_RST(pscdata));
au_sync();
static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
int i;
/* disable PSC during cold reset */
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
unsigned long r, ro, stat;
int chans, t, stype = SUBSTREAM_TYPE(substream);
static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
- /* FIXME */
- struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
int ret, stype = SUBSTREAM_TYPE(substream);
ret = 0;
.hw_params = au1xpsc_ac97_hw_params,
};
-struct snd_soc_dai_driver au1xpsc_ac97_dai = {
+static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
.ac97_control = 1,
.probe = au1xpsc_ac97_probe,
.playback = {
},
.ops = &au1xpsc_ac97_dai_ops,
};
-EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai);
static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
{
unsigned long sel;
struct au1xpsc_audio_data *wd;
- if (au1xpsc_ac97_workdata)
- return -EBUSY;
-
wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
if (!wd)
return -ENOMEM;
au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(wd));
au_sync();
- ret = snd_soc_register_dai(&pdev->dev, &au1xpsc_ac97_dai);
+ /* name the DAI like this device instance ("au1xpsc-ac97.PSCINDEX") */
+ memcpy(&wd->dai_drv, &au1xpsc_ac97_dai_template,
+ sizeof(struct snd_soc_dai_driver));
+ wd->dai_drv.name = dev_name(&pdev->dev);
+
+ platform_set_drvdata(pdev, wd);
+
+ ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
if (ret)
goto out1;
wd->dmapd = au1xpsc_pcm_add(pdev);
if (wd->dmapd) {
- platform_set_drvdata(pdev, wd);
- au1xpsc_ac97_workdata = wd; /* MDEV */
+ au1xpsc_ac97_workdata = wd;
return 0;
}
static struct platform_driver au1xpsc_ac97_driver = {
.driver = {
- .name = "au1xpsc-ac97",
+ .name = "au1xpsc_ac97",
.owner = THIS_MODULE,
.pm = AU1XPSCAC97_PMOPS,
},
*
* Au1xxx-PSC I2S glue.
*
- * NOTE: all of these drivers can only work with a SINGLE instance
- * of a PSC. Multiple independent audio devices are impossible
- * with ASoC v1.
* NOTE: so far only PSC slave mode (bit- and frameclock) is supported.
*/
((stype) == PCM_TX ? PSC_I2SPCR_TC : PSC_I2SPCR_RC)
-/* instance data. There can be only one, MacLeod!!!! */
-static struct au1xpsc_audio_data *au1xpsc_i2s_workdata;
-
static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(cpu_dai);
unsigned long ct;
int ret;
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
int cfgbits;
unsigned long stat;
static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
int ret, stype = SUBSTREAM_TYPE(substream);
switch (cmd) {
return ret;
}
-static int au1xpsc_i2s_probe(struct snd_soc_dai *dai)
-{
- return au1xpsc_i2s_workdata ? 0 : -ENODEV;
-}
-
static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
.trigger = au1xpsc_i2s_trigger,
.hw_params = au1xpsc_i2s_hw_params,
.set_fmt = au1xpsc_i2s_set_fmt,
};
-static struct snd_soc_dai_driver au1xpsc_i2s_dai = {
- .probe = au1xpsc_i2s_probe,
+static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = {
.playback = {
.rates = AU1XPSC_I2S_RATES,
.formats = AU1XPSC_I2S_FMTS,
int ret;
struct au1xpsc_audio_data *wd;
- if (au1xpsc_i2s_workdata)
- return -EBUSY;
-
wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
if (!wd)
return -ENOMEM;
* time out.
*/
- ret = snd_soc_register_dai(&pdev->dev, &au1xpsc_i2s_dai);
+ /* name the DAI like this device instance ("au1xpsc-i2s.PSCINDEX") */
+ memcpy(&wd->dai_drv, &au1xpsc_i2s_dai_template,
+ sizeof(struct snd_soc_dai_driver));
+ wd->dai_drv.name = dev_name(&pdev->dev);
+
+ platform_set_drvdata(pdev, wd);
+
+ ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
if (ret)
goto out1;
/* finally add the DMA device for this PSC */
wd->dmapd = au1xpsc_pcm_add(pdev);
- if (wd->dmapd) {
- platform_set_drvdata(pdev, wd);
- au1xpsc_i2s_workdata = wd;
+ if (wd->dmapd)
return 0;
- }
snd_soc_unregister_dai(&pdev->dev);
out1:
release_mem_region(r->start, resource_size(r));
kfree(wd);
- au1xpsc_i2s_workdata = NULL; /* MDEV */
-
return 0;
}
static struct platform_driver au1xpsc_i2s_driver = {
.driver = {
- .name = "au1xpsc",
+ .name = "au1xpsc_i2s",
.owner = THIS_MODULE,
.pm = AU1XPSCI2S_PMOPS,
},
static int __init au1xpsc_i2s_load(void)
{
- au1xpsc_i2s_workdata = NULL;
return platform_driver_register(&au1xpsc_i2s_driver);
}
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * NOTE: all of these drivers can only work with a SINGLE instance
- * of a PSC. Multiple independent audio devices are impossible
- * with ASoC v1.
*/
#ifndef _AU1X_PCM_H
#define _AU1X_PCM_H
-extern struct snd_ac97_bus_ops soc_ac97_ops;
-
/* DBDMA helpers */
extern struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev);
extern void au1xpsc_pcm_destroy(struct platform_device *dmapd);
unsigned long cfg;
unsigned long rate;
+ struct snd_soc_dai_driver dai_drv;
+
unsigned long pm[2];
struct mutex lock;
struct platform_device *dmapd;