[alsa-devel] [PATCH V2 2/4] ASoC: SAMSUNG: Add I2S0 internal dma driver

Jassi Brar jassisinghbrar at gmail.com
Sat Jun 18 10:58:38 CEST 2011


On Wed, Jun 15, 2011 at 2:13 PM, Sangbeom Kim <sbkim73 at samsung.com> wrote:

> +       .channels_min = 2,
> +       .channels_max = 2,
> +       .buffer_bytes_max = MAX_IDMA_BUFFER,
> +       .period_bytes_min = 128,
> +       .period_bytes_max = MAX_IDMA_PERIOD,
> +       .periods_min = 1,
> +       .periods_max = 2,
> +};
The settings here don't ensure ring buffer is always MAX_IDMA_BUFFER.
Whereas you assume that in 'iis_irq'.


> +
> +void i2sdma_getpos(dma_addr_t *src, struct snd_pcm_substream *substream)
> +{
> +       struct idma_ctrl *prtd = substream->runtime->private_data;
> +
> +       if (prtd && (prtd->state & ST_RUNNING))
> +               *src = idma.lp_tx_addr +
> +                       (readl(idma.regs + I2STRNCNT) & 0xffffff) * 4;
> +       else
> +               *src = idma.lp_tx_addr;
> +}
Why do we need this function ?


> +
> +static int idma_hw_params(struct snd_pcm_substream *substream,
> +                               struct snd_pcm_hw_params *params)
> +{
> +       struct snd_pcm_runtime *runtime = substream->runtime;
> +       struct idma_ctrl *prtd = substream->runtime->private_data;
> +
> +       dev_dbg(dev, "Entered %s\n", __func__);
> +
> +       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
> +       runtime->dma_bytes = params_buffer_bytes(params);
> +
> +       prtd->start = prtd->pos = runtime->dma_addr;
> +       prtd->period = params_periods(params);
> +       prtd->periodsz = params_period_bytes(params);
> +       prtd->end = idma.lp_tx_addr + runtime->dma_bytes;
     prtd->end = runtime->dma_addr + runtime->dma_bytes;   makes better sense


> +static snd_pcm_uframes_t
> +       idma_pointer(struct snd_pcm_substream *substream)
> +{
> +       struct snd_pcm_runtime *runtime = substream->runtime;
> +       struct idma_ctrl *prtd = runtime->private_data;
> +       dma_addr_t src;
> +       unsigned long res;
> +
> +       dev_dbg(dev, "Entered %s\n", __func__);
> +
> +       spin_lock(&prtd->lock);
> +
> +       idma_getpos(&src);
> +       res = src - prtd->start;
> +
> +       spin_unlock(&prtd->lock);
> +
> +       dev_dbg(dev, "Pointer %x \n", src);
> +
> +       if (res >= snd_pcm_lib_buffer_bytes(substream)) {
> +               if (res == snd_pcm_lib_buffer_bytes(substream))
        This second check is redundant.


+static irqreturn_t iis_irq(int irqno, void *dev_id)
+{
+       struct idma_ctrl *prtd = (struct idma_ctrl *)dev_id;
+       u32 iiscon, iisahb, val, addr;
+
+       iisahb  = readl(idma.regs + I2SAHB);
+       iiscon  = readl(idma.regs + I2SCON);
+
+       val = (iisahb & AHB_LVL0INT) ? AHB_CLRLVL0INT : 0;
+
+       if (val) {
+               iisahb |= val;
+               writel(iisahb, idma.regs + I2SAHB);
+
+               addr = readl(idma.regs + I2SLVL0ADDR) - idma.lp_tx_addr;
+               addr += prtd->period;
+               addr %= MAX_IDMA_BUFFER;
+               addr += idma.lp_tx_addr;
+
+               writel(addr, idma.regs + I2SLVL0ADDR);
+
+               if (prtd->cb) {
+                       if (iisahb & AHB_LVL0INT)
   iisahb will always have the AHB_LVL0INT bit set at this point.


> +void idma_reg_init(void *regs)
> +{
> +       spin_lock_init(&idma.lock);
> +       idma.regs = regs;
> +}
> +
Why initialize lock twice, here ...

> +void idma_addr_init(dma_addr_t addr)
> +{
> +       spin_lock_init(&idma.lock);
> +       idma.lp_tx_addr = addr;
> +}
... and here.
And we might have races here - there is no mechanism to ensure these
functions are called before idma.lp_tx_addr and idma.regs are used.
Also, please try to merge them into one function.


> +MODULE_DESCRIPTION("Samsung ASoC IDMA Driver");
> +MODULE_LICENSE("GPL");
The MODULE_AUTHOR field is missing here.


Thnx,
-j


More information about the Alsa-devel mailing list