[alsa-devel] [PATCH 1/2] sound: asoc: Adding support for SPEAr13XX ASoC driver

rajeev rajeev-dlh.kumar at st.com
Fri Mar 18 08:19:04 CET 2011


Hi Mark
Thanks for your review comment.
Please find my answer inline

On 3/17/2011 8:35 PM, Mark Brown wrote:
> On Thu, Mar 17, 2011 at 04:53:35PM +0530, Rajeev Kumar wrote:
> 
>> This patch contains the following support as per the ASoC framework:
>> 1. Platform Driver (I2S based).
>> 2. Machine Driver.
> 
> These should be split into separate patches...
>
OK
 
>> The codec driver for STA529 is present in a separate patch.
> 
> ...and this should come before the machine driver patch as the machine
> driver depends on the CODEC.
> 
OK

>> -config SND_SOC_CACHE_LZO
>> -	bool "Support LZO compression for register caches"
>> -	select LZO_COMPRESS
>> -	select LZO_DECOMPRESS
>> -	---help---
>> -	   Select this to enable LZO compression for register caches.
>> -	   This will allow machine or CODEC drivers to compress register
>> -	   caches in memory, reducing the memory consumption at the
>> -	   expense of performance.  If this is not present and is used
>> -	   the system will fall back to uncompressed caches.
>> -
>> -	   Usually it is safe to disable this option, where cache
>> -	   compression in used the rbtree option will typically perform
>> -	   better.
> 
> Hrm?
> 
Oops..
That's a mistake, will be corrected in V2

>> @@ -50,12 +35,11 @@ source "sound/soc/jz4740/Kconfig"
>>  source "sound/soc/nuc900/Kconfig"
>>  source "sound/soc/omap/Kconfig"
>>  source "sound/soc/kirkwood/Kconfig"
>> -source "sound/soc/mid-x86/Kconfig"
>>  source "sound/soc/pxa/Kconfig"
>> -source "sound/soc/samsung/Kconfig"
>> +#source "sound/soc/s3c24xx/Kconfig"
>>  source "sound/soc/s6000/Kconfig"
>>  source "sound/soc/sh/Kconfig"
>> -source "sound/soc/tegra/Kconfig"
>> +source "sound/soc/spear/Kconfig"
>>  source "sound/soc/txx9/Kconfig"
>>  
> 
> Interesting too....
same as above

> 
>> +config SND_SPEAR_SOC_EVM
>> +	tristate "SoC Audio support for Spear EVM"
>> +	depends on SND_SPEAR_SOC
>> +	select SND_SPEAR_SOC_I2S
>> +	select SND_SOC_STA529
>> +	help
>> +	 Say Y if you want to add support for SoC audio on ST SPEAR
>> +	 platform
> 
> The description here isn't terribly good, this is actually a driver for
> the EVM machine.
>
OK
 
>> @@ -0,0 +1,6 @@
>> +# SPEAR Platform Support
>> +obj-$(CONFIG_SND_SPEAR_SOC) += spear13xx-pcm.o
>> +obj-$(CONFIG_SND_SPEAR_SOC_I2S) += spear13xx-i2s.o
>> +
>> +# SPEAR Machine Support
>> +obj-$(CONFIG_SND_SPEAR_SOC_EVM) += evb_sta529.o
> 
> The modules should always be snd-soc-whatever.
>
OK

 
>> + * Copyright (C) 2010 ST Microelectronics
>> + * Rajeev Kumar<rajeev-dlh.kumar at st.com>
> 
> Space between your name and e-mail.
> 
OK

>> +	format = params_format(params);
>> +	rate = params_rate(params);
>> +	channel = params_channels(params);
>> +	freq = format * rate * channel * 8;
>> +	ref_clock = freq * 8;
> 
> Use the utility functions in soc-util to do the format, rate and channel
> number calculation.
>
OK
 
>> +	/* set the codec system clock for DAC */
>> +	ret = snd_soc_dai_set_sysclk(codec_dai, 0 , ref_clock,
>> +			SND_SOC_CLOCK_IN);
>> +	if (ret < 0)
>> +		return ret;
> 
> Should be "0, " not "0 , ".
>
OK
 
>> +	/*setting ref clock in 278 offset*/
>> +	val = readl(PERIP2_CLK_ENB);
>> +	val |= 0x80;
>> +	writel(val, PERIP2_CLK_ENB);
>> +
>> +	/*setting mode 0 in conf regiter: 32c offset*/
>> +	val = readl(PERIP_CFG);
>> +	val |= 0x0;
>> +	writel(val, PERIP_CFG);
> 
> These should be exposed by the relevant driver.
> 
OK

