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 <[email protected]>
Seems ok from an AT91 perspective. I know little about audio + DT integration, so I am not judging this part. Acked-by: Nicolas Ferre <[email protected]> > --- > .../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 <[email protected]>"); > 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 _______________________________________________ devicetree-discuss mailing list [email protected] https://lists.ozlabs.org/listinfo/devicetree-discuss
