xref: /openbmc/linux/sound/pci/es1938.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  Driver for ESS Solo-1 (ES1938, ES1946, ES1969) soundcard
41da177e4SLinus Torvalds  *  Copyright (c) by Jaromir Koutek <miri@punknet.cz>,
5c1017a4cSJaroslav Kysela  *                   Jaroslav Kysela <perex@perex.cz>,
61da177e4SLinus Torvalds  *                   Thomas Sailer <sailer@ife.ee.ethz.ch>,
71da177e4SLinus Torvalds  *                   Abramo Bagnara <abramo@alsa-project.org>,
81da177e4SLinus Torvalds  *                   Markus Gruber <gruber@eikon.tum.de>
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  * Rewritten from sonicvibes.c source.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  *  TODO:
131da177e4SLinus Torvalds  *    Rewrite better spinlocks
141da177e4SLinus Torvalds  */
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds /*
171da177e4SLinus Torvalds   NOTES:
181da177e4SLinus Torvalds   - Capture data is written unaligned starting from dma_base + 1 so I need to
191da177e4SLinus Torvalds     disable mmap and to add a copy callback.
201da177e4SLinus Torvalds   - After several cycle of the following:
211da177e4SLinus Torvalds     while : ; do arecord -d1 -f cd -t raw | aplay -f cd ; done
221da177e4SLinus Torvalds     a "playback write error (DMA or IRQ trouble?)" may happen.
231da177e4SLinus Torvalds     This is due to playback interrupts not generated.
241da177e4SLinus Torvalds     I suspect a timing issue.
251da177e4SLinus Torvalds   - Sometimes the interrupt handler is invoked wrongly during playback.
261da177e4SLinus Torvalds     This generates some harmless "Unexpected hw_pointer: wrong interrupt
271da177e4SLinus Torvalds     acknowledge".
281da177e4SLinus Torvalds     I've seen that using small period sizes.
291da177e4SLinus Torvalds     Reproducible with:
301da177e4SLinus Torvalds     mpg123 test.mp3 &
311da177e4SLinus Torvalds     hdparm -t -T /dev/hda
321da177e4SLinus Torvalds */
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds #include <linux/init.h>
361da177e4SLinus Torvalds #include <linux/interrupt.h>
371da177e4SLinus Torvalds #include <linux/pci.h>
381da177e4SLinus Torvalds #include <linux/slab.h>
391da177e4SLinus Torvalds #include <linux/gameport.h>
4065a77217SPaul Gortmaker #include <linux/module.h>
411da177e4SLinus Torvalds #include <linux/delay.h>
42910638aeSMatthias Gehre #include <linux/dma-mapping.h>
436cbbfe1cSTakashi Iwai #include <linux/io.h>
441da177e4SLinus Torvalds #include <sound/core.h>
451da177e4SLinus Torvalds #include <sound/control.h>
461da177e4SLinus Torvalds #include <sound/pcm.h>
471da177e4SLinus Torvalds #include <sound/opl3.h>
481da177e4SLinus Torvalds #include <sound/mpu401.h>
491da177e4SLinus Torvalds #include <sound/initval.h>
500b593972STakashi Iwai #include <sound/tlv.h>
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds MODULE_AUTHOR("Jaromir Koutek <miri@punknet.cz>");
531da177e4SLinus Torvalds MODULE_DESCRIPTION("ESS Solo-1");
541da177e4SLinus Torvalds MODULE_LICENSE("GPL");
551da177e4SLinus Torvalds 
56b2fac073SFabian Frederick #if IS_REACHABLE(CONFIG_GAMEPORT)
571da177e4SLinus Torvalds #define SUPPORT_JOYSTICK 1
581da177e4SLinus Torvalds #endif
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
611da177e4SLinus Torvalds static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
62a67ff6a5SRusty Russell static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds module_param_array(index, int, NULL, 0444);
651da177e4SLinus Torvalds MODULE_PARM_DESC(index, "Index value for ESS Solo-1 soundcard.");
661da177e4SLinus Torvalds module_param_array(id, charp, NULL, 0444);
671da177e4SLinus Torvalds MODULE_PARM_DESC(id, "ID string for ESS Solo-1 soundcard.");
681da177e4SLinus Torvalds module_param_array(enable, bool, NULL, 0444);
691da177e4SLinus Torvalds MODULE_PARM_DESC(enable, "Enable ESS Solo-1 soundcard.");
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds #define SLIO_REG(chip, x) ((chip)->io_port + ESSIO_REG_##x)
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds #define SLDM_REG(chip, x) ((chip)->ddma_port + ESSDM_REG_##x)
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds #define SLSB_REG(chip, x) ((chip)->sb_port + ESSSB_REG_##x)
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds #define SL_PCI_LEGACYCONTROL		0x40
781da177e4SLinus Torvalds #define SL_PCI_CONFIG			0x50
791da177e4SLinus Torvalds #define SL_PCI_DDMACONTROL		0x60
801da177e4SLinus Torvalds 
811da177e4SLinus Torvalds #define ESSIO_REG_AUDIO2DMAADDR		0
821da177e4SLinus Torvalds #define ESSIO_REG_AUDIO2DMACOUNT	4
831da177e4SLinus Torvalds #define ESSIO_REG_AUDIO2MODE		6
841da177e4SLinus Torvalds #define ESSIO_REG_IRQCONTROL		7
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds #define ESSDM_REG_DMAADDR		0x00
871da177e4SLinus Torvalds #define ESSDM_REG_DMACOUNT		0x04
881da177e4SLinus Torvalds #define ESSDM_REG_DMACOMMAND		0x08
891da177e4SLinus Torvalds #define ESSDM_REG_DMASTATUS		0x08
901da177e4SLinus Torvalds #define ESSDM_REG_DMAMODE		0x0b
911da177e4SLinus Torvalds #define ESSDM_REG_DMACLEAR		0x0d
921da177e4SLinus Torvalds #define ESSDM_REG_DMAMASK		0x0f
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds #define ESSSB_REG_FMLOWADDR		0x00
951da177e4SLinus Torvalds #define ESSSB_REG_FMHIGHADDR		0x02
961da177e4SLinus Torvalds #define ESSSB_REG_MIXERADDR		0x04
971da177e4SLinus Torvalds #define ESSSB_REG_MIXERDATA		0x05
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds #define ESSSB_IREG_AUDIO1		0x14
1001da177e4SLinus Torvalds #define ESSSB_IREG_MICMIX		0x1a
1011da177e4SLinus Torvalds #define ESSSB_IREG_RECSRC		0x1c
1021da177e4SLinus Torvalds #define ESSSB_IREG_MASTER		0x32
1031da177e4SLinus Torvalds #define ESSSB_IREG_FM			0x36
1041da177e4SLinus Torvalds #define ESSSB_IREG_AUXACD		0x38
1051da177e4SLinus Torvalds #define ESSSB_IREG_AUXB			0x3a
1061da177e4SLinus Torvalds #define ESSSB_IREG_PCSPEAKER		0x3c
1071da177e4SLinus Torvalds #define ESSSB_IREG_LINE			0x3e
1081da177e4SLinus Torvalds #define ESSSB_IREG_SPATCONTROL		0x50
1091da177e4SLinus Torvalds #define ESSSB_IREG_SPATLEVEL		0x52
1101da177e4SLinus Torvalds #define ESSSB_IREG_MASTER_LEFT		0x60
1111da177e4SLinus Torvalds #define ESSSB_IREG_MASTER_RIGHT		0x62
1121da177e4SLinus Torvalds #define ESSSB_IREG_MPU401CONTROL	0x64
1131da177e4SLinus Torvalds #define ESSSB_IREG_MICMIXRECORD		0x68
1141da177e4SLinus Torvalds #define ESSSB_IREG_AUDIO2RECORD		0x69
1151da177e4SLinus Torvalds #define ESSSB_IREG_AUXACDRECORD		0x6a
1161da177e4SLinus Torvalds #define ESSSB_IREG_FMRECORD		0x6b
1171da177e4SLinus Torvalds #define ESSSB_IREG_AUXBRECORD		0x6c
1181da177e4SLinus Torvalds #define ESSSB_IREG_MONO			0x6d
1191da177e4SLinus Torvalds #define ESSSB_IREG_LINERECORD		0x6e
1201da177e4SLinus Torvalds #define ESSSB_IREG_MONORECORD		0x6f
1211da177e4SLinus Torvalds #define ESSSB_IREG_AUDIO2SAMPLE		0x70
1221da177e4SLinus Torvalds #define ESSSB_IREG_AUDIO2MODE		0x71
1231da177e4SLinus Torvalds #define ESSSB_IREG_AUDIO2FILTER		0x72
1241da177e4SLinus Torvalds #define ESSSB_IREG_AUDIO2TCOUNTL	0x74
1251da177e4SLinus Torvalds #define ESSSB_IREG_AUDIO2TCOUNTH	0x76
1261da177e4SLinus Torvalds #define ESSSB_IREG_AUDIO2CONTROL1	0x78
1271da177e4SLinus Torvalds #define ESSSB_IREG_AUDIO2CONTROL2	0x7a
1281da177e4SLinus Torvalds #define ESSSB_IREG_AUDIO2		0x7c
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds #define ESSSB_REG_RESET			0x06
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds #define ESSSB_REG_READDATA		0x0a
1331da177e4SLinus Torvalds #define ESSSB_REG_WRITEDATA		0x0c
1341da177e4SLinus Torvalds #define ESSSB_REG_READSTATUS		0x0c
1351da177e4SLinus Torvalds 
1361da177e4SLinus Torvalds #define ESSSB_REG_STATUS		0x0e
1371da177e4SLinus Torvalds 
1381da177e4SLinus Torvalds #define ESS_CMD_EXTSAMPLERATE		0xa1
1391da177e4SLinus Torvalds #define ESS_CMD_FILTERDIV		0xa2
1401da177e4SLinus Torvalds #define ESS_CMD_DMACNTRELOADL		0xa4
1411da177e4SLinus Torvalds #define ESS_CMD_DMACNTRELOADH		0xa5
1421da177e4SLinus Torvalds #define ESS_CMD_ANALOGCONTROL		0xa8
1431da177e4SLinus Torvalds #define ESS_CMD_IRQCONTROL		0xb1
1441da177e4SLinus Torvalds #define ESS_CMD_DRQCONTROL		0xb2
1451da177e4SLinus Torvalds #define ESS_CMD_RECLEVEL		0xb4
1461da177e4SLinus Torvalds #define ESS_CMD_SETFORMAT		0xb6
1471da177e4SLinus Torvalds #define ESS_CMD_SETFORMAT2		0xb7
1481da177e4SLinus Torvalds #define ESS_CMD_DMACONTROL		0xb8
1491da177e4SLinus Torvalds #define ESS_CMD_DMATYPE			0xb9
1501da177e4SLinus Torvalds #define ESS_CMD_OFFSETLEFT		0xba
1511da177e4SLinus Torvalds #define ESS_CMD_OFFSETRIGHT		0xbb
1521da177e4SLinus Torvalds #define ESS_CMD_READREG			0xc0
1531da177e4SLinus Torvalds #define ESS_CMD_ENABLEEXT		0xc6
1541da177e4SLinus Torvalds #define ESS_CMD_PAUSEDMA		0xd0
1551da177e4SLinus Torvalds #define ESS_CMD_ENABLEAUDIO1		0xd1
1561da177e4SLinus Torvalds #define ESS_CMD_STOPAUDIO1		0xd3
1571da177e4SLinus Torvalds #define ESS_CMD_AUDIO1STATUS		0xd8
1581da177e4SLinus Torvalds #define ESS_CMD_CONTDMA			0xd4
1591da177e4SLinus Torvalds #define ESS_CMD_TESTIRQ			0xf2
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds #define ESS_RECSRC_MIC		0
1621da177e4SLinus Torvalds #define ESS_RECSRC_AUXACD	2
1631da177e4SLinus Torvalds #define ESS_RECSRC_AUXB		5
1641da177e4SLinus Torvalds #define ESS_RECSRC_LINE		6
1651da177e4SLinus Torvalds #define ESS_RECSRC_NONE		7
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds #define DAC1 0x01
1681da177e4SLinus Torvalds #define ADC1 0x02
1691da177e4SLinus Torvalds #define DAC2 0x04
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds /*
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds  */
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds #define SAVED_REG_SIZE	32 /* max. number of registers to save */
1761da177e4SLinus Torvalds 
177e571f594STakashi Iwai struct es1938 {
1781da177e4SLinus Torvalds 	int irq;
1791da177e4SLinus Torvalds 
1801da177e4SLinus Torvalds 	unsigned long io_port;
1811da177e4SLinus Torvalds 	unsigned long sb_port;
1821da177e4SLinus Torvalds 	unsigned long vc_port;
1831da177e4SLinus Torvalds 	unsigned long mpu_port;
1841da177e4SLinus Torvalds 	unsigned long game_port;
1851da177e4SLinus Torvalds 	unsigned long ddma_port;
1861da177e4SLinus Torvalds 
1871da177e4SLinus Torvalds 	unsigned char irqmask;
1881da177e4SLinus Torvalds 	unsigned char revision;
1891da177e4SLinus Torvalds 
190e571f594STakashi Iwai 	struct snd_kcontrol *hw_volume;
191e571f594STakashi Iwai 	struct snd_kcontrol *hw_switch;
192e571f594STakashi Iwai 	struct snd_kcontrol *master_volume;
193e571f594STakashi Iwai 	struct snd_kcontrol *master_switch;
1941da177e4SLinus Torvalds 
1951da177e4SLinus Torvalds 	struct pci_dev *pci;
196e571f594STakashi Iwai 	struct snd_card *card;
197e571f594STakashi Iwai 	struct snd_pcm *pcm;
198e571f594STakashi Iwai 	struct snd_pcm_substream *capture_substream;
199e571f594STakashi Iwai 	struct snd_pcm_substream *playback1_substream;
200e571f594STakashi Iwai 	struct snd_pcm_substream *playback2_substream;
201e571f594STakashi Iwai 	struct snd_rawmidi *rmidi;
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds 	unsigned int dma1_size;
2041da177e4SLinus Torvalds 	unsigned int dma2_size;
2051da177e4SLinus Torvalds 	unsigned int dma1_start;
2061da177e4SLinus Torvalds 	unsigned int dma2_start;
2071da177e4SLinus Torvalds 	unsigned int dma1_shift;
2081da177e4SLinus Torvalds 	unsigned int dma2_shift;
20919e2e3c3SHermann Lauer 	unsigned int last_capture_dmaaddr;
2101da177e4SLinus Torvalds 	unsigned int active;
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds 	spinlock_t reg_lock;
2131da177e4SLinus Torvalds 	spinlock_t mixer_lock;
214e571f594STakashi Iwai         struct snd_info_entry *proc_entry;
2151da177e4SLinus Torvalds 
2161da177e4SLinus Torvalds #ifdef SUPPORT_JOYSTICK
2171da177e4SLinus Torvalds 	struct gameport *gameport;
2181da177e4SLinus Torvalds #endif
219c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
2201da177e4SLinus Torvalds 	unsigned char saved_regs[SAVED_REG_SIZE];
2211da177e4SLinus Torvalds #endif
2221da177e4SLinus Torvalds };
2231da177e4SLinus Torvalds 
2247d12e780SDavid Howells static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id);
2251da177e4SLinus Torvalds 
2269baa3c34SBenoit Taine static const struct pci_device_id snd_es1938_ids[] = {
22728d27aaeSJoe Perches 	{ PCI_VDEVICE(ESS, 0x1969), 0, },   /* Solo-1 */
2281da177e4SLinus Torvalds 	{ 0, }
2291da177e4SLinus Torvalds };
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, snd_es1938_ids);
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds #define RESET_LOOP_TIMEOUT	0x10000
2341da177e4SLinus Torvalds #define WRITE_LOOP_TIMEOUT	0x10000
2351da177e4SLinus Torvalds #define GET_LOOP_TIMEOUT	0x01000
2361da177e4SLinus Torvalds 
2371da177e4SLinus Torvalds /* -----------------------------------------------------------------
2381da177e4SLinus Torvalds  * Write to a mixer register
2391da177e4SLinus Torvalds  * -----------------------------------------------------------------*/
snd_es1938_mixer_write(struct es1938 * chip,unsigned char reg,unsigned char val)240e571f594STakashi Iwai static void snd_es1938_mixer_write(struct es1938 *chip, unsigned char reg, unsigned char val)
2411da177e4SLinus Torvalds {
2421da177e4SLinus Torvalds 	unsigned long flags;
2431da177e4SLinus Torvalds 	spin_lock_irqsave(&chip->mixer_lock, flags);
2441da177e4SLinus Torvalds 	outb(reg, SLSB_REG(chip, MIXERADDR));
2451da177e4SLinus Torvalds 	outb(val, SLSB_REG(chip, MIXERDATA));
2461da177e4SLinus Torvalds 	spin_unlock_irqrestore(&chip->mixer_lock, flags);
247ebebecaaSTakashi Iwai 	dev_dbg(chip->card->dev, "Mixer reg %02x set to %02x\n", reg, val);
2481da177e4SLinus Torvalds }
2491da177e4SLinus Torvalds 
2501da177e4SLinus Torvalds /* -----------------------------------------------------------------
2511da177e4SLinus Torvalds  * Read from a mixer register
2521da177e4SLinus Torvalds  * -----------------------------------------------------------------*/
snd_es1938_mixer_read(struct es1938 * chip,unsigned char reg)253e571f594STakashi Iwai static int snd_es1938_mixer_read(struct es1938 *chip, unsigned char reg)
2541da177e4SLinus Torvalds {
2551da177e4SLinus Torvalds 	int data;
2561da177e4SLinus Torvalds 	unsigned long flags;
2571da177e4SLinus Torvalds 	spin_lock_irqsave(&chip->mixer_lock, flags);
2581da177e4SLinus Torvalds 	outb(reg, SLSB_REG(chip, MIXERADDR));
2591da177e4SLinus Torvalds 	data = inb(SLSB_REG(chip, MIXERDATA));
2601da177e4SLinus Torvalds 	spin_unlock_irqrestore(&chip->mixer_lock, flags);
261ebebecaaSTakashi Iwai 	dev_dbg(chip->card->dev, "Mixer reg %02x now is %02x\n", reg, data);
2621da177e4SLinus Torvalds 	return data;
2631da177e4SLinus Torvalds }
2641da177e4SLinus Torvalds 
2651da177e4SLinus Torvalds /* -----------------------------------------------------------------
2661da177e4SLinus Torvalds  * Write to some bits of a mixer register (return old value)
2671da177e4SLinus Torvalds  * -----------------------------------------------------------------*/
snd_es1938_mixer_bits(struct es1938 * chip,unsigned char reg,unsigned char mask,unsigned char val)268e571f594STakashi Iwai static int snd_es1938_mixer_bits(struct es1938 *chip, unsigned char reg,
269e571f594STakashi Iwai 				 unsigned char mask, unsigned char val)
2701da177e4SLinus Torvalds {
2711da177e4SLinus Torvalds 	unsigned long flags;
2721da177e4SLinus Torvalds 	unsigned char old, new, oval;
2731da177e4SLinus Torvalds 	spin_lock_irqsave(&chip->mixer_lock, flags);
2741da177e4SLinus Torvalds 	outb(reg, SLSB_REG(chip, MIXERADDR));
2751da177e4SLinus Torvalds 	old = inb(SLSB_REG(chip, MIXERDATA));
2761da177e4SLinus Torvalds 	oval = old & mask;
2771da177e4SLinus Torvalds 	if (val != oval) {
2781da177e4SLinus Torvalds 		new = (old & ~mask) | (val & mask);
2791da177e4SLinus Torvalds 		outb(new, SLSB_REG(chip, MIXERDATA));
280ebebecaaSTakashi Iwai 		dev_dbg(chip->card->dev,
281ebebecaaSTakashi Iwai 			"Mixer reg %02x was %02x, set to %02x\n",
28299b359baSTakashi Iwai 			   reg, old, new);
2831da177e4SLinus Torvalds 	}
2841da177e4SLinus Torvalds 	spin_unlock_irqrestore(&chip->mixer_lock, flags);
2851da177e4SLinus Torvalds 	return oval;
2861da177e4SLinus Torvalds }
2871da177e4SLinus Torvalds 
2881da177e4SLinus Torvalds /* -----------------------------------------------------------------
2891da177e4SLinus Torvalds  * Write command to Controller Registers
2901da177e4SLinus Torvalds  * -----------------------------------------------------------------*/
snd_es1938_write_cmd(struct es1938 * chip,unsigned char cmd)291e571f594STakashi Iwai static void snd_es1938_write_cmd(struct es1938 *chip, unsigned char cmd)
2921da177e4SLinus Torvalds {
2931da177e4SLinus Torvalds 	int i;
2941da177e4SLinus Torvalds 	unsigned char v;
2951da177e4SLinus Torvalds 	for (i = 0; i < WRITE_LOOP_TIMEOUT; i++) {
2963dc52815STakashi Iwai 		v = inb(SLSB_REG(chip, READSTATUS));
2973dc52815STakashi Iwai 		if (!(v & 0x80)) {
2981da177e4SLinus Torvalds 			outb(cmd, SLSB_REG(chip, WRITEDATA));
2991da177e4SLinus Torvalds 			return;
3001da177e4SLinus Torvalds 		}
3011da177e4SLinus Torvalds 	}
302ebebecaaSTakashi Iwai 	dev_err(chip->card->dev,
303ebebecaaSTakashi Iwai 		"snd_es1938_write_cmd timeout (0x02%x/0x02%x)\n", cmd, v);
3041da177e4SLinus Torvalds }
3051da177e4SLinus Torvalds 
3061da177e4SLinus Torvalds /* -----------------------------------------------------------------
3071da177e4SLinus Torvalds  * Read the Read Data Buffer
3081da177e4SLinus Torvalds  * -----------------------------------------------------------------*/
snd_es1938_get_byte(struct es1938 * chip)309e571f594STakashi Iwai static int snd_es1938_get_byte(struct es1938 *chip)
3101da177e4SLinus Torvalds {
3111da177e4SLinus Torvalds 	int i;
3121da177e4SLinus Torvalds 	unsigned char v;
3133dc52815STakashi Iwai 	for (i = GET_LOOP_TIMEOUT; i; i--) {
3143dc52815STakashi Iwai 		v = inb(SLSB_REG(chip, STATUS));
3153dc52815STakashi Iwai 		if (v & 0x80)
3161da177e4SLinus Torvalds 			return inb(SLSB_REG(chip, READDATA));
3173dc52815STakashi Iwai 	}
318ebebecaaSTakashi Iwai 	dev_err(chip->card->dev, "get_byte timeout: status 0x02%x\n", v);
3191da177e4SLinus Torvalds 	return -ENODEV;
3201da177e4SLinus Torvalds }
3211da177e4SLinus Torvalds 
3221da177e4SLinus Torvalds /* -----------------------------------------------------------------
3231da177e4SLinus Torvalds  * Write value cmd register
3241da177e4SLinus Torvalds  * -----------------------------------------------------------------*/
snd_es1938_write(struct es1938 * chip,unsigned char reg,unsigned char val)325e571f594STakashi Iwai static void snd_es1938_write(struct es1938 *chip, unsigned char reg, unsigned char val)
3261da177e4SLinus Torvalds {
3271da177e4SLinus Torvalds 	unsigned long flags;
3281da177e4SLinus Torvalds 	spin_lock_irqsave(&chip->reg_lock, flags);
3291da177e4SLinus Torvalds 	snd_es1938_write_cmd(chip, reg);
3301da177e4SLinus Torvalds 	snd_es1938_write_cmd(chip, val);
3311da177e4SLinus Torvalds 	spin_unlock_irqrestore(&chip->reg_lock, flags);
332ebebecaaSTakashi Iwai 	dev_dbg(chip->card->dev, "Reg %02x set to %02x\n", reg, val);
3331da177e4SLinus Torvalds }
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds /* -----------------------------------------------------------------
3361da177e4SLinus Torvalds  * Read data from cmd register and return it
3371da177e4SLinus Torvalds  * -----------------------------------------------------------------*/
snd_es1938_read(struct es1938 * chip,unsigned char reg)338e571f594STakashi Iwai static unsigned char snd_es1938_read(struct es1938 *chip, unsigned char reg)
3391da177e4SLinus Torvalds {
3401da177e4SLinus Torvalds 	unsigned char val;
3411da177e4SLinus Torvalds 	unsigned long flags;
3421da177e4SLinus Torvalds 	spin_lock_irqsave(&chip->reg_lock, flags);
3431da177e4SLinus Torvalds 	snd_es1938_write_cmd(chip, ESS_CMD_READREG);
3441da177e4SLinus Torvalds 	snd_es1938_write_cmd(chip, reg);
3451da177e4SLinus Torvalds 	val = snd_es1938_get_byte(chip);
3461da177e4SLinus Torvalds 	spin_unlock_irqrestore(&chip->reg_lock, flags);
347ebebecaaSTakashi Iwai 	dev_dbg(chip->card->dev, "Reg %02x now is %02x\n", reg, val);
3481da177e4SLinus Torvalds 	return val;
3491da177e4SLinus Torvalds }
3501da177e4SLinus Torvalds 
3511da177e4SLinus Torvalds /* -----------------------------------------------------------------
3521da177e4SLinus Torvalds  * Write data to cmd register and return old value
3531da177e4SLinus Torvalds  * -----------------------------------------------------------------*/
snd_es1938_bits(struct es1938 * chip,unsigned char reg,unsigned char mask,unsigned char val)354e571f594STakashi Iwai static int snd_es1938_bits(struct es1938 *chip, unsigned char reg, unsigned char mask,
355e571f594STakashi Iwai 			   unsigned char val)
3561da177e4SLinus Torvalds {
3571da177e4SLinus Torvalds 	unsigned long flags;
3581da177e4SLinus Torvalds 	unsigned char old, new, oval;
3591da177e4SLinus Torvalds 	spin_lock_irqsave(&chip->reg_lock, flags);
3601da177e4SLinus Torvalds 	snd_es1938_write_cmd(chip, ESS_CMD_READREG);
3611da177e4SLinus Torvalds 	snd_es1938_write_cmd(chip, reg);
3621da177e4SLinus Torvalds 	old = snd_es1938_get_byte(chip);
3631da177e4SLinus Torvalds 	oval = old & mask;
3641da177e4SLinus Torvalds 	if (val != oval) {
3651da177e4SLinus Torvalds 		snd_es1938_write_cmd(chip, reg);
3661da177e4SLinus Torvalds 		new = (old & ~mask) | (val & mask);
3671da177e4SLinus Torvalds 		snd_es1938_write_cmd(chip, new);
368ebebecaaSTakashi Iwai 		dev_dbg(chip->card->dev, "Reg %02x was %02x, set to %02x\n",
36999b359baSTakashi Iwai 			   reg, old, new);
3701da177e4SLinus Torvalds 	}
3711da177e4SLinus Torvalds 	spin_unlock_irqrestore(&chip->reg_lock, flags);
3721da177e4SLinus Torvalds 	return oval;
3731da177e4SLinus Torvalds }
3741da177e4SLinus Torvalds 
3751da177e4SLinus Torvalds /* --------------------------------------------------------------------
3761da177e4SLinus Torvalds  * Reset the chip
3771da177e4SLinus Torvalds  * --------------------------------------------------------------------*/
snd_es1938_reset(struct es1938 * chip)378e571f594STakashi Iwai static void snd_es1938_reset(struct es1938 *chip)
3791da177e4SLinus Torvalds {
3801da177e4SLinus Torvalds 	int i;
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 	outb(3, SLSB_REG(chip, RESET));
3831da177e4SLinus Torvalds 	inb(SLSB_REG(chip, RESET));
3841da177e4SLinus Torvalds 	outb(0, SLSB_REG(chip, RESET));
3851da177e4SLinus Torvalds 	for (i = 0; i < RESET_LOOP_TIMEOUT; i++) {
3861da177e4SLinus Torvalds 		if (inb(SLSB_REG(chip, STATUS)) & 0x80) {
3871da177e4SLinus Torvalds 			if (inb(SLSB_REG(chip, READDATA)) == 0xaa)
3881da177e4SLinus Torvalds 				goto __next;
3891da177e4SLinus Torvalds 		}
3901da177e4SLinus Torvalds 	}
391ebebecaaSTakashi Iwai 	dev_err(chip->card->dev, "ESS Solo-1 reset failed\n");
3921da177e4SLinus Torvalds 
3931da177e4SLinus Torvalds      __next:
3941da177e4SLinus Torvalds 	snd_es1938_write_cmd(chip, ESS_CMD_ENABLEEXT);
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds 	/* Demand transfer DMA: 4 bytes per DMA request */
3971da177e4SLinus Torvalds 	snd_es1938_write(chip, ESS_CMD_DMATYPE, 2);
3981da177e4SLinus Torvalds 
3991da177e4SLinus Torvalds 	/* Change behaviour of register A1
4001da177e4SLinus Torvalds 	   4x oversampling
4011da177e4SLinus Torvalds 	   2nd channel DAC asynchronous */
4021da177e4SLinus Torvalds 	snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2MODE, 0x32);
4031da177e4SLinus Torvalds 	/* enable/select DMA channel and IRQ channel */
4041da177e4SLinus Torvalds 	snd_es1938_bits(chip, ESS_CMD_IRQCONTROL, 0xf0, 0x50);
4051da177e4SLinus Torvalds 	snd_es1938_bits(chip, ESS_CMD_DRQCONTROL, 0xf0, 0x50);
4061da177e4SLinus Torvalds 	snd_es1938_write_cmd(chip, ESS_CMD_ENABLEAUDIO1);
4071da177e4SLinus Torvalds 	/* Set spatializer parameters to recommended values */
4081da177e4SLinus Torvalds 	snd_es1938_mixer_write(chip, 0x54, 0x8f);
4091da177e4SLinus Torvalds 	snd_es1938_mixer_write(chip, 0x56, 0x95);
4101da177e4SLinus Torvalds 	snd_es1938_mixer_write(chip, 0x58, 0x94);
4111da177e4SLinus Torvalds 	snd_es1938_mixer_write(chip, 0x5a, 0x80);
4121da177e4SLinus Torvalds }
4131da177e4SLinus Torvalds 
4141da177e4SLinus Torvalds /* --------------------------------------------------------------------
4151da177e4SLinus Torvalds  * Reset the FIFOs
4161da177e4SLinus Torvalds  * --------------------------------------------------------------------*/
snd_es1938_reset_fifo(struct es1938 * chip)417e571f594STakashi Iwai static void snd_es1938_reset_fifo(struct es1938 *chip)
4181da177e4SLinus Torvalds {
4191da177e4SLinus Torvalds 	outb(2, SLSB_REG(chip, RESET));
4201da177e4SLinus Torvalds 	outb(0, SLSB_REG(chip, RESET));
4211da177e4SLinus Torvalds }
4221da177e4SLinus Torvalds 
42344d71507STakashi Iwai static const struct snd_ratnum clocks[2] = {
4241da177e4SLinus Torvalds 	{
4251da177e4SLinus Torvalds 		.num = 793800,
4261da177e4SLinus Torvalds 		.den_min = 1,
4271da177e4SLinus Torvalds 		.den_max = 128,
4281da177e4SLinus Torvalds 		.den_step = 1,
4291da177e4SLinus Torvalds 	},
4301da177e4SLinus Torvalds 	{
4311da177e4SLinus Torvalds 		.num = 768000,
4321da177e4SLinus Torvalds 		.den_min = 1,
4331da177e4SLinus Torvalds 		.den_max = 128,
4341da177e4SLinus Torvalds 		.den_step = 1,
4351da177e4SLinus Torvalds 	}
4361da177e4SLinus Torvalds };
4371da177e4SLinus Torvalds 
43844d71507STakashi Iwai static const struct snd_pcm_hw_constraint_ratnums hw_constraints_clocks = {
4391da177e4SLinus Torvalds 	.nrats = 2,
4401da177e4SLinus Torvalds 	.rats = clocks,
4411da177e4SLinus Torvalds };
4421da177e4SLinus Torvalds 
4431da177e4SLinus Torvalds 
snd_es1938_rate_set(struct es1938 * chip,struct snd_pcm_substream * substream,int mode)444e571f594STakashi Iwai static void snd_es1938_rate_set(struct es1938 *chip,
445e571f594STakashi Iwai 				struct snd_pcm_substream *substream,
4461da177e4SLinus Torvalds 				int mode)
4471da177e4SLinus Torvalds {
4481da177e4SLinus Torvalds 	unsigned int bits, div0;
449e571f594STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
4501da177e4SLinus Torvalds 	if (runtime->rate_num == clocks[0].num)
4511da177e4SLinus Torvalds 		bits = 128 - runtime->rate_den;
4521da177e4SLinus Torvalds 	else
4531da177e4SLinus Torvalds 		bits = 256 - runtime->rate_den;
4541da177e4SLinus Torvalds 
4551da177e4SLinus Torvalds 	/* set filter register */
4561da177e4SLinus Torvalds 	div0 = 256 - 7160000*20/(8*82*runtime->rate);
4571da177e4SLinus Torvalds 
4581da177e4SLinus Torvalds 	if (mode == DAC2) {
4591da177e4SLinus Torvalds 		snd_es1938_mixer_write(chip, 0x70, bits);
4601da177e4SLinus Torvalds 		snd_es1938_mixer_write(chip, 0x72, div0);
4611da177e4SLinus Torvalds 	} else {
4621da177e4SLinus Torvalds 		snd_es1938_write(chip, 0xA1, bits);
4631da177e4SLinus Torvalds 		snd_es1938_write(chip, 0xA2, div0);
4641da177e4SLinus Torvalds 	}
4651da177e4SLinus Torvalds }
4661da177e4SLinus Torvalds 
4671da177e4SLinus Torvalds /* --------------------------------------------------------------------
4681da177e4SLinus Torvalds  * Configure Solo1 builtin DMA Controller
4691da177e4SLinus Torvalds  * --------------------------------------------------------------------*/
4701da177e4SLinus Torvalds 
snd_es1938_playback1_setdma(struct es1938 * chip)471e571f594STakashi Iwai static void snd_es1938_playback1_setdma(struct es1938 *chip)
4721da177e4SLinus Torvalds {
4731da177e4SLinus Torvalds 	outb(0x00, SLIO_REG(chip, AUDIO2MODE));
4741da177e4SLinus Torvalds 	outl(chip->dma2_start, SLIO_REG(chip, AUDIO2DMAADDR));
4751da177e4SLinus Torvalds 	outw(0, SLIO_REG(chip, AUDIO2DMACOUNT));
4761da177e4SLinus Torvalds 	outw(chip->dma2_size, SLIO_REG(chip, AUDIO2DMACOUNT));
4771da177e4SLinus Torvalds }
4781da177e4SLinus Torvalds 
snd_es1938_playback2_setdma(struct es1938 * chip)479e571f594STakashi Iwai static void snd_es1938_playback2_setdma(struct es1938 *chip)
4801da177e4SLinus Torvalds {
4811da177e4SLinus Torvalds 	/* Enable DMA controller */
4821da177e4SLinus Torvalds 	outb(0xc4, SLDM_REG(chip, DMACOMMAND));
4831da177e4SLinus Torvalds 	/* 1. Master reset */
4841da177e4SLinus Torvalds 	outb(0, SLDM_REG(chip, DMACLEAR));
4851da177e4SLinus Torvalds 	/* 2. Mask DMA */
4861da177e4SLinus Torvalds 	outb(1, SLDM_REG(chip, DMAMASK));
4871da177e4SLinus Torvalds 	outb(0x18, SLDM_REG(chip, DMAMODE));
4881da177e4SLinus Torvalds 	outl(chip->dma1_start, SLDM_REG(chip, DMAADDR));
4891da177e4SLinus Torvalds 	outw(chip->dma1_size - 1, SLDM_REG(chip, DMACOUNT));
4901da177e4SLinus Torvalds 	/* 3. Unmask DMA */
4911da177e4SLinus Torvalds 	outb(0, SLDM_REG(chip, DMAMASK));
4921da177e4SLinus Torvalds }
4931da177e4SLinus Torvalds 
snd_es1938_capture_setdma(struct es1938 * chip)494e571f594STakashi Iwai static void snd_es1938_capture_setdma(struct es1938 *chip)
4951da177e4SLinus Torvalds {
4961da177e4SLinus Torvalds 	/* Enable DMA controller */
4971da177e4SLinus Torvalds 	outb(0xc4, SLDM_REG(chip, DMACOMMAND));
4981da177e4SLinus Torvalds 	/* 1. Master reset */
4991da177e4SLinus Torvalds 	outb(0, SLDM_REG(chip, DMACLEAR));
5001da177e4SLinus Torvalds 	/* 2. Mask DMA */
5011da177e4SLinus Torvalds 	outb(1, SLDM_REG(chip, DMAMASK));
5021da177e4SLinus Torvalds 	outb(0x14, SLDM_REG(chip, DMAMODE));
5031da177e4SLinus Torvalds 	outl(chip->dma1_start, SLDM_REG(chip, DMAADDR));
50419e2e3c3SHermann Lauer 	chip->last_capture_dmaaddr = chip->dma1_start;
5051da177e4SLinus Torvalds 	outw(chip->dma1_size - 1, SLDM_REG(chip, DMACOUNT));
5061da177e4SLinus Torvalds 	/* 3. Unmask DMA */
5071da177e4SLinus Torvalds 	outb(0, SLDM_REG(chip, DMAMASK));
5081da177e4SLinus Torvalds }
5091da177e4SLinus Torvalds 
5101da177e4SLinus Torvalds /* ----------------------------------------------------------------------
5111da177e4SLinus Torvalds  *
5121da177e4SLinus Torvalds  *                           *** PCM part ***
5131da177e4SLinus Torvalds  */
5141da177e4SLinus Torvalds 
snd_es1938_capture_trigger(struct snd_pcm_substream * substream,int cmd)515e571f594STakashi Iwai static int snd_es1938_capture_trigger(struct snd_pcm_substream *substream,
5161da177e4SLinus Torvalds 				      int cmd)
5171da177e4SLinus Torvalds {
518e571f594STakashi Iwai 	struct es1938 *chip = snd_pcm_substream_chip(substream);
5191da177e4SLinus Torvalds 	int val;
5201da177e4SLinus Torvalds 	switch (cmd) {
5211da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_START:
52293b9f426STakashi Iwai 	case SNDRV_PCM_TRIGGER_RESUME:
5231da177e4SLinus Torvalds 		val = 0x0f;
5241da177e4SLinus Torvalds 		chip->active |= ADC1;
5251da177e4SLinus Torvalds 		break;
5261da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_STOP:
52793b9f426STakashi Iwai 	case SNDRV_PCM_TRIGGER_SUSPEND:
5281da177e4SLinus Torvalds 		val = 0x00;
5291da177e4SLinus Torvalds 		chip->active &= ~ADC1;
5301da177e4SLinus Torvalds 		break;
5311da177e4SLinus Torvalds 	default:
5321da177e4SLinus Torvalds 		return -EINVAL;
5331da177e4SLinus Torvalds 	}
5341da177e4SLinus Torvalds 	snd_es1938_write(chip, ESS_CMD_DMACONTROL, val);
5351da177e4SLinus Torvalds 	return 0;
5361da177e4SLinus Torvalds }
5371da177e4SLinus Torvalds 
snd_es1938_playback1_trigger(struct snd_pcm_substream * substream,int cmd)538e571f594STakashi Iwai static int snd_es1938_playback1_trigger(struct snd_pcm_substream *substream,
5391da177e4SLinus Torvalds 					int cmd)
5401da177e4SLinus Torvalds {
541e571f594STakashi Iwai 	struct es1938 *chip = snd_pcm_substream_chip(substream);
5421da177e4SLinus Torvalds 	switch (cmd) {
5431da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_START:
54493b9f426STakashi Iwai 	case SNDRV_PCM_TRIGGER_RESUME:
5451da177e4SLinus Torvalds 		/* According to the documentation this should be:
5461da177e4SLinus Torvalds 		   0x13 but that value may randomly swap stereo channels */
5471da177e4SLinus Torvalds                 snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2CONTROL1, 0x92);
5481da177e4SLinus Torvalds                 udelay(10);
5491da177e4SLinus Torvalds 		snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2CONTROL1, 0x93);
5501da177e4SLinus Torvalds                 /* This two stage init gives the FIFO -> DAC connection time to
5511da177e4SLinus Torvalds                  * settle before first data from DMA flows in.  This should ensure
5521da177e4SLinus Torvalds                  * no swapping of stereo channels.  Report a bug if otherwise :-) */
5531da177e4SLinus Torvalds 		outb(0x0a, SLIO_REG(chip, AUDIO2MODE));
5541da177e4SLinus Torvalds 		chip->active |= DAC2;
5551da177e4SLinus Torvalds 		break;
5561da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_STOP:
55793b9f426STakashi Iwai 	case SNDRV_PCM_TRIGGER_SUSPEND:
5581da177e4SLinus Torvalds 		outb(0, SLIO_REG(chip, AUDIO2MODE));
5591da177e4SLinus Torvalds 		snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2CONTROL1, 0);
5601da177e4SLinus Torvalds 		chip->active &= ~DAC2;
5611da177e4SLinus Torvalds 		break;
5621da177e4SLinus Torvalds 	default:
5631da177e4SLinus Torvalds 		return -EINVAL;
5641da177e4SLinus Torvalds 	}
5651da177e4SLinus Torvalds 	return 0;
5661da177e4SLinus Torvalds }
5671da177e4SLinus Torvalds 
snd_es1938_playback2_trigger(struct snd_pcm_substream * substream,int cmd)568e571f594STakashi Iwai static int snd_es1938_playback2_trigger(struct snd_pcm_substream *substream,
5691da177e4SLinus Torvalds 					int cmd)
5701da177e4SLinus Torvalds {
571e571f594STakashi Iwai 	struct es1938 *chip = snd_pcm_substream_chip(substream);
5721da177e4SLinus Torvalds 	int val;
5731da177e4SLinus Torvalds 	switch (cmd) {
5741da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_START:
57593b9f426STakashi Iwai 	case SNDRV_PCM_TRIGGER_RESUME:
5761da177e4SLinus Torvalds 		val = 5;
5771da177e4SLinus Torvalds 		chip->active |= DAC1;
5781da177e4SLinus Torvalds 		break;
5791da177e4SLinus Torvalds 	case SNDRV_PCM_TRIGGER_STOP:
58093b9f426STakashi Iwai 	case SNDRV_PCM_TRIGGER_SUSPEND:
5811da177e4SLinus Torvalds 		val = 0;
5821da177e4SLinus Torvalds 		chip->active &= ~DAC1;
5831da177e4SLinus Torvalds 		break;
5841da177e4SLinus Torvalds 	default:
5851da177e4SLinus Torvalds 		return -EINVAL;
5861da177e4SLinus Torvalds 	}
5871da177e4SLinus Torvalds 	snd_es1938_write(chip, ESS_CMD_DMACONTROL, val);
5881da177e4SLinus Torvalds 	return 0;
5891da177e4SLinus Torvalds }
5901da177e4SLinus Torvalds 
snd_es1938_playback_trigger(struct snd_pcm_substream * substream,int cmd)591e571f594STakashi Iwai static int snd_es1938_playback_trigger(struct snd_pcm_substream *substream,
5921da177e4SLinus Torvalds 				       int cmd)
5931da177e4SLinus Torvalds {
5941da177e4SLinus Torvalds 	switch (substream->number) {
5951da177e4SLinus Torvalds 	case 0:
5961da177e4SLinus Torvalds 		return snd_es1938_playback1_trigger(substream, cmd);
5971da177e4SLinus Torvalds 	case 1:
5981da177e4SLinus Torvalds 		return snd_es1938_playback2_trigger(substream, cmd);
5991da177e4SLinus Torvalds 	}
6001da177e4SLinus Torvalds 	snd_BUG();
6011da177e4SLinus Torvalds 	return -EINVAL;
6021da177e4SLinus Torvalds }
6031da177e4SLinus Torvalds 
6041da177e4SLinus Torvalds /* --------------------------------------------------------------------
6051da177e4SLinus Torvalds  * First channel for Extended Mode Audio 1 ADC Operation
6061da177e4SLinus Torvalds  * --------------------------------------------------------------------*/
snd_es1938_capture_prepare(struct snd_pcm_substream * substream)607e571f594STakashi Iwai static int snd_es1938_capture_prepare(struct snd_pcm_substream *substream)
6081da177e4SLinus Torvalds {
609e571f594STakashi Iwai 	struct es1938 *chip = snd_pcm_substream_chip(substream);
610e571f594STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
6111da177e4SLinus Torvalds 	int u, is8, mono;
6121da177e4SLinus Torvalds 	unsigned int size = snd_pcm_lib_buffer_bytes(substream);
6131da177e4SLinus Torvalds 	unsigned int count = snd_pcm_lib_period_bytes(substream);
6141da177e4SLinus Torvalds 
6151da177e4SLinus Torvalds 	chip->dma1_size = size;
6161da177e4SLinus Torvalds 	chip->dma1_start = runtime->dma_addr;
6171da177e4SLinus Torvalds 
6181da177e4SLinus Torvalds 	mono = (runtime->channels > 1) ? 0 : 1;
6191da177e4SLinus Torvalds 	is8 = snd_pcm_format_width(runtime->format) == 16 ? 0 : 1;
6201da177e4SLinus Torvalds 	u = snd_pcm_format_unsigned(runtime->format);
6211da177e4SLinus Torvalds 
6221da177e4SLinus Torvalds 	chip->dma1_shift = 2 - mono - is8;
6231da177e4SLinus Torvalds 
6241da177e4SLinus Torvalds 	snd_es1938_reset_fifo(chip);
6251da177e4SLinus Torvalds 
6261da177e4SLinus Torvalds 	/* program type */
6271da177e4SLinus Torvalds 	snd_es1938_bits(chip, ESS_CMD_ANALOGCONTROL, 0x03, (mono ? 2 : 1));
6281da177e4SLinus Torvalds 
6291da177e4SLinus Torvalds 	/* set clock and counters */
6301da177e4SLinus Torvalds         snd_es1938_rate_set(chip, substream, ADC1);
6311da177e4SLinus Torvalds 
6321da177e4SLinus Torvalds 	count = 0x10000 - count;
6331da177e4SLinus Torvalds 	snd_es1938_write(chip, ESS_CMD_DMACNTRELOADL, count & 0xff);
6341da177e4SLinus Torvalds 	snd_es1938_write(chip, ESS_CMD_DMACNTRELOADH, count >> 8);
6351da177e4SLinus Torvalds 
6361da177e4SLinus Torvalds 	/* initialize and configure ADC */
6371da177e4SLinus Torvalds 	snd_es1938_write(chip, ESS_CMD_SETFORMAT2, u ? 0x51 : 0x71);
6381da177e4SLinus Torvalds 	snd_es1938_write(chip, ESS_CMD_SETFORMAT2, 0x90 |
6391da177e4SLinus Torvalds 		       (u ? 0x00 : 0x20) |
6401da177e4SLinus Torvalds 		       (is8 ? 0x00 : 0x04) |
6411da177e4SLinus Torvalds 		       (mono ? 0x40 : 0x08));
6421da177e4SLinus Torvalds 
6431da177e4SLinus Torvalds 	//	snd_es1938_reset_fifo(chip);
6441da177e4SLinus Torvalds 
6451da177e4SLinus Torvalds 	/* 11. configure system interrupt controller and DMA controller */
6461da177e4SLinus Torvalds 	snd_es1938_capture_setdma(chip);
6471da177e4SLinus Torvalds 
6481da177e4SLinus Torvalds 	return 0;
6491da177e4SLinus Torvalds }
6501da177e4SLinus Torvalds 
6511da177e4SLinus Torvalds 
6521da177e4SLinus Torvalds /* ------------------------------------------------------------------------------
6531da177e4SLinus Torvalds  * Second Audio channel DAC Operation
6541da177e4SLinus Torvalds  * ------------------------------------------------------------------------------*/
snd_es1938_playback1_prepare(struct snd_pcm_substream * substream)655e571f594STakashi Iwai static int snd_es1938_playback1_prepare(struct snd_pcm_substream *substream)
6561da177e4SLinus Torvalds {
657e571f594STakashi Iwai 	struct es1938 *chip = snd_pcm_substream_chip(substream);
658e571f594STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
6591da177e4SLinus Torvalds 	int u, is8, mono;
6601da177e4SLinus Torvalds 	unsigned int size = snd_pcm_lib_buffer_bytes(substream);
6611da177e4SLinus Torvalds 	unsigned int count = snd_pcm_lib_period_bytes(substream);
6621da177e4SLinus Torvalds 
6631da177e4SLinus Torvalds 	chip->dma2_size = size;
6641da177e4SLinus Torvalds 	chip->dma2_start = runtime->dma_addr;
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds 	mono = (runtime->channels > 1) ? 0 : 1;
6671da177e4SLinus Torvalds 	is8 = snd_pcm_format_width(runtime->format) == 16 ? 0 : 1;
6681da177e4SLinus Torvalds 	u = snd_pcm_format_unsigned(runtime->format);
6691da177e4SLinus Torvalds 
6701da177e4SLinus Torvalds 	chip->dma2_shift = 2 - mono - is8;
6711da177e4SLinus Torvalds 
6721da177e4SLinus Torvalds         snd_es1938_reset_fifo(chip);
6731da177e4SLinus Torvalds 
6741da177e4SLinus Torvalds 	/* set clock and counters */
6751da177e4SLinus Torvalds         snd_es1938_rate_set(chip, substream, DAC2);
6761da177e4SLinus Torvalds 
6771da177e4SLinus Torvalds 	count >>= 1;
6781da177e4SLinus Torvalds 	count = 0x10000 - count;
6791da177e4SLinus Torvalds 	snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2TCOUNTL, count & 0xff);
6801da177e4SLinus Torvalds 	snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2TCOUNTH, count >> 8);
6811da177e4SLinus Torvalds 
6821da177e4SLinus Torvalds 	/* initialize and configure Audio 2 DAC */
683e571f594STakashi Iwai 	snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2CONTROL2, 0x40 | (u ? 0 : 4) |
684e571f594STakashi Iwai 			       (mono ? 0 : 2) | (is8 ? 0 : 1));
6851da177e4SLinus Torvalds 
6861da177e4SLinus Torvalds 	/* program DMA */
6871da177e4SLinus Torvalds 	snd_es1938_playback1_setdma(chip);
6881da177e4SLinus Torvalds 
6891da177e4SLinus Torvalds 	return 0;
6901da177e4SLinus Torvalds }
6911da177e4SLinus Torvalds 
snd_es1938_playback2_prepare(struct snd_pcm_substream * substream)692e571f594STakashi Iwai static int snd_es1938_playback2_prepare(struct snd_pcm_substream *substream)
6931da177e4SLinus Torvalds {
694e571f594STakashi Iwai 	struct es1938 *chip = snd_pcm_substream_chip(substream);
695e571f594STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
6961da177e4SLinus Torvalds 	int u, is8, mono;
6971da177e4SLinus Torvalds 	unsigned int size = snd_pcm_lib_buffer_bytes(substream);
6981da177e4SLinus Torvalds 	unsigned int count = snd_pcm_lib_period_bytes(substream);
6991da177e4SLinus Torvalds 
7001da177e4SLinus Torvalds 	chip->dma1_size = size;
7011da177e4SLinus Torvalds 	chip->dma1_start = runtime->dma_addr;
7021da177e4SLinus Torvalds 
7031da177e4SLinus Torvalds 	mono = (runtime->channels > 1) ? 0 : 1;
7041da177e4SLinus Torvalds 	is8 = snd_pcm_format_width(runtime->format) == 16 ? 0 : 1;
7051da177e4SLinus Torvalds 	u = snd_pcm_format_unsigned(runtime->format);
7061da177e4SLinus Torvalds 
7071da177e4SLinus Torvalds 	chip->dma1_shift = 2 - mono - is8;
7081da177e4SLinus Torvalds 
7091da177e4SLinus Torvalds 	count = 0x10000 - count;
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds 	/* reset */
7121da177e4SLinus Torvalds 	snd_es1938_reset_fifo(chip);
7131da177e4SLinus Torvalds 
7141da177e4SLinus Torvalds 	snd_es1938_bits(chip, ESS_CMD_ANALOGCONTROL, 0x03, (mono ? 2 : 1));
7151da177e4SLinus Torvalds 
7161da177e4SLinus Torvalds 	/* set clock and counters */
7171da177e4SLinus Torvalds         snd_es1938_rate_set(chip, substream, DAC1);
7181da177e4SLinus Torvalds 	snd_es1938_write(chip, ESS_CMD_DMACNTRELOADL, count & 0xff);
7191da177e4SLinus Torvalds 	snd_es1938_write(chip, ESS_CMD_DMACNTRELOADH, count >> 8);
7201da177e4SLinus Torvalds 
7211da177e4SLinus Torvalds 	/* initialized and configure DAC */
7221da177e4SLinus Torvalds         snd_es1938_write(chip, ESS_CMD_SETFORMAT, u ? 0x80 : 0x00);
7231da177e4SLinus Torvalds         snd_es1938_write(chip, ESS_CMD_SETFORMAT, u ? 0x51 : 0x71);
7241da177e4SLinus Torvalds         snd_es1938_write(chip, ESS_CMD_SETFORMAT2,
7251da177e4SLinus Torvalds 			 0x90 | (mono ? 0x40 : 0x08) |
7261da177e4SLinus Torvalds 			 (is8 ? 0x00 : 0x04) | (u ? 0x00 : 0x20));
7271da177e4SLinus Torvalds 
7281da177e4SLinus Torvalds 	/* program DMA */
7291da177e4SLinus Torvalds 	snd_es1938_playback2_setdma(chip);
7301da177e4SLinus Torvalds 
7311da177e4SLinus Torvalds 	return 0;
7321da177e4SLinus Torvalds }
7331da177e4SLinus Torvalds 
snd_es1938_playback_prepare(struct snd_pcm_substream * substream)734e571f594STakashi Iwai static int snd_es1938_playback_prepare(struct snd_pcm_substream *substream)
7351da177e4SLinus Torvalds {
7361da177e4SLinus Torvalds 	switch (substream->number) {
7371da177e4SLinus Torvalds 	case 0:
7381da177e4SLinus Torvalds 		return snd_es1938_playback1_prepare(substream);
7391da177e4SLinus Torvalds 	case 1:
7401da177e4SLinus Torvalds 		return snd_es1938_playback2_prepare(substream);
7411da177e4SLinus Torvalds 	}
7421da177e4SLinus Torvalds 	snd_BUG();
7431da177e4SLinus Torvalds 	return -EINVAL;
7441da177e4SLinus Torvalds }
7451da177e4SLinus Torvalds 
74619e2e3c3SHermann Lauer /* during the incrementing of dma counters the DMA register reads sometimes
74719e2e3c3SHermann Lauer    returns garbage. To ensure a valid hw pointer, the following checks which
74819e2e3c3SHermann Lauer    should be very unlikely to fail are used:
74919e2e3c3SHermann Lauer    - is the current DMA address in the valid DMA range ?
75019e2e3c3SHermann Lauer    - is the sum of DMA address and DMA counter pointing to the last DMA byte ?
75119e2e3c3SHermann Lauer    One can argue this could differ by one byte depending on which register is
75219e2e3c3SHermann Lauer    updated first, so the implementation below allows for that.
75319e2e3c3SHermann Lauer */
snd_es1938_capture_pointer(struct snd_pcm_substream * substream)754e571f594STakashi Iwai static snd_pcm_uframes_t snd_es1938_capture_pointer(struct snd_pcm_substream *substream)
7551da177e4SLinus Torvalds {
756e571f594STakashi Iwai 	struct es1938 *chip = snd_pcm_substream_chip(substream);
7571da177e4SLinus Torvalds 	size_t ptr;
75819e2e3c3SHermann Lauer #if 0
7591da177e4SLinus Torvalds 	size_t old, new;
7601da177e4SLinus Torvalds 	/* This stuff is *needed*, don't ask why - AB */
7611da177e4SLinus Torvalds 	old = inw(SLDM_REG(chip, DMACOUNT));
7621da177e4SLinus Torvalds 	while ((new = inw(SLDM_REG(chip, DMACOUNT))) != old)
7631da177e4SLinus Torvalds 		old = new;
7641da177e4SLinus Torvalds 	ptr = chip->dma1_size - 1 - new;
7651da177e4SLinus Torvalds #else
76619e2e3c3SHermann Lauer 	size_t count;
76719e2e3c3SHermann Lauer 	unsigned int diff;
76819e2e3c3SHermann Lauer 
76919e2e3c3SHermann Lauer 	ptr = inl(SLDM_REG(chip, DMAADDR));
77019e2e3c3SHermann Lauer 	count = inw(SLDM_REG(chip, DMACOUNT));
77119e2e3c3SHermann Lauer 	diff = chip->dma1_start + chip->dma1_size - ptr - count;
77219e2e3c3SHermann Lauer 
77319e2e3c3SHermann Lauer 	if (diff > 3 || ptr < chip->dma1_start
77419e2e3c3SHermann Lauer 	      || ptr >= chip->dma1_start+chip->dma1_size)
77519e2e3c3SHermann Lauer 	  ptr = chip->last_capture_dmaaddr;            /* bad, use last saved */
77619e2e3c3SHermann Lauer 	else
77719e2e3c3SHermann Lauer 	  chip->last_capture_dmaaddr = ptr;            /* good, remember it */
77819e2e3c3SHermann Lauer 
77919e2e3c3SHermann Lauer 	ptr -= chip->dma1_start;
7801da177e4SLinus Torvalds #endif
7811da177e4SLinus Torvalds 	return ptr >> chip->dma1_shift;
7821da177e4SLinus Torvalds }
7831da177e4SLinus Torvalds 
snd_es1938_playback1_pointer(struct snd_pcm_substream * substream)784e571f594STakashi Iwai static snd_pcm_uframes_t snd_es1938_playback1_pointer(struct snd_pcm_substream *substream)
7851da177e4SLinus Torvalds {
786e571f594STakashi Iwai 	struct es1938 *chip = snd_pcm_substream_chip(substream);
7871da177e4SLinus Torvalds 	size_t ptr;
7881da177e4SLinus Torvalds #if 1
7891da177e4SLinus Torvalds 	ptr = chip->dma2_size - inw(SLIO_REG(chip, AUDIO2DMACOUNT));
7901da177e4SLinus Torvalds #else
7911da177e4SLinus Torvalds 	ptr = inl(SLIO_REG(chip, AUDIO2DMAADDR)) - chip->dma2_start;
7921da177e4SLinus Torvalds #endif
7931da177e4SLinus Torvalds 	return ptr >> chip->dma2_shift;
7941da177e4SLinus Torvalds }
7951da177e4SLinus Torvalds 
snd_es1938_playback2_pointer(struct snd_pcm_substream * substream)796e571f594STakashi Iwai static snd_pcm_uframes_t snd_es1938_playback2_pointer(struct snd_pcm_substream *substream)
7971da177e4SLinus Torvalds {
798e571f594STakashi Iwai 	struct es1938 *chip = snd_pcm_substream_chip(substream);
7991da177e4SLinus Torvalds 	size_t ptr;
8001da177e4SLinus Torvalds 	size_t old, new;
8011da177e4SLinus Torvalds #if 1
8021da177e4SLinus Torvalds 	/* This stuff is *needed*, don't ask why - AB */
8031da177e4SLinus Torvalds 	old = inw(SLDM_REG(chip, DMACOUNT));
8041da177e4SLinus Torvalds 	while ((new = inw(SLDM_REG(chip, DMACOUNT))) != old)
8051da177e4SLinus Torvalds 		old = new;
8061da177e4SLinus Torvalds 	ptr = chip->dma1_size - 1 - new;
8071da177e4SLinus Torvalds #else
8081da177e4SLinus Torvalds 	ptr = inl(SLDM_REG(chip, DMAADDR)) - chip->dma1_start;
8091da177e4SLinus Torvalds #endif
8101da177e4SLinus Torvalds 	return ptr >> chip->dma1_shift;
8111da177e4SLinus Torvalds }
8121da177e4SLinus Torvalds 
snd_es1938_playback_pointer(struct snd_pcm_substream * substream)813e571f594STakashi Iwai static snd_pcm_uframes_t snd_es1938_playback_pointer(struct snd_pcm_substream *substream)
8141da177e4SLinus Torvalds {
8151da177e4SLinus Torvalds 	switch (substream->number) {
8161da177e4SLinus Torvalds 	case 0:
8171da177e4SLinus Torvalds 		return snd_es1938_playback1_pointer(substream);
8181da177e4SLinus Torvalds 	case 1:
8191da177e4SLinus Torvalds 		return snd_es1938_playback2_pointer(substream);
8201da177e4SLinus Torvalds 	}
8211da177e4SLinus Torvalds 	snd_BUG();
8221da177e4SLinus Torvalds 	return -EINVAL;
8231da177e4SLinus Torvalds }
8241da177e4SLinus Torvalds 
snd_es1938_capture_copy(struct snd_pcm_substream * substream,int channel,unsigned long pos,struct iov_iter * dst,unsigned long count)825e571f594STakashi Iwai static int snd_es1938_capture_copy(struct snd_pcm_substream *substream,
826b96c3a15STakashi Iwai 				   int channel, unsigned long pos,
827*07ee02a2STakashi Iwai 				   struct iov_iter *dst, unsigned long count)
8281da177e4SLinus Torvalds {
829e571f594STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
830e571f594STakashi Iwai 	struct es1938 *chip = snd_pcm_substream_chip(substream);
831b96c3a15STakashi Iwai 
832da3cec35STakashi Iwai 	if (snd_BUG_ON(pos + count > chip->dma1_size))
833da3cec35STakashi Iwai 		return -EINVAL;
8341da177e4SLinus Torvalds 	if (pos + count < chip->dma1_size) {
835*07ee02a2STakashi Iwai 		if (copy_to_iter(runtime->dma_area + pos + 1, count, dst) != count)
8361da177e4SLinus Torvalds 			return -EFAULT;
8371da177e4SLinus Torvalds 	} else {
838*07ee02a2STakashi Iwai 		if (copy_to_iter(runtime->dma_area + pos + 1, count - 1, dst) != count - 1)
8391da177e4SLinus Torvalds 			return -EFAULT;
840*07ee02a2STakashi Iwai 		if (copy_to_iter(runtime->dma_area, 1, dst) != 1)
8411da177e4SLinus Torvalds 			return -EFAULT;
8421da177e4SLinus Torvalds 	}
8431da177e4SLinus Torvalds 	return 0;
8441da177e4SLinus Torvalds }
8451da177e4SLinus Torvalds 
8461da177e4SLinus Torvalds /* ----------------------------------------------------------------------
8471da177e4SLinus Torvalds  * Audio1 Capture (ADC)
8481da177e4SLinus Torvalds  * ----------------------------------------------------------------------*/
849dee49895SBhumika Goyal static const struct snd_pcm_hardware snd_es1938_capture =
8501da177e4SLinus Torvalds {
8511da177e4SLinus Torvalds 	.info =			(SNDRV_PCM_INFO_INTERLEAVED |
8521da177e4SLinus Torvalds 				SNDRV_PCM_INFO_BLOCK_TRANSFER),
853e571f594STakashi Iwai 	.formats =		(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
854e571f594STakashi Iwai 				 SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),
8551da177e4SLinus Torvalds 	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
8561da177e4SLinus Torvalds 	.rate_min =		6000,
8571da177e4SLinus Torvalds 	.rate_max =		48000,
8581da177e4SLinus Torvalds 	.channels_min =		1,
8591da177e4SLinus Torvalds 	.channels_max =		2,
8601da177e4SLinus Torvalds         .buffer_bytes_max =	0x8000,       /* DMA controller screws on higher values */
8611da177e4SLinus Torvalds 	.period_bytes_min =	64,
8621da177e4SLinus Torvalds 	.period_bytes_max =	0x8000,
8631da177e4SLinus Torvalds 	.periods_min =		1,
8641da177e4SLinus Torvalds 	.periods_max =		1024,
8651da177e4SLinus Torvalds 	.fifo_size =		256,
8661da177e4SLinus Torvalds };
8671da177e4SLinus Torvalds 
8681da177e4SLinus Torvalds /* -----------------------------------------------------------------------
8691da177e4SLinus Torvalds  * Audio2 Playback (DAC)
8701da177e4SLinus Torvalds  * -----------------------------------------------------------------------*/
871dee49895SBhumika Goyal static const struct snd_pcm_hardware snd_es1938_playback =
8721da177e4SLinus Torvalds {
8731da177e4SLinus Torvalds 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
8741da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
8751da177e4SLinus Torvalds 				 SNDRV_PCM_INFO_MMAP_VALID),
876e571f594STakashi Iwai 	.formats =		(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
877e571f594STakashi Iwai 				 SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),
8781da177e4SLinus Torvalds 	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
8791da177e4SLinus Torvalds 	.rate_min =		6000,
8801da177e4SLinus Torvalds 	.rate_max =		48000,
8811da177e4SLinus Torvalds 	.channels_min =		1,
8821da177e4SLinus Torvalds 	.channels_max =		2,
8831da177e4SLinus Torvalds         .buffer_bytes_max =	0x8000,       /* DMA controller screws on higher values */
8841da177e4SLinus Torvalds 	.period_bytes_min =	64,
8851da177e4SLinus Torvalds 	.period_bytes_max =	0x8000,
8861da177e4SLinus Torvalds 	.periods_min =		1,
8871da177e4SLinus Torvalds 	.periods_max =		1024,
8881da177e4SLinus Torvalds 	.fifo_size =		256,
8891da177e4SLinus Torvalds };
8901da177e4SLinus Torvalds 
snd_es1938_capture_open(struct snd_pcm_substream * substream)891e571f594STakashi Iwai static int snd_es1938_capture_open(struct snd_pcm_substream *substream)
8921da177e4SLinus Torvalds {
893e571f594STakashi Iwai 	struct es1938 *chip = snd_pcm_substream_chip(substream);
894e571f594STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
8951da177e4SLinus Torvalds 
8961da177e4SLinus Torvalds 	if (chip->playback2_substream)
8971da177e4SLinus Torvalds 		return -EAGAIN;
8981da177e4SLinus Torvalds 	chip->capture_substream = substream;
8991da177e4SLinus Torvalds 	runtime->hw = snd_es1938_capture;
9001da177e4SLinus Torvalds 	snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
9011da177e4SLinus Torvalds 				      &hw_constraints_clocks);
9021da177e4SLinus Torvalds 	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, 0xff00);
9031da177e4SLinus Torvalds 	return 0;
9041da177e4SLinus Torvalds }
9051da177e4SLinus Torvalds 
snd_es1938_playback_open(struct snd_pcm_substream * substream)906e571f594STakashi Iwai static int snd_es1938_playback_open(struct snd_pcm_substream *substream)
9071da177e4SLinus Torvalds {
908e571f594STakashi Iwai 	struct es1938 *chip = snd_pcm_substream_chip(substream);
909e571f594STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
9101da177e4SLinus Torvalds 
9111da177e4SLinus Torvalds 	switch (substream->number) {
9121da177e4SLinus Torvalds 	case 0:
9131da177e4SLinus Torvalds 		chip->playback1_substream = substream;
9141da177e4SLinus Torvalds 		break;
9151da177e4SLinus Torvalds 	case 1:
9161da177e4SLinus Torvalds 		if (chip->capture_substream)
9171da177e4SLinus Torvalds 			return -EAGAIN;
9181da177e4SLinus Torvalds 		chip->playback2_substream = substream;
9191da177e4SLinus Torvalds 		break;
9201da177e4SLinus Torvalds 	default:
9211da177e4SLinus Torvalds 		snd_BUG();
9221da177e4SLinus Torvalds 		return -EINVAL;
9231da177e4SLinus Torvalds 	}
9241da177e4SLinus Torvalds 	runtime->hw = snd_es1938_playback;
9251da177e4SLinus Torvalds 	snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
9261da177e4SLinus Torvalds 				      &hw_constraints_clocks);
9271da177e4SLinus Torvalds 	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, 0xff00);
9281da177e4SLinus Torvalds 	return 0;
9291da177e4SLinus Torvalds }
9301da177e4SLinus Torvalds 
snd_es1938_capture_close(struct snd_pcm_substream * substream)931e571f594STakashi Iwai static int snd_es1938_capture_close(struct snd_pcm_substream *substream)
9321da177e4SLinus Torvalds {
933e571f594STakashi Iwai 	struct es1938 *chip = snd_pcm_substream_chip(substream);
9341da177e4SLinus Torvalds 
9351da177e4SLinus Torvalds 	chip->capture_substream = NULL;
9361da177e4SLinus Torvalds 	return 0;
9371da177e4SLinus Torvalds }
9381da177e4SLinus Torvalds 
snd_es1938_playback_close(struct snd_pcm_substream * substream)939e571f594STakashi Iwai static int snd_es1938_playback_close(struct snd_pcm_substream *substream)
9401da177e4SLinus Torvalds {
941e571f594STakashi Iwai 	struct es1938 *chip = snd_pcm_substream_chip(substream);
9421da177e4SLinus Torvalds 
9431da177e4SLinus Torvalds 	switch (substream->number) {
9441da177e4SLinus Torvalds 	case 0:
9451da177e4SLinus Torvalds 		chip->playback1_substream = NULL;
9461da177e4SLinus Torvalds 		break;
9471da177e4SLinus Torvalds 	case 1:
9481da177e4SLinus Torvalds 		chip->playback2_substream = NULL;
9491da177e4SLinus Torvalds 		break;
9501da177e4SLinus Torvalds 	default:
9511da177e4SLinus Torvalds 		snd_BUG();
9521da177e4SLinus Torvalds 		return -EINVAL;
9531da177e4SLinus Torvalds 	}
9541da177e4SLinus Torvalds 	return 0;
9551da177e4SLinus Torvalds }
9561da177e4SLinus Torvalds 
9576769e988SJulia Lawall static const struct snd_pcm_ops snd_es1938_playback_ops = {
9581da177e4SLinus Torvalds 	.open =		snd_es1938_playback_open,
9591da177e4SLinus Torvalds 	.close =	snd_es1938_playback_close,
9601da177e4SLinus Torvalds 	.prepare =	snd_es1938_playback_prepare,
9611da177e4SLinus Torvalds 	.trigger =	snd_es1938_playback_trigger,
9621da177e4SLinus Torvalds 	.pointer =	snd_es1938_playback_pointer,
9631da177e4SLinus Torvalds };
9641da177e4SLinus Torvalds 
9656769e988SJulia Lawall static const struct snd_pcm_ops snd_es1938_capture_ops = {
9661da177e4SLinus Torvalds 	.open =		snd_es1938_capture_open,
9671da177e4SLinus Torvalds 	.close =	snd_es1938_capture_close,
9681da177e4SLinus Torvalds 	.prepare =	snd_es1938_capture_prepare,
9691da177e4SLinus Torvalds 	.trigger =	snd_es1938_capture_trigger,
9701da177e4SLinus Torvalds 	.pointer =	snd_es1938_capture_pointer,
971*07ee02a2STakashi Iwai 	.copy =		snd_es1938_capture_copy,
9721da177e4SLinus Torvalds };
9731da177e4SLinus Torvalds 
snd_es1938_new_pcm(struct es1938 * chip,int device)974e23e7a14SBill Pemberton static int snd_es1938_new_pcm(struct es1938 *chip, int device)
9751da177e4SLinus Torvalds {
976e571f594STakashi Iwai 	struct snd_pcm *pcm;
9771da177e4SLinus Torvalds 	int err;
9781da177e4SLinus Torvalds 
9793dc52815STakashi Iwai 	err = snd_pcm_new(chip->card, "es-1938-1946", device, 2, 1, &pcm);
9803dc52815STakashi Iwai 	if (err < 0)
9811da177e4SLinus Torvalds 		return err;
9821da177e4SLinus Torvalds 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_es1938_playback_ops);
9831da177e4SLinus Torvalds 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_es1938_capture_ops);
9841da177e4SLinus Torvalds 
9851da177e4SLinus Torvalds 	pcm->private_data = chip;
9861da177e4SLinus Torvalds 	pcm->info_flags = 0;
9871da177e4SLinus Torvalds 	strcpy(pcm->name, "ESS Solo-1");
9881da177e4SLinus Torvalds 
989d244a1dbSTakashi Iwai 	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
990d244a1dbSTakashi Iwai 				       &chip->pci->dev, 64*1024, 64*1024);
9911da177e4SLinus Torvalds 
9921da177e4SLinus Torvalds 	chip->pcm = pcm;
9931da177e4SLinus Torvalds 	return 0;
9941da177e4SLinus Torvalds }
9951da177e4SLinus Torvalds 
9961da177e4SLinus Torvalds /* -------------------------------------------------------------------
9971da177e4SLinus Torvalds  *
9981da177e4SLinus Torvalds  *                       *** Mixer part ***
9991da177e4SLinus Torvalds  */
10001da177e4SLinus Torvalds 
snd_es1938_info_mux(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1001e571f594STakashi Iwai static int snd_es1938_info_mux(struct snd_kcontrol *kcontrol,
1002e571f594STakashi Iwai 			       struct snd_ctl_elem_info *uinfo)
10031da177e4SLinus Torvalds {
10046b6b295eSTakashi Iwai 	static const char * const texts[8] = {
10051da177e4SLinus Torvalds 		"Mic", "Mic Master", "CD", "AOUT",
10061da177e4SLinus Torvalds 		"Mic1", "Mix", "Line", "Master"
10071da177e4SLinus Torvalds 	};
10081da177e4SLinus Torvalds 
10096b6b295eSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 8, texts);
10101da177e4SLinus Torvalds }
10111da177e4SLinus Torvalds 
snd_es1938_get_mux(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1012e571f594STakashi Iwai static int snd_es1938_get_mux(struct snd_kcontrol *kcontrol,
1013e571f594STakashi Iwai 			      struct snd_ctl_elem_value *ucontrol)
10141da177e4SLinus Torvalds {
1015e571f594STakashi Iwai 	struct es1938 *chip = snd_kcontrol_chip(kcontrol);
10161da177e4SLinus Torvalds 	ucontrol->value.enumerated.item[0] = snd_es1938_mixer_read(chip, 0x1c) & 0x07;
10171da177e4SLinus Torvalds 	return 0;
10181da177e4SLinus Torvalds }
10191da177e4SLinus Torvalds 
snd_es1938_put_mux(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1020e571f594STakashi Iwai static int snd_es1938_put_mux(struct snd_kcontrol *kcontrol,
1021e571f594STakashi Iwai 			      struct snd_ctl_elem_value *ucontrol)
10221da177e4SLinus Torvalds {
1023e571f594STakashi Iwai 	struct es1938 *chip = snd_kcontrol_chip(kcontrol);
10241da177e4SLinus Torvalds 	unsigned char val = ucontrol->value.enumerated.item[0];
10251da177e4SLinus Torvalds 
10261da177e4SLinus Torvalds 	if (val > 7)
10271da177e4SLinus Torvalds 		return -EINVAL;
10281da177e4SLinus Torvalds 	return snd_es1938_mixer_bits(chip, 0x1c, 0x07, val) != val;
10291da177e4SLinus Torvalds }
10301da177e4SLinus Torvalds 
1031a5ce8890STakashi Iwai #define snd_es1938_info_spatializer_enable	snd_ctl_boolean_mono_info
10321da177e4SLinus Torvalds 
snd_es1938_get_spatializer_enable(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1033e571f594STakashi Iwai static int snd_es1938_get_spatializer_enable(struct snd_kcontrol *kcontrol,
1034e571f594STakashi Iwai 					     struct snd_ctl_elem_value *ucontrol)
10351da177e4SLinus Torvalds {
1036e571f594STakashi Iwai 	struct es1938 *chip = snd_kcontrol_chip(kcontrol);
10371da177e4SLinus Torvalds 	unsigned char val = snd_es1938_mixer_read(chip, 0x50);
10381da177e4SLinus Torvalds 	ucontrol->value.integer.value[0] = !!(val & 8);
10391da177e4SLinus Torvalds 	return 0;
10401da177e4SLinus Torvalds }
10411da177e4SLinus Torvalds 
snd_es1938_put_spatializer_enable(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1042e571f594STakashi Iwai static int snd_es1938_put_spatializer_enable(struct snd_kcontrol *kcontrol,
1043e571f594STakashi Iwai 					     struct snd_ctl_elem_value *ucontrol)
10441da177e4SLinus Torvalds {
1045e571f594STakashi Iwai 	struct es1938 *chip = snd_kcontrol_chip(kcontrol);
10461da177e4SLinus Torvalds 	unsigned char oval, nval;
10471da177e4SLinus Torvalds 	int change;
10481da177e4SLinus Torvalds 	nval = ucontrol->value.integer.value[0] ? 0x0c : 0x04;
10491da177e4SLinus Torvalds 	oval = snd_es1938_mixer_read(chip, 0x50) & 0x0c;
10501da177e4SLinus Torvalds 	change = nval != oval;
10511da177e4SLinus Torvalds 	if (change) {
10521da177e4SLinus Torvalds 		snd_es1938_mixer_write(chip, 0x50, nval & ~0x04);
10531da177e4SLinus Torvalds 		snd_es1938_mixer_write(chip, 0x50, nval);
10541da177e4SLinus Torvalds 	}
10551da177e4SLinus Torvalds 	return change;
10561da177e4SLinus Torvalds }
10571da177e4SLinus Torvalds 
snd_es1938_info_hw_volume(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1058e571f594STakashi Iwai static int snd_es1938_info_hw_volume(struct snd_kcontrol *kcontrol,
1059e571f594STakashi Iwai 				     struct snd_ctl_elem_info *uinfo)
10601da177e4SLinus Torvalds {
10611da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
10621da177e4SLinus Torvalds 	uinfo->count = 2;
10631da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
10641da177e4SLinus Torvalds 	uinfo->value.integer.max = 63;
10651da177e4SLinus Torvalds 	return 0;
10661da177e4SLinus Torvalds }
10671da177e4SLinus Torvalds 
snd_es1938_get_hw_volume(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1068e571f594STakashi Iwai static int snd_es1938_get_hw_volume(struct snd_kcontrol *kcontrol,
1069e571f594STakashi Iwai 				    struct snd_ctl_elem_value *ucontrol)
10701da177e4SLinus Torvalds {
1071e571f594STakashi Iwai 	struct es1938 *chip = snd_kcontrol_chip(kcontrol);
10721da177e4SLinus Torvalds 	ucontrol->value.integer.value[0] = snd_es1938_mixer_read(chip, 0x61) & 0x3f;
10731da177e4SLinus Torvalds 	ucontrol->value.integer.value[1] = snd_es1938_mixer_read(chip, 0x63) & 0x3f;
10741da177e4SLinus Torvalds 	return 0;
10751da177e4SLinus Torvalds }
10761da177e4SLinus Torvalds 
1077a5ce8890STakashi Iwai #define snd_es1938_info_hw_switch		snd_ctl_boolean_stereo_info
10781da177e4SLinus Torvalds 
snd_es1938_get_hw_switch(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1079e571f594STakashi Iwai static int snd_es1938_get_hw_switch(struct snd_kcontrol *kcontrol,
1080e571f594STakashi Iwai 				    struct snd_ctl_elem_value *ucontrol)
10811da177e4SLinus Torvalds {
1082e571f594STakashi Iwai 	struct es1938 *chip = snd_kcontrol_chip(kcontrol);
10831da177e4SLinus Torvalds 	ucontrol->value.integer.value[0] = !(snd_es1938_mixer_read(chip, 0x61) & 0x40);
10841da177e4SLinus Torvalds 	ucontrol->value.integer.value[1] = !(snd_es1938_mixer_read(chip, 0x63) & 0x40);
10851da177e4SLinus Torvalds 	return 0;
10861da177e4SLinus Torvalds }
10871da177e4SLinus Torvalds 
snd_es1938_hwv_free(struct snd_kcontrol * kcontrol)1088e571f594STakashi Iwai static void snd_es1938_hwv_free(struct snd_kcontrol *kcontrol)
10891da177e4SLinus Torvalds {
1090e571f594STakashi Iwai 	struct es1938 *chip = snd_kcontrol_chip(kcontrol);
10911da177e4SLinus Torvalds 	chip->master_volume = NULL;
10921da177e4SLinus Torvalds 	chip->master_switch = NULL;
10931da177e4SLinus Torvalds 	chip->hw_volume = NULL;
10941da177e4SLinus Torvalds 	chip->hw_switch = NULL;
10951da177e4SLinus Torvalds }
10961da177e4SLinus Torvalds 
snd_es1938_reg_bits(struct es1938 * chip,unsigned char reg,unsigned char mask,unsigned char val)1097e571f594STakashi Iwai static int snd_es1938_reg_bits(struct es1938 *chip, unsigned char reg,
10981da177e4SLinus Torvalds 			       unsigned char mask, unsigned char val)
10991da177e4SLinus Torvalds {
11001da177e4SLinus Torvalds 	if (reg < 0xa0)
11011da177e4SLinus Torvalds 		return snd_es1938_mixer_bits(chip, reg, mask, val);
11021da177e4SLinus Torvalds 	else
11031da177e4SLinus Torvalds 		return snd_es1938_bits(chip, reg, mask, val);
11041da177e4SLinus Torvalds }
11051da177e4SLinus Torvalds 
snd_es1938_reg_read(struct es1938 * chip,unsigned char reg)1106e571f594STakashi Iwai static int snd_es1938_reg_read(struct es1938 *chip, unsigned char reg)
11071da177e4SLinus Torvalds {
11081da177e4SLinus Torvalds 	if (reg < 0xa0)
11091da177e4SLinus Torvalds 		return snd_es1938_mixer_read(chip, reg);
11101da177e4SLinus Torvalds 	else
11111da177e4SLinus Torvalds 		return snd_es1938_read(chip, reg);
11121da177e4SLinus Torvalds }
11131da177e4SLinus Torvalds 
11140b593972STakashi Iwai #define ES1938_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv)    \
11150b593972STakashi Iwai { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11160b593972STakashi Iwai   .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,\
11170b593972STakashi Iwai   .name = xname, .index = xindex, \
11180b593972STakashi Iwai   .info = snd_es1938_info_single, \
11190b593972STakashi Iwai   .get = snd_es1938_get_single, .put = snd_es1938_put_single, \
11200b593972STakashi Iwai   .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
11210b593972STakashi Iwai   .tlv = { .p = xtlv } }
11221da177e4SLinus Torvalds #define ES1938_SINGLE(xname, xindex, reg, shift, mask, invert) \
11231da177e4SLinus Torvalds { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
11241da177e4SLinus Torvalds   .info = snd_es1938_info_single, \
11251da177e4SLinus Torvalds   .get = snd_es1938_get_single, .put = snd_es1938_put_single, \
11261da177e4SLinus Torvalds   .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
11271da177e4SLinus Torvalds 
snd_es1938_info_single(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1128e571f594STakashi Iwai static int snd_es1938_info_single(struct snd_kcontrol *kcontrol,
1129e571f594STakashi Iwai 				  struct snd_ctl_elem_info *uinfo)
11301da177e4SLinus Torvalds {
11311da177e4SLinus Torvalds 	int mask = (kcontrol->private_value >> 16) & 0xff;
11321da177e4SLinus Torvalds 
11331da177e4SLinus Torvalds 	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
11341da177e4SLinus Torvalds 	uinfo->count = 1;
11351da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
11361da177e4SLinus Torvalds 	uinfo->value.integer.max = mask;
11371da177e4SLinus Torvalds 	return 0;
11381da177e4SLinus Torvalds }
11391da177e4SLinus Torvalds 
snd_es1938_get_single(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1140e571f594STakashi Iwai static int snd_es1938_get_single(struct snd_kcontrol *kcontrol,
1141e571f594STakashi Iwai 				 struct snd_ctl_elem_value *ucontrol)
11421da177e4SLinus Torvalds {
1143e571f594STakashi Iwai 	struct es1938 *chip = snd_kcontrol_chip(kcontrol);
11441da177e4SLinus Torvalds 	int reg = kcontrol->private_value & 0xff;
11451da177e4SLinus Torvalds 	int shift = (kcontrol->private_value >> 8) & 0xff;
11461da177e4SLinus Torvalds 	int mask = (kcontrol->private_value >> 16) & 0xff;
11471da177e4SLinus Torvalds 	int invert = (kcontrol->private_value >> 24) & 0xff;
11481da177e4SLinus Torvalds 	int val;
11491da177e4SLinus Torvalds 
11501da177e4SLinus Torvalds 	val = snd_es1938_reg_read(chip, reg);
11511da177e4SLinus Torvalds 	ucontrol->value.integer.value[0] = (val >> shift) & mask;
11521da177e4SLinus Torvalds 	if (invert)
11531da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
11541da177e4SLinus Torvalds 	return 0;
11551da177e4SLinus Torvalds }
11561da177e4SLinus Torvalds 
snd_es1938_put_single(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1157e571f594STakashi Iwai static int snd_es1938_put_single(struct snd_kcontrol *kcontrol,
1158e571f594STakashi Iwai 				 struct snd_ctl_elem_value *ucontrol)
11591da177e4SLinus Torvalds {
1160e571f594STakashi Iwai 	struct es1938 *chip = snd_kcontrol_chip(kcontrol);
11611da177e4SLinus Torvalds 	int reg = kcontrol->private_value & 0xff;
11621da177e4SLinus Torvalds 	int shift = (kcontrol->private_value >> 8) & 0xff;
11631da177e4SLinus Torvalds 	int mask = (kcontrol->private_value >> 16) & 0xff;
11641da177e4SLinus Torvalds 	int invert = (kcontrol->private_value >> 24) & 0xff;
11651da177e4SLinus Torvalds 	unsigned char val;
11661da177e4SLinus Torvalds 
11671da177e4SLinus Torvalds 	val = (ucontrol->value.integer.value[0] & mask);
11681da177e4SLinus Torvalds 	if (invert)
11691da177e4SLinus Torvalds 		val = mask - val;
11701da177e4SLinus Torvalds 	mask <<= shift;
11711da177e4SLinus Torvalds 	val <<= shift;
11721da177e4SLinus Torvalds 	return snd_es1938_reg_bits(chip, reg, mask, val) != val;
11731da177e4SLinus Torvalds }
11741da177e4SLinus Torvalds 
11750b593972STakashi Iwai #define ES1938_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \
11760b593972STakashi Iwai { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11770b593972STakashi Iwai   .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,\
11780b593972STakashi Iwai   .name = xname, .index = xindex, \
11790b593972STakashi Iwai   .info = snd_es1938_info_double, \
11800b593972STakashi Iwai   .get = snd_es1938_get_double, .put = snd_es1938_put_double, \
11810b593972STakashi Iwai   .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22), \
11820b593972STakashi Iwai   .tlv = { .p = xtlv } }
11831da177e4SLinus Torvalds #define ES1938_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
11841da177e4SLinus Torvalds { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
11851da177e4SLinus Torvalds   .info = snd_es1938_info_double, \
11861da177e4SLinus Torvalds   .get = snd_es1938_get_double, .put = snd_es1938_put_double, \
11871da177e4SLinus Torvalds   .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
11881da177e4SLinus Torvalds 
snd_es1938_info_double(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1189e571f594STakashi Iwai static int snd_es1938_info_double(struct snd_kcontrol *kcontrol,
1190e571f594STakashi Iwai 				  struct snd_ctl_elem_info *uinfo)
11911da177e4SLinus Torvalds {
11921da177e4SLinus Torvalds 	int mask = (kcontrol->private_value >> 24) & 0xff;
11931da177e4SLinus Torvalds 
11941da177e4SLinus Torvalds 	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
11951da177e4SLinus Torvalds 	uinfo->count = 2;
11961da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
11971da177e4SLinus Torvalds 	uinfo->value.integer.max = mask;
11981da177e4SLinus Torvalds 	return 0;
11991da177e4SLinus Torvalds }
12001da177e4SLinus Torvalds 
snd_es1938_get_double(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1201e571f594STakashi Iwai static int snd_es1938_get_double(struct snd_kcontrol *kcontrol,
1202e571f594STakashi Iwai 				 struct snd_ctl_elem_value *ucontrol)
12031da177e4SLinus Torvalds {
1204e571f594STakashi Iwai 	struct es1938 *chip = snd_kcontrol_chip(kcontrol);
12051da177e4SLinus Torvalds 	int left_reg = kcontrol->private_value & 0xff;
12061da177e4SLinus Torvalds 	int right_reg = (kcontrol->private_value >> 8) & 0xff;
12071da177e4SLinus Torvalds 	int shift_left = (kcontrol->private_value >> 16) & 0x07;
12081da177e4SLinus Torvalds 	int shift_right = (kcontrol->private_value >> 19) & 0x07;
12091da177e4SLinus Torvalds 	int mask = (kcontrol->private_value >> 24) & 0xff;
12101da177e4SLinus Torvalds 	int invert = (kcontrol->private_value >> 22) & 1;
12111da177e4SLinus Torvalds 	unsigned char left, right;
12121da177e4SLinus Torvalds 
12131da177e4SLinus Torvalds 	left = snd_es1938_reg_read(chip, left_reg);
12141da177e4SLinus Torvalds 	if (left_reg != right_reg)
12151da177e4SLinus Torvalds 		right = snd_es1938_reg_read(chip, right_reg);
12161da177e4SLinus Torvalds 	else
12171da177e4SLinus Torvalds 		right = left;
12181da177e4SLinus Torvalds 	ucontrol->value.integer.value[0] = (left >> shift_left) & mask;
12191da177e4SLinus Torvalds 	ucontrol->value.integer.value[1] = (right >> shift_right) & mask;
12201da177e4SLinus Torvalds 	if (invert) {
12211da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
12221da177e4SLinus Torvalds 		ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
12231da177e4SLinus Torvalds 	}
12241da177e4SLinus Torvalds 	return 0;
12251da177e4SLinus Torvalds }
12261da177e4SLinus Torvalds 
snd_es1938_put_double(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1227e571f594STakashi Iwai static int snd_es1938_put_double(struct snd_kcontrol *kcontrol,
1228e571f594STakashi Iwai 				 struct snd_ctl_elem_value *ucontrol)
12291da177e4SLinus Torvalds {
1230e571f594STakashi Iwai 	struct es1938 *chip = snd_kcontrol_chip(kcontrol);
12311da177e4SLinus Torvalds 	int left_reg = kcontrol->private_value & 0xff;
12321da177e4SLinus Torvalds 	int right_reg = (kcontrol->private_value >> 8) & 0xff;
12331da177e4SLinus Torvalds 	int shift_left = (kcontrol->private_value >> 16) & 0x07;
12341da177e4SLinus Torvalds 	int shift_right = (kcontrol->private_value >> 19) & 0x07;
12351da177e4SLinus Torvalds 	int mask = (kcontrol->private_value >> 24) & 0xff;
12361da177e4SLinus Torvalds 	int invert = (kcontrol->private_value >> 22) & 1;
12371da177e4SLinus Torvalds 	int change;
12381da177e4SLinus Torvalds 	unsigned char val1, val2, mask1, mask2;
12391da177e4SLinus Torvalds 
12401da177e4SLinus Torvalds 	val1 = ucontrol->value.integer.value[0] & mask;
12411da177e4SLinus Torvalds 	val2 = ucontrol->value.integer.value[1] & mask;
12421da177e4SLinus Torvalds 	if (invert) {
12431da177e4SLinus Torvalds 		val1 = mask - val1;
12441da177e4SLinus Torvalds 		val2 = mask - val2;
12451da177e4SLinus Torvalds 	}
12461da177e4SLinus Torvalds 	val1 <<= shift_left;
12471da177e4SLinus Torvalds 	val2 <<= shift_right;
12481da177e4SLinus Torvalds 	mask1 = mask << shift_left;
12491da177e4SLinus Torvalds 	mask2 = mask << shift_right;
12501da177e4SLinus Torvalds 	if (left_reg != right_reg) {
12511da177e4SLinus Torvalds 		change = 0;
12521da177e4SLinus Torvalds 		if (snd_es1938_reg_bits(chip, left_reg, mask1, val1) != val1)
12531da177e4SLinus Torvalds 			change = 1;
12541da177e4SLinus Torvalds 		if (snd_es1938_reg_bits(chip, right_reg, mask2, val2) != val2)
12551da177e4SLinus Torvalds 			change = 1;
12561da177e4SLinus Torvalds 	} else {
12571da177e4SLinus Torvalds 		change = (snd_es1938_reg_bits(chip, left_reg, mask1 | mask2,
12581da177e4SLinus Torvalds 					      val1 | val2) != (val1 | val2));
12591da177e4SLinus Torvalds 	}
12601da177e4SLinus Torvalds 	return change;
12611da177e4SLinus Torvalds }
12621da177e4SLinus Torvalds 
1263093eef41SClemens Ladisch static const DECLARE_TLV_DB_RANGE(db_scale_master,
12640b593972STakashi Iwai 	0, 54, TLV_DB_SCALE_ITEM(-3600, 50, 1),
12650b593972STakashi Iwai 	54, 63, TLV_DB_SCALE_ITEM(-900, 100, 0),
1266093eef41SClemens Ladisch );
12670b593972STakashi Iwai 
1268093eef41SClemens Ladisch static const DECLARE_TLV_DB_RANGE(db_scale_audio1,
12690b593972STakashi Iwai 	0, 8, TLV_DB_SCALE_ITEM(-3300, 300, 1),
12700b593972STakashi Iwai 	8, 15, TLV_DB_SCALE_ITEM(-900, 150, 0),
1271093eef41SClemens Ladisch );
12720b593972STakashi Iwai 
1273093eef41SClemens Ladisch static const DECLARE_TLV_DB_RANGE(db_scale_audio2,
12740b593972STakashi Iwai 	0, 8, TLV_DB_SCALE_ITEM(-3450, 300, 1),
12750b593972STakashi Iwai 	8, 15, TLV_DB_SCALE_ITEM(-1050, 150, 0),
1276093eef41SClemens Ladisch );
12770b593972STakashi Iwai 
1278093eef41SClemens Ladisch static const DECLARE_TLV_DB_RANGE(db_scale_mic,
12790b593972STakashi Iwai 	0, 8, TLV_DB_SCALE_ITEM(-2400, 300, 1),
12800b593972STakashi Iwai 	8, 15, TLV_DB_SCALE_ITEM(0, 150, 0),
1281093eef41SClemens Ladisch );
12820b593972STakashi Iwai 
1283093eef41SClemens Ladisch static const DECLARE_TLV_DB_RANGE(db_scale_line,
12840b593972STakashi Iwai 	0, 8, TLV_DB_SCALE_ITEM(-3150, 300, 1),
12850b593972STakashi Iwai 	8, 15, TLV_DB_SCALE_ITEM(-750, 150, 0),
1286093eef41SClemens Ladisch );
12870b593972STakashi Iwai 
12880cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(db_scale_capture, 0, 150, 0);
12890b593972STakashi Iwai 
1290b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_es1938_controls[] = {
12910b593972STakashi Iwai ES1938_DOUBLE_TLV("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0,
12920b593972STakashi Iwai 		  db_scale_master),
12931da177e4SLinus Torvalds ES1938_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1),
12941da177e4SLinus Torvalds {
12951da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12961da177e4SLinus Torvalds 	.name = "Hardware Master Playback Volume",
12971da177e4SLinus Torvalds 	.access = SNDRV_CTL_ELEM_ACCESS_READ,
12981da177e4SLinus Torvalds 	.info = snd_es1938_info_hw_volume,
12991da177e4SLinus Torvalds 	.get = snd_es1938_get_hw_volume,
13001da177e4SLinus Torvalds },
13011da177e4SLinus Torvalds {
13021da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1303dbf91dd4SClemens Ladisch 	.access = (SNDRV_CTL_ELEM_ACCESS_READ |
13040b593972STakashi Iwai 		   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
13051da177e4SLinus Torvalds 	.name = "Hardware Master Playback Switch",
13061da177e4SLinus Torvalds 	.info = snd_es1938_info_hw_switch,
13071da177e4SLinus Torvalds 	.get = snd_es1938_get_hw_switch,
13080b593972STakashi Iwai 	.tlv = { .p = db_scale_master },
13091da177e4SLinus Torvalds },
13101da177e4SLinus Torvalds ES1938_SINGLE("Hardware Volume Split", 0, 0x64, 7, 1, 0),
13110b593972STakashi Iwai ES1938_DOUBLE_TLV("Line Playback Volume", 0, 0x3e, 0x3e, 4, 0, 15, 0,
13120b593972STakashi Iwai 		  db_scale_line),
13131da177e4SLinus Torvalds ES1938_DOUBLE("CD Playback Volume", 0, 0x38, 0x38, 4, 0, 15, 0),
13140b593972STakashi Iwai ES1938_DOUBLE_TLV("FM Playback Volume", 0, 0x36, 0x36, 4, 0, 15, 0,
13150b593972STakashi Iwai 		  db_scale_mic),
13160b593972STakashi Iwai ES1938_DOUBLE_TLV("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0,
13170b593972STakashi Iwai 		  db_scale_line),
13180b593972STakashi Iwai ES1938_DOUBLE_TLV("Mic Playback Volume", 0, 0x1a, 0x1a, 4, 0, 15, 0,
13190b593972STakashi Iwai 		  db_scale_mic),
13200b593972STakashi Iwai ES1938_DOUBLE_TLV("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0,
13210b593972STakashi Iwai 		  db_scale_line),
13220b593972STakashi Iwai ES1938_DOUBLE_TLV("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0,
13230b593972STakashi Iwai 		  db_scale_capture),
1324d355c82aSJaroslav Kysela ES1938_SINGLE("Beep Volume", 0, 0x3c, 0, 7, 0),
13251da177e4SLinus Torvalds ES1938_SINGLE("Record Monitor", 0, 0xa8, 3, 1, 0),
13261da177e4SLinus Torvalds ES1938_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
13271da177e4SLinus Torvalds {
13281da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13291da177e4SLinus Torvalds 	.name = "Capture Source",
13301da177e4SLinus Torvalds 	.info = snd_es1938_info_mux,
13311da177e4SLinus Torvalds 	.get = snd_es1938_get_mux,
13321da177e4SLinus Torvalds 	.put = snd_es1938_put_mux,
13331da177e4SLinus Torvalds },
13340b593972STakashi Iwai ES1938_DOUBLE_TLV("Mono Input Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0,
13350b593972STakashi Iwai 		  db_scale_line),
13360b593972STakashi Iwai ES1938_DOUBLE_TLV("PCM Capture Volume", 0, 0x69, 0x69, 4, 0, 15, 0,
13370b593972STakashi Iwai 		  db_scale_audio2),
13380b593972STakashi Iwai ES1938_DOUBLE_TLV("Mic Capture Volume", 0, 0x68, 0x68, 4, 0, 15, 0,
13390b593972STakashi Iwai 		  db_scale_mic),
13400b593972STakashi Iwai ES1938_DOUBLE_TLV("Line Capture Volume", 0, 0x6e, 0x6e, 4, 0, 15, 0,
13410b593972STakashi Iwai 		  db_scale_line),
13420b593972STakashi Iwai ES1938_DOUBLE_TLV("FM Capture Volume", 0, 0x6b, 0x6b, 4, 0, 15, 0,
13430b593972STakashi Iwai 		  db_scale_mic),
13440b593972STakashi Iwai ES1938_DOUBLE_TLV("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0,
13450b593972STakashi Iwai 		  db_scale_line),
13460b593972STakashi Iwai ES1938_DOUBLE_TLV("CD Capture Volume", 0, 0x6a, 0x6a, 4, 0, 15, 0,
13470b593972STakashi Iwai 		  db_scale_line),
13480b593972STakashi Iwai ES1938_DOUBLE_TLV("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0,
13490b593972STakashi Iwai 		  db_scale_line),
13500b593972STakashi Iwai ES1938_DOUBLE_TLV("PCM Playback Volume", 0, 0x7c, 0x7c, 4, 0, 15, 0,
13510b593972STakashi Iwai 		  db_scale_audio2),
13520b593972STakashi Iwai ES1938_DOUBLE_TLV("PCM Playback Volume", 1, 0x14, 0x14, 4, 0, 15, 0,
13530b593972STakashi Iwai 		  db_scale_audio1),
13541da177e4SLinus Torvalds ES1938_SINGLE("3D Control - Level", 0, 0x52, 0, 63, 0),
13551da177e4SLinus Torvalds {
13561da177e4SLinus Torvalds 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13571da177e4SLinus Torvalds 	.name = "3D Control - Switch",
13581da177e4SLinus Torvalds 	.info = snd_es1938_info_spatializer_enable,
13591da177e4SLinus Torvalds 	.get = snd_es1938_get_spatializer_enable,
13601da177e4SLinus Torvalds 	.put = snd_es1938_put_spatializer_enable,
13611da177e4SLinus Torvalds },
13621da177e4SLinus Torvalds ES1938_SINGLE("Mic Boost (+26dB)", 0, 0x7d, 3, 1, 0)
13631da177e4SLinus Torvalds };
13641da177e4SLinus Torvalds 
13651da177e4SLinus Torvalds 
13661da177e4SLinus Torvalds /* ---------------------------------------------------------------------------- */
13671da177e4SLinus Torvalds /* ---------------------------------------------------------------------------- */
13681da177e4SLinus Torvalds 
13691da177e4SLinus Torvalds /*
13701da177e4SLinus Torvalds  * initialize the chip - used by resume callback, too
13711da177e4SLinus Torvalds  */
snd_es1938_chip_init(struct es1938 * chip)1372e571f594STakashi Iwai static void snd_es1938_chip_init(struct es1938 *chip)
13731da177e4SLinus Torvalds {
13741da177e4SLinus Torvalds 	/* reset chip */
13751da177e4SLinus Torvalds 	snd_es1938_reset(chip);
13761da177e4SLinus Torvalds 
13771da177e4SLinus Torvalds 	/* configure native mode */
13781da177e4SLinus Torvalds 
13791da177e4SLinus Torvalds 	/* enable bus master */
13801da177e4SLinus Torvalds 	pci_set_master(chip->pci);
13811da177e4SLinus Torvalds 
13821da177e4SLinus Torvalds 	/* disable legacy audio */
13831da177e4SLinus Torvalds 	pci_write_config_word(chip->pci, SL_PCI_LEGACYCONTROL, 0x805f);
13841da177e4SLinus Torvalds 
13851da177e4SLinus Torvalds 	/* set DDMA base */
13861da177e4SLinus Torvalds 	pci_write_config_word(chip->pci, SL_PCI_DDMACONTROL, chip->ddma_port | 1);
13871da177e4SLinus Torvalds 
13881da177e4SLinus Torvalds 	/* set DMA/IRQ policy */
13891da177e4SLinus Torvalds 	pci_write_config_dword(chip->pci, SL_PCI_CONFIG, 0);
13901da177e4SLinus Torvalds 
13911da177e4SLinus Torvalds 	/* enable Audio 1, Audio 2, MPU401 IRQ and HW volume IRQ*/
13921da177e4SLinus Torvalds 	outb(0xf0, SLIO_REG(chip, IRQCONTROL));
13931da177e4SLinus Torvalds 
13941da177e4SLinus Torvalds 	/* reset DMA */
13951da177e4SLinus Torvalds 	outb(0, SLDM_REG(chip, DMACLEAR));
13961da177e4SLinus Torvalds }
13971da177e4SLinus Torvalds 
1398c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
13991da177e4SLinus Torvalds /*
14001da177e4SLinus Torvalds  * PM support
14011da177e4SLinus Torvalds  */
14021da177e4SLinus Torvalds 
140396d5ebf2STakashi Iwai static const unsigned char saved_regs[SAVED_REG_SIZE+1] = {
14041da177e4SLinus Torvalds 	0x14, 0x1a, 0x1c, 0x3a, 0x3c, 0x3e, 0x36, 0x38,
14051da177e4SLinus Torvalds 	0x50, 0x52, 0x60, 0x61, 0x62, 0x63, 0x64, 0x68,
14061da177e4SLinus Torvalds 	0x69, 0x6a, 0x6b, 0x6d, 0x6e, 0x6f, 0x7c, 0x7d,
14071da177e4SLinus Torvalds 	0xa8, 0xb4,
14081da177e4SLinus Torvalds };
14091da177e4SLinus Torvalds 
14101da177e4SLinus Torvalds 
es1938_suspend(struct device * dev)141168cb2b55STakashi Iwai static int es1938_suspend(struct device *dev)
14121da177e4SLinus Torvalds {
141368cb2b55STakashi Iwai 	struct snd_card *card = dev_get_drvdata(dev);
1414b34a580eSTakashi Iwai 	struct es1938 *chip = card->private_data;
141596d5ebf2STakashi Iwai 	const unsigned char *s;
141696d5ebf2STakashi Iwai 	unsigned char *d;
14171da177e4SLinus Torvalds 
1418b34a580eSTakashi Iwai 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
14191da177e4SLinus Torvalds 
14201da177e4SLinus Torvalds 	/* save mixer-related registers */
14211da177e4SLinus Torvalds 	for (s = saved_regs, d = chip->saved_regs; *s; s++, d++)
14221da177e4SLinus Torvalds 		*d = snd_es1938_reg_read(chip, *s);
14231da177e4SLinus Torvalds 
14241da177e4SLinus Torvalds 	outb(0x00, SLIO_REG(chip, IRQCONTROL)); /* disable irqs */
142530b35399STakashi Iwai 	if (chip->irq >= 0) {
1426e571f594STakashi Iwai 		free_irq(chip->irq, chip);
142730b35399STakashi Iwai 		chip->irq = -1;
14286b276e62STakashi Iwai 		card->sync_irq = -1;
142930b35399STakashi Iwai 	}
14301da177e4SLinus Torvalds 	return 0;
14311da177e4SLinus Torvalds }
14321da177e4SLinus Torvalds 
es1938_resume(struct device * dev)143368cb2b55STakashi Iwai static int es1938_resume(struct device *dev)
14341da177e4SLinus Torvalds {
143568cb2b55STakashi Iwai 	struct pci_dev *pci = to_pci_dev(dev);
143668cb2b55STakashi Iwai 	struct snd_card *card = dev_get_drvdata(dev);
1437b34a580eSTakashi Iwai 	struct es1938 *chip = card->private_data;
143896d5ebf2STakashi Iwai 	const unsigned char *s;
143996d5ebf2STakashi Iwai 	unsigned char *d;
14401da177e4SLinus Torvalds 
144130b35399STakashi Iwai 	if (request_irq(pci->irq, snd_es1938_interrupt,
1442934c2b6dSTakashi Iwai 			IRQF_SHARED, KBUILD_MODNAME, chip)) {
1443ebebecaaSTakashi Iwai 		dev_err(dev, "unable to grab IRQ %d, disabling device\n",
1444ebebecaaSTakashi Iwai 			pci->irq);
144530b35399STakashi Iwai 		snd_card_disconnect(card);
144630b35399STakashi Iwai 		return -EIO;
144730b35399STakashi Iwai 	}
1448b34a580eSTakashi Iwai 	chip->irq = pci->irq;
14496b276e62STakashi Iwai 	card->sync_irq = chip->irq;
14501da177e4SLinus Torvalds 	snd_es1938_chip_init(chip);
14511da177e4SLinus Torvalds 
14521da177e4SLinus Torvalds 	/* restore mixer-related registers */
14531da177e4SLinus Torvalds 	for (s = saved_regs, d = chip->saved_regs; *s; s++, d++) {
14541da177e4SLinus Torvalds 		if (*s < 0xa0)
14551da177e4SLinus Torvalds 			snd_es1938_mixer_write(chip, *s, *d);
14561da177e4SLinus Torvalds 		else
14571da177e4SLinus Torvalds 			snd_es1938_write(chip, *s, *d);
14581da177e4SLinus Torvalds 	}
14591da177e4SLinus Torvalds 
1460b34a580eSTakashi Iwai 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
14611da177e4SLinus Torvalds 	return 0;
14621da177e4SLinus Torvalds }
146368cb2b55STakashi Iwai 
146468cb2b55STakashi Iwai static SIMPLE_DEV_PM_OPS(es1938_pm, es1938_suspend, es1938_resume);
146568cb2b55STakashi Iwai #define ES1938_PM_OPS	&es1938_pm
146668cb2b55STakashi Iwai #else
146768cb2b55STakashi Iwai #define ES1938_PM_OPS	NULL
1468c7561cd8STakashi Iwai #endif /* CONFIG_PM_SLEEP */
14691da177e4SLinus Torvalds 
14701da177e4SLinus Torvalds #ifdef SUPPORT_JOYSTICK
snd_es1938_create_gameport(struct es1938 * chip)1471e23e7a14SBill Pemberton static int snd_es1938_create_gameport(struct es1938 *chip)
14721da177e4SLinus Torvalds {
14731da177e4SLinus Torvalds 	struct gameport *gp;
14741da177e4SLinus Torvalds 
14751da177e4SLinus Torvalds 	chip->gameport = gp = gameport_allocate_port();
14761da177e4SLinus Torvalds 	if (!gp) {
1477ebebecaaSTakashi Iwai 		dev_err(chip->card->dev,
1478ebebecaaSTakashi Iwai 			"cannot allocate memory for gameport\n");
14791da177e4SLinus Torvalds 		return -ENOMEM;
14801da177e4SLinus Torvalds 	}
14811da177e4SLinus Torvalds 
14821da177e4SLinus Torvalds 	gameport_set_name(gp, "ES1938");
14831da177e4SLinus Torvalds 	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
14841da177e4SLinus Torvalds 	gameport_set_dev_parent(gp, &chip->pci->dev);
14851da177e4SLinus Torvalds 	gp->io = chip->game_port;
14861da177e4SLinus Torvalds 
14871da177e4SLinus Torvalds 	gameport_register_port(gp);
14881da177e4SLinus Torvalds 
14891da177e4SLinus Torvalds 	return 0;
14901da177e4SLinus Torvalds }
14911da177e4SLinus Torvalds 
snd_es1938_free_gameport(struct es1938 * chip)1492e571f594STakashi Iwai static void snd_es1938_free_gameport(struct es1938 *chip)
14931da177e4SLinus Torvalds {
14941da177e4SLinus Torvalds 	if (chip->gameport) {
14951da177e4SLinus Torvalds 		gameport_unregister_port(chip->gameport);
14961da177e4SLinus Torvalds 		chip->gameport = NULL;
14971da177e4SLinus Torvalds 	}
14981da177e4SLinus Torvalds }
14991da177e4SLinus Torvalds #else
snd_es1938_create_gameport(struct es1938 * chip)1500e571f594STakashi Iwai static inline int snd_es1938_create_gameport(struct es1938 *chip) { return -ENOSYS; }
snd_es1938_free_gameport(struct es1938 * chip)1501e571f594STakashi Iwai static inline void snd_es1938_free_gameport(struct es1938 *chip) { }
15021da177e4SLinus Torvalds #endif /* SUPPORT_JOYSTICK */
15031da177e4SLinus Torvalds 
snd_es1938_free(struct snd_card * card)150408e9d3abSTakashi Iwai static void snd_es1938_free(struct snd_card *card)
15051da177e4SLinus Torvalds {
150608e9d3abSTakashi Iwai 	struct es1938 *chip = card->private_data;
150708e9d3abSTakashi Iwai 
15081da177e4SLinus Torvalds 	/* disable irqs */
15091da177e4SLinus Torvalds 	outb(0x00, SLIO_REG(chip, IRQCONTROL));
15101da177e4SLinus Torvalds 	if (chip->rmidi)
15111da177e4SLinus Torvalds 		snd_es1938_mixer_bits(chip, ESSSB_IREG_MPU401CONTROL, 0x40, 0);
15121da177e4SLinus Torvalds 
15131da177e4SLinus Torvalds 	snd_es1938_free_gameport(chip);
15141da177e4SLinus Torvalds 
1515f000fd80SJeff Garzik 	if (chip->irq >= 0)
1516e571f594STakashi Iwai 		free_irq(chip->irq, chip);
15171da177e4SLinus Torvalds }
15181da177e4SLinus Torvalds 
snd_es1938_create(struct snd_card * card,struct pci_dev * pci)1519e23e7a14SBill Pemberton static int snd_es1938_create(struct snd_card *card,
152008e9d3abSTakashi Iwai 			     struct pci_dev *pci)
15211da177e4SLinus Torvalds {
152208e9d3abSTakashi Iwai 	struct es1938 *chip = card->private_data;
15231da177e4SLinus Torvalds 	int err;
15241da177e4SLinus Torvalds 
15251da177e4SLinus Torvalds 	/* enable PCI device */
152608e9d3abSTakashi Iwai 	err = pcim_enable_device(pci);
15273dc52815STakashi Iwai 	if (err < 0)
15281da177e4SLinus Torvalds 		return err;
15291da177e4SLinus Torvalds         /* check, if we can restrict PCI DMA transfers to 24 bits */
1530669f65eaSTakashi Iwai 	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(24))) {
1531ebebecaaSTakashi Iwai 		dev_err(card->dev,
1532ebebecaaSTakashi Iwai 			"architecture does not support 24bit PCI busmaster DMA\n");
15331da177e4SLinus Torvalds                 return -ENXIO;
15341da177e4SLinus Torvalds         }
15351da177e4SLinus Torvalds 
15361da177e4SLinus Torvalds 	spin_lock_init(&chip->reg_lock);
15371da177e4SLinus Torvalds 	spin_lock_init(&chip->mixer_lock);
15381da177e4SLinus Torvalds 	chip->card = card;
15391da177e4SLinus Torvalds 	chip->pci = pci;
154030b35399STakashi Iwai 	chip->irq = -1;
15413dc52815STakashi Iwai 	err = pci_request_regions(pci, "ESS Solo-1");
154208e9d3abSTakashi Iwai 	if (err < 0)
15431da177e4SLinus Torvalds 		return err;
15441da177e4SLinus Torvalds 	chip->io_port = pci_resource_start(pci, 0);
15451da177e4SLinus Torvalds 	chip->sb_port = pci_resource_start(pci, 1);
15461da177e4SLinus Torvalds 	chip->vc_port = pci_resource_start(pci, 2);
15471da177e4SLinus Torvalds 	chip->mpu_port = pci_resource_start(pci, 3);
15481da177e4SLinus Torvalds 	chip->game_port = pci_resource_start(pci, 4);
154908e9d3abSTakashi Iwai 	/* still use non-managed irq handler as it's re-acquired at PM resume */
1550437a5a46STakashi Iwai 	if (request_irq(pci->irq, snd_es1938_interrupt, IRQF_SHARED,
1551934c2b6dSTakashi Iwai 			KBUILD_MODNAME, chip)) {
1552ebebecaaSTakashi Iwai 		dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
15531da177e4SLinus Torvalds 		return -EBUSY;
15541da177e4SLinus Torvalds 	}
15551da177e4SLinus Torvalds 	chip->irq = pci->irq;
15566b276e62STakashi Iwai 	card->sync_irq = chip->irq;
155708e9d3abSTakashi Iwai 	card->private_free = snd_es1938_free;
1558ebebecaaSTakashi Iwai 	dev_dbg(card->dev,
1559ebebecaaSTakashi Iwai 		"create: io: 0x%lx, sb: 0x%lx, vc: 0x%lx, mpu: 0x%lx, game: 0x%lx\n",
15601da177e4SLinus Torvalds 		   chip->io_port, chip->sb_port, chip->vc_port, chip->mpu_port, chip->game_port);
15611da177e4SLinus Torvalds 
15621da177e4SLinus Torvalds 	chip->ddma_port = chip->vc_port + 0x00;		/* fix from Thomas Sailer */
15631da177e4SLinus Torvalds 
15641da177e4SLinus Torvalds 	snd_es1938_chip_init(chip);
15651da177e4SLinus Torvalds 	return 0;
15661da177e4SLinus Torvalds }
15671da177e4SLinus Torvalds 
15681da177e4SLinus Torvalds /* --------------------------------------------------------------------
15691da177e4SLinus Torvalds  * Interrupt handler
15701da177e4SLinus Torvalds  * -------------------------------------------------------------------- */
snd_es1938_interrupt(int irq,void * dev_id)15717d12e780SDavid Howells static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id)
15721da177e4SLinus Torvalds {
1573e571f594STakashi Iwai 	struct es1938 *chip = dev_id;
15748068a581SPierre-Louis Bossart 	unsigned char status;
15758068a581SPierre-Louis Bossart 	__always_unused unsigned char audiostatus;
15761da177e4SLinus Torvalds 	int handled = 0;
15771da177e4SLinus Torvalds 
15781da177e4SLinus Torvalds 	status = inb(SLIO_REG(chip, IRQCONTROL));
15791da177e4SLinus Torvalds #if 0
1580ebebecaaSTakashi Iwai 	dev_dbg(chip->card->dev,
1581ebebecaaSTakashi Iwai 		"Es1938debug - interrupt status: =0x%x\n", status);
15821da177e4SLinus Torvalds #endif
15831da177e4SLinus Torvalds 
15841da177e4SLinus Torvalds 	/* AUDIO 1 */
15851da177e4SLinus Torvalds 	if (status & 0x10) {
15861da177e4SLinus Torvalds #if 0
1587ebebecaaSTakashi Iwai 		dev_dbg(chip->card->dev,
1588ee419653STakashi Iwai 		       "Es1938debug - AUDIO channel 1 interrupt\n");
1589ebebecaaSTakashi Iwai 		dev_dbg(chip->card->dev,
1590ee419653STakashi Iwai 		       "Es1938debug - AUDIO channel 1 DMAC DMA count: %u\n",
1591e571f594STakashi Iwai 		       inw(SLDM_REG(chip, DMACOUNT)));
1592ebebecaaSTakashi Iwai 		dev_dbg(chip->card->dev,
1593ee419653STakashi Iwai 		       "Es1938debug - AUDIO channel 1 DMAC DMA base: %u\n",
1594e571f594STakashi Iwai 		       inl(SLDM_REG(chip, DMAADDR)));
1595ebebecaaSTakashi Iwai 		dev_dbg(chip->card->dev,
1596ee419653STakashi Iwai 		       "Es1938debug - AUDIO channel 1 DMAC DMA status: 0x%x\n",
1597e571f594STakashi Iwai 		       inl(SLDM_REG(chip, DMASTATUS)));
15981da177e4SLinus Torvalds #endif
15991da177e4SLinus Torvalds 		/* clear irq */
16001da177e4SLinus Torvalds 		handled = 1;
16011da177e4SLinus Torvalds 		audiostatus = inb(SLSB_REG(chip, STATUS));
16021da177e4SLinus Torvalds 		if (chip->active & ADC1)
16031da177e4SLinus Torvalds 			snd_pcm_period_elapsed(chip->capture_substream);
16041da177e4SLinus Torvalds 		else if (chip->active & DAC1)
16051da177e4SLinus Torvalds 			snd_pcm_period_elapsed(chip->playback2_substream);
16061da177e4SLinus Torvalds 	}
16071da177e4SLinus Torvalds 
16081da177e4SLinus Torvalds 	/* AUDIO 2 */
16091da177e4SLinus Torvalds 	if (status & 0x20) {
16101da177e4SLinus Torvalds #if 0
1611ebebecaaSTakashi Iwai 		dev_dbg(chip->card->dev,
1612ee419653STakashi Iwai 		       "Es1938debug - AUDIO channel 2 interrupt\n");
1613ebebecaaSTakashi Iwai 		dev_dbg(chip->card->dev,
1614ee419653STakashi Iwai 		       "Es1938debug - AUDIO channel 2 DMAC DMA count: %u\n",
1615e571f594STakashi Iwai 		       inw(SLIO_REG(chip, AUDIO2DMACOUNT)));
1616ebebecaaSTakashi Iwai 		dev_dbg(chip->card->dev,
1617ee419653STakashi Iwai 		       "Es1938debug - AUDIO channel 2 DMAC DMA base: %u\n",
1618e571f594STakashi Iwai 		       inl(SLIO_REG(chip, AUDIO2DMAADDR)));
16191da177e4SLinus Torvalds 
16201da177e4SLinus Torvalds #endif
16211da177e4SLinus Torvalds 		/* clear irq */
16221da177e4SLinus Torvalds 		handled = 1;
16231da177e4SLinus Torvalds 		snd_es1938_mixer_bits(chip, ESSSB_IREG_AUDIO2CONTROL2, 0x80, 0);
16241da177e4SLinus Torvalds 		if (chip->active & DAC2)
16251da177e4SLinus Torvalds 			snd_pcm_period_elapsed(chip->playback1_substream);
16261da177e4SLinus Torvalds 	}
16271da177e4SLinus Torvalds 
16281da177e4SLinus Torvalds 	/* Hardware volume */
16291da177e4SLinus Torvalds 	if (status & 0x40) {
16301da177e4SLinus Torvalds 		int split = snd_es1938_mixer_read(chip, 0x64) & 0x80;
16311da177e4SLinus Torvalds 		handled = 1;
16321da177e4SLinus Torvalds 		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_switch->id);
16331da177e4SLinus Torvalds 		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_volume->id);
16341da177e4SLinus Torvalds 		if (!split) {
1635e571f594STakashi Iwai 			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
1636e571f594STakashi Iwai 				       &chip->master_switch->id);
1637e571f594STakashi Iwai 			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
1638e571f594STakashi Iwai 				       &chip->master_volume->id);
16391da177e4SLinus Torvalds 		}
16401da177e4SLinus Torvalds 		/* ack interrupt */
16411da177e4SLinus Torvalds 		snd_es1938_mixer_write(chip, 0x66, 0x00);
16421da177e4SLinus Torvalds 	}
16431da177e4SLinus Torvalds 
16441da177e4SLinus Torvalds 	/* MPU401 */
16451da177e4SLinus Torvalds 	if (status & 0x80) {
16461da177e4SLinus Torvalds 		// the following line is evil! It switches off MIDI interrupt handling after the first interrupt received.
16471da177e4SLinus Torvalds 		// replacing the last 0 by 0x40 works for ESS-Solo1, but just doing nothing works as well!
16481da177e4SLinus Torvalds 		// andreas@flying-snail.de
16491da177e4SLinus Torvalds 		// snd_es1938_mixer_bits(chip, ESSSB_IREG_MPU401CONTROL, 0x40, 0); /* ack? */
16501da177e4SLinus Torvalds 		if (chip->rmidi) {
16511da177e4SLinus Torvalds 			handled = 1;
16527d12e780SDavid Howells 			snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
16531da177e4SLinus Torvalds 		}
16541da177e4SLinus Torvalds 	}
16551da177e4SLinus Torvalds 	return IRQ_RETVAL(handled);
16561da177e4SLinus Torvalds }
16571da177e4SLinus Torvalds 
16581da177e4SLinus Torvalds #define ES1938_DMA_SIZE 64
16591da177e4SLinus Torvalds 
snd_es1938_mixer(struct es1938 * chip)1660e23e7a14SBill Pemberton static int snd_es1938_mixer(struct es1938 *chip)
16611da177e4SLinus Torvalds {
1662e571f594STakashi Iwai 	struct snd_card *card;
16631da177e4SLinus Torvalds 	unsigned int idx;
16641da177e4SLinus Torvalds 	int err;
16651da177e4SLinus Torvalds 
16661da177e4SLinus Torvalds 	card = chip->card;
16671da177e4SLinus Torvalds 
16681da177e4SLinus Torvalds 	strcpy(card->mixername, "ESS Solo-1");
16691da177e4SLinus Torvalds 
16701da177e4SLinus Torvalds 	for (idx = 0; idx < ARRAY_SIZE(snd_es1938_controls); idx++) {
1671e571f594STakashi Iwai 		struct snd_kcontrol *kctl;
16721da177e4SLinus Torvalds 		kctl = snd_ctl_new1(&snd_es1938_controls[idx], chip);
16731da177e4SLinus Torvalds 		switch (idx) {
16741da177e4SLinus Torvalds 			case 0:
16751da177e4SLinus Torvalds 				chip->master_volume = kctl;
16761da177e4SLinus Torvalds 				kctl->private_free = snd_es1938_hwv_free;
16771da177e4SLinus Torvalds 				break;
16781da177e4SLinus Torvalds 			case 1:
16791da177e4SLinus Torvalds 				chip->master_switch = kctl;
16801da177e4SLinus Torvalds 				kctl->private_free = snd_es1938_hwv_free;
16811da177e4SLinus Torvalds 				break;
16821da177e4SLinus Torvalds 			case 2:
16831da177e4SLinus Torvalds 				chip->hw_volume = kctl;
16841da177e4SLinus Torvalds 				kctl->private_free = snd_es1938_hwv_free;
16851da177e4SLinus Torvalds 				break;
16861da177e4SLinus Torvalds 			case 3:
16871da177e4SLinus Torvalds 				chip->hw_switch = kctl;
16881da177e4SLinus Torvalds 				kctl->private_free = snd_es1938_hwv_free;
16891da177e4SLinus Torvalds 				break;
16901da177e4SLinus Torvalds 			}
16913dc52815STakashi Iwai 		err = snd_ctl_add(card, kctl);
16923dc52815STakashi Iwai 		if (err < 0)
16931da177e4SLinus Torvalds 			return err;
16941da177e4SLinus Torvalds 	}
16951da177e4SLinus Torvalds 	return 0;
16961da177e4SLinus Torvalds }
16971da177e4SLinus Torvalds 
16981da177e4SLinus Torvalds 
__snd_es1938_probe(struct pci_dev * pci,const struct pci_device_id * pci_id)1699bc226285STakashi Iwai static int __snd_es1938_probe(struct pci_dev *pci,
17001da177e4SLinus Torvalds 			      const struct pci_device_id *pci_id)
17011da177e4SLinus Torvalds {
17021da177e4SLinus Torvalds 	static int dev;
1703e571f594STakashi Iwai 	struct snd_card *card;
1704e571f594STakashi Iwai 	struct es1938 *chip;
1705e571f594STakashi Iwai 	struct snd_opl3 *opl3;
17061da177e4SLinus Torvalds 	int idx, err;
17071da177e4SLinus Torvalds 
17081da177e4SLinus Torvalds 	if (dev >= SNDRV_CARDS)
17091da177e4SLinus Torvalds 		return -ENODEV;
17101da177e4SLinus Torvalds 	if (!enable[dev]) {
17111da177e4SLinus Torvalds 		dev++;
17121da177e4SLinus Torvalds 		return -ENOENT;
17131da177e4SLinus Torvalds 	}
17141da177e4SLinus Torvalds 
171508e9d3abSTakashi Iwai 	err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
171608e9d3abSTakashi Iwai 				sizeof(*chip), &card);
1717e58de7baSTakashi Iwai 	if (err < 0)
1718e58de7baSTakashi Iwai 		return err;
171908e9d3abSTakashi Iwai 	chip = card->private_data;
172008e9d3abSTakashi Iwai 
172108e9d3abSTakashi Iwai 	for (idx = 0; idx < 5; idx++)
17221da177e4SLinus Torvalds 		if (pci_resource_start(pci, idx) == 0 ||
172308e9d3abSTakashi Iwai 		    !(pci_resource_flags(pci, idx) & IORESOURCE_IO))
17241da177e4SLinus Torvalds 			return -ENODEV;
172508e9d3abSTakashi Iwai 
172608e9d3abSTakashi Iwai 	err = snd_es1938_create(card, pci);
172708e9d3abSTakashi Iwai 	if (err < 0)
17281da177e4SLinus Torvalds 		return err;
17291da177e4SLinus Torvalds 
17301da177e4SLinus Torvalds 	strcpy(card->driver, "ES1938");
17311da177e4SLinus Torvalds 	strcpy(card->shortname, "ESS ES1938 (Solo-1)");
17321da177e4SLinus Torvalds 	sprintf(card->longname, "%s rev %i, irq %i",
17331da177e4SLinus Torvalds 		card->shortname,
17341da177e4SLinus Torvalds 		chip->revision,
17351da177e4SLinus Torvalds 		chip->irq);
17361da177e4SLinus Torvalds 
17373dc52815STakashi Iwai 	err = snd_es1938_new_pcm(chip, 0);
173808e9d3abSTakashi Iwai 	if (err < 0)
17391da177e4SLinus Torvalds 		return err;
17403dc52815STakashi Iwai 	err = snd_es1938_mixer(chip);
174108e9d3abSTakashi Iwai 	if (err < 0)
17421da177e4SLinus Torvalds 		return err;
17431da177e4SLinus Torvalds 	if (snd_opl3_create(card,
17441da177e4SLinus Torvalds 			    SLSB_REG(chip, FMLOWADDR),
17451da177e4SLinus Torvalds 			    SLSB_REG(chip, FMHIGHADDR),
17461da177e4SLinus Torvalds 			    OPL3_HW_OPL3, 1, &opl3) < 0) {
1747ebebecaaSTakashi Iwai 		dev_err(card->dev, "OPL3 not detected at 0x%lx\n",
17481da177e4SLinus Torvalds 			   SLSB_REG(chip, FMLOWADDR));
17491da177e4SLinus Torvalds 	} else {
17503dc52815STakashi Iwai 		err = snd_opl3_timer_new(opl3, 0, 1);
175108e9d3abSTakashi Iwai 		if (err < 0)
17521da177e4SLinus Torvalds 	                return err;
17533dc52815STakashi Iwai 		err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
175408e9d3abSTakashi Iwai 		if (err < 0)
17551da177e4SLinus Torvalds 	                return err;
17561da177e4SLinus Torvalds 	}
17571da177e4SLinus Torvalds 	if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
1758dba8b469SClemens Ladisch 				chip->mpu_port,
1759dba8b469SClemens Ladisch 				MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK,
1760dba8b469SClemens Ladisch 				-1, &chip->rmidi) < 0) {
1761ebebecaaSTakashi Iwai 		dev_err(card->dev, "unable to initialize MPU-401\n");
17621da177e4SLinus Torvalds 	} else {
17631da177e4SLinus Torvalds 		// this line is vital for MIDI interrupt handling on ess-solo1
17641da177e4SLinus Torvalds 		// andreas@flying-snail.de
17651da177e4SLinus Torvalds 		snd_es1938_mixer_bits(chip, ESSSB_IREG_MPU401CONTROL, 0x40, 0x40);
17661da177e4SLinus Torvalds 	}
17671da177e4SLinus Torvalds 
17681da177e4SLinus Torvalds 	snd_es1938_create_gameport(chip);
17691da177e4SLinus Torvalds 
17703dc52815STakashi Iwai 	err = snd_card_register(card);
177108e9d3abSTakashi Iwai 	if (err < 0)
17721da177e4SLinus Torvalds 		return err;
17731da177e4SLinus Torvalds 
17741da177e4SLinus Torvalds 	pci_set_drvdata(pci, card);
17751da177e4SLinus Torvalds 	dev++;
17761da177e4SLinus Torvalds 	return 0;
17771da177e4SLinus Torvalds }
17781da177e4SLinus Torvalds 
snd_es1938_probe(struct pci_dev * pci,const struct pci_device_id * pci_id)1779bc226285STakashi Iwai static int snd_es1938_probe(struct pci_dev *pci,
1780bc226285STakashi Iwai 			    const struct pci_device_id *pci_id)
1781bc226285STakashi Iwai {
1782bc226285STakashi Iwai 	return snd_card_free_on_error(&pci->dev, __snd_es1938_probe(pci, pci_id));
1783bc226285STakashi Iwai }
1784bc226285STakashi Iwai 
1785e9f66d9bSTakashi Iwai static struct pci_driver es1938_driver = {
17863733e424STakashi Iwai 	.name = KBUILD_MODNAME,
17871da177e4SLinus Torvalds 	.id_table = snd_es1938_ids,
17881da177e4SLinus Torvalds 	.probe = snd_es1938_probe,
178968cb2b55STakashi Iwai 	.driver = {
179068cb2b55STakashi Iwai 		.pm = ES1938_PM_OPS,
179168cb2b55STakashi Iwai 	},
17921da177e4SLinus Torvalds };
17931da177e4SLinus Torvalds 
1794e9f66d9bSTakashi Iwai module_pci_driver(es1938_driver);
1795