|
|
|
@@ -48,11 +48,7 @@
|
|
|
|
|
#include "atmel_ssc_dai.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20)
|
|
|
|
|
#define NUM_SSC_DEVICES 1
|
|
|
|
|
#else
|
|
|
|
|
#define NUM_SSC_DEVICES 3
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* SSC PDC registers required by the PCM DMA engine.
|
|
|
|
@@ -107,7 +103,6 @@ static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
|
|
|
|
|
.pdc = &pdc_rx_reg,
|
|
|
|
|
.mask = &ssc_rx_mask,
|
|
|
|
|
} },
|
|
|
|
|
#if NUM_SSC_DEVICES == 3
|
|
|
|
|
{{
|
|
|
|
|
.name = "SSC1 PCM out",
|
|
|
|
|
.pdc = &pdc_tx_reg,
|
|
|
|
@@ -128,7 +123,6 @@ static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
|
|
|
|
|
.pdc = &pdc_rx_reg,
|
|
|
|
|
.mask = &ssc_rx_mask,
|
|
|
|
|
} },
|
|
|
|
|
#endif
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -139,7 +133,6 @@ static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = {
|
|
|
|
|
.dir_mask = SSC_DIR_MASK_UNUSED,
|
|
|
|
|
.initialized = 0,
|
|
|
|
|
},
|
|
|
|
|
#if NUM_SSC_DEVICES == 3
|
|
|
|
|
{
|
|
|
|
|
.name = "ssc1",
|
|
|
|
|
.lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock),
|
|
|
|
@@ -152,7 +145,6 @@ static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = {
|
|
|
|
|
.dir_mask = SSC_DIR_MASK_UNUSED,
|
|
|
|
|
.initialized = 0,
|
|
|
|
|
},
|
|
|
|
|
#endif
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -690,27 +682,9 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
|
|
|
|
|
static int atmel_ssc_probe(struct snd_soc_dai *dai)
|
|
|
|
|
{
|
|
|
|
|
struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
snd_soc_dai_set_drvdata(dai, ssc_p);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Request SSC device
|
|
|
|
|
*/
|
|
|
|
|
ssc_p->ssc = ssc_request(dai->id);
|
|
|
|
|
if (IS_ERR(ssc_p->ssc)) {
|
|
|
|
|
printk(KERN_ERR "ASoC: Failed to request SSC %d\n", dai->id);
|
|
|
|
|
ret = PTR_ERR(ssc_p->ssc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int atmel_ssc_remove(struct snd_soc_dai *dai)
|
|
|
|
|
{
|
|
|
|
|
struct atmel_ssc_info *ssc_p = snd_soc_dai_get_drvdata(dai);
|
|
|
|
|
|
|
|
|
|
ssc_free(ssc_p->ssc);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -728,11 +702,8 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = {
|
|
|
|
|
.set_clkdiv = atmel_ssc_set_dai_clkdiv,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = {
|
|
|
|
|
{
|
|
|
|
|
.name = "atmel-ssc-dai.0",
|
|
|
|
|
static struct snd_soc_dai_driver atmel_ssc_dai = {
|
|
|
|
|
.probe = atmel_ssc_probe,
|
|
|
|
|
.remove = atmel_ssc_remove,
|
|
|
|
|
.suspend = atmel_ssc_suspend,
|
|
|
|
|
.resume = atmel_ssc_resume,
|
|
|
|
|
.playback = {
|
|
|
|
@@ -746,69 +717,37 @@ static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = {
|
|
|
|
|
.rates = ATMEL_SSC_RATES,
|
|
|
|
|
.formats = ATMEL_SSC_FORMATS,},
|
|
|
|
|
.ops = &atmel_ssc_dai_ops,
|
|
|
|
|
},
|
|
|
|
|
#if NUM_SSC_DEVICES == 3
|
|
|
|
|
{
|
|
|
|
|
.name = "atmel-ssc-dai.1",
|
|
|
|
|
.probe = atmel_ssc_probe,
|
|
|
|
|
.remove = atmel_ssc_remove,
|
|
|
|
|
.suspend = atmel_ssc_suspend,
|
|
|
|
|
.resume = atmel_ssc_resume,
|
|
|
|
|
.playback = {
|
|
|
|
|
.channels_min = 1,
|
|
|
|
|
.channels_max = 2,
|
|
|
|
|
.rates = ATMEL_SSC_RATES,
|
|
|
|
|
.formats = ATMEL_SSC_FORMATS,},
|
|
|
|
|
.capture = {
|
|
|
|
|
.channels_min = 1,
|
|
|
|
|
.channels_max = 2,
|
|
|
|
|
.rates = ATMEL_SSC_RATES,
|
|
|
|
|
.formats = ATMEL_SSC_FORMATS,},
|
|
|
|
|
.ops = &atmel_ssc_dai_ops,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = "atmel-ssc-dai.2",
|
|
|
|
|
.probe = atmel_ssc_probe,
|
|
|
|
|
.remove = atmel_ssc_remove,
|
|
|
|
|
.suspend = atmel_ssc_suspend,
|
|
|
|
|
.resume = atmel_ssc_resume,
|
|
|
|
|
.playback = {
|
|
|
|
|
.channels_min = 1,
|
|
|
|
|
.channels_max = 2,
|
|
|
|
|
.rates = ATMEL_SSC_RATES,
|
|
|
|
|
.formats = ATMEL_SSC_FORMATS,},
|
|
|
|
|
.capture = {
|
|
|
|
|
.channels_min = 1,
|
|
|
|
|
.channels_max = 2,
|
|
|
|
|
.rates = ATMEL_SSC_RATES,
|
|
|
|
|
.formats = ATMEL_SSC_FORMATS,},
|
|
|
|
|
.ops = &atmel_ssc_dai_ops,
|
|
|
|
|
},
|
|
|
|
|
#endif
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static __devinit int asoc_ssc_probe(struct platform_device *pdev)
|
|
|
|
|
static int asoc_ssc_init(struct device *dev)
|
|
|
|
|
{
|
|
|
|
|
BUG_ON(pdev->id < 0);
|
|
|
|
|
BUG_ON(pdev->id >= ARRAY_SIZE(atmel_ssc_dai));
|
|
|
|
|
return snd_soc_register_dai(&pdev->dev, &atmel_ssc_dai[pdev->id]);
|
|
|
|
|
}
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
ret = snd_soc_register_dai(dev, &atmel_ssc_dai);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "Could not register DAI: %d\n", ret);
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = atmel_pcm_platform_register(dev);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "Could not register PCM: %d\n", ret);
|
|
|
|
|
goto err_unregister_dai;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int __devexit asoc_ssc_remove(struct platform_device *pdev)
|
|
|
|
|
{
|
|
|
|
|
snd_soc_unregister_dai(&pdev->dev);
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
err_unregister_dai:
|
|
|
|
|
snd_soc_unregister_dai(dev);
|
|
|
|
|
err:
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct platform_driver asoc_ssc_driver = {
|
|
|
|
|
.driver = {
|
|
|
|
|
.name = "atmel-ssc-dai",
|
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
.probe = asoc_ssc_probe,
|
|
|
|
|
.remove = __devexit_p(asoc_ssc_remove),
|
|
|
|
|
};
|
|
|
|
|
static void asoc_ssc_exit(struct device *dev)
|
|
|
|
|
{
|
|
|
|
|
atmel_pcm_platform_unregister(dev);
|
|
|
|
|
snd_soc_unregister_dai(dev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* atmel_ssc_set_audio - Allocate the specified SSC for audio use.
|
|
|
|
@@ -816,50 +755,32 @@ static struct platform_driver asoc_ssc_driver = {
|
|
|
|
|
int atmel_ssc_set_audio(int ssc_id)
|
|
|
|
|
{
|
|
|
|
|
struct ssc_device *ssc;
|
|
|
|
|
static struct platform_device *dma_pdev;
|
|
|
|
|
struct platform_device *ssc_pdev;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
if (ssc_id < 0 || ssc_id >= ARRAY_SIZE(atmel_ssc_dai))
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
/* Allocate a dummy device for DMA if we don't have one already */
|
|
|
|
|
if (!dma_pdev) {
|
|
|
|
|
dma_pdev = platform_device_alloc("atmel-pcm-audio", -1);
|
|
|
|
|
if (!dma_pdev)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
ret = platform_device_add(dma_pdev);
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
platform_device_put(dma_pdev);
|
|
|
|
|
dma_pdev = NULL;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id);
|
|
|
|
|
if (!ssc_pdev)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
/* If we can grab the SSC briefly to parent the DAI device off it */
|
|
|
|
|
ssc = ssc_request(ssc_id);
|
|
|
|
|
if (IS_ERR(ssc))
|
|
|
|
|
pr_warn("Unable to parent ASoC SSC DAI on SSC: %ld\n",
|
|
|
|
|
if (IS_ERR(ssc)) {
|
|
|
|
|
pr_err("Unable to parent ASoC SSC DAI on SSC: %ld\n",
|
|
|
|
|
PTR_ERR(ssc));
|
|
|
|
|
else {
|
|
|
|
|
ssc_pdev->dev.parent = &(ssc->pdev->dev);
|
|
|
|
|
ssc_free(ssc);
|
|
|
|
|
return PTR_ERR(ssc);
|
|
|
|
|
} else {
|
|
|
|
|
ssc_info[ssc_id].ssc = ssc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = platform_device_add(ssc_pdev);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
platform_device_put(ssc_pdev);
|
|
|
|
|
ret = asoc_ssc_init(&ssc->pdev->dev);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(atmel_ssc_set_audio);
|
|
|
|
|
|
|
|
|
|
module_platform_driver(asoc_ssc_driver);
|
|
|
|
|
void atmel_ssc_put_audio(int ssc_id)
|
|
|
|
|
{
|
|
|
|
|
struct ssc_device *ssc = ssc_info[ssc_id].ssc;
|
|
|
|
|
|
|
|
|
|
ssc_free(ssc);
|
|
|
|
|
asoc_ssc_exit(&ssc->pdev->dev);
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(atmel_ssc_put_audio);
|
|
|
|
|
|
|
|
|
|
/* Module information */
|
|
|
|
|
MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com");
|
|
|
|
|