[SPARC] cs4231: Fix SBUS support in this driver.
Christopher Zimmermann [Wed, 21 Sep 2005 07:41:22 +0000 (00:41 -0700)]
From: Christopher Zimmermann <madroach@zakweb.de>

This patch enables SBus support for the cs4231 sound driver.
It is tested on an Ultra2. Capture and playback both work.
I experienced lags and crashes using certain threaded
players like ogg123 and mp3blaster, while the former is
lagging far more. This behavior may be specific to SMP
systems. It is reproducable using the dummy sound card
driver. Sox works flawlessly.

Setting up the calculation of ptr in snd_cs4231_playback_pointer
was a bit strange. I got it to work by not incrementing the
[pc]_periods_sent counter when starting DMA the first time
in cs4231_dma_trigger. Therefore this dummy thing.

[ I did some minor cleanups -DaveM ]

Signed-off-by: David S. Miller <davem@davemloft.net>

sound/sparc/cs4231.c

index 2fb27c4..f4361c5 100644 (file)
@@ -173,7 +173,7 @@ static cs4231_t *cs4231_list;
 
 #define CS4231_GLOBALIRQ       0x01    /* IRQ is active */
 
-/* definitions for codec irq status */
+/* definitions for codec irq status - CS4231_IRQ_STATUS        */
 
 #define CS4231_PLAYBACK_IRQ    0x10
 #define CS4231_RECORD_IRQ      0x20
@@ -402,7 +402,7 @@ static void snd_cs4231_outm(cs4231_t *chip, unsigned char reg,
                udelay(100);
 #ifdef CONFIG_SND_DEBUG
        if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
-               snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
+               snd_printdd("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
 #endif
        if (chip->calibrate_mute) {
                chip->image[reg] &= mask;
@@ -425,6 +425,10 @@ static void snd_cs4231_dout(cs4231_t *chip, unsigned char reg, unsigned char val
             timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);
             timeout--)
                udelay(100);
+#ifdef CONFIG_SND_DEBUG
+       if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
+               snd_printdd("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
+#endif
        __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));
        __cs4231_writeb(chip, value, CS4231P(chip, REG));
        mb();
@@ -440,15 +444,12 @@ static void snd_cs4231_out(cs4231_t *chip, unsigned char reg, unsigned char valu
                udelay(100);
 #ifdef CONFIG_SND_DEBUG
        if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
-               snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
+               snd_printdd("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
 #endif
        __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));
        __cs4231_writeb(chip, value, CS4231P(chip, REG));
        chip->image[reg] = value;
        mb();
-#if 0
-       printk("codec out - reg 0x%x = 0x%x\n", chip->mce_bit | reg, value);
-#endif
 }
 
 static unsigned char snd_cs4231_in(cs4231_t *chip, unsigned char reg)
@@ -462,61 +463,14 @@ static unsigned char snd_cs4231_in(cs4231_t *chip, unsigned char reg)
                udelay(100);
 #ifdef CONFIG_SND_DEBUG
        if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
-               snd_printk("in: auto calibration time out - reg = 0x%x\n", reg);
+               snd_printdd("in: auto calibration time out - reg = 0x%x\n", reg);
 #endif
        __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));
        mb();
        ret = __cs4231_readb(chip, CS4231P(chip, REG));
-#if 0
-       printk("codec in - reg 0x%x = 0x%x\n", chip->mce_bit | reg, ret);
-#endif
        return ret;
 }
 
-#if 0
-
-static void snd_cs4231_debug(cs4231_t *chip)
-{
-       printk("CS4231 REGS:      INDEX = 0x%02x  ",
-              __cs4231_readb(chip, CS4231P(chip, REGSEL)));
-       printk("                 STATUS = 0x%02x\n",
-              __cs4231_readb(chip, CS4231P(chip, STATUS)));
-       printk("  0x00: left input      = 0x%02x  ", snd_cs4231_in(chip, 0x00));
-       printk("  0x10: alt 1 (CFIG 2)  = 0x%02x\n", snd_cs4231_in(chip, 0x10));
-       printk("  0x01: right input     = 0x%02x  ", snd_cs4231_in(chip, 0x01));
-       printk("  0x11: alt 2 (CFIG 3)  = 0x%02x\n", snd_cs4231_in(chip, 0x11));
-       printk("  0x02: GF1 left input  = 0x%02x  ", snd_cs4231_in(chip, 0x02));
-       printk("  0x12: left line in    = 0x%02x\n", snd_cs4231_in(chip, 0x12));
-       printk("  0x03: GF1 right input = 0x%02x  ", snd_cs4231_in(chip, 0x03));
-       printk("  0x13: right line in   = 0x%02x\n", snd_cs4231_in(chip, 0x13));
-       printk("  0x04: CD left input   = 0x%02x  ", snd_cs4231_in(chip, 0x04));
-       printk("  0x14: timer low       = 0x%02x\n", snd_cs4231_in(chip, 0x14));
-       printk("  0x05: CD right input  = 0x%02x  ", snd_cs4231_in(chip, 0x05));
-       printk("  0x15: timer high      = 0x%02x\n", snd_cs4231_in(chip, 0x15));
-       printk("  0x06: left output     = 0x%02x  ", snd_cs4231_in(chip, 0x06));
-       printk("  0x16: left MIC (PnP)  = 0x%02x\n", snd_cs4231_in(chip, 0x16));
-       printk("  0x07: right output    = 0x%02x  ", snd_cs4231_in(chip, 0x07));
-       printk("  0x17: right MIC (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x17));
-       printk("  0x08: playback format = 0x%02x  ", snd_cs4231_in(chip, 0x08));
-       printk("  0x18: IRQ status      = 0x%02x\n", snd_cs4231_in(chip, 0x18));
-       printk("  0x09: iface (CFIG 1)  = 0x%02x  ", snd_cs4231_in(chip, 0x09));
-       printk("  0x19: left line out   = 0x%02x\n", snd_cs4231_in(chip, 0x19));
-       printk("  0x0a: pin control     = 0x%02x  ", snd_cs4231_in(chip, 0x0a));
-       printk("  0x1a: mono control    = 0x%02x\n", snd_cs4231_in(chip, 0x1a));
-       printk("  0x0b: init & status   = 0x%02x  ", snd_cs4231_in(chip, 0x0b));
-       printk("  0x1b: right line out  = 0x%02x\n", snd_cs4231_in(chip, 0x1b));
-       printk("  0x0c: revision & mode = 0x%02x  ", snd_cs4231_in(chip, 0x0c));
-       printk("  0x1c: record format   = 0x%02x\n", snd_cs4231_in(chip, 0x1c));
-       printk("  0x0d: loopback        = 0x%02x  ", snd_cs4231_in(chip, 0x0d));
-       printk("  0x1d: var freq (PnP)  = 0x%02x\n", snd_cs4231_in(chip, 0x1d));
-       printk("  0x0e: ply upr count   = 0x%02x  ", snd_cs4231_in(chip, 0x0e));
-       printk("  0x1e: rec upr count   = 0x%02x\n", snd_cs4231_in(chip, 0x1e));
-       printk("  0x0f: ply lwr count   = 0x%02x  ", snd_cs4231_in(chip, 0x0f));
-       printk("  0x1f: rec lwr count   = 0x%02x\n", snd_cs4231_in(chip, 0x1f));
-}
-
-#endif
-
 /*
  *  CS4231 detection / MCE routines
  */
@@ -528,11 +482,12 @@ static void snd_cs4231_busy_wait(cs4231_t *chip)
        /* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */
        for (timeout = 5; timeout > 0; timeout--)
                __cs4231_readb(chip, CS4231P(chip, REGSEL));
+
        /* end of cleanup sequence */
-       for (timeout = 250;
+       for (timeout = 500;
             timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);
             timeout--)
-               udelay(100);
+               udelay(1000);
 }
 
 static void snd_cs4231_mce_up(cs4231_t *chip)
@@ -545,12 +500,12 @@ static void snd_cs4231_mce_up(cs4231_t *chip)
                udelay(100);
 #ifdef CONFIG_SND_DEBUG
        if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
