Re: [PATCH 4/4] S3C64XX DSP: Added the CPU driver for PCM controllers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Nov 2, 2009 at 8:17 PM, Mark Brown
<broonie@xxxxxxxxxxxxxxxxxxxxxxxxxxx> wrote:
> On Mon, Nov 02, 2009 at 11:09:51AM +0900, jassisinghbrar@xxxxxxxxx wrote:
>
>> +static int s3c64xx_dsp_trigger(struct snd_pcm_substream *substream, int cmd,
>> +                            struct snd_soc_dai *dai)
>> +{
>> +     struct snd_soc_pcm_runtime *rtd = substream->private_data;
>> +     struct s3c_dsp_info *dsp = to_info(rtd->dai->cpu_dai);
>> +     unsigned long irqs;
>> +
>> +     pr_debug("Entered %s\n", __func__);
>> +
>> +     switch (cmd) {
>> +     case SNDRV_PCM_TRIGGER_START:
>> +     case SNDRV_PCM_TRIGGER_RESUME:
>> +     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
>> +             local_irq_save(irqs);
>
> Why local_irq_save()?  On existing uniprocessor systems they should be
> equivalent to a regular IRQ save and if there are future multi core
> chips using the driver I can't imagine that a local IRQ save will be
> enough.
Don't we need to protect critical mode change in PCM control register?
Since the s3c64xx_dsp_snd_tx/rxctrl is small and non-blocking, I think
protection by simply enabling/disabling IRQs should be fine.

>> +     default:
>> +             pr_err("Unsupported data format!\n");
>> +             return -EINVAL;
>
> Pretty much all the prints in the driver could be dev_ versions.
okay, will change it.

>> +static int s3c64xx_dsp_set_clkdiv(struct snd_soc_dai *cpu_dai,
>> +                               int div_id, int div)
>> +{
>> +     struct s3c_dsp_info *dsp = to_info(cpu_dai);
>> +     void __iomem *regs = dsp->regs;
>> +     u32 clkctl = readl(regs + S3C64XX_PCM_CLKCTL);
>> +
>> +     pr_debug("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
>> +
>> +     switch (div_id) {
>> +     case S3C64XX_DSP_SCLK_DIV:
>> +             clkctl &= ~(S3C64XX_PCM_CLKCTL_SCLKDIV_MASK
>> +                             << S3C64XX_PCM_CLKCTL_SCLKDIV_SHIFT);
>> +             clkctl |= ((div & S3C64XX_PCM_CLKCTL_SCLKDIV_MASK)
>> +                             << S3C64XX_PCM_CLKCTL_SCLKDIV_SHIFT);
>> +             break;
>> +
>> +     case S3C64XX_DSP_SYNC_DIV:
>> +             clkctl &= ~(S3C64XX_PCM_CLKCTL_SYNCDIV_MASK
>> +                             << S3C64XX_PCM_CLKCTL_SYNCDIV_SHIFT);
>> +             clkctl |= ((div & S3C64XX_PCM_CLKCTL_SYNCDIV_MASK)
>> +                             << S3C64XX_PCM_CLKCTL_SYNCDIV_SHIFT);
>> +             break;
>
> You should really provide defaults for these - the overwhelming majority
> of systems are going to want standard configurations and there's no
> point in them all replicating the code to work those out.  Either
> provide a function which takes the params and sets things up that
> machine drivers can call from their hw_params() or just do that
> automatically from the PCM driver hw_params() if the machine driver
> didn't explicitly configure anything.
okay, will change it

>> +
>> +     default:
>> +             return -EINVAL;
>> +     }
>> +
>> +     writel(clkctl, regs + S3C64XX_PCM_CLKCTL);
>> +
>> +     return 0;
>> +}
>> +
>> +static int s3c64xx_dsp_set_sysclk(struct snd_soc_dai *cpu_dai,
>> +                               int clk_id, unsigned int freq, int dir)
>> +{
>> +     struct s3c_dsp_info *dsp = to_info(cpu_dai);
>> +     void __iomem *regs = dsp->regs;
>> +     u32 clkctl = readl(regs + S3C64XX_PCM_CLKCTL);
>> +
>> +     switch (clk_id) {
>> +     case S3C64XX_DSP_CLKSRC_PCLK:
>> +             clkctl |= S3C64XX_PCM_CLKCTL_SERCLKSEL_PCLK;
>> +             break;
>> +
>> +     case S3C64XX_DSP_CLKSRC_MUX:
>> +             clkctl &= ~S3C64XX_PCM_CLKCTL_SERCLKSEL_PCLK;
>> +
>> +             if (clk_get_rate(dsp->pcm_cclk) != freq)
>> +                     clk_set_rate(dsp->pcm_cclk, freq);
>> +
>> +             break;
>> +
>> +     default:
>> +             return -EINVAL;
>> +     }
>> +
>> +     writel(clkctl, regs + S3C64XX_PCM_CLKCTL);
>> +
>> +     return 0;
>> +}
>> +
>> +struct clk *s3c64xx_dsp_get_clock(struct snd_soc_dai *dai)
>> +{
>> +     struct s3c_dsp_info *dsp = to_info(dai);
>> +     void __iomem *regs = dsp->regs;
>> +     u32 clkctl = readl(regs + S3C64XX_PCM_CLKCTL);
>> +
>> +     if (clkctl & S3C64XX_PCM_CLKCTL_SERCLKSEL_PCLK)
>> +             return dsp->pcm_pclk;
>> +     else
>> +             return dsp->pcm_cclk;
>> +}
>> +EXPORT_SYMBOL_GPL(s3c64xx_dsp_get_clock);
>> +
>> +static int s3c64xx_dsp_probe(struct platform_device *pdev,
>> +                          struct snd_soc_dai *dai)
>> +{
>> +     /* configure GPIO for the PCM controller */
>> +     switch (dai->id) {
>> +     case 0:
>> +             s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_PCM0_SCLK);
>> +             s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_PCM0_EXTCLK);
>> +             s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_PCM0_FSYNC);
>> +             s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_PCM0_SIN);
>> +             s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_PCM0_SOUT);
>> +             break;
>> +     case 1:
>> +             s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_PCM1_SCLK);
>> +             s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_PCM1_EXTCLK);
>> +             s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_PCM1_FSYNC);
>> +             s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_PCM1_SIN);
>> +             s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_PCM1_SOUT);
>> +             break;
>> +     default:
>> +             printk(KERN_DEBUG "Invalid PCM Controller number!");
>> +             return -EINVAL;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static struct snd_soc_dai_ops s3c64xx_dsp_dai_ops = {
>> +     .set_sysclk     = s3c64xx_dsp_set_sysclk,
>> +     .trigger        = s3c64xx_dsp_trigger,
>> +     .hw_params      = s3c64xx_dsp_hw_params,
>> +     .set_fmt        = s3c64xx_dsp_set_fmt,
>> +     .set_clkdiv     = s3c64xx_dsp_set_clkdiv,
>> +};
>> +
>> +#define S3C64XX_DSP_RATES  SNDRV_PCM_RATE_8000_96000
>> +
>> +#define S3C64XX_DSP_DECLARE(n)                       \
>> +{                                                            \
>> +     .name            = "s3c64xx-dsp",                       \
>> +     .id              = (n),                         \
>> +     .symmetric_rates = 1,                                   \
>> +     .probe           = s3c64xx_dsp_probe,                   \
>> +     .ops = &s3c64xx_dsp_dai_ops,                            \
>> +     .playback = {                                           \
>> +             .channels_min   = 2,                            \
>> +             .channels_max   = 2,                            \
>> +             .rates          = S3C64XX_DSP_RATES,            \
>> +             .formats        = SNDRV_PCM_FMTBIT_S16_LE,      \
>> +     },                                                      \
>> +     .capture = {                                            \
>> +             .channels_min   = 2,                            \
>> +             .channels_max   = 2,                            \
>> +             .rates          = S3C64XX_DSP_RATES,            \
>> +             .formats        = SNDRV_PCM_FMTBIT_S16_LE,      \
>> +     },                                                      \
>> +}
>> +
>> +struct snd_soc_dai s3c64xx_dsp_dai[] = {
>> +     S3C64XX_DSP_DECLARE(0),
>> +     S3C64XX_DSP_DECLARE(1),
>> +};
>> +EXPORT_SYMBOL_GPL(s3c64xx_dsp_dai);
>> +
>> +static int s3c_dsp_probe(struct platform_device *pdev,
>> +                 struct snd_soc_dai *dai,
>> +                 struct s3c_dsp_info *dsp,
>> +                 unsigned long base)
>> +{
>> +     struct device *dev = &pdev->dev;
>> +
>> +     dsp->dev = dev;
>> +
>> +     /* record our dsp structure for later use in the callbacks */
>> +     dai->private_data = dsp;
>> +
>> +     if (!base) {
>> +             struct resource *res = platform_get_resource(pdev,
>> +                                                          IORESOURCE_MEM,
>> +                                                          0);
>> +             if (!res) {
>> +                     dev_err(dev, "Unable to get register resource\n");
>> +                     return -ENXIO;
>> +             }
>> +
>> +             if (!request_mem_region(res->start, resource_size(res),
>> +                                     "s3c64xx-dsp")) {
>> +                     dev_err(dev, "Unable to request register region\n");
>> +                     return -EBUSY;
>> +             }
>> +
>> +             base = res->start;
>> +     }
>> +
>> +     dsp->regs = ioremap(base, 0x100);
>> +     if (dsp->regs == NULL) {
>> +             dev_err(dev, "cannot ioremap registers\n");
>> +             return -ENXIO;
>> +     }
>> +
>> +     dsp->pcm_pclk = clk_get(dev, "pcm");
>> +     if (IS_ERR(dsp->pcm_pclk)) {
>> +             dev_err(dev, "failed to get pcm_clock\n");
>> +             iounmap(dsp->regs);
>> +             return -ENOENT;
>> +     }
>> +
>> +     clk_enable(dsp->pcm_pclk);
>> +
>> +     return 0;
>> +}
>> +
>> +static __devinit int s3c64xx_dsp_dev_probe(struct platform_device *pdev)
>> +{
>> +     struct s3c_dsp_info *dsp;
>> +     struct snd_soc_dai *dai;
>> +     int ret;
>> +
>> +     if (pdev->id >= ARRAY_SIZE(s3c64xx_dsp)) {
>> +             dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
>> +             return -EINVAL;
>> +     }
>> +
>> +     dsp = &s3c64xx_dsp[pdev->id];
>> +     dai = &s3c64xx_dsp_dai[pdev->id];
>> +     dai->dev = &pdev->dev;
>> +
>> +     dsp->dma_capture = &s3c64xx_pcm_stereo_in[pdev->id];
>> +     dsp->dma_playback = &s3c64xx_pcm_stereo_out[pdev->id];
>> +
>> +     dsp->pcm_cclk = clk_get(&pdev->dev, "audio-bus");
>> +     if (IS_ERR(dsp->pcm_cclk)) {
>> +             dev_err(&pdev->dev, "failed to get audio-bus\n");
>> +             ret = PTR_ERR(dsp->pcm_cclk);
>> +             goto err;
>> +     }
>> +     clk_enable(dsp->pcm_cclk);
>> +
>> +     ret = s3c_dsp_probe(pdev, dai, dsp, 0);
>> +     if (ret)
>> +             goto err_clk;
>> +
>> +     ret = snd_soc_register_dai(dai);
>> +     if (ret != 0)
>> +             goto err_dsp;
>> +
>> +     return 0;
>> +
>> +err_dsp:
>> +     /* Not implemented */
>> +err_clk:
>> +     clk_put(dsp->pcm_cclk);
>> +err:
>> +     return ret;
>> +}
>> +
>> +static __devexit int s3c64xx_dsp_dev_remove(struct platform_device *pdev)
>> +{
>> +     dev_err(&pdev->dev, "Device removal not yet supported\n");
>> +     return 0;
>> +}
>> +
>> +static struct platform_driver s3c64xx_dsp_driver = {
>> +     .probe  = s3c64xx_dsp_dev_probe,
>> +     .remove = s3c64xx_dsp_dev_remove,
>> +     .driver = {
>> +             .name = "s3c64xx-dsp",
>> +             .owner = THIS_MODULE,
>> +     },
>> +};
>> +
>> +static int __init s3c64xx_dsp_init(void)
>> +{
>> +     return platform_driver_register(&s3c64xx_dsp_driver);
>> +}
>> +module_init(s3c64xx_dsp_init);
>> +
>> +static void __exit s3c64xx_dsp_exit(void)
>> +{
>> +     platform_driver_unregister(&s3c64xx_dsp_driver);
>> +}
>> +module_exit(s3c64xx_dsp_exit);
>> +
>> +/* Module information */
>> +MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@xxxxxxxxxxx>");
>> +MODULE_DESCRIPTION("S3C64XX PCM Controller Driver");
>> diff --git a/sound/soc/s3c24xx/s3c64xx-dsp.h b/sound/soc/s3c24xx/s3c64xx-dsp.h
>> new file mode 100644
>> index 0000000..cb92346
>> --- /dev/null
>> +++ b/sound/soc/s3c24xx/s3c64xx-dsp.h
>> @@ -0,0 +1,41 @@
>> +/*  sound/soc/s3c24xx/s3c64xx-dsp.h
>> + *
>> + *  ALSA Soc Audio Layer - S3C64XX PCM Controller driver
>> + *
>> + *  This program is free software; you can redistribute  it and/or modify it
>> + *  under  the terms of  the GNU General  Public License as published by the
>> + *  Free Software Foundation;  either version 2 of the  License, or (at your
>> + *  option) any later version.
>> + */
>> +
>> +#ifndef __SND_SOC_S3C64XX_PCM_H
>> +#define __SND_SOC_S3C64XX_PCM_H __FILE__
>> +
>> +#define S3C64XX_DSP_CLKSRC_PCLK      0
>> +#define S3C64XX_DSP_CLKSRC_MUX       1
>> +
>> +#define S3C64XX_DSP_SYNC_DIV 0
>> +#define S3C64XX_DSP_SCLK_DIV 1
>> +
>> +/**
>> + * struct s3c_dsp_info - S3C PCM Controller information
>> + * @dev: The parent device passed to use from the probe.
>> + * @regs: The pointer to the device register block.
>> + * @dma_playback: DMA information for playback channel.
>> + * @dma_capture: DMA information for capture channel.
>> + */
>> +struct s3c_dsp_info {
>> +     struct device   *dev;
>> +     void __iomem    *regs;
>> +
>> +     /* Whether to keep PCMSCLK enabled even when idle(no active xfer) */
>> +     unsigned int idleclk;
>> +
>> +     struct clk      *pcm_pclk;
>> +     struct clk      *pcm_cclk;
>> +
>> +     struct s3c24xx_pcm_dma_params   *dma_playback;
>> +     struct s3c24xx_pcm_dma_params   *dma_capture;
>> +};
>> +
>> +#endif /* __SND_SOC_S3C64XX_PCM_H */
>> --
>> 1.6.2.5
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>
> --
> "You grabbed my hand and we fell into it, like a daydream - or a fever."
>
--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux SoC Development]     [Linux Rockchip Development]     [Linux USB Development]     [Video for Linux]     [Linux Audio Users]     [Linux SCSI]     [Yosemite News]

  Powered by Linux