[alsa-devel] [Patch v2 3/4] ASoC: atmel-ssc-dai: register platform from DAIs
Nicolas Ferre
nicolas.ferre at atmel.com
Wed Oct 31 10:41:03 CET 2012
On 10/31/2012 08:26 AM, Bo Shen :
> Register platform from DAIs
>
> Add atmel-ssc-dai device tree support
>
> Although atmel-ssc-dai is a virtual devices, but it needs the ssc
> controller as his parent. So, when use dai based on ssc, you should
> let the dai know which ssc should be used.
> Using ssc_request to implement this, so in dts file, need to assign
> "atmel,dai-master" to dai.
>
> Signed-off-by: Bo Shen <voice.shen at atmel.com>
Seems ok from an AT91 perspective.
I know little about audio + DT integration, so I am not judging this part.
Acked-by: Nicolas Ferre <nicolas.ferre at atmel.com>
> ---
> .../devicetree/bindings/sound/atmel-ssc-dai.txt | 18 ++
> arch/arm/mach-at91/board-sam9g20ek.c | 6 -
> sound/soc/atmel/atmel-pcm.c | 23 +-
> sound/soc/atmel/atmel-pcm.h | 3 +
> sound/soc/atmel/atmel_ssc_dai.c | 251 ++++++--------------
> sound/soc/atmel/sam9g20_wm8731.c | 2 +-
> 6 files changed, 103 insertions(+), 200 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/sound/atmel-ssc-dai.txt
>
> diff --git a/Documentation/devicetree/bindings/sound/atmel-ssc-dai.txt b/Documentation/devicetree/bindings/sound/atmel-ssc-dai.txt
> new file mode 100644
> index 0000000..5afb0e9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/atmel-ssc-dai.txt
> @@ -0,0 +1,18 @@
> +* Atmel DAI interface based on SSC controller
> +
> +THe ssc is physical device. Which can be used to connect audio codec,
> +DAC, Magnetic card reader, and etc. So, build ssc controller as a
> +library.
> +
> +The dai is a virtual device, which will build on ssc controller.
> +So, use "atmel,dai-master" to let the dai know which ssc as his master.
> +
> +Required properties:
> + - compatible: "atmel,atmel-ssc-dai"
> + - atmel,dai-master: this dai base on which ssc controller
> +
> +Example:
> +dai: dai {
> + compatible = "atmel,atmel-ssc-dai";
> + atmel,dai-master = <&ssc0>;
> +};
> diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
> index 5b6a6f9..ebdbf42 100644
> --- a/arch/arm/mach-at91/board-sam9g20ek.c
> +++ b/arch/arm/mach-at91/board-sam9g20ek.c
> @@ -353,11 +353,6 @@ static struct i2c_board_info __initdata ek_i2c_devices[] = {
> },
> };
>
> -static struct platform_device sam9g20ek_pcm_device = {
> - .name = "atmel-pcm-audio",
> - .id = -1,
> -};
> -
> static struct platform_device sam9g20ek_audio_device = {
> .name = "at91sam9g20ek-audio",
> .id = -1,
> @@ -365,7 +360,6 @@ static struct platform_device sam9g20ek_audio_device = {
>
> static void __init ek_add_device_audio(void)
> {
> - platform_device_register(&sam9g20ek_pcm_device);
> platform_device_register(&sam9g20ek_audio_device);
> }
>
> diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
> index 9b84f98..1e9cd2c 100644
> --- a/sound/soc/atmel/atmel-pcm.c
> +++ b/sound/soc/atmel/atmel-pcm.c
> @@ -473,28 +473,17 @@ static struct snd_soc_platform_driver atmel_soc_platform = {
> .resume = atmel_pcm_resume,
> };
>
> -static int __devinit atmel_soc_platform_probe(struct platform_device *pdev)
> +int __devinit atmel_pcm_platform_register(struct device *dev)
> {
> - return snd_soc_register_platform(&pdev->dev, &atmel_soc_platform);
> + return snd_soc_register_platform(dev, &atmel_soc_platform);
> }
> +EXPORT_SYMBOL(atmel_pcm_platform_register);
>
> -static int __devexit atmel_soc_platform_remove(struct platform_device *pdev)
> +void __devexit atmel_pcm_platform_unregister(struct device *dev)
> {
> - snd_soc_unregister_platform(&pdev->dev);
> - return 0;
> + snd_soc_unregister_platform(dev);
> }
> -
> -static struct platform_driver atmel_pcm_driver = {
> - .driver = {
> - .name = "atmel-pcm-audio",
> - .owner = THIS_MODULE,
> - },
> -
> - .probe = atmel_soc_platform_probe,
> - .remove = __devexit_p(atmel_soc_platform_remove),
> -};
> -
> -module_platform_driver(atmel_pcm_driver);
> +EXPORT_SYMBOL(atmel_pcm_platform_unregister);
>
> MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou at atmel.com>");
> MODULE_DESCRIPTION("Atmel PCM module");
> diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h
> index 5e0a95e..2d1c60f 100644
> --- a/sound/soc/atmel/atmel-pcm.h
> +++ b/sound/soc/atmel/atmel-pcm.h
> @@ -80,4 +80,7 @@ struct atmel_pcm_dma_params {
> #define ssc_readx(base, reg) (__raw_readl((base) + (reg)))
> #define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg))
>
> +int __devexit atmel_pcm_platform_register(struct device *dev);
> +void __devexit atmel_pcm_platform_unregister(struct device *dev);
> +
> #endif /* _ATMEL_PCM_H */
> diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
> index 354341e..5ff0774 100644
> --- a/sound/soc/atmel/atmel_ssc_dai.c
> +++ b/sound/soc/atmel/atmel_ssc_dai.c
> @@ -42,18 +42,13 @@
> #include <sound/initval.h>
> #include <sound/soc.h>
>
> +#include <linux/of.h>
> +
> #include <mach/hardware.h>
>
> #include "atmel-pcm.h"
> #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.
> */
> @@ -96,63 +91,24 @@ static struct atmel_ssc_mask ssc_rx_mask = {
> /*
> * DMA parameters.
> */
> -static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
> - {{
> - .name = "SSC0 PCM out",
> - .pdc = &pdc_tx_reg,
> - .mask = &ssc_tx_mask,
> - },
> +static struct atmel_pcm_dma_params ssc_dma_params[2] = {
> {
> - .name = "SSC0 PCM in",
> - .pdc = &pdc_rx_reg,
> - .mask = &ssc_rx_mask,
> - } },
> -#if NUM_SSC_DEVICES == 3
> - {{
> - .name = "SSC1 PCM out",
> + .name = "SSC PCM out",
> .pdc = &pdc_tx_reg,
> .mask = &ssc_tx_mask,
> },
> {
> - .name = "SSC1 PCM in",
> + .name = "SSC PCM in",
> .pdc = &pdc_rx_reg,
> .mask = &ssc_rx_mask,
> - } },
> - {{
> - .name = "SSC2 PCM out",
> - .pdc = &pdc_tx_reg,
> - .mask = &ssc_tx_mask,
> },
> - {
> - .name = "SSC2 PCM in",
> - .pdc = &pdc_rx_reg,
> - .mask = &ssc_rx_mask,
> - } },
> -#endif
> };
>
> -
> -static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = {
> - {
> - .name = "ssc0",
> +static struct atmel_ssc_info ssc_info = {
> + .name = "ssc",
> .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock),
> .dir_mask = SSC_DIR_MASK_UNUSED,
> .initialized = 0,
> - },
> -#if NUM_SSC_DEVICES == 3
> - {
> - .name = "ssc1",
> - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock),
> - .dir_mask = SSC_DIR_MASK_UNUSED,
> - .initialized = 0,
> - },
> - {
> - .name = "ssc2",
> - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock),
> - .dir_mask = SSC_DIR_MASK_UNUSED,
> - .initialized = 0,
> - },
> -#endif
> };
>
>
> @@ -205,7 +161,7 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)
> static int atmel_ssc_startup(struct snd_pcm_substream *substream,
> struct snd_soc_dai *dai)
> {
> - struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
> + struct atmel_ssc_info *ssc_p = &ssc_info;
> int dir_mask;
>
> pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
> @@ -234,7 +190,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
> static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
> struct snd_soc_dai *dai)
> {
> - struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
> + struct atmel_ssc_info *ssc_p = &ssc_info;
> struct atmel_pcm_dma_params *dma_params;
> int dir, dir_mask;
>
> @@ -285,7 +241,7 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
> static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai,
> unsigned int fmt)
> {
> - struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
> + struct atmel_ssc_info *ssc_p = &ssc_info;
>
> ssc_p->daifmt = fmt;
> return 0;
> @@ -297,7 +253,7 @@ static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai,
> static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
> int div_id, int div)
> {
> - struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
> + struct atmel_ssc_info *ssc_p = &ssc_info;
>
> switch (div_id) {
> case ATMEL_SSC_CMR_DIV:
> @@ -336,8 +292,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
> struct snd_soc_dai *dai)
> {
> struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
> - int id = dai->id;
> - struct atmel_ssc_info *ssc_p = &ssc_info[id];
> + struct atmel_ssc_info *ssc_p = &ssc_info;
> struct atmel_pcm_dma_params *dma_params;
> int dir, channels, bits;
> u32 tfmr, rfmr, tcmr, rcmr;
> @@ -354,7 +309,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
> else
> dir = 1;
>
> - dma_params = &ssc_dma_params[id][dir];
> + dma_params = &ssc_dma_params[dir];
> dma_params->ssc = ssc_p->ssc;
> dma_params->substream = substream;
>
> @@ -603,7 +558,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
> static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
> struct snd_soc_dai *dai)
> {
> - struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
> + struct atmel_ssc_info *ssc_p = &ssc_info;
> struct atmel_pcm_dma_params *dma_params;
> int dir;
>
> @@ -631,7 +586,7 @@ static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai)
> if (!cpu_dai->active)
> return 0;
>
> - ssc_p = &ssc_info[cpu_dai->id];
> + ssc_p = &ssc_info;
>
> /* Save the status register before disabling transmit and receive */
> ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR);
> @@ -660,7 +615,7 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
> if (!cpu_dai->active)
> return 0;
>
> - ssc_p = &ssc_info[cpu_dai->id];
> + ssc_p = &ssc_info;
>
> /* restore SSC register settings */
> ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr);
> @@ -689,31 +644,14 @@ 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];
> + struct atmel_ssc_info *ssc_p = &ssc_info;
> 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;
> -}
> -
> #define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
>
> #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
> @@ -728,11 +666,9 @@ 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 = {
> + .name = "atmel-ssc-dai",
> .probe = atmel_ssc_probe,
> - .remove = atmel_ssc_remove,
> .suspend = atmel_ssc_suspend,
> .resume = atmel_ssc_resume,
> .playback = {
> @@ -746,119 +682,82 @@ 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)
> {
> - 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]);
> + struct ssc_device *ssc;
> + int ret, id;
> +
> + if (pdev->dev.of_node) {
> + struct device_node *np = pdev->dev.of_node;
> + struct device_node *dai_master_np;
> +
> + dai_master_np = of_parse_phandle(np, "atmel,dai-master", 0);
> + if (!dai_master_np) {
> + dev_err(&pdev->dev, "No SSC for atmel dai");
> + return -EINVAL;
> + }
> +
> + id = of_alias_get_id(dai_master_np, "ssc");
> + } else {
> + id = to_platform_device(pdev->dev.parent)->id;
> + }
> +
> + ssc = ssc_request(id);
> + if (IS_ERR(ssc)) {
> + dev_err(&pdev->dev, "Failed to request SSC %d\n", id);
> + return PTR_ERR(ssc);
> + }
> + ssc_info.ssc = ssc;
> + pdev->dev.parent = &(ssc->pdev->dev);
> +
> + ret = snd_soc_register_dai(&pdev->dev, &atmel_ssc_dai);
> + if (ret) {
> + dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
> + goto err_unregister_dai;
> + }
> +
> + ret = atmel_pcm_platform_register(&pdev->dev);
> + if (ret) {
> + dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
> + goto err;
> + };
> +
> + return 0;
> +
> +err_unregister_dai:
> + snd_soc_unregister_dai(&pdev->dev);
> +err:
> + return ret;
> }
>
> static int __devexit asoc_ssc_remove(struct platform_device *pdev)
> {
> + atmel_pcm_platform_unregister(&pdev->dev);
> snd_soc_unregister_dai(&pdev->dev);
> return 0;
> }
>
> +#ifdef CONFIG_OF
> +static const struct of_device_id atmel_ssc_dai_dt_ids[] = {
> + { .compatible = "atmel,atmel-ssc-dai", },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, atmel_ssc_dai_dt_ids);
> +#endif
> +
> static struct platform_driver asoc_ssc_driver = {
> .driver = {
> - .name = "atmel-ssc-dai",
> - .owner = THIS_MODULE,
> + .name = "atmel-ssc-dai",
> + .owner = THIS_MODULE,
> + .of_match_table = of_match_ptr(atmel_ssc_dai_dt_ids),
> },
>
> .probe = asoc_ssc_probe,
> .remove = __devexit_p(asoc_ssc_remove),
> };
>
> -/**
> - * atmel_ssc_set_audio - Allocate the specified SSC for audio use.
> - */
> -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",
> - PTR_ERR(ssc));
> - else {
> - ssc_pdev->dev.parent = &(ssc->pdev->dev);
> - ssc_free(ssc);
> - }
> -
> - ret = platform_device_add(ssc_pdev);
> - if (ret < 0)
> - platform_device_put(ssc_pdev);
> -
> - return ret;
> -}
> -EXPORT_SYMBOL_GPL(atmel_ssc_set_audio);
> -
> module_platform_driver(asoc_ssc_driver);
>
> /* Module information */
> diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
> index e5e27db..c3e1df5 100644
> --- a/sound/soc/atmel/sam9g20_wm8731.c
> +++ b/sound/soc/atmel/sam9g20_wm8731.c
> @@ -182,7 +182,7 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = {
> .cpu_dai_name = "atmel-ssc-dai.0",
> .codec_dai_name = "wm8731-hifi",
> .init = at91sam9g20ek_wm8731_init,
> - .platform_name = "atmel-pcm-audio",
> + .platform_name = "atmel-ssc-dai.0",
> .codec_name = "wm8731.0-001b",
> .ops = &at91sam9g20ek_ops,
> };
>
--
Nicolas Ferre
More information about the Alsa-devel
mailing list