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 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.

> +	default:
> +		pr_err("Unsupported data format!\n");
> +		return -EINVAL;

Pretty much all the prints in the driver could be dev_ versions.

> +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.

> +
> +	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