Commit b128254f authored by Georg Chini's avatar Georg Chini Committed by David S. Miller

[SPARC]: More abstractions and cleanups of dma handling in cs4231.

From: Georg Chini <georg.chini@triaton-webhosting.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent dedeb002
...@@ -79,6 +79,7 @@ extern int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr, ...@@ -79,6 +79,7 @@ extern int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr,
size_t len); size_t len);
extern void ebus_dma_prepare(struct ebus_dma_info *p, int write); extern void ebus_dma_prepare(struct ebus_dma_info *p, int write);
extern unsigned int ebus_dma_residue(struct ebus_dma_info *p); extern unsigned int ebus_dma_residue(struct ebus_dma_info *p);
extern unsigned int ebus_dma_addr(struct ebus_dma_info *p);
extern void ebus_dma_enable(struct ebus_dma_info *p, int on); extern void ebus_dma_enable(struct ebus_dma_info *p, int on);
extern struct linux_ebus *ebus_chain; extern struct linux_ebus *ebus_chain;
......
...@@ -62,25 +62,36 @@ MODULE_LICENSE("GPL"); ...@@ -62,25 +62,36 @@ MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Sun,CS4231}}"); MODULE_SUPPORTED_DEVICE("{{Sun,CS4231}}");
#ifdef SBUS_SUPPORT #ifdef SBUS_SUPPORT
struct sbus_dma_info { typedef struct sbus_dma_info {
spinlock_t lock; spinlock_t lock;
int dir; int dir;
void __iomem *regs; void __iomem *regs;
}; } sbus_dma_info_t;
#endif #endif
typedef struct snd_cs4231 { typedef struct snd_cs4231 cs4231_t;
spinlock_t lock;
void __iomem *port; typedef struct cs4231_dma_control {
void (*prepare)(struct cs4231_dma_control *dma_cont, int dir);
void (*enable)(struct cs4231_dma_control *dma_cont, int on);
int (*request)(struct cs4231_dma_control *dma_cont, dma_addr_t bus_addr, size_t len);
unsigned int (*address)(struct cs4231_dma_control *dma_cont);
void (*reset)(cs4231_t *chip);
void (*preallocate)(cs4231_t *chip, snd_pcm_t *pcm);
#ifdef EBUS_SUPPORT #ifdef EBUS_SUPPORT
struct ebus_dma_info eb2c; struct ebus_dma_info ebus_info;
struct ebus_dma_info eb2p;
#endif #endif
#ifdef SBUS_SUPPORT #ifdef SBUS_SUPPORT
struct sbus_dma_info sb2c; struct sbus_dma_info sbus_info;
struct sbus_dma_info sb2p;
#endif #endif
} cs4231_dma_control_t;
struct snd_cs4231 {
spinlock_t lock;
void __iomem *port;
cs4231_dma_control_t p_dma;
cs4231_dma_control_t c_dma;
u32 flags; u32 flags;
#define CS4231_FLAG_EBUS 0x00000001 #define CS4231_FLAG_EBUS 0x00000001
...@@ -119,7 +130,7 @@ typedef struct snd_cs4231 { ...@@ -119,7 +130,7 @@ typedef struct snd_cs4231 {
unsigned int irq[2]; unsigned int irq[2];
unsigned int regs_size; unsigned int regs_size;
struct snd_cs4231 *next; struct snd_cs4231 *next;
} cs4231_t; };
static cs4231_t *cs4231_list; static cs4231_t *cs4231_list;
...@@ -493,103 +504,6 @@ static unsigned char snd_cs4231_in(cs4231_t *chip, unsigned char reg) ...@@ -493,103 +504,6 @@ static unsigned char snd_cs4231_in(cs4231_t *chip, unsigned char reg)
return ret; return ret;
} }
/*
* SBUS DMA routines
*/
#ifdef SBUS_SUPPORT
int sbus_dma_request(struct sbus_dma_info *base, dma_addr_t bus_addr, size_t len)
{
unsigned long flags;
u32 test, csr;
int err;
if (len >= (1 << 24))
return -EINVAL;
spin_lock_irqsave(&base->lock, flags);
csr = sbus_readl(base->regs + APCCSR);
err = -EINVAL;
test = APC_CDMA_READY;
if ( base->dir == APC_PLAY )
test = APC_PDMA_READY;
if (!(csr & test))
goto out;
err = -EBUSY;
csr = sbus_readl(base->regs + APCCSR);
test = APC_XINT_CNVA;
if ( base->dir == APC_PLAY )
test = APC_XINT_PNVA;
if (!(csr & test))
goto out;
err = 0;
sbus_writel(bus_addr, base->regs + base->dir + APCNVA);
sbus_writel(len, base->regs + base->dir + APCNC);
out:
spin_unlock_irqrestore(&base->lock, flags);
return err;
}
void sbus_dma_prepare(struct sbus_dma_info *base)
{
unsigned long flags;
u32 csr, test;
spin_lock_irqsave(&base->lock, flags);
csr = sbus_readl(base->regs + APCCSR);
test = APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA |
APC_XINT_PLAY | APC_XINT_PEMP | APC_XINT_GENL |
APC_XINT_PENA;
if ( base->dir == APC_RECORD )
test = APC_GENL_INT | APC_CAPT_INT | APC_XINT_ENA |
APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL;
csr |= test;
sbus_writel(csr, base->regs + APCCSR);
spin_unlock_irqrestore(&base->lock, flags);
}
void sbus_dma_enable(struct sbus_dma_info *base, int on)
{
unsigned long flags;
u32 csr, shift;
spin_lock_irqsave(&base->lock, flags);
if (!on) {
if (base->dir == APC_PLAY) {
sbus_writel(0, base->regs + base->dir + APCNVA);
sbus_writel(1, base->regs + base->dir + APCC);
}
else
{
sbus_writel(0, base->regs + base->dir + APCNC);
sbus_writel(0, base->regs + base->dir + APCVA);
}
}
udelay(500);
csr = sbus_readl(base->regs + APCCSR);
shift = 0;
if ( base->dir == APC_PLAY )
shift = 1;
if (on)
csr &= ~(APC_CPAUSE << shift);
else
csr |= (APC_CPAUSE << shift);
sbus_writel(csr, base->regs + APCCSR);
if (on)
csr |= (APC_CDMA_READY << shift);
else
csr &= ~(APC_CDMA_READY << shift);
sbus_writel(csr, base->regs + APCCSR);
spin_unlock_irqrestore(&base->lock, flags);
}
unsigned int sbus_dma_addr(struct sbus_dma_info *base)
{
return sbus_readl(base->regs + base->dir + APCVA);
}
#endif
/* /*
* CS4231 detection / MCE routines * CS4231 detection / MCE routines
*/ */
...@@ -688,8 +602,7 @@ static void snd_cs4231_mce_down(cs4231_t *chip) ...@@ -688,8 +602,7 @@ static void snd_cs4231_mce_down(cs4231_t *chip)
spin_unlock_irqrestore(&chip->lock, flags); spin_unlock_irqrestore(&chip->lock, flags);
} }
#ifdef EBUS_SUPPORT static void snd_cs4231_advance_dma(struct cs4231_dma_control *dma_cont, 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;
...@@ -700,89 +613,41 @@ static void snd_cs4231_ebus_advance_dma(struct ebus_dma_info *p, snd_pcm_substre ...@@ -700,89 +613,41 @@ static void snd_cs4231_ebus_advance_dma(struct ebus_dma_info *p, snd_pcm_substre
if (period_size >= (1 << 24)) if (period_size >= (1 << 24))
BUG(); BUG();
if (ebus_dma_request(p, runtime->dma_addr + offset, period_size)) if (dma_cont->request(dma_cont, runtime->dma_addr + offset, period_size))
return; return;
(*periods_sent) = ((*periods_sent) + 1) % runtime->periods; (*periods_sent) = ((*periods_sent) + 1) % runtime->periods;
} }
} }
#endif
#ifdef SBUS_SUPPORT
static void snd_cs4231_sbus_advance_dma(struct sbus_dma_info *p, snd_pcm_substream_t *substream, unsigned int *periods_sent)
{
snd_pcm_runtime_t *runtime = substream->runtime;
while (1) {
unsigned int period_size = snd_pcm_lib_period_bytes(substream);
unsigned int offset = period_size * (*periods_sent);
if (period_size > 0xffff + 1)
BUG();
if (sbus_dma_request(p, runtime->dma_addr + offset, period_size))
return;
(*periods_sent) = (*periods_sent + 1) % runtime->periods;
}
}
#endif
static void cs4231_dma_trigger(snd_pcm_substream_t *substream, unsigned int what, int on) static void cs4231_dma_trigger(snd_pcm_substream_t *substream, unsigned int what, int on)
{ {
cs4231_t *chip = snd_pcm_substream_chip(substream); cs4231_t *chip = snd_pcm_substream_chip(substream);
cs4231_dma_control_t *dma_cont;
#ifdef EBUS_SUPPORT
if (chip->flags & CS4231_FLAG_EBUS) {
if (what & CS4231_PLAYBACK_ENABLE) {
if (on) {
ebus_dma_prepare(&chip->eb2p, 0);
ebus_dma_enable(&chip->eb2p, 1);
snd_cs4231_ebus_advance_dma(&chip->eb2p,
chip->playback_substream,
&chip->p_periods_sent);
} else {
ebus_dma_enable(&chip->eb2p, 0);
}
}
if (what & CS4231_RECORD_ENABLE) {
if (on) {
ebus_dma_prepare(&chip->eb2c, 1);
ebus_dma_enable(&chip->eb2c, 1);
snd_cs4231_ebus_advance_dma(&chip->eb2c,
chip->capture_substream,
&chip->c_periods_sent);
} else {
ebus_dma_enable(&chip->eb2c, 0);
}
}
} else {
#endif
#ifdef SBUS_SUPPORT
if (what & CS4231_PLAYBACK_ENABLE) { if (what & CS4231_PLAYBACK_ENABLE) {
dma_cont = &chip->p_dma;
if (on) { if (on) {
sbus_dma_prepare(&chip->sb2p); dma_cont->prepare(dma_cont, 0);
sbus_dma_enable(&chip->sb2p, 1); dma_cont->enable(dma_cont, 1);
snd_cs4231_sbus_advance_dma(&chip->sb2p, snd_cs4231_advance_dma(dma_cont,
chip->playback_substream, chip->playback_substream,
&chip->p_periods_sent); &chip->p_periods_sent);
} else { } else {
sbus_dma_enable(&chip->sb2p, 0); dma_cont->enable(dma_cont, 0);
} }
} }
if (what & CS4231_RECORD_ENABLE) { if (what & CS4231_RECORD_ENABLE) {
dma_cont = &chip->c_dma;
if (on) { if (on) {
sbus_dma_prepare(&chip->sb2c); dma_cont->prepare(dma_cont, 1);
sbus_dma_enable(&chip->sb2c, 1); dma_cont->enable(dma_cont, 1);
snd_cs4231_sbus_advance_dma(&chip->sb2c, snd_cs4231_advance_dma(dma_cont,
chip->capture_substream, chip->capture_substream,
&chip->c_periods_sent); &chip->c_periods_sent);
} else { } else {
sbus_dma_enable(&chip->sb2c, 0); dma_cont->enable(dma_cont, 0);
} }
} }
#endif
#ifdef EBUS_SUPPORT
}
#endif
} }
static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd) static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd)
...@@ -1273,140 +1138,55 @@ static void snd_cs4231_overrange(cs4231_t *chip) ...@@ -1273,140 +1138,55 @@ static void snd_cs4231_overrange(cs4231_t *chip)
chip->capture_substream->runtime->overrange++; chip->capture_substream->runtime->overrange++;
} }
#ifdef SBUS_SUPPORT static void snd_cs4231_play_callback(cs4231_t *cookie)
static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long flags;
unsigned char status;
u32 csr;
cs4231_t *chip = dev_id;
/*This is IRQ is not raised by the cs4231*/
if (!(__cs4231_readb(chip, CS4231P(chip, STATUS)) & CS4231_GLOBALIRQ))
return IRQ_NONE;
/* ACK the APC interrupt. */
csr = sbus_readl(chip->port + APCCSR);
sbus_writel(csr, chip->port + APCCSR);
if ((chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) &&
(csr & APC_PLAY_INT) &&
(csr & APC_XINT_PNVA) &&
!(csr & APC_XINT_EMPT)) {
snd_pcm_period_elapsed(chip->playback_substream);
snd_cs4231_sbus_advance_dma(&chip->sb2p, chip->playback_substream,
&chip->p_periods_sent);
}
if ((chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) &&
(csr & APC_CAPT_INT) &&
(csr & APC_XINT_CNVA) &&
!(csr & APC_XINT_EMPT)) {
snd_pcm_period_elapsed(chip->capture_substream);
snd_cs4231_sbus_advance_dma(&chip->sb2c,chip->capture_substream,
&chip->c_periods_sent);
}
status = snd_cs4231_in(chip, CS4231_IRQ_STATUS);
if (status & CS4231_TIMER_IRQ) {
if (chip->timer)
snd_timer_interrupt(chip->timer, chip->timer->sticks);
}
if (status & CS4231_RECORD_IRQ)
snd_cs4231_overrange(chip);
/* 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;
}
#endif
#ifdef EBUS_SUPPORT
static void snd_cs4231_ebus_play_callback(struct ebus_dma_info *p, int event, void *cookie)
{ {
cs4231_t *chip = cookie; cs4231_t *chip = cookie;
if (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) { if (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) {
snd_pcm_period_elapsed(chip->playback_substream); snd_pcm_period_elapsed(chip->playback_substream);
snd_cs4231_ebus_advance_dma(p, chip->playback_substream, snd_cs4231_advance_dma(&chip->p_dma, chip->playback_substream,
&chip->p_periods_sent); &chip->p_periods_sent);
} }
} }
static void snd_cs4231_ebus_capture_callback(struct ebus_dma_info *p, int event, void *cookie) static void snd_cs4231_capture_callback(cs4231_t *cookie)
{ {
cs4231_t *chip = cookie; cs4231_t *chip = cookie;
if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) { if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) {
snd_pcm_period_elapsed(chip->capture_substream); snd_pcm_period_elapsed(chip->capture_substream);
snd_cs4231_ebus_advance_dma(p, chip->capture_substream, snd_cs4231_advance_dma(&chip->c_dma, chip->capture_substream,
&chip->c_periods_sent); &chip->c_periods_sent);
} }
} }
#endif
static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substream) static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substream)
{ {
cs4231_t *chip = snd_pcm_substream_chip(substream); cs4231_t *chip = snd_pcm_substream_chip(substream);
cs4231_dma_control_t *dma_cont = &chip->p_dma;
size_t ptr; size_t ptr;
#ifdef EBUS_SUPPORT
size_t residue, period_bytes;
#endif
if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE))
return 0; return 0;
#ifdef EBUS_SUPPORT ptr = dma_cont->address(dma_cont);
period_bytes = snd_pcm_lib_period_bytes(substream); if (ptr != 0)
ptr = period_bytes * chip->p_periods_sent; ptr -= substream->runtime->dma_addr;
if (chip->flags & CS4231_FLAG_EBUS) {
residue = ebus_dma_residue(&chip->eb2p);
ptr += period_bytes - residue;
} else {
#endif
#ifdef SBUS_SUPPORT
ptr = sbus_dma_addr(&chip->sb2p);
if (ptr != 0)
ptr -= substream->runtime->dma_addr;
#endif
#ifdef EBUS_SUPPORT
}
#endif
return bytes_to_frames(substream->runtime, ptr); return bytes_to_frames(substream->runtime, ptr);
} }
static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substream) static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substream)
{ {
cs4231_t *chip = snd_pcm_substream_chip(substream); cs4231_t *chip = snd_pcm_substream_chip(substream);
cs4231_dma_control_t *dma_cont = &chip->c_dma;
size_t ptr; size_t ptr;
#ifdef EBUS_SUPPORT
size_t residue, period_bytes;
#endif
if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE)) if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE))
return 0; return 0;
#ifdef EBUS_SUPPORT ptr = dma_cont->address(dma_cont);
period_bytes = snd_pcm_lib_period_bytes(substream); if (ptr != 0)
ptr = period_bytes * chip->c_periods_sent; ptr -= substream->runtime->dma_addr;
if (chip->flags & CS4231_FLAG_EBUS) {
residue = ebus_dma_residue(&chip->eb2c);
ptr += period_bytes - residue;
} else {
#endif
#ifdef SBUS_SUPPORT
ptr = sbus_dma_addr(&chip->sb2c);
if (ptr != 0)
ptr -= substream->runtime->dma_addr;
#endif
#ifdef EBUS_SUPPORT
}
#endif
return bytes_to_frames(substream->runtime, ptr); return bytes_to_frames(substream->runtime, ptr);
} }
...@@ -1442,30 +1222,8 @@ static int snd_cs4231_probe(cs4231_t *chip) ...@@ -1442,30 +1222,8 @@ static int snd_cs4231_probe(cs4231_t *chip)
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&chip->lock, flags);
/* Reset DMA engine. */ /* Reset DMA engine (sbus only). */
#ifdef EBUS_SUPPORT chip->p_dma.reset(chip);
if (chip->flags & CS4231_FLAG_EBUS) {
/* Done by ebus_dma_register */
} else {
#endif
#ifdef SBUS_SUPPORT
sbus_writel(APC_CHIP_RESET, chip->port + APCCSR);
sbus_writel(0x00, chip->port + APCCSR);
sbus_writel(sbus_readl(chip->port + APCCSR) | APC_CDC_RESET,
chip->port + APCCSR);
udelay(20);
sbus_writel(sbus_readl(chip->port + APCCSR) & ~APC_CDC_RESET,
chip->port + APCCSR);
sbus_writel(sbus_readl(chip->port + APCCSR) | (APC_XINT_ENA |
APC_XINT_PENA |
APC_XINT_CENA),
chip->port + APCCSR);
#endif
#ifdef EBUS_SUPPORT
}
#endif
__cs4231_readb(chip, CS4231P(chip, STATUS)); /* clear any pendings IRQ */ __cs4231_readb(chip, CS4231P(chip, STATUS)); /* clear any pendings IRQ */
__cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); __cs4231_writeb(chip, 0, CS4231P(chip, STATUS));
...@@ -1585,8 +1343,8 @@ static int snd_cs4231_playback_close(snd_pcm_substream_t *substream) ...@@ -1585,8 +1343,8 @@ static int snd_cs4231_playback_close(snd_pcm_substream_t *substream)
{ {
cs4231_t *chip = snd_pcm_substream_chip(substream); cs4231_t *chip = snd_pcm_substream_chip(substream);
chip->playback_substream = NULL;
snd_cs4231_close(chip, CS4231_MODE_PLAY); snd_cs4231_close(chip, CS4231_MODE_PLAY);
chip->playback_substream = NULL;
return 0; return 0;
} }
...@@ -1595,8 +1353,8 @@ static int snd_cs4231_capture_close(snd_pcm_substream_t *substream) ...@@ -1595,8 +1353,8 @@ static int snd_cs4231_capture_close(snd_pcm_substream_t *substream)
{ {
cs4231_t *chip = snd_pcm_substream_chip(substream); cs4231_t *chip = snd_pcm_substream_chip(substream);
chip->capture_substream = NULL;
snd_cs4231_close(chip, CS4231_MODE_RECORD); snd_cs4231_close(chip, CS4231_MODE_RECORD);
chip->capture_substream = NULL;
return 0; return 0;
} }
...@@ -1651,21 +1409,7 @@ int snd_cs4231_pcm(cs4231_t *chip) ...@@ -1651,21 +1409,7 @@ int snd_cs4231_pcm(cs4231_t *chip)
pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
strcpy(pcm->name, "CS4231"); strcpy(pcm->name, "CS4231");
#ifdef EBUS_SUPPORT chip->p_dma.preallocate(chip, pcm);
if (chip->flags & CS4231_FLAG_EBUS) {
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->dev_u.pdev),
64*1024, 128*1024);
} else {
#endif
#ifdef SBUS_SUPPORT
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS,
snd_dma_sbus_data(chip->dev_u.sdev),
64*1024, 128*1024);
#endif
#ifdef EBUS_SUPPORT
}
#endif
chip->pcm = pcm; chip->pcm = pcm;
...@@ -2022,6 +1766,180 @@ out_err: ...@@ -2022,6 +1766,180 @@ out_err:
} }
#ifdef SBUS_SUPPORT #ifdef SBUS_SUPPORT
static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long flags;
unsigned char status;
u32 csr;
cs4231_t *chip = dev_id;
/*This is IRQ is not raised by the cs4231*/
if (!(__cs4231_readb(chip, CS4231P(chip, STATUS)) & CS4231_GLOBALIRQ))
return IRQ_NONE;
/* ACK the APC interrupt. */
csr = sbus_readl(chip->port + APCCSR);
sbus_writel(csr, chip->port + APCCSR);
if ((csr & APC_PDMA_READY) &&
(csr & APC_PLAY_INT) &&
(csr & APC_XINT_PNVA) &&
!(csr & APC_XINT_EMPT))
snd_cs4231_play_callback(chip);
if ((csr & APC_CDMA_READY) &&
(csr & APC_CAPT_INT) &&
(csr & APC_XINT_CNVA) &&
!(csr & APC_XINT_EMPT))
snd_cs4231_capture_callback(chip);
status = snd_cs4231_in(chip, CS4231_IRQ_STATUS);
if (status & CS4231_TIMER_IRQ) {
if (chip->timer)
snd_timer_interrupt(chip->timer, chip->timer->sticks);
}
if ((status & CS4231_RECORD_IRQ) && (csr & APC_CDMA_READY))
snd_cs4231_overrange(chip);
/* 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;
}
/*
* SBUS DMA routines
*/
int sbus_dma_request(struct cs4231_dma_control *dma_cont, dma_addr_t bus_addr, size_t len)
{
unsigned long flags;
u32 test, csr;
int err;
sbus_dma_info_t *base = &dma_cont->sbus_info;
if (len >= (1 << 24))
return -EINVAL;
spin_lock_irqsave(&base->lock, flags);
csr = sbus_readl(base->regs + APCCSR);
err = -EINVAL;
test = APC_CDMA_READY;
if ( base->dir == APC_PLAY )
test = APC_PDMA_READY;
if (!(csr & test))
goto out;
err = -EBUSY;
csr = sbus_readl(base->regs + APCCSR);
test = APC_XINT_CNVA;
if ( base->dir == APC_PLAY )
test = APC_XINT_PNVA;
if (!(csr & test))
goto out;
err = 0;
sbus_writel(bus_addr, base->regs + base->dir + APCNVA);
sbus_writel(len, base->regs + base->dir + APCNC);
out:
spin_unlock_irqrestore(&base->lock, flags);
return err;
}
void sbus_dma_prepare(struct cs4231_dma_control *dma_cont, int d)
{
unsigned long flags;
u32 csr, test;
sbus_dma_info_t *base = &dma_cont->sbus_info;
spin_lock_irqsave(&base->lock, flags);
csr = sbus_readl(base->regs + APCCSR);
test = APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA |
APC_XINT_PLAY | APC_XINT_PEMP | APC_XINT_GENL |
APC_XINT_PENA;
if ( base->dir == APC_RECORD )
test = APC_GENL_INT | APC_CAPT_INT | APC_XINT_ENA |
APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL;
csr |= test;
sbus_writel(csr, base->regs + APCCSR);
spin_unlock_irqrestore(&base->lock, flags);
}
void sbus_dma_enable(struct cs4231_dma_control *dma_cont, int on)
{
unsigned long flags;
u32 csr, shift;
sbus_dma_info_t *base = &dma_cont->sbus_info;
spin_lock_irqsave(&base->lock, flags);
if (!on) {
if (base->dir == APC_PLAY) {
sbus_writel(0, base->regs + base->dir + APCNVA);
sbus_writel(1, base->regs + base->dir + APCC);
}
else
{
sbus_writel(0, base->regs + base->dir + APCNC);
sbus_writel(0, base->regs + base->dir + APCVA);
}
}
udelay(600);
csr = sbus_readl(base->regs + APCCSR);
shift = 0;
if ( base->dir == APC_PLAY )
shift = 1;
if (on)
csr &= ~(APC_CPAUSE << shift);
else
csr |= (APC_CPAUSE << shift);
sbus_writel(csr, base->regs + APCCSR);
if (on)
csr |= (APC_CDMA_READY << shift);
else
csr &= ~(APC_CDMA_READY << shift);
sbus_writel(csr, base->regs + APCCSR);
spin_unlock_irqrestore(&base->lock, flags);
}
unsigned int sbus_dma_addr(struct cs4231_dma_control *dma_cont)
{
sbus_dma_info_t *base = &dma_cont->sbus_info;
return sbus_readl(base->regs + base->dir + APCVA);
}
void sbus_dma_reset(cs4231_t *chip)
{
sbus_writel(APC_CHIP_RESET, chip->port + APCCSR);
sbus_writel(0x00, chip->port + APCCSR);
sbus_writel(sbus_readl(chip->port + APCCSR) | APC_CDC_RESET,
chip->port + APCCSR);
udelay(20);
sbus_writel(sbus_readl(chip->port + APCCSR) & ~APC_CDC_RESET,
chip->port + APCCSR);
sbus_writel(sbus_readl(chip->port + APCCSR) | (APC_XINT_ENA |
APC_XINT_PENA |
APC_XINT_CENA),
chip->port + APCCSR);
}
void sbus_dma_preallocate(cs4231_t *chip, snd_pcm_t *pcm)
{
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS,
snd_dma_sbus_data(chip->dev_u.sdev),
64*1024, 128*1024);
}
/*
* Init and exit routines
*/
static int snd_cs4231_sbus_free(cs4231_t *chip) static int snd_cs4231_sbus_free(cs4231_t *chip)
{ {
if (chip->irq[0]) if (chip->irq[0])
...@@ -2063,8 +1981,8 @@ static int __init snd_cs4231_sbus_create(snd_card_t *card, ...@@ -2063,8 +1981,8 @@ static int __init snd_cs4231_sbus_create(snd_card_t *card,
return -ENOMEM; return -ENOMEM;
spin_lock_init(&chip->lock); spin_lock_init(&chip->lock);
spin_lock_init(&chip->sb2c.lock); spin_lock_init(&chip->c_dma.sbus_info.lock);
spin_lock_init(&chip->sb2p.lock); spin_lock_init(&chip->p_dma.sbus_info.lock);
init_MUTEX(&chip->mce_mutex); init_MUTEX(&chip->mce_mutex);
init_MUTEX(&chip->open_mutex); init_MUTEX(&chip->open_mutex);
chip->card = card; chip->card = card;
...@@ -2080,10 +1998,24 @@ static int __init snd_cs4231_sbus_create(snd_card_t *card, ...@@ -2080,10 +1998,24 @@ static int __init snd_cs4231_sbus_create(snd_card_t *card,
return -EIO; return -EIO;
} }
chip->sb2c.regs = chip->port; chip->c_dma.sbus_info.regs = chip->port;
chip->sb2p.regs = chip->port; chip->p_dma.sbus_info.regs = chip->port;
chip->sb2c.dir = APC_RECORD; chip->c_dma.sbus_info.dir = APC_RECORD;
chip->sb2p.dir = APC_PLAY; chip->p_dma.sbus_info.dir = APC_PLAY;
chip->p_dma.prepare = sbus_dma_prepare;
chip->p_dma.enable = sbus_dma_enable;
chip->p_dma.request = sbus_dma_request;
chip->p_dma.address = sbus_dma_addr;
chip->p_dma.reset = sbus_dma_reset;
chip->p_dma.preallocate = sbus_dma_preallocate;
chip->c_dma.prepare = sbus_dma_prepare;
chip->c_dma.enable = sbus_dma_enable;
chip->c_dma.request = sbus_dma_request;
chip->c_dma.address = sbus_dma_addr;
chip->c_dma.reset = sbus_dma_reset;
chip->c_dma.preallocate = sbus_dma_preallocate;
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)) {
...@@ -2138,15 +2070,70 @@ static int cs4231_sbus_attach(struct sbus_dev *sdev) ...@@ -2138,15 +2070,70 @@ static int cs4231_sbus_attach(struct sbus_dev *sdev)
#endif #endif
#ifdef EBUS_SUPPORT #ifdef EBUS_SUPPORT
static void snd_cs4231_ebus_play_callback(struct ebus_dma_info *p, int event, void *cookie)
{
cs4231_t *chip = cookie;
snd_cs4231_play_callback(chip);
}
static void snd_cs4231_ebus_capture_callback(struct ebus_dma_info *p, int event, void *cookie)
{
cs4231_t *chip = cookie;
snd_cs4231_capture_callback(chip);
}
/*
* EBUS DMA wrappers
*/
int _ebus_dma_request(struct cs4231_dma_control *dma_cont, dma_addr_t bus_addr, size_t len)
{
return ebus_dma_request(&dma_cont->ebus_info, bus_addr, len);
}
void _ebus_dma_enable(struct cs4231_dma_control *dma_cont, int on)
{
ebus_dma_enable(&dma_cont->ebus_info, on);
}
void _ebus_dma_prepare(struct cs4231_dma_control *dma_cont, int dir)
{
ebus_dma_prepare(&dma_cont->ebus_info, dir);
}
unsigned int _ebus_dma_addr(struct cs4231_dma_control *dma_cont)
{
return ebus_dma_addr(&dma_cont->ebus_info);
}
void _ebus_dma_reset(cs4231_t *chip)
{
return;
}
void _ebus_dma_preallocate(cs4231_t *chip, snd_pcm_t *pcm)
{
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->dev_u.pdev),
64*1024, 128*1024);
}
/*
* Init and exit routines
*/
static int snd_cs4231_ebus_free(cs4231_t *chip) static int snd_cs4231_ebus_free(cs4231_t *chip)
{ {
if (chip->eb2c.regs) { if (chip->c_dma.ebus_info.regs) {
ebus_dma_unregister(&chip->eb2c); ebus_dma_unregister(&chip->c_dma.ebus_info);
iounmap(chip->eb2c.regs); iounmap(chip->c_dma.ebus_info.regs);
} }
if (chip->eb2p.regs) { if (chip->p_dma.ebus_info.regs) {
ebus_dma_unregister(&chip->eb2p); ebus_dma_unregister(&chip->p_dma.ebus_info);
iounmap(chip->eb2p.regs); iounmap(chip->p_dma.ebus_info.regs);
} }
if (chip->port) if (chip->port)
...@@ -2184,8 +2171,8 @@ static int __init snd_cs4231_ebus_create(snd_card_t *card, ...@@ -2184,8 +2171,8 @@ static int __init snd_cs4231_ebus_create(snd_card_t *card,
return -ENOMEM; return -ENOMEM;
spin_lock_init(&chip->lock); spin_lock_init(&chip->lock);
spin_lock_init(&chip->eb2c.lock); spin_lock_init(&chip->c_dma.ebus_info.lock);
spin_lock_init(&chip->eb2p.lock); spin_lock_init(&chip->p_dma.ebus_info.lock);
init_MUTEX(&chip->mce_mutex); init_MUTEX(&chip->mce_mutex);
init_MUTEX(&chip->open_mutex); init_MUTEX(&chip->open_mutex);
chip->flags |= CS4231_FLAG_EBUS; chip->flags |= CS4231_FLAG_EBUS;
...@@ -2193,43 +2180,57 @@ static int __init snd_cs4231_ebus_create(snd_card_t *card, ...@@ -2193,43 +2180,57 @@ static int __init snd_cs4231_ebus_create(snd_card_t *card,
chip->dev_u.pdev = edev->bus->self; chip->dev_u.pdev = edev->bus->self;
memcpy(&chip->image, &snd_cs4231_original_image, memcpy(&chip->image, &snd_cs4231_original_image,
sizeof(snd_cs4231_original_image)); sizeof(snd_cs4231_original_image));
strcpy(chip->eb2c.name, "cs4231(capture)"); strcpy(chip->c_dma.ebus_info.name, "cs4231(capture)");
chip->eb2c.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER; chip->c_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
chip->eb2c.callback = snd_cs4231_ebus_capture_callback; chip->c_dma.ebus_info.callback = snd_cs4231_ebus_capture_callback;
chip->eb2c.client_cookie = chip; chip->c_dma.ebus_info.client_cookie = chip;
chip->eb2c.irq = edev->irqs[0]; chip->c_dma.ebus_info.irq = edev->irqs[0];
strcpy(chip->eb2p.name, "cs4231(play)"); strcpy(chip->p_dma.ebus_info.name, "cs4231(play)");
chip->eb2p.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER; chip->p_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
chip->eb2p.callback = snd_cs4231_ebus_play_callback; chip->p_dma.ebus_info.callback = snd_cs4231_ebus_play_callback;
chip->eb2p.client_cookie = chip; chip->p_dma.ebus_info.client_cookie = chip;
chip->eb2p.irq = edev->irqs[1]; chip->p_dma.ebus_info.irq = edev->irqs[1];
chip->p_dma.prepare = _ebus_dma_prepare;
chip->p_dma.enable = _ebus_dma_enable;
chip->p_dma.request = _ebus_dma_request;
chip->p_dma.address = _ebus_dma_addr;
chip->p_dma.reset = _ebus_dma_reset;
chip->p_dma.preallocate = _ebus_dma_preallocate;
chip->c_dma.prepare = _ebus_dma_prepare;
chip->c_dma.enable = _ebus_dma_enable;
chip->c_dma.request = _ebus_dma_request;
chip->c_dma.address = _ebus_dma_addr;
chip->c_dma.reset = _ebus_dma_reset;
chip->c_dma.preallocate = _ebus_dma_preallocate;
chip->port = ioremap(edev->resource[0].start, 0x10); chip->port = ioremap(edev->resource[0].start, 0x10);
chip->eb2p.regs = ioremap(edev->resource[1].start, 0x10); chip->p_dma.ebus_info.regs = ioremap(edev->resource[1].start, 0x10);
chip->eb2c.regs = ioremap(edev->resource[2].start, 0x10); chip->c_dma.ebus_info.regs = ioremap(edev->resource[2].start, 0x10);
if (!chip->port || !chip->eb2p.regs || !chip->eb2c.regs) { if (!chip->port || !chip->p_dma.ebus_info.regs || !chip->c_dma.ebus_info.regs) {
snd_cs4231_ebus_free(chip); snd_cs4231_ebus_free(chip);
snd_printdd("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->c_dma.ebus_info)) {
snd_cs4231_ebus_free(chip); snd_cs4231_ebus_free(chip);
snd_printdd("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->c_dma.ebus_info, 1)) {
snd_cs4231_ebus_free(chip); snd_cs4231_ebus_free(chip);
snd_printdd("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->p_dma.ebus_info)) {
snd_cs4231_ebus_free(chip); snd_cs4231_ebus_free(chip);
snd_printdd("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->p_dma.ebus_info, 1)) {
snd_cs4231_ebus_free(chip); snd_cs4231_ebus_free(chip);
snd_printdd("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