-               snd_printk("mce_up - auto calibration time out (0)\n");
+               snd_printdd("mce_up - auto calibration time out (0)\n");
 #endif
        chip->mce_bit |= CS4231_MCE;
        timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL));
        if (timeout == 0x80)
-               snd_printk("mce_up [%p]: serious init problem - codec still busy\n", chip->port);
+               snd_printdd("mce_up [%p]: serious init problem - codec still busy\n", chip->port);
        if (!(timeout & CS4231_MCE))
                __cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL));
        spin_unlock_irqrestore(&chip->lock, flags);
@@ -563,18 +518,15 @@ static void snd_cs4231_mce_down(cs4231_t *chip)
 
        spin_lock_irqsave(&chip->lock, flags);
        snd_cs4231_busy_wait(chip);
-#if 0
-       printk("(1) timeout = %i\n", timeout);
-#endif
 #ifdef CONFIG_SND_DEBUG
        if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
-               snd_printk("mce_down [%p] - auto calibration time out (0)\n", CS4231P(chip, REGSEL));
+               snd_printdd("mce_down [%p] - auto calibration time out (0)\n", CS4231P(chip, REGSEL));
 #endif
        chip->mce_bit &= ~CS4231_MCE;
        timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL));
        __cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL));
        if (timeout == 0x80)
-               snd_printk("mce_down [%p]: serious init problem - codec still busy\n", chip->port);
+               snd_printdd("mce_down [%p]: serious init problem - codec still busy\n", chip->port);
        if ((timeout & CS4231_MCE) == 0) {
                spin_unlock_irqrestore(&chip->lock, flags);
                return;
@@ -590,9 +542,7 @@ static void snd_cs4231_mce_down(cs4231_t *chip)
                spin_unlock_irqrestore(&chip->lock, flags);
                return;
        }
-#if 0
-       printk("(2) timeout = %i, jiffies = %li\n", timeout, jiffies);
-#endif
+
        /* in 10ms increments, check condition, up to 250ms */
        timeout = 25;
        while (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) {
@@ -604,9 +554,7 @@ static void snd_cs4231_mce_down(cs4231_t *chip)
                msleep(10);
                spin_lock_irqsave(&chip->lock, flags);
        }
-#if 0
-       printk("(3) jiffies = %li\n", jiffies);
-#endif
+
        /* in 10ms increments, check condition, up to 100ms */
        timeout = 10;
        while (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) {
@@ -619,54 +567,58 @@ static void snd_cs4231_mce_down(cs4231_t *chip)
                spin_lock_irqsave(&chip->lock, flags);
        }
        spin_unlock_irqrestore(&chip->lock, flags);
-#if 0
-       printk("(4) jiffies = %li\n", jiffies);
-       snd_printk("mce_down - exit = 0x%x\n", __cs4231_readb(chip, CS4231P(chip, REGSEL)));
-#endif
 }
 
-#if 0 /* Unused for now... */
-static unsigned int snd_cs4231_get_count(unsigned char format, unsigned int size)
-{
-       switch (format & 0xe0) {
-       case CS4231_LINEAR_16:
-       case CS4231_LINEAR_16_BIG:
-               size >>= 1;
-               break;
-       case CS4231_ADPCM_16:
-               return size >> 2;
-       }
-       if (format & CS4231_STEREO)
-               size >>= 1;
-       return size;
-}
-#endif
-
 #ifdef EBUS_SUPPORT
 static void snd_cs4231_ebus_advance_dma(struct ebus_dma_info *p, snd_pcm_substream_t *substream, unsigned int *periods_sent)
 {
        snd_pcm_runtime_t *runtime = substream->runtime;
 
        while (1) {
-               unsigned int dma_size = snd_pcm_lib_period_bytes(substream);
-               unsigned int offset = dma_size * (*periods_sent);
+               unsigned int period_size = snd_pcm_lib_period_bytes(substream);
+               unsigned int offset = period_size * (*periods_sent);
 
-               if (dma_size >= (1 << 24))
+               if (period_size >= (1 << 24))
                        BUG();
 
-               if (ebus_dma_request(p, runtime->dma_addr + offset, dma_size))
+               if (ebus_dma_request(p, runtime->dma_addr + offset, period_size))
                        return;
-#if 0
-               printk("ebus_advance: Sent period %u (size[%x] offset[%x])\n",
-                      (*periods_sent), dma_size, offset);
-#endif
                (*periods_sent) = ((*periods_sent) + 1) % runtime->periods;
        }
 }
 #endif
 