>> +static int __init spear_init(void)
>> +{
>> +	int ret;
>> +
>> +	/* Create and register platform device */
>> +	evb_snd_device = platform_device_alloc("soc-audio", 0);
>> +	if (!evb_snd_device) {
>> +		printk(KERN_ERR "platform_device_alloc fails\n");
>> +		return -ENOMEM;
>> +	}
> 
> Please register the machine using snd_soc_register_card() rather than
> soc-audio.  soc-audio is being phased out.
>
OK, will be corrected in V2

 
>> +static int
>> +spear13xx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
>> +		unsigned int freq, int dir)
>> +{
>> +	struct spear13xx_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
>> +	struct clk *sclk_clk, *src_clk;
>> +	int ret = -EINVAL;
>> +
>> +	sclk_clk = clk_get_sys(NULL, "i2s_sclk_clk");
>> +	if (IS_ERR(sclk_clk)) {
>> +		dev_err(dev->dev, "couldn't get i2s_sclk\n");
>> +		return PTR_ERR(sclk_clk);
>> +	}
>> +
>> +	src_clk = clk_get_sys(NULL, "i2s_src_clk");
>> +	if (IS_ERR(src_clk)) {
>> +		ret = PTR_ERR(src_clk);
>> +		dev_err(dev->dev, "couldn't get i2s_src_sclk\n");
>> +		goto put_sclk_clk;
>> +	}
>> +
>> +	if (clk_set_parent(sclk_clk, src_clk))
>> +		goto put_src_clk;
>> +
>> +	ret = clk_enable(sclk_clk);
>> +	if (ret < 0) {
>> +		dev_err(dev->dev, "enable i2s_sclk fail\n");
>> +		goto put_src_clk;
>> +	}
>> +	return 0;
> 
> The clock requests should be being done as part of the probe, not here -
> think what will happen when the driver is unloaded, the references will
> never be released.  Similarly, the clock should be being enabled and
> disabled as part of the normal driver flow.
> 
> Since the driver is just completely ignoring the clock rate that's
> configured there probably shouldn't be a set_sysclk() function at all.
>
OK, This is basically platform specific part so I need to move it in plat code.
and remove this function.
 
>> +void
>> +i2s_start_play(struct spear13xx_i2s_dev *dev,
>> +		struct snd_pcm_substream *substream)
>> +{
> 
> Non-exported functions should be static.
> 
Ok

>> +	/* for 2.0 audio*/
>> +	if (dev->mode <= 2) {
>> +		i2s_write_reg(dev->i2s_base, CCR, 0x00);
>> +		if (!val) {
>> +			i2s_write_reg(dev->i2s_base, RCR0, 0x2);
> 
> Some of these register writes are also done by the playback path but
> there's no synchronisation between the playback and record paths.
>
OK I will take care of that.
 
>> +void
>> +i2s_stop(struct spear13xx_i2s_dev *dev, struct snd_pcm_substream *substream)
>> +{
>> +	i2s_write_reg(dev->i2s_base, IER, 0);
>> +	i2s_write_reg(dev->i2s_base, IMR0, 0x33);
>> +	i2s_write_reg(dev->i2s_base, IMR1, 0x33);
>> +	i2s_write_reg(dev->i2s_base, ITER, 0);
>> +	i2s_write_reg(dev->i2s_base, IRER, 0);
>> +	i2s_write_reg(dev->i2s_base, CER, 0);
>> +}
> 
> This appears to stop both playback and capture streams but the two
> should be independant.
> 
some flag should be there to avoid this. will be corrected in V2

>> +static irqreturn_t i2s_play_irq(int irq, void *_dev)
>> +{
>> +	struct spear13xx_i2s_dev *dev = (struct spear13xx_i2s_dev *)_dev;
>> +	u32 ch0, ch1;
>> +
>> +	/* check for the tx data overrun condition */
>> +	ch0 = i2s_read_reg(dev->i2s_base, ISR0) & 0x20;
>> +	ch1 = i2s_read_reg(dev->i2s_base, ISR1) & 0x20;
>> +	if (ch0 || ch1) {
>> +
>> +		/* disable i2s block */
>> +		i2s_write_reg(dev->i2s_base, IER, 0);
>> +
>> +		/* disable tx block */
>> +		i2s_write_reg(dev->i2s_base, ITER, 0);
>> +
>> +		/* flush all the tx fifo */
>> +		i2s_write_reg(dev->i2s_base, TXFFR, 1);
>> +
>> +		/* clear tx data overrun interrupt: channel 0 */
>> +		i2s_read_reg(dev->i2s_base, TOR0);
>> +
>> +		/* clear tx data overrun interrupt: channel 1 */
>> +		i2s_read_reg(dev->i2s_base, TOR1);
>> +	}
> 
> If we're overrunning or underrunning I'd expect to see some sort of
> error report happening even if it's just a log.
>
ok
 

>> +static int
>> +spear13xx_i2s_startup(struct snd_pcm_substream *substream,
>> +		struct snd_soc_dai *cpu_dai)
>> +{
>> +	struct spear13xx_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
>> +	u32 ret = 0;
>> +
>> +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
>> +		ret = request_irq(dev->play_irq, i2s_play_irq, 0,
>> +				"spear13xx-i2s", dev);
>> +	} else {
>> +		ret = request_irq(dev->capture_irq, i2s_capture_irq,
>> +				0, "spear13xx-i2s", dev);
>> +	}
> 
> The interrupts should be acquired on probe, constantly requesting and
> releasing them is undesirable.
> 
Ok, will be moved to probe function.

>> +	if (ret) {
>> +		dev_err(dev->dev, "irq registration failure\n");
>> +		iounmap(dev->i2s_base);
>> +		clk_disable(dev->clk);
>> +		clk_put(dev->clk);
>> +		kfree(dev);
>> +		release_mem_region(dev->res->start, resource_size(dev->res));
>> +		return ret;
>> +	}
> 
> This error handling is not associated with anything the startup()
> function has done...
>
This is related to request_irq and will removed from this place.
 
>> +static int spear13xx_i2s_hw_params(struct snd_pcm_substream *substream,
>> +		struct snd_pcm_hw_params *params,
>> +		struct snd_soc_dai *dai)
>> +{
>> +	struct spear13xx_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
>> +	u32 channel;
>> +
>> +	channel = params_channels(params);
>> +
>> +	dev->mode = channel;
> 
> Having channel here isn't doing a lot...
I was actually planning to expand this routine in future.
Should I remove it from the current version?

> 
>> +	/* mask i2s interrupt for channel 0 */
>> +	i2s_write_reg(dev->i2s_base, IMR0, 0x33);
>> +
>> +	/* mask i2s interrupt for channel 1 */
>> +	i2s_write_reg(dev->i2s_base, IMR1, 0x33);
>> +
>> +	i2s_stop(dev, substream);
> 
> Again, simultaneous playback and capture.
> 
Ok

>> +MODULE_AUTHOR("Rajeev Kumar");
>> +MODULE_DESCRIPTION("SPEAr I2S SoC Interface");
>> +MODULE_LICENSE("GPL");
> 
> Should have a MODULE_ALIAS() for autoloading.
> 
OK

>> +#ifndef SPEAR_I2S_H
>> +#define SPEAR_I2S_H
>> +
>> +#define MAX_CHANNEL_NUM		2
>> +#define MIN_CHANNEL_NUM		2
> 
> These need namespacing.
> 
>> +	.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
>> +			SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
>> +			SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
>> +			SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
>> +			SNDRV_PCM_RATE_KNOT),
>> +	.rate_min = 48000,
>> +	.rate_max = 48000,
> 
> These constraints don't agree with each other - the rate limits claim to
> support 48kHz only, the rates setting tells a different story.
> 
At present I checked STA529(codec) only with 48Khz,I need to check with other data rates also.


>> +static int spear13xx_pcm_hw_params(struct snd_pcm_substream *substream,
>> +		struct snd_pcm_hw_params *params)
>> +{
>> +	struct snd_pcm_runtime *runtime = substream->runtime;
>> +	struct spear13xx_runtime_data *prtd = runtime->private_data;
>> +	int ret;
>> +
>> +	ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	prtd->substream = substream;
>> +	prtd->pos = 0;
>> +	return 0;
>> +}
> 
> Rather than passing the channel count through from the I2S driver you
> could just get it directly here.
> 
Are you talking about this "struct spear13xx_runtime_data *prtd = runtime->private_data"
Could you please elaborate little bit more.


>> +static void dma_configure(struct snd_pcm_substream *substream)
>> +{
>> +	struct spear13xx_runtime_data *prtd = substream->runtime->private_data;
>> +
>> +	dma_cap_zero(prtd->mask);
>> +	dma_cap_set(DMA_SLAVE, prtd->mask);
>> +
>> +	prtd->slaves = &data;
>> +	/* we need to pass physical address here */
>> +	prtd->slaves->mem2i2s_slave.tx_reg = (dma_addr_t)prtd->txdma;
>> +	prtd->slaves->mem2i2s_slave.rx_reg = 0;
>> +	prtd->slaves->i2s2mem_slave.tx_reg = 0;
>> +	prtd->slaves->i2s2mem_slave.rx_reg = (dma_addr_t)prtd->rxdma;
>> +
>> +	substream->runtime->private_data = prtd;
>> +}
>> +static bool filter(struct dma_chan *chan, void *slave)
> 
> Blank lines between functions please.
>
OK
 
>> +	dev_info(buf->dev.dev,
>> +			" preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
>> +			(void *)buf->area, (void *)buf->addr, size);
> 
> dev_dbg()
>
OK
 
>> +static struct platform_driver spear13xx_pcm_driver = {
>> +	.driver = {
>> +			.name = "spear-pcm-audio",
>> +			.owner = THIS_MODULE,
>> +	},
> 
> Fix indentation here.
> 
OK

>> +MODULE_AUTHOR("Rajeev Kumar");
>> +MODULE_DESCRIPTION("spear PCM DMA module");
>> +MODULE_LICENSE("GPL");
> 
> MODULE_ALIAS() again please.
> .
OK

Best Rgds
Rajeev

> 



More information about the Alsa-devel mailing list