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