Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b7bbf876 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: ctxfi - Use native timer interrupt on emu20k1



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: default avatarTakashi Iwai <tiwai@suse.de>
parent 6bc5874a
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
snd-ctxfi-objs := xfi.o ctatc.o ctvmem.o ctpcm.o ctmixer.o ctresource.o \
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
	cthw20k2.o cthw20k1.o


obj-$(CONFIG_SND_CTXFI) += snd-ctxfi.o
obj-$(CONFIG_SND_CTXFI) += snd-ctxfi.o
+2 −0
Original line number Original line Diff line number Diff line
@@ -589,6 +589,8 @@


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


#define		GIP		0x1C6010
#define		GIP		0x1C6010
#define		GIE		0x1C6014
#define		GIE		0x1C6014
+20 −1
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@
#include "ctsrc.h"
#include "ctsrc.h"
#include "ctamixer.h"
#include "ctamixer.h"
#include "ctdaio.h"
#include "ctdaio.h"
#include "cttimer.h"
#include <linux/delay.h>
#include <linux/delay.h>
#include <sound/pcm.h>
#include <sound/pcm.h>
#include <sound/control.h>
#include <sound/control.h>
@@ -307,6 +308,8 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
			src = apcm->src;
			src = apcm->src;
	}
	}


	ct_timer_prepare(apcm->timer);

	return 0;
	return 0;


error1:
error1:
@@ -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->set_state(src, SRC_STATE_INIT);
	src->ops->commit_write(src);
	src->ops->commit_write(src);


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


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


	ct_timer_stop(apcm->timer);

	src = apcm->src;
	src = apcm->src;
	src->ops->set_bm(src, 0);
	src->ops->set_bm(src, 0);
	src->ops->set_state(src, SRC_STATE_OFF);
	src->ops->set_state(src, SRC_STATE_OFF);
@@ -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;
	return 0;
}
}


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


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


@@ -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);
	dao->ops->set_right_input(dao, &amixer->rsc);
	spin_unlock_irqrestore(&atc->atc_lock, flags);
	spin_unlock_irqrestore(&atc->atc_lock, flags);


	ct_timer_prepare(apcm->timer);

	return 0;
	return 0;
}
}


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


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

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


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

	atc->create_alsa_devs = ct_create_alsa_devs;
	atc->create_alsa_devs = ct_create_alsa_devs;


	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, atc, &ops);
	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, atc, &ops);
@@ -1602,4 +1622,3 @@ error1:
	printk(KERN_ERR "ctxfi: Something wrong!!!\n");
	printk(KERN_ERR "ctxfi: Something wrong!!!\n");
	return err;
	return err;
}
}
+5 −4
Original line number Original line Diff line number Diff line
@@ -59,16 +59,15 @@ struct ct_atc_chip_details {
};
};


struct ct_atc;
struct ct_atc;
struct ct_timer;
struct ct_timer_instance;


/* alsa pcm stream descriptor */
/* alsa pcm stream descriptor */
struct ct_atc_pcm {
struct ct_atc_pcm {
	struct snd_pcm_substream *substream;
	struct snd_pcm_substream *substream;
	void (*interrupt)(struct ct_atc_pcm *apcm);
	void (*interrupt)(struct ct_atc_pcm *apcm);
	struct ct_timer_instance *timer;
	unsigned int started:1;
	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. */
	/* Only mono and interleaved modes are supported now. */
	struct ct_vm_block *vm_block;
	struct ct_vm_block *vm_block;
@@ -144,6 +143,8 @@ struct ct_atc {
	unsigned char n_src;
	unsigned char n_src;
	unsigned char n_srcimp;
	unsigned char n_srcimp;
	unsigned char n_pcm;
	unsigned char n_pcm;

	struct ct_timer *timer;
};
};




+19 −0
Original line number Original line Diff line number Diff line
@@ -145,6 +145,12 @@ struct hw {
	int (*daio_mgr_set_imapaddr)(void *blk, unsigned int addr);
	int (*daio_mgr_set_imapaddr)(void *blk, unsigned int addr);
	int (*daio_mgr_commit_write)(struct hw *hw, void *blk);
	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 */
	struct pci_dev *pci;	/* the pci kernel structure of this card */
	int irq;
	int irq;
	unsigned long io_base;
	unsigned long io_base;
@@ -157,4 +163,17 @@ int destroy_hw_obj(struct hw *hw);
unsigned int get_field(unsigned int data, unsigned int field);
unsigned int get_field(unsigned int data, unsigned int field);
void set_field(unsigned int *data, unsigned int field, unsigned int value);
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 */
#endif /* CTHARDWARE_H */
Loading