Commit a131430c authored by Christopher Zimmermann's avatar Christopher Zimmermann Committed by David S. Miller

[SPARC] cs4231: Fix SBUS support in this driver.

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: default avatarDavid S. Miller <davem@davemloft.net>
parent 1a3e64aa
...@@ -173,7 +173,7 @@ static cs4231_t *cs4231_list; ...@@ -173,7 +173,7 @@ static cs4231_t *cs4231_list;
#define CS4231_GLOBALIRQ 0x01 /* IRQ is active */ #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_PLAYBACK_IRQ 0x10
#define CS4231_RECORD_IRQ 0x20 #define CS4231_RECORD_IRQ 0x20
...@@ -402,7 +402,7 @@ static void snd_cs4231_outm(cs4231_t *chip, unsigned char reg, ...@@ -402,7 +402,7 @@ static void snd_cs4231_outm(cs4231_t *chip, unsigned char reg,
udelay(100); udelay(100);
#ifdef CONFIG_SND_DEBUG #ifdef CONFIG_SND_DEBUG
if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) 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 #endif
if (chip->calibrate_mute) { if (chip->calibrate_mute) {
chip->image[reg] &= mask; chip->image[reg] &= mask;
...@@ -425,6 +425,10 @@ static void snd_cs4231_dout(cs4231_t *chip, unsigned char reg, unsigned char val ...@@ -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 > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);
timeout--) timeout--)
udelay(100); 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, chip->mce_bit | reg, CS4231P(chip, REGSEL));
__cs4231_writeb(chip, value, CS4231P(chip, REG)); __cs4231_writeb(chip, value, CS4231P(chip, REG));
mb(); mb();
...@@ -440,15 +444,12 @@ static void snd_cs4231_out(cs4231_t *chip, unsigned char reg, unsigned char valu ...@@ -440,15 +444,12 @@ static void snd_cs4231_out(cs4231_t *chip, unsigned char reg, unsigned char valu
udelay(100); udelay(100);
#ifdef CONFIG_SND_DEBUG #ifdef CONFIG_SND_DEBUG
if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) 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 #endif
__cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL)); __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));
__cs4231_writeb(chip, value, CS4231P(chip, REG)); __cs4231_writeb(chip, value, CS4231P(chip, REG));
chip->image[reg] = value; chip->image[reg] = value;
mb(); 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) 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) ...@@ -462,61 +463,14 @@ static unsigned char snd_cs4231_in(cs4231_t *chip, unsigned char reg)
udelay(100); udelay(100);
#ifdef CONFIG_SND_DEBUG #ifdef CONFIG_SND_DEBUG
if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) 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 #endif
__cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL)); __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));
mb(); mb();
ret = __cs4231_readb(chip, CS4231P(chip, REG)); 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; 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 * CS4231 detection / MCE routines
*/ */
...@@ -528,11 +482,12 @@ static void snd_cs4231_busy_wait(cs4231_t *chip) ...@@ -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) */ /* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */
for (timeout = 5; timeout > 0; timeout--) for (timeout = 5; timeout > 0; timeout--)
__cs4231_readb(chip, CS4231P(chip, REGSEL)); __cs4231_readb(chip, CS4231P(chip, REGSEL));
/* end of cleanup sequence */ /* end of cleanup sequence */
for (timeout = 250; for (timeout = 500;
timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);
timeout--) timeout--)
udelay(100); udelay(1000);
} }
static void snd_cs4231_mce_up(cs4231_t *chip) static void snd_cs4231_mce_up(cs4231_t *chip)
...@@ -545,12 +500,12 @@ static void snd_cs4231_mce_up(cs4231_t *chip) ...@@ -545,12 +500,12 @@ static void snd_cs4231_mce_up(cs4231_t *chip)
udelay(100); udelay(100);
#ifdef CONFIG_SND_DEBUG #ifdef CONFIG_SND_DEBUG
if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) 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 #endif
chip->mce_bit |= CS4231_MCE; chip->mce_bit |= CS4231_MCE;
timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL)); timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL));
if (timeout == 0x80) 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)) if (!(timeout & CS4231_MCE))
__cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL)); __cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL));
spin_unlock_irqrestore(&chip->lock, flags); spin_unlock_irqrestore(&chip->lock, flags);
...@@ -563,18 +518,15 @@ static void snd_cs4231_mce_down(cs4231_t *chip) ...@@ -563,18 +518,15 @@ static void snd_cs4231_mce_down(cs4231_t *chip)
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&chip->lock, flags);
snd_cs4231_busy_wait(chip); snd_cs4231_busy_wait(chip);
#if 0
printk("(1) timeout = %i\n", timeout);
#endif
#ifdef CONFIG_SND_DEBUG #ifdef CONFIG_SND_DEBUG
if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) 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 #endif
chip->mce_bit &= ~CS4231_MCE; chip->mce_bit &= ~CS4231_MCE;
timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL)); timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL));
__cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL)); __cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL));
if (timeout == 0x80) 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) { if ((timeout & CS4231_MCE) == 0) {
spin_unlock_irqrestore(&chip->lock, flags); spin_unlock_irqrestore(&chip->lock, flags);
return; return;
...@@ -590,9 +542,7 @@ static void snd_cs4231_mce_down(cs4231_t *chip) ...@@ -590,9 +542,7 @@ static void snd_cs4231_mce_down(cs4231_t *chip)
spin_unlock_irqrestore(&chip->lock, flags); spin_unlock_irqrestore(&chip->lock, flags);
return; return;
} }
#if 0
printk("(2) timeout = %i, jiffies = %li\n", timeout, jiffies);
#endif
/* in 10ms increments, check condition, up to 250ms */ /* in 10ms increments, check condition, up to 250ms */
timeout = 25; timeout = 25;
while (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) { 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) ...@@ -604,9 +554,7 @@ static void snd_cs4231_mce_down(cs4231_t *chip)
msleep(10); msleep(10);
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&chip->lock, flags);
} }
#if 0
printk("(3) jiffies = %li\n", jiffies);
#endif
/* in 10ms increments, check condition, up to 100ms */ /* in 10ms increments, check condition, up to 100ms */
timeout = 10; timeout = 10;
while (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) { while (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) {
...@@ -619,54 +567,58 @@ static void snd_cs4231_mce_down(cs4231_t *chip) ...@@ -619,54 +567,58 @@ static void snd_cs4231_mce_down(cs4231_t *chip)
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&chip->lock, flags);
} }
spin_unlock_irqrestore(&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 #ifdef EBUS_SUPPORT
static void snd_cs4231_ebus_advance_dma(struct ebus_dma_info *p, snd_pcm_substream_t *substream, unsigned int *periods_sent) 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; snd_pcm_runtime_t *runtime = substream->runtime;
while (1) { while (1) {
unsigned int dma_size = snd_pcm_lib_period_bytes(substream); unsigned int period_size = snd_pcm_lib_period_bytes(substream);
unsigned int offset = dma_size * (*periods_sent); unsigned int offset = period_size * (*periods_sent);
if (dma_size >= (1 << 24)) if (period_size >= (1 << 24))
BUG(); BUG();
if (ebus_dma_request(p, runtime->dma_addr + offset, dma_size)) if (ebus_dma_request(p, runtime->dma_addr + offset, period_size))
return; 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; (*periods_sent) = ((*periods_sent) + 1) % runtime->periods;
} }
} }
#endif #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 #ifdef EBUS_SUPPORT
if (chip->flags & CS4231_FLAG_EBUS) { if (chip->flags & CS4231_FLAG_EBUS) {
if (what & CS4231_PLAYBACK_ENABLE) { if (what & CS4231_PLAYBACK_ENABLE) {
...@@ -694,6 +646,60 @@ static void cs4231_dma_trigger(cs4231_t *chip, unsigned int what, int on) ...@@ -694,6 +646,60 @@ static void cs4231_dma_trigger(cs4231_t *chip, unsigned int what, int on)
} else { } else {
#endif #endif
#ifdef SBUS_SUPPORT #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 #endif
#ifdef EBUS_SUPPORT #ifdef EBUS_SUPPORT
} }
...@@ -725,25 +731,12 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd) ...@@ -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); spin_lock_irqsave(&chip->lock, flags);
if (cmd == SNDRV_PCM_TRIGGER_START) { if (cmd == SNDRV_PCM_TRIGGER_START) {
cs4231_dma_trigger(chip, what, 1); cs4231_dma_trigger(substream, what, 1);
chip->image[CS4231_IFACE_CTRL] |= what; 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 { } else {
cs4231_dma_trigger(chip, what, 0); cs4231_dma_trigger(substream, what, 0);
chip->image[CS4231_IFACE_CTRL] &= ~what; chip->image[CS4231_IFACE_CTRL] &= ~what;
} }
snd_cs4231_out(chip, CS4231_IFACE_CTRL, snd_cs4231_out(chip, CS4231_IFACE_CTRL,
...@@ -755,9 +748,7 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd) ...@@ -755,9 +748,7 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd)
result = -EINVAL; result = -EINVAL;
break; break;
} }
#if 0
snd_cs4231_debug(chip);
#endif
return result; return result;
} }
...@@ -790,9 +781,6 @@ static unsigned char snd_cs4231_get_format(cs4231_t *chip, int format, int chann ...@@ -790,9 +781,6 @@ static unsigned char snd_cs4231_get_format(cs4231_t *chip, int format, int chann
} }
if (channels > 1) if (channels > 1)
rformat |= CS4231_STEREO; rformat |= CS4231_STEREO;
#if 0
snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);
#endif
return rformat; return rformat;
} }
...@@ -944,7 +932,7 @@ static void snd_cs4231_init(cs4231_t *chip) ...@@ -944,7 +932,7 @@ static void snd_cs4231_init(cs4231_t *chip)
snd_cs4231_mce_down(chip); snd_cs4231_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE #ifdef SNDRV_DEBUG_MCE
snd_printk("init: (1)\n"); snd_printdd("init: (1)\n");
#endif #endif
snd_cs4231_mce_up(chip); snd_cs4231_mce_up(chip);
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&chip->lock, flags);
...@@ -957,7 +945,7 @@ static void snd_cs4231_init(cs4231_t *chip) ...@@ -957,7 +945,7 @@ static void snd_cs4231_init(cs4231_t *chip)
snd_cs4231_mce_down(chip); snd_cs4231_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE #ifdef SNDRV_DEBUG_MCE
snd_printk("init: (2)\n"); snd_printdd("init: (2)\n");
#endif #endif
snd_cs4231_mce_up(chip); snd_cs4231_mce_up(chip);
...@@ -967,7 +955,7 @@ static void snd_cs4231_init(cs4231_t *chip) ...@@ -967,7 +955,7 @@ static void snd_cs4231_init(cs4231_t *chip)
snd_cs4231_mce_down(chip); snd_cs4231_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE #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 #endif
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&chip->lock, flags);
...@@ -981,7 +969,7 @@ static void snd_cs4231_init(cs4231_t *chip) ...@@ -981,7 +969,7 @@ static void snd_cs4231_init(cs4231_t *chip)
snd_cs4231_mce_down(chip); snd_cs4231_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE #ifdef SNDRV_DEBUG_MCE
snd_printk("init: (4)\n"); snd_printdd("init: (4)\n");
#endif #endif
snd_cs4231_mce_up(chip); snd_cs4231_mce_up(chip);
...@@ -991,7 +979,7 @@ static void snd_cs4231_init(cs4231_t *chip) ...@@ -991,7 +979,7 @@ static void snd_cs4231_init(cs4231_t *chip)
snd_cs4231_mce_down(chip); snd_cs4231_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE #ifdef SNDRV_DEBUG_MCE
snd_printk("init: (5)\n"); snd_printdd("init: (5)\n");
#endif #endif
} }
...@@ -1022,6 +1010,7 @@ static int snd_cs4231_open(cs4231_t *chip, unsigned int mode) ...@@ -1022,6 +1010,7 @@ static int snd_cs4231_open(cs4231_t *chip, unsigned int mode)
CS4231_RECORD_IRQ | CS4231_RECORD_IRQ |
CS4231_TIMER_IRQ); CS4231_TIMER_IRQ);
snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
spin_unlock_irqrestore(&chip->lock, flags); spin_unlock_irqrestore(&chip->lock, flags);
chip->mode = mode; chip->mode = mode;
...@@ -1136,11 +1125,21 @@ static int snd_cs4231_playback_hw_free(snd_pcm_substream_t *substream) ...@@ -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) static int snd_cs4231_playback_prepare(snd_pcm_substream_t *substream)
{ {
cs4231_t *chip = snd_pcm_substream_chip(substream); cs4231_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&chip->lock, flags);
chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE |
CS4231_PLAYBACK_PIO); 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); spin_unlock_irqrestore(&chip->lock, flags);
return 0; return 0;
...@@ -1172,12 +1171,16 @@ static int snd_cs4231_capture_hw_free(snd_pcm_substream_t *substream) ...@@ -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) static int snd_cs4231_capture_prepare(snd_pcm_substream_t *substream)
{ {
cs4231_t *chip = snd_pcm_substream_chip(substream); cs4231_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&chip->lock, flags);
chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE |
CS4231_RECORD_PIO); 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); spin_unlock_irqrestore(&chip->lock, flags);
return 0; return 0;
...@@ -1196,53 +1199,61 @@ static void snd_cs4231_overrange(cs4231_t *chip) ...@@ -1196,53 +1199,61 @@ static void snd_cs4231_overrange(cs4231_t *chip)
chip->capture_substream->runtime->overrange++; 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 long flags;
unsigned char status; 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); status = snd_cs4231_in(chip, CS4231_IRQ_STATUS);
if (!status)
return;
if (status & CS4231_TIMER_IRQ) { if (status & CS4231_TIMER_IRQ) {
if (chip->timer) if (chip->timer)
snd_timer_interrupt(chip->timer, chip->timer->sticks); 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_cs4231_overrange(chip);
snd_pcm_period_elapsed(chip->capture_substream);
}
/* ACK the CS4231 interrupt. */ /* ACK the CS4231 interrupt. */
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&chip->lock, flags);
snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0); snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0);
spin_unlock_irqrestore(&chip->lock, flags); spin_unlock_irqrestore(&chip->lock, flags);
return 0;
} }
#ifdef SBUS_SUPPORT #ifdef SBUS_SUPPORT
static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs) static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
cs4231_t *chip = dev_id; 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. */ /* ACK the APC interrupt. */
u32 csr = sbus_readl(chip->port + APCCSR);
sbus_writel(csr, 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 #endif
...@@ -1290,7 +1301,8 @@ static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substr ...@@ -1290,7 +1301,8 @@ static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substr
#ifdef EBUS_SUPPORT #ifdef EBUS_SUPPORT
} }
#endif #endif
ptr += (period_bytes - residue); ptr += period_bytes - residue;
return bytes_to_frames(substream->runtime, ptr); 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 ...@@ -1314,7 +1326,7 @@ static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substr
#ifdef EBUS_SUPPORT #ifdef EBUS_SUPPORT
} }
#endif #endif
ptr += (period_bytes - residue); ptr += period_bytes - residue;
return bytes_to_frames(substream->runtime, ptr); return bytes_to_frames(substream->runtime, ptr);
} }
...@@ -1328,9 +1340,6 @@ static int snd_cs4231_probe(cs4231_t *chip) ...@@ -1328,9 +1340,6 @@ static int snd_cs4231_probe(cs4231_t *chip)
int i, id, vers; int i, id, vers;
unsigned char *ptr; unsigned char *ptr;
#if 0
snd_cs4231_debug(chip);
#endif
id = vers = 0; id = vers = 0;
for (i = 0; i < 50; i++) { for (i = 0; i < 50; i++) {
mb(); mb();
...@@ -1985,13 +1994,13 @@ static int __init snd_cs4231_sbus_create(snd_card_t *card, ...@@ -1985,13 +1994,13 @@ static int __init snd_cs4231_sbus_create(snd_card_t *card,
chip->port = sbus_ioremap(&sdev->resource[0], 0, chip->port = sbus_ioremap(&sdev->resource[0], 0,
chip->regs_size, "cs4231"); chip->regs_size, "cs4231");
if (!chip->port) { 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; return -EIO;
} }
if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt, if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt,
SA_SHIRQ, "cs4231", chip)) { 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, dev,
__irq_itoa(sdev->irqs[0])); __irq_itoa(sdev->irqs[0]));
snd_cs4231_sbus_free(chip); snd_cs4231_sbus_free(chip);
...@@ -2113,29 +2122,29 @@ static int __init snd_cs4231_ebus_create(snd_card_t *card, ...@@ -2113,29 +2122,29 @@ static int __init snd_cs4231_ebus_create(snd_card_t *card,
chip->eb2c.regs = ioremap(edev->resource[2].start, 0x10); chip->eb2c.regs = ioremap(edev->resource[2].start, 0x10);
if (!chip->port || !chip->eb2p.regs || !chip->eb2c.regs) { if (!chip->port || !chip->eb2p.regs || !chip->eb2c.regs) {
snd_cs4231_ebus_free(chip); 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; return -EIO;
} }
if (ebus_dma_register(&chip->eb2c)) { if (ebus_dma_register(&chip->eb2c)) {
snd_cs4231_ebus_free(chip); 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; return -EBUSY;
} }
if (ebus_dma_irq_enable(&chip->eb2c, 1)) { if (ebus_dma_irq_enable(&chip->eb2c, 1)) {
snd_cs4231_ebus_free(chip); 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; return -EBUSY;
} }
if (ebus_dma_register(&chip->eb2p)) { if (ebus_dma_register(&chip->eb2p)) {
snd_cs4231_ebus_free(chip); 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; return -EBUSY;
} }
if (ebus_dma_irq_enable(&chip->eb2p, 1)) { if (ebus_dma_irq_enable(&chip->eb2p, 1)) {
snd_cs4231_ebus_free(chip); 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; return -EBUSY;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment