Skip to content

Commit

Permalink
ALSA: ctxfi - Use native timer interrupt on emu20k1
Browse files Browse the repository at this point in the history
emu20k1 has a native timer interrupt based on the audio clock, which
is more accurate than the system timer (from the synchronization POV).
This patch adds the code to handle this with multiple streams.

The system timer is still used on emu20k2, and can be used also for
emu20k1 easily by changing USE_SYSTEM_TIMER to 1 in cttimer.c.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Takashi Iwai committed Jun 5, 2009
1 parent 6bc5874 commit b7bbf87
Show file tree
Hide file tree
Showing 9 changed files with 543 additions and 105 deletions.
2 changes: 1 addition & 1 deletion sound/pci/ctxfi/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
snd-ctxfi-objs := xfi.o ctatc.o ctvmem.o ctpcm.o ctmixer.o ctresource.o \
ctsrc.o ctamixer.o ctdaio.o ctimap.o cthardware.o \
ctsrc.o ctamixer.o ctdaio.o ctimap.o cthardware.o cttimer.o \
cthw20k2.o cthw20k1.o

obj-$(CONFIG_SND_CTXFI) += snd-ctxfi.o
2 changes: 2 additions & 0 deletions sound/pci/ctxfi/ct20k1reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,8 @@

#define WC 0x1C6000
#define TIMR 0x1C6004
# define TIMR_IE (1<<15)
# define TIMR_IP (1<<14)

#define GIP 0x1C6010
#define GIE 0x1C6014
Expand Down
21 changes: 20 additions & 1 deletion sound/pci/ctxfi/ctatc.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "ctsrc.h"
#include "ctamixer.h"
#include "ctdaio.h"
#include "cttimer.h"
#include <linux/delay.h>
#include <sound/pcm.h>
#include <sound/control.h>
Expand Down Expand Up @@ -307,6 +308,8 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
src = apcm->src;
}

ct_timer_prepare(apcm->timer);

return 0;

error1:
Expand Down Expand Up @@ -389,6 +392,7 @@ static int atc_pcm_playback_start(struct ct_atc *atc, struct ct_atc_pcm *apcm)
src->ops->set_state(src, SRC_STATE_INIT);
src->ops->commit_write(src);

ct_timer_start(apcm->timer);
return 0;
}

Expand All @@ -397,6 +401,8 @@ static int atc_pcm_stop(struct ct_atc *atc, struct ct_atc_pcm *apcm)
struct src *src = NULL;
int i = 0;

ct_timer_stop(apcm->timer);

src = apcm->src;
src->ops->set_bm(src, 0);
src->ops->set_state(src, SRC_STATE_OFF);
Expand Down Expand Up @@ -701,6 +707,8 @@ static int atc_pcm_capture_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
}
}

ct_timer_prepare(apcm->timer);

return 0;
}

Expand Down Expand Up @@ -749,6 +757,7 @@ static int atc_pcm_capture_start(struct ct_atc *atc, struct ct_atc_pcm *apcm)
/* Enable relevant SRCs synchronously */
src_mgr->commit_write(src_mgr);

ct_timer_start(apcm->timer);
return 0;
}

Expand Down Expand Up @@ -906,6 +915,8 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
dao->ops->set_right_input(dao, &amixer->rsc);
spin_unlock_irqrestore(&atc->atc_lock, flags);

ct_timer_prepare(apcm->timer);

return 0;
}

Expand Down Expand Up @@ -1100,6 +1111,11 @@ static int ct_atc_destroy(struct ct_atc *atc)
if (NULL == atc)
return 0;

if (atc->timer) {
ct_timer_free(atc->timer);
atc->timer = NULL;
}

/* Stop hardware and disable all interrupts */
if (NULL != atc->hw)
((struct hw *)atc->hw)->card_stop(atc->hw);
Expand Down Expand Up @@ -1586,6 +1602,10 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci,
/* Build topology */
atc_connect_resources(atc);

atc->timer = ct_timer_new(atc);
if (!atc->timer)
goto error1;

atc->create_alsa_devs = ct_create_alsa_devs;

err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, atc, &ops);
Expand All @@ -1602,4 +1622,3 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci,
printk(KERN_ERR "ctxfi: Something wrong!!!\n");
return err;
}

9 changes: 5 additions & 4 deletions sound/pci/ctxfi/ctatc.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,15 @@ struct ct_atc_chip_details {
};

struct ct_atc;
struct ct_timer;
struct ct_timer_instance;

/* alsa pcm stream descriptor */
struct ct_atc_pcm {
struct snd_pcm_substream *substream;
void (*interrupt)(struct ct_atc_pcm *apcm);
struct ct_timer_instance *timer;
unsigned int started:1;
unsigned int stop_timer:1;
struct timer_list timer;
spinlock_t timer_lock;
unsigned int position;

/* Only mono and interleaved modes are supported now. */
struct ct_vm_block *vm_block;
Expand Down Expand Up @@ -144,6 +143,8 @@ struct ct_atc {
unsigned char n_src;
unsigned char n_srcimp;
unsigned char n_pcm;

struct ct_timer *timer;
};


Expand Down
19 changes: 19 additions & 0 deletions sound/pci/ctxfi/cthardware.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,12 @@ struct hw {
int (*daio_mgr_set_imapaddr)(void *blk, unsigned int addr);
int (*daio_mgr_commit_write)(struct hw *hw, void *blk);

int (*set_timer_irq)(struct hw *hw, int enable);
int (*set_timer_tick)(struct hw *hw, unsigned int tick);

void (*irq_callback)(void *data, unsigned int bit);
void *irq_callback_data;

struct pci_dev *pci; /* the pci kernel structure of this card */
int irq;
unsigned long io_base;
Expand All @@ -157,4 +163,17 @@ int destroy_hw_obj(struct hw *hw);
unsigned int get_field(unsigned int data, unsigned int field);
void set_field(unsigned int *data, unsigned int field, unsigned int value);

/* IRQ bits */
#define PLL_INT (1 << 10) /* PLL input-clock out-of-range */
#define FI_INT (1 << 9) /* forced interrupt */
#define IT_INT (1 << 8) /* timer interrupt */
#define PCI_INT (1 << 7) /* PCI bus error pending */
#define URT_INT (1 << 6) /* UART Tx/Rx */
#define GPI_INT (1 << 5) /* GPI pin */
#define MIX_INT (1 << 4) /* mixer parameter segment FIFO channels */
#define DAI_INT (1 << 3) /* DAI (SR-tracker or SPDIF-receiver) */
#define TP_INT (1 << 2) /* transport priority queue */
#define DSP_INT (1 << 1) /* DSP */
#define SRC_INT (1 << 0) /* SRC channels */

#endif /* CTHARDWARE_H */
43 changes: 40 additions & 3 deletions sound/pci/ctxfi/cthw20k1.c
Original file line number Diff line number Diff line change
Expand Up @@ -1171,6 +1171,21 @@ static int daio_mgr_put_ctrl_blk(void *blk)
return 0;
}

/* Timer interrupt */
static int set_timer_irq(struct hw *hw, int enable)
{
hw_write_20kx(hw, GIE, enable ? IT_INT : 0);
return 0;
}

static int set_timer_tick(struct hw *hw, unsigned int ticks)
{
if (ticks)
ticks |= TIMR_IE | TIMR_IP;
hw_write_20kx(hw, TIMR, ticks);
return 0;
}

/* Card hardware initialization block */
struct dac_conf {
unsigned int msr; /* master sample rate in rsrs */
Expand Down Expand Up @@ -1878,6 +1893,22 @@ static int uaa_to_xfi(struct pci_dev *pci)
return 0;
}

static irqreturn_t ct_20k1_interrupt(int irq, void *dev_id)
{
struct hw *hw = dev_id;
unsigned int status;

status = hw_read_20kx(hw, GIP);
if (!status)
return IRQ_NONE;

if (hw->irq_callback)
hw->irq_callback(hw->irq_callback_data, status);

hw_write_20kx(hw, GIP, status);
return IRQ_HANDLED;
}

static int hw_card_start(struct hw *hw)
{
int err = 0;
Expand Down Expand Up @@ -1914,12 +1945,13 @@ static int hw_card_start(struct hw *hw)
hw->io_base = pci_resource_start(pci, 0);
}

/*if ((err = request_irq(pci->irq, ct_atc_interrupt, IRQF_SHARED,
atc->chip_details->nm_card, hw))) {
err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED,
"ctxfi", hw);
if (err < 0) {
printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
goto error2;
}
hw->irq = pci->irq;
*/

pci_set_master(pci);

Expand All @@ -1936,6 +1968,8 @@ static int hw_card_start(struct hw *hw)
static int hw_card_stop(struct hw *hw)
{
/* TODO: Disable interrupt and so on... */
if (hw->irq >= 0)
synchronize_irq(hw->irq);
return 0;
}

Expand Down Expand Up @@ -2215,6 +2249,9 @@ int create_20k1_hw_obj(struct hw **rhw)
hw->daio_mgr_set_imapaddr = daio_mgr_set_imapaddr;
hw->daio_mgr_commit_write = daio_mgr_commit_write;

hw->set_timer_irq = set_timer_irq;
hw->set_timer_tick = set_timer_tick;

*rhw = hw;

return 0;
Expand Down
Loading

0 comments on commit b7bbf87

Please sign in to comment.