18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
48c2ecf20Sopenharmony_ci *  Routines for control of YMF724/740/744/754 chips
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/delay.h>
88c2ecf20Sopenharmony_ci#include <linux/firmware.h>
98c2ecf20Sopenharmony_ci#include <linux/init.h>
108c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
118c2ecf20Sopenharmony_ci#include <linux/pci.h>
128c2ecf20Sopenharmony_ci#include <linux/sched.h>
138c2ecf20Sopenharmony_ci#include <linux/slab.h>
148c2ecf20Sopenharmony_ci#include <linux/mutex.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/io.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <sound/core.h>
198c2ecf20Sopenharmony_ci#include <sound/control.h>
208c2ecf20Sopenharmony_ci#include <sound/info.h>
218c2ecf20Sopenharmony_ci#include <sound/tlv.h>
228c2ecf20Sopenharmony_ci#include "ymfpci.h"
238c2ecf20Sopenharmony_ci#include <sound/asoundef.h>
248c2ecf20Sopenharmony_ci#include <sound/mpu401.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <asm/byteorder.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/*
298c2ecf20Sopenharmony_ci *  common I/O routines
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic void snd_ymfpci_irq_wait(struct snd_ymfpci *chip);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic inline u8 snd_ymfpci_readb(struct snd_ymfpci *chip, u32 offset)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	return readb(chip->reg_area_virt + offset);
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic inline void snd_ymfpci_writeb(struct snd_ymfpci *chip, u32 offset, u8 val)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	writeb(val, chip->reg_area_virt + offset);
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic inline u16 snd_ymfpci_readw(struct snd_ymfpci *chip, u32 offset)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	return readw(chip->reg_area_virt + offset);
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic inline void snd_ymfpci_writew(struct snd_ymfpci *chip, u32 offset, u16 val)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	writew(val, chip->reg_area_virt + offset);
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic inline u32 snd_ymfpci_readl(struct snd_ymfpci *chip, u32 offset)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	return readl(chip->reg_area_virt + offset);
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic inline void snd_ymfpci_writel(struct snd_ymfpci *chip, u32 offset, u32 val)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	writel(val, chip->reg_area_virt + offset);
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic int snd_ymfpci_codec_ready(struct snd_ymfpci *chip, int secondary)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	unsigned long end_time;
678c2ecf20Sopenharmony_ci	u32 reg = secondary ? YDSXGR_SECSTATUSADR : YDSXGR_PRISTATUSADR;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	end_time = jiffies + msecs_to_jiffies(750);
708c2ecf20Sopenharmony_ci	do {
718c2ecf20Sopenharmony_ci		if ((snd_ymfpci_readw(chip, reg) & 0x8000) == 0)
728c2ecf20Sopenharmony_ci			return 0;
738c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(1);
748c2ecf20Sopenharmony_ci	} while (time_before(jiffies, end_time));
758c2ecf20Sopenharmony_ci	dev_err(chip->card->dev,
768c2ecf20Sopenharmony_ci		"codec_ready: codec %i is not ready [0x%x]\n",
778c2ecf20Sopenharmony_ci		secondary, snd_ymfpci_readw(chip, reg));
788c2ecf20Sopenharmony_ci	return -EBUSY;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic void snd_ymfpci_codec_write(struct snd_ac97 *ac97, u16 reg, u16 val)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = ac97->private_data;
848c2ecf20Sopenharmony_ci	u32 cmd;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	snd_ymfpci_codec_ready(chip, 0);
878c2ecf20Sopenharmony_ci	cmd = ((YDSXG_AC97WRITECMD | reg) << 16) | val;
888c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_AC97CMDDATA, cmd);
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic u16 snd_ymfpci_codec_read(struct snd_ac97 *ac97, u16 reg)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = ac97->private_data;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	if (snd_ymfpci_codec_ready(chip, 0))
968c2ecf20Sopenharmony_ci		return ~0;
978c2ecf20Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg);
988c2ecf20Sopenharmony_ci	if (snd_ymfpci_codec_ready(chip, 0))
998c2ecf20Sopenharmony_ci		return ~0;
1008c2ecf20Sopenharmony_ci	if (chip->device_id == PCI_DEVICE_ID_YAMAHA_744 && chip->rev < 2) {
1018c2ecf20Sopenharmony_ci		int i;
1028c2ecf20Sopenharmony_ci		for (i = 0; i < 600; i++)
1038c2ecf20Sopenharmony_ci			snd_ymfpci_readw(chip, YDSXGR_PRISTATUSDATA);
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci	return snd_ymfpci_readw(chip, YDSXGR_PRISTATUSDATA);
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci/*
1098c2ecf20Sopenharmony_ci *  Misc routines
1108c2ecf20Sopenharmony_ci */
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic u32 snd_ymfpci_calc_delta(u32 rate)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	switch (rate) {
1158c2ecf20Sopenharmony_ci	case 8000:	return 0x02aaab00;
1168c2ecf20Sopenharmony_ci	case 11025:	return 0x03accd00;
1178c2ecf20Sopenharmony_ci	case 16000:	return 0x05555500;
1188c2ecf20Sopenharmony_ci	case 22050:	return 0x07599a00;
1198c2ecf20Sopenharmony_ci	case 32000:	return 0x0aaaab00;
1208c2ecf20Sopenharmony_ci	case 44100:	return 0x0eb33300;
1218c2ecf20Sopenharmony_ci	default:	return ((rate << 16) / 375) << 5;
1228c2ecf20Sopenharmony_ci	}
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic const u32 def_rate[8] = {
1268c2ecf20Sopenharmony_ci	100, 2000, 8000, 11025, 16000, 22050, 32000, 48000
1278c2ecf20Sopenharmony_ci};
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic u32 snd_ymfpci_calc_lpfK(u32 rate)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	u32 i;
1328c2ecf20Sopenharmony_ci	static const u32 val[8] = {
1338c2ecf20Sopenharmony_ci		0x00570000, 0x06AA0000, 0x18B20000, 0x20930000,
1348c2ecf20Sopenharmony_ci		0x2B9A0000, 0x35A10000, 0x3EAA0000, 0x40000000
1358c2ecf20Sopenharmony_ci	};
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	if (rate == 44100)
1388c2ecf20Sopenharmony_ci		return 0x40000000;	/* FIXME: What's the right value? */
1398c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++)
1408c2ecf20Sopenharmony_ci		if (rate <= def_rate[i])
1418c2ecf20Sopenharmony_ci			return val[i];
1428c2ecf20Sopenharmony_ci	return val[0];
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic u32 snd_ymfpci_calc_lpfQ(u32 rate)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	u32 i;
1488c2ecf20Sopenharmony_ci	static const u32 val[8] = {
1498c2ecf20Sopenharmony_ci		0x35280000, 0x34A70000, 0x32020000, 0x31770000,
1508c2ecf20Sopenharmony_ci		0x31390000, 0x31C90000, 0x33D00000, 0x40000000
1518c2ecf20Sopenharmony_ci	};
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (rate == 44100)
1548c2ecf20Sopenharmony_ci		return 0x370A0000;
1558c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++)
1568c2ecf20Sopenharmony_ci		if (rate <= def_rate[i])
1578c2ecf20Sopenharmony_ci			return val[i];
1588c2ecf20Sopenharmony_ci	return val[0];
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci/*
1628c2ecf20Sopenharmony_ci *  Hardware start management
1638c2ecf20Sopenharmony_ci */
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic void snd_ymfpci_hw_start(struct snd_ymfpci *chip)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	unsigned long flags;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
1708c2ecf20Sopenharmony_ci	if (chip->start_count++ > 0)
1718c2ecf20Sopenharmony_ci		goto __end;
1728c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_MODE,
1738c2ecf20Sopenharmony_ci			  snd_ymfpci_readl(chip, YDSXGR_MODE) | 3);
1748c2ecf20Sopenharmony_ci	chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT) & 1;
1758c2ecf20Sopenharmony_ci      __end:
1768c2ecf20Sopenharmony_ci      	spin_unlock_irqrestore(&chip->reg_lock, flags);
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic void snd_ymfpci_hw_stop(struct snd_ymfpci *chip)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	unsigned long flags;
1828c2ecf20Sopenharmony_ci	long timeout = 1000;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
1858c2ecf20Sopenharmony_ci	if (--chip->start_count > 0)
1868c2ecf20Sopenharmony_ci		goto __end;
1878c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_MODE,
1888c2ecf20Sopenharmony_ci			  snd_ymfpci_readl(chip, YDSXGR_MODE) & ~3);
1898c2ecf20Sopenharmony_ci	while (timeout-- > 0) {
1908c2ecf20Sopenharmony_ci		if ((snd_ymfpci_readl(chip, YDSXGR_STATUS) & 2) == 0)
1918c2ecf20Sopenharmony_ci			break;
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci	if (atomic_read(&chip->interrupt_sleep_count)) {
1948c2ecf20Sopenharmony_ci		atomic_set(&chip->interrupt_sleep_count, 0);
1958c2ecf20Sopenharmony_ci		wake_up(&chip->interrupt_sleep);
1968c2ecf20Sopenharmony_ci	}
1978c2ecf20Sopenharmony_ci      __end:
1988c2ecf20Sopenharmony_ci      	spin_unlock_irqrestore(&chip->reg_lock, flags);
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci/*
2028c2ecf20Sopenharmony_ci *  Playback voice management
2038c2ecf20Sopenharmony_ci */
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic int voice_alloc(struct snd_ymfpci *chip,
2068c2ecf20Sopenharmony_ci		       enum snd_ymfpci_voice_type type, int pair,
2078c2ecf20Sopenharmony_ci		       struct snd_ymfpci_voice **rvoice)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	struct snd_ymfpci_voice *voice, *voice2;
2108c2ecf20Sopenharmony_ci	int idx;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	*rvoice = NULL;
2138c2ecf20Sopenharmony_ci	for (idx = 0; idx < YDSXG_PLAYBACK_VOICES; idx += pair ? 2 : 1) {
2148c2ecf20Sopenharmony_ci		voice = &chip->voices[idx];
2158c2ecf20Sopenharmony_ci		voice2 = pair ? &chip->voices[idx+1] : NULL;
2168c2ecf20Sopenharmony_ci		if (voice->use || (voice2 && voice2->use))
2178c2ecf20Sopenharmony_ci			continue;
2188c2ecf20Sopenharmony_ci		voice->use = 1;
2198c2ecf20Sopenharmony_ci		if (voice2)
2208c2ecf20Sopenharmony_ci			voice2->use = 1;
2218c2ecf20Sopenharmony_ci		switch (type) {
2228c2ecf20Sopenharmony_ci		case YMFPCI_PCM:
2238c2ecf20Sopenharmony_ci			voice->pcm = 1;
2248c2ecf20Sopenharmony_ci			if (voice2)
2258c2ecf20Sopenharmony_ci				voice2->pcm = 1;
2268c2ecf20Sopenharmony_ci			break;
2278c2ecf20Sopenharmony_ci		case YMFPCI_SYNTH:
2288c2ecf20Sopenharmony_ci			voice->synth = 1;
2298c2ecf20Sopenharmony_ci			break;
2308c2ecf20Sopenharmony_ci		case YMFPCI_MIDI:
2318c2ecf20Sopenharmony_ci			voice->midi = 1;
2328c2ecf20Sopenharmony_ci			break;
2338c2ecf20Sopenharmony_ci		}
2348c2ecf20Sopenharmony_ci		snd_ymfpci_hw_start(chip);
2358c2ecf20Sopenharmony_ci		if (voice2)
2368c2ecf20Sopenharmony_ci			snd_ymfpci_hw_start(chip);
2378c2ecf20Sopenharmony_ci		*rvoice = voice;
2388c2ecf20Sopenharmony_ci		return 0;
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci	return -ENOMEM;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic int snd_ymfpci_voice_alloc(struct snd_ymfpci *chip,
2448c2ecf20Sopenharmony_ci				  enum snd_ymfpci_voice_type type, int pair,
2458c2ecf20Sopenharmony_ci				  struct snd_ymfpci_voice **rvoice)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	unsigned long flags;
2488c2ecf20Sopenharmony_ci	int result;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!rvoice))
2518c2ecf20Sopenharmony_ci		return -EINVAL;
2528c2ecf20Sopenharmony_ci	if (snd_BUG_ON(pair && type != YMFPCI_PCM))
2538c2ecf20Sopenharmony_ci		return -EINVAL;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chip->voice_lock, flags);
2568c2ecf20Sopenharmony_ci	for (;;) {
2578c2ecf20Sopenharmony_ci		result = voice_alloc(chip, type, pair, rvoice);
2588c2ecf20Sopenharmony_ci		if (result == 0 || type != YMFPCI_PCM)
2598c2ecf20Sopenharmony_ci			break;
2608c2ecf20Sopenharmony_ci		/* TODO: synth/midi voice deallocation */
2618c2ecf20Sopenharmony_ci		break;
2628c2ecf20Sopenharmony_ci	}
2638c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chip->voice_lock, flags);
2648c2ecf20Sopenharmony_ci	return result;
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_cistatic int snd_ymfpci_voice_free(struct snd_ymfpci *chip, struct snd_ymfpci_voice *pvoice)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	unsigned long flags;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!pvoice))
2728c2ecf20Sopenharmony_ci		return -EINVAL;
2738c2ecf20Sopenharmony_ci	snd_ymfpci_hw_stop(chip);
2748c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chip->voice_lock, flags);
2758c2ecf20Sopenharmony_ci	if (pvoice->number == chip->src441_used) {
2768c2ecf20Sopenharmony_ci		chip->src441_used = -1;
2778c2ecf20Sopenharmony_ci		pvoice->ypcm->use_441_slot = 0;
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci	pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0;
2808c2ecf20Sopenharmony_ci	pvoice->ypcm = NULL;
2818c2ecf20Sopenharmony_ci	pvoice->interrupt = NULL;
2828c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chip->voice_lock, flags);
2838c2ecf20Sopenharmony_ci	return 0;
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci/*
2878c2ecf20Sopenharmony_ci *  PCM part
2888c2ecf20Sopenharmony_ci */
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic void snd_ymfpci_pcm_interrupt(struct snd_ymfpci *chip, struct snd_ymfpci_voice *voice)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm;
2938c2ecf20Sopenharmony_ci	u32 pos, delta;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	ypcm = voice->ypcm;
2968c2ecf20Sopenharmony_ci	if (!ypcm)
2978c2ecf20Sopenharmony_ci		return;
2988c2ecf20Sopenharmony_ci	if (ypcm->substream == NULL)
2998c2ecf20Sopenharmony_ci		return;
3008c2ecf20Sopenharmony_ci	spin_lock(&chip->reg_lock);
3018c2ecf20Sopenharmony_ci	if (ypcm->running) {
3028c2ecf20Sopenharmony_ci		pos = le32_to_cpu(voice->bank[chip->active_bank].start);
3038c2ecf20Sopenharmony_ci		if (pos < ypcm->last_pos)
3048c2ecf20Sopenharmony_ci			delta = pos + (ypcm->buffer_size - ypcm->last_pos);
3058c2ecf20Sopenharmony_ci		else
3068c2ecf20Sopenharmony_ci			delta = pos - ypcm->last_pos;
3078c2ecf20Sopenharmony_ci		ypcm->period_pos += delta;
3088c2ecf20Sopenharmony_ci		ypcm->last_pos = pos;
3098c2ecf20Sopenharmony_ci		if (ypcm->period_pos >= ypcm->period_size) {
3108c2ecf20Sopenharmony_ci			/*
3118c2ecf20Sopenharmony_ci			dev_dbg(chip->card->dev,
3128c2ecf20Sopenharmony_ci			       "done - active_bank = 0x%x, start = 0x%x\n",
3138c2ecf20Sopenharmony_ci			       chip->active_bank,
3148c2ecf20Sopenharmony_ci			       voice->bank[chip->active_bank].start);
3158c2ecf20Sopenharmony_ci			*/
3168c2ecf20Sopenharmony_ci			ypcm->period_pos %= ypcm->period_size;
3178c2ecf20Sopenharmony_ci			spin_unlock(&chip->reg_lock);
3188c2ecf20Sopenharmony_ci			snd_pcm_period_elapsed(ypcm->substream);
3198c2ecf20Sopenharmony_ci			spin_lock(&chip->reg_lock);
3208c2ecf20Sopenharmony_ci		}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci		if (unlikely(ypcm->update_pcm_vol)) {
3238c2ecf20Sopenharmony_ci			unsigned int subs = ypcm->substream->number;
3248c2ecf20Sopenharmony_ci			unsigned int next_bank = 1 - chip->active_bank;
3258c2ecf20Sopenharmony_ci			struct snd_ymfpci_playback_bank *bank;
3268c2ecf20Sopenharmony_ci			__le32 volume;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci			bank = &voice->bank[next_bank];
3298c2ecf20Sopenharmony_ci			volume = cpu_to_le32(chip->pcm_mixer[subs].left << 15);
3308c2ecf20Sopenharmony_ci			bank->left_gain_end = volume;
3318c2ecf20Sopenharmony_ci			if (ypcm->output_rear)
3328c2ecf20Sopenharmony_ci				bank->eff2_gain_end = volume;
3338c2ecf20Sopenharmony_ci			if (ypcm->voices[1])
3348c2ecf20Sopenharmony_ci				bank = &ypcm->voices[1]->bank[next_bank];
3358c2ecf20Sopenharmony_ci			volume = cpu_to_le32(chip->pcm_mixer[subs].right << 15);
3368c2ecf20Sopenharmony_ci			bank->right_gain_end = volume;
3378c2ecf20Sopenharmony_ci			if (ypcm->output_rear)
3388c2ecf20Sopenharmony_ci				bank->eff3_gain_end = volume;
3398c2ecf20Sopenharmony_ci			ypcm->update_pcm_vol--;
3408c2ecf20Sopenharmony_ci		}
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci	spin_unlock(&chip->reg_lock);
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic void snd_ymfpci_pcm_capture_interrupt(struct snd_pcm_substream *substream)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
3488c2ecf20Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = runtime->private_data;
3498c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = ypcm->chip;
3508c2ecf20Sopenharmony_ci	u32 pos, delta;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	spin_lock(&chip->reg_lock);
3538c2ecf20Sopenharmony_ci	if (ypcm->running) {
3548c2ecf20Sopenharmony_ci		pos = le32_to_cpu(chip->bank_capture[ypcm->capture_bank_number][chip->active_bank]->start) >> ypcm->shift;
3558c2ecf20Sopenharmony_ci		if (pos < ypcm->last_pos)
3568c2ecf20Sopenharmony_ci			delta = pos + (ypcm->buffer_size - ypcm->last_pos);
3578c2ecf20Sopenharmony_ci		else
3588c2ecf20Sopenharmony_ci			delta = pos - ypcm->last_pos;
3598c2ecf20Sopenharmony_ci		ypcm->period_pos += delta;
3608c2ecf20Sopenharmony_ci		ypcm->last_pos = pos;
3618c2ecf20Sopenharmony_ci		if (ypcm->period_pos >= ypcm->period_size) {
3628c2ecf20Sopenharmony_ci			ypcm->period_pos %= ypcm->period_size;
3638c2ecf20Sopenharmony_ci			/*
3648c2ecf20Sopenharmony_ci			dev_dbg(chip->card->dev,
3658c2ecf20Sopenharmony_ci			       "done - active_bank = 0x%x, start = 0x%x\n",
3668c2ecf20Sopenharmony_ci			       chip->active_bank,
3678c2ecf20Sopenharmony_ci			       voice->bank[chip->active_bank].start);
3688c2ecf20Sopenharmony_ci			*/
3698c2ecf20Sopenharmony_ci			spin_unlock(&chip->reg_lock);
3708c2ecf20Sopenharmony_ci			snd_pcm_period_elapsed(substream);
3718c2ecf20Sopenharmony_ci			spin_lock(&chip->reg_lock);
3728c2ecf20Sopenharmony_ci		}
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci	spin_unlock(&chip->reg_lock);
3758c2ecf20Sopenharmony_ci}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_cistatic int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream,
3788c2ecf20Sopenharmony_ci				       int cmd)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
3818c2ecf20Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data;
3828c2ecf20Sopenharmony_ci	struct snd_kcontrol *kctl = NULL;
3838c2ecf20Sopenharmony_ci	int result = 0;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	spin_lock(&chip->reg_lock);
3868c2ecf20Sopenharmony_ci	if (ypcm->voices[0] == NULL) {
3878c2ecf20Sopenharmony_ci		result = -EINVAL;
3888c2ecf20Sopenharmony_ci		goto __unlock;
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci	switch (cmd) {
3918c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
3928c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
3938c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
3948c2ecf20Sopenharmony_ci		chip->ctrl_playback[ypcm->voices[0]->number + 1] = cpu_to_le32(ypcm->voices[0]->bank_addr);
3958c2ecf20Sopenharmony_ci		if (ypcm->voices[1] != NULL && !ypcm->use_441_slot)
3968c2ecf20Sopenharmony_ci			chip->ctrl_playback[ypcm->voices[1]->number + 1] = cpu_to_le32(ypcm->voices[1]->bank_addr);
3978c2ecf20Sopenharmony_ci		ypcm->running = 1;
3988c2ecf20Sopenharmony_ci		break;
3998c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
4008c2ecf20Sopenharmony_ci		if (substream->pcm == chip->pcm && !ypcm->use_441_slot) {
4018c2ecf20Sopenharmony_ci			kctl = chip->pcm_mixer[substream->number].ctl;
4028c2ecf20Sopenharmony_ci			kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
4038c2ecf20Sopenharmony_ci		}
4048c2ecf20Sopenharmony_ci		fallthrough;
4058c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
4068c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
4078c2ecf20Sopenharmony_ci		chip->ctrl_playback[ypcm->voices[0]->number + 1] = 0;
4088c2ecf20Sopenharmony_ci		if (ypcm->voices[1] != NULL && !ypcm->use_441_slot)
4098c2ecf20Sopenharmony_ci			chip->ctrl_playback[ypcm->voices[1]->number + 1] = 0;
4108c2ecf20Sopenharmony_ci		ypcm->running = 0;
4118c2ecf20Sopenharmony_ci		break;
4128c2ecf20Sopenharmony_ci	default:
4138c2ecf20Sopenharmony_ci		result = -EINVAL;
4148c2ecf20Sopenharmony_ci		break;
4158c2ecf20Sopenharmony_ci	}
4168c2ecf20Sopenharmony_ci      __unlock:
4178c2ecf20Sopenharmony_ci	spin_unlock(&chip->reg_lock);
4188c2ecf20Sopenharmony_ci	if (kctl)
4198c2ecf20Sopenharmony_ci		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
4208c2ecf20Sopenharmony_ci	return result;
4218c2ecf20Sopenharmony_ci}
4228c2ecf20Sopenharmony_cistatic int snd_ymfpci_capture_trigger(struct snd_pcm_substream *substream,
4238c2ecf20Sopenharmony_ci				      int cmd)
4248c2ecf20Sopenharmony_ci{
4258c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
4268c2ecf20Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data;
4278c2ecf20Sopenharmony_ci	int result = 0;
4288c2ecf20Sopenharmony_ci	u32 tmp;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	spin_lock(&chip->reg_lock);
4318c2ecf20Sopenharmony_ci	switch (cmd) {
4328c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
4338c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
4348c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
4358c2ecf20Sopenharmony_ci		tmp = snd_ymfpci_readl(chip, YDSXGR_MAPOFREC) | (1 << ypcm->capture_bank_number);
4368c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_MAPOFREC, tmp);
4378c2ecf20Sopenharmony_ci		ypcm->running = 1;
4388c2ecf20Sopenharmony_ci		break;
4398c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
4408c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
4418c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
4428c2ecf20Sopenharmony_ci		tmp = snd_ymfpci_readl(chip, YDSXGR_MAPOFREC) & ~(1 << ypcm->capture_bank_number);
4438c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_MAPOFREC, tmp);
4448c2ecf20Sopenharmony_ci		ypcm->running = 0;
4458c2ecf20Sopenharmony_ci		break;
4468c2ecf20Sopenharmony_ci	default:
4478c2ecf20Sopenharmony_ci		result = -EINVAL;
4488c2ecf20Sopenharmony_ci		break;
4498c2ecf20Sopenharmony_ci	}
4508c2ecf20Sopenharmony_ci	spin_unlock(&chip->reg_lock);
4518c2ecf20Sopenharmony_ci	return result;
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_cistatic int snd_ymfpci_pcm_voice_alloc(struct snd_ymfpci_pcm *ypcm, int voices)
4558c2ecf20Sopenharmony_ci{
4568c2ecf20Sopenharmony_ci	int err;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	if (ypcm->voices[1] != NULL && voices < 2) {
4598c2ecf20Sopenharmony_ci		snd_ymfpci_voice_free(ypcm->chip, ypcm->voices[1]);
4608c2ecf20Sopenharmony_ci		ypcm->voices[1] = NULL;
4618c2ecf20Sopenharmony_ci	}
4628c2ecf20Sopenharmony_ci	if (voices == 1 && ypcm->voices[0] != NULL)
4638c2ecf20Sopenharmony_ci		return 0;		/* already allocated */
4648c2ecf20Sopenharmony_ci	if (voices == 2 && ypcm->voices[0] != NULL && ypcm->voices[1] != NULL)
4658c2ecf20Sopenharmony_ci		return 0;		/* already allocated */
4668c2ecf20Sopenharmony_ci	if (voices > 1) {
4678c2ecf20Sopenharmony_ci		if (ypcm->voices[0] != NULL && ypcm->voices[1] == NULL) {
4688c2ecf20Sopenharmony_ci			snd_ymfpci_voice_free(ypcm->chip, ypcm->voices[0]);
4698c2ecf20Sopenharmony_ci			ypcm->voices[0] = NULL;
4708c2ecf20Sopenharmony_ci		}
4718c2ecf20Sopenharmony_ci	}
4728c2ecf20Sopenharmony_ci	err = snd_ymfpci_voice_alloc(ypcm->chip, YMFPCI_PCM, voices > 1, &ypcm->voices[0]);
4738c2ecf20Sopenharmony_ci	if (err < 0)
4748c2ecf20Sopenharmony_ci		return err;
4758c2ecf20Sopenharmony_ci	ypcm->voices[0]->ypcm = ypcm;
4768c2ecf20Sopenharmony_ci	ypcm->voices[0]->interrupt = snd_ymfpci_pcm_interrupt;
4778c2ecf20Sopenharmony_ci	if (voices > 1) {
4788c2ecf20Sopenharmony_ci		ypcm->voices[1] = &ypcm->chip->voices[ypcm->voices[0]->number + 1];
4798c2ecf20Sopenharmony_ci		ypcm->voices[1]->ypcm = ypcm;
4808c2ecf20Sopenharmony_ci	}
4818c2ecf20Sopenharmony_ci	return 0;
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_cistatic void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int voiceidx,
4858c2ecf20Sopenharmony_ci				      struct snd_pcm_runtime *runtime,
4868c2ecf20Sopenharmony_ci				      int has_pcm_volume)
4878c2ecf20Sopenharmony_ci{
4888c2ecf20Sopenharmony_ci	struct snd_ymfpci_voice *voice = ypcm->voices[voiceidx];
4898c2ecf20Sopenharmony_ci	u32 format;
4908c2ecf20Sopenharmony_ci	u32 delta = snd_ymfpci_calc_delta(runtime->rate);
4918c2ecf20Sopenharmony_ci	u32 lpfQ = snd_ymfpci_calc_lpfQ(runtime->rate);
4928c2ecf20Sopenharmony_ci	u32 lpfK = snd_ymfpci_calc_lpfK(runtime->rate);
4938c2ecf20Sopenharmony_ci	struct snd_ymfpci_playback_bank *bank;
4948c2ecf20Sopenharmony_ci	unsigned int nbank;
4958c2ecf20Sopenharmony_ci	__le32 vol_left, vol_right;
4968c2ecf20Sopenharmony_ci	u8 use_left, use_right;
4978c2ecf20Sopenharmony_ci	unsigned long flags;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!voice))
5008c2ecf20Sopenharmony_ci		return;
5018c2ecf20Sopenharmony_ci	if (runtime->channels == 1) {
5028c2ecf20Sopenharmony_ci		use_left = 1;
5038c2ecf20Sopenharmony_ci		use_right = 1;
5048c2ecf20Sopenharmony_ci	} else {
5058c2ecf20Sopenharmony_ci		use_left = (voiceidx & 1) == 0;
5068c2ecf20Sopenharmony_ci		use_right = !use_left;
5078c2ecf20Sopenharmony_ci	}
5088c2ecf20Sopenharmony_ci	if (has_pcm_volume) {
5098c2ecf20Sopenharmony_ci		vol_left = cpu_to_le32(ypcm->chip->pcm_mixer
5108c2ecf20Sopenharmony_ci				       [ypcm->substream->number].left << 15);
5118c2ecf20Sopenharmony_ci		vol_right = cpu_to_le32(ypcm->chip->pcm_mixer
5128c2ecf20Sopenharmony_ci					[ypcm->substream->number].right << 15);
5138c2ecf20Sopenharmony_ci	} else {
5148c2ecf20Sopenharmony_ci		vol_left = cpu_to_le32(0x40000000);
5158c2ecf20Sopenharmony_ci		vol_right = cpu_to_le32(0x40000000);
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ypcm->chip->voice_lock, flags);
5188c2ecf20Sopenharmony_ci	format = runtime->channels == 2 ? 0x00010000 : 0;
5198c2ecf20Sopenharmony_ci	if (snd_pcm_format_width(runtime->format) == 8)
5208c2ecf20Sopenharmony_ci		format |= 0x80000000;
5218c2ecf20Sopenharmony_ci	else if (ypcm->chip->device_id == PCI_DEVICE_ID_YAMAHA_754 &&
5228c2ecf20Sopenharmony_ci		 runtime->rate == 44100 && runtime->channels == 2 &&
5238c2ecf20Sopenharmony_ci		 voiceidx == 0 && (ypcm->chip->src441_used == -1 ||
5248c2ecf20Sopenharmony_ci				   ypcm->chip->src441_used == voice->number)) {
5258c2ecf20Sopenharmony_ci		ypcm->chip->src441_used = voice->number;
5268c2ecf20Sopenharmony_ci		ypcm->use_441_slot = 1;
5278c2ecf20Sopenharmony_ci		format |= 0x10000000;
5288c2ecf20Sopenharmony_ci	}
5298c2ecf20Sopenharmony_ci	if (ypcm->chip->src441_used == voice->number &&
5308c2ecf20Sopenharmony_ci	    (format & 0x10000000) == 0) {
5318c2ecf20Sopenharmony_ci		ypcm->chip->src441_used = -1;
5328c2ecf20Sopenharmony_ci		ypcm->use_441_slot = 0;
5338c2ecf20Sopenharmony_ci	}
5348c2ecf20Sopenharmony_ci	if (runtime->channels == 2 && (voiceidx & 1) != 0)
5358c2ecf20Sopenharmony_ci		format |= 1;
5368c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ypcm->chip->voice_lock, flags);
5378c2ecf20Sopenharmony_ci	for (nbank = 0; nbank < 2; nbank++) {
5388c2ecf20Sopenharmony_ci		bank = &voice->bank[nbank];
5398c2ecf20Sopenharmony_ci		memset(bank, 0, sizeof(*bank));
5408c2ecf20Sopenharmony_ci		bank->format = cpu_to_le32(format);
5418c2ecf20Sopenharmony_ci		bank->base = cpu_to_le32(runtime->dma_addr);
5428c2ecf20Sopenharmony_ci		bank->loop_end = cpu_to_le32(ypcm->buffer_size);
5438c2ecf20Sopenharmony_ci		bank->lpfQ = cpu_to_le32(lpfQ);
5448c2ecf20Sopenharmony_ci		bank->delta =
5458c2ecf20Sopenharmony_ci		bank->delta_end = cpu_to_le32(delta);
5468c2ecf20Sopenharmony_ci		bank->lpfK =
5478c2ecf20Sopenharmony_ci		bank->lpfK_end = cpu_to_le32(lpfK);
5488c2ecf20Sopenharmony_ci		bank->eg_gain =
5498c2ecf20Sopenharmony_ci		bank->eg_gain_end = cpu_to_le32(0x40000000);
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci		if (ypcm->output_front) {
5528c2ecf20Sopenharmony_ci			if (use_left) {
5538c2ecf20Sopenharmony_ci				bank->left_gain =
5548c2ecf20Sopenharmony_ci				bank->left_gain_end = vol_left;
5558c2ecf20Sopenharmony_ci			}
5568c2ecf20Sopenharmony_ci			if (use_right) {
5578c2ecf20Sopenharmony_ci				bank->right_gain =
5588c2ecf20Sopenharmony_ci				bank->right_gain_end = vol_right;
5598c2ecf20Sopenharmony_ci			}
5608c2ecf20Sopenharmony_ci		}
5618c2ecf20Sopenharmony_ci		if (ypcm->output_rear) {
5628c2ecf20Sopenharmony_ci		        if (!ypcm->swap_rear) {
5638c2ecf20Sopenharmony_ci        			if (use_left) {
5648c2ecf20Sopenharmony_ci        				bank->eff2_gain =
5658c2ecf20Sopenharmony_ci        				bank->eff2_gain_end = vol_left;
5668c2ecf20Sopenharmony_ci        			}
5678c2ecf20Sopenharmony_ci        			if (use_right) {
5688c2ecf20Sopenharmony_ci        				bank->eff3_gain =
5698c2ecf20Sopenharmony_ci        				bank->eff3_gain_end = vol_right;
5708c2ecf20Sopenharmony_ci        			}
5718c2ecf20Sopenharmony_ci		        } else {
5728c2ecf20Sopenharmony_ci        			/* The SPDIF out channels seem to be swapped, so we have
5738c2ecf20Sopenharmony_ci        			 * to swap them here, too.  The rear analog out channels
5748c2ecf20Sopenharmony_ci        			 * will be wrong, but otherwise AC3 would not work.
5758c2ecf20Sopenharmony_ci        			 */
5768c2ecf20Sopenharmony_ci        			if (use_left) {
5778c2ecf20Sopenharmony_ci        				bank->eff3_gain =
5788c2ecf20Sopenharmony_ci        				bank->eff3_gain_end = vol_left;
5798c2ecf20Sopenharmony_ci        			}
5808c2ecf20Sopenharmony_ci        			if (use_right) {
5818c2ecf20Sopenharmony_ci        				bank->eff2_gain =
5828c2ecf20Sopenharmony_ci        				bank->eff2_gain_end = vol_right;
5838c2ecf20Sopenharmony_ci        			}
5848c2ecf20Sopenharmony_ci        		}
5858c2ecf20Sopenharmony_ci                }
5868c2ecf20Sopenharmony_ci	}
5878c2ecf20Sopenharmony_ci}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_cistatic int snd_ymfpci_ac3_init(struct snd_ymfpci *chip)
5908c2ecf20Sopenharmony_ci{
5918c2ecf20Sopenharmony_ci	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev,
5928c2ecf20Sopenharmony_ci				4096, &chip->ac3_tmp_base) < 0)
5938c2ecf20Sopenharmony_ci		return -ENOMEM;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	chip->bank_effect[3][0]->base =
5968c2ecf20Sopenharmony_ci	chip->bank_effect[3][1]->base = cpu_to_le32(chip->ac3_tmp_base.addr);
5978c2ecf20Sopenharmony_ci	chip->bank_effect[3][0]->loop_end =
5988c2ecf20Sopenharmony_ci	chip->bank_effect[3][1]->loop_end = cpu_to_le32(1024);
5998c2ecf20Sopenharmony_ci	chip->bank_effect[4][0]->base =
6008c2ecf20Sopenharmony_ci	chip->bank_effect[4][1]->base = cpu_to_le32(chip->ac3_tmp_base.addr + 2048);
6018c2ecf20Sopenharmony_ci	chip->bank_effect[4][0]->loop_end =
6028c2ecf20Sopenharmony_ci	chip->bank_effect[4][1]->loop_end = cpu_to_le32(1024);
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
6058c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT,
6068c2ecf20Sopenharmony_ci			  snd_ymfpci_readl(chip, YDSXGR_MAPOFEFFECT) | 3 << 3);
6078c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
6088c2ecf20Sopenharmony_ci	return 0;
6098c2ecf20Sopenharmony_ci}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_cistatic int snd_ymfpci_ac3_done(struct snd_ymfpci *chip)
6128c2ecf20Sopenharmony_ci{
6138c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
6148c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT,
6158c2ecf20Sopenharmony_ci			  snd_ymfpci_readl(chip, YDSXGR_MAPOFEFFECT) & ~(3 << 3));
6168c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
6178c2ecf20Sopenharmony_ci	// snd_ymfpci_irq_wait(chip);
6188c2ecf20Sopenharmony_ci	if (chip->ac3_tmp_base.area) {
6198c2ecf20Sopenharmony_ci		snd_dma_free_pages(&chip->ac3_tmp_base);
6208c2ecf20Sopenharmony_ci		chip->ac3_tmp_base.area = NULL;
6218c2ecf20Sopenharmony_ci	}
6228c2ecf20Sopenharmony_ci	return 0;
6238c2ecf20Sopenharmony_ci}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_cistatic int snd_ymfpci_playback_hw_params(struct snd_pcm_substream *substream,
6268c2ecf20Sopenharmony_ci					 struct snd_pcm_hw_params *hw_params)
6278c2ecf20Sopenharmony_ci{
6288c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
6298c2ecf20Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = runtime->private_data;
6308c2ecf20Sopenharmony_ci	int err;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	err = snd_ymfpci_pcm_voice_alloc(ypcm, params_channels(hw_params));
6338c2ecf20Sopenharmony_ci	if (err < 0)
6348c2ecf20Sopenharmony_ci		return err;
6358c2ecf20Sopenharmony_ci	return 0;
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_cistatic int snd_ymfpci_playback_hw_free(struct snd_pcm_substream *substream)
6398c2ecf20Sopenharmony_ci{
6408c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
6418c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
6428c2ecf20Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	if (runtime->private_data == NULL)
6458c2ecf20Sopenharmony_ci		return 0;
6468c2ecf20Sopenharmony_ci	ypcm = runtime->private_data;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	/* wait, until the PCI operations are not finished */
6498c2ecf20Sopenharmony_ci	snd_ymfpci_irq_wait(chip);
6508c2ecf20Sopenharmony_ci	if (ypcm->voices[1]) {
6518c2ecf20Sopenharmony_ci		snd_ymfpci_voice_free(chip, ypcm->voices[1]);
6528c2ecf20Sopenharmony_ci		ypcm->voices[1] = NULL;
6538c2ecf20Sopenharmony_ci	}
6548c2ecf20Sopenharmony_ci	if (ypcm->voices[0]) {
6558c2ecf20Sopenharmony_ci		snd_ymfpci_voice_free(chip, ypcm->voices[0]);
6568c2ecf20Sopenharmony_ci		ypcm->voices[0] = NULL;
6578c2ecf20Sopenharmony_ci	}
6588c2ecf20Sopenharmony_ci	return 0;
6598c2ecf20Sopenharmony_ci}
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_cistatic int snd_ymfpci_playback_prepare(struct snd_pcm_substream *substream)
6628c2ecf20Sopenharmony_ci{
6638c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
6648c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
6658c2ecf20Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = runtime->private_data;
6668c2ecf20Sopenharmony_ci	struct snd_kcontrol *kctl;
6678c2ecf20Sopenharmony_ci	unsigned int nvoice;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	ypcm->period_size = runtime->period_size;
6708c2ecf20Sopenharmony_ci	ypcm->buffer_size = runtime->buffer_size;
6718c2ecf20Sopenharmony_ci	ypcm->period_pos = 0;
6728c2ecf20Sopenharmony_ci	ypcm->last_pos = 0;
6738c2ecf20Sopenharmony_ci	for (nvoice = 0; nvoice < runtime->channels; nvoice++)
6748c2ecf20Sopenharmony_ci		snd_ymfpci_pcm_init_voice(ypcm, nvoice, runtime,
6758c2ecf20Sopenharmony_ci					  substream->pcm == chip->pcm);
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	if (substream->pcm == chip->pcm && !ypcm->use_441_slot) {
6788c2ecf20Sopenharmony_ci		kctl = chip->pcm_mixer[substream->number].ctl;
6798c2ecf20Sopenharmony_ci		kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
6808c2ecf20Sopenharmony_ci		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
6818c2ecf20Sopenharmony_ci	}
6828c2ecf20Sopenharmony_ci	return 0;
6838c2ecf20Sopenharmony_ci}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_cistatic int snd_ymfpci_capture_hw_free(struct snd_pcm_substream *substream)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	/* wait, until the PCI operations are not finished */
6908c2ecf20Sopenharmony_ci	snd_ymfpci_irq_wait(chip);
6918c2ecf20Sopenharmony_ci	return 0;
6928c2ecf20Sopenharmony_ci}
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_cistatic int snd_ymfpci_capture_prepare(struct snd_pcm_substream *substream)
6958c2ecf20Sopenharmony_ci{
6968c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
6978c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
6988c2ecf20Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = runtime->private_data;
6998c2ecf20Sopenharmony_ci	struct snd_ymfpci_capture_bank * bank;
7008c2ecf20Sopenharmony_ci	int nbank;
7018c2ecf20Sopenharmony_ci	u32 rate, format;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	ypcm->period_size = runtime->period_size;
7048c2ecf20Sopenharmony_ci	ypcm->buffer_size = runtime->buffer_size;
7058c2ecf20Sopenharmony_ci	ypcm->period_pos = 0;
7068c2ecf20Sopenharmony_ci	ypcm->last_pos = 0;
7078c2ecf20Sopenharmony_ci	ypcm->shift = 0;
7088c2ecf20Sopenharmony_ci	rate = ((48000 * 4096) / runtime->rate) - 1;
7098c2ecf20Sopenharmony_ci	format = 0;
7108c2ecf20Sopenharmony_ci	if (runtime->channels == 2) {
7118c2ecf20Sopenharmony_ci		format |= 2;
7128c2ecf20Sopenharmony_ci		ypcm->shift++;
7138c2ecf20Sopenharmony_ci	}
7148c2ecf20Sopenharmony_ci	if (snd_pcm_format_width(runtime->format) == 8)
7158c2ecf20Sopenharmony_ci		format |= 1;
7168c2ecf20Sopenharmony_ci	else
7178c2ecf20Sopenharmony_ci		ypcm->shift++;
7188c2ecf20Sopenharmony_ci	switch (ypcm->capture_bank_number) {
7198c2ecf20Sopenharmony_ci	case 0:
7208c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_RECFORMAT, format);
7218c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_RECSLOTSR, rate);
7228c2ecf20Sopenharmony_ci		break;
7238c2ecf20Sopenharmony_ci	case 1:
7248c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_ADCFORMAT, format);
7258c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_ADCSLOTSR, rate);
7268c2ecf20Sopenharmony_ci		break;
7278c2ecf20Sopenharmony_ci	}
7288c2ecf20Sopenharmony_ci	for (nbank = 0; nbank < 2; nbank++) {
7298c2ecf20Sopenharmony_ci		bank = chip->bank_capture[ypcm->capture_bank_number][nbank];
7308c2ecf20Sopenharmony_ci		bank->base = cpu_to_le32(runtime->dma_addr);
7318c2ecf20Sopenharmony_ci		bank->loop_end = cpu_to_le32(ypcm->buffer_size << ypcm->shift);
7328c2ecf20Sopenharmony_ci		bank->start = 0;
7338c2ecf20Sopenharmony_ci		bank->num_of_loops = 0;
7348c2ecf20Sopenharmony_ci	}
7358c2ecf20Sopenharmony_ci	return 0;
7368c2ecf20Sopenharmony_ci}
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t snd_ymfpci_playback_pointer(struct snd_pcm_substream *substream)
7398c2ecf20Sopenharmony_ci{
7408c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
7418c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
7428c2ecf20Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = runtime->private_data;
7438c2ecf20Sopenharmony_ci	struct snd_ymfpci_voice *voice = ypcm->voices[0];
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	if (!(ypcm->running && voice))
7468c2ecf20Sopenharmony_ci		return 0;
7478c2ecf20Sopenharmony_ci	return le32_to_cpu(voice->bank[chip->active_bank].start);
7488c2ecf20Sopenharmony_ci}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t snd_ymfpci_capture_pointer(struct snd_pcm_substream *substream)
7518c2ecf20Sopenharmony_ci{
7528c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
7538c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
7548c2ecf20Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = runtime->private_data;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	if (!ypcm->running)
7578c2ecf20Sopenharmony_ci		return 0;
7588c2ecf20Sopenharmony_ci	return le32_to_cpu(chip->bank_capture[ypcm->capture_bank_number][chip->active_bank]->start) >> ypcm->shift;
7598c2ecf20Sopenharmony_ci}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_cistatic void snd_ymfpci_irq_wait(struct snd_ymfpci *chip)
7628c2ecf20Sopenharmony_ci{
7638c2ecf20Sopenharmony_ci	wait_queue_entry_t wait;
7648c2ecf20Sopenharmony_ci	int loops = 4;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	while (loops-- > 0) {
7678c2ecf20Sopenharmony_ci		if ((snd_ymfpci_readl(chip, YDSXGR_MODE) & 3) == 0)
7688c2ecf20Sopenharmony_ci		 	continue;
7698c2ecf20Sopenharmony_ci		init_waitqueue_entry(&wait, current);
7708c2ecf20Sopenharmony_ci		add_wait_queue(&chip->interrupt_sleep, &wait);
7718c2ecf20Sopenharmony_ci		atomic_inc(&chip->interrupt_sleep_count);
7728c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(msecs_to_jiffies(50));
7738c2ecf20Sopenharmony_ci		remove_wait_queue(&chip->interrupt_sleep, &wait);
7748c2ecf20Sopenharmony_ci	}
7758c2ecf20Sopenharmony_ci}
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_cistatic irqreturn_t snd_ymfpci_interrupt(int irq, void *dev_id)
7788c2ecf20Sopenharmony_ci{
7798c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = dev_id;
7808c2ecf20Sopenharmony_ci	u32 status, nvoice, mode;
7818c2ecf20Sopenharmony_ci	struct snd_ymfpci_voice *voice;
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	status = snd_ymfpci_readl(chip, YDSXGR_STATUS);
7848c2ecf20Sopenharmony_ci	if (status & 0x80000000) {
7858c2ecf20Sopenharmony_ci		chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT) & 1;
7868c2ecf20Sopenharmony_ci		spin_lock(&chip->voice_lock);
7878c2ecf20Sopenharmony_ci		for (nvoice = 0; nvoice < YDSXG_PLAYBACK_VOICES; nvoice++) {
7888c2ecf20Sopenharmony_ci			voice = &chip->voices[nvoice];
7898c2ecf20Sopenharmony_ci			if (voice->interrupt)
7908c2ecf20Sopenharmony_ci				voice->interrupt(chip, voice);
7918c2ecf20Sopenharmony_ci		}
7928c2ecf20Sopenharmony_ci		for (nvoice = 0; nvoice < YDSXG_CAPTURE_VOICES; nvoice++) {
7938c2ecf20Sopenharmony_ci			if (chip->capture_substream[nvoice])
7948c2ecf20Sopenharmony_ci				snd_ymfpci_pcm_capture_interrupt(chip->capture_substream[nvoice]);
7958c2ecf20Sopenharmony_ci		}
7968c2ecf20Sopenharmony_ci#if 0
7978c2ecf20Sopenharmony_ci		for (nvoice = 0; nvoice < YDSXG_EFFECT_VOICES; nvoice++) {
7988c2ecf20Sopenharmony_ci			if (chip->effect_substream[nvoice])
7998c2ecf20Sopenharmony_ci				snd_ymfpci_pcm_effect_interrupt(chip->effect_substream[nvoice]);
8008c2ecf20Sopenharmony_ci		}
8018c2ecf20Sopenharmony_ci#endif
8028c2ecf20Sopenharmony_ci		spin_unlock(&chip->voice_lock);
8038c2ecf20Sopenharmony_ci		spin_lock(&chip->reg_lock);
8048c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_STATUS, 0x80000000);
8058c2ecf20Sopenharmony_ci		mode = snd_ymfpci_readl(chip, YDSXGR_MODE) | 2;
8068c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_MODE, mode);
8078c2ecf20Sopenharmony_ci		spin_unlock(&chip->reg_lock);
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci		if (atomic_read(&chip->interrupt_sleep_count)) {
8108c2ecf20Sopenharmony_ci			atomic_set(&chip->interrupt_sleep_count, 0);
8118c2ecf20Sopenharmony_ci			wake_up(&chip->interrupt_sleep);
8128c2ecf20Sopenharmony_ci		}
8138c2ecf20Sopenharmony_ci	}
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	status = snd_ymfpci_readw(chip, YDSXGR_INTFLAG);
8168c2ecf20Sopenharmony_ci	if (status & 1) {
8178c2ecf20Sopenharmony_ci		if (chip->timer)
8188c2ecf20Sopenharmony_ci			snd_timer_interrupt(chip->timer, chip->timer_ticks);
8198c2ecf20Sopenharmony_ci	}
8208c2ecf20Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_INTFLAG, status);
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	if (chip->rawmidi)
8238c2ecf20Sopenharmony_ci		snd_mpu401_uart_interrupt(irq, chip->rawmidi->private_data);
8248c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
8258c2ecf20Sopenharmony_ci}
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware snd_ymfpci_playback =
8288c2ecf20Sopenharmony_ci{
8298c2ecf20Sopenharmony_ci	.info =			(SNDRV_PCM_INFO_MMAP |
8308c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_MMAP_VALID |
8318c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_INTERLEAVED |
8328c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
8338c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_PAUSE |
8348c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_RESUME),
8358c2ecf20Sopenharmony_ci	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
8368c2ecf20Sopenharmony_ci	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
8378c2ecf20Sopenharmony_ci	.rate_min =		8000,
8388c2ecf20Sopenharmony_ci	.rate_max =		48000,
8398c2ecf20Sopenharmony_ci	.channels_min =		1,
8408c2ecf20Sopenharmony_ci	.channels_max =		2,
8418c2ecf20Sopenharmony_ci	.buffer_bytes_max =	256 * 1024, /* FIXME: enough? */
8428c2ecf20Sopenharmony_ci	.period_bytes_min =	64,
8438c2ecf20Sopenharmony_ci	.period_bytes_max =	256 * 1024, /* FIXME: enough? */
8448c2ecf20Sopenharmony_ci	.periods_min =		3,
8458c2ecf20Sopenharmony_ci	.periods_max =		1024,
8468c2ecf20Sopenharmony_ci	.fifo_size =		0,
8478c2ecf20Sopenharmony_ci};
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware snd_ymfpci_capture =
8508c2ecf20Sopenharmony_ci{
8518c2ecf20Sopenharmony_ci	.info =			(SNDRV_PCM_INFO_MMAP |
8528c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_MMAP_VALID |
8538c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_INTERLEAVED |
8548c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
8558c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_PAUSE |
8568c2ecf20Sopenharmony_ci				 SNDRV_PCM_INFO_RESUME),
8578c2ecf20Sopenharmony_ci	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
8588c2ecf20Sopenharmony_ci	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
8598c2ecf20Sopenharmony_ci	.rate_min =		8000,
8608c2ecf20Sopenharmony_ci	.rate_max =		48000,
8618c2ecf20Sopenharmony_ci	.channels_min =		1,
8628c2ecf20Sopenharmony_ci	.channels_max =		2,
8638c2ecf20Sopenharmony_ci	.buffer_bytes_max =	256 * 1024, /* FIXME: enough? */
8648c2ecf20Sopenharmony_ci	.period_bytes_min =	64,
8658c2ecf20Sopenharmony_ci	.period_bytes_max =	256 * 1024, /* FIXME: enough? */
8668c2ecf20Sopenharmony_ci	.periods_min =		3,
8678c2ecf20Sopenharmony_ci	.periods_max =		1024,
8688c2ecf20Sopenharmony_ci	.fifo_size =		0,
8698c2ecf20Sopenharmony_ci};
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_cistatic void snd_ymfpci_pcm_free_substream(struct snd_pcm_runtime *runtime)
8728c2ecf20Sopenharmony_ci{
8738c2ecf20Sopenharmony_ci	kfree(runtime->private_data);
8748c2ecf20Sopenharmony_ci}
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_cistatic int snd_ymfpci_playback_open_1(struct snd_pcm_substream *substream)
8778c2ecf20Sopenharmony_ci{
8788c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
8798c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
8808c2ecf20Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm;
8818c2ecf20Sopenharmony_ci	int err;
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	runtime->hw = snd_ymfpci_playback;
8848c2ecf20Sopenharmony_ci	/* FIXME? True value is 256/48 = 5.33333 ms */
8858c2ecf20Sopenharmony_ci	err = snd_pcm_hw_constraint_minmax(runtime,
8868c2ecf20Sopenharmony_ci					   SNDRV_PCM_HW_PARAM_PERIOD_TIME,
8878c2ecf20Sopenharmony_ci					   5334, UINT_MAX);
8888c2ecf20Sopenharmony_ci	if (err < 0)
8898c2ecf20Sopenharmony_ci		return err;
8908c2ecf20Sopenharmony_ci	err = snd_pcm_hw_rule_noresample(runtime, 48000);
8918c2ecf20Sopenharmony_ci	if (err < 0)
8928c2ecf20Sopenharmony_ci		return err;
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	ypcm = kzalloc(sizeof(*ypcm), GFP_KERNEL);
8958c2ecf20Sopenharmony_ci	if (ypcm == NULL)
8968c2ecf20Sopenharmony_ci		return -ENOMEM;
8978c2ecf20Sopenharmony_ci	ypcm->chip = chip;
8988c2ecf20Sopenharmony_ci	ypcm->type = PLAYBACK_VOICE;
8998c2ecf20Sopenharmony_ci	ypcm->substream = substream;
9008c2ecf20Sopenharmony_ci	runtime->private_data = ypcm;
9018c2ecf20Sopenharmony_ci	runtime->private_free = snd_ymfpci_pcm_free_substream;
9028c2ecf20Sopenharmony_ci	return 0;
9038c2ecf20Sopenharmony_ci}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci/* call with spinlock held */
9068c2ecf20Sopenharmony_cistatic void ymfpci_open_extension(struct snd_ymfpci *chip)
9078c2ecf20Sopenharmony_ci{
9088c2ecf20Sopenharmony_ci	if (! chip->rear_opened) {
9098c2ecf20Sopenharmony_ci		if (! chip->spdif_opened) /* set AC3 */
9108c2ecf20Sopenharmony_ci			snd_ymfpci_writel(chip, YDSXGR_MODE,
9118c2ecf20Sopenharmony_ci					  snd_ymfpci_readl(chip, YDSXGR_MODE) | (1 << 30));
9128c2ecf20Sopenharmony_ci		/* enable second codec (4CHEN) */
9138c2ecf20Sopenharmony_ci		snd_ymfpci_writew(chip, YDSXGR_SECCONFIG,
9148c2ecf20Sopenharmony_ci				  (snd_ymfpci_readw(chip, YDSXGR_SECCONFIG) & ~0x0330) | 0x0010);
9158c2ecf20Sopenharmony_ci	}
9168c2ecf20Sopenharmony_ci}
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci/* call with spinlock held */
9198c2ecf20Sopenharmony_cistatic void ymfpci_close_extension(struct snd_ymfpci *chip)
9208c2ecf20Sopenharmony_ci{
9218c2ecf20Sopenharmony_ci	if (! chip->rear_opened) {
9228c2ecf20Sopenharmony_ci		if (! chip->spdif_opened)
9238c2ecf20Sopenharmony_ci			snd_ymfpci_writel(chip, YDSXGR_MODE,
9248c2ecf20Sopenharmony_ci					  snd_ymfpci_readl(chip, YDSXGR_MODE) & ~(1 << 30));
9258c2ecf20Sopenharmony_ci		snd_ymfpci_writew(chip, YDSXGR_SECCONFIG,
9268c2ecf20Sopenharmony_ci				  (snd_ymfpci_readw(chip, YDSXGR_SECCONFIG) & ~0x0330) & ~0x0010);
9278c2ecf20Sopenharmony_ci	}
9288c2ecf20Sopenharmony_ci}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_cistatic int snd_ymfpci_playback_open(struct snd_pcm_substream *substream)
9318c2ecf20Sopenharmony_ci{
9328c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
9338c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
9348c2ecf20Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm;
9358c2ecf20Sopenharmony_ci	int err;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	err = snd_ymfpci_playback_open_1(substream);
9388c2ecf20Sopenharmony_ci	if (err < 0)
9398c2ecf20Sopenharmony_ci		return err;
9408c2ecf20Sopenharmony_ci	ypcm = runtime->private_data;
9418c2ecf20Sopenharmony_ci	ypcm->output_front = 1;
9428c2ecf20Sopenharmony_ci	ypcm->output_rear = chip->mode_dup4ch ? 1 : 0;
9438c2ecf20Sopenharmony_ci	ypcm->swap_rear = 0;
9448c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
9458c2ecf20Sopenharmony_ci	if (ypcm->output_rear) {
9468c2ecf20Sopenharmony_ci		ymfpci_open_extension(chip);
9478c2ecf20Sopenharmony_ci		chip->rear_opened++;
9488c2ecf20Sopenharmony_ci	}
9498c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
9508c2ecf20Sopenharmony_ci	return 0;
9518c2ecf20Sopenharmony_ci}
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_cistatic int snd_ymfpci_playback_spdif_open(struct snd_pcm_substream *substream)
9548c2ecf20Sopenharmony_ci{
9558c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
9568c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
9578c2ecf20Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm;
9588c2ecf20Sopenharmony_ci	int err;
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	err = snd_ymfpci_playback_open_1(substream);
9618c2ecf20Sopenharmony_ci	if (err < 0)
9628c2ecf20Sopenharmony_ci		return err;
9638c2ecf20Sopenharmony_ci	ypcm = runtime->private_data;
9648c2ecf20Sopenharmony_ci	ypcm->output_front = 0;
9658c2ecf20Sopenharmony_ci	ypcm->output_rear = 1;
9668c2ecf20Sopenharmony_ci	ypcm->swap_rear = 1;
9678c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
9688c2ecf20Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL,
9698c2ecf20Sopenharmony_ci			  snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) | 2);
9708c2ecf20Sopenharmony_ci	ymfpci_open_extension(chip);
9718c2ecf20Sopenharmony_ci	chip->spdif_pcm_bits = chip->spdif_bits;
9728c2ecf20Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_pcm_bits);
9738c2ecf20Sopenharmony_ci	chip->spdif_opened++;
9748c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	chip->spdif_pcm_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
9778c2ecf20Sopenharmony_ci	snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE |
9788c2ecf20Sopenharmony_ci		       SNDRV_CTL_EVENT_MASK_INFO, &chip->spdif_pcm_ctl->id);
9798c2ecf20Sopenharmony_ci	return 0;
9808c2ecf20Sopenharmony_ci}
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_cistatic int snd_ymfpci_playback_4ch_open(struct snd_pcm_substream *substream)
9838c2ecf20Sopenharmony_ci{
9848c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
9858c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
9868c2ecf20Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm;
9878c2ecf20Sopenharmony_ci	int err;
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	err = snd_ymfpci_playback_open_1(substream);
9908c2ecf20Sopenharmony_ci	if (err < 0)
9918c2ecf20Sopenharmony_ci		return err;
9928c2ecf20Sopenharmony_ci	ypcm = runtime->private_data;
9938c2ecf20Sopenharmony_ci	ypcm->output_front = 0;
9948c2ecf20Sopenharmony_ci	ypcm->output_rear = 1;
9958c2ecf20Sopenharmony_ci	ypcm->swap_rear = 0;
9968c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
9978c2ecf20Sopenharmony_ci	ymfpci_open_extension(chip);
9988c2ecf20Sopenharmony_ci	chip->rear_opened++;
9998c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
10008c2ecf20Sopenharmony_ci	return 0;
10018c2ecf20Sopenharmony_ci}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_cistatic int snd_ymfpci_capture_open(struct snd_pcm_substream *substream,
10048c2ecf20Sopenharmony_ci				   u32 capture_bank_number)
10058c2ecf20Sopenharmony_ci{
10068c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
10078c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
10088c2ecf20Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm;
10098c2ecf20Sopenharmony_ci	int err;
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	runtime->hw = snd_ymfpci_capture;
10128c2ecf20Sopenharmony_ci	/* FIXME? True value is 256/48 = 5.33333 ms */
10138c2ecf20Sopenharmony_ci	err = snd_pcm_hw_constraint_minmax(runtime,
10148c2ecf20Sopenharmony_ci					   SNDRV_PCM_HW_PARAM_PERIOD_TIME,
10158c2ecf20Sopenharmony_ci					   5334, UINT_MAX);
10168c2ecf20Sopenharmony_ci	if (err < 0)
10178c2ecf20Sopenharmony_ci		return err;
10188c2ecf20Sopenharmony_ci	err = snd_pcm_hw_rule_noresample(runtime, 48000);
10198c2ecf20Sopenharmony_ci	if (err < 0)
10208c2ecf20Sopenharmony_ci		return err;
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	ypcm = kzalloc(sizeof(*ypcm), GFP_KERNEL);
10238c2ecf20Sopenharmony_ci	if (ypcm == NULL)
10248c2ecf20Sopenharmony_ci		return -ENOMEM;
10258c2ecf20Sopenharmony_ci	ypcm->chip = chip;
10268c2ecf20Sopenharmony_ci	ypcm->type = capture_bank_number + CAPTURE_REC;
10278c2ecf20Sopenharmony_ci	ypcm->substream = substream;
10288c2ecf20Sopenharmony_ci	ypcm->capture_bank_number = capture_bank_number;
10298c2ecf20Sopenharmony_ci	chip->capture_substream[capture_bank_number] = substream;
10308c2ecf20Sopenharmony_ci	runtime->private_data = ypcm;
10318c2ecf20Sopenharmony_ci	runtime->private_free = snd_ymfpci_pcm_free_substream;
10328c2ecf20Sopenharmony_ci	snd_ymfpci_hw_start(chip);
10338c2ecf20Sopenharmony_ci	return 0;
10348c2ecf20Sopenharmony_ci}
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_cistatic int snd_ymfpci_capture_rec_open(struct snd_pcm_substream *substream)
10378c2ecf20Sopenharmony_ci{
10388c2ecf20Sopenharmony_ci	return snd_ymfpci_capture_open(substream, 0);
10398c2ecf20Sopenharmony_ci}
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_cistatic int snd_ymfpci_capture_ac97_open(struct snd_pcm_substream *substream)
10428c2ecf20Sopenharmony_ci{
10438c2ecf20Sopenharmony_ci	return snd_ymfpci_capture_open(substream, 1);
10448c2ecf20Sopenharmony_ci}
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_cistatic int snd_ymfpci_playback_close_1(struct snd_pcm_substream *substream)
10478c2ecf20Sopenharmony_ci{
10488c2ecf20Sopenharmony_ci	return 0;
10498c2ecf20Sopenharmony_ci}
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_cistatic int snd_ymfpci_playback_close(struct snd_pcm_substream *substream)
10528c2ecf20Sopenharmony_ci{
10538c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
10548c2ecf20Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data;
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
10578c2ecf20Sopenharmony_ci	if (ypcm->output_rear && chip->rear_opened > 0) {
10588c2ecf20Sopenharmony_ci		chip->rear_opened--;
10598c2ecf20Sopenharmony_ci		ymfpci_close_extension(chip);
10608c2ecf20Sopenharmony_ci	}
10618c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
10628c2ecf20Sopenharmony_ci	return snd_ymfpci_playback_close_1(substream);
10638c2ecf20Sopenharmony_ci}
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_cistatic int snd_ymfpci_playback_spdif_close(struct snd_pcm_substream *substream)
10668c2ecf20Sopenharmony_ci{
10678c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
10708c2ecf20Sopenharmony_ci	chip->spdif_opened = 0;
10718c2ecf20Sopenharmony_ci	ymfpci_close_extension(chip);
10728c2ecf20Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL,
10738c2ecf20Sopenharmony_ci			  snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) & ~2);
10748c2ecf20Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_bits);
10758c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
10768c2ecf20Sopenharmony_ci	chip->spdif_pcm_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
10778c2ecf20Sopenharmony_ci	snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE |
10788c2ecf20Sopenharmony_ci		       SNDRV_CTL_EVENT_MASK_INFO, &chip->spdif_pcm_ctl->id);
10798c2ecf20Sopenharmony_ci	return snd_ymfpci_playback_close_1(substream);
10808c2ecf20Sopenharmony_ci}
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_cistatic int snd_ymfpci_playback_4ch_close(struct snd_pcm_substream *substream)
10838c2ecf20Sopenharmony_ci{
10848c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
10878c2ecf20Sopenharmony_ci	if (chip->rear_opened > 0) {
10888c2ecf20Sopenharmony_ci		chip->rear_opened--;
10898c2ecf20Sopenharmony_ci		ymfpci_close_extension(chip);
10908c2ecf20Sopenharmony_ci	}
10918c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
10928c2ecf20Sopenharmony_ci	return snd_ymfpci_playback_close_1(substream);
10938c2ecf20Sopenharmony_ci}
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_cistatic int snd_ymfpci_capture_close(struct snd_pcm_substream *substream)
10968c2ecf20Sopenharmony_ci{
10978c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
10988c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
10998c2ecf20Sopenharmony_ci	struct snd_ymfpci_pcm *ypcm = runtime->private_data;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	if (ypcm != NULL) {
11028c2ecf20Sopenharmony_ci		chip->capture_substream[ypcm->capture_bank_number] = NULL;
11038c2ecf20Sopenharmony_ci		snd_ymfpci_hw_stop(chip);
11048c2ecf20Sopenharmony_ci	}
11058c2ecf20Sopenharmony_ci	return 0;
11068c2ecf20Sopenharmony_ci}
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_ymfpci_playback_ops = {
11098c2ecf20Sopenharmony_ci	.open =			snd_ymfpci_playback_open,
11108c2ecf20Sopenharmony_ci	.close =		snd_ymfpci_playback_close,
11118c2ecf20Sopenharmony_ci	.hw_params =		snd_ymfpci_playback_hw_params,
11128c2ecf20Sopenharmony_ci	.hw_free =		snd_ymfpci_playback_hw_free,
11138c2ecf20Sopenharmony_ci	.prepare =		snd_ymfpci_playback_prepare,
11148c2ecf20Sopenharmony_ci	.trigger =		snd_ymfpci_playback_trigger,
11158c2ecf20Sopenharmony_ci	.pointer =		snd_ymfpci_playback_pointer,
11168c2ecf20Sopenharmony_ci};
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_ymfpci_capture_rec_ops = {
11198c2ecf20Sopenharmony_ci	.open =			snd_ymfpci_capture_rec_open,
11208c2ecf20Sopenharmony_ci	.close =		snd_ymfpci_capture_close,
11218c2ecf20Sopenharmony_ci	.hw_free =		snd_ymfpci_capture_hw_free,
11228c2ecf20Sopenharmony_ci	.prepare =		snd_ymfpci_capture_prepare,
11238c2ecf20Sopenharmony_ci	.trigger =		snd_ymfpci_capture_trigger,
11248c2ecf20Sopenharmony_ci	.pointer =		snd_ymfpci_capture_pointer,
11258c2ecf20Sopenharmony_ci};
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ciint snd_ymfpci_pcm(struct snd_ymfpci *chip, int device)
11288c2ecf20Sopenharmony_ci{
11298c2ecf20Sopenharmony_ci	struct snd_pcm *pcm;
11308c2ecf20Sopenharmony_ci	int err;
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	err = snd_pcm_new(chip->card, "YMFPCI", device, 32, 1, &pcm);
11338c2ecf20Sopenharmony_ci	if (err < 0)
11348c2ecf20Sopenharmony_ci		return err;
11358c2ecf20Sopenharmony_ci	pcm->private_data = chip;
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ymfpci_playback_ops);
11388c2ecf20Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ymfpci_capture_rec_ops);
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	/* global setup */
11418c2ecf20Sopenharmony_ci	pcm->info_flags = 0;
11428c2ecf20Sopenharmony_ci	strcpy(pcm->name, "YMFPCI");
11438c2ecf20Sopenharmony_ci	chip->pcm = pcm;
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
11468c2ecf20Sopenharmony_ci				       &chip->pci->dev, 64*1024, 256*1024);
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
11498c2ecf20Sopenharmony_ci				     snd_pcm_std_chmaps, 2, 0, NULL);
11508c2ecf20Sopenharmony_ci}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_ymfpci_capture_ac97_ops = {
11538c2ecf20Sopenharmony_ci	.open =			snd_ymfpci_capture_ac97_open,
11548c2ecf20Sopenharmony_ci	.close =		snd_ymfpci_capture_close,
11558c2ecf20Sopenharmony_ci	.hw_free =		snd_ymfpci_capture_hw_free,
11568c2ecf20Sopenharmony_ci	.prepare =		snd_ymfpci_capture_prepare,
11578c2ecf20Sopenharmony_ci	.trigger =		snd_ymfpci_capture_trigger,
11588c2ecf20Sopenharmony_ci	.pointer =		snd_ymfpci_capture_pointer,
11598c2ecf20Sopenharmony_ci};
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ciint snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device)
11628c2ecf20Sopenharmony_ci{
11638c2ecf20Sopenharmony_ci	struct snd_pcm *pcm;
11648c2ecf20Sopenharmony_ci	int err;
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	err = snd_pcm_new(chip->card, "YMFPCI - PCM2", device, 0, 1, &pcm);
11678c2ecf20Sopenharmony_ci	if (err < 0)
11688c2ecf20Sopenharmony_ci		return err;
11698c2ecf20Sopenharmony_ci	pcm->private_data = chip;
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ymfpci_capture_ac97_ops);
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci	/* global setup */
11748c2ecf20Sopenharmony_ci	pcm->info_flags = 0;
11758c2ecf20Sopenharmony_ci	sprintf(pcm->name, "YMFPCI - %s",
11768c2ecf20Sopenharmony_ci		chip->device_id == PCI_DEVICE_ID_YAMAHA_754 ? "Direct Recording" : "AC'97");
11778c2ecf20Sopenharmony_ci	chip->pcm2 = pcm;
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
11808c2ecf20Sopenharmony_ci				       &chip->pci->dev, 64*1024, 256*1024);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	return 0;
11838c2ecf20Sopenharmony_ci}
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_ymfpci_playback_spdif_ops = {
11868c2ecf20Sopenharmony_ci	.open =			snd_ymfpci_playback_spdif_open,
11878c2ecf20Sopenharmony_ci	.close =		snd_ymfpci_playback_spdif_close,
11888c2ecf20Sopenharmony_ci	.hw_params =		snd_ymfpci_playback_hw_params,
11898c2ecf20Sopenharmony_ci	.hw_free =		snd_ymfpci_playback_hw_free,
11908c2ecf20Sopenharmony_ci	.prepare =		snd_ymfpci_playback_prepare,
11918c2ecf20Sopenharmony_ci	.trigger =		snd_ymfpci_playback_trigger,
11928c2ecf20Sopenharmony_ci	.pointer =		snd_ymfpci_playback_pointer,
11938c2ecf20Sopenharmony_ci};
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ciint snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device)
11968c2ecf20Sopenharmony_ci{
11978c2ecf20Sopenharmony_ci	struct snd_pcm *pcm;
11988c2ecf20Sopenharmony_ci	int err;
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	err = snd_pcm_new(chip->card, "YMFPCI - IEC958", device, 1, 0, &pcm);
12018c2ecf20Sopenharmony_ci	if (err < 0)
12028c2ecf20Sopenharmony_ci		return err;
12038c2ecf20Sopenharmony_ci	pcm->private_data = chip;
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ymfpci_playback_spdif_ops);
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	/* global setup */
12088c2ecf20Sopenharmony_ci	pcm->info_flags = 0;
12098c2ecf20Sopenharmony_ci	strcpy(pcm->name, "YMFPCI - IEC958");
12108c2ecf20Sopenharmony_ci	chip->pcm_spdif = pcm;
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
12138c2ecf20Sopenharmony_ci				       &chip->pci->dev, 64*1024, 256*1024);
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	return 0;
12168c2ecf20Sopenharmony_ci}
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_ymfpci_playback_4ch_ops = {
12198c2ecf20Sopenharmony_ci	.open =			snd_ymfpci_playback_4ch_open,
12208c2ecf20Sopenharmony_ci	.close =		snd_ymfpci_playback_4ch_close,
12218c2ecf20Sopenharmony_ci	.hw_params =		snd_ymfpci_playback_hw_params,
12228c2ecf20Sopenharmony_ci	.hw_free =		snd_ymfpci_playback_hw_free,
12238c2ecf20Sopenharmony_ci	.prepare =		snd_ymfpci_playback_prepare,
12248c2ecf20Sopenharmony_ci	.trigger =		snd_ymfpci_playback_trigger,
12258c2ecf20Sopenharmony_ci	.pointer =		snd_ymfpci_playback_pointer,
12268c2ecf20Sopenharmony_ci};
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_cistatic const struct snd_pcm_chmap_elem surround_map[] = {
12298c2ecf20Sopenharmony_ci	{ .channels = 1,
12308c2ecf20Sopenharmony_ci	  .map = { SNDRV_CHMAP_MONO } },
12318c2ecf20Sopenharmony_ci	{ .channels = 2,
12328c2ecf20Sopenharmony_ci	  .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
12338c2ecf20Sopenharmony_ci	{ }
12348c2ecf20Sopenharmony_ci};
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ciint snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device)
12378c2ecf20Sopenharmony_ci{
12388c2ecf20Sopenharmony_ci	struct snd_pcm *pcm;
12398c2ecf20Sopenharmony_ci	int err;
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci	err = snd_pcm_new(chip->card, "YMFPCI - Rear", device, 1, 0, &pcm);
12428c2ecf20Sopenharmony_ci	if (err < 0)
12438c2ecf20Sopenharmony_ci		return err;
12448c2ecf20Sopenharmony_ci	pcm->private_data = chip;
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ymfpci_playback_4ch_ops);
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	/* global setup */
12498c2ecf20Sopenharmony_ci	pcm->info_flags = 0;
12508c2ecf20Sopenharmony_ci	strcpy(pcm->name, "YMFPCI - Rear PCM");
12518c2ecf20Sopenharmony_ci	chip->pcm_4ch = pcm;
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
12548c2ecf20Sopenharmony_ci				       &chip->pci->dev, 64*1024, 256*1024);
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
12578c2ecf20Sopenharmony_ci				     surround_map, 2, 0, NULL);
12588c2ecf20Sopenharmony_ci}
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_cistatic int snd_ymfpci_spdif_default_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12618c2ecf20Sopenharmony_ci{
12628c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
12638c2ecf20Sopenharmony_ci	uinfo->count = 1;
12648c2ecf20Sopenharmony_ci	return 0;
12658c2ecf20Sopenharmony_ci}
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_cistatic int snd_ymfpci_spdif_default_get(struct snd_kcontrol *kcontrol,
12688c2ecf20Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
12698c2ecf20Sopenharmony_ci{
12708c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
12738c2ecf20Sopenharmony_ci	ucontrol->value.iec958.status[0] = (chip->spdif_bits >> 0) & 0xff;
12748c2ecf20Sopenharmony_ci	ucontrol->value.iec958.status[1] = (chip->spdif_bits >> 8) & 0xff;
12758c2ecf20Sopenharmony_ci	ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000;
12768c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
12778c2ecf20Sopenharmony_ci	return 0;
12788c2ecf20Sopenharmony_ci}
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_cistatic int snd_ymfpci_spdif_default_put(struct snd_kcontrol *kcontrol,
12818c2ecf20Sopenharmony_ci					 struct snd_ctl_elem_value *ucontrol)
12828c2ecf20Sopenharmony_ci{
12838c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
12848c2ecf20Sopenharmony_ci	unsigned int val;
12858c2ecf20Sopenharmony_ci	int change;
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	val = ((ucontrol->value.iec958.status[0] & 0x3e) << 0) |
12888c2ecf20Sopenharmony_ci	      (ucontrol->value.iec958.status[1] << 8);
12898c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
12908c2ecf20Sopenharmony_ci	change = chip->spdif_bits != val;
12918c2ecf20Sopenharmony_ci	chip->spdif_bits = val;
12928c2ecf20Sopenharmony_ci	if ((snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) & 1) && chip->pcm_spdif == NULL)
12938c2ecf20Sopenharmony_ci		snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_bits);
12948c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
12958c2ecf20Sopenharmony_ci	return change;
12968c2ecf20Sopenharmony_ci}
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_spdif_default =
12998c2ecf20Sopenharmony_ci{
13008c2ecf20Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
13018c2ecf20Sopenharmony_ci	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
13028c2ecf20Sopenharmony_ci	.info =		snd_ymfpci_spdif_default_info,
13038c2ecf20Sopenharmony_ci	.get =		snd_ymfpci_spdif_default_get,
13048c2ecf20Sopenharmony_ci	.put =		snd_ymfpci_spdif_default_put
13058c2ecf20Sopenharmony_ci};
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_cistatic int snd_ymfpci_spdif_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13088c2ecf20Sopenharmony_ci{
13098c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
13108c2ecf20Sopenharmony_ci	uinfo->count = 1;
13118c2ecf20Sopenharmony_ci	return 0;
13128c2ecf20Sopenharmony_ci}
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_cistatic int snd_ymfpci_spdif_mask_get(struct snd_kcontrol *kcontrol,
13158c2ecf20Sopenharmony_ci				      struct snd_ctl_elem_value *ucontrol)
13168c2ecf20Sopenharmony_ci{
13178c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
13208c2ecf20Sopenharmony_ci	ucontrol->value.iec958.status[0] = 0x3e;
13218c2ecf20Sopenharmony_ci	ucontrol->value.iec958.status[1] = 0xff;
13228c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
13238c2ecf20Sopenharmony_ci	return 0;
13248c2ecf20Sopenharmony_ci}
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_spdif_mask =
13278c2ecf20Sopenharmony_ci{
13288c2ecf20Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
13298c2ecf20Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
13308c2ecf20Sopenharmony_ci	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
13318c2ecf20Sopenharmony_ci	.info =		snd_ymfpci_spdif_mask_info,
13328c2ecf20Sopenharmony_ci	.get =		snd_ymfpci_spdif_mask_get,
13338c2ecf20Sopenharmony_ci};
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_cistatic int snd_ymfpci_spdif_stream_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13368c2ecf20Sopenharmony_ci{
13378c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
13388c2ecf20Sopenharmony_ci	uinfo->count = 1;
13398c2ecf20Sopenharmony_ci	return 0;
13408c2ecf20Sopenharmony_ci}
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_cistatic int snd_ymfpci_spdif_stream_get(struct snd_kcontrol *kcontrol,
13438c2ecf20Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
13448c2ecf20Sopenharmony_ci{
13458c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
13488c2ecf20Sopenharmony_ci	ucontrol->value.iec958.status[0] = (chip->spdif_pcm_bits >> 0) & 0xff;
13498c2ecf20Sopenharmony_ci	ucontrol->value.iec958.status[1] = (chip->spdif_pcm_bits >> 8) & 0xff;
13508c2ecf20Sopenharmony_ci	ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000;
13518c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
13528c2ecf20Sopenharmony_ci	return 0;
13538c2ecf20Sopenharmony_ci}
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_cistatic int snd_ymfpci_spdif_stream_put(struct snd_kcontrol *kcontrol,
13568c2ecf20Sopenharmony_ci					struct snd_ctl_elem_value *ucontrol)
13578c2ecf20Sopenharmony_ci{
13588c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
13598c2ecf20Sopenharmony_ci	unsigned int val;
13608c2ecf20Sopenharmony_ci	int change;
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci	val = ((ucontrol->value.iec958.status[0] & 0x3e) << 0) |
13638c2ecf20Sopenharmony_ci	      (ucontrol->value.iec958.status[1] << 8);
13648c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
13658c2ecf20Sopenharmony_ci	change = chip->spdif_pcm_bits != val;
13668c2ecf20Sopenharmony_ci	chip->spdif_pcm_bits = val;
13678c2ecf20Sopenharmony_ci	if ((snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) & 2))
13688c2ecf20Sopenharmony_ci		snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_pcm_bits);
13698c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
13708c2ecf20Sopenharmony_ci	return change;
13718c2ecf20Sopenharmony_ci}
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_spdif_stream =
13748c2ecf20Sopenharmony_ci{
13758c2ecf20Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
13768c2ecf20Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
13778c2ecf20Sopenharmony_ci	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
13788c2ecf20Sopenharmony_ci	.info =		snd_ymfpci_spdif_stream_info,
13798c2ecf20Sopenharmony_ci	.get =		snd_ymfpci_spdif_stream_get,
13808c2ecf20Sopenharmony_ci	.put =		snd_ymfpci_spdif_stream_put
13818c2ecf20Sopenharmony_ci};
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_cistatic int snd_ymfpci_drec_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info)
13848c2ecf20Sopenharmony_ci{
13858c2ecf20Sopenharmony_ci	static const char *const texts[3] = {"AC'97", "IEC958", "ZV Port"};
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci	return snd_ctl_enum_info(info, 1, 3, texts);
13888c2ecf20Sopenharmony_ci}
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_cistatic int snd_ymfpci_drec_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value)
13918c2ecf20Sopenharmony_ci{
13928c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
13938c2ecf20Sopenharmony_ci	u16 reg;
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
13968c2ecf20Sopenharmony_ci	reg = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL);
13978c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
13988c2ecf20Sopenharmony_ci	if (!(reg & 0x100))
13998c2ecf20Sopenharmony_ci		value->value.enumerated.item[0] = 0;
14008c2ecf20Sopenharmony_ci	else
14018c2ecf20Sopenharmony_ci		value->value.enumerated.item[0] = 1 + ((reg & 0x200) != 0);
14028c2ecf20Sopenharmony_ci	return 0;
14038c2ecf20Sopenharmony_ci}
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_cistatic int snd_ymfpci_drec_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value)
14068c2ecf20Sopenharmony_ci{
14078c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
14088c2ecf20Sopenharmony_ci	u16 reg, old_reg;
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
14118c2ecf20Sopenharmony_ci	old_reg = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL);
14128c2ecf20Sopenharmony_ci	if (value->value.enumerated.item[0] == 0)
14138c2ecf20Sopenharmony_ci		reg = old_reg & ~0x100;
14148c2ecf20Sopenharmony_ci	else
14158c2ecf20Sopenharmony_ci		reg = (old_reg & ~0x300) | 0x100 | ((value->value.enumerated.item[0] == 2) << 9);
14168c2ecf20Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, reg);
14178c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
14188c2ecf20Sopenharmony_ci	return reg != old_reg;
14198c2ecf20Sopenharmony_ci}
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_drec_source = {
14228c2ecf20Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
14238c2ecf20Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
14248c2ecf20Sopenharmony_ci	.name =		"Direct Recording Source",
14258c2ecf20Sopenharmony_ci	.info =		snd_ymfpci_drec_source_info,
14268c2ecf20Sopenharmony_ci	.get =		snd_ymfpci_drec_source_get,
14278c2ecf20Sopenharmony_ci	.put =		snd_ymfpci_drec_source_put
14288c2ecf20Sopenharmony_ci};
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci/*
14318c2ecf20Sopenharmony_ci *  Mixer controls
14328c2ecf20Sopenharmony_ci */
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci#define YMFPCI_SINGLE(xname, xindex, reg, shift) \
14358c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
14368c2ecf20Sopenharmony_ci  .info = snd_ymfpci_info_single, \
14378c2ecf20Sopenharmony_ci  .get = snd_ymfpci_get_single, .put = snd_ymfpci_put_single, \
14388c2ecf20Sopenharmony_ci  .private_value = ((reg) | ((shift) << 16)) }
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci#define snd_ymfpci_info_single		snd_ctl_boolean_mono_info
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_cistatic int snd_ymfpci_get_single(struct snd_kcontrol *kcontrol,
14438c2ecf20Sopenharmony_ci				 struct snd_ctl_elem_value *ucontrol)
14448c2ecf20Sopenharmony_ci{
14458c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
14468c2ecf20Sopenharmony_ci	int reg = kcontrol->private_value & 0xffff;
14478c2ecf20Sopenharmony_ci	unsigned int shift = (kcontrol->private_value >> 16) & 0xff;
14488c2ecf20Sopenharmony_ci	unsigned int mask = 1;
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci	switch (reg) {
14518c2ecf20Sopenharmony_ci	case YDSXGR_SPDIFOUTCTRL: break;
14528c2ecf20Sopenharmony_ci	case YDSXGR_SPDIFINCTRL: break;
14538c2ecf20Sopenharmony_ci	default: return -EINVAL;
14548c2ecf20Sopenharmony_ci	}
14558c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] =
14568c2ecf20Sopenharmony_ci		(snd_ymfpci_readl(chip, reg) >> shift) & mask;
14578c2ecf20Sopenharmony_ci	return 0;
14588c2ecf20Sopenharmony_ci}
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_cistatic int snd_ymfpci_put_single(struct snd_kcontrol *kcontrol,
14618c2ecf20Sopenharmony_ci				 struct snd_ctl_elem_value *ucontrol)
14628c2ecf20Sopenharmony_ci{
14638c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
14648c2ecf20Sopenharmony_ci	int reg = kcontrol->private_value & 0xffff;
14658c2ecf20Sopenharmony_ci	unsigned int shift = (kcontrol->private_value >> 16) & 0xff;
14668c2ecf20Sopenharmony_ci 	unsigned int mask = 1;
14678c2ecf20Sopenharmony_ci	int change;
14688c2ecf20Sopenharmony_ci	unsigned int val, oval;
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	switch (reg) {
14718c2ecf20Sopenharmony_ci	case YDSXGR_SPDIFOUTCTRL: break;
14728c2ecf20Sopenharmony_ci	case YDSXGR_SPDIFINCTRL: break;
14738c2ecf20Sopenharmony_ci	default: return -EINVAL;
14748c2ecf20Sopenharmony_ci	}
14758c2ecf20Sopenharmony_ci	val = (ucontrol->value.integer.value[0] & mask);
14768c2ecf20Sopenharmony_ci	val <<= shift;
14778c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
14788c2ecf20Sopenharmony_ci	oval = snd_ymfpci_readl(chip, reg);
14798c2ecf20Sopenharmony_ci	val = (oval & ~(mask << shift)) | val;
14808c2ecf20Sopenharmony_ci	change = val != oval;
14818c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, reg, val);
14828c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
14838c2ecf20Sopenharmony_ci	return change;
14848c2ecf20Sopenharmony_ci}
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_LINEAR(db_scale_native, TLV_DB_GAIN_MUTE, 0);
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci#define YMFPCI_DOUBLE(xname, xindex, reg) \
14898c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
14908c2ecf20Sopenharmony_ci  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
14918c2ecf20Sopenharmony_ci  .info = snd_ymfpci_info_double, \
14928c2ecf20Sopenharmony_ci  .get = snd_ymfpci_get_double, .put = snd_ymfpci_put_double, \
14938c2ecf20Sopenharmony_ci  .private_value = reg, \
14948c2ecf20Sopenharmony_ci  .tlv = { .p = db_scale_native } }
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_cistatic int snd_ymfpci_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14978c2ecf20Sopenharmony_ci{
14988c2ecf20Sopenharmony_ci	unsigned int reg = kcontrol->private_value;
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_ci	if (reg < 0x80 || reg >= 0xc0)
15018c2ecf20Sopenharmony_ci		return -EINVAL;
15028c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
15038c2ecf20Sopenharmony_ci	uinfo->count = 2;
15048c2ecf20Sopenharmony_ci	uinfo->value.integer.min = 0;
15058c2ecf20Sopenharmony_ci	uinfo->value.integer.max = 16383;
15068c2ecf20Sopenharmony_ci	return 0;
15078c2ecf20Sopenharmony_ci}
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_cistatic int snd_ymfpci_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
15108c2ecf20Sopenharmony_ci{
15118c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
15128c2ecf20Sopenharmony_ci	unsigned int reg = kcontrol->private_value;
15138c2ecf20Sopenharmony_ci	unsigned int shift_left = 0, shift_right = 16, mask = 16383;
15148c2ecf20Sopenharmony_ci	unsigned int val;
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	if (reg < 0x80 || reg >= 0xc0)
15178c2ecf20Sopenharmony_ci		return -EINVAL;
15188c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
15198c2ecf20Sopenharmony_ci	val = snd_ymfpci_readl(chip, reg);
15208c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
15218c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = (val >> shift_left) & mask;
15228c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[1] = (val >> shift_right) & mask;
15238c2ecf20Sopenharmony_ci	return 0;
15248c2ecf20Sopenharmony_ci}
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_cistatic int snd_ymfpci_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
15278c2ecf20Sopenharmony_ci{
15288c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
15298c2ecf20Sopenharmony_ci	unsigned int reg = kcontrol->private_value;
15308c2ecf20Sopenharmony_ci	unsigned int shift_left = 0, shift_right = 16, mask = 16383;
15318c2ecf20Sopenharmony_ci	int change;
15328c2ecf20Sopenharmony_ci	unsigned int val1, val2, oval;
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	if (reg < 0x80 || reg >= 0xc0)
15358c2ecf20Sopenharmony_ci		return -EINVAL;
15368c2ecf20Sopenharmony_ci	val1 = ucontrol->value.integer.value[0] & mask;
15378c2ecf20Sopenharmony_ci	val2 = ucontrol->value.integer.value[1] & mask;
15388c2ecf20Sopenharmony_ci	val1 <<= shift_left;
15398c2ecf20Sopenharmony_ci	val2 <<= shift_right;
15408c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
15418c2ecf20Sopenharmony_ci	oval = snd_ymfpci_readl(chip, reg);
15428c2ecf20Sopenharmony_ci	val1 = (oval & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2;
15438c2ecf20Sopenharmony_ci	change = val1 != oval;
15448c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, reg, val1);
15458c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
15468c2ecf20Sopenharmony_ci	return change;
15478c2ecf20Sopenharmony_ci}
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_cistatic int snd_ymfpci_put_nativedacvol(struct snd_kcontrol *kcontrol,
15508c2ecf20Sopenharmony_ci				       struct snd_ctl_elem_value *ucontrol)
15518c2ecf20Sopenharmony_ci{
15528c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
15538c2ecf20Sopenharmony_ci	unsigned int reg = YDSXGR_NATIVEDACOUTVOL;
15548c2ecf20Sopenharmony_ci	unsigned int reg2 = YDSXGR_BUF441OUTVOL;
15558c2ecf20Sopenharmony_ci	int change;
15568c2ecf20Sopenharmony_ci	unsigned int value, oval;
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci	value = ucontrol->value.integer.value[0] & 0x3fff;
15598c2ecf20Sopenharmony_ci	value |= (ucontrol->value.integer.value[1] & 0x3fff) << 16;
15608c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
15618c2ecf20Sopenharmony_ci	oval = snd_ymfpci_readl(chip, reg);
15628c2ecf20Sopenharmony_ci	change = value != oval;
15638c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, reg, value);
15648c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, reg2, value);
15658c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
15668c2ecf20Sopenharmony_ci	return change;
15678c2ecf20Sopenharmony_ci}
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci/*
15708c2ecf20Sopenharmony_ci * 4ch duplication
15718c2ecf20Sopenharmony_ci */
15728c2ecf20Sopenharmony_ci#define snd_ymfpci_info_dup4ch		snd_ctl_boolean_mono_info
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_cistatic int snd_ymfpci_get_dup4ch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
15758c2ecf20Sopenharmony_ci{
15768c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
15778c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = chip->mode_dup4ch;
15788c2ecf20Sopenharmony_ci	return 0;
15798c2ecf20Sopenharmony_ci}
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_cistatic int snd_ymfpci_put_dup4ch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
15828c2ecf20Sopenharmony_ci{
15838c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
15848c2ecf20Sopenharmony_ci	int change;
15858c2ecf20Sopenharmony_ci	change = (ucontrol->value.integer.value[0] != chip->mode_dup4ch);
15868c2ecf20Sopenharmony_ci	if (change)
15878c2ecf20Sopenharmony_ci		chip->mode_dup4ch = !!ucontrol->value.integer.value[0];
15888c2ecf20Sopenharmony_ci	return change;
15898c2ecf20Sopenharmony_ci}
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_dup4ch = {
15928c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15938c2ecf20Sopenharmony_ci	.name = "4ch Duplication",
15948c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
15958c2ecf20Sopenharmony_ci	.info = snd_ymfpci_info_dup4ch,
15968c2ecf20Sopenharmony_ci	.get = snd_ymfpci_get_dup4ch,
15978c2ecf20Sopenharmony_ci	.put = snd_ymfpci_put_dup4ch,
15988c2ecf20Sopenharmony_ci};
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_controls[] = {
16018c2ecf20Sopenharmony_ci{
16028c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
16038c2ecf20Sopenharmony_ci	.name = "Wave Playback Volume",
16048c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
16058c2ecf20Sopenharmony_ci		  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
16068c2ecf20Sopenharmony_ci	.info = snd_ymfpci_info_double,
16078c2ecf20Sopenharmony_ci	.get = snd_ymfpci_get_double,
16088c2ecf20Sopenharmony_ci	.put = snd_ymfpci_put_nativedacvol,
16098c2ecf20Sopenharmony_ci	.private_value = YDSXGR_NATIVEDACOUTVOL,
16108c2ecf20Sopenharmony_ci	.tlv = { .p = db_scale_native },
16118c2ecf20Sopenharmony_ci},
16128c2ecf20Sopenharmony_ciYMFPCI_DOUBLE("Wave Capture Volume", 0, YDSXGR_NATIVEDACLOOPVOL),
16138c2ecf20Sopenharmony_ciYMFPCI_DOUBLE("Digital Capture Volume", 0, YDSXGR_NATIVEDACINVOL),
16148c2ecf20Sopenharmony_ciYMFPCI_DOUBLE("Digital Capture Volume", 1, YDSXGR_NATIVEADCINVOL),
16158c2ecf20Sopenharmony_ciYMFPCI_DOUBLE("ADC Playback Volume", 0, YDSXGR_PRIADCOUTVOL),
16168c2ecf20Sopenharmony_ciYMFPCI_DOUBLE("ADC Capture Volume", 0, YDSXGR_PRIADCLOOPVOL),
16178c2ecf20Sopenharmony_ciYMFPCI_DOUBLE("ADC Playback Volume", 1, YDSXGR_SECADCOUTVOL),
16188c2ecf20Sopenharmony_ciYMFPCI_DOUBLE("ADC Capture Volume", 1, YDSXGR_SECADCLOOPVOL),
16198c2ecf20Sopenharmony_ciYMFPCI_DOUBLE("FM Legacy Playback Volume", 0, YDSXGR_LEGACYOUTVOL),
16208c2ecf20Sopenharmony_ciYMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ", PLAYBACK,VOLUME), 0, YDSXGR_ZVOUTVOL),
16218c2ecf20Sopenharmony_ciYMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("", CAPTURE,VOLUME), 0, YDSXGR_ZVLOOPVOL),
16228c2ecf20Sopenharmony_ciYMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ",PLAYBACK,VOLUME), 1, YDSXGR_SPDIFOUTVOL),
16238c2ecf20Sopenharmony_ciYMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,VOLUME), 1, YDSXGR_SPDIFLOOPVOL),
16248c2ecf20Sopenharmony_ciYMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), 0, YDSXGR_SPDIFOUTCTRL, 0),
16258c2ecf20Sopenharmony_ciYMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0, YDSXGR_SPDIFINCTRL, 0),
16268c2ecf20Sopenharmony_ciYMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("Loop",NONE,NONE), 0, YDSXGR_SPDIFINCTRL, 4),
16278c2ecf20Sopenharmony_ci};
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci/*
16318c2ecf20Sopenharmony_ci * GPIO
16328c2ecf20Sopenharmony_ci */
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_cistatic int snd_ymfpci_get_gpio_out(struct snd_ymfpci *chip, int pin)
16358c2ecf20Sopenharmony_ci{
16368c2ecf20Sopenharmony_ci	u16 reg, mode;
16378c2ecf20Sopenharmony_ci	unsigned long flags;
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
16408c2ecf20Sopenharmony_ci	reg = snd_ymfpci_readw(chip, YDSXGR_GPIOFUNCENABLE);
16418c2ecf20Sopenharmony_ci	reg &= ~(1 << (pin + 8));
16428c2ecf20Sopenharmony_ci	reg |= (1 << pin);
16438c2ecf20Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg);
16448c2ecf20Sopenharmony_ci	/* set the level mode for input line */
16458c2ecf20Sopenharmony_ci	mode = snd_ymfpci_readw(chip, YDSXGR_GPIOTYPECONFIG);
16468c2ecf20Sopenharmony_ci	mode &= ~(3 << (pin * 2));
16478c2ecf20Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_GPIOTYPECONFIG, mode);
16488c2ecf20Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg | (1 << (pin + 8)));
16498c2ecf20Sopenharmony_ci	mode = snd_ymfpci_readw(chip, YDSXGR_GPIOINSTATUS);
16508c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
16518c2ecf20Sopenharmony_ci	return (mode >> pin) & 1;
16528c2ecf20Sopenharmony_ci}
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_cistatic int snd_ymfpci_set_gpio_out(struct snd_ymfpci *chip, int pin, int enable)
16558c2ecf20Sopenharmony_ci{
16568c2ecf20Sopenharmony_ci	u16 reg;
16578c2ecf20Sopenharmony_ci	unsigned long flags;
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
16608c2ecf20Sopenharmony_ci	reg = snd_ymfpci_readw(chip, YDSXGR_GPIOFUNCENABLE);
16618c2ecf20Sopenharmony_ci	reg &= ~(1 << pin);
16628c2ecf20Sopenharmony_ci	reg &= ~(1 << (pin + 8));
16638c2ecf20Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg);
16648c2ecf20Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_GPIOOUTCTRL, enable << pin);
16658c2ecf20Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg | (1 << (pin + 8)));
16668c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci	return 0;
16698c2ecf20Sopenharmony_ci}
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci#define snd_ymfpci_gpio_sw_info		snd_ctl_boolean_mono_info
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_cistatic int snd_ymfpci_gpio_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
16748c2ecf20Sopenharmony_ci{
16758c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
16768c2ecf20Sopenharmony_ci	int pin = (int)kcontrol->private_value;
16778c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = snd_ymfpci_get_gpio_out(chip, pin);
16788c2ecf20Sopenharmony_ci	return 0;
16798c2ecf20Sopenharmony_ci}
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_cistatic int snd_ymfpci_gpio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
16828c2ecf20Sopenharmony_ci{
16838c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
16848c2ecf20Sopenharmony_ci	int pin = (int)kcontrol->private_value;
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	if (snd_ymfpci_get_gpio_out(chip, pin) != ucontrol->value.integer.value[0]) {
16878c2ecf20Sopenharmony_ci		snd_ymfpci_set_gpio_out(chip, pin, !!ucontrol->value.integer.value[0]);
16888c2ecf20Sopenharmony_ci		ucontrol->value.integer.value[0] = snd_ymfpci_get_gpio_out(chip, pin);
16898c2ecf20Sopenharmony_ci		return 1;
16908c2ecf20Sopenharmony_ci	}
16918c2ecf20Sopenharmony_ci	return 0;
16928c2ecf20Sopenharmony_ci}
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_rear_shared = {
16958c2ecf20Sopenharmony_ci	.name = "Shared Rear/Line-In Switch",
16968c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
16978c2ecf20Sopenharmony_ci	.info = snd_ymfpci_gpio_sw_info,
16988c2ecf20Sopenharmony_ci	.get = snd_ymfpci_gpio_sw_get,
16998c2ecf20Sopenharmony_ci	.put = snd_ymfpci_gpio_sw_put,
17008c2ecf20Sopenharmony_ci	.private_value = 2,
17018c2ecf20Sopenharmony_ci};
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci/*
17048c2ecf20Sopenharmony_ci * PCM voice volume
17058c2ecf20Sopenharmony_ci */
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_cistatic int snd_ymfpci_pcm_vol_info(struct snd_kcontrol *kcontrol,
17088c2ecf20Sopenharmony_ci				   struct snd_ctl_elem_info *uinfo)
17098c2ecf20Sopenharmony_ci{
17108c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
17118c2ecf20Sopenharmony_ci	uinfo->count = 2;
17128c2ecf20Sopenharmony_ci	uinfo->value.integer.min = 0;
17138c2ecf20Sopenharmony_ci	uinfo->value.integer.max = 0x8000;
17148c2ecf20Sopenharmony_ci	return 0;
17158c2ecf20Sopenharmony_ci}
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_cistatic int snd_ymfpci_pcm_vol_get(struct snd_kcontrol *kcontrol,
17188c2ecf20Sopenharmony_ci				  struct snd_ctl_elem_value *ucontrol)
17198c2ecf20Sopenharmony_ci{
17208c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
17218c2ecf20Sopenharmony_ci	unsigned int subs = kcontrol->id.subdevice;
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = chip->pcm_mixer[subs].left;
17248c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[1] = chip->pcm_mixer[subs].right;
17258c2ecf20Sopenharmony_ci	return 0;
17268c2ecf20Sopenharmony_ci}
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_cistatic int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol,
17298c2ecf20Sopenharmony_ci				  struct snd_ctl_elem_value *ucontrol)
17308c2ecf20Sopenharmony_ci{
17318c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
17328c2ecf20Sopenharmony_ci	unsigned int subs = kcontrol->id.subdevice;
17338c2ecf20Sopenharmony_ci	struct snd_pcm_substream *substream;
17348c2ecf20Sopenharmony_ci	unsigned long flags;
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	if (ucontrol->value.integer.value[0] != chip->pcm_mixer[subs].left ||
17378c2ecf20Sopenharmony_ci	    ucontrol->value.integer.value[1] != chip->pcm_mixer[subs].right) {
17388c2ecf20Sopenharmony_ci		chip->pcm_mixer[subs].left = ucontrol->value.integer.value[0];
17398c2ecf20Sopenharmony_ci		chip->pcm_mixer[subs].right = ucontrol->value.integer.value[1];
17408c2ecf20Sopenharmony_ci		if (chip->pcm_mixer[subs].left > 0x8000)
17418c2ecf20Sopenharmony_ci			chip->pcm_mixer[subs].left = 0x8000;
17428c2ecf20Sopenharmony_ci		if (chip->pcm_mixer[subs].right > 0x8000)
17438c2ecf20Sopenharmony_ci			chip->pcm_mixer[subs].right = 0x8000;
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci		substream = (struct snd_pcm_substream *)kcontrol->private_value;
17468c2ecf20Sopenharmony_ci		spin_lock_irqsave(&chip->voice_lock, flags);
17478c2ecf20Sopenharmony_ci		if (substream->runtime && substream->runtime->private_data) {
17488c2ecf20Sopenharmony_ci			struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data;
17498c2ecf20Sopenharmony_ci			if (!ypcm->use_441_slot)
17508c2ecf20Sopenharmony_ci				ypcm->update_pcm_vol = 2;
17518c2ecf20Sopenharmony_ci		}
17528c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&chip->voice_lock, flags);
17538c2ecf20Sopenharmony_ci		return 1;
17548c2ecf20Sopenharmony_ci	}
17558c2ecf20Sopenharmony_ci	return 0;
17568c2ecf20Sopenharmony_ci}
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_pcm_volume = {
17598c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_PCM,
17608c2ecf20Sopenharmony_ci	.name = "PCM Playback Volume",
17618c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
17628c2ecf20Sopenharmony_ci		SNDRV_CTL_ELEM_ACCESS_INACTIVE,
17638c2ecf20Sopenharmony_ci	.info = snd_ymfpci_pcm_vol_info,
17648c2ecf20Sopenharmony_ci	.get = snd_ymfpci_pcm_vol_get,
17658c2ecf20Sopenharmony_ci	.put = snd_ymfpci_pcm_vol_put,
17668c2ecf20Sopenharmony_ci};
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_ci/*
17708c2ecf20Sopenharmony_ci *  Mixer routines
17718c2ecf20Sopenharmony_ci */
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_cistatic void snd_ymfpci_mixer_free_ac97_bus(struct snd_ac97_bus *bus)
17748c2ecf20Sopenharmony_ci{
17758c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = bus->private_data;
17768c2ecf20Sopenharmony_ci	chip->ac97_bus = NULL;
17778c2ecf20Sopenharmony_ci}
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_cistatic void snd_ymfpci_mixer_free_ac97(struct snd_ac97 *ac97)
17808c2ecf20Sopenharmony_ci{
17818c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = ac97->private_data;
17828c2ecf20Sopenharmony_ci	chip->ac97 = NULL;
17838c2ecf20Sopenharmony_ci}
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ciint snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch)
17868c2ecf20Sopenharmony_ci{
17878c2ecf20Sopenharmony_ci	struct snd_ac97_template ac97;
17888c2ecf20Sopenharmony_ci	struct snd_kcontrol *kctl;
17898c2ecf20Sopenharmony_ci	struct snd_pcm_substream *substream;
17908c2ecf20Sopenharmony_ci	unsigned int idx;
17918c2ecf20Sopenharmony_ci	int err;
17928c2ecf20Sopenharmony_ci	static const struct snd_ac97_bus_ops ops = {
17938c2ecf20Sopenharmony_ci		.write = snd_ymfpci_codec_write,
17948c2ecf20Sopenharmony_ci		.read = snd_ymfpci_codec_read,
17958c2ecf20Sopenharmony_ci	};
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci	err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus);
17988c2ecf20Sopenharmony_ci	if (err < 0)
17998c2ecf20Sopenharmony_ci		return err;
18008c2ecf20Sopenharmony_ci	chip->ac97_bus->private_free = snd_ymfpci_mixer_free_ac97_bus;
18018c2ecf20Sopenharmony_ci	chip->ac97_bus->no_vra = 1; /* YMFPCI doesn't need VRA */
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci	memset(&ac97, 0, sizeof(ac97));
18048c2ecf20Sopenharmony_ci	ac97.private_data = chip;
18058c2ecf20Sopenharmony_ci	ac97.private_free = snd_ymfpci_mixer_free_ac97;
18068c2ecf20Sopenharmony_ci	err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97);
18078c2ecf20Sopenharmony_ci	if (err < 0)
18088c2ecf20Sopenharmony_ci		return err;
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci	/* to be sure */
18118c2ecf20Sopenharmony_ci	snd_ac97_update_bits(chip->ac97, AC97_EXTENDED_STATUS,
18128c2ecf20Sopenharmony_ci			     AC97_EA_VRA|AC97_EA_VRM, 0);
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_ci	for (idx = 0; idx < ARRAY_SIZE(snd_ymfpci_controls); idx++) {
18158c2ecf20Sopenharmony_ci		err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_controls[idx], chip));
18168c2ecf20Sopenharmony_ci		if (err < 0)
18178c2ecf20Sopenharmony_ci			return err;
18188c2ecf20Sopenharmony_ci	}
18198c2ecf20Sopenharmony_ci	if (chip->ac97->ext_id & AC97_EI_SDAC) {
18208c2ecf20Sopenharmony_ci		kctl = snd_ctl_new1(&snd_ymfpci_dup4ch, chip);
18218c2ecf20Sopenharmony_ci		err = snd_ctl_add(chip->card, kctl);
18228c2ecf20Sopenharmony_ci		if (err < 0)
18238c2ecf20Sopenharmony_ci			return err;
18248c2ecf20Sopenharmony_ci	}
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_ci	/* add S/PDIF control */
18278c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!chip->pcm_spdif))
18288c2ecf20Sopenharmony_ci		return -ENXIO;
18298c2ecf20Sopenharmony_ci	kctl = snd_ctl_new1(&snd_ymfpci_spdif_default, chip);
18308c2ecf20Sopenharmony_ci	err = snd_ctl_add(chip->card, kctl);
18318c2ecf20Sopenharmony_ci	if (err < 0)
18328c2ecf20Sopenharmony_ci		return err;
18338c2ecf20Sopenharmony_ci	kctl->id.device = chip->pcm_spdif->device;
18348c2ecf20Sopenharmony_ci	kctl = snd_ctl_new1(&snd_ymfpci_spdif_mask, chip);
18358c2ecf20Sopenharmony_ci	err = snd_ctl_add(chip->card, kctl);
18368c2ecf20Sopenharmony_ci	if (err < 0)
18378c2ecf20Sopenharmony_ci		return err;
18388c2ecf20Sopenharmony_ci	kctl->id.device = chip->pcm_spdif->device;
18398c2ecf20Sopenharmony_ci	kctl = snd_ctl_new1(&snd_ymfpci_spdif_stream, chip);
18408c2ecf20Sopenharmony_ci	err = snd_ctl_add(chip->card, kctl);
18418c2ecf20Sopenharmony_ci	if (err < 0)
18428c2ecf20Sopenharmony_ci		return err;
18438c2ecf20Sopenharmony_ci	kctl->id.device = chip->pcm_spdif->device;
18448c2ecf20Sopenharmony_ci	chip->spdif_pcm_ctl = kctl;
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci	/* direct recording source */
18478c2ecf20Sopenharmony_ci	if (chip->device_id == PCI_DEVICE_ID_YAMAHA_754) {
18488c2ecf20Sopenharmony_ci		kctl = snd_ctl_new1(&snd_ymfpci_drec_source, chip);
18498c2ecf20Sopenharmony_ci		err = snd_ctl_add(chip->card, kctl);
18508c2ecf20Sopenharmony_ci		if (err < 0)
18518c2ecf20Sopenharmony_ci			return err;
18528c2ecf20Sopenharmony_ci	}
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci	/*
18558c2ecf20Sopenharmony_ci	 * shared rear/line-in
18568c2ecf20Sopenharmony_ci	 */
18578c2ecf20Sopenharmony_ci	if (rear_switch) {
18588c2ecf20Sopenharmony_ci		err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_rear_shared, chip));
18598c2ecf20Sopenharmony_ci		if (err < 0)
18608c2ecf20Sopenharmony_ci			return err;
18618c2ecf20Sopenharmony_ci	}
18628c2ecf20Sopenharmony_ci
18638c2ecf20Sopenharmony_ci	/* per-voice volume */
18648c2ecf20Sopenharmony_ci	substream = chip->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
18658c2ecf20Sopenharmony_ci	for (idx = 0; idx < 32; ++idx) {
18668c2ecf20Sopenharmony_ci		kctl = snd_ctl_new1(&snd_ymfpci_pcm_volume, chip);
18678c2ecf20Sopenharmony_ci		if (!kctl)
18688c2ecf20Sopenharmony_ci			return -ENOMEM;
18698c2ecf20Sopenharmony_ci		kctl->id.device = chip->pcm->device;
18708c2ecf20Sopenharmony_ci		kctl->id.subdevice = idx;
18718c2ecf20Sopenharmony_ci		kctl->private_value = (unsigned long)substream;
18728c2ecf20Sopenharmony_ci		err = snd_ctl_add(chip->card, kctl);
18738c2ecf20Sopenharmony_ci		if (err < 0)
18748c2ecf20Sopenharmony_ci			return err;
18758c2ecf20Sopenharmony_ci		chip->pcm_mixer[idx].left = 0x8000;
18768c2ecf20Sopenharmony_ci		chip->pcm_mixer[idx].right = 0x8000;
18778c2ecf20Sopenharmony_ci		chip->pcm_mixer[idx].ctl = kctl;
18788c2ecf20Sopenharmony_ci		substream = substream->next;
18798c2ecf20Sopenharmony_ci	}
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ci	return 0;
18828c2ecf20Sopenharmony_ci}
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci/*
18868c2ecf20Sopenharmony_ci * timer
18878c2ecf20Sopenharmony_ci */
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_cistatic int snd_ymfpci_timer_start(struct snd_timer *timer)
18908c2ecf20Sopenharmony_ci{
18918c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip;
18928c2ecf20Sopenharmony_ci	unsigned long flags;
18938c2ecf20Sopenharmony_ci	unsigned int count;
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_ci	chip = snd_timer_chip(timer);
18968c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
18978c2ecf20Sopenharmony_ci	if (timer->sticks > 1) {
18988c2ecf20Sopenharmony_ci		chip->timer_ticks = timer->sticks;
18998c2ecf20Sopenharmony_ci		count = timer->sticks - 1;
19008c2ecf20Sopenharmony_ci	} else {
19018c2ecf20Sopenharmony_ci		/*
19028c2ecf20Sopenharmony_ci		 * Divisor 1 is not allowed; fake it by using divisor 2 and
19038c2ecf20Sopenharmony_ci		 * counting two ticks for each interrupt.
19048c2ecf20Sopenharmony_ci		 */
19058c2ecf20Sopenharmony_ci		chip->timer_ticks = 2;
19068c2ecf20Sopenharmony_ci		count = 2 - 1;
19078c2ecf20Sopenharmony_ci	}
19088c2ecf20Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_TIMERCOUNT, count);
19098c2ecf20Sopenharmony_ci	snd_ymfpci_writeb(chip, YDSXGR_TIMERCTRL, 0x03);
19108c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
19118c2ecf20Sopenharmony_ci	return 0;
19128c2ecf20Sopenharmony_ci}
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_cistatic int snd_ymfpci_timer_stop(struct snd_timer *timer)
19158c2ecf20Sopenharmony_ci{
19168c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip;
19178c2ecf20Sopenharmony_ci	unsigned long flags;
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci	chip = snd_timer_chip(timer);
19208c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
19218c2ecf20Sopenharmony_ci	snd_ymfpci_writeb(chip, YDSXGR_TIMERCTRL, 0x00);
19228c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
19238c2ecf20Sopenharmony_ci	return 0;
19248c2ecf20Sopenharmony_ci}
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_cistatic int snd_ymfpci_timer_precise_resolution(struct snd_timer *timer,
19278c2ecf20Sopenharmony_ci					       unsigned long *num, unsigned long *den)
19288c2ecf20Sopenharmony_ci{
19298c2ecf20Sopenharmony_ci	*num = 1;
19308c2ecf20Sopenharmony_ci	*den = 96000;
19318c2ecf20Sopenharmony_ci	return 0;
19328c2ecf20Sopenharmony_ci}
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_cistatic const struct snd_timer_hardware snd_ymfpci_timer_hw = {
19358c2ecf20Sopenharmony_ci	.flags = SNDRV_TIMER_HW_AUTO,
19368c2ecf20Sopenharmony_ci	.resolution = 10417, /* 1 / 96 kHz = 10.41666...us */
19378c2ecf20Sopenharmony_ci	.ticks = 0x10000,
19388c2ecf20Sopenharmony_ci	.start = snd_ymfpci_timer_start,
19398c2ecf20Sopenharmony_ci	.stop = snd_ymfpci_timer_stop,
19408c2ecf20Sopenharmony_ci	.precise_resolution = snd_ymfpci_timer_precise_resolution,
19418c2ecf20Sopenharmony_ci};
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_ciint snd_ymfpci_timer(struct snd_ymfpci *chip, int device)
19448c2ecf20Sopenharmony_ci{
19458c2ecf20Sopenharmony_ci	struct snd_timer *timer = NULL;
19468c2ecf20Sopenharmony_ci	struct snd_timer_id tid;
19478c2ecf20Sopenharmony_ci	int err;
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci	tid.dev_class = SNDRV_TIMER_CLASS_CARD;
19508c2ecf20Sopenharmony_ci	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
19518c2ecf20Sopenharmony_ci	tid.card = chip->card->number;
19528c2ecf20Sopenharmony_ci	tid.device = device;
19538c2ecf20Sopenharmony_ci	tid.subdevice = 0;
19548c2ecf20Sopenharmony_ci	err = snd_timer_new(chip->card, "YMFPCI", &tid, &timer);
19558c2ecf20Sopenharmony_ci	if (err >= 0) {
19568c2ecf20Sopenharmony_ci		strcpy(timer->name, "YMFPCI timer");
19578c2ecf20Sopenharmony_ci		timer->private_data = chip;
19588c2ecf20Sopenharmony_ci		timer->hw = snd_ymfpci_timer_hw;
19598c2ecf20Sopenharmony_ci	}
19608c2ecf20Sopenharmony_ci	chip->timer = timer;
19618c2ecf20Sopenharmony_ci	return err;
19628c2ecf20Sopenharmony_ci}
19638c2ecf20Sopenharmony_ci
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci/*
19668c2ecf20Sopenharmony_ci *  proc interface
19678c2ecf20Sopenharmony_ci */
19688c2ecf20Sopenharmony_ci
19698c2ecf20Sopenharmony_cistatic void snd_ymfpci_proc_read(struct snd_info_entry *entry,
19708c2ecf20Sopenharmony_ci				 struct snd_info_buffer *buffer)
19718c2ecf20Sopenharmony_ci{
19728c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = entry->private_data;
19738c2ecf20Sopenharmony_ci	int i;
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "YMFPCI\n\n");
19768c2ecf20Sopenharmony_ci	for (i = 0; i <= YDSXGR_WORKBASE; i += 4)
19778c2ecf20Sopenharmony_ci		snd_iprintf(buffer, "%04x: %04x\n", i, snd_ymfpci_readl(chip, i));
19788c2ecf20Sopenharmony_ci}
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_cistatic int snd_ymfpci_proc_init(struct snd_card *card, struct snd_ymfpci *chip)
19818c2ecf20Sopenharmony_ci{
19828c2ecf20Sopenharmony_ci	return snd_card_ro_proc_new(card, "ymfpci", chip, snd_ymfpci_proc_read);
19838c2ecf20Sopenharmony_ci}
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci/*
19868c2ecf20Sopenharmony_ci *  initialization routines
19878c2ecf20Sopenharmony_ci */
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_cistatic void snd_ymfpci_aclink_reset(struct pci_dev * pci)
19908c2ecf20Sopenharmony_ci{
19918c2ecf20Sopenharmony_ci	u8 cmd;
19928c2ecf20Sopenharmony_ci
19938c2ecf20Sopenharmony_ci	pci_read_config_byte(pci, PCIR_DSXG_CTRL, &cmd);
19948c2ecf20Sopenharmony_ci#if 0 // force to reset
19958c2ecf20Sopenharmony_ci	if (cmd & 0x03) {
19968c2ecf20Sopenharmony_ci#endif
19978c2ecf20Sopenharmony_ci		pci_write_config_byte(pci, PCIR_DSXG_CTRL, cmd & 0xfc);
19988c2ecf20Sopenharmony_ci		pci_write_config_byte(pci, PCIR_DSXG_CTRL, cmd | 0x03);
19998c2ecf20Sopenharmony_ci		pci_write_config_byte(pci, PCIR_DSXG_CTRL, cmd & 0xfc);
20008c2ecf20Sopenharmony_ci		pci_write_config_word(pci, PCIR_DSXG_PWRCTRL1, 0);
20018c2ecf20Sopenharmony_ci		pci_write_config_word(pci, PCIR_DSXG_PWRCTRL2, 0);
20028c2ecf20Sopenharmony_ci#if 0
20038c2ecf20Sopenharmony_ci	}
20048c2ecf20Sopenharmony_ci#endif
20058c2ecf20Sopenharmony_ci}
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_cistatic void snd_ymfpci_enable_dsp(struct snd_ymfpci *chip)
20088c2ecf20Sopenharmony_ci{
20098c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_CONFIG, 0x00000001);
20108c2ecf20Sopenharmony_ci}
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_cistatic void snd_ymfpci_disable_dsp(struct snd_ymfpci *chip)
20138c2ecf20Sopenharmony_ci{
20148c2ecf20Sopenharmony_ci	u32 val;
20158c2ecf20Sopenharmony_ci	int timeout = 1000;
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_ci	val = snd_ymfpci_readl(chip, YDSXGR_CONFIG);
20188c2ecf20Sopenharmony_ci	if (val)
20198c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_CONFIG, 0x00000000);
20208c2ecf20Sopenharmony_ci	while (timeout-- > 0) {
20218c2ecf20Sopenharmony_ci		val = snd_ymfpci_readl(chip, YDSXGR_STATUS);
20228c2ecf20Sopenharmony_ci		if ((val & 0x00000002) == 0)
20238c2ecf20Sopenharmony_ci			break;
20248c2ecf20Sopenharmony_ci	}
20258c2ecf20Sopenharmony_ci}
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_cistatic int snd_ymfpci_request_firmware(struct snd_ymfpci *chip)
20288c2ecf20Sopenharmony_ci{
20298c2ecf20Sopenharmony_ci	int err, is_1e;
20308c2ecf20Sopenharmony_ci	const char *name;
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci	err = request_firmware(&chip->dsp_microcode, "yamaha/ds1_dsp.fw",
20338c2ecf20Sopenharmony_ci			       &chip->pci->dev);
20348c2ecf20Sopenharmony_ci	if (err >= 0) {
20358c2ecf20Sopenharmony_ci		if (chip->dsp_microcode->size != YDSXG_DSPLENGTH) {
20368c2ecf20Sopenharmony_ci			dev_err(chip->card->dev,
20378c2ecf20Sopenharmony_ci				"DSP microcode has wrong size\n");
20388c2ecf20Sopenharmony_ci			err = -EINVAL;
20398c2ecf20Sopenharmony_ci		}
20408c2ecf20Sopenharmony_ci	}
20418c2ecf20Sopenharmony_ci	if (err < 0)
20428c2ecf20Sopenharmony_ci		return err;
20438c2ecf20Sopenharmony_ci	is_1e = chip->device_id == PCI_DEVICE_ID_YAMAHA_724F ||
20448c2ecf20Sopenharmony_ci		chip->device_id == PCI_DEVICE_ID_YAMAHA_740C ||
20458c2ecf20Sopenharmony_ci		chip->device_id == PCI_DEVICE_ID_YAMAHA_744 ||
20468c2ecf20Sopenharmony_ci		chip->device_id == PCI_DEVICE_ID_YAMAHA_754;
20478c2ecf20Sopenharmony_ci	name = is_1e ? "yamaha/ds1e_ctrl.fw" : "yamaha/ds1_ctrl.fw";
20488c2ecf20Sopenharmony_ci	err = request_firmware(&chip->controller_microcode, name,
20498c2ecf20Sopenharmony_ci			       &chip->pci->dev);
20508c2ecf20Sopenharmony_ci	if (err >= 0) {
20518c2ecf20Sopenharmony_ci		if (chip->controller_microcode->size != YDSXG_CTRLLENGTH) {
20528c2ecf20Sopenharmony_ci			dev_err(chip->card->dev,
20538c2ecf20Sopenharmony_ci				"controller microcode has wrong size\n");
20548c2ecf20Sopenharmony_ci			err = -EINVAL;
20558c2ecf20Sopenharmony_ci		}
20568c2ecf20Sopenharmony_ci	}
20578c2ecf20Sopenharmony_ci	if (err < 0)
20588c2ecf20Sopenharmony_ci		return err;
20598c2ecf20Sopenharmony_ci	return 0;
20608c2ecf20Sopenharmony_ci}
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_ciMODULE_FIRMWARE("yamaha/ds1_dsp.fw");
20638c2ecf20Sopenharmony_ciMODULE_FIRMWARE("yamaha/ds1_ctrl.fw");
20648c2ecf20Sopenharmony_ciMODULE_FIRMWARE("yamaha/ds1e_ctrl.fw");
20658c2ecf20Sopenharmony_ci
20668c2ecf20Sopenharmony_cistatic void snd_ymfpci_download_image(struct snd_ymfpci *chip)
20678c2ecf20Sopenharmony_ci{
20688c2ecf20Sopenharmony_ci	int i;
20698c2ecf20Sopenharmony_ci	u16 ctrl;
20708c2ecf20Sopenharmony_ci	const __le32 *inst;
20718c2ecf20Sopenharmony_ci
20728c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x00000000);
20738c2ecf20Sopenharmony_ci	snd_ymfpci_disable_dsp(chip);
20748c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_MODE, 0x00010000);
20758c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_MODE, 0x00000000);
20768c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_MAPOFREC, 0x00000000);
20778c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT, 0x00000000);
20788c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, 0x00000000);
20798c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_RECCTRLBASE, 0x00000000);
20808c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_EFFCTRLBASE, 0x00000000);
20818c2ecf20Sopenharmony_ci	ctrl = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL);
20828c2ecf20Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
20838c2ecf20Sopenharmony_ci
20848c2ecf20Sopenharmony_ci	/* setup DSP instruction code */
20858c2ecf20Sopenharmony_ci	inst = (const __le32 *)chip->dsp_microcode->data;
20868c2ecf20Sopenharmony_ci	for (i = 0; i < YDSXG_DSPLENGTH / 4; i++)
20878c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2),
20888c2ecf20Sopenharmony_ci				  le32_to_cpu(inst[i]));
20898c2ecf20Sopenharmony_ci
20908c2ecf20Sopenharmony_ci	/* setup control instruction code */
20918c2ecf20Sopenharmony_ci	inst = (const __le32 *)chip->controller_microcode->data;
20928c2ecf20Sopenharmony_ci	for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++)
20938c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_CTRLINSTRAM + (i << 2),
20948c2ecf20Sopenharmony_ci				  le32_to_cpu(inst[i]));
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci	snd_ymfpci_enable_dsp(chip);
20978c2ecf20Sopenharmony_ci}
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_cistatic int snd_ymfpci_memalloc(struct snd_ymfpci *chip)
21008c2ecf20Sopenharmony_ci{
21018c2ecf20Sopenharmony_ci	long size, playback_ctrl_size;
21028c2ecf20Sopenharmony_ci	int voice, bank, reg;
21038c2ecf20Sopenharmony_ci	u8 *ptr;
21048c2ecf20Sopenharmony_ci	dma_addr_t ptr_addr;
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_ci	playback_ctrl_size = 4 + 4 * YDSXG_PLAYBACK_VOICES;
21078c2ecf20Sopenharmony_ci	chip->bank_size_playback = snd_ymfpci_readl(chip, YDSXGR_PLAYCTRLSIZE) << 2;
21088c2ecf20Sopenharmony_ci	chip->bank_size_capture = snd_ymfpci_readl(chip, YDSXGR_RECCTRLSIZE) << 2;
21098c2ecf20Sopenharmony_ci	chip->bank_size_effect = snd_ymfpci_readl(chip, YDSXGR_EFFCTRLSIZE) << 2;
21108c2ecf20Sopenharmony_ci	chip->work_size = YDSXG_DEFAULT_WORK_SIZE;
21118c2ecf20Sopenharmony_ci
21128c2ecf20Sopenharmony_ci	size = ALIGN(playback_ctrl_size, 0x100) +
21138c2ecf20Sopenharmony_ci	       ALIGN(chip->bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES, 0x100) +
21148c2ecf20Sopenharmony_ci	       ALIGN(chip->bank_size_capture * 2 * YDSXG_CAPTURE_VOICES, 0x100) +
21158c2ecf20Sopenharmony_ci	       ALIGN(chip->bank_size_effect * 2 * YDSXG_EFFECT_VOICES, 0x100) +
21168c2ecf20Sopenharmony_ci	       chip->work_size;
21178c2ecf20Sopenharmony_ci	/* work_ptr must be aligned to 256 bytes, but it's already
21188c2ecf20Sopenharmony_ci	   covered with the kernel page allocation mechanism */
21198c2ecf20Sopenharmony_ci	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev,
21208c2ecf20Sopenharmony_ci				size, &chip->work_ptr) < 0)
21218c2ecf20Sopenharmony_ci		return -ENOMEM;
21228c2ecf20Sopenharmony_ci	ptr = chip->work_ptr.area;
21238c2ecf20Sopenharmony_ci	ptr_addr = chip->work_ptr.addr;
21248c2ecf20Sopenharmony_ci	memset(ptr, 0, size);	/* for sure */
21258c2ecf20Sopenharmony_ci
21268c2ecf20Sopenharmony_ci	chip->bank_base_playback = ptr;
21278c2ecf20Sopenharmony_ci	chip->bank_base_playback_addr = ptr_addr;
21288c2ecf20Sopenharmony_ci	chip->ctrl_playback = (__le32 *)ptr;
21298c2ecf20Sopenharmony_ci	chip->ctrl_playback[0] = cpu_to_le32(YDSXG_PLAYBACK_VOICES);
21308c2ecf20Sopenharmony_ci	ptr += ALIGN(playback_ctrl_size, 0x100);
21318c2ecf20Sopenharmony_ci	ptr_addr += ALIGN(playback_ctrl_size, 0x100);
21328c2ecf20Sopenharmony_ci	for (voice = 0; voice < YDSXG_PLAYBACK_VOICES; voice++) {
21338c2ecf20Sopenharmony_ci		chip->voices[voice].number = voice;
21348c2ecf20Sopenharmony_ci		chip->voices[voice].bank = (struct snd_ymfpci_playback_bank *)ptr;
21358c2ecf20Sopenharmony_ci		chip->voices[voice].bank_addr = ptr_addr;
21368c2ecf20Sopenharmony_ci		for (bank = 0; bank < 2; bank++) {
21378c2ecf20Sopenharmony_ci			chip->bank_playback[voice][bank] = (struct snd_ymfpci_playback_bank *)ptr;
21388c2ecf20Sopenharmony_ci			ptr += chip->bank_size_playback;
21398c2ecf20Sopenharmony_ci			ptr_addr += chip->bank_size_playback;
21408c2ecf20Sopenharmony_ci		}
21418c2ecf20Sopenharmony_ci	}
21428c2ecf20Sopenharmony_ci	ptr = (char *)ALIGN((unsigned long)ptr, 0x100);
21438c2ecf20Sopenharmony_ci	ptr_addr = ALIGN(ptr_addr, 0x100);
21448c2ecf20Sopenharmony_ci	chip->bank_base_capture = ptr;
21458c2ecf20Sopenharmony_ci	chip->bank_base_capture_addr = ptr_addr;
21468c2ecf20Sopenharmony_ci	for (voice = 0; voice < YDSXG_CAPTURE_VOICES; voice++)
21478c2ecf20Sopenharmony_ci		for (bank = 0; bank < 2; bank++) {
21488c2ecf20Sopenharmony_ci			chip->bank_capture[voice][bank] = (struct snd_ymfpci_capture_bank *)ptr;
21498c2ecf20Sopenharmony_ci			ptr += chip->bank_size_capture;
21508c2ecf20Sopenharmony_ci			ptr_addr += chip->bank_size_capture;
21518c2ecf20Sopenharmony_ci		}
21528c2ecf20Sopenharmony_ci	ptr = (char *)ALIGN((unsigned long)ptr, 0x100);
21538c2ecf20Sopenharmony_ci	ptr_addr = ALIGN(ptr_addr, 0x100);
21548c2ecf20Sopenharmony_ci	chip->bank_base_effect = ptr;
21558c2ecf20Sopenharmony_ci	chip->bank_base_effect_addr = ptr_addr;
21568c2ecf20Sopenharmony_ci	for (voice = 0; voice < YDSXG_EFFECT_VOICES; voice++)
21578c2ecf20Sopenharmony_ci		for (bank = 0; bank < 2; bank++) {
21588c2ecf20Sopenharmony_ci			chip->bank_effect[voice][bank] = (struct snd_ymfpci_effect_bank *)ptr;
21598c2ecf20Sopenharmony_ci			ptr += chip->bank_size_effect;
21608c2ecf20Sopenharmony_ci			ptr_addr += chip->bank_size_effect;
21618c2ecf20Sopenharmony_ci		}
21628c2ecf20Sopenharmony_ci	ptr = (char *)ALIGN((unsigned long)ptr, 0x100);
21638c2ecf20Sopenharmony_ci	ptr_addr = ALIGN(ptr_addr, 0x100);
21648c2ecf20Sopenharmony_ci	chip->work_base = ptr;
21658c2ecf20Sopenharmony_ci	chip->work_base_addr = ptr_addr;
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci	snd_BUG_ON(ptr + PAGE_ALIGN(chip->work_size) !=
21688c2ecf20Sopenharmony_ci		   chip->work_ptr.area + chip->work_ptr.bytes);
21698c2ecf20Sopenharmony_ci
21708c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, chip->bank_base_playback_addr);
21718c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_RECCTRLBASE, chip->bank_base_capture_addr);
21728c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_EFFCTRLBASE, chip->bank_base_effect_addr);
21738c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_WORKBASE, chip->work_base_addr);
21748c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_WORKSIZE, chip->work_size >> 2);
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_ci	/* S/PDIF output initialization */
21778c2ecf20Sopenharmony_ci	chip->spdif_bits = chip->spdif_pcm_bits = SNDRV_PCM_DEFAULT_CON_SPDIF & 0xffff;
21788c2ecf20Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL, 0);
21798c2ecf20Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_bits);
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_ci	/* S/PDIF input initialization */
21828c2ecf20Sopenharmony_ci	snd_ymfpci_writew(chip, YDSXGR_SPDIFINCTRL, 0);
21838c2ecf20Sopenharmony_ci
21848c2ecf20Sopenharmony_ci	/* digital mixer setup */
21858c2ecf20Sopenharmony_ci	for (reg = 0x80; reg < 0xc0; reg += 4)
21868c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, reg, 0);
21878c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff);
21888c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0x3fff3fff);
21898c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_ZVOUTVOL, 0x3fff3fff);
21908c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_SPDIFOUTVOL, 0x3fff3fff);
21918c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_NATIVEADCINVOL, 0x3fff3fff);
21928c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_NATIVEDACINVOL, 0x3fff3fff);
21938c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_PRIADCLOOPVOL, 0x3fff3fff);
21948c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_LEGACYOUTVOL, 0x3fff3fff);
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_ci	return 0;
21978c2ecf20Sopenharmony_ci}
21988c2ecf20Sopenharmony_ci
21998c2ecf20Sopenharmony_cistatic int snd_ymfpci_free(struct snd_ymfpci *chip)
22008c2ecf20Sopenharmony_ci{
22018c2ecf20Sopenharmony_ci	u16 ctrl;
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!chip))
22048c2ecf20Sopenharmony_ci		return -EINVAL;
22058c2ecf20Sopenharmony_ci
22068c2ecf20Sopenharmony_ci	if (chip->res_reg_area) {	/* don't touch busy hardware */
22078c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0);
22088c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0);
22098c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_LEGACYOUTVOL, 0);
22108c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_STATUS, ~0);
22118c2ecf20Sopenharmony_ci		snd_ymfpci_disable_dsp(chip);
22128c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, 0);
22138c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_RECCTRLBASE, 0);
22148c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_EFFCTRLBASE, 0);
22158c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_WORKBASE, 0);
22168c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_WORKSIZE, 0);
22178c2ecf20Sopenharmony_ci		ctrl = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL);
22188c2ecf20Sopenharmony_ci		snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
22198c2ecf20Sopenharmony_ci	}
22208c2ecf20Sopenharmony_ci
22218c2ecf20Sopenharmony_ci	snd_ymfpci_ac3_done(chip);
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci	/* Set PCI device to D3 state */
22248c2ecf20Sopenharmony_ci#if 0
22258c2ecf20Sopenharmony_ci	/* FIXME: temporarily disabled, otherwise we cannot fire up
22268c2ecf20Sopenharmony_ci	 * the chip again unless reboot.  ACPI bug?
22278c2ecf20Sopenharmony_ci	 */
22288c2ecf20Sopenharmony_ci	pci_set_power_state(chip->pci, PCI_D3hot);
22298c2ecf20Sopenharmony_ci#endif
22308c2ecf20Sopenharmony_ci
22318c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
22328c2ecf20Sopenharmony_ci	kfree(chip->saved_regs);
22338c2ecf20Sopenharmony_ci#endif
22348c2ecf20Sopenharmony_ci	if (chip->irq >= 0)
22358c2ecf20Sopenharmony_ci		free_irq(chip->irq, chip);
22368c2ecf20Sopenharmony_ci	release_and_free_resource(chip->mpu_res);
22378c2ecf20Sopenharmony_ci	release_and_free_resource(chip->fm_res);
22388c2ecf20Sopenharmony_ci	snd_ymfpci_free_gameport(chip);
22398c2ecf20Sopenharmony_ci	iounmap(chip->reg_area_virt);
22408c2ecf20Sopenharmony_ci	if (chip->work_ptr.area)
22418c2ecf20Sopenharmony_ci		snd_dma_free_pages(&chip->work_ptr);
22428c2ecf20Sopenharmony_ci
22438c2ecf20Sopenharmony_ci	release_and_free_resource(chip->res_reg_area);
22448c2ecf20Sopenharmony_ci
22458c2ecf20Sopenharmony_ci	pci_write_config_word(chip->pci, 0x40, chip->old_legacy_ctrl);
22468c2ecf20Sopenharmony_ci
22478c2ecf20Sopenharmony_ci	pci_disable_device(chip->pci);
22488c2ecf20Sopenharmony_ci	release_firmware(chip->dsp_microcode);
22498c2ecf20Sopenharmony_ci	release_firmware(chip->controller_microcode);
22508c2ecf20Sopenharmony_ci	kfree(chip);
22518c2ecf20Sopenharmony_ci	return 0;
22528c2ecf20Sopenharmony_ci}
22538c2ecf20Sopenharmony_ci
22548c2ecf20Sopenharmony_cistatic int snd_ymfpci_dev_free(struct snd_device *device)
22558c2ecf20Sopenharmony_ci{
22568c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = device->device_data;
22578c2ecf20Sopenharmony_ci	return snd_ymfpci_free(chip);
22588c2ecf20Sopenharmony_ci}
22598c2ecf20Sopenharmony_ci
22608c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
22618c2ecf20Sopenharmony_cistatic const int saved_regs_index[] = {
22628c2ecf20Sopenharmony_ci	/* spdif */
22638c2ecf20Sopenharmony_ci	YDSXGR_SPDIFOUTCTRL,
22648c2ecf20Sopenharmony_ci	YDSXGR_SPDIFOUTSTATUS,
22658c2ecf20Sopenharmony_ci	YDSXGR_SPDIFINCTRL,
22668c2ecf20Sopenharmony_ci	/* volumes */
22678c2ecf20Sopenharmony_ci	YDSXGR_PRIADCLOOPVOL,
22688c2ecf20Sopenharmony_ci	YDSXGR_NATIVEDACINVOL,
22698c2ecf20Sopenharmony_ci	YDSXGR_NATIVEDACOUTVOL,
22708c2ecf20Sopenharmony_ci	YDSXGR_BUF441OUTVOL,
22718c2ecf20Sopenharmony_ci	YDSXGR_NATIVEADCINVOL,
22728c2ecf20Sopenharmony_ci	YDSXGR_SPDIFLOOPVOL,
22738c2ecf20Sopenharmony_ci	YDSXGR_SPDIFOUTVOL,
22748c2ecf20Sopenharmony_ci	YDSXGR_ZVOUTVOL,
22758c2ecf20Sopenharmony_ci	YDSXGR_LEGACYOUTVOL,
22768c2ecf20Sopenharmony_ci	/* address bases */
22778c2ecf20Sopenharmony_ci	YDSXGR_PLAYCTRLBASE,
22788c2ecf20Sopenharmony_ci	YDSXGR_RECCTRLBASE,
22798c2ecf20Sopenharmony_ci	YDSXGR_EFFCTRLBASE,
22808c2ecf20Sopenharmony_ci	YDSXGR_WORKBASE,
22818c2ecf20Sopenharmony_ci	/* capture set up */
22828c2ecf20Sopenharmony_ci	YDSXGR_MAPOFREC,
22838c2ecf20Sopenharmony_ci	YDSXGR_RECFORMAT,
22848c2ecf20Sopenharmony_ci	YDSXGR_RECSLOTSR,
22858c2ecf20Sopenharmony_ci	YDSXGR_ADCFORMAT,
22868c2ecf20Sopenharmony_ci	YDSXGR_ADCSLOTSR,
22878c2ecf20Sopenharmony_ci};
22888c2ecf20Sopenharmony_ci#define YDSXGR_NUM_SAVED_REGS	ARRAY_SIZE(saved_regs_index)
22898c2ecf20Sopenharmony_ci
22908c2ecf20Sopenharmony_cistatic int snd_ymfpci_suspend(struct device *dev)
22918c2ecf20Sopenharmony_ci{
22928c2ecf20Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
22938c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = card->private_data;
22948c2ecf20Sopenharmony_ci	unsigned int i;
22958c2ecf20Sopenharmony_ci
22968c2ecf20Sopenharmony_ci	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
22978c2ecf20Sopenharmony_ci	snd_ac97_suspend(chip->ac97);
22988c2ecf20Sopenharmony_ci	for (i = 0; i < YDSXGR_NUM_SAVED_REGS; i++)
22998c2ecf20Sopenharmony_ci		chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]);
23008c2ecf20Sopenharmony_ci	chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE);
23018c2ecf20Sopenharmony_ci	pci_read_config_word(chip->pci, PCIR_DSXG_LEGACY,
23028c2ecf20Sopenharmony_ci			     &chip->saved_dsxg_legacy);
23038c2ecf20Sopenharmony_ci	pci_read_config_word(chip->pci, PCIR_DSXG_ELEGACY,
23048c2ecf20Sopenharmony_ci			     &chip->saved_dsxg_elegacy);
23058c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0);
23068c2ecf20Sopenharmony_ci	snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0);
23078c2ecf20Sopenharmony_ci	snd_ymfpci_disable_dsp(chip);
23088c2ecf20Sopenharmony_ci	return 0;
23098c2ecf20Sopenharmony_ci}
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_cistatic int snd_ymfpci_resume(struct device *dev)
23128c2ecf20Sopenharmony_ci{
23138c2ecf20Sopenharmony_ci	struct pci_dev *pci = to_pci_dev(dev);
23148c2ecf20Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
23158c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip = card->private_data;
23168c2ecf20Sopenharmony_ci	unsigned int i;
23178c2ecf20Sopenharmony_ci
23188c2ecf20Sopenharmony_ci	snd_ymfpci_aclink_reset(pci);
23198c2ecf20Sopenharmony_ci	snd_ymfpci_codec_ready(chip, 0);
23208c2ecf20Sopenharmony_ci	snd_ymfpci_download_image(chip);
23218c2ecf20Sopenharmony_ci	udelay(100);
23228c2ecf20Sopenharmony_ci
23238c2ecf20Sopenharmony_ci	for (i = 0; i < YDSXGR_NUM_SAVED_REGS; i++)
23248c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, saved_regs_index[i], chip->saved_regs[i]);
23258c2ecf20Sopenharmony_ci
23268c2ecf20Sopenharmony_ci	snd_ac97_resume(chip->ac97);
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_ci	pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY,
23298c2ecf20Sopenharmony_ci			      chip->saved_dsxg_legacy);
23308c2ecf20Sopenharmony_ci	pci_write_config_word(chip->pci, PCIR_DSXG_ELEGACY,
23318c2ecf20Sopenharmony_ci			      chip->saved_dsxg_elegacy);
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_ci	/* start hw again */
23348c2ecf20Sopenharmony_ci	if (chip->start_count > 0) {
23358c2ecf20Sopenharmony_ci		spin_lock_irq(&chip->reg_lock);
23368c2ecf20Sopenharmony_ci		snd_ymfpci_writel(chip, YDSXGR_MODE, chip->saved_ydsxgr_mode);
23378c2ecf20Sopenharmony_ci		chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT);
23388c2ecf20Sopenharmony_ci		spin_unlock_irq(&chip->reg_lock);
23398c2ecf20Sopenharmony_ci	}
23408c2ecf20Sopenharmony_ci	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
23418c2ecf20Sopenharmony_ci	return 0;
23428c2ecf20Sopenharmony_ci}
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_ciSIMPLE_DEV_PM_OPS(snd_ymfpci_pm, snd_ymfpci_suspend, snd_ymfpci_resume);
23458c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */
23468c2ecf20Sopenharmony_ci
23478c2ecf20Sopenharmony_ciint snd_ymfpci_create(struct snd_card *card,
23488c2ecf20Sopenharmony_ci		      struct pci_dev *pci,
23498c2ecf20Sopenharmony_ci		      unsigned short old_legacy_ctrl,
23508c2ecf20Sopenharmony_ci		      struct snd_ymfpci **rchip)
23518c2ecf20Sopenharmony_ci{
23528c2ecf20Sopenharmony_ci	struct snd_ymfpci *chip;
23538c2ecf20Sopenharmony_ci	int err;
23548c2ecf20Sopenharmony_ci	static const struct snd_device_ops ops = {
23558c2ecf20Sopenharmony_ci		.dev_free =	snd_ymfpci_dev_free,
23568c2ecf20Sopenharmony_ci	};
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ci	*rchip = NULL;
23598c2ecf20Sopenharmony_ci
23608c2ecf20Sopenharmony_ci	/* enable PCI device */
23618c2ecf20Sopenharmony_ci	err = pci_enable_device(pci);
23628c2ecf20Sopenharmony_ci	if (err < 0)
23638c2ecf20Sopenharmony_ci		return err;
23648c2ecf20Sopenharmony_ci
23658c2ecf20Sopenharmony_ci	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
23668c2ecf20Sopenharmony_ci	if (chip == NULL) {
23678c2ecf20Sopenharmony_ci		pci_disable_device(pci);
23688c2ecf20Sopenharmony_ci		return -ENOMEM;
23698c2ecf20Sopenharmony_ci	}
23708c2ecf20Sopenharmony_ci	chip->old_legacy_ctrl = old_legacy_ctrl;
23718c2ecf20Sopenharmony_ci	spin_lock_init(&chip->reg_lock);
23728c2ecf20Sopenharmony_ci	spin_lock_init(&chip->voice_lock);
23738c2ecf20Sopenharmony_ci	init_waitqueue_head(&chip->interrupt_sleep);
23748c2ecf20Sopenharmony_ci	atomic_set(&chip->interrupt_sleep_count, 0);
23758c2ecf20Sopenharmony_ci	chip->card = card;
23768c2ecf20Sopenharmony_ci	chip->pci = pci;
23778c2ecf20Sopenharmony_ci	chip->irq = -1;
23788c2ecf20Sopenharmony_ci	chip->device_id = pci->device;
23798c2ecf20Sopenharmony_ci	chip->rev = pci->revision;
23808c2ecf20Sopenharmony_ci	chip->reg_area_phys = pci_resource_start(pci, 0);
23818c2ecf20Sopenharmony_ci	chip->reg_area_virt = ioremap(chip->reg_area_phys, 0x8000);
23828c2ecf20Sopenharmony_ci	pci_set_master(pci);
23838c2ecf20Sopenharmony_ci	chip->src441_used = -1;
23848c2ecf20Sopenharmony_ci
23858c2ecf20Sopenharmony_ci	chip->res_reg_area = request_mem_region(chip->reg_area_phys, 0x8000, "YMFPCI");
23868c2ecf20Sopenharmony_ci	if (!chip->res_reg_area) {
23878c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
23888c2ecf20Sopenharmony_ci			"unable to grab memory region 0x%lx-0x%lx\n",
23898c2ecf20Sopenharmony_ci			chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1);
23908c2ecf20Sopenharmony_ci		err = -EBUSY;
23918c2ecf20Sopenharmony_ci		goto free_chip;
23928c2ecf20Sopenharmony_ci	}
23938c2ecf20Sopenharmony_ci	if (request_irq(pci->irq, snd_ymfpci_interrupt, IRQF_SHARED,
23948c2ecf20Sopenharmony_ci			KBUILD_MODNAME, chip)) {
23958c2ecf20Sopenharmony_ci		dev_err(chip->card->dev, "unable to grab IRQ %d\n", pci->irq);
23968c2ecf20Sopenharmony_ci		err = -EBUSY;
23978c2ecf20Sopenharmony_ci		goto free_chip;
23988c2ecf20Sopenharmony_ci	}
23998c2ecf20Sopenharmony_ci	chip->irq = pci->irq;
24008c2ecf20Sopenharmony_ci	card->sync_irq = chip->irq;
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci	snd_ymfpci_aclink_reset(pci);
24038c2ecf20Sopenharmony_ci	if (snd_ymfpci_codec_ready(chip, 0) < 0) {
24048c2ecf20Sopenharmony_ci		err = -EIO;
24058c2ecf20Sopenharmony_ci		goto free_chip;
24068c2ecf20Sopenharmony_ci	}
24078c2ecf20Sopenharmony_ci
24088c2ecf20Sopenharmony_ci	err = snd_ymfpci_request_firmware(chip);
24098c2ecf20Sopenharmony_ci	if (err < 0) {
24108c2ecf20Sopenharmony_ci		dev_err(chip->card->dev, "firmware request failed: %d\n", err);
24118c2ecf20Sopenharmony_ci		goto free_chip;
24128c2ecf20Sopenharmony_ci	}
24138c2ecf20Sopenharmony_ci	snd_ymfpci_download_image(chip);
24148c2ecf20Sopenharmony_ci
24158c2ecf20Sopenharmony_ci	udelay(100); /* seems we need a delay after downloading image.. */
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_ci	if (snd_ymfpci_memalloc(chip) < 0) {
24188c2ecf20Sopenharmony_ci		err = -EIO;
24198c2ecf20Sopenharmony_ci		goto free_chip;
24208c2ecf20Sopenharmony_ci	}
24218c2ecf20Sopenharmony_ci
24228c2ecf20Sopenharmony_ci	err = snd_ymfpci_ac3_init(chip);
24238c2ecf20Sopenharmony_ci	if (err < 0)
24248c2ecf20Sopenharmony_ci		goto free_chip;
24258c2ecf20Sopenharmony_ci
24268c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
24278c2ecf20Sopenharmony_ci	chip->saved_regs = kmalloc_array(YDSXGR_NUM_SAVED_REGS, sizeof(u32),
24288c2ecf20Sopenharmony_ci					 GFP_KERNEL);
24298c2ecf20Sopenharmony_ci	if (chip->saved_regs == NULL) {
24308c2ecf20Sopenharmony_ci		err = -ENOMEM;
24318c2ecf20Sopenharmony_ci		goto free_chip;
24328c2ecf20Sopenharmony_ci	}
24338c2ecf20Sopenharmony_ci#endif
24348c2ecf20Sopenharmony_ci
24358c2ecf20Sopenharmony_ci	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
24368c2ecf20Sopenharmony_ci	if (err < 0)
24378c2ecf20Sopenharmony_ci		goto free_chip;
24388c2ecf20Sopenharmony_ci
24398c2ecf20Sopenharmony_ci	snd_ymfpci_proc_init(card, chip);
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_ci	*rchip = chip;
24428c2ecf20Sopenharmony_ci	return 0;
24438c2ecf20Sopenharmony_ci
24448c2ecf20Sopenharmony_cifree_chip:
24458c2ecf20Sopenharmony_ci	snd_ymfpci_free(chip);
24468c2ecf20Sopenharmony_ci	return err;
24478c2ecf20Sopenharmony_ci}
2448