162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
462306a36Sopenharmony_ci *  Routines for control of YMF724/740/744/754 chips
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/delay.h>
862306a36Sopenharmony_ci#include <linux/firmware.h>
962306a36Sopenharmony_ci#include <linux/init.h>
1062306a36Sopenharmony_ci#include <linux/interrupt.h>
1162306a36Sopenharmony_ci#include <linux/pci.h>
1262306a36Sopenharmony_ci#include <linux/sched.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci#include <linux/mutex.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/io.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <sound/core.h>
1962306a36Sopenharmony_ci#include <sound/control.h>
2062306a36Sopenharmony_ci#include <sound/info.h>
2162306a36Sopenharmony_ci#include <sound/tlv.h>
2262306a36Sopenharmony_ci#include "ymfpci.h"
2362306a36Sopenharmony_ci#include <sound/asoundef.h>
2462306a36Sopenharmony_ci#include <sound/mpu401.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include <asm/byteorder.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/*
2962306a36Sopenharmony_ci *  common I/O routines
3062306a36Sopenharmony_ci */
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic void snd_ymfpci_irq_wait(struct snd_ymfpci *chip);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic inline void snd_ymfpci_writeb(struct snd_ymfpci *chip, u32 offset, u8 val)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	writeb(val, chip->reg_area_virt + offset);
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic inline u16 snd_ymfpci_readw(struct snd_ymfpci *chip, u32 offset)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	return readw(chip->reg_area_virt + offset);
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic inline void snd_ymfpci_writew(struct snd_ymfpci *chip, u32 offset, u16 val)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	writew(val, chip->reg_area_virt + offset);
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic inline u32 snd_ymfpci_readl(struct snd_ymfpci *chip, u32 offset)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	return readl(chip->reg_area_virt + offset);
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic inline void snd_ymfpci_writel(struct snd_ymfpci *chip, u32 offset, u32 val)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	writel(val, chip->reg_area_virt + offset);
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic int snd_ymfpci_codec_ready(struct snd_ymfpci *chip, int secondary)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	unsigned long end_time;
6262306a36Sopenharmony_ci	u32 reg = secondary ? YDSXGR_SECSTATUSADR : YDSXGR_PRISTATUSADR;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	end_time = jiffies + msecs_to_jiffies(750);
6562306a36Sopenharmony_ci	do {
6662306a36Sopenharmony_ci		if ((snd_ymfpci_readw(chip, reg) & 0x8000) == 0)
6762306a36Sopenharmony_ci			return 0;
6862306a36Sopenharmony_ci		schedule_timeout_uninterruptible(1);
6962306a36Sopenharmony_ci	} while (time_before(jiffies, end_time));
7062306a36Sopenharmony_ci	dev_err(chip->card->dev,
7162306a36Sopenharmony_ci		"codec_ready: codec %i is not ready [0x%x]\n",
7262306a36Sopenharmony_ci		secondary, snd_ymfpci_readw(chip, reg));
7362306a36Sopenharmony_ci	return -EBUSY;
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic void snd_ymfpci_codec_write(struct snd_ac97 *ac97, u16 reg, u16 val)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	struct snd_ymfpci *chip = ac97->private_data;
7962306a36Sopenharmony_ci	u32 cmd;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	snd_ymfpci_codec_ready(chip, 0);
8262306a36Sopenharmony_ci	cmd = ((YDSXG_AC97WRITECMD | reg) << 16) | val;
8362306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_AC97CMDDATA, cmd);
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic u16 snd_ymfpci_codec_read(struct snd_ac97 *ac97, u16 reg)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	struct snd_ymfpci *chip = ac97->private_data;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	if (snd_ymfpci_codec_ready(chip, 0))
9162306a36Sopenharmony_ci		return ~0;
9262306a36Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg);
9362306a36Sopenharmony_ci	if (snd_ymfpci_codec_ready(chip, 0))
9462306a36Sopenharmony_ci		return ~0;
9562306a36Sopenharmony_ci	if (chip->device_id == PCI_DEVICE_ID_YAMAHA_744 && chip->rev < 2) {
9662306a36Sopenharmony_ci		int i;
9762306a36Sopenharmony_ci		for (i = 0; i < 600; i++)
9862306a36Sopenharmony_ci			snd_ymfpci_readw(chip, YDSXGR_PRISTATUSDATA);
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci	return snd_ymfpci_readw(chip, YDSXGR_PRISTATUSDATA);
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/*
10462306a36Sopenharmony_ci *  Misc routines
10562306a36Sopenharmony_ci */
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic u32 snd_ymfpci_calc_delta(u32 rate)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	switch (rate) {
11062306a36Sopenharmony_ci	case 8000:	return 0x02aaab00;
11162306a36Sopenharmony_ci	case 11025:	return 0x03accd00;
11262306a36Sopenharmony_ci	case 16000:	return 0x05555500;
11362306a36Sopenharmony_ci	case 22050:	return 0x07599a00;
11462306a36Sopenharmony_ci	case 32000:	return 0x0aaaab00;
11562306a36Sopenharmony_ci	case 44100:	return 0x0eb33300;
11662306a36Sopenharmony_ci	default:	return ((rate << 16) / 375) << 5;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic const u32 def_rate[8] = {
12162306a36Sopenharmony_ci	100, 2000, 8000, 11025, 16000, 22050, 32000, 48000
12262306a36Sopenharmony_ci};
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic u32 snd_ymfpci_calc_lpfK(u32 rate)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	u32 i;
12762306a36Sopenharmony_ci	static const u32 val[8] = {
12862306a36Sopenharmony_ci		0x00570000, 0x06AA0000, 0x18B20000, 0x20930000,
12962306a36Sopenharmony_ci		0x2B9A0000, 0x35A10000, 0x3EAA0000, 0x40000000
13062306a36Sopenharmony_ci	};
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	if (rate == 44100)
13362306a36Sopenharmony_ci		return 0x40000000;	/* FIXME: What's the right value? */
13462306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
13562306a36Sopenharmony_ci		if (rate <= def_rate[i])
13662306a36Sopenharmony_ci			return val[i];
13762306a36Sopenharmony_ci	return val[0];
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic u32 snd_ymfpci_calc_lpfQ(u32 rate)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	u32 i;
14362306a36Sopenharmony_ci	static const u32 val[8] = {
14462306a36Sopenharmony_ci		0x35280000, 0x34A70000, 0x32020000, 0x31770000,
14562306a36Sopenharmony_ci		0x31390000, 0x31C90000, 0x33D00000, 0x40000000
14662306a36Sopenharmony_ci	};
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	if (rate == 44100)
14962306a36Sopenharmony_ci		return 0x370A0000;
15062306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
15162306a36Sopenharmony_ci		if (rate <= def_rate[i])
15262306a36Sopenharmony_ci			return val[i];
15362306a36Sopenharmony_ci	return val[0];
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/*
15762306a36Sopenharmony_ci *  Hardware start management
15862306a36Sopenharmony_ci */
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic void snd_ymfpci_hw_start(struct snd_ymfpci *chip)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	unsigned long flags;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
16562306a36Sopenharmony_ci	if (chip->start_count++ > 0)
16662306a36Sopenharmony_ci		goto __end;
16762306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_MODE,
16862306a36Sopenharmony_ci			  snd_ymfpci_readl(chip, YDSXGR_MODE) | 3);
16962306a36Sopenharmony_ci	chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT) & 1;
17062306a36Sopenharmony_ci      __end:
17162306a36Sopenharmony_ci      	spin_unlock_irqrestore(&chip->reg_lock, flags);
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic void snd_ymfpci_hw_stop(struct snd_ymfpci *chip)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	unsigned long flags;
17762306a36Sopenharmony_ci	long timeout = 1000;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
18062306a36Sopenharmony_ci	if (--chip->start_count > 0)
18162306a36Sopenharmony_ci		goto __end;
18262306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_MODE,
18362306a36Sopenharmony_ci			  snd_ymfpci_readl(chip, YDSXGR_MODE) & ~3);
18462306a36Sopenharmony_ci	while (timeout-- > 0) {
18562306a36Sopenharmony_ci		if ((snd_ymfpci_readl(chip, YDSXGR_STATUS) & 2) == 0)
18662306a36Sopenharmony_ci			break;
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci	if (atomic_read(&chip->interrupt_sleep_count)) {
18962306a36Sopenharmony_ci		atomic_set(&chip->interrupt_sleep_count, 0);
19062306a36Sopenharmony_ci		wake_up(&chip->interrupt_sleep);
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ci      __end:
19362306a36Sopenharmony_ci      	spin_unlock_irqrestore(&chip->reg_lock, flags);
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci/*
19762306a36Sopenharmony_ci *  Playback voice management
19862306a36Sopenharmony_ci */
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic int voice_alloc(struct snd_ymfpci *chip,
20162306a36Sopenharmony_ci		       enum snd_ymfpci_voice_type type, int pair,
20262306a36Sopenharmony_ci		       struct snd_ymfpci_voice **rvoice)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct snd_ymfpci_voice *voice, *voice2;
20562306a36Sopenharmony_ci	int idx;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	*rvoice = NULL;
20862306a36Sopenharmony_ci	for (idx = 0; idx < YDSXG_PLAYBACK_VOICES; idx += pair ? 2 : 1) {
20962306a36Sopenharmony_ci		voice = &chip->voices[idx];
21062306a36Sopenharmony_ci		voice2 = pair ? &chip->voices[idx+1] : NULL;
21162306a36Sopenharmony_ci		if (voice->use || (voice2 && voice2->use))
21262306a36Sopenharmony_ci			continue;
21362306a36Sopenharmony_ci		voice->use = 1;
21462306a36Sopenharmony_ci		if (voice2)
21562306a36Sopenharmony_ci			voice2->use = 1;
21662306a36Sopenharmony_ci		switch (type) {
21762306a36Sopenharmony_ci		case YMFPCI_PCM:
21862306a36Sopenharmony_ci			voice->pcm = 1;
21962306a36Sopenharmony_ci			if (voice2)
22062306a36Sopenharmony_ci				voice2->pcm = 1;
22162306a36Sopenharmony_ci			break;
22262306a36Sopenharmony_ci		case YMFPCI_SYNTH:
22362306a36Sopenharmony_ci			voice->synth = 1;
22462306a36Sopenharmony_ci			break;
22562306a36Sopenharmony_ci		case YMFPCI_MIDI:
22662306a36Sopenharmony_ci			voice->midi = 1;
22762306a36Sopenharmony_ci			break;
22862306a36Sopenharmony_ci		}
22962306a36Sopenharmony_ci		snd_ymfpci_hw_start(chip);
23062306a36Sopenharmony_ci		if (voice2)
23162306a36Sopenharmony_ci			snd_ymfpci_hw_start(chip);
23262306a36Sopenharmony_ci		*rvoice = voice;
23362306a36Sopenharmony_ci		return 0;
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci	return -ENOMEM;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic int snd_ymfpci_voice_alloc(struct snd_ymfpci *chip,
23962306a36Sopenharmony_ci				  enum snd_ymfpci_voice_type type, int pair,
24062306a36Sopenharmony_ci				  struct snd_ymfpci_voice **rvoice)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	unsigned long flags;
24362306a36Sopenharmony_ci	int result;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	if (snd_BUG_ON(!rvoice))
24662306a36Sopenharmony_ci		return -EINVAL;
24762306a36Sopenharmony_ci	if (snd_BUG_ON(pair && type != YMFPCI_PCM))
24862306a36Sopenharmony_ci		return -EINVAL;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	spin_lock_irqsave(&chip->voice_lock, flags);
25162306a36Sopenharmony_ci	for (;;) {
25262306a36Sopenharmony_ci		result = voice_alloc(chip, type, pair, rvoice);
25362306a36Sopenharmony_ci		if (result == 0 || type != YMFPCI_PCM)
25462306a36Sopenharmony_ci			break;
25562306a36Sopenharmony_ci		/* TODO: synth/midi voice deallocation */
25662306a36Sopenharmony_ci		break;
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->voice_lock, flags);
25962306a36Sopenharmony_ci	return result;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic int snd_ymfpci_voice_free(struct snd_ymfpci *chip, struct snd_ymfpci_voice *pvoice)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	unsigned long flags;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	if (snd_BUG_ON(!pvoice))
26762306a36Sopenharmony_ci		return -EINVAL;
26862306a36Sopenharmony_ci	snd_ymfpci_hw_stop(chip);
26962306a36Sopenharmony_ci	spin_lock_irqsave(&chip->voice_lock, flags);
27062306a36Sopenharmony_ci	if (pvoice->number == chip->src441_used) {
27162306a36Sopenharmony_ci		chip->src441_used = -1;
27262306a36Sopenharmony_ci		pvoice->ypcm->use_441_slot = 0;
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci	pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0;
27562306a36Sopenharmony_ci	pvoice->ypcm = NULL;
27662306a36Sopenharmony_ci	pvoice->interrupt = NULL;
27762306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->voice_lock, flags);
27862306a36Sopenharmony_ci	return 0;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci/*
28262306a36Sopenharmony_ci *  PCM part
28362306a36Sopenharmony_ci */
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic void snd_ymfpci_pcm_interrupt(struct snd_ymfpci *chip, struct snd_ymfpci_voice *voice)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm;
28862306a36Sopenharmony_ci	u32 pos, delta;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	ypcm = voice->ypcm;
29162306a36Sopenharmony_ci	if (!ypcm)
29262306a36Sopenharmony_ci		return;
29362306a36Sopenharmony_ci	if (ypcm->substream == NULL)
29462306a36Sopenharmony_ci		return;
29562306a36Sopenharmony_ci	spin_lock(&chip->reg_lock);
29662306a36Sopenharmony_ci	if (ypcm->running) {
29762306a36Sopenharmony_ci		pos = le32_to_cpu(voice->bank[chip->active_bank].start);
29862306a36Sopenharmony_ci		if (pos < ypcm->last_pos)
29962306a36Sopenharmony_ci			delta = pos + (ypcm->buffer_size - ypcm->last_pos);
30062306a36Sopenharmony_ci		else
30162306a36Sopenharmony_ci			delta = pos - ypcm->last_pos;
30262306a36Sopenharmony_ci		ypcm->period_pos += delta;
30362306a36Sopenharmony_ci		ypcm->last_pos = pos;
30462306a36Sopenharmony_ci		if (ypcm->period_pos >= ypcm->period_size) {
30562306a36Sopenharmony_ci			/*
30662306a36Sopenharmony_ci			dev_dbg(chip->card->dev,
30762306a36Sopenharmony_ci			       "done - active_bank = 0x%x, start = 0x%x\n",
30862306a36Sopenharmony_ci			       chip->active_bank,
30962306a36Sopenharmony_ci			       voice->bank[chip->active_bank].start);
31062306a36Sopenharmony_ci			*/
31162306a36Sopenharmony_ci			ypcm->period_pos %= ypcm->period_size;
31262306a36Sopenharmony_ci			spin_unlock(&chip->reg_lock);
31362306a36Sopenharmony_ci			snd_pcm_period_elapsed(ypcm->substream);
31462306a36Sopenharmony_ci			spin_lock(&chip->reg_lock);
31562306a36Sopenharmony_ci		}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci		if (unlikely(ypcm->update_pcm_vol)) {
31862306a36Sopenharmony_ci			unsigned int subs = ypcm->substream->number;
31962306a36Sopenharmony_ci			unsigned int next_bank = 1 - chip->active_bank;
32062306a36Sopenharmony_ci			struct snd_ymfpci_playback_bank *bank;
32162306a36Sopenharmony_ci			__le32 volume;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci			bank = &voice->bank[next_bank];
32462306a36Sopenharmony_ci			volume = cpu_to_le32(chip->pcm_mixer[subs].left << 15);
32562306a36Sopenharmony_ci			bank->left_gain_end = volume;
32662306a36Sopenharmony_ci			if (ypcm->output_rear)
32762306a36Sopenharmony_ci				bank->eff2_gain_end = volume;
32862306a36Sopenharmony_ci			if (ypcm->voices[1])
32962306a36Sopenharmony_ci				bank = &ypcm->voices[1]->bank[next_bank];
33062306a36Sopenharmony_ci			volume = cpu_to_le32(chip->pcm_mixer[subs].right << 15);
33162306a36Sopenharmony_ci			bank->right_gain_end = volume;
33262306a36Sopenharmony_ci			if (ypcm->output_rear)
33362306a36Sopenharmony_ci				bank->eff3_gain_end = volume;
33462306a36Sopenharmony_ci			ypcm->update_pcm_vol--;
33562306a36Sopenharmony_ci		}
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci	spin_unlock(&chip->reg_lock);
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic void snd_ymfpci_pcm_capture_interrupt(struct snd_pcm_substream *substream)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
34362306a36Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = runtime->private_data;
34462306a36Sopenharmony_ci	struct snd_ymfpci *chip = ypcm->chip;
34562306a36Sopenharmony_ci	u32 pos, delta;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	spin_lock(&chip->reg_lock);
34862306a36Sopenharmony_ci	if (ypcm->running) {
34962306a36Sopenharmony_ci		pos = le32_to_cpu(chip->bank_capture[ypcm->capture_bank_number][chip->active_bank]->start) >> ypcm->shift;
35062306a36Sopenharmony_ci		if (pos < ypcm->last_pos)
35162306a36Sopenharmony_ci			delta = pos + (ypcm->buffer_size - ypcm->last_pos);
35262306a36Sopenharmony_ci		else
35362306a36Sopenharmony_ci			delta = pos - ypcm->last_pos;
35462306a36Sopenharmony_ci		ypcm->period_pos += delta;
35562306a36Sopenharmony_ci		ypcm->last_pos = pos;
35662306a36Sopenharmony_ci		if (ypcm->period_pos >= ypcm->period_size) {
35762306a36Sopenharmony_ci			ypcm->period_pos %= ypcm->period_size;
35862306a36Sopenharmony_ci			/*
35962306a36Sopenharmony_ci			dev_dbg(chip->card->dev,
36062306a36Sopenharmony_ci			       "done - active_bank = 0x%x, start = 0x%x\n",
36162306a36Sopenharmony_ci			       chip->active_bank,
36262306a36Sopenharmony_ci			       voice->bank[chip->active_bank].start);
36362306a36Sopenharmony_ci			*/
36462306a36Sopenharmony_ci			spin_unlock(&chip->reg_lock);
36562306a36Sopenharmony_ci			snd_pcm_period_elapsed(substream);
36662306a36Sopenharmony_ci			spin_lock(&chip->reg_lock);
36762306a36Sopenharmony_ci		}
36862306a36Sopenharmony_ci	}
36962306a36Sopenharmony_ci	spin_unlock(&chip->reg_lock);
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream,
37362306a36Sopenharmony_ci				       int cmd)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
37662306a36Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data;
37762306a36Sopenharmony_ci	struct snd_kcontrol *kctl = NULL;
37862306a36Sopenharmony_ci	int result = 0;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	spin_lock(&chip->reg_lock);
38162306a36Sopenharmony_ci	if (ypcm->voices[0] == NULL) {
38262306a36Sopenharmony_ci		result = -EINVAL;
38362306a36Sopenharmony_ci		goto __unlock;
38462306a36Sopenharmony_ci	}
38562306a36Sopenharmony_ci	switch (cmd) {
38662306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
38762306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
38862306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
38962306a36Sopenharmony_ci		chip->ctrl_playback[ypcm->voices[0]->number + 1] = cpu_to_le32(ypcm->voices[0]->bank_addr);
39062306a36Sopenharmony_ci		if (ypcm->voices[1] != NULL && !ypcm->use_441_slot)
39162306a36Sopenharmony_ci			chip->ctrl_playback[ypcm->voices[1]->number + 1] = cpu_to_le32(ypcm->voices[1]->bank_addr);
39262306a36Sopenharmony_ci		ypcm->running = 1;
39362306a36Sopenharmony_ci		break;
39462306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
39562306a36Sopenharmony_ci		if (substream->pcm == chip->pcm && !ypcm->use_441_slot) {
39662306a36Sopenharmony_ci			kctl = chip->pcm_mixer[substream->number].ctl;
39762306a36Sopenharmony_ci			kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
39862306a36Sopenharmony_ci		}
39962306a36Sopenharmony_ci		fallthrough;
40062306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
40162306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
40262306a36Sopenharmony_ci		chip->ctrl_playback[ypcm->voices[0]->number + 1] = 0;
40362306a36Sopenharmony_ci		if (ypcm->voices[1] != NULL && !ypcm->use_441_slot)
40462306a36Sopenharmony_ci			chip->ctrl_playback[ypcm->voices[1]->number + 1] = 0;
40562306a36Sopenharmony_ci		ypcm->running = 0;
40662306a36Sopenharmony_ci		break;
40762306a36Sopenharmony_ci	default:
40862306a36Sopenharmony_ci		result = -EINVAL;
40962306a36Sopenharmony_ci		break;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci      __unlock:
41262306a36Sopenharmony_ci	spin_unlock(&chip->reg_lock);
41362306a36Sopenharmony_ci	if (kctl)
41462306a36Sopenharmony_ci		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
41562306a36Sopenharmony_ci	return result;
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_cistatic int snd_ymfpci_capture_trigger(struct snd_pcm_substream *substream,
41862306a36Sopenharmony_ci				      int cmd)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
42162306a36Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data;
42262306a36Sopenharmony_ci	int result = 0;
42362306a36Sopenharmony_ci	u32 tmp;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	spin_lock(&chip->reg_lock);
42662306a36Sopenharmony_ci	switch (cmd) {
42762306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
42862306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
42962306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
43062306a36Sopenharmony_ci		tmp = snd_ymfpci_readl(chip, YDSXGR_MAPOFREC) | (1 << ypcm->capture_bank_number);
43162306a36Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_MAPOFREC, tmp);
43262306a36Sopenharmony_ci		ypcm->running = 1;
43362306a36Sopenharmony_ci		break;
43462306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
43562306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
43662306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
43762306a36Sopenharmony_ci		tmp = snd_ymfpci_readl(chip, YDSXGR_MAPOFREC) & ~(1 << ypcm->capture_bank_number);
43862306a36Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_MAPOFREC, tmp);
43962306a36Sopenharmony_ci		ypcm->running = 0;
44062306a36Sopenharmony_ci		break;
44162306a36Sopenharmony_ci	default:
44262306a36Sopenharmony_ci		result = -EINVAL;
44362306a36Sopenharmony_ci		break;
44462306a36Sopenharmony_ci	}
44562306a36Sopenharmony_ci	spin_unlock(&chip->reg_lock);
44662306a36Sopenharmony_ci	return result;
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic int snd_ymfpci_pcm_voice_alloc(struct snd_ymfpci_pcm *ypcm, int voices)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	int err;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	if (ypcm->voices[1] != NULL && voices < 2) {
45462306a36Sopenharmony_ci		snd_ymfpci_voice_free(ypcm->chip, ypcm->voices[1]);
45562306a36Sopenharmony_ci		ypcm->voices[1] = NULL;
45662306a36Sopenharmony_ci	}
45762306a36Sopenharmony_ci	if (voices == 1 && ypcm->voices[0] != NULL)
45862306a36Sopenharmony_ci		return 0;		/* already allocated */
45962306a36Sopenharmony_ci	if (voices == 2 && ypcm->voices[0] != NULL && ypcm->voices[1] != NULL)
46062306a36Sopenharmony_ci		return 0;		/* already allocated */
46162306a36Sopenharmony_ci	if (voices > 1) {
46262306a36Sopenharmony_ci		if (ypcm->voices[0] != NULL && ypcm->voices[1] == NULL) {
46362306a36Sopenharmony_ci			snd_ymfpci_voice_free(ypcm->chip, ypcm->voices[0]);
46462306a36Sopenharmony_ci			ypcm->voices[0] = NULL;
46562306a36Sopenharmony_ci		}
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci	err = snd_ymfpci_voice_alloc(ypcm->chip, YMFPCI_PCM, voices > 1, &ypcm->voices[0]);
46862306a36Sopenharmony_ci	if (err < 0)
46962306a36Sopenharmony_ci		return err;
47062306a36Sopenharmony_ci	ypcm->voices[0]->ypcm = ypcm;
47162306a36Sopenharmony_ci	ypcm->voices[0]->interrupt = snd_ymfpci_pcm_interrupt;
47262306a36Sopenharmony_ci	if (voices > 1) {
47362306a36Sopenharmony_ci		ypcm->voices[1] = &ypcm->chip->voices[ypcm->voices[0]->number + 1];
47462306a36Sopenharmony_ci		ypcm->voices[1]->ypcm = ypcm;
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci	return 0;
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_cistatic void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int voiceidx,
48062306a36Sopenharmony_ci				      struct snd_pcm_runtime *runtime,
48162306a36Sopenharmony_ci				      int has_pcm_volume)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	struct snd_ymfpci_voice *voice = ypcm->voices[voiceidx];
48462306a36Sopenharmony_ci	u32 format;
48562306a36Sopenharmony_ci	u32 delta = snd_ymfpci_calc_delta(runtime->rate);
48662306a36Sopenharmony_ci	u32 lpfQ = snd_ymfpci_calc_lpfQ(runtime->rate);
48762306a36Sopenharmony_ci	u32 lpfK = snd_ymfpci_calc_lpfK(runtime->rate);
48862306a36Sopenharmony_ci	struct snd_ymfpci_playback_bank *bank;
48962306a36Sopenharmony_ci	unsigned int nbank;
49062306a36Sopenharmony_ci	__le32 vol_left, vol_right;
49162306a36Sopenharmony_ci	u8 use_left, use_right;
49262306a36Sopenharmony_ci	unsigned long flags;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	if (snd_BUG_ON(!voice))
49562306a36Sopenharmony_ci		return;
49662306a36Sopenharmony_ci	if (runtime->channels == 1) {
49762306a36Sopenharmony_ci		use_left = 1;
49862306a36Sopenharmony_ci		use_right = 1;
49962306a36Sopenharmony_ci	} else {
50062306a36Sopenharmony_ci		use_left = (voiceidx & 1) == 0;
50162306a36Sopenharmony_ci		use_right = !use_left;
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci	if (has_pcm_volume) {
50462306a36Sopenharmony_ci		vol_left = cpu_to_le32(ypcm->chip->pcm_mixer
50562306a36Sopenharmony_ci				       [ypcm->substream->number].left << 15);
50662306a36Sopenharmony_ci		vol_right = cpu_to_le32(ypcm->chip->pcm_mixer
50762306a36Sopenharmony_ci					[ypcm->substream->number].right << 15);
50862306a36Sopenharmony_ci	} else {
50962306a36Sopenharmony_ci		vol_left = cpu_to_le32(0x40000000);
51062306a36Sopenharmony_ci		vol_right = cpu_to_le32(0x40000000);
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci	spin_lock_irqsave(&ypcm->chip->voice_lock, flags);
51362306a36Sopenharmony_ci	format = runtime->channels == 2 ? 0x00010000 : 0;
51462306a36Sopenharmony_ci	if (snd_pcm_format_width(runtime->format) == 8)
51562306a36Sopenharmony_ci		format |= 0x80000000;
51662306a36Sopenharmony_ci	else if (ypcm->chip->device_id == PCI_DEVICE_ID_YAMAHA_754 &&
51762306a36Sopenharmony_ci		 runtime->rate == 44100 && runtime->channels == 2 &&
51862306a36Sopenharmony_ci		 voiceidx == 0 && (ypcm->chip->src441_used == -1 ||
51962306a36Sopenharmony_ci				   ypcm->chip->src441_used == voice->number)) {
52062306a36Sopenharmony_ci		ypcm->chip->src441_used = voice->number;
52162306a36Sopenharmony_ci		ypcm->use_441_slot = 1;
52262306a36Sopenharmony_ci		format |= 0x10000000;
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci	if (ypcm->chip->src441_used == voice->number &&
52562306a36Sopenharmony_ci	    (format & 0x10000000) == 0) {
52662306a36Sopenharmony_ci		ypcm->chip->src441_used = -1;
52762306a36Sopenharmony_ci		ypcm->use_441_slot = 0;
52862306a36Sopenharmony_ci	}
52962306a36Sopenharmony_ci	if (runtime->channels == 2 && (voiceidx & 1) != 0)
53062306a36Sopenharmony_ci		format |= 1;
53162306a36Sopenharmony_ci	spin_unlock_irqrestore(&ypcm->chip->voice_lock, flags);
53262306a36Sopenharmony_ci	for (nbank = 0; nbank < 2; nbank++) {
53362306a36Sopenharmony_ci		bank = &voice->bank[nbank];
53462306a36Sopenharmony_ci		memset(bank, 0, sizeof(*bank));
53562306a36Sopenharmony_ci		bank->format = cpu_to_le32(format);
53662306a36Sopenharmony_ci		bank->base = cpu_to_le32(runtime->dma_addr);
53762306a36Sopenharmony_ci		bank->loop_end = cpu_to_le32(ypcm->buffer_size);
53862306a36Sopenharmony_ci		bank->lpfQ = cpu_to_le32(lpfQ);
53962306a36Sopenharmony_ci		bank->delta =
54062306a36Sopenharmony_ci		bank->delta_end = cpu_to_le32(delta);
54162306a36Sopenharmony_ci		bank->lpfK =
54262306a36Sopenharmony_ci		bank->lpfK_end = cpu_to_le32(lpfK);
54362306a36Sopenharmony_ci		bank->eg_gain =
54462306a36Sopenharmony_ci		bank->eg_gain_end = cpu_to_le32(0x40000000);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci		if (ypcm->output_front) {
54762306a36Sopenharmony_ci			if (use_left) {
54862306a36Sopenharmony_ci				bank->left_gain =
54962306a36Sopenharmony_ci				bank->left_gain_end = vol_left;
55062306a36Sopenharmony_ci			}
55162306a36Sopenharmony_ci			if (use_right) {
55262306a36Sopenharmony_ci				bank->right_gain =
55362306a36Sopenharmony_ci				bank->right_gain_end = vol_right;
55462306a36Sopenharmony_ci			}
55562306a36Sopenharmony_ci		}
55662306a36Sopenharmony_ci		if (ypcm->output_rear) {
55762306a36Sopenharmony_ci		        if (!ypcm->swap_rear) {
55862306a36Sopenharmony_ci        			if (use_left) {
55962306a36Sopenharmony_ci        				bank->eff2_gain =
56062306a36Sopenharmony_ci        				bank->eff2_gain_end = vol_left;
56162306a36Sopenharmony_ci        			}
56262306a36Sopenharmony_ci        			if (use_right) {
56362306a36Sopenharmony_ci        				bank->eff3_gain =
56462306a36Sopenharmony_ci        				bank->eff3_gain_end = vol_right;
56562306a36Sopenharmony_ci        			}
56662306a36Sopenharmony_ci		        } else {
56762306a36Sopenharmony_ci        			/* The SPDIF out channels seem to be swapped, so we have
56862306a36Sopenharmony_ci        			 * to swap them here, too.  The rear analog out channels
56962306a36Sopenharmony_ci        			 * will be wrong, but otherwise AC3 would not work.
57062306a36Sopenharmony_ci        			 */
57162306a36Sopenharmony_ci        			if (use_left) {
57262306a36Sopenharmony_ci        				bank->eff3_gain =
57362306a36Sopenharmony_ci        				bank->eff3_gain_end = vol_left;
57462306a36Sopenharmony_ci        			}
57562306a36Sopenharmony_ci        			if (use_right) {
57662306a36Sopenharmony_ci        				bank->eff2_gain =
57762306a36Sopenharmony_ci        				bank->eff2_gain_end = vol_right;
57862306a36Sopenharmony_ci        			}
57962306a36Sopenharmony_ci        		}
58062306a36Sopenharmony_ci                }
58162306a36Sopenharmony_ci	}
58262306a36Sopenharmony_ci}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_cistatic int snd_ymfpci_ac3_init(struct snd_ymfpci *chip)
58562306a36Sopenharmony_ci{
58662306a36Sopenharmony_ci	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev,
58762306a36Sopenharmony_ci				4096, &chip->ac3_tmp_base) < 0)
58862306a36Sopenharmony_ci		return -ENOMEM;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	chip->bank_effect[3][0]->base =
59162306a36Sopenharmony_ci	chip->bank_effect[3][1]->base = cpu_to_le32(chip->ac3_tmp_base.addr);
59262306a36Sopenharmony_ci	chip->bank_effect[3][0]->loop_end =
59362306a36Sopenharmony_ci	chip->bank_effect[3][1]->loop_end = cpu_to_le32(1024);
59462306a36Sopenharmony_ci	chip->bank_effect[4][0]->base =
59562306a36Sopenharmony_ci	chip->bank_effect[4][1]->base = cpu_to_le32(chip->ac3_tmp_base.addr + 2048);
59662306a36Sopenharmony_ci	chip->bank_effect[4][0]->loop_end =
59762306a36Sopenharmony_ci	chip->bank_effect[4][1]->loop_end = cpu_to_le32(1024);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
60062306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT,
60162306a36Sopenharmony_ci			  snd_ymfpci_readl(chip, YDSXGR_MAPOFEFFECT) | 3 << 3);
60262306a36Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
60362306a36Sopenharmony_ci	return 0;
60462306a36Sopenharmony_ci}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_cistatic int snd_ymfpci_ac3_done(struct snd_ymfpci *chip)
60762306a36Sopenharmony_ci{
60862306a36Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
60962306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT,
61062306a36Sopenharmony_ci			  snd_ymfpci_readl(chip, YDSXGR_MAPOFEFFECT) & ~(3 << 3));
61162306a36Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
61262306a36Sopenharmony_ci	// snd_ymfpci_irq_wait(chip);
61362306a36Sopenharmony_ci	if (chip->ac3_tmp_base.area) {
61462306a36Sopenharmony_ci		snd_dma_free_pages(&chip->ac3_tmp_base);
61562306a36Sopenharmony_ci		chip->ac3_tmp_base.area = NULL;
61662306a36Sopenharmony_ci	}
61762306a36Sopenharmony_ci	return 0;
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_cistatic int snd_ymfpci_playback_hw_params(struct snd_pcm_substream *substream,
62162306a36Sopenharmony_ci					 struct snd_pcm_hw_params *hw_params)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
62462306a36Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = runtime->private_data;
62562306a36Sopenharmony_ci	int err;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	err = snd_ymfpci_pcm_voice_alloc(ypcm, params_channels(hw_params));
62862306a36Sopenharmony_ci	if (err < 0)
62962306a36Sopenharmony_ci		return err;
63062306a36Sopenharmony_ci	return 0;
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic int snd_ymfpci_playback_hw_free(struct snd_pcm_substream *substream)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
63662306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
63762306a36Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	if (runtime->private_data == NULL)
64062306a36Sopenharmony_ci		return 0;
64162306a36Sopenharmony_ci	ypcm = runtime->private_data;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	/* wait, until the PCI operations are not finished */
64462306a36Sopenharmony_ci	snd_ymfpci_irq_wait(chip);
64562306a36Sopenharmony_ci	if (ypcm->voices[1]) {
64662306a36Sopenharmony_ci		snd_ymfpci_voice_free(chip, ypcm->voices[1]);
64762306a36Sopenharmony_ci		ypcm->voices[1] = NULL;
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci	if (ypcm->voices[0]) {
65062306a36Sopenharmony_ci		snd_ymfpci_voice_free(chip, ypcm->voices[0]);
65162306a36Sopenharmony_ci		ypcm->voices[0] = NULL;
65262306a36Sopenharmony_ci	}
65362306a36Sopenharmony_ci	return 0;
65462306a36Sopenharmony_ci}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_cistatic int snd_ymfpci_playback_prepare(struct snd_pcm_substream *substream)
65762306a36Sopenharmony_ci{
65862306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
65962306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
66062306a36Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = runtime->private_data;
66162306a36Sopenharmony_ci	struct snd_kcontrol *kctl;
66262306a36Sopenharmony_ci	unsigned int nvoice;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	ypcm->period_size = runtime->period_size;
66562306a36Sopenharmony_ci	ypcm->buffer_size = runtime->buffer_size;
66662306a36Sopenharmony_ci	ypcm->period_pos = 0;
66762306a36Sopenharmony_ci	ypcm->last_pos = 0;
66862306a36Sopenharmony_ci	for (nvoice = 0; nvoice < runtime->channels; nvoice++)
66962306a36Sopenharmony_ci		snd_ymfpci_pcm_init_voice(ypcm, nvoice, runtime,
67062306a36Sopenharmony_ci					  substream->pcm == chip->pcm);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	if (substream->pcm == chip->pcm && !ypcm->use_441_slot) {
67362306a36Sopenharmony_ci		kctl = chip->pcm_mixer[substream->number].ctl;
67462306a36Sopenharmony_ci		kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
67562306a36Sopenharmony_ci		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
67662306a36Sopenharmony_ci	}
67762306a36Sopenharmony_ci	return 0;
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cistatic int snd_ymfpci_capture_hw_free(struct snd_pcm_substream *substream)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/* wait, until the PCI operations are not finished */
68562306a36Sopenharmony_ci	snd_ymfpci_irq_wait(chip);
68662306a36Sopenharmony_ci	return 0;
68762306a36Sopenharmony_ci}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_cistatic int snd_ymfpci_capture_prepare(struct snd_pcm_substream *substream)
69062306a36Sopenharmony_ci{
69162306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
69262306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
69362306a36Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = runtime->private_data;
69462306a36Sopenharmony_ci	struct snd_ymfpci_capture_bank * bank;
69562306a36Sopenharmony_ci	int nbank;
69662306a36Sopenharmony_ci	u32 rate, format;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	ypcm->period_size = runtime->period_size;
69962306a36Sopenharmony_ci	ypcm->buffer_size = runtime->buffer_size;
70062306a36Sopenharmony_ci	ypcm->period_pos = 0;
70162306a36Sopenharmony_ci	ypcm->last_pos = 0;
70262306a36Sopenharmony_ci	ypcm->shift = 0;
70362306a36Sopenharmony_ci	rate = ((48000 * 4096) / runtime->rate) - 1;
70462306a36Sopenharmony_ci	format = 0;
70562306a36Sopenharmony_ci	if (runtime->channels == 2) {
70662306a36Sopenharmony_ci		format |= 2;
70762306a36Sopenharmony_ci		ypcm->shift++;
70862306a36Sopenharmony_ci	}
70962306a36Sopenharmony_ci	if (snd_pcm_format_width(runtime->format) == 8)
71062306a36Sopenharmony_ci		format |= 1;
71162306a36Sopenharmony_ci	else
71262306a36Sopenharmony_ci		ypcm->shift++;
71362306a36Sopenharmony_ci	switch (ypcm->capture_bank_number) {
71462306a36Sopenharmony_ci	case 0:
71562306a36Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_RECFORMAT, format);
71662306a36Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_RECSLOTSR, rate);
71762306a36Sopenharmony_ci		break;
71862306a36Sopenharmony_ci	case 1:
71962306a36Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_ADCFORMAT, format);
72062306a36Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_ADCSLOTSR, rate);
72162306a36Sopenharmony_ci		break;
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci	for (nbank = 0; nbank < 2; nbank++) {
72462306a36Sopenharmony_ci		bank = chip->bank_capture[ypcm->capture_bank_number][nbank];
72562306a36Sopenharmony_ci		bank->base = cpu_to_le32(runtime->dma_addr);
72662306a36Sopenharmony_ci		bank->loop_end = cpu_to_le32(ypcm->buffer_size << ypcm->shift);
72762306a36Sopenharmony_ci		bank->start = 0;
72862306a36Sopenharmony_ci		bank->num_of_loops = 0;
72962306a36Sopenharmony_ci	}
73062306a36Sopenharmony_ci	return 0;
73162306a36Sopenharmony_ci}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_cistatic snd_pcm_uframes_t snd_ymfpci_playback_pointer(struct snd_pcm_substream *substream)
73462306a36Sopenharmony_ci{
73562306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
73662306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
73762306a36Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = runtime->private_data;
73862306a36Sopenharmony_ci	struct snd_ymfpci_voice *voice = ypcm->voices[0];
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	if (!(ypcm->running && voice))
74162306a36Sopenharmony_ci		return 0;
74262306a36Sopenharmony_ci	return le32_to_cpu(voice->bank[chip->active_bank].start);
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_cistatic snd_pcm_uframes_t snd_ymfpci_capture_pointer(struct snd_pcm_substream *substream)
74662306a36Sopenharmony_ci{
74762306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
74862306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
74962306a36Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = runtime->private_data;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	if (!ypcm->running)
75262306a36Sopenharmony_ci		return 0;
75362306a36Sopenharmony_ci	return le32_to_cpu(chip->bank_capture[ypcm->capture_bank_number][chip->active_bank]->start) >> ypcm->shift;
75462306a36Sopenharmony_ci}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_cistatic void snd_ymfpci_irq_wait(struct snd_ymfpci *chip)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	wait_queue_entry_t wait;
75962306a36Sopenharmony_ci	int loops = 4;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	while (loops-- > 0) {
76262306a36Sopenharmony_ci		if ((snd_ymfpci_readl(chip, YDSXGR_MODE) & 3) == 0)
76362306a36Sopenharmony_ci		 	continue;
76462306a36Sopenharmony_ci		init_waitqueue_entry(&wait, current);
76562306a36Sopenharmony_ci		add_wait_queue(&chip->interrupt_sleep, &wait);
76662306a36Sopenharmony_ci		atomic_inc(&chip->interrupt_sleep_count);
76762306a36Sopenharmony_ci		schedule_timeout_uninterruptible(msecs_to_jiffies(50));
76862306a36Sopenharmony_ci		remove_wait_queue(&chip->interrupt_sleep, &wait);
76962306a36Sopenharmony_ci	}
77062306a36Sopenharmony_ci}
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_cistatic irqreturn_t snd_ymfpci_interrupt(int irq, void *dev_id)
77362306a36Sopenharmony_ci{
77462306a36Sopenharmony_ci	struct snd_ymfpci *chip = dev_id;
77562306a36Sopenharmony_ci	u32 status, nvoice, mode;
77662306a36Sopenharmony_ci	struct snd_ymfpci_voice *voice;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	status = snd_ymfpci_readl(chip, YDSXGR_STATUS);
77962306a36Sopenharmony_ci	if (status & 0x80000000) {
78062306a36Sopenharmony_ci		chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT) & 1;
78162306a36Sopenharmony_ci		spin_lock(&chip->voice_lock);
78262306a36Sopenharmony_ci		for (nvoice = 0; nvoice < YDSXG_PLAYBACK_VOICES; nvoice++) {
78362306a36Sopenharmony_ci			voice = &chip->voices[nvoice];
78462306a36Sopenharmony_ci			if (voice->interrupt)
78562306a36Sopenharmony_ci				voice->interrupt(chip, voice);
78662306a36Sopenharmony_ci		}
78762306a36Sopenharmony_ci		for (nvoice = 0; nvoice < YDSXG_CAPTURE_VOICES; nvoice++) {
78862306a36Sopenharmony_ci			if (chip->capture_substream[nvoice])
78962306a36Sopenharmony_ci				snd_ymfpci_pcm_capture_interrupt(chip->capture_substream[nvoice]);
79062306a36Sopenharmony_ci		}
79162306a36Sopenharmony_ci#if 0
79262306a36Sopenharmony_ci		for (nvoice = 0; nvoice < YDSXG_EFFECT_VOICES; nvoice++) {
79362306a36Sopenharmony_ci			if (chip->effect_substream[nvoice])
79462306a36Sopenharmony_ci				snd_ymfpci_pcm_effect_interrupt(chip->effect_substream[nvoice]);
79562306a36Sopenharmony_ci		}
79662306a36Sopenharmony_ci#endif
79762306a36Sopenharmony_ci		spin_unlock(&chip->voice_lock);
79862306a36Sopenharmony_ci		spin_lock(&chip->reg_lock);
79962306a36Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_STATUS, 0x80000000);
80062306a36Sopenharmony_ci		mode = snd_ymfpci_readl(chip, YDSXGR_MODE) | 2;
80162306a36Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_MODE, mode);
80262306a36Sopenharmony_ci		spin_unlock(&chip->reg_lock);
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci		if (atomic_read(&chip->interrupt_sleep_count)) {
80562306a36Sopenharmony_ci			atomic_set(&chip->interrupt_sleep_count, 0);
80662306a36Sopenharmony_ci			wake_up(&chip->interrupt_sleep);
80762306a36Sopenharmony_ci		}
80862306a36Sopenharmony_ci	}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	status = snd_ymfpci_readw(chip, YDSXGR_INTFLAG);
81162306a36Sopenharmony_ci	if (status & 1) {
81262306a36Sopenharmony_ci		if (chip->timer)
81362306a36Sopenharmony_ci			snd_timer_interrupt(chip->timer, chip->timer_ticks);
81462306a36Sopenharmony_ci	}
81562306a36Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_INTFLAG, status);
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	if (chip->rawmidi)
81862306a36Sopenharmony_ci		snd_mpu401_uart_interrupt(irq, chip->rawmidi->private_data);
81962306a36Sopenharmony_ci	return IRQ_HANDLED;
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_ymfpci_playback =
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci	.info =			(SNDRV_PCM_INFO_MMAP |
82562306a36Sopenharmony_ci				 SNDRV_PCM_INFO_MMAP_VALID |
82662306a36Sopenharmony_ci				 SNDRV_PCM_INFO_INTERLEAVED |
82762306a36Sopenharmony_ci				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
82862306a36Sopenharmony_ci				 SNDRV_PCM_INFO_PAUSE |
82962306a36Sopenharmony_ci				 SNDRV_PCM_INFO_RESUME),
83062306a36Sopenharmony_ci	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
83162306a36Sopenharmony_ci	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
83262306a36Sopenharmony_ci	.rate_min =		8000,
83362306a36Sopenharmony_ci	.rate_max =		48000,
83462306a36Sopenharmony_ci	.channels_min =		1,
83562306a36Sopenharmony_ci	.channels_max =		2,
83662306a36Sopenharmony_ci	.buffer_bytes_max =	256 * 1024, /* FIXME: enough? */
83762306a36Sopenharmony_ci	.period_bytes_min =	64,
83862306a36Sopenharmony_ci	.period_bytes_max =	256 * 1024, /* FIXME: enough? */
83962306a36Sopenharmony_ci	.periods_min =		3,
84062306a36Sopenharmony_ci	.periods_max =		1024,
84162306a36Sopenharmony_ci	.fifo_size =		0,
84262306a36Sopenharmony_ci};
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_ymfpci_capture =
84562306a36Sopenharmony_ci{
84662306a36Sopenharmony_ci	.info =			(SNDRV_PCM_INFO_MMAP |
84762306a36Sopenharmony_ci				 SNDRV_PCM_INFO_MMAP_VALID |
84862306a36Sopenharmony_ci				 SNDRV_PCM_INFO_INTERLEAVED |
84962306a36Sopenharmony_ci				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
85062306a36Sopenharmony_ci				 SNDRV_PCM_INFO_PAUSE |
85162306a36Sopenharmony_ci				 SNDRV_PCM_INFO_RESUME),
85262306a36Sopenharmony_ci	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
85362306a36Sopenharmony_ci	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
85462306a36Sopenharmony_ci	.rate_min =		8000,
85562306a36Sopenharmony_ci	.rate_max =		48000,
85662306a36Sopenharmony_ci	.channels_min =		1,
85762306a36Sopenharmony_ci	.channels_max =		2,
85862306a36Sopenharmony_ci	.buffer_bytes_max =	256 * 1024, /* FIXME: enough? */
85962306a36Sopenharmony_ci	.period_bytes_min =	64,
86062306a36Sopenharmony_ci	.period_bytes_max =	256 * 1024, /* FIXME: enough? */
86162306a36Sopenharmony_ci	.periods_min =		3,
86262306a36Sopenharmony_ci	.periods_max =		1024,
86362306a36Sopenharmony_ci	.fifo_size =		0,
86462306a36Sopenharmony_ci};
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_cistatic void snd_ymfpci_pcm_free_substream(struct snd_pcm_runtime *runtime)
86762306a36Sopenharmony_ci{
86862306a36Sopenharmony_ci	kfree(runtime->private_data);
86962306a36Sopenharmony_ci}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_cistatic int snd_ymfpci_playback_open_1(struct snd_pcm_substream *substream)
87262306a36Sopenharmony_ci{
87362306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
87462306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
87562306a36Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm;
87662306a36Sopenharmony_ci	int err;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	runtime->hw = snd_ymfpci_playback;
87962306a36Sopenharmony_ci	/* FIXME? True value is 256/48 = 5.33333 ms */
88062306a36Sopenharmony_ci	err = snd_pcm_hw_constraint_minmax(runtime,
88162306a36Sopenharmony_ci					   SNDRV_PCM_HW_PARAM_PERIOD_TIME,
88262306a36Sopenharmony_ci					   5334, UINT_MAX);
88362306a36Sopenharmony_ci	if (err < 0)
88462306a36Sopenharmony_ci		return err;
88562306a36Sopenharmony_ci	err = snd_pcm_hw_rule_noresample(runtime, 48000);
88662306a36Sopenharmony_ci	if (err < 0)
88762306a36Sopenharmony_ci		return err;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	ypcm = kzalloc(sizeof(*ypcm), GFP_KERNEL);
89062306a36Sopenharmony_ci	if (ypcm == NULL)
89162306a36Sopenharmony_ci		return -ENOMEM;
89262306a36Sopenharmony_ci	ypcm->chip = chip;
89362306a36Sopenharmony_ci	ypcm->type = PLAYBACK_VOICE;
89462306a36Sopenharmony_ci	ypcm->substream = substream;
89562306a36Sopenharmony_ci	runtime->private_data = ypcm;
89662306a36Sopenharmony_ci	runtime->private_free = snd_ymfpci_pcm_free_substream;
89762306a36Sopenharmony_ci	return 0;
89862306a36Sopenharmony_ci}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci/* call with spinlock held */
90162306a36Sopenharmony_cistatic void ymfpci_open_extension(struct snd_ymfpci *chip)
90262306a36Sopenharmony_ci{
90362306a36Sopenharmony_ci	if (! chip->rear_opened) {
90462306a36Sopenharmony_ci		if (! chip->spdif_opened) /* set AC3 */
90562306a36Sopenharmony_ci			snd_ymfpci_writel(chip, YDSXGR_MODE,
90662306a36Sopenharmony_ci					  snd_ymfpci_readl(chip, YDSXGR_MODE) | (1 << 30));
90762306a36Sopenharmony_ci		/* enable second codec (4CHEN) */
90862306a36Sopenharmony_ci		snd_ymfpci_writew(chip, YDSXGR_SECCONFIG,
90962306a36Sopenharmony_ci				  (snd_ymfpci_readw(chip, YDSXGR_SECCONFIG) & ~0x0330) | 0x0010);
91062306a36Sopenharmony_ci	}
91162306a36Sopenharmony_ci}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci/* call with spinlock held */
91462306a36Sopenharmony_cistatic void ymfpci_close_extension(struct snd_ymfpci *chip)
91562306a36Sopenharmony_ci{
91662306a36Sopenharmony_ci	if (! chip->rear_opened) {
91762306a36Sopenharmony_ci		if (! chip->spdif_opened)
91862306a36Sopenharmony_ci			snd_ymfpci_writel(chip, YDSXGR_MODE,
91962306a36Sopenharmony_ci					  snd_ymfpci_readl(chip, YDSXGR_MODE) & ~(1 << 30));
92062306a36Sopenharmony_ci		snd_ymfpci_writew(chip, YDSXGR_SECCONFIG,
92162306a36Sopenharmony_ci				  (snd_ymfpci_readw(chip, YDSXGR_SECCONFIG) & ~0x0330) & ~0x0010);
92262306a36Sopenharmony_ci	}
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_cistatic int snd_ymfpci_playback_open(struct snd_pcm_substream *substream)
92662306a36Sopenharmony_ci{
92762306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
92862306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
92962306a36Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm;
93062306a36Sopenharmony_ci	int err;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	err = snd_ymfpci_playback_open_1(substream);
93362306a36Sopenharmony_ci	if (err < 0)
93462306a36Sopenharmony_ci		return err;
93562306a36Sopenharmony_ci	ypcm = runtime->private_data;
93662306a36Sopenharmony_ci	ypcm->output_front = 1;
93762306a36Sopenharmony_ci	ypcm->output_rear = chip->mode_dup4ch ? 1 : 0;
93862306a36Sopenharmony_ci	ypcm->swap_rear = 0;
93962306a36Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
94062306a36Sopenharmony_ci	if (ypcm->output_rear) {
94162306a36Sopenharmony_ci		ymfpci_open_extension(chip);
94262306a36Sopenharmony_ci		chip->rear_opened++;
94362306a36Sopenharmony_ci	}
94462306a36Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
94562306a36Sopenharmony_ci	return 0;
94662306a36Sopenharmony_ci}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_cistatic int snd_ymfpci_playback_spdif_open(struct snd_pcm_substream *substream)
94962306a36Sopenharmony_ci{
95062306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
95162306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
95262306a36Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm;
95362306a36Sopenharmony_ci	int err;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	err = snd_ymfpci_playback_open_1(substream);
95662306a36Sopenharmony_ci	if (err < 0)
95762306a36Sopenharmony_ci		return err;
95862306a36Sopenharmony_ci	ypcm = runtime->private_data;
95962306a36Sopenharmony_ci	ypcm->output_front = 0;
96062306a36Sopenharmony_ci	ypcm->output_rear = 1;
96162306a36Sopenharmony_ci	ypcm->swap_rear = 1;
96262306a36Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
96362306a36Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL,
96462306a36Sopenharmony_ci			  snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) | 2);
96562306a36Sopenharmony_ci	ymfpci_open_extension(chip);
96662306a36Sopenharmony_ci	chip->spdif_pcm_bits = chip->spdif_bits;
96762306a36Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_pcm_bits);
96862306a36Sopenharmony_ci	chip->spdif_opened++;
96962306a36Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	chip->spdif_pcm_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
97262306a36Sopenharmony_ci	snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE |
97362306a36Sopenharmony_ci		       SNDRV_CTL_EVENT_MASK_INFO, &chip->spdif_pcm_ctl->id);
97462306a36Sopenharmony_ci	return 0;
97562306a36Sopenharmony_ci}
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_cistatic int snd_ymfpci_playback_4ch_open(struct snd_pcm_substream *substream)
97862306a36Sopenharmony_ci{
97962306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
98062306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
98162306a36Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm;
98262306a36Sopenharmony_ci	int err;
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	err = snd_ymfpci_playback_open_1(substream);
98562306a36Sopenharmony_ci	if (err < 0)
98662306a36Sopenharmony_ci		return err;
98762306a36Sopenharmony_ci	ypcm = runtime->private_data;
98862306a36Sopenharmony_ci	ypcm->output_front = 0;
98962306a36Sopenharmony_ci	ypcm->output_rear = 1;
99062306a36Sopenharmony_ci	ypcm->swap_rear = 0;
99162306a36Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
99262306a36Sopenharmony_ci	ymfpci_open_extension(chip);
99362306a36Sopenharmony_ci	chip->rear_opened++;
99462306a36Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
99562306a36Sopenharmony_ci	return 0;
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_cistatic int snd_ymfpci_capture_open(struct snd_pcm_substream *substream,
99962306a36Sopenharmony_ci				   u32 capture_bank_number)
100062306a36Sopenharmony_ci{
100162306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
100262306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
100362306a36Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm;
100462306a36Sopenharmony_ci	int err;
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	runtime->hw = snd_ymfpci_capture;
100762306a36Sopenharmony_ci	/* FIXME? True value is 256/48 = 5.33333 ms */
100862306a36Sopenharmony_ci	err = snd_pcm_hw_constraint_minmax(runtime,
100962306a36Sopenharmony_ci					   SNDRV_PCM_HW_PARAM_PERIOD_TIME,
101062306a36Sopenharmony_ci					   5334, UINT_MAX);
101162306a36Sopenharmony_ci	if (err < 0)
101262306a36Sopenharmony_ci		return err;
101362306a36Sopenharmony_ci	err = snd_pcm_hw_rule_noresample(runtime, 48000);
101462306a36Sopenharmony_ci	if (err < 0)
101562306a36Sopenharmony_ci		return err;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	ypcm = kzalloc(sizeof(*ypcm), GFP_KERNEL);
101862306a36Sopenharmony_ci	if (ypcm == NULL)
101962306a36Sopenharmony_ci		return -ENOMEM;
102062306a36Sopenharmony_ci	ypcm->chip = chip;
102162306a36Sopenharmony_ci	ypcm->type = capture_bank_number + CAPTURE_REC;
102262306a36Sopenharmony_ci	ypcm->substream = substream;
102362306a36Sopenharmony_ci	ypcm->capture_bank_number = capture_bank_number;
102462306a36Sopenharmony_ci	chip->capture_substream[capture_bank_number] = substream;
102562306a36Sopenharmony_ci	runtime->private_data = ypcm;
102662306a36Sopenharmony_ci	runtime->private_free = snd_ymfpci_pcm_free_substream;
102762306a36Sopenharmony_ci	snd_ymfpci_hw_start(chip);
102862306a36Sopenharmony_ci	return 0;
102962306a36Sopenharmony_ci}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_cistatic int snd_ymfpci_capture_rec_open(struct snd_pcm_substream *substream)
103262306a36Sopenharmony_ci{
103362306a36Sopenharmony_ci	return snd_ymfpci_capture_open(substream, 0);
103462306a36Sopenharmony_ci}
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_cistatic int snd_ymfpci_capture_ac97_open(struct snd_pcm_substream *substream)
103762306a36Sopenharmony_ci{
103862306a36Sopenharmony_ci	return snd_ymfpci_capture_open(substream, 1);
103962306a36Sopenharmony_ci}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_cistatic int snd_ymfpci_playback_close_1(struct snd_pcm_substream *substream)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	return 0;
104462306a36Sopenharmony_ci}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_cistatic int snd_ymfpci_playback_close(struct snd_pcm_substream *substream)
104762306a36Sopenharmony_ci{
104862306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
104962306a36Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
105262306a36Sopenharmony_ci	if (ypcm->output_rear && chip->rear_opened > 0) {
105362306a36Sopenharmony_ci		chip->rear_opened--;
105462306a36Sopenharmony_ci		ymfpci_close_extension(chip);
105562306a36Sopenharmony_ci	}
105662306a36Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
105762306a36Sopenharmony_ci	return snd_ymfpci_playback_close_1(substream);
105862306a36Sopenharmony_ci}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_cistatic int snd_ymfpci_playback_spdif_close(struct snd_pcm_substream *substream)
106162306a36Sopenharmony_ci{
106262306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
106562306a36Sopenharmony_ci	chip->spdif_opened = 0;
106662306a36Sopenharmony_ci	ymfpci_close_extension(chip);
106762306a36Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL,
106862306a36Sopenharmony_ci			  snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) & ~2);
106962306a36Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_bits);
107062306a36Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
107162306a36Sopenharmony_ci	chip->spdif_pcm_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
107262306a36Sopenharmony_ci	snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE |
107362306a36Sopenharmony_ci		       SNDRV_CTL_EVENT_MASK_INFO, &chip->spdif_pcm_ctl->id);
107462306a36Sopenharmony_ci	return snd_ymfpci_playback_close_1(substream);
107562306a36Sopenharmony_ci}
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_cistatic int snd_ymfpci_playback_4ch_close(struct snd_pcm_substream *substream)
107862306a36Sopenharmony_ci{
107962306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
108262306a36Sopenharmony_ci	if (chip->rear_opened > 0) {
108362306a36Sopenharmony_ci		chip->rear_opened--;
108462306a36Sopenharmony_ci		ymfpci_close_extension(chip);
108562306a36Sopenharmony_ci	}
108662306a36Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
108762306a36Sopenharmony_ci	return snd_ymfpci_playback_close_1(substream);
108862306a36Sopenharmony_ci}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_cistatic int snd_ymfpci_capture_close(struct snd_pcm_substream *substream)
109162306a36Sopenharmony_ci{
109262306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
109362306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
109462306a36Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = runtime->private_data;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	if (ypcm != NULL) {
109762306a36Sopenharmony_ci		chip->capture_substream[ypcm->capture_bank_number] = NULL;
109862306a36Sopenharmony_ci		snd_ymfpci_hw_stop(chip);
109962306a36Sopenharmony_ci	}
110062306a36Sopenharmony_ci	return 0;
110162306a36Sopenharmony_ci}
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_ymfpci_playback_ops = {
110462306a36Sopenharmony_ci	.open =			snd_ymfpci_playback_open,
110562306a36Sopenharmony_ci	.close =		snd_ymfpci_playback_close,
110662306a36Sopenharmony_ci	.hw_params =		snd_ymfpci_playback_hw_params,
110762306a36Sopenharmony_ci	.hw_free =		snd_ymfpci_playback_hw_free,
110862306a36Sopenharmony_ci	.prepare =		snd_ymfpci_playback_prepare,
110962306a36Sopenharmony_ci	.trigger =		snd_ymfpci_playback_trigger,
111062306a36Sopenharmony_ci	.pointer =		snd_ymfpci_playback_pointer,
111162306a36Sopenharmony_ci};
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_ymfpci_capture_rec_ops = {
111462306a36Sopenharmony_ci	.open =			snd_ymfpci_capture_rec_open,
111562306a36Sopenharmony_ci	.close =		snd_ymfpci_capture_close,
111662306a36Sopenharmony_ci	.hw_free =		snd_ymfpci_capture_hw_free,
111762306a36Sopenharmony_ci	.prepare =		snd_ymfpci_capture_prepare,
111862306a36Sopenharmony_ci	.trigger =		snd_ymfpci_capture_trigger,
111962306a36Sopenharmony_ci	.pointer =		snd_ymfpci_capture_pointer,
112062306a36Sopenharmony_ci};
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ciint snd_ymfpci_pcm(struct snd_ymfpci *chip, int device)
112362306a36Sopenharmony_ci{
112462306a36Sopenharmony_ci	struct snd_pcm *pcm;
112562306a36Sopenharmony_ci	int err;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	err = snd_pcm_new(chip->card, "YMFPCI", device, 32, 1, &pcm);
112862306a36Sopenharmony_ci	if (err < 0)
112962306a36Sopenharmony_ci		return err;
113062306a36Sopenharmony_ci	pcm->private_data = chip;
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ymfpci_playback_ops);
113362306a36Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ymfpci_capture_rec_ops);
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	/* global setup */
113662306a36Sopenharmony_ci	pcm->info_flags = 0;
113762306a36Sopenharmony_ci	strcpy(pcm->name, "YMFPCI");
113862306a36Sopenharmony_ci	chip->pcm = pcm;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
114162306a36Sopenharmony_ci				       &chip->pci->dev, 64*1024, 256*1024);
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
114462306a36Sopenharmony_ci				     snd_pcm_std_chmaps, 2, 0, NULL);
114562306a36Sopenharmony_ci}
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_ymfpci_capture_ac97_ops = {
114862306a36Sopenharmony_ci	.open =			snd_ymfpci_capture_ac97_open,
114962306a36Sopenharmony_ci	.close =		snd_ymfpci_capture_close,
115062306a36Sopenharmony_ci	.hw_free =		snd_ymfpci_capture_hw_free,
115162306a36Sopenharmony_ci	.prepare =		snd_ymfpci_capture_prepare,
115262306a36Sopenharmony_ci	.trigger =		snd_ymfpci_capture_trigger,
115362306a36Sopenharmony_ci	.pointer =		snd_ymfpci_capture_pointer,
115462306a36Sopenharmony_ci};
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ciint snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device)
115762306a36Sopenharmony_ci{
115862306a36Sopenharmony_ci	struct snd_pcm *pcm;
115962306a36Sopenharmony_ci	int err;
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	err = snd_pcm_new(chip->card, "YMFPCI - PCM2", device, 0, 1, &pcm);
116262306a36Sopenharmony_ci	if (err < 0)
116362306a36Sopenharmony_ci		return err;
116462306a36Sopenharmony_ci	pcm->private_data = chip;
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ymfpci_capture_ac97_ops);
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	/* global setup */
116962306a36Sopenharmony_ci	pcm->info_flags = 0;
117062306a36Sopenharmony_ci	sprintf(pcm->name, "YMFPCI - %s",
117162306a36Sopenharmony_ci		chip->device_id == PCI_DEVICE_ID_YAMAHA_754 ? "Direct Recording" : "AC'97");
117262306a36Sopenharmony_ci	chip->pcm2 = pcm;
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
117562306a36Sopenharmony_ci				       &chip->pci->dev, 64*1024, 256*1024);
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	return 0;
117862306a36Sopenharmony_ci}
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_ymfpci_playback_spdif_ops = {
118162306a36Sopenharmony_ci	.open =			snd_ymfpci_playback_spdif_open,
118262306a36Sopenharmony_ci	.close =		snd_ymfpci_playback_spdif_close,
118362306a36Sopenharmony_ci	.hw_params =		snd_ymfpci_playback_hw_params,
118462306a36Sopenharmony_ci	.hw_free =		snd_ymfpci_playback_hw_free,
118562306a36Sopenharmony_ci	.prepare =		snd_ymfpci_playback_prepare,
118662306a36Sopenharmony_ci	.trigger =		snd_ymfpci_playback_trigger,
118762306a36Sopenharmony_ci	.pointer =		snd_ymfpci_playback_pointer,
118862306a36Sopenharmony_ci};
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ciint snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device)
119162306a36Sopenharmony_ci{
119262306a36Sopenharmony_ci	struct snd_pcm *pcm;
119362306a36Sopenharmony_ci	int err;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	err = snd_pcm_new(chip->card, "YMFPCI - IEC958", device, 1, 0, &pcm);
119662306a36Sopenharmony_ci	if (err < 0)
119762306a36Sopenharmony_ci		return err;
119862306a36Sopenharmony_ci	pcm->private_data = chip;
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ymfpci_playback_spdif_ops);
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	/* global setup */
120362306a36Sopenharmony_ci	pcm->info_flags = 0;
120462306a36Sopenharmony_ci	strcpy(pcm->name, "YMFPCI - IEC958");
120562306a36Sopenharmony_ci	chip->pcm_spdif = pcm;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
120862306a36Sopenharmony_ci				       &chip->pci->dev, 64*1024, 256*1024);
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	return 0;
121162306a36Sopenharmony_ci}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_ymfpci_playback_4ch_ops = {
121462306a36Sopenharmony_ci	.open =			snd_ymfpci_playback_4ch_open,
121562306a36Sopenharmony_ci	.close =		snd_ymfpci_playback_4ch_close,
121662306a36Sopenharmony_ci	.hw_params =		snd_ymfpci_playback_hw_params,
121762306a36Sopenharmony_ci	.hw_free =		snd_ymfpci_playback_hw_free,
121862306a36Sopenharmony_ci	.prepare =		snd_ymfpci_playback_prepare,
121962306a36Sopenharmony_ci	.trigger =		snd_ymfpci_playback_trigger,
122062306a36Sopenharmony_ci	.pointer =		snd_ymfpci_playback_pointer,
122162306a36Sopenharmony_ci};
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_cistatic const struct snd_pcm_chmap_elem surround_map[] = {
122462306a36Sopenharmony_ci	{ .channels = 1,
122562306a36Sopenharmony_ci	  .map = { SNDRV_CHMAP_MONO } },
122662306a36Sopenharmony_ci	{ .channels = 2,
122762306a36Sopenharmony_ci	  .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
122862306a36Sopenharmony_ci	{ }
122962306a36Sopenharmony_ci};
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ciint snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device)
123262306a36Sopenharmony_ci{
123362306a36Sopenharmony_ci	struct snd_pcm *pcm;
123462306a36Sopenharmony_ci	int err;
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	err = snd_pcm_new(chip->card, "YMFPCI - Rear", device, 1, 0, &pcm);
123762306a36Sopenharmony_ci	if (err < 0)
123862306a36Sopenharmony_ci		return err;
123962306a36Sopenharmony_ci	pcm->private_data = chip;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ymfpci_playback_4ch_ops);
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	/* global setup */
124462306a36Sopenharmony_ci	pcm->info_flags = 0;
124562306a36Sopenharmony_ci	strcpy(pcm->name, "YMFPCI - Rear PCM");
124662306a36Sopenharmony_ci	chip->pcm_4ch = pcm;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
124962306a36Sopenharmony_ci				       &chip->pci->dev, 64*1024, 256*1024);
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
125262306a36Sopenharmony_ci				     surround_map, 2, 0, NULL);
125362306a36Sopenharmony_ci}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_cistatic int snd_ymfpci_spdif_default_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
125662306a36Sopenharmony_ci{
125762306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
125862306a36Sopenharmony_ci	uinfo->count = 1;
125962306a36Sopenharmony_ci	return 0;
126062306a36Sopenharmony_ci}
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_cistatic int snd_ymfpci_spdif_default_get(struct snd_kcontrol *kcontrol,
126362306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
126462306a36Sopenharmony_ci{
126562306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
126862306a36Sopenharmony_ci	ucontrol->value.iec958.status[0] = (chip->spdif_bits >> 0) & 0xff;
126962306a36Sopenharmony_ci	ucontrol->value.iec958.status[1] = (chip->spdif_bits >> 8) & 0xff;
127062306a36Sopenharmony_ci	ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000;
127162306a36Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
127262306a36Sopenharmony_ci	return 0;
127362306a36Sopenharmony_ci}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_cistatic int snd_ymfpci_spdif_default_put(struct snd_kcontrol *kcontrol,
127662306a36Sopenharmony_ci					 struct snd_ctl_elem_value *ucontrol)
127762306a36Sopenharmony_ci{
127862306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
127962306a36Sopenharmony_ci	unsigned int val;
128062306a36Sopenharmony_ci	int change;
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	val = ((ucontrol->value.iec958.status[0] & 0x3e) << 0) |
128362306a36Sopenharmony_ci	      (ucontrol->value.iec958.status[1] << 8);
128462306a36Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
128562306a36Sopenharmony_ci	change = chip->spdif_bits != val;
128662306a36Sopenharmony_ci	chip->spdif_bits = val;
128762306a36Sopenharmony_ci	if ((snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) & 1) && chip->pcm_spdif == NULL)
128862306a36Sopenharmony_ci		snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_bits);
128962306a36Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
129062306a36Sopenharmony_ci	return change;
129162306a36Sopenharmony_ci}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_spdif_default =
129462306a36Sopenharmony_ci{
129562306a36Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
129662306a36Sopenharmony_ci	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
129762306a36Sopenharmony_ci	.info =		snd_ymfpci_spdif_default_info,
129862306a36Sopenharmony_ci	.get =		snd_ymfpci_spdif_default_get,
129962306a36Sopenharmony_ci	.put =		snd_ymfpci_spdif_default_put
130062306a36Sopenharmony_ci};
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_cistatic int snd_ymfpci_spdif_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
130362306a36Sopenharmony_ci{
130462306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
130562306a36Sopenharmony_ci	uinfo->count = 1;
130662306a36Sopenharmony_ci	return 0;
130762306a36Sopenharmony_ci}
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_cistatic int snd_ymfpci_spdif_mask_get(struct snd_kcontrol *kcontrol,
131062306a36Sopenharmony_ci				      struct snd_ctl_elem_value *ucontrol)
131162306a36Sopenharmony_ci{
131262306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
131562306a36Sopenharmony_ci	ucontrol->value.iec958.status[0] = 0x3e;
131662306a36Sopenharmony_ci	ucontrol->value.iec958.status[1] = 0xff;
131762306a36Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
131862306a36Sopenharmony_ci	return 0;
131962306a36Sopenharmony_ci}
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_spdif_mask =
132262306a36Sopenharmony_ci{
132362306a36Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
132462306a36Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
132562306a36Sopenharmony_ci	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
132662306a36Sopenharmony_ci	.info =		snd_ymfpci_spdif_mask_info,
132762306a36Sopenharmony_ci	.get =		snd_ymfpci_spdif_mask_get,
132862306a36Sopenharmony_ci};
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_cistatic int snd_ymfpci_spdif_stream_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
133162306a36Sopenharmony_ci{
133262306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
133362306a36Sopenharmony_ci	uinfo->count = 1;
133462306a36Sopenharmony_ci	return 0;
133562306a36Sopenharmony_ci}
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_cistatic int snd_ymfpci_spdif_stream_get(struct snd_kcontrol *kcontrol,
133862306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
133962306a36Sopenharmony_ci{
134062306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
134362306a36Sopenharmony_ci	ucontrol->value.iec958.status[0] = (chip->spdif_pcm_bits >> 0) & 0xff;
134462306a36Sopenharmony_ci	ucontrol->value.iec958.status[1] = (chip->spdif_pcm_bits >> 8) & 0xff;
134562306a36Sopenharmony_ci	ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000;
134662306a36Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
134762306a36Sopenharmony_ci	return 0;
134862306a36Sopenharmony_ci}
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_cistatic int snd_ymfpci_spdif_stream_put(struct snd_kcontrol *kcontrol,
135162306a36Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
135262306a36Sopenharmony_ci{
135362306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
135462306a36Sopenharmony_ci	unsigned int val;
135562306a36Sopenharmony_ci	int change;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	val = ((ucontrol->value.iec958.status[0] & 0x3e) << 0) |
135862306a36Sopenharmony_ci	      (ucontrol->value.iec958.status[1] << 8);
135962306a36Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
136062306a36Sopenharmony_ci	change = chip->spdif_pcm_bits != val;
136162306a36Sopenharmony_ci	chip->spdif_pcm_bits = val;
136262306a36Sopenharmony_ci	if ((snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) & 2))
136362306a36Sopenharmony_ci		snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_pcm_bits);
136462306a36Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
136562306a36Sopenharmony_ci	return change;
136662306a36Sopenharmony_ci}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_spdif_stream =
136962306a36Sopenharmony_ci{
137062306a36Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
137162306a36Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
137262306a36Sopenharmony_ci	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
137362306a36Sopenharmony_ci	.info =		snd_ymfpci_spdif_stream_info,
137462306a36Sopenharmony_ci	.get =		snd_ymfpci_spdif_stream_get,
137562306a36Sopenharmony_ci	.put =		snd_ymfpci_spdif_stream_put
137662306a36Sopenharmony_ci};
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_cistatic int snd_ymfpci_drec_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info)
137962306a36Sopenharmony_ci{
138062306a36Sopenharmony_ci	static const char *const texts[3] = {"AC'97", "IEC958", "ZV Port"};
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	return snd_ctl_enum_info(info, 1, 3, texts);
138362306a36Sopenharmony_ci}
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_cistatic int snd_ymfpci_drec_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value)
138662306a36Sopenharmony_ci{
138762306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
138862306a36Sopenharmony_ci	u16 reg;
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
139162306a36Sopenharmony_ci	reg = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL);
139262306a36Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
139362306a36Sopenharmony_ci	if (!(reg & 0x100))
139462306a36Sopenharmony_ci		value->value.enumerated.item[0] = 0;
139562306a36Sopenharmony_ci	else
139662306a36Sopenharmony_ci		value->value.enumerated.item[0] = 1 + ((reg & 0x200) != 0);
139762306a36Sopenharmony_ci	return 0;
139862306a36Sopenharmony_ci}
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_cistatic int snd_ymfpci_drec_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value)
140162306a36Sopenharmony_ci{
140262306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
140362306a36Sopenharmony_ci	u16 reg, old_reg;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
140662306a36Sopenharmony_ci	old_reg = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL);
140762306a36Sopenharmony_ci	if (value->value.enumerated.item[0] == 0)
140862306a36Sopenharmony_ci		reg = old_reg & ~0x100;
140962306a36Sopenharmony_ci	else
141062306a36Sopenharmony_ci		reg = (old_reg & ~0x300) | 0x100 | ((value->value.enumerated.item[0] == 2) << 9);
141162306a36Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, reg);
141262306a36Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
141362306a36Sopenharmony_ci	return reg != old_reg;
141462306a36Sopenharmony_ci}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_drec_source = {
141762306a36Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
141862306a36Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
141962306a36Sopenharmony_ci	.name =		"Direct Recording Source",
142062306a36Sopenharmony_ci	.info =		snd_ymfpci_drec_source_info,
142162306a36Sopenharmony_ci	.get =		snd_ymfpci_drec_source_get,
142262306a36Sopenharmony_ci	.put =		snd_ymfpci_drec_source_put
142362306a36Sopenharmony_ci};
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci/*
142662306a36Sopenharmony_ci *  Mixer controls
142762306a36Sopenharmony_ci */
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci#define YMFPCI_SINGLE(xname, xindex, reg, shift) \
143062306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
143162306a36Sopenharmony_ci  .info = snd_ymfpci_info_single, \
143262306a36Sopenharmony_ci  .get = snd_ymfpci_get_single, .put = snd_ymfpci_put_single, \
143362306a36Sopenharmony_ci  .private_value = ((reg) | ((shift) << 16)) }
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci#define snd_ymfpci_info_single		snd_ctl_boolean_mono_info
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_cistatic int snd_ymfpci_get_single(struct snd_kcontrol *kcontrol,
143862306a36Sopenharmony_ci				 struct snd_ctl_elem_value *ucontrol)
143962306a36Sopenharmony_ci{
144062306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
144162306a36Sopenharmony_ci	int reg = kcontrol->private_value & 0xffff;
144262306a36Sopenharmony_ci	unsigned int shift = (kcontrol->private_value >> 16) & 0xff;
144362306a36Sopenharmony_ci	unsigned int mask = 1;
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	switch (reg) {
144662306a36Sopenharmony_ci	case YDSXGR_SPDIFOUTCTRL: break;
144762306a36Sopenharmony_ci	case YDSXGR_SPDIFINCTRL: break;
144862306a36Sopenharmony_ci	default: return -EINVAL;
144962306a36Sopenharmony_ci	}
145062306a36Sopenharmony_ci	ucontrol->value.integer.value[0] =
145162306a36Sopenharmony_ci		(snd_ymfpci_readl(chip, reg) >> shift) & mask;
145262306a36Sopenharmony_ci	return 0;
145362306a36Sopenharmony_ci}
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_cistatic int snd_ymfpci_put_single(struct snd_kcontrol *kcontrol,
145662306a36Sopenharmony_ci				 struct snd_ctl_elem_value *ucontrol)
145762306a36Sopenharmony_ci{
145862306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
145962306a36Sopenharmony_ci	int reg = kcontrol->private_value & 0xffff;
146062306a36Sopenharmony_ci	unsigned int shift = (kcontrol->private_value >> 16) & 0xff;
146162306a36Sopenharmony_ci 	unsigned int mask = 1;
146262306a36Sopenharmony_ci	int change;
146362306a36Sopenharmony_ci	unsigned int val, oval;
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	switch (reg) {
146662306a36Sopenharmony_ci	case YDSXGR_SPDIFOUTCTRL: break;
146762306a36Sopenharmony_ci	case YDSXGR_SPDIFINCTRL: break;
146862306a36Sopenharmony_ci	default: return -EINVAL;
146962306a36Sopenharmony_ci	}
147062306a36Sopenharmony_ci	val = (ucontrol->value.integer.value[0] & mask);
147162306a36Sopenharmony_ci	val <<= shift;
147262306a36Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
147362306a36Sopenharmony_ci	oval = snd_ymfpci_readl(chip, reg);
147462306a36Sopenharmony_ci	val = (oval & ~(mask << shift)) | val;
147562306a36Sopenharmony_ci	change = val != oval;
147662306a36Sopenharmony_ci	snd_ymfpci_writel(chip, reg, val);
147762306a36Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
147862306a36Sopenharmony_ci	return change;
147962306a36Sopenharmony_ci}
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_cistatic const DECLARE_TLV_DB_LINEAR(db_scale_native, TLV_DB_GAIN_MUTE, 0);
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci#define YMFPCI_DOUBLE(xname, xindex, reg) \
148462306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
148562306a36Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
148662306a36Sopenharmony_ci  .info = snd_ymfpci_info_double, \
148762306a36Sopenharmony_ci  .get = snd_ymfpci_get_double, .put = snd_ymfpci_put_double, \
148862306a36Sopenharmony_ci  .private_value = reg, \
148962306a36Sopenharmony_ci  .tlv = { .p = db_scale_native } }
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_cistatic int snd_ymfpci_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
149262306a36Sopenharmony_ci{
149362306a36Sopenharmony_ci	unsigned int reg = kcontrol->private_value;
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	if (reg < 0x80 || reg >= 0xc0)
149662306a36Sopenharmony_ci		return -EINVAL;
149762306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
149862306a36Sopenharmony_ci	uinfo->count = 2;
149962306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
150062306a36Sopenharmony_ci	uinfo->value.integer.max = 16383;
150162306a36Sopenharmony_ci	return 0;
150262306a36Sopenharmony_ci}
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_cistatic int snd_ymfpci_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
150562306a36Sopenharmony_ci{
150662306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
150762306a36Sopenharmony_ci	unsigned int reg = kcontrol->private_value;
150862306a36Sopenharmony_ci	unsigned int shift_left = 0, shift_right = 16, mask = 16383;
150962306a36Sopenharmony_ci	unsigned int val;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	if (reg < 0x80 || reg >= 0xc0)
151262306a36Sopenharmony_ci		return -EINVAL;
151362306a36Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
151462306a36Sopenharmony_ci	val = snd_ymfpci_readl(chip, reg);
151562306a36Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
151662306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = (val >> shift_left) & mask;
151762306a36Sopenharmony_ci	ucontrol->value.integer.value[1] = (val >> shift_right) & mask;
151862306a36Sopenharmony_ci	return 0;
151962306a36Sopenharmony_ci}
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_cistatic int snd_ymfpci_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
152262306a36Sopenharmony_ci{
152362306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
152462306a36Sopenharmony_ci	unsigned int reg = kcontrol->private_value;
152562306a36Sopenharmony_ci	unsigned int shift_left = 0, shift_right = 16, mask = 16383;
152662306a36Sopenharmony_ci	int change;
152762306a36Sopenharmony_ci	unsigned int val1, val2, oval;
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	if (reg < 0x80 || reg >= 0xc0)
153062306a36Sopenharmony_ci		return -EINVAL;
153162306a36Sopenharmony_ci	val1 = ucontrol->value.integer.value[0] & mask;
153262306a36Sopenharmony_ci	val2 = ucontrol->value.integer.value[1] & mask;
153362306a36Sopenharmony_ci	val1 <<= shift_left;
153462306a36Sopenharmony_ci	val2 <<= shift_right;
153562306a36Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
153662306a36Sopenharmony_ci	oval = snd_ymfpci_readl(chip, reg);
153762306a36Sopenharmony_ci	val1 = (oval & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2;
153862306a36Sopenharmony_ci	change = val1 != oval;
153962306a36Sopenharmony_ci	snd_ymfpci_writel(chip, reg, val1);
154062306a36Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
154162306a36Sopenharmony_ci	return change;
154262306a36Sopenharmony_ci}
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_cistatic int snd_ymfpci_put_nativedacvol(struct snd_kcontrol *kcontrol,
154562306a36Sopenharmony_ci				       struct snd_ctl_elem_value *ucontrol)
154662306a36Sopenharmony_ci{
154762306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
154862306a36Sopenharmony_ci	unsigned int reg = YDSXGR_NATIVEDACOUTVOL;
154962306a36Sopenharmony_ci	unsigned int reg2 = YDSXGR_BUF441OUTVOL;
155062306a36Sopenharmony_ci	int change;
155162306a36Sopenharmony_ci	unsigned int value, oval;
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	value = ucontrol->value.integer.value[0] & 0x3fff;
155462306a36Sopenharmony_ci	value |= (ucontrol->value.integer.value[1] & 0x3fff) << 16;
155562306a36Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
155662306a36Sopenharmony_ci	oval = snd_ymfpci_readl(chip, reg);
155762306a36Sopenharmony_ci	change = value != oval;
155862306a36Sopenharmony_ci	snd_ymfpci_writel(chip, reg, value);
155962306a36Sopenharmony_ci	snd_ymfpci_writel(chip, reg2, value);
156062306a36Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
156162306a36Sopenharmony_ci	return change;
156262306a36Sopenharmony_ci}
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci/*
156562306a36Sopenharmony_ci * 4ch duplication
156662306a36Sopenharmony_ci */
156762306a36Sopenharmony_ci#define snd_ymfpci_info_dup4ch		snd_ctl_boolean_mono_info
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_cistatic int snd_ymfpci_get_dup4ch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
157062306a36Sopenharmony_ci{
157162306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
157262306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = chip->mode_dup4ch;
157362306a36Sopenharmony_ci	return 0;
157462306a36Sopenharmony_ci}
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_cistatic int snd_ymfpci_put_dup4ch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
157762306a36Sopenharmony_ci{
157862306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
157962306a36Sopenharmony_ci	int change;
158062306a36Sopenharmony_ci	change = (ucontrol->value.integer.value[0] != chip->mode_dup4ch);
158162306a36Sopenharmony_ci	if (change)
158262306a36Sopenharmony_ci		chip->mode_dup4ch = !!ucontrol->value.integer.value[0];
158362306a36Sopenharmony_ci	return change;
158462306a36Sopenharmony_ci}
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_dup4ch = {
158762306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
158862306a36Sopenharmony_ci	.name = "4ch Duplication",
158962306a36Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
159062306a36Sopenharmony_ci	.info = snd_ymfpci_info_dup4ch,
159162306a36Sopenharmony_ci	.get = snd_ymfpci_get_dup4ch,
159262306a36Sopenharmony_ci	.put = snd_ymfpci_put_dup4ch,
159362306a36Sopenharmony_ci};
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_controls[] = {
159662306a36Sopenharmony_ci{
159762306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
159862306a36Sopenharmony_ci	.name = "Wave Playback Volume",
159962306a36Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
160062306a36Sopenharmony_ci		  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
160162306a36Sopenharmony_ci	.info = snd_ymfpci_info_double,
160262306a36Sopenharmony_ci	.get = snd_ymfpci_get_double,
160362306a36Sopenharmony_ci	.put = snd_ymfpci_put_nativedacvol,
160462306a36Sopenharmony_ci	.private_value = YDSXGR_NATIVEDACOUTVOL,
160562306a36Sopenharmony_ci	.tlv = { .p = db_scale_native },
160662306a36Sopenharmony_ci},
160762306a36Sopenharmony_ciYMFPCI_DOUBLE("Wave Capture Volume", 0, YDSXGR_NATIVEDACLOOPVOL),
160862306a36Sopenharmony_ciYMFPCI_DOUBLE("Digital Capture Volume", 0, YDSXGR_NATIVEDACINVOL),
160962306a36Sopenharmony_ciYMFPCI_DOUBLE("Digital Capture Volume", 1, YDSXGR_NATIVEADCINVOL),
161062306a36Sopenharmony_ciYMFPCI_DOUBLE("ADC Playback Volume", 0, YDSXGR_PRIADCOUTVOL),
161162306a36Sopenharmony_ciYMFPCI_DOUBLE("ADC Capture Volume", 0, YDSXGR_PRIADCLOOPVOL),
161262306a36Sopenharmony_ciYMFPCI_DOUBLE("ADC Playback Volume", 1, YDSXGR_SECADCOUTVOL),
161362306a36Sopenharmony_ciYMFPCI_DOUBLE("ADC Capture Volume", 1, YDSXGR_SECADCLOOPVOL),
161462306a36Sopenharmony_ciYMFPCI_DOUBLE("FM Legacy Playback Volume", 0, YDSXGR_LEGACYOUTVOL),
161562306a36Sopenharmony_ciYMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ", PLAYBACK,VOLUME), 0, YDSXGR_ZVOUTVOL),
161662306a36Sopenharmony_ciYMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("", CAPTURE,VOLUME), 0, YDSXGR_ZVLOOPVOL),
161762306a36Sopenharmony_ciYMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ",PLAYBACK,VOLUME), 1, YDSXGR_SPDIFOUTVOL),
161862306a36Sopenharmony_ciYMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,VOLUME), 1, YDSXGR_SPDIFLOOPVOL),
161962306a36Sopenharmony_ciYMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), 0, YDSXGR_SPDIFOUTCTRL, 0),
162062306a36Sopenharmony_ciYMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0, YDSXGR_SPDIFINCTRL, 0),
162162306a36Sopenharmony_ciYMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("Loop",NONE,NONE), 0, YDSXGR_SPDIFINCTRL, 4),
162262306a36Sopenharmony_ci};
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci/*
162662306a36Sopenharmony_ci * GPIO
162762306a36Sopenharmony_ci */
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_cistatic int snd_ymfpci_get_gpio_out(struct snd_ymfpci *chip, int pin)
163062306a36Sopenharmony_ci{
163162306a36Sopenharmony_ci	u16 reg, mode;
163262306a36Sopenharmony_ci	unsigned long flags;
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
163562306a36Sopenharmony_ci	reg = snd_ymfpci_readw(chip, YDSXGR_GPIOFUNCENABLE);
163662306a36Sopenharmony_ci	reg &= ~(1 << (pin + 8));
163762306a36Sopenharmony_ci	reg |= (1 << pin);
163862306a36Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg);
163962306a36Sopenharmony_ci	/* set the level mode for input line */
164062306a36Sopenharmony_ci	mode = snd_ymfpci_readw(chip, YDSXGR_GPIOTYPECONFIG);
164162306a36Sopenharmony_ci	mode &= ~(3 << (pin * 2));
164262306a36Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_GPIOTYPECONFIG, mode);
164362306a36Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg | (1 << (pin + 8)));
164462306a36Sopenharmony_ci	mode = snd_ymfpci_readw(chip, YDSXGR_GPIOINSTATUS);
164562306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
164662306a36Sopenharmony_ci	return (mode >> pin) & 1;
164762306a36Sopenharmony_ci}
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_cistatic int snd_ymfpci_set_gpio_out(struct snd_ymfpci *chip, int pin, int enable)
165062306a36Sopenharmony_ci{
165162306a36Sopenharmony_ci	u16 reg;
165262306a36Sopenharmony_ci	unsigned long flags;
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
165562306a36Sopenharmony_ci	reg = snd_ymfpci_readw(chip, YDSXGR_GPIOFUNCENABLE);
165662306a36Sopenharmony_ci	reg &= ~(1 << pin);
165762306a36Sopenharmony_ci	reg &= ~(1 << (pin + 8));
165862306a36Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg);
165962306a36Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_GPIOOUTCTRL, enable << pin);
166062306a36Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg | (1 << (pin + 8)));
166162306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	return 0;
166462306a36Sopenharmony_ci}
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci#define snd_ymfpci_gpio_sw_info		snd_ctl_boolean_mono_info
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_cistatic int snd_ymfpci_gpio_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
166962306a36Sopenharmony_ci{
167062306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
167162306a36Sopenharmony_ci	int pin = (int)kcontrol->private_value;
167262306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = snd_ymfpci_get_gpio_out(chip, pin);
167362306a36Sopenharmony_ci	return 0;
167462306a36Sopenharmony_ci}
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_cistatic int snd_ymfpci_gpio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
167762306a36Sopenharmony_ci{
167862306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
167962306a36Sopenharmony_ci	int pin = (int)kcontrol->private_value;
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	if (snd_ymfpci_get_gpio_out(chip, pin) != ucontrol->value.integer.value[0]) {
168262306a36Sopenharmony_ci		snd_ymfpci_set_gpio_out(chip, pin, !!ucontrol->value.integer.value[0]);
168362306a36Sopenharmony_ci		ucontrol->value.integer.value[0] = snd_ymfpci_get_gpio_out(chip, pin);
168462306a36Sopenharmony_ci		return 1;
168562306a36Sopenharmony_ci	}
168662306a36Sopenharmony_ci	return 0;
168762306a36Sopenharmony_ci}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_rear_shared = {
169062306a36Sopenharmony_ci	.name = "Shared Rear/Line-In Switch",
169162306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
169262306a36Sopenharmony_ci	.info = snd_ymfpci_gpio_sw_info,
169362306a36Sopenharmony_ci	.get = snd_ymfpci_gpio_sw_get,
169462306a36Sopenharmony_ci	.put = snd_ymfpci_gpio_sw_put,
169562306a36Sopenharmony_ci	.private_value = 2,
169662306a36Sopenharmony_ci};
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci/*
169962306a36Sopenharmony_ci * PCM voice volume
170062306a36Sopenharmony_ci */
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_cistatic int snd_ymfpci_pcm_vol_info(struct snd_kcontrol *kcontrol,
170362306a36Sopenharmony_ci				   struct snd_ctl_elem_info *uinfo)
170462306a36Sopenharmony_ci{
170562306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
170662306a36Sopenharmony_ci	uinfo->count = 2;
170762306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
170862306a36Sopenharmony_ci	uinfo->value.integer.max = 0x8000;
170962306a36Sopenharmony_ci	return 0;
171062306a36Sopenharmony_ci}
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_cistatic int snd_ymfpci_pcm_vol_get(struct snd_kcontrol *kcontrol,
171362306a36Sopenharmony_ci				  struct snd_ctl_elem_value *ucontrol)
171462306a36Sopenharmony_ci{
171562306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
171662306a36Sopenharmony_ci	unsigned int subs = kcontrol->id.subdevice;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = chip->pcm_mixer[subs].left;
171962306a36Sopenharmony_ci	ucontrol->value.integer.value[1] = chip->pcm_mixer[subs].right;
172062306a36Sopenharmony_ci	return 0;
172162306a36Sopenharmony_ci}
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_cistatic int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol,
172462306a36Sopenharmony_ci				  struct snd_ctl_elem_value *ucontrol)
172562306a36Sopenharmony_ci{
172662306a36Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
172762306a36Sopenharmony_ci	unsigned int subs = kcontrol->id.subdevice;
172862306a36Sopenharmony_ci	struct snd_pcm_substream *substream;
172962306a36Sopenharmony_ci	unsigned long flags;
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	if (ucontrol->value.integer.value[0] != chip->pcm_mixer[subs].left ||
173262306a36Sopenharmony_ci	    ucontrol->value.integer.value[1] != chip->pcm_mixer[subs].right) {
173362306a36Sopenharmony_ci		chip->pcm_mixer[subs].left = ucontrol->value.integer.value[0];
173462306a36Sopenharmony_ci		chip->pcm_mixer[subs].right = ucontrol->value.integer.value[1];
173562306a36Sopenharmony_ci		if (chip->pcm_mixer[subs].left > 0x8000)
173662306a36Sopenharmony_ci			chip->pcm_mixer[subs].left = 0x8000;
173762306a36Sopenharmony_ci		if (chip->pcm_mixer[subs].right > 0x8000)
173862306a36Sopenharmony_ci			chip->pcm_mixer[subs].right = 0x8000;
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci		substream = (struct snd_pcm_substream *)kcontrol->private_value;
174162306a36Sopenharmony_ci		spin_lock_irqsave(&chip->voice_lock, flags);
174262306a36Sopenharmony_ci		if (substream->runtime && substream->runtime->private_data) {
174362306a36Sopenharmony_ci			struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data;
174462306a36Sopenharmony_ci			if (!ypcm->use_441_slot)
174562306a36Sopenharmony_ci				ypcm->update_pcm_vol = 2;
174662306a36Sopenharmony_ci		}
174762306a36Sopenharmony_ci		spin_unlock_irqrestore(&chip->voice_lock, flags);
174862306a36Sopenharmony_ci		return 1;
174962306a36Sopenharmony_ci	}
175062306a36Sopenharmony_ci	return 0;
175162306a36Sopenharmony_ci}
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_pcm_volume = {
175462306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_PCM,
175562306a36Sopenharmony_ci	.name = "PCM Playback Volume",
175662306a36Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
175762306a36Sopenharmony_ci		SNDRV_CTL_ELEM_ACCESS_INACTIVE,
175862306a36Sopenharmony_ci	.info = snd_ymfpci_pcm_vol_info,
175962306a36Sopenharmony_ci	.get = snd_ymfpci_pcm_vol_get,
176062306a36Sopenharmony_ci	.put = snd_ymfpci_pcm_vol_put,
176162306a36Sopenharmony_ci};
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci/*
176562306a36Sopenharmony_ci *  Mixer routines
176662306a36Sopenharmony_ci */
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_cistatic void snd_ymfpci_mixer_free_ac97_bus(struct snd_ac97_bus *bus)
176962306a36Sopenharmony_ci{
177062306a36Sopenharmony_ci	struct snd_ymfpci *chip = bus->private_data;
177162306a36Sopenharmony_ci	chip->ac97_bus = NULL;
177262306a36Sopenharmony_ci}
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_cistatic void snd_ymfpci_mixer_free_ac97(struct snd_ac97 *ac97)
177562306a36Sopenharmony_ci{
177662306a36Sopenharmony_ci	struct snd_ymfpci *chip = ac97->private_data;
177762306a36Sopenharmony_ci	chip->ac97 = NULL;
177862306a36Sopenharmony_ci}
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ciint snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch)
178162306a36Sopenharmony_ci{
178262306a36Sopenharmony_ci	struct snd_ac97_template ac97;
178362306a36Sopenharmony_ci	struct snd_kcontrol *kctl;
178462306a36Sopenharmony_ci	struct snd_pcm_substream *substream;
178562306a36Sopenharmony_ci	unsigned int idx;
178662306a36Sopenharmony_ci	int err;
178762306a36Sopenharmony_ci	static const struct snd_ac97_bus_ops ops = {
178862306a36Sopenharmony_ci		.write = snd_ymfpci_codec_write,
178962306a36Sopenharmony_ci		.read = snd_ymfpci_codec_read,
179062306a36Sopenharmony_ci	};
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus);
179362306a36Sopenharmony_ci	if (err < 0)
179462306a36Sopenharmony_ci		return err;
179562306a36Sopenharmony_ci	chip->ac97_bus->private_free = snd_ymfpci_mixer_free_ac97_bus;
179662306a36Sopenharmony_ci	chip->ac97_bus->no_vra = 1; /* YMFPCI doesn't need VRA */
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	memset(&ac97, 0, sizeof(ac97));
179962306a36Sopenharmony_ci	ac97.private_data = chip;
180062306a36Sopenharmony_ci	ac97.private_free = snd_ymfpci_mixer_free_ac97;
180162306a36Sopenharmony_ci	err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97);
180262306a36Sopenharmony_ci	if (err < 0)
180362306a36Sopenharmony_ci		return err;
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	/* to be sure */
180662306a36Sopenharmony_ci	snd_ac97_update_bits(chip->ac97, AC97_EXTENDED_STATUS,
180762306a36Sopenharmony_ci			     AC97_EA_VRA|AC97_EA_VRM, 0);
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	for (idx = 0; idx < ARRAY_SIZE(snd_ymfpci_controls); idx++) {
181062306a36Sopenharmony_ci		err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_controls[idx], chip));
181162306a36Sopenharmony_ci		if (err < 0)
181262306a36Sopenharmony_ci			return err;
181362306a36Sopenharmony_ci	}
181462306a36Sopenharmony_ci	if (chip->ac97->ext_id & AC97_EI_SDAC) {
181562306a36Sopenharmony_ci		kctl = snd_ctl_new1(&snd_ymfpci_dup4ch, chip);
181662306a36Sopenharmony_ci		err = snd_ctl_add(chip->card, kctl);
181762306a36Sopenharmony_ci		if (err < 0)
181862306a36Sopenharmony_ci			return err;
181962306a36Sopenharmony_ci	}
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	/* add S/PDIF control */
182262306a36Sopenharmony_ci	if (snd_BUG_ON(!chip->pcm_spdif))
182362306a36Sopenharmony_ci		return -ENXIO;
182462306a36Sopenharmony_ci	kctl = snd_ctl_new1(&snd_ymfpci_spdif_default, chip);
182562306a36Sopenharmony_ci	kctl->id.device = chip->pcm_spdif->device;
182662306a36Sopenharmony_ci	err = snd_ctl_add(chip->card, kctl);
182762306a36Sopenharmony_ci	if (err < 0)
182862306a36Sopenharmony_ci		return err;
182962306a36Sopenharmony_ci	kctl = snd_ctl_new1(&snd_ymfpci_spdif_mask, chip);
183062306a36Sopenharmony_ci	kctl->id.device = chip->pcm_spdif->device;
183162306a36Sopenharmony_ci	err = snd_ctl_add(chip->card, kctl);
183262306a36Sopenharmony_ci	if (err < 0)
183362306a36Sopenharmony_ci		return err;
183462306a36Sopenharmony_ci	kctl = snd_ctl_new1(&snd_ymfpci_spdif_stream, chip);
183562306a36Sopenharmony_ci	kctl->id.device = chip->pcm_spdif->device;
183662306a36Sopenharmony_ci	err = snd_ctl_add(chip->card, kctl);
183762306a36Sopenharmony_ci	if (err < 0)
183862306a36Sopenharmony_ci		return err;
183962306a36Sopenharmony_ci	chip->spdif_pcm_ctl = kctl;
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	/* direct recording source */
184262306a36Sopenharmony_ci	if (chip->device_id == PCI_DEVICE_ID_YAMAHA_754) {
184362306a36Sopenharmony_ci		kctl = snd_ctl_new1(&snd_ymfpci_drec_source, chip);
184462306a36Sopenharmony_ci		err = snd_ctl_add(chip->card, kctl);
184562306a36Sopenharmony_ci		if (err < 0)
184662306a36Sopenharmony_ci			return err;
184762306a36Sopenharmony_ci	}
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	/*
185062306a36Sopenharmony_ci	 * shared rear/line-in
185162306a36Sopenharmony_ci	 */
185262306a36Sopenharmony_ci	if (rear_switch) {
185362306a36Sopenharmony_ci		err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_rear_shared, chip));
185462306a36Sopenharmony_ci		if (err < 0)
185562306a36Sopenharmony_ci			return err;
185662306a36Sopenharmony_ci	}
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	/* per-voice volume */
185962306a36Sopenharmony_ci	substream = chip->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
186062306a36Sopenharmony_ci	for (idx = 0; idx < 32; ++idx) {
186162306a36Sopenharmony_ci		kctl = snd_ctl_new1(&snd_ymfpci_pcm_volume, chip);
186262306a36Sopenharmony_ci		if (!kctl)
186362306a36Sopenharmony_ci			return -ENOMEM;
186462306a36Sopenharmony_ci		kctl->id.device = chip->pcm->device;
186562306a36Sopenharmony_ci		kctl->id.subdevice = idx;
186662306a36Sopenharmony_ci		kctl->private_value = (unsigned long)substream;
186762306a36Sopenharmony_ci		err = snd_ctl_add(chip->card, kctl);
186862306a36Sopenharmony_ci		if (err < 0)
186962306a36Sopenharmony_ci			return err;
187062306a36Sopenharmony_ci		chip->pcm_mixer[idx].left = 0x8000;
187162306a36Sopenharmony_ci		chip->pcm_mixer[idx].right = 0x8000;
187262306a36Sopenharmony_ci		chip->pcm_mixer[idx].ctl = kctl;
187362306a36Sopenharmony_ci		substream = substream->next;
187462306a36Sopenharmony_ci	}
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	return 0;
187762306a36Sopenharmony_ci}
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci/*
188162306a36Sopenharmony_ci * timer
188262306a36Sopenharmony_ci */
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_cistatic int snd_ymfpci_timer_start(struct snd_timer *timer)
188562306a36Sopenharmony_ci{
188662306a36Sopenharmony_ci	struct snd_ymfpci *chip;
188762306a36Sopenharmony_ci	unsigned long flags;
188862306a36Sopenharmony_ci	unsigned int count;
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	chip = snd_timer_chip(timer);
189162306a36Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
189262306a36Sopenharmony_ci	if (timer->sticks > 1) {
189362306a36Sopenharmony_ci		chip->timer_ticks = timer->sticks;
189462306a36Sopenharmony_ci		count = timer->sticks - 1;
189562306a36Sopenharmony_ci	} else {
189662306a36Sopenharmony_ci		/*
189762306a36Sopenharmony_ci		 * Divisor 1 is not allowed; fake it by using divisor 2 and
189862306a36Sopenharmony_ci		 * counting two ticks for each interrupt.
189962306a36Sopenharmony_ci		 */
190062306a36Sopenharmony_ci		chip->timer_ticks = 2;
190162306a36Sopenharmony_ci		count = 2 - 1;
190262306a36Sopenharmony_ci	}
190362306a36Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_TIMERCOUNT, count);
190462306a36Sopenharmony_ci	snd_ymfpci_writeb(chip, YDSXGR_TIMERCTRL, 0x03);
190562306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
190662306a36Sopenharmony_ci	return 0;
190762306a36Sopenharmony_ci}
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_cistatic int snd_ymfpci_timer_stop(struct snd_timer *timer)
191062306a36Sopenharmony_ci{
191162306a36Sopenharmony_ci	struct snd_ymfpci *chip;
191262306a36Sopenharmony_ci	unsigned long flags;
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci	chip = snd_timer_chip(timer);
191562306a36Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
191662306a36Sopenharmony_ci	snd_ymfpci_writeb(chip, YDSXGR_TIMERCTRL, 0x00);
191762306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
191862306a36Sopenharmony_ci	return 0;
191962306a36Sopenharmony_ci}
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_cistatic int snd_ymfpci_timer_precise_resolution(struct snd_timer *timer,
192262306a36Sopenharmony_ci					       unsigned long *num, unsigned long *den)
192362306a36Sopenharmony_ci{
192462306a36Sopenharmony_ci	*num = 1;
192562306a36Sopenharmony_ci	*den = 96000;
192662306a36Sopenharmony_ci	return 0;
192762306a36Sopenharmony_ci}
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_cistatic const struct snd_timer_hardware snd_ymfpci_timer_hw = {
193062306a36Sopenharmony_ci	.flags = SNDRV_TIMER_HW_AUTO,
193162306a36Sopenharmony_ci	.resolution = 10417, /* 1 / 96 kHz = 10.41666...us */
193262306a36Sopenharmony_ci	.ticks = 0x10000,
193362306a36Sopenharmony_ci	.start = snd_ymfpci_timer_start,
193462306a36Sopenharmony_ci	.stop = snd_ymfpci_timer_stop,
193562306a36Sopenharmony_ci	.precise_resolution = snd_ymfpci_timer_precise_resolution,
193662306a36Sopenharmony_ci};
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ciint snd_ymfpci_timer(struct snd_ymfpci *chip, int device)
193962306a36Sopenharmony_ci{
194062306a36Sopenharmony_ci	struct snd_timer *timer = NULL;
194162306a36Sopenharmony_ci	struct snd_timer_id tid;
194262306a36Sopenharmony_ci	int err;
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	tid.dev_class = SNDRV_TIMER_CLASS_CARD;
194562306a36Sopenharmony_ci	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
194662306a36Sopenharmony_ci	tid.card = chip->card->number;
194762306a36Sopenharmony_ci	tid.device = device;
194862306a36Sopenharmony_ci	tid.subdevice = 0;
194962306a36Sopenharmony_ci	err = snd_timer_new(chip->card, "YMFPCI", &tid, &timer);
195062306a36Sopenharmony_ci	if (err >= 0) {
195162306a36Sopenharmony_ci		strcpy(timer->name, "YMFPCI timer");
195262306a36Sopenharmony_ci		timer->private_data = chip;
195362306a36Sopenharmony_ci		timer->hw = snd_ymfpci_timer_hw;
195462306a36Sopenharmony_ci	}
195562306a36Sopenharmony_ci	chip->timer = timer;
195662306a36Sopenharmony_ci	return err;
195762306a36Sopenharmony_ci}
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci/*
196162306a36Sopenharmony_ci *  proc interface
196262306a36Sopenharmony_ci */
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_cistatic void snd_ymfpci_proc_read(struct snd_info_entry *entry,
196562306a36Sopenharmony_ci				 struct snd_info_buffer *buffer)
196662306a36Sopenharmony_ci{
196762306a36Sopenharmony_ci	struct snd_ymfpci *chip = entry->private_data;
196862306a36Sopenharmony_ci	int i;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	snd_iprintf(buffer, "YMFPCI\n\n");
197162306a36Sopenharmony_ci	for (i = 0; i <= YDSXGR_WORKBASE; i += 4)
197262306a36Sopenharmony_ci		snd_iprintf(buffer, "%04x: %04x\n", i, snd_ymfpci_readl(chip, i));
197362306a36Sopenharmony_ci}
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_cistatic int snd_ymfpci_proc_init(struct snd_card *card, struct snd_ymfpci *chip)
197662306a36Sopenharmony_ci{
197762306a36Sopenharmony_ci	return snd_card_ro_proc_new(card, "ymfpci", chip, snd_ymfpci_proc_read);
197862306a36Sopenharmony_ci}
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci/*
198162306a36Sopenharmony_ci *  initialization routines
198262306a36Sopenharmony_ci */
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_cistatic void snd_ymfpci_aclink_reset(struct pci_dev * pci)
198562306a36Sopenharmony_ci{
198662306a36Sopenharmony_ci	u8 cmd;
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci	pci_read_config_byte(pci, PCIR_DSXG_CTRL, &cmd);
198962306a36Sopenharmony_ci#if 0 // force to reset
199062306a36Sopenharmony_ci	if (cmd & 0x03) {
199162306a36Sopenharmony_ci#endif
199262306a36Sopenharmony_ci		pci_write_config_byte(pci, PCIR_DSXG_CTRL, cmd & 0xfc);
199362306a36Sopenharmony_ci		pci_write_config_byte(pci, PCIR_DSXG_CTRL, cmd | 0x03);
199462306a36Sopenharmony_ci		pci_write_config_byte(pci, PCIR_DSXG_CTRL, cmd & 0xfc);
199562306a36Sopenharmony_ci		pci_write_config_word(pci, PCIR_DSXG_PWRCTRL1, 0);
199662306a36Sopenharmony_ci		pci_write_config_word(pci, PCIR_DSXG_PWRCTRL2, 0);
199762306a36Sopenharmony_ci#if 0
199862306a36Sopenharmony_ci	}
199962306a36Sopenharmony_ci#endif
200062306a36Sopenharmony_ci}
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_cistatic void snd_ymfpci_enable_dsp(struct snd_ymfpci *chip)
200362306a36Sopenharmony_ci{
200462306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_CONFIG, 0x00000001);
200562306a36Sopenharmony_ci}
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_cistatic void snd_ymfpci_disable_dsp(struct snd_ymfpci *chip)
200862306a36Sopenharmony_ci{
200962306a36Sopenharmony_ci	u32 val;
201062306a36Sopenharmony_ci	int timeout = 1000;
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci	val = snd_ymfpci_readl(chip, YDSXGR_CONFIG);
201362306a36Sopenharmony_ci	if (val)
201462306a36Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_CONFIG, 0x00000000);
201562306a36Sopenharmony_ci	while (timeout-- > 0) {
201662306a36Sopenharmony_ci		val = snd_ymfpci_readl(chip, YDSXGR_STATUS);
201762306a36Sopenharmony_ci		if ((val & 0x00000002) == 0)
201862306a36Sopenharmony_ci			break;
201962306a36Sopenharmony_ci	}
202062306a36Sopenharmony_ci}
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_cistatic int snd_ymfpci_request_firmware(struct snd_ymfpci *chip)
202362306a36Sopenharmony_ci{
202462306a36Sopenharmony_ci	int err, is_1e;
202562306a36Sopenharmony_ci	const char *name;
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci	err = request_firmware(&chip->dsp_microcode, "yamaha/ds1_dsp.fw",
202862306a36Sopenharmony_ci			       &chip->pci->dev);
202962306a36Sopenharmony_ci	if (err >= 0) {
203062306a36Sopenharmony_ci		if (chip->dsp_microcode->size != YDSXG_DSPLENGTH) {
203162306a36Sopenharmony_ci			dev_err(chip->card->dev,
203262306a36Sopenharmony_ci				"DSP microcode has wrong size\n");
203362306a36Sopenharmony_ci			err = -EINVAL;
203462306a36Sopenharmony_ci		}
203562306a36Sopenharmony_ci	}
203662306a36Sopenharmony_ci	if (err < 0)
203762306a36Sopenharmony_ci		return err;
203862306a36Sopenharmony_ci	is_1e = chip->device_id == PCI_DEVICE_ID_YAMAHA_724F ||
203962306a36Sopenharmony_ci		chip->device_id == PCI_DEVICE_ID_YAMAHA_740C ||
204062306a36Sopenharmony_ci		chip->device_id == PCI_DEVICE_ID_YAMAHA_744 ||
204162306a36Sopenharmony_ci		chip->device_id == PCI_DEVICE_ID_YAMAHA_754;
204262306a36Sopenharmony_ci	name = is_1e ? "yamaha/ds1e_ctrl.fw" : "yamaha/ds1_ctrl.fw";
204362306a36Sopenharmony_ci	err = request_firmware(&chip->controller_microcode, name,
204462306a36Sopenharmony_ci			       &chip->pci->dev);
204562306a36Sopenharmony_ci	if (err >= 0) {
204662306a36Sopenharmony_ci		if (chip->controller_microcode->size != YDSXG_CTRLLENGTH) {
204762306a36Sopenharmony_ci			dev_err(chip->card->dev,
204862306a36Sopenharmony_ci				"controller microcode has wrong size\n");
204962306a36Sopenharmony_ci			err = -EINVAL;
205062306a36Sopenharmony_ci		}
205162306a36Sopenharmony_ci	}
205262306a36Sopenharmony_ci	if (err < 0)
205362306a36Sopenharmony_ci		return err;
205462306a36Sopenharmony_ci	return 0;
205562306a36Sopenharmony_ci}
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ciMODULE_FIRMWARE("yamaha/ds1_dsp.fw");
205862306a36Sopenharmony_ciMODULE_FIRMWARE("yamaha/ds1_ctrl.fw");
205962306a36Sopenharmony_ciMODULE_FIRMWARE("yamaha/ds1e_ctrl.fw");
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_cistatic void snd_ymfpci_download_image(struct snd_ymfpci *chip)
206262306a36Sopenharmony_ci{
206362306a36Sopenharmony_ci	int i;
206462306a36Sopenharmony_ci	u16 ctrl;
206562306a36Sopenharmony_ci	const __le32 *inst;
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x00000000);
206862306a36Sopenharmony_ci	snd_ymfpci_disable_dsp(chip);
206962306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_MODE, 0x00010000);
207062306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_MODE, 0x00000000);
207162306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_MAPOFREC, 0x00000000);
207262306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT, 0x00000000);
207362306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, 0x00000000);
207462306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_RECCTRLBASE, 0x00000000);
207562306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_EFFCTRLBASE, 0x00000000);
207662306a36Sopenharmony_ci	ctrl = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL);
207762306a36Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci	/* setup DSP instruction code */
208062306a36Sopenharmony_ci	inst = (const __le32 *)chip->dsp_microcode->data;
208162306a36Sopenharmony_ci	for (i = 0; i < YDSXG_DSPLENGTH / 4; i++)
208262306a36Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2),
208362306a36Sopenharmony_ci				  le32_to_cpu(inst[i]));
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci	/* setup control instruction code */
208662306a36Sopenharmony_ci	inst = (const __le32 *)chip->controller_microcode->data;
208762306a36Sopenharmony_ci	for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++)
208862306a36Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_CTRLINSTRAM + (i << 2),
208962306a36Sopenharmony_ci				  le32_to_cpu(inst[i]));
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	snd_ymfpci_enable_dsp(chip);
209262306a36Sopenharmony_ci}
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_cistatic int snd_ymfpci_memalloc(struct snd_ymfpci *chip)
209562306a36Sopenharmony_ci{
209662306a36Sopenharmony_ci	long size, playback_ctrl_size;
209762306a36Sopenharmony_ci	int voice, bank, reg;
209862306a36Sopenharmony_ci	u8 *ptr;
209962306a36Sopenharmony_ci	dma_addr_t ptr_addr;
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci	playback_ctrl_size = 4 + 4 * YDSXG_PLAYBACK_VOICES;
210262306a36Sopenharmony_ci	chip->bank_size_playback = snd_ymfpci_readl(chip, YDSXGR_PLAYCTRLSIZE) << 2;
210362306a36Sopenharmony_ci	chip->bank_size_capture = snd_ymfpci_readl(chip, YDSXGR_RECCTRLSIZE) << 2;
210462306a36Sopenharmony_ci	chip->bank_size_effect = snd_ymfpci_readl(chip, YDSXGR_EFFCTRLSIZE) << 2;
210562306a36Sopenharmony_ci	chip->work_size = YDSXG_DEFAULT_WORK_SIZE;
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci	size = ALIGN(playback_ctrl_size, 0x100) +
210862306a36Sopenharmony_ci	       ALIGN(chip->bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES, 0x100) +
210962306a36Sopenharmony_ci	       ALIGN(chip->bank_size_capture * 2 * YDSXG_CAPTURE_VOICES, 0x100) +
211062306a36Sopenharmony_ci	       ALIGN(chip->bank_size_effect * 2 * YDSXG_EFFECT_VOICES, 0x100) +
211162306a36Sopenharmony_ci	       chip->work_size;
211262306a36Sopenharmony_ci	/* work_ptr must be aligned to 256 bytes, but it's already
211362306a36Sopenharmony_ci	   covered with the kernel page allocation mechanism */
211462306a36Sopenharmony_ci	chip->work_ptr = snd_devm_alloc_pages(&chip->pci->dev,
211562306a36Sopenharmony_ci					      SNDRV_DMA_TYPE_DEV, size);
211662306a36Sopenharmony_ci	if (!chip->work_ptr)
211762306a36Sopenharmony_ci		return -ENOMEM;
211862306a36Sopenharmony_ci	ptr = chip->work_ptr->area;
211962306a36Sopenharmony_ci	ptr_addr = chip->work_ptr->addr;
212062306a36Sopenharmony_ci	memset(ptr, 0, size);	/* for sure */
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci	chip->bank_base_playback = ptr;
212362306a36Sopenharmony_ci	chip->bank_base_playback_addr = ptr_addr;
212462306a36Sopenharmony_ci	chip->ctrl_playback = (__le32 *)ptr;
212562306a36Sopenharmony_ci	chip->ctrl_playback[0] = cpu_to_le32(YDSXG_PLAYBACK_VOICES);
212662306a36Sopenharmony_ci	ptr += ALIGN(playback_ctrl_size, 0x100);
212762306a36Sopenharmony_ci	ptr_addr += ALIGN(playback_ctrl_size, 0x100);
212862306a36Sopenharmony_ci	for (voice = 0; voice < YDSXG_PLAYBACK_VOICES; voice++) {
212962306a36Sopenharmony_ci		chip->voices[voice].number = voice;
213062306a36Sopenharmony_ci		chip->voices[voice].bank = (struct snd_ymfpci_playback_bank *)ptr;
213162306a36Sopenharmony_ci		chip->voices[voice].bank_addr = ptr_addr;
213262306a36Sopenharmony_ci		for (bank = 0; bank < 2; bank++) {
213362306a36Sopenharmony_ci			chip->bank_playback[voice][bank] = (struct snd_ymfpci_playback_bank *)ptr;
213462306a36Sopenharmony_ci			ptr += chip->bank_size_playback;
213562306a36Sopenharmony_ci			ptr_addr += chip->bank_size_playback;
213662306a36Sopenharmony_ci		}
213762306a36Sopenharmony_ci	}
213862306a36Sopenharmony_ci	ptr = (char *)ALIGN((unsigned long)ptr, 0x100);
213962306a36Sopenharmony_ci	ptr_addr = ALIGN(ptr_addr, 0x100);
214062306a36Sopenharmony_ci	chip->bank_base_capture = ptr;
214162306a36Sopenharmony_ci	chip->bank_base_capture_addr = ptr_addr;
214262306a36Sopenharmony_ci	for (voice = 0; voice < YDSXG_CAPTURE_VOICES; voice++)
214362306a36Sopenharmony_ci		for (bank = 0; bank < 2; bank++) {
214462306a36Sopenharmony_ci			chip->bank_capture[voice][bank] = (struct snd_ymfpci_capture_bank *)ptr;
214562306a36Sopenharmony_ci			ptr += chip->bank_size_capture;
214662306a36Sopenharmony_ci			ptr_addr += chip->bank_size_capture;
214762306a36Sopenharmony_ci		}
214862306a36Sopenharmony_ci	ptr = (char *)ALIGN((unsigned long)ptr, 0x100);
214962306a36Sopenharmony_ci	ptr_addr = ALIGN(ptr_addr, 0x100);
215062306a36Sopenharmony_ci	chip->bank_base_effect = ptr;
215162306a36Sopenharmony_ci	chip->bank_base_effect_addr = ptr_addr;
215262306a36Sopenharmony_ci	for (voice = 0; voice < YDSXG_EFFECT_VOICES; voice++)
215362306a36Sopenharmony_ci		for (bank = 0; bank < 2; bank++) {
215462306a36Sopenharmony_ci			chip->bank_effect[voice][bank] = (struct snd_ymfpci_effect_bank *)ptr;
215562306a36Sopenharmony_ci			ptr += chip->bank_size_effect;
215662306a36Sopenharmony_ci			ptr_addr += chip->bank_size_effect;
215762306a36Sopenharmony_ci		}
215862306a36Sopenharmony_ci	ptr = (char *)ALIGN((unsigned long)ptr, 0x100);
215962306a36Sopenharmony_ci	ptr_addr = ALIGN(ptr_addr, 0x100);
216062306a36Sopenharmony_ci	chip->work_base = ptr;
216162306a36Sopenharmony_ci	chip->work_base_addr = ptr_addr;
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci	snd_BUG_ON(ptr + PAGE_ALIGN(chip->work_size) !=
216462306a36Sopenharmony_ci		   chip->work_ptr->area + chip->work_ptr->bytes);
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, chip->bank_base_playback_addr);
216762306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_RECCTRLBASE, chip->bank_base_capture_addr);
216862306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_EFFCTRLBASE, chip->bank_base_effect_addr);
216962306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_WORKBASE, chip->work_base_addr);
217062306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_WORKSIZE, chip->work_size >> 2);
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	/* S/PDIF output initialization */
217362306a36Sopenharmony_ci	chip->spdif_bits = chip->spdif_pcm_bits = SNDRV_PCM_DEFAULT_CON_SPDIF & 0xffff;
217462306a36Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL, 0);
217562306a36Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_bits);
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci	/* S/PDIF input initialization */
217862306a36Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_SPDIFINCTRL, 0);
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	/* digital mixer setup */
218162306a36Sopenharmony_ci	for (reg = 0x80; reg < 0xc0; reg += 4)
218262306a36Sopenharmony_ci		snd_ymfpci_writel(chip, reg, 0);
218362306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff);
218462306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0x3fff3fff);
218562306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_ZVOUTVOL, 0x3fff3fff);
218662306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_SPDIFOUTVOL, 0x3fff3fff);
218762306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_NATIVEADCINVOL, 0x3fff3fff);
218862306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_NATIVEDACINVOL, 0x3fff3fff);
218962306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_PRIADCLOOPVOL, 0x3fff3fff);
219062306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_LEGACYOUTVOL, 0x3fff3fff);
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci	return 0;
219362306a36Sopenharmony_ci}
219462306a36Sopenharmony_ci
219562306a36Sopenharmony_cistatic void snd_ymfpci_free(struct snd_card *card)
219662306a36Sopenharmony_ci{
219762306a36Sopenharmony_ci	struct snd_ymfpci *chip = card->private_data;
219862306a36Sopenharmony_ci	u16 ctrl;
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0);
220162306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0);
220262306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_LEGACYOUTVOL, 0);
220362306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_STATUS, ~0);
220462306a36Sopenharmony_ci	snd_ymfpci_disable_dsp(chip);
220562306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, 0);
220662306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_RECCTRLBASE, 0);
220762306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_EFFCTRLBASE, 0);
220862306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_WORKBASE, 0);
220962306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_WORKSIZE, 0);
221062306a36Sopenharmony_ci	ctrl = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL);
221162306a36Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci	snd_ymfpci_ac3_done(chip);
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci	snd_ymfpci_free_gameport(chip);
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ci	pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY, chip->old_legacy_ctrl);
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	release_firmware(chip->dsp_microcode);
222062306a36Sopenharmony_ci	release_firmware(chip->controller_microcode);
222162306a36Sopenharmony_ci}
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_cistatic int snd_ymfpci_suspend(struct device *dev)
222462306a36Sopenharmony_ci{
222562306a36Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
222662306a36Sopenharmony_ci	struct snd_ymfpci *chip = card->private_data;
222762306a36Sopenharmony_ci	unsigned int i, legacy_reg_count = DSXG_PCI_NUM_SAVED_LEGACY_REGS;
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_ci	if (chip->pci->device >= 0x0010) /* YMF 744/754 */
223062306a36Sopenharmony_ci		legacy_reg_count = DSXG_PCI_NUM_SAVED_REGS;
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
223362306a36Sopenharmony_ci	snd_ac97_suspend(chip->ac97);
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci	for (i = 0; i < YDSXGR_NUM_SAVED_REGS; i++)
223662306a36Sopenharmony_ci		chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]);
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci	chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE);
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci	for (i = 0; i < legacy_reg_count; i++)
224162306a36Sopenharmony_ci		pci_read_config_word(chip->pci, pci_saved_regs_index[i],
224262306a36Sopenharmony_ci				      chip->saved_dsxg_pci_regs + i);
224362306a36Sopenharmony_ci
224462306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0);
224562306a36Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0);
224662306a36Sopenharmony_ci	snd_ymfpci_disable_dsp(chip);
224762306a36Sopenharmony_ci	return 0;
224862306a36Sopenharmony_ci}
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_cistatic int snd_ymfpci_resume(struct device *dev)
225162306a36Sopenharmony_ci{
225262306a36Sopenharmony_ci	struct pci_dev *pci = to_pci_dev(dev);
225362306a36Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
225462306a36Sopenharmony_ci	struct snd_ymfpci *chip = card->private_data;
225562306a36Sopenharmony_ci	unsigned int i, legacy_reg_count = DSXG_PCI_NUM_SAVED_LEGACY_REGS;
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci	if (chip->pci->device >= 0x0010) /* YMF 744/754 */
225862306a36Sopenharmony_ci		legacy_reg_count = DSXG_PCI_NUM_SAVED_REGS;
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci	snd_ymfpci_aclink_reset(pci);
226162306a36Sopenharmony_ci	snd_ymfpci_codec_ready(chip, 0);
226262306a36Sopenharmony_ci	snd_ymfpci_download_image(chip);
226362306a36Sopenharmony_ci	udelay(100);
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	for (i = 0; i < YDSXGR_NUM_SAVED_REGS; i++)
226662306a36Sopenharmony_ci		snd_ymfpci_writel(chip, saved_regs_index[i], chip->saved_regs[i]);
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_ci	snd_ac97_resume(chip->ac97);
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_ci	for (i = 0; i < legacy_reg_count; i++)
227162306a36Sopenharmony_ci		pci_write_config_word(chip->pci, pci_saved_regs_index[i],
227262306a36Sopenharmony_ci				      chip->saved_dsxg_pci_regs[i]);
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci	/* start hw again */
227562306a36Sopenharmony_ci	if (chip->start_count > 0) {
227662306a36Sopenharmony_ci		spin_lock_irq(&chip->reg_lock);
227762306a36Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_MODE, chip->saved_ydsxgr_mode);
227862306a36Sopenharmony_ci		chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT);
227962306a36Sopenharmony_ci		spin_unlock_irq(&chip->reg_lock);
228062306a36Sopenharmony_ci	}
228162306a36Sopenharmony_ci	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
228262306a36Sopenharmony_ci	return 0;
228362306a36Sopenharmony_ci}
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_ciDEFINE_SIMPLE_DEV_PM_OPS(snd_ymfpci_pm, snd_ymfpci_suspend, snd_ymfpci_resume);
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ciint snd_ymfpci_create(struct snd_card *card,
228862306a36Sopenharmony_ci		      struct pci_dev *pci,
228962306a36Sopenharmony_ci		      u16 old_legacy_ctrl)
229062306a36Sopenharmony_ci{
229162306a36Sopenharmony_ci	struct snd_ymfpci *chip = card->private_data;
229262306a36Sopenharmony_ci	int err;
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci	/* enable PCI device */
229562306a36Sopenharmony_ci	err = pcim_enable_device(pci);
229662306a36Sopenharmony_ci	if (err < 0)
229762306a36Sopenharmony_ci		return err;
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_ci	chip->old_legacy_ctrl = old_legacy_ctrl;
230062306a36Sopenharmony_ci	spin_lock_init(&chip->reg_lock);
230162306a36Sopenharmony_ci	spin_lock_init(&chip->voice_lock);
230262306a36Sopenharmony_ci	init_waitqueue_head(&chip->interrupt_sleep);
230362306a36Sopenharmony_ci	atomic_set(&chip->interrupt_sleep_count, 0);
230462306a36Sopenharmony_ci	chip->card = card;
230562306a36Sopenharmony_ci	chip->pci = pci;
230662306a36Sopenharmony_ci	chip->irq = -1;
230762306a36Sopenharmony_ci	chip->device_id = pci->device;
230862306a36Sopenharmony_ci	chip->rev = pci->revision;
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci	err = pci_request_regions(pci, "YMFPCI");
231162306a36Sopenharmony_ci	if (err < 0)
231262306a36Sopenharmony_ci		return err;
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ci	chip->reg_area_phys = pci_resource_start(pci, 0);
231562306a36Sopenharmony_ci	chip->reg_area_virt = devm_ioremap(&pci->dev, chip->reg_area_phys, 0x8000);
231662306a36Sopenharmony_ci	if (!chip->reg_area_virt) {
231762306a36Sopenharmony_ci		dev_err(chip->card->dev,
231862306a36Sopenharmony_ci			"unable to grab memory region 0x%lx-0x%lx\n",
231962306a36Sopenharmony_ci			chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1);
232062306a36Sopenharmony_ci		return -EBUSY;
232162306a36Sopenharmony_ci	}
232262306a36Sopenharmony_ci	pci_set_master(pci);
232362306a36Sopenharmony_ci	chip->src441_used = -1;
232462306a36Sopenharmony_ci
232562306a36Sopenharmony_ci	if (devm_request_irq(&pci->dev, pci->irq, snd_ymfpci_interrupt, IRQF_SHARED,
232662306a36Sopenharmony_ci			KBUILD_MODNAME, chip)) {
232762306a36Sopenharmony_ci		dev_err(chip->card->dev, "unable to grab IRQ %d\n", pci->irq);
232862306a36Sopenharmony_ci		return -EBUSY;
232962306a36Sopenharmony_ci	}
233062306a36Sopenharmony_ci	chip->irq = pci->irq;
233162306a36Sopenharmony_ci	card->sync_irq = chip->irq;
233262306a36Sopenharmony_ci	card->private_free = snd_ymfpci_free;
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci	snd_ymfpci_aclink_reset(pci);
233562306a36Sopenharmony_ci	if (snd_ymfpci_codec_ready(chip, 0) < 0)
233662306a36Sopenharmony_ci		return -EIO;
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_ci	err = snd_ymfpci_request_firmware(chip);
233962306a36Sopenharmony_ci	if (err < 0) {
234062306a36Sopenharmony_ci		dev_err(chip->card->dev, "firmware request failed: %d\n", err);
234162306a36Sopenharmony_ci		return err;
234262306a36Sopenharmony_ci	}
234362306a36Sopenharmony_ci	snd_ymfpci_download_image(chip);
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci	udelay(100); /* seems we need a delay after downloading image.. */
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_ci	if (snd_ymfpci_memalloc(chip) < 0)
234862306a36Sopenharmony_ci		return -EIO;
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci	err = snd_ymfpci_ac3_init(chip);
235162306a36Sopenharmony_ci	if (err < 0)
235262306a36Sopenharmony_ci		return err;
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_ci	snd_ymfpci_proc_init(card, chip);
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	return 0;
235762306a36Sopenharmony_ci}
2358