-static void cs4231_dma_trigger(cs4231_t *chip, unsigned int what, int on)
+#ifdef SBUS_SUPPORT
+static void snd_cs4231_sbus_advance_dma(snd_pcm_substream_t *substream, unsigned int *periods_sent)
+{
+       cs4231_t *chip = snd_pcm_substream_chip(substream);
+       snd_pcm_runtime_t *runtime = substream->runtime;
+
+       unsigned int period_size = snd_pcm_lib_period_bytes(substream);
+       unsigned int offset = period_size * (*periods_sent % runtime->periods);
+
+       if (runtime->period_size > 0xffff + 1)
+               BUG();
+
+       switch (substream->stream) {
+       case SNDRV_PCM_STREAM_PLAYBACK:
+               sbus_writel(runtime->dma_addr + offset, chip->port + APCPNVA);
+               sbus_writel(period_size, chip->port + APCPNC);
+               break;
+       case SNDRV_PCM_STREAM_CAPTURE:
+               sbus_writel(runtime->dma_addr + offset, chip->port + APCCNVA);
+               sbus_writel(period_size, chip->port + APCCNC);
+               break;
+       }
+
+       (*periods_sent) = (*periods_sent + 1) % runtime->periods;
+}
+#endif
+
+static void cs4231_dma_trigger(snd_pcm_substream_t *substream, unsigned int what, int on)
 {
+       cs4231_t *chip = snd_pcm_substream_chip(substream);
+
 #ifdef EBUS_SUPPORT
        if (chip->flags & CS4231_FLAG_EBUS) {
                if (what & CS4231_PLAYBACK_ENABLE) {
@@ -694,6 +646,60 @@ static void cs4231_dma_trigger(cs4231_t *chip, unsigned int what, int on)
        } else {
 #endif
 #ifdef SBUS_SUPPORT
+       u32 csr = sbus_readl(chip->port + APCCSR);
+       /* I don't know why, but on sbus the period counter must
+        * only start counting after the first period is sent.
+        * Therefore this dummy thing.
+        */
+       unsigned int dummy = 0;
+
+       switch (what) {
+       case CS4231_PLAYBACK_ENABLE:
+               if (on) {
+                       csr &= ~APC_XINT_PLAY;
+                       sbus_writel(csr, chip->port + APCCSR);
+
+                       csr &= ~APC_PPAUSE;
+                       sbus_writel(csr, chip->port + APCCSR);
+
+                       snd_cs4231_sbus_advance_dma(substream, &dummy);
+
+                       csr |=  APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA |
+                               APC_XINT_PLAY | APC_XINT_EMPT | APC_XINT_GENL |
+                               APC_XINT_PENA | APC_PDMA_READY;
+                       sbus_writel(csr, chip->port + APCCSR);
+               } else {
+                       csr |= APC_PPAUSE;
+                       sbus_writel(csr, chip->port + APCCSR);
+
+                       csr &= ~APC_PDMA_READY;
+                       sbus_writel(csr, chip->port + APCCSR);
+               }
+               break;
+       case CS4231_RECORD_ENABLE:
+               if (on) {
+                       csr &= ~APC_XINT_CAPT;
+                       sbus_writel(csr, chip->port + APCCSR);
+
+                       csr &= ~APC_CPAUSE;
+                       sbus_writel(csr, chip->port + APCCSR);
+
+                       snd_cs4231_sbus_advance_dma(substream, &dummy);
+
+                       csr |=  APC_GENL_INT | APC_CAPT_INT | APC_XINT_ENA |
+                               APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL |
+                               APC_CDMA_READY;
+
+                       sbus_writel(csr, chip->port + APCCSR);
+               } else {
+                       csr |= APC_CPAUSE;
+                       sbus_writel(csr, chip->port + APCCSR);
+
+                       csr &= ~APC_CDMA_READY;
+                       sbus_writel(csr, chip->port + APCCSR);
+               }
+               break;
+       }
 #endif
 #ifdef EBUS_SUPPORT
        }
@@ -725,25 +731,12 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd)
                        }
                }
 
-#if 0
-               printk("TRIGGER: what[%x] on(%d)\n",
-                      what, (cmd == SNDRV_PCM_TRIGGER_START));
-#endif
-
                spin_lock_irqsave(&chip->lock, flags);
                if (cmd == SNDRV_PCM_TRIGGER_START) {
-                       cs4231_dma_trigger(chip, what, 1);
+                       cs4231_dma_trigger(substream, what, 1);
                        chip->image[CS4231_IFACE_CTRL] |= what;
-                       if (what & CS4231_PLAYBACK_ENABLE) {
-                               snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, 0xff);
-                               snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, 0xff);
-                       }
-                       if (what & CS4231_RECORD_ENABLE) {
-                               snd_cs4231_out(chip, CS4231_REC_LWR_CNT, 0xff);
-                               snd_cs4231_out(chip, CS4231_REC_UPR_CNT, 0xff);
-                       }
                } else {
-                       cs4231_dma_trigger(chip, what, 0);
+                       cs4231_dma_trigger(substream, what, 0);
                        chip->image[CS4231_IFACE_CTRL] &= ~what;
                }
                snd_cs4231_out(chip, CS4231_IFACE_CTRL,
@@ -755,9 +748,7 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd)
                result = -EINVAL;
                break;
        }
-#if 0
-       snd_cs4231_debug(chip);
-#endif
+
        return result;
 }
 
@@ -790,9 +781,6 @@ static unsigned char snd_cs4231_get_format(cs4231_t *chip, int format, int chann
        }
        if (channels > 1)
                rformat |= CS4231_STEREO;
-#if 0
-       snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);
-#endif
        return rformat;
 }
 
@@ -944,7 +932,7 @@ static void snd_cs4231_init(cs4231_t *chip)
        snd_cs4231_mce_down(chip);
 
 #ifdef SNDRV_DEBUG_MCE
-       snd_printk("init: (1)\n");
+       snd_printdd("init: (1)\n");
 #endif
        snd_cs4231_mce_up(chip);
        spin_lock_irqsave(&chip->lock, flags);
@@ -957,7 +945,7 @@ static void snd_cs4231_init(cs4231_t *chip)
        snd_cs4231_mce_down(chip);
 
 #ifdef SNDRV_DEBUG_MCE
-       snd_printk("init: (2)\n");
+       snd_printdd("init: (2)\n");
 #endif
 
        snd_cs4231_mce_up(chip);
@@ -967,7 +955,7 @@ static void snd_cs4231_init(cs4231_t *chip)
        snd_cs4231_mce_down(chip);
 
 #ifdef SNDRV_DEBUG_MCE
-       snd_printk("init: (3) - afei = 0x%x\n", chip->image[CS4231_ALT_FEATURE_1]);
+       snd_printdd("init: (3) - afei = 0x%x\n", chip->image[CS4231_ALT_FEATURE_1]);
 #endif
 
        spin_lock_irqsave(&chip->lock, flags);
@@ -981,7 +969,7 @@ static void snd_cs4231_init(cs4231_t *chip)
        snd_cs4231_mce_down(chip);
 
 #ifdef SNDRV_DEBUG_MCE
-       snd_printk("init: (4)\n");
+       snd_printdd("init: (4)\n");
 #endif
 
        snd_cs4231_mce_up(chip);
@@ -991,7 +979,7 @@ static void snd_cs4231_init(cs4231_t *chip)
        snd_cs4231_mce_down(chip);
 
 #ifdef SNDRV_DEBUG_MCE
-       snd_printk("init: (5)\n");
+       snd_printdd("init: (5)\n");
 #endif
 }
 
@@ -1022,6 +1010,7 @@ static int snd_cs4231_open(cs4231_t *chip, unsigned int mode)
                       CS4231_RECORD_IRQ |
                       CS4231_TIMER_IRQ);
        snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
+
        spin_unlock_irqrestore(&chip->lock, flags);
 
        chip->mode = mode;
@@ -1136,11 +1125,21 @@ static int snd_cs4231_playback_hw_free(snd_pcm_substream_t *substream)
 static int snd_cs4231_playback_prepare(snd_pcm_substream_t *substream)
 {
        cs4231_t *chip = snd_pcm_substream_chip(substream);
+       snd_pcm_runtime_t *runtime = substream->runtime;
        unsigned long flags;
 
        spin_lock_irqsave(&chip->lock, flags);
+
        chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE |
                                            CS4231_PLAYBACK_PIO);
+
+       if (runtime->period_size > 0xffff + 1)
+               BUG();
+
+       snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (runtime->period_size - 1) & 0x00ff);
+       snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (runtime->period_size - 1) >> 8 & 0x00ff);
+       chip->p_periods_sent = 0;
+
        spin_unlock_irqrestore(&chip->lock, flags);
 
        return 0;
@@ -1172,12 +1171,16 @@ static int snd_cs4231_capture_hw_free(snd_pcm_substream_t *substream)
 static int snd_cs4231_capture_prepare(snd_pcm_substream_t *substream)
 {
        cs4231_t *chip = snd_pcm_substream_chip(substream);
+       snd_pcm_runtime_t *runtime = substream->runtime;
        unsigned long flags;
 
        spin_lock_irqsave(&chip->lock, flags);
        chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE |
                                            CS4231_RECORD_PIO);
 
+       snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (runtime->period_size - 1) & 0x00ff);
+       snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (runtime->period_size - 1) >> 8 & 0x00ff);
+
        spin_unlock_irqrestore(&chip->lock, flags);
 
        return 0;
@@ -1196,53 +1199,61 @@ static void snd_cs4231_overrange(cs4231_t *chip)
                chip->capture_substream->runtime->overrange++;
 }
 
-static void snd_cs4231_generic_interrupt(cs4231_t *chip)
+static irqreturn_t snd_cs4231_generic_interrupt(cs4231_t *chip)
 {
        unsigned long flags;
        unsigned char status;
 
+       /*This is IRQ is not raised by the cs4231*/
+       if (!(__cs4231_readb(chip, CS4231P(chip, STATUS)) & CS4231_GLOBALIRQ))
+               return IRQ_NONE;
+
        status = snd_cs4231_in(chip, CS4231_IRQ_STATUS);
-       if (!status)
-               return;
 
        if (status & CS4231_TIMER_IRQ) {
                if (chip->timer)
                        snd_timer_interrupt(chip->timer, chip->timer->sticks);
        }               
-       if (status & CS4231_PLAYBACK_IRQ)
-               snd_pcm_period_elapsed(chip->playback_substream);
-       if (status & CS4231_RECORD_IRQ) {
+
+       if (status & CS4231_RECORD_IRQ)
                snd_cs4231_overrange(chip);
-               snd_pcm_period_elapsed(chip->capture_substream);
-       }
 
        /* ACK the CS4231 interrupt. */
        spin_lock_irqsave(&chip->lock, flags);
        snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0);
        spin_unlock_irqrestore(&chip->lock, flags);
+
+       return 0;
 }
 
 #ifdef SBUS_SUPPORT
 static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        cs4231_t *chip = dev_id;
-       u32 csr;
-
-       csr = sbus_readl(chip->port + APCCSR);
-       if (!(csr & (APC_INT_PENDING |
-                    APC_PLAY_INT |
-                    APC_CAPT_INT |
-                    APC_GENL_INT |
-                    APC_XINT_PEMP |
-                    APC_XINT_CEMP)))
-               return IRQ_NONE;
 
        /* ACK the APC interrupt. */
+       u32 csr = sbus_readl(chip->port + APCCSR);
+
        sbus_writel(csr, chip->port + APCCSR);
 
-       snd_cs4231_generic_interrupt(chip);
+       if ((chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) &&
+           (csr & APC_PLAY_INT) &&
+           (csr & APC_XINT_PNVA) &&
+           !(csr & APC_XINT_EMPT)) {
+               snd_cs4231_sbus_advance_dma(chip->playback_substream,
+                                           &chip->p_periods_sent);
+               snd_pcm_period_elapsed(chip->playback_substream);
+       }
 
-       return IRQ_HANDLED;
+       if ((chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) &&
+           (csr & APC_CAPT_INT) &&
+           (csr & APC_XINT_CNVA)) {
+               snd_cs4231_sbus_advance_dma(chip->capture_substream,
+                                           &chip->c_periods_sent);
+               snd_pcm_period_elapsed(chip->capture_substream);
+       }
+
+       return snd_cs4231_generic_interrupt(chip);
 }
 #endif
 
@@ -1290,7 +1301,8 @@ static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substr
 #ifdef EBUS_SUPPORT
        }
 #endif
-       ptr += (period_bytes - residue);
+       ptr += period_bytes - residue;
+
        return bytes_to_frames(substream->runtime, ptr);
 }
 
@@ -1314,7 +1326,7 @@ static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substr
 #ifdef EBUS_SUPPORT
        }
 #endif
-       ptr += (period_bytes - residue);
+       ptr += period_bytes - residue;
        return bytes_to_frames(substream->runtime, ptr);
 }
 
@@ -1328,9 +1340,6 @@ static int snd_cs4231_probe(cs4231_t *chip)
        int i, id, vers;
        unsigned char *ptr;
 
-#if 0
-       snd_cs4231_debug(chip);
-#endif
        id = vers = 0;
        for (i = 0; i < 50; i++) {
                mb();
@@ -1985,13 +1994,13 @@ static int __init snd_cs4231_sbus_create(snd_card_t *card,
        chip->port = sbus_ioremap(&sdev->resource[0], 0,
                                  chip->regs_size, "cs4231");
        if (!chip->port) {
-               snd_printk("cs4231-%d: Unable to map chip registers.\n", dev);
+               snd_printdd("cs4231-%d: Unable to map chip registers.\n", dev);
                return -EIO;
        }
 
        if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt,
                        SA_SHIRQ, "cs4231", chip)) {
-               snd_printk("cs4231-%d: Unable to grab SBUS IRQ %s\n",
+               snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %s\n",
                           dev,
                           __irq_itoa(sdev->irqs[0]));
                snd_cs4231_sbus_free(chip);
@@ -2113,29 +2122,29 @@ static int __init snd_cs4231_ebus_create(snd_card_t *card,
        chip->eb2c.regs = ioremap(edev->resource[2].start, 0x10);
        if (!chip->port || !chip->eb2p.regs || !chip->eb2c.regs) {
                snd_cs4231_ebus_free(chip);
-               snd_printk("cs4231-%d: Unable to map chip registers.\n", dev);
+               snd_printdd("cs4231-%d: Unable to map chip registers.\n", dev);
                return -EIO;
        }
 
        if (ebus_dma_register(&chip->eb2c)) {
                snd_cs4231_ebus_free(chip);
-               snd_printk("cs4231-%d: Unable to register EBUS capture DMA\n", dev);
+               snd_printdd("cs4231-%d: Unable to register EBUS capture DMA\n", dev);
                return -EBUSY;
        }
        if (ebus_dma_irq_enable(&chip->eb2c, 1)) {
                snd_cs4231_ebus_free(chip);
-               snd_printk("cs4231-%d: Unable to enable EBUS capture IRQ\n", dev);
+               snd_printdd("cs4231-%d: Unable to enable EBUS capture IRQ\n", dev);
                return -EBUSY;
        }
 
        if (ebus_dma_register(&chip->eb2p)) {
                snd_cs4231_ebus_free(chip);
-               snd_printk("cs4231-%d: Unable to register EBUS play DMA\n", dev);
+               snd_printdd("cs4231-%d: Unable to register EBUS play DMA\n", dev);
                return -EBUSY;
        }
        if (ebus_dma_irq_enable(&chip->eb2p, 1)) {
                snd_cs4231_ebus_free(chip);
-               snd_printk("cs4231-%d: Unable to enable EBUS play IRQ\n", dev);
+               snd_printdd("cs4231-%d: Unable to enable EBUS play IRQ\n", dev);
                return -EBUSY;
        }