static int snd_ad1816a_capture_prepare(struct snd_pcm_substream *substream)
{
	struct snd_ad1816a *chip = snd_pcm_substream_chip(substream);
	unsigned long flags;
	struct snd_pcm_runtime *runtime = substream->runtime;
	unsigned int size, rate;

	spin_lock_irqsave(&chip->lock, flags);

	chip->c_dma_size = size = snd_pcm_lib_buffer_bytes(substream);
	snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG,
		AD1816A_CAPTURE_ENABLE | AD1816A_CAPTURE_PIO, 0x00);

	snd_dma_program(chip->dma2, runtime->dma_addr, size,
			DMA_MODE_READ | DMA_AUTOINIT);

	rate = runtime->rate;
	if (chip->clock_freq)
		rate = (rate * 33000) / chip->clock_freq;
	snd_ad1816a_write(chip, AD1816A_CAPTURE_SAMPLE_RATE, rate);
	snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG,
		AD1816A_FMT_ALL | AD1816A_FMT_STEREO,
		snd_ad1816a_get_format(chip, runtime->format,
			runtime->channels));

	snd_ad1816a_write(chip, AD1816A_CAPTURE_BASE_COUNT,
		snd_pcm_lib_period_bytes(substream) / 4 - 1);

	spin_unlock_irqrestore(&chip->lock, flags);
	return 0;
}
static int snd_ad1816a_trigger(struct snd_ad1816a *chip, unsigned char what,
			       int channel, int cmd, int iscapture)
{
	int error = 0;

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_STOP:
		spin_lock(&chip->lock);
		cmd = (cmd == SNDRV_PCM_TRIGGER_START) ? 0xff: 0x00;
		/* if (what & AD1816A_PLAYBACK_ENABLE) */
		/* That is not valid, because playback and capture enable
		 * are the same bit pattern, just to different addresses
		 */
		if (! iscapture)
			snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG,
				AD1816A_PLAYBACK_ENABLE, cmd);
		else
			snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG,
				AD1816A_CAPTURE_ENABLE, cmd);
		spin_unlock(&chip->lock);
		break;
	default:
		snd_printk(KERN_WARNING "invalid trigger mode 0x%x.\n", what);
		error = -EINVAL;
	}

	return error;
}
static void snd_ad1816a_close(struct snd_ad1816a *chip, unsigned int mode)
{
	unsigned long flags;

	spin_lock_irqsave(&chip->lock, flags);

	switch ((mode &= AD1816A_MODE_OPEN)) {
	case AD1816A_MODE_PLAYBACK:
		snd_ad1816a_out_mask(chip, AD1816A_INTERRUPT_STATUS,
			AD1816A_PLAYBACK_IRQ_PENDING, 0x00);
		snd_ad1816a_write_mask(chip, AD1816A_INTERRUPT_ENABLE,
			AD1816A_PLAYBACK_IRQ_ENABLE, 0x0000);
		break;
	case AD1816A_MODE_CAPTURE:
		snd_ad1816a_out_mask(chip, AD1816A_INTERRUPT_STATUS,
			AD1816A_CAPTURE_IRQ_PENDING, 0x00);
		snd_ad1816a_write_mask(chip, AD1816A_INTERRUPT_ENABLE,
			AD1816A_CAPTURE_IRQ_ENABLE, 0x0000);
		break;
	case AD1816A_MODE_TIMER:
		snd_ad1816a_out_mask(chip, AD1816A_INTERRUPT_STATUS,
			AD1816A_TIMER_IRQ_PENDING, 0x00);
		snd_ad1816a_write_mask(chip, AD1816A_INTERRUPT_ENABLE,
			AD1816A_TIMER_IRQ_ENABLE, 0x0000);
	}
	if (!((chip->mode &= ~mode) & AD1816A_MODE_OPEN))
		chip->mode = 0;

	spin_unlock_irqrestore(&chip->lock, flags);
}
static int snd_ad1816a_open(struct snd_ad1816a *chip, unsigned int mode)
{
	unsigned long flags;

	spin_lock_irqsave(&chip->lock, flags);

	if (chip->mode & mode) {
		spin_unlock_irqrestore(&chip->lock, flags);
		return -EAGAIN;
	}

	switch ((mode &= AD1816A_MODE_OPEN)) {
	case AD1816A_MODE_PLAYBACK:
		snd_ad1816a_out_mask(chip, AD1816A_INTERRUPT_STATUS,
			AD1816A_PLAYBACK_IRQ_PENDING, 0x00);
		snd_ad1816a_write_mask(chip, AD1816A_INTERRUPT_ENABLE,
			AD1816A_PLAYBACK_IRQ_ENABLE, 0xffff);
		break;
	case AD1816A_MODE_CAPTURE:
		snd_ad1816a_out_mask(chip, AD1816A_INTERRUPT_STATUS,
			AD1816A_CAPTURE_IRQ_PENDING, 0x00);
		snd_ad1816a_write_mask(chip, AD1816A_INTERRUPT_ENABLE,
			AD1816A_CAPTURE_IRQ_ENABLE, 0xffff);
		break;
	case AD1816A_MODE_TIMER:
		snd_ad1816a_out_mask(chip, AD1816A_INTERRUPT_STATUS,
			AD1816A_TIMER_IRQ_PENDING, 0x00);
		snd_ad1816a_write_mask(chip, AD1816A_INTERRUPT_ENABLE,
			AD1816A_TIMER_IRQ_ENABLE, 0xffff);
	}
	chip->mode |= mode;

	spin_unlock_irqrestore(&chip->lock, flags);
	return 0;
}
static int snd_ad1816a_trigger(struct snd_ad1816a *chip, unsigned char what,
			       int channel, int cmd, int iscapture)
{
	int error = 0;

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_STOP:
		spin_lock(&chip->lock);
		cmd = (cmd == SNDRV_PCM_TRIGGER_START) ? 0xff: 0x00;
		
		if (! iscapture)
			snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG,
				AD1816A_PLAYBACK_ENABLE, cmd);
		else
			snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG,
				AD1816A_CAPTURE_ENABLE, cmd);
		spin_unlock(&chip->lock);
		break;
	default:
		snd_printk(KERN_WARNING "invalid trigger mode 0x%x.\n", what);
		error = -EINVAL;
	}

	return error;
}
Esempio n. 6
0
static int snd_ad1816a_playback_prepare(snd_pcm_substream_t *substream)
{
	ad1816a_t *chip = snd_pcm_substream_chip(substream);
	unsigned long flags;
	snd_pcm_runtime_t *runtime = substream->runtime;
	unsigned int size;

	spin_lock_irqsave(&chip->lock, flags);

	chip->p_dma_size = size = snd_pcm_lib_buffer_bytes(substream);
	snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG,
		AD1816A_PLAYBACK_ENABLE | AD1816A_PLAYBACK_PIO, 0x00);

	snd_dma_program(chip->dma1, runtime->dma_addr, size,
			DMA_MODE_WRITE | DMA_AUTOINIT);

	snd_ad1816a_write(chip, AD1816A_PLAYBACK_SAMPLE_RATE, runtime->rate);
	snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG,
		AD1816A_FMT_ALL | AD1816A_FMT_STEREO,
		snd_ad1816a_get_format(chip, runtime->format,
			runtime->channels));

	snd_ad1816a_write(chip, AD1816A_PLAYBACK_BASE_COUNT,
		snd_pcm_lib_period_bytes(substream) / 4 - 1);

	spin_unlock_irqrestore(&chip->lock, flags);
	return 0;
}
static void __devinit snd_ad1816a_init(struct snd_ad1816a *chip)
{
	unsigned long flags;

	spin_lock_irqsave(&chip->lock, flags);

	snd_ad1816a_out(chip, AD1816A_INTERRUPT_STATUS, 0x00);
	snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG,
		AD1816A_PLAYBACK_ENABLE | AD1816A_PLAYBACK_PIO, 0x00);
	snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG,
		AD1816A_CAPTURE_ENABLE | AD1816A_CAPTURE_PIO, 0x00);
	snd_ad1816a_write(chip, AD1816A_INTERRUPT_ENABLE, 0x0000);
	snd_ad1816a_write_mask(chip, AD1816A_CHIP_CONFIG,
		AD1816A_CAPTURE_NOT_EQUAL | AD1816A_WSS_ENABLE, 0xffff);
	snd_ad1816a_write(chip, AD1816A_DSP_CONFIG, 0x0000);
	snd_ad1816a_write(chip, AD1816A_POWERDOWN_CTRL, 0x0000);

	spin_unlock_irqrestore(&chip->lock, flags);
}