11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Driver for ESS Maestro3/Allegro (ES1988) soundcards.
41da177e4SLinus Torvalds * Copyright (c) 2000 by Zach Brown <zab@zabbo.net>
51da177e4SLinus Torvalds * Takashi Iwai <tiwai@suse.de>
61da177e4SLinus Torvalds *
71da177e4SLinus Torvalds * Most of the hardware init stuffs are based on maestro3 driver for
81da177e4SLinus Torvalds * OSS/Free by Zach Brown. Many thanks to Zach!
91da177e4SLinus Torvalds *
101da177e4SLinus Torvalds * ChangeLog:
111da177e4SLinus Torvalds * Aug. 27, 2001
121da177e4SLinus Torvalds * - Fixed deadlock on capture
131da177e4SLinus Torvalds * - Added Canyon3D-2 support by Rob Riggs <rob@pangalactic.org>
141da177e4SLinus Torvalds */
151da177e4SLinus Torvalds
161da177e4SLinus Torvalds #define CARD_NAME "ESS Maestro3/Allegro/Canyon3D-2"
171da177e4SLinus Torvalds #define DRIVER_NAME "Maestro3"
181da177e4SLinus Torvalds
196cbbfe1cSTakashi Iwai #include <linux/io.h>
201da177e4SLinus Torvalds #include <linux/delay.h>
211da177e4SLinus Torvalds #include <linux/interrupt.h>
221da177e4SLinus Torvalds #include <linux/init.h>
231da177e4SLinus Torvalds #include <linux/pci.h>
249d2f928dSTobias Klauser #include <linux/dma-mapping.h>
251da177e4SLinus Torvalds #include <linux/slab.h>
261da177e4SLinus Torvalds #include <linux/vmalloc.h>
2765a77217SPaul Gortmaker #include <linux/module.h>
2881d7724aSClemens Ladisch #include <linux/firmware.h>
29eb581adfSHans de Goede #include <linux/input.h>
301da177e4SLinus Torvalds #include <sound/core.h>
311da177e4SLinus Torvalds #include <sound/info.h>
321da177e4SLinus Torvalds #include <sound/control.h>
331da177e4SLinus Torvalds #include <sound/pcm.h>
341da177e4SLinus Torvalds #include <sound/mpu401.h>
351da177e4SLinus Torvalds #include <sound/ac97_codec.h>
361da177e4SLinus Torvalds #include <sound/initval.h>
3781d7724aSClemens Ladisch #include <asm/byteorder.h>
381da177e4SLinus Torvalds
391da177e4SLinus Torvalds MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Takashi Iwai <tiwai@suse.de>");
401da177e4SLinus Torvalds MODULE_DESCRIPTION("ESS Maestro3 PCI");
411da177e4SLinus Torvalds MODULE_LICENSE("GPL");
427e0af29dSClemens Ladisch MODULE_FIRMWARE("ess/maestro3_assp_kernel.fw");
437e0af29dSClemens Ladisch MODULE_FIRMWARE("ess/maestro3_assp_minisrc.fw");
441da177e4SLinus Torvalds
451da177e4SLinus Torvalds static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
461da177e4SLinus Torvalds static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
47a67ff6a5SRusty Russell static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* all enabled */
48a67ff6a5SRusty Russell static bool external_amp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
491da177e4SLinus Torvalds static int amp_gpio[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1};
501da177e4SLinus Torvalds
511da177e4SLinus Torvalds module_param_array(index, int, NULL, 0444);
521da177e4SLinus Torvalds MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
531da177e4SLinus Torvalds module_param_array(id, charp, NULL, 0444);
541da177e4SLinus Torvalds MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
551da177e4SLinus Torvalds module_param_array(enable, bool, NULL, 0444);
561da177e4SLinus Torvalds MODULE_PARM_DESC(enable, "Enable this soundcard.");
571da177e4SLinus Torvalds module_param_array(external_amp, bool, NULL, 0444);
581da177e4SLinus Torvalds MODULE_PARM_DESC(external_amp, "Enable external amp for " CARD_NAME " soundcard.");
591da177e4SLinus Torvalds module_param_array(amp_gpio, int, NULL, 0444);
601da177e4SLinus Torvalds MODULE_PARM_DESC(amp_gpio, "GPIO pin number for external amp. (default = -1)");
611da177e4SLinus Torvalds
621da177e4SLinus Torvalds #define MAX_PLAYBACKS 2
631da177e4SLinus Torvalds #define MAX_CAPTURES 1
641da177e4SLinus Torvalds #define NR_DSPS (MAX_PLAYBACKS + MAX_CAPTURES)
651da177e4SLinus Torvalds
661da177e4SLinus Torvalds
671da177e4SLinus Torvalds /*
681da177e4SLinus Torvalds * maestro3 registers
691da177e4SLinus Torvalds */
701da177e4SLinus Torvalds
711da177e4SLinus Torvalds /* Allegro PCI configuration registers */
721da177e4SLinus Torvalds #define PCI_LEGACY_AUDIO_CTRL 0x40
731da177e4SLinus Torvalds #define SOUND_BLASTER_ENABLE 0x00000001
741da177e4SLinus Torvalds #define FM_SYNTHESIS_ENABLE 0x00000002
751da177e4SLinus Torvalds #define GAME_PORT_ENABLE 0x00000004
761da177e4SLinus Torvalds #define MPU401_IO_ENABLE 0x00000008
771da177e4SLinus Torvalds #define MPU401_IRQ_ENABLE 0x00000010
781da177e4SLinus Torvalds #define ALIAS_10BIT_IO 0x00000020
791da177e4SLinus Torvalds #define SB_DMA_MASK 0x000000C0
801da177e4SLinus Torvalds #define SB_DMA_0 0x00000040
811da177e4SLinus Torvalds #define SB_DMA_1 0x00000040
821da177e4SLinus Torvalds #define SB_DMA_R 0x00000080
831da177e4SLinus Torvalds #define SB_DMA_3 0x000000C0
841da177e4SLinus Torvalds #define SB_IRQ_MASK 0x00000700
851da177e4SLinus Torvalds #define SB_IRQ_5 0x00000000
861da177e4SLinus Torvalds #define SB_IRQ_7 0x00000100
871da177e4SLinus Torvalds #define SB_IRQ_9 0x00000200
881da177e4SLinus Torvalds #define SB_IRQ_10 0x00000300
891da177e4SLinus Torvalds #define MIDI_IRQ_MASK 0x00003800
901da177e4SLinus Torvalds #define SERIAL_IRQ_ENABLE 0x00004000
911da177e4SLinus Torvalds #define DISABLE_LEGACY 0x00008000
921da177e4SLinus Torvalds
931da177e4SLinus Torvalds #define PCI_ALLEGRO_CONFIG 0x50
941da177e4SLinus Torvalds #define SB_ADDR_240 0x00000004
951da177e4SLinus Torvalds #define MPU_ADDR_MASK 0x00000018
961da177e4SLinus Torvalds #define MPU_ADDR_330 0x00000000
971da177e4SLinus Torvalds #define MPU_ADDR_300 0x00000008
981da177e4SLinus Torvalds #define MPU_ADDR_320 0x00000010
991da177e4SLinus Torvalds #define MPU_ADDR_340 0x00000018
1001da177e4SLinus Torvalds #define USE_PCI_TIMING 0x00000040
1011da177e4SLinus Torvalds #define POSTED_WRITE_ENABLE 0x00000080
1021da177e4SLinus Torvalds #define DMA_POLICY_MASK 0x00000700
1031da177e4SLinus Torvalds #define DMA_DDMA 0x00000000
1041da177e4SLinus Torvalds #define DMA_TDMA 0x00000100
1051da177e4SLinus Torvalds #define DMA_PCPCI 0x00000200
1061da177e4SLinus Torvalds #define DMA_WBDMA16 0x00000400
1071da177e4SLinus Torvalds #define DMA_WBDMA4 0x00000500
1081da177e4SLinus Torvalds #define DMA_WBDMA2 0x00000600
1091da177e4SLinus Torvalds #define DMA_WBDMA1 0x00000700
1101da177e4SLinus Torvalds #define DMA_SAFE_GUARD 0x00000800
1111da177e4SLinus Torvalds #define HI_PERF_GP_ENABLE 0x00001000
1121da177e4SLinus Torvalds #define PIC_SNOOP_MODE_0 0x00002000
1131da177e4SLinus Torvalds #define PIC_SNOOP_MODE_1 0x00004000
1141da177e4SLinus Torvalds #define SOUNDBLASTER_IRQ_MASK 0x00008000
1151da177e4SLinus Torvalds #define RING_IN_ENABLE 0x00010000
1161da177e4SLinus Torvalds #define SPDIF_TEST_MODE 0x00020000
1171da177e4SLinus Torvalds #define CLK_MULT_MODE_SELECT_2 0x00040000
1181da177e4SLinus Torvalds #define EEPROM_WRITE_ENABLE 0x00080000
1191da177e4SLinus Torvalds #define CODEC_DIR_IN 0x00100000
1201da177e4SLinus Torvalds #define HV_BUTTON_FROM_GD 0x00200000
1211da177e4SLinus Torvalds #define REDUCED_DEBOUNCE 0x00400000
1221da177e4SLinus Torvalds #define HV_CTRL_ENABLE 0x00800000
1231da177e4SLinus Torvalds #define SPDIF_ENABLE 0x01000000
1241da177e4SLinus Torvalds #define CLK_DIV_SELECT 0x06000000
1251da177e4SLinus Torvalds #define CLK_DIV_BY_48 0x00000000
1261da177e4SLinus Torvalds #define CLK_DIV_BY_49 0x02000000
1271da177e4SLinus Torvalds #define CLK_DIV_BY_50 0x04000000
1281da177e4SLinus Torvalds #define CLK_DIV_RESERVED 0x06000000
1291da177e4SLinus Torvalds #define PM_CTRL_ENABLE 0x08000000
1301da177e4SLinus Torvalds #define CLK_MULT_MODE_SELECT 0x30000000
1311da177e4SLinus Torvalds #define CLK_MULT_MODE_SHIFT 28
1321da177e4SLinus Torvalds #define CLK_MULT_MODE_0 0x00000000
1331da177e4SLinus Torvalds #define CLK_MULT_MODE_1 0x10000000
1341da177e4SLinus Torvalds #define CLK_MULT_MODE_2 0x20000000
1351da177e4SLinus Torvalds #define CLK_MULT_MODE_3 0x30000000
1361da177e4SLinus Torvalds #define INT_CLK_SELECT 0x40000000
1371da177e4SLinus Torvalds #define INT_CLK_MULT_RESET 0x80000000
1381da177e4SLinus Torvalds
1391da177e4SLinus Torvalds /* M3 */
1401da177e4SLinus Torvalds #define INT_CLK_SRC_NOT_PCI 0x00100000
1411da177e4SLinus Torvalds #define INT_CLK_MULT_ENABLE 0x80000000
1421da177e4SLinus Torvalds
1431da177e4SLinus Torvalds #define PCI_ACPI_CONTROL 0x54
1441da177e4SLinus Torvalds #define PCI_ACPI_D0 0x00000000
1451da177e4SLinus Torvalds #define PCI_ACPI_D1 0xB4F70000
1461da177e4SLinus Torvalds #define PCI_ACPI_D2 0xB4F7B4F7
1471da177e4SLinus Torvalds
1481da177e4SLinus Torvalds #define PCI_USER_CONFIG 0x58
1491da177e4SLinus Torvalds #define EXT_PCI_MASTER_ENABLE 0x00000001
1501da177e4SLinus Torvalds #define SPDIF_OUT_SELECT 0x00000002
1511da177e4SLinus Torvalds #define TEST_PIN_DIR_CTRL 0x00000004
1521da177e4SLinus Torvalds #define AC97_CODEC_TEST 0x00000020
1531da177e4SLinus Torvalds #define TRI_STATE_BUFFER 0x00000080
1541da177e4SLinus Torvalds #define IN_CLK_12MHZ_SELECT 0x00000100
1551da177e4SLinus Torvalds #define MULTI_FUNC_DISABLE 0x00000200
1561da177e4SLinus Torvalds #define EXT_MASTER_PAIR_SEL 0x00000400
1571da177e4SLinus Torvalds #define PCI_MASTER_SUPPORT 0x00000800
1581da177e4SLinus Torvalds #define STOP_CLOCK_ENABLE 0x00001000
1591da177e4SLinus Torvalds #define EAPD_DRIVE_ENABLE 0x00002000
1601da177e4SLinus Torvalds #define REQ_TRI_STATE_ENABLE 0x00004000
1611da177e4SLinus Torvalds #define REQ_LOW_ENABLE 0x00008000
1621da177e4SLinus Torvalds #define MIDI_1_ENABLE 0x00010000
1631da177e4SLinus Torvalds #define MIDI_2_ENABLE 0x00020000
1641da177e4SLinus Torvalds #define SB_AUDIO_SYNC 0x00040000
1651da177e4SLinus Torvalds #define HV_CTRL_TEST 0x00100000
1661da177e4SLinus Torvalds #define SOUNDBLASTER_TEST 0x00400000
1671da177e4SLinus Torvalds
1681da177e4SLinus Torvalds #define PCI_USER_CONFIG_C 0x5C
1691da177e4SLinus Torvalds
1701da177e4SLinus Torvalds #define PCI_DDMA_CTRL 0x60
1711da177e4SLinus Torvalds #define DDMA_ENABLE 0x00000001
1721da177e4SLinus Torvalds
1731da177e4SLinus Torvalds
1741da177e4SLinus Torvalds /* Allegro registers */
1751da177e4SLinus Torvalds #define HOST_INT_CTRL 0x18
1761da177e4SLinus Torvalds #define SB_INT_ENABLE 0x0001
1771da177e4SLinus Torvalds #define MPU401_INT_ENABLE 0x0002
1781da177e4SLinus Torvalds #define ASSP_INT_ENABLE 0x0010
1791da177e4SLinus Torvalds #define RING_INT_ENABLE 0x0020
1801da177e4SLinus Torvalds #define HV_INT_ENABLE 0x0040
1811da177e4SLinus Torvalds #define CLKRUN_GEN_ENABLE 0x0100
1821da177e4SLinus Torvalds #define HV_CTRL_TO_PME 0x0400
1831da177e4SLinus Torvalds #define SOFTWARE_RESET_ENABLE 0x8000
1841da177e4SLinus Torvalds
1851da177e4SLinus Torvalds /*
1861da177e4SLinus Torvalds * should be using the above defines, probably.
1871da177e4SLinus Torvalds */
1881da177e4SLinus Torvalds #define REGB_ENABLE_RESET 0x01
1891da177e4SLinus Torvalds #define REGB_STOP_CLOCK 0x10
1901da177e4SLinus Torvalds
1911da177e4SLinus Torvalds #define HOST_INT_STATUS 0x1A
1921da177e4SLinus Torvalds #define SB_INT_PENDING 0x01
1931da177e4SLinus Torvalds #define MPU401_INT_PENDING 0x02
1941da177e4SLinus Torvalds #define ASSP_INT_PENDING 0x10
1951da177e4SLinus Torvalds #define RING_INT_PENDING 0x20
1961da177e4SLinus Torvalds #define HV_INT_PENDING 0x40
1971da177e4SLinus Torvalds
1981da177e4SLinus Torvalds #define HARDWARE_VOL_CTRL 0x1B
1991da177e4SLinus Torvalds #define SHADOW_MIX_REG_VOICE 0x1C
2001da177e4SLinus Torvalds #define HW_VOL_COUNTER_VOICE 0x1D
2011da177e4SLinus Torvalds #define SHADOW_MIX_REG_MASTER 0x1E
2021da177e4SLinus Torvalds #define HW_VOL_COUNTER_MASTER 0x1F
2031da177e4SLinus Torvalds
2041da177e4SLinus Torvalds #define CODEC_COMMAND 0x30
2051da177e4SLinus Torvalds #define CODEC_READ_B 0x80
2061da177e4SLinus Torvalds
2071da177e4SLinus Torvalds #define CODEC_STATUS 0x30
2081da177e4SLinus Torvalds #define CODEC_BUSY_B 0x01
2091da177e4SLinus Torvalds
2101da177e4SLinus Torvalds #define CODEC_DATA 0x32
2111da177e4SLinus Torvalds
2121da177e4SLinus Torvalds #define RING_BUS_CTRL_A 0x36
2131da177e4SLinus Torvalds #define RAC_PME_ENABLE 0x0100
2141da177e4SLinus Torvalds #define RAC_SDFS_ENABLE 0x0200
2151da177e4SLinus Torvalds #define LAC_PME_ENABLE 0x0400
2161da177e4SLinus Torvalds #define LAC_SDFS_ENABLE 0x0800
2171da177e4SLinus Torvalds #define SERIAL_AC_LINK_ENABLE 0x1000
2181da177e4SLinus Torvalds #define IO_SRAM_ENABLE 0x2000
2191da177e4SLinus Torvalds #define IIS_INPUT_ENABLE 0x8000
2201da177e4SLinus Torvalds
2211da177e4SLinus Torvalds #define RING_BUS_CTRL_B 0x38
2221da177e4SLinus Torvalds #define SECOND_CODEC_ID_MASK 0x0003
2231da177e4SLinus Torvalds #define SPDIF_FUNC_ENABLE 0x0010
2241da177e4SLinus Torvalds #define SECOND_AC_ENABLE 0x0020
2251da177e4SLinus Torvalds #define SB_MODULE_INTF_ENABLE 0x0040
2261da177e4SLinus Torvalds #define SSPE_ENABLE 0x0040
2271da177e4SLinus Torvalds #define M3I_DOCK_ENABLE 0x0080
2281da177e4SLinus Torvalds
2291da177e4SLinus Torvalds #define SDO_OUT_DEST_CTRL 0x3A
2301da177e4SLinus Torvalds #define COMMAND_ADDR_OUT 0x0003
2311da177e4SLinus Torvalds #define PCM_LR_OUT_LOCAL 0x0000
2321da177e4SLinus Torvalds #define PCM_LR_OUT_REMOTE 0x0004
2331da177e4SLinus Torvalds #define PCM_LR_OUT_MUTE 0x0008
2341da177e4SLinus Torvalds #define PCM_LR_OUT_BOTH 0x000C
2351da177e4SLinus Torvalds #define LINE1_DAC_OUT_LOCAL 0x0000
2361da177e4SLinus Torvalds #define LINE1_DAC_OUT_REMOTE 0x0010
2371da177e4SLinus Torvalds #define LINE1_DAC_OUT_MUTE 0x0020
2381da177e4SLinus Torvalds #define LINE1_DAC_OUT_BOTH 0x0030
2391da177e4SLinus Torvalds #define PCM_CLS_OUT_LOCAL 0x0000
2401da177e4SLinus Torvalds #define PCM_CLS_OUT_REMOTE 0x0040
2411da177e4SLinus Torvalds #define PCM_CLS_OUT_MUTE 0x0080
2421da177e4SLinus Torvalds #define PCM_CLS_OUT_BOTH 0x00C0
2431da177e4SLinus Torvalds #define PCM_RLF_OUT_LOCAL 0x0000
2441da177e4SLinus Torvalds #define PCM_RLF_OUT_REMOTE 0x0100
2451da177e4SLinus Torvalds #define PCM_RLF_OUT_MUTE 0x0200
2461da177e4SLinus Torvalds #define PCM_RLF_OUT_BOTH 0x0300
2471da177e4SLinus Torvalds #define LINE2_DAC_OUT_LOCAL 0x0000
2481da177e4SLinus Torvalds #define LINE2_DAC_OUT_REMOTE 0x0400
2491da177e4SLinus Torvalds #define LINE2_DAC_OUT_MUTE 0x0800
2501da177e4SLinus Torvalds #define LINE2_DAC_OUT_BOTH 0x0C00
2511da177e4SLinus Torvalds #define HANDSET_OUT_LOCAL 0x0000
2521da177e4SLinus Torvalds #define HANDSET_OUT_REMOTE 0x1000
2531da177e4SLinus Torvalds #define HANDSET_OUT_MUTE 0x2000
2541da177e4SLinus Torvalds #define HANDSET_OUT_BOTH 0x3000
2551da177e4SLinus Torvalds #define IO_CTRL_OUT_LOCAL 0x0000
2561da177e4SLinus Torvalds #define IO_CTRL_OUT_REMOTE 0x4000
2571da177e4SLinus Torvalds #define IO_CTRL_OUT_MUTE 0x8000
2581da177e4SLinus Torvalds #define IO_CTRL_OUT_BOTH 0xC000
2591da177e4SLinus Torvalds
2601da177e4SLinus Torvalds #define SDO_IN_DEST_CTRL 0x3C
2611da177e4SLinus Torvalds #define STATUS_ADDR_IN 0x0003
2621da177e4SLinus Torvalds #define PCM_LR_IN_LOCAL 0x0000
2631da177e4SLinus Torvalds #define PCM_LR_IN_REMOTE 0x0004
2641da177e4SLinus Torvalds #define PCM_LR_RESERVED 0x0008
2651da177e4SLinus Torvalds #define PCM_LR_IN_BOTH 0x000C
2661da177e4SLinus Torvalds #define LINE1_ADC_IN_LOCAL 0x0000
2671da177e4SLinus Torvalds #define LINE1_ADC_IN_REMOTE 0x0010
2681da177e4SLinus Torvalds #define LINE1_ADC_IN_MUTE 0x0020
2691da177e4SLinus Torvalds #define MIC_ADC_IN_LOCAL 0x0000
2701da177e4SLinus Torvalds #define MIC_ADC_IN_REMOTE 0x0040
2711da177e4SLinus Torvalds #define MIC_ADC_IN_MUTE 0x0080
2721da177e4SLinus Torvalds #define LINE2_DAC_IN_LOCAL 0x0000
2731da177e4SLinus Torvalds #define LINE2_DAC_IN_REMOTE 0x0400
2741da177e4SLinus Torvalds #define LINE2_DAC_IN_MUTE 0x0800
2751da177e4SLinus Torvalds #define HANDSET_IN_LOCAL 0x0000
2761da177e4SLinus Torvalds #define HANDSET_IN_REMOTE 0x1000
2771da177e4SLinus Torvalds #define HANDSET_IN_MUTE 0x2000
2781da177e4SLinus Torvalds #define IO_STATUS_IN_LOCAL 0x0000
2791da177e4SLinus Torvalds #define IO_STATUS_IN_REMOTE 0x4000
2801da177e4SLinus Torvalds
2811da177e4SLinus Torvalds #define SPDIF_IN_CTRL 0x3E
2821da177e4SLinus Torvalds #define SPDIF_IN_ENABLE 0x0001
2831da177e4SLinus Torvalds
2841da177e4SLinus Torvalds #define GPIO_DATA 0x60
2851da177e4SLinus Torvalds #define GPIO_DATA_MASK 0x0FFF
2861da177e4SLinus Torvalds #define GPIO_HV_STATUS 0x3000
2871da177e4SLinus Torvalds #define GPIO_PME_STATUS 0x4000
2881da177e4SLinus Torvalds
2891da177e4SLinus Torvalds #define GPIO_MASK 0x64
2901da177e4SLinus Torvalds #define GPIO_DIRECTION 0x68
2911da177e4SLinus Torvalds #define GPO_PRIMARY_AC97 0x0001
2921da177e4SLinus Torvalds #define GPI_LINEOUT_SENSE 0x0004
2931da177e4SLinus Torvalds #define GPO_SECONDARY_AC97 0x0008
2941da177e4SLinus Torvalds #define GPI_VOL_DOWN 0x0010
2951da177e4SLinus Torvalds #define GPI_VOL_UP 0x0020
2961da177e4SLinus Torvalds #define GPI_IIS_CLK 0x0040
2971da177e4SLinus Torvalds #define GPI_IIS_LRCLK 0x0080
2981da177e4SLinus Torvalds #define GPI_IIS_DATA 0x0100
2991da177e4SLinus Torvalds #define GPI_DOCKING_STATUS 0x0100
3001da177e4SLinus Torvalds #define GPI_HEADPHONE_SENSE 0x0200
3011da177e4SLinus Torvalds #define GPO_EXT_AMP_SHUTDOWN 0x1000
3021da177e4SLinus Torvalds
3031da177e4SLinus Torvalds #define GPO_EXT_AMP_M3 1 /* default m3 amp */
3041da177e4SLinus Torvalds #define GPO_EXT_AMP_ALLEGRO 8 /* default allegro amp */
3051da177e4SLinus Torvalds
3061da177e4SLinus Torvalds /* M3 */
3071da177e4SLinus Torvalds #define GPO_M3_EXT_AMP_SHUTDN 0x0002
3081da177e4SLinus Torvalds
3091da177e4SLinus Torvalds #define ASSP_INDEX_PORT 0x80
3101da177e4SLinus Torvalds #define ASSP_MEMORY_PORT 0x82
3111da177e4SLinus Torvalds #define ASSP_DATA_PORT 0x84
3121da177e4SLinus Torvalds
3131da177e4SLinus Torvalds #define MPU401_DATA_PORT 0x98
3141da177e4SLinus Torvalds #define MPU401_STATUS_PORT 0x99
3151da177e4SLinus Torvalds
3161da177e4SLinus Torvalds #define CLK_MULT_DATA_PORT 0x9C
3171da177e4SLinus Torvalds
3181da177e4SLinus Torvalds #define ASSP_CONTROL_A 0xA2
3191da177e4SLinus Torvalds #define ASSP_0_WS_ENABLE 0x01
3201da177e4SLinus Torvalds #define ASSP_CTRL_A_RESERVED1 0x02
3211da177e4SLinus Torvalds #define ASSP_CTRL_A_RESERVED2 0x04
3221da177e4SLinus Torvalds #define ASSP_CLK_49MHZ_SELECT 0x08
3231da177e4SLinus Torvalds #define FAST_PLU_ENABLE 0x10
3241da177e4SLinus Torvalds #define ASSP_CTRL_A_RESERVED3 0x20
3251da177e4SLinus Torvalds #define DSP_CLK_36MHZ_SELECT 0x40
3261da177e4SLinus Torvalds
3271da177e4SLinus Torvalds #define ASSP_CONTROL_B 0xA4
3281da177e4SLinus Torvalds #define RESET_ASSP 0x00
3291da177e4SLinus Torvalds #define RUN_ASSP 0x01
3301da177e4SLinus Torvalds #define ENABLE_ASSP_CLOCK 0x00
3311da177e4SLinus Torvalds #define STOP_ASSP_CLOCK 0x10
3321da177e4SLinus Torvalds #define RESET_TOGGLE 0x40
3331da177e4SLinus Torvalds
3341da177e4SLinus Torvalds #define ASSP_CONTROL_C 0xA6
3351da177e4SLinus Torvalds #define ASSP_HOST_INT_ENABLE 0x01
3361da177e4SLinus Torvalds #define FM_ADDR_REMAP_DISABLE 0x02
3371da177e4SLinus Torvalds #define HOST_WRITE_PORT_ENABLE 0x08
3381da177e4SLinus Torvalds
3391da177e4SLinus Torvalds #define ASSP_HOST_INT_STATUS 0xAC
3401da177e4SLinus Torvalds #define DSP2HOST_REQ_PIORECORD 0x01
3411da177e4SLinus Torvalds #define DSP2HOST_REQ_I2SRATE 0x02
3421da177e4SLinus Torvalds #define DSP2HOST_REQ_TIMER 0x04
3431da177e4SLinus Torvalds
3441da177e4SLinus Torvalds /*
3451da177e4SLinus Torvalds * ASSP control regs
3461da177e4SLinus Torvalds */
3471da177e4SLinus Torvalds #define DSP_PORT_TIMER_COUNT 0x06
3481da177e4SLinus Torvalds
3491da177e4SLinus Torvalds #define DSP_PORT_MEMORY_INDEX 0x80
3501da177e4SLinus Torvalds
3511da177e4SLinus Torvalds #define DSP_PORT_MEMORY_TYPE 0x82
3521da177e4SLinus Torvalds #define MEMTYPE_INTERNAL_CODE 0x0002
3531da177e4SLinus Torvalds #define MEMTYPE_INTERNAL_DATA 0x0003
3541da177e4SLinus Torvalds #define MEMTYPE_MASK 0x0003
3551da177e4SLinus Torvalds
3561da177e4SLinus Torvalds #define DSP_PORT_MEMORY_DATA 0x84
3571da177e4SLinus Torvalds
3581da177e4SLinus Torvalds #define DSP_PORT_CONTROL_REG_A 0xA2
3591da177e4SLinus Torvalds #define DSP_PORT_CONTROL_REG_B 0xA4
3601da177e4SLinus Torvalds #define DSP_PORT_CONTROL_REG_C 0xA6
3611da177e4SLinus Torvalds
3621da177e4SLinus Torvalds #define REV_A_CODE_MEMORY_BEGIN 0x0000
3631da177e4SLinus Torvalds #define REV_A_CODE_MEMORY_END 0x0FFF
3641da177e4SLinus Torvalds #define REV_A_CODE_MEMORY_UNIT_LENGTH 0x0040
3651da177e4SLinus Torvalds #define REV_A_CODE_MEMORY_LENGTH (REV_A_CODE_MEMORY_END - REV_A_CODE_MEMORY_BEGIN + 1)
3661da177e4SLinus Torvalds
3671da177e4SLinus Torvalds #define REV_B_CODE_MEMORY_BEGIN 0x0000
3681da177e4SLinus Torvalds #define REV_B_CODE_MEMORY_END 0x0BFF
3691da177e4SLinus Torvalds #define REV_B_CODE_MEMORY_UNIT_LENGTH 0x0040
3701da177e4SLinus Torvalds #define REV_B_CODE_MEMORY_LENGTH (REV_B_CODE_MEMORY_END - REV_B_CODE_MEMORY_BEGIN + 1)
3711da177e4SLinus Torvalds
3721da177e4SLinus Torvalds #define REV_A_DATA_MEMORY_BEGIN 0x1000
3731da177e4SLinus Torvalds #define REV_A_DATA_MEMORY_END 0x2FFF
3741da177e4SLinus Torvalds #define REV_A_DATA_MEMORY_UNIT_LENGTH 0x0080
3751da177e4SLinus Torvalds #define REV_A_DATA_MEMORY_LENGTH (REV_A_DATA_MEMORY_END - REV_A_DATA_MEMORY_BEGIN + 1)
3761da177e4SLinus Torvalds
3771da177e4SLinus Torvalds #define REV_B_DATA_MEMORY_BEGIN 0x1000
3781da177e4SLinus Torvalds #define REV_B_DATA_MEMORY_END 0x2BFF
3791da177e4SLinus Torvalds #define REV_B_DATA_MEMORY_UNIT_LENGTH 0x0080
3801da177e4SLinus Torvalds #define REV_B_DATA_MEMORY_LENGTH (REV_B_DATA_MEMORY_END - REV_B_DATA_MEMORY_BEGIN + 1)
3811da177e4SLinus Torvalds
3821da177e4SLinus Torvalds
3831da177e4SLinus Torvalds #define NUM_UNITS_KERNEL_CODE 16
3841da177e4SLinus Torvalds #define NUM_UNITS_KERNEL_DATA 2
3851da177e4SLinus Torvalds
3861da177e4SLinus Torvalds #define NUM_UNITS_KERNEL_CODE_WITH_HSP 16
3871da177e4SLinus Torvalds #define NUM_UNITS_KERNEL_DATA_WITH_HSP 5
3881da177e4SLinus Torvalds
3891da177e4SLinus Torvalds /*
3901da177e4SLinus Torvalds * Kernel data layout
3911da177e4SLinus Torvalds */
3921da177e4SLinus Torvalds
3931da177e4SLinus Torvalds #define DP_SHIFT_COUNT 7
3941da177e4SLinus Torvalds
3951da177e4SLinus Torvalds #define KDATA_BASE_ADDR 0x1000
3961da177e4SLinus Torvalds #define KDATA_BASE_ADDR2 0x1080
3971da177e4SLinus Torvalds
3981da177e4SLinus Torvalds #define KDATA_TASK0 (KDATA_BASE_ADDR + 0x0000)
3991da177e4SLinus Torvalds #define KDATA_TASK1 (KDATA_BASE_ADDR + 0x0001)
4001da177e4SLinus Torvalds #define KDATA_TASK2 (KDATA_BASE_ADDR + 0x0002)
4011da177e4SLinus Torvalds #define KDATA_TASK3 (KDATA_BASE_ADDR + 0x0003)
4021da177e4SLinus Torvalds #define KDATA_TASK4 (KDATA_BASE_ADDR + 0x0004)
4031da177e4SLinus Torvalds #define KDATA_TASK5 (KDATA_BASE_ADDR + 0x0005)
4041da177e4SLinus Torvalds #define KDATA_TASK6 (KDATA_BASE_ADDR + 0x0006)
4051da177e4SLinus Torvalds #define KDATA_TASK7 (KDATA_BASE_ADDR + 0x0007)
4061da177e4SLinus Torvalds #define KDATA_TASK_ENDMARK (KDATA_BASE_ADDR + 0x0008)
4071da177e4SLinus Torvalds
4081da177e4SLinus Torvalds #define KDATA_CURRENT_TASK (KDATA_BASE_ADDR + 0x0009)
4091da177e4SLinus Torvalds #define KDATA_TASK_SWITCH (KDATA_BASE_ADDR + 0x000A)
4101da177e4SLinus Torvalds
4111da177e4SLinus Torvalds #define KDATA_INSTANCE0_POS3D (KDATA_BASE_ADDR + 0x000B)
4121da177e4SLinus Torvalds #define KDATA_INSTANCE1_POS3D (KDATA_BASE_ADDR + 0x000C)
4131da177e4SLinus Torvalds #define KDATA_INSTANCE2_POS3D (KDATA_BASE_ADDR + 0x000D)
4141da177e4SLinus Torvalds #define KDATA_INSTANCE3_POS3D (KDATA_BASE_ADDR + 0x000E)
4151da177e4SLinus Torvalds #define KDATA_INSTANCE4_POS3D (KDATA_BASE_ADDR + 0x000F)
4161da177e4SLinus Torvalds #define KDATA_INSTANCE5_POS3D (KDATA_BASE_ADDR + 0x0010)
4171da177e4SLinus Torvalds #define KDATA_INSTANCE6_POS3D (KDATA_BASE_ADDR + 0x0011)
4181da177e4SLinus Torvalds #define KDATA_INSTANCE7_POS3D (KDATA_BASE_ADDR + 0x0012)
4191da177e4SLinus Torvalds #define KDATA_INSTANCE8_POS3D (KDATA_BASE_ADDR + 0x0013)
4201da177e4SLinus Torvalds #define KDATA_INSTANCE_POS3D_ENDMARK (KDATA_BASE_ADDR + 0x0014)
4211da177e4SLinus Torvalds
4221da177e4SLinus Torvalds #define KDATA_INSTANCE0_SPKVIRT (KDATA_BASE_ADDR + 0x0015)
4231da177e4SLinus Torvalds #define KDATA_INSTANCE_SPKVIRT_ENDMARK (KDATA_BASE_ADDR + 0x0016)
4241da177e4SLinus Torvalds
4251da177e4SLinus Torvalds #define KDATA_INSTANCE0_SPDIF (KDATA_BASE_ADDR + 0x0017)
4261da177e4SLinus Torvalds #define KDATA_INSTANCE_SPDIF_ENDMARK (KDATA_BASE_ADDR + 0x0018)
4271da177e4SLinus Torvalds
4281da177e4SLinus Torvalds #define KDATA_INSTANCE0_MODEM (KDATA_BASE_ADDR + 0x0019)
4291da177e4SLinus Torvalds #define KDATA_INSTANCE_MODEM_ENDMARK (KDATA_BASE_ADDR + 0x001A)
4301da177e4SLinus Torvalds
4311da177e4SLinus Torvalds #define KDATA_INSTANCE0_SRC (KDATA_BASE_ADDR + 0x001B)
4321da177e4SLinus Torvalds #define KDATA_INSTANCE1_SRC (KDATA_BASE_ADDR + 0x001C)
4331da177e4SLinus Torvalds #define KDATA_INSTANCE_SRC_ENDMARK (KDATA_BASE_ADDR + 0x001D)
4341da177e4SLinus Torvalds
4351da177e4SLinus Torvalds #define KDATA_INSTANCE0_MINISRC (KDATA_BASE_ADDR + 0x001E)
4361da177e4SLinus Torvalds #define KDATA_INSTANCE1_MINISRC (KDATA_BASE_ADDR + 0x001F)
4371da177e4SLinus Torvalds #define KDATA_INSTANCE2_MINISRC (KDATA_BASE_ADDR + 0x0020)
4381da177e4SLinus Torvalds #define KDATA_INSTANCE3_MINISRC (KDATA_BASE_ADDR + 0x0021)
4391da177e4SLinus Torvalds #define KDATA_INSTANCE_MINISRC_ENDMARK (KDATA_BASE_ADDR + 0x0022)
4401da177e4SLinus Torvalds
4411da177e4SLinus Torvalds #define KDATA_INSTANCE0_CPYTHRU (KDATA_BASE_ADDR + 0x0023)
4421da177e4SLinus Torvalds #define KDATA_INSTANCE1_CPYTHRU (KDATA_BASE_ADDR + 0x0024)
4431da177e4SLinus Torvalds #define KDATA_INSTANCE_CPYTHRU_ENDMARK (KDATA_BASE_ADDR + 0x0025)
4441da177e4SLinus Torvalds
4451da177e4SLinus Torvalds #define KDATA_CURRENT_DMA (KDATA_BASE_ADDR + 0x0026)
4461da177e4SLinus Torvalds #define KDATA_DMA_SWITCH (KDATA_BASE_ADDR + 0x0027)
4471da177e4SLinus Torvalds #define KDATA_DMA_ACTIVE (KDATA_BASE_ADDR + 0x0028)
4481da177e4SLinus Torvalds
4491da177e4SLinus Torvalds #define KDATA_DMA_XFER0 (KDATA_BASE_ADDR + 0x0029)
4501da177e4SLinus Torvalds #define KDATA_DMA_XFER1 (KDATA_BASE_ADDR + 0x002A)
4511da177e4SLinus Torvalds #define KDATA_DMA_XFER2 (KDATA_BASE_ADDR + 0x002B)
4521da177e4SLinus Torvalds #define KDATA_DMA_XFER3 (KDATA_BASE_ADDR + 0x002C)
4531da177e4SLinus Torvalds #define KDATA_DMA_XFER4 (KDATA_BASE_ADDR + 0x002D)
4541da177e4SLinus Torvalds #define KDATA_DMA_XFER5 (KDATA_BASE_ADDR + 0x002E)
4551da177e4SLinus Torvalds #define KDATA_DMA_XFER6 (KDATA_BASE_ADDR + 0x002F)
4561da177e4SLinus Torvalds #define KDATA_DMA_XFER7 (KDATA_BASE_ADDR + 0x0030)
4571da177e4SLinus Torvalds #define KDATA_DMA_XFER8 (KDATA_BASE_ADDR + 0x0031)
4581da177e4SLinus Torvalds #define KDATA_DMA_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0032)
4591da177e4SLinus Torvalds
4601da177e4SLinus Torvalds #define KDATA_I2S_SAMPLE_COUNT (KDATA_BASE_ADDR + 0x0033)
4611da177e4SLinus Torvalds #define KDATA_I2S_INT_METER (KDATA_BASE_ADDR + 0x0034)
4621da177e4SLinus Torvalds #define KDATA_I2S_ACTIVE (KDATA_BASE_ADDR + 0x0035)
4631da177e4SLinus Torvalds
4641da177e4SLinus Torvalds #define KDATA_TIMER_COUNT_RELOAD (KDATA_BASE_ADDR + 0x0036)
4651da177e4SLinus Torvalds #define KDATA_TIMER_COUNT_CURRENT (KDATA_BASE_ADDR + 0x0037)
4661da177e4SLinus Torvalds
4671da177e4SLinus Torvalds #define KDATA_HALT_SYNCH_CLIENT (KDATA_BASE_ADDR + 0x0038)
4681da177e4SLinus Torvalds #define KDATA_HALT_SYNCH_DMA (KDATA_BASE_ADDR + 0x0039)
4691da177e4SLinus Torvalds #define KDATA_HALT_ACKNOWLEDGE (KDATA_BASE_ADDR + 0x003A)
4701da177e4SLinus Torvalds
4711da177e4SLinus Torvalds #define KDATA_ADC1_XFER0 (KDATA_BASE_ADDR + 0x003B)
4721da177e4SLinus Torvalds #define KDATA_ADC1_XFER_ENDMARK (KDATA_BASE_ADDR + 0x003C)
4731da177e4SLinus Torvalds #define KDATA_ADC1_LEFT_VOLUME (KDATA_BASE_ADDR + 0x003D)
4741da177e4SLinus Torvalds #define KDATA_ADC1_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x003E)
4751da177e4SLinus Torvalds #define KDATA_ADC1_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x003F)
4761da177e4SLinus Torvalds #define KDATA_ADC1_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x0040)
4771da177e4SLinus Torvalds
4781da177e4SLinus Torvalds #define KDATA_ADC2_XFER0 (KDATA_BASE_ADDR + 0x0041)
4791da177e4SLinus Torvalds #define KDATA_ADC2_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0042)
4801da177e4SLinus Torvalds #define KDATA_ADC2_LEFT_VOLUME (KDATA_BASE_ADDR + 0x0043)
4811da177e4SLinus Torvalds #define KDATA_ADC2_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x0044)
4821da177e4SLinus Torvalds #define KDATA_ADC2_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x0045)
4831da177e4SLinus Torvalds #define KDATA_ADC2_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x0046)
4841da177e4SLinus Torvalds
4851da177e4SLinus Torvalds #define KDATA_CD_XFER0 (KDATA_BASE_ADDR + 0x0047)
4861da177e4SLinus Torvalds #define KDATA_CD_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0048)
4871da177e4SLinus Torvalds #define KDATA_CD_LEFT_VOLUME (KDATA_BASE_ADDR + 0x0049)
4881da177e4SLinus Torvalds #define KDATA_CD_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x004A)
4891da177e4SLinus Torvalds #define KDATA_CD_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x004B)
4901da177e4SLinus Torvalds #define KDATA_CD_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x004C)
4911da177e4SLinus Torvalds
4921da177e4SLinus Torvalds #define KDATA_MIC_XFER0 (KDATA_BASE_ADDR + 0x004D)
4931da177e4SLinus Torvalds #define KDATA_MIC_XFER_ENDMARK (KDATA_BASE_ADDR + 0x004E)
4941da177e4SLinus Torvalds #define KDATA_MIC_VOLUME (KDATA_BASE_ADDR + 0x004F)
4951da177e4SLinus Torvalds #define KDATA_MIC_SUR_VOL (KDATA_BASE_ADDR + 0x0050)
4961da177e4SLinus Torvalds
4971da177e4SLinus Torvalds #define KDATA_I2S_XFER0 (KDATA_BASE_ADDR + 0x0051)
4981da177e4SLinus Torvalds #define KDATA_I2S_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0052)
4991da177e4SLinus Torvalds
5001da177e4SLinus Torvalds #define KDATA_CHI_XFER0 (KDATA_BASE_ADDR + 0x0053)
5011da177e4SLinus Torvalds #define KDATA_CHI_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0054)
5021da177e4SLinus Torvalds
5031da177e4SLinus Torvalds #define KDATA_SPDIF_XFER (KDATA_BASE_ADDR + 0x0055)
5041da177e4SLinus Torvalds #define KDATA_SPDIF_CURRENT_FRAME (KDATA_BASE_ADDR + 0x0056)
5051da177e4SLinus Torvalds #define KDATA_SPDIF_FRAME0 (KDATA_BASE_ADDR + 0x0057)
5061da177e4SLinus Torvalds #define KDATA_SPDIF_FRAME1 (KDATA_BASE_ADDR + 0x0058)
5071da177e4SLinus Torvalds #define KDATA_SPDIF_FRAME2 (KDATA_BASE_ADDR + 0x0059)
5081da177e4SLinus Torvalds
5091da177e4SLinus Torvalds #define KDATA_SPDIF_REQUEST (KDATA_BASE_ADDR + 0x005A)
5101da177e4SLinus Torvalds #define KDATA_SPDIF_TEMP (KDATA_BASE_ADDR + 0x005B)
5111da177e4SLinus Torvalds
5121da177e4SLinus Torvalds #define KDATA_SPDIFIN_XFER0 (KDATA_BASE_ADDR + 0x005C)
5131da177e4SLinus Torvalds #define KDATA_SPDIFIN_XFER_ENDMARK (KDATA_BASE_ADDR + 0x005D)
5141da177e4SLinus Torvalds #define KDATA_SPDIFIN_INT_METER (KDATA_BASE_ADDR + 0x005E)
5151da177e4SLinus Torvalds
5161da177e4SLinus Torvalds #define KDATA_DSP_RESET_COUNT (KDATA_BASE_ADDR + 0x005F)
5171da177e4SLinus Torvalds #define KDATA_DEBUG_OUTPUT (KDATA_BASE_ADDR + 0x0060)
5181da177e4SLinus Torvalds
5191da177e4SLinus Torvalds #define KDATA_KERNEL_ISR_LIST (KDATA_BASE_ADDR + 0x0061)
5201da177e4SLinus Torvalds
5211da177e4SLinus Torvalds #define KDATA_KERNEL_ISR_CBSR1 (KDATA_BASE_ADDR + 0x0062)
5221da177e4SLinus Torvalds #define KDATA_KERNEL_ISR_CBER1 (KDATA_BASE_ADDR + 0x0063)
5231da177e4SLinus Torvalds #define KDATA_KERNEL_ISR_CBCR (KDATA_BASE_ADDR + 0x0064)
5241da177e4SLinus Torvalds #define KDATA_KERNEL_ISR_AR0 (KDATA_BASE_ADDR + 0x0065)
5251da177e4SLinus Torvalds #define KDATA_KERNEL_ISR_AR1 (KDATA_BASE_ADDR + 0x0066)
5261da177e4SLinus Torvalds #define KDATA_KERNEL_ISR_AR2 (KDATA_BASE_ADDR + 0x0067)
5271da177e4SLinus Torvalds #define KDATA_KERNEL_ISR_AR3 (KDATA_BASE_ADDR + 0x0068)
5281da177e4SLinus Torvalds #define KDATA_KERNEL_ISR_AR4 (KDATA_BASE_ADDR + 0x0069)
5291da177e4SLinus Torvalds #define KDATA_KERNEL_ISR_AR5 (KDATA_BASE_ADDR + 0x006A)
5301da177e4SLinus Torvalds #define KDATA_KERNEL_ISR_BRCR (KDATA_BASE_ADDR + 0x006B)
5311da177e4SLinus Torvalds #define KDATA_KERNEL_ISR_PASR (KDATA_BASE_ADDR + 0x006C)
5321da177e4SLinus Torvalds #define KDATA_KERNEL_ISR_PAER (KDATA_BASE_ADDR + 0x006D)
5331da177e4SLinus Torvalds
5341da177e4SLinus Torvalds #define KDATA_CLIENT_SCRATCH0 (KDATA_BASE_ADDR + 0x006E)
5351da177e4SLinus Torvalds #define KDATA_CLIENT_SCRATCH1 (KDATA_BASE_ADDR + 0x006F)
5361da177e4SLinus Torvalds #define KDATA_KERNEL_SCRATCH (KDATA_BASE_ADDR + 0x0070)
5371da177e4SLinus Torvalds #define KDATA_KERNEL_ISR_SCRATCH (KDATA_BASE_ADDR + 0x0071)
5381da177e4SLinus Torvalds
5391da177e4SLinus Torvalds #define KDATA_OUEUE_LEFT (KDATA_BASE_ADDR + 0x0072)
5401da177e4SLinus Torvalds #define KDATA_QUEUE_RIGHT (KDATA_BASE_ADDR + 0x0073)
5411da177e4SLinus Torvalds
5421da177e4SLinus Torvalds #define KDATA_ADC1_REQUEST (KDATA_BASE_ADDR + 0x0074)
5431da177e4SLinus Torvalds #define KDATA_ADC2_REQUEST (KDATA_BASE_ADDR + 0x0075)
5441da177e4SLinus Torvalds #define KDATA_CD_REQUEST (KDATA_BASE_ADDR + 0x0076)
5451da177e4SLinus Torvalds #define KDATA_MIC_REQUEST (KDATA_BASE_ADDR + 0x0077)
5461da177e4SLinus Torvalds
5471da177e4SLinus Torvalds #define KDATA_ADC1_MIXER_REQUEST (KDATA_BASE_ADDR + 0x0078)
5481da177e4SLinus Torvalds #define KDATA_ADC2_MIXER_REQUEST (KDATA_BASE_ADDR + 0x0079)
5491da177e4SLinus Torvalds #define KDATA_CD_MIXER_REQUEST (KDATA_BASE_ADDR + 0x007A)
5501da177e4SLinus Torvalds #define KDATA_MIC_MIXER_REQUEST (KDATA_BASE_ADDR + 0x007B)
5511da177e4SLinus Torvalds #define KDATA_MIC_SYNC_COUNTER (KDATA_BASE_ADDR + 0x007C)
5521da177e4SLinus Torvalds
5531da177e4SLinus Torvalds /*
5541da177e4SLinus Torvalds * second 'segment' (?) reserved for mixer
5551da177e4SLinus Torvalds * buffers..
5561da177e4SLinus Torvalds */
5571da177e4SLinus Torvalds
5581da177e4SLinus Torvalds #define KDATA_MIXER_WORD0 (KDATA_BASE_ADDR2 + 0x0000)
5591da177e4SLinus Torvalds #define KDATA_MIXER_WORD1 (KDATA_BASE_ADDR2 + 0x0001)
5601da177e4SLinus Torvalds #define KDATA_MIXER_WORD2 (KDATA_BASE_ADDR2 + 0x0002)
5611da177e4SLinus Torvalds #define KDATA_MIXER_WORD3 (KDATA_BASE_ADDR2 + 0x0003)
5621da177e4SLinus Torvalds #define KDATA_MIXER_WORD4 (KDATA_BASE_ADDR2 + 0x0004)
5631da177e4SLinus Torvalds #define KDATA_MIXER_WORD5 (KDATA_BASE_ADDR2 + 0x0005)
5641da177e4SLinus Torvalds #define KDATA_MIXER_WORD6 (KDATA_BASE_ADDR2 + 0x0006)
5651da177e4SLinus Torvalds #define KDATA_MIXER_WORD7 (KDATA_BASE_ADDR2 + 0x0007)
5661da177e4SLinus Torvalds #define KDATA_MIXER_WORD8 (KDATA_BASE_ADDR2 + 0x0008)
5671da177e4SLinus Torvalds #define KDATA_MIXER_WORD9 (KDATA_BASE_ADDR2 + 0x0009)
5681da177e4SLinus Torvalds #define KDATA_MIXER_WORDA (KDATA_BASE_ADDR2 + 0x000A)
5691da177e4SLinus Torvalds #define KDATA_MIXER_WORDB (KDATA_BASE_ADDR2 + 0x000B)
5701da177e4SLinus Torvalds #define KDATA_MIXER_WORDC (KDATA_BASE_ADDR2 + 0x000C)
5711da177e4SLinus Torvalds #define KDATA_MIXER_WORDD (KDATA_BASE_ADDR2 + 0x000D)
5721da177e4SLinus Torvalds #define KDATA_MIXER_WORDE (KDATA_BASE_ADDR2 + 0x000E)
5731da177e4SLinus Torvalds #define KDATA_MIXER_WORDF (KDATA_BASE_ADDR2 + 0x000F)
5741da177e4SLinus Torvalds
5751da177e4SLinus Torvalds #define KDATA_MIXER_XFER0 (KDATA_BASE_ADDR2 + 0x0010)
5761da177e4SLinus Torvalds #define KDATA_MIXER_XFER1 (KDATA_BASE_ADDR2 + 0x0011)
5771da177e4SLinus Torvalds #define KDATA_MIXER_XFER2 (KDATA_BASE_ADDR2 + 0x0012)
5781da177e4SLinus Torvalds #define KDATA_MIXER_XFER3 (KDATA_BASE_ADDR2 + 0x0013)
5791da177e4SLinus Torvalds #define KDATA_MIXER_XFER4 (KDATA_BASE_ADDR2 + 0x0014)
5801da177e4SLinus Torvalds #define KDATA_MIXER_XFER5 (KDATA_BASE_ADDR2 + 0x0015)
5811da177e4SLinus Torvalds #define KDATA_MIXER_XFER6 (KDATA_BASE_ADDR2 + 0x0016)
5821da177e4SLinus Torvalds #define KDATA_MIXER_XFER7 (KDATA_BASE_ADDR2 + 0x0017)
5831da177e4SLinus Torvalds #define KDATA_MIXER_XFER8 (KDATA_BASE_ADDR2 + 0x0018)
5841da177e4SLinus Torvalds #define KDATA_MIXER_XFER9 (KDATA_BASE_ADDR2 + 0x0019)
5851da177e4SLinus Torvalds #define KDATA_MIXER_XFER_ENDMARK (KDATA_BASE_ADDR2 + 0x001A)
5861da177e4SLinus Torvalds
5871da177e4SLinus Torvalds #define KDATA_MIXER_TASK_NUMBER (KDATA_BASE_ADDR2 + 0x001B)
5881da177e4SLinus Torvalds #define KDATA_CURRENT_MIXER (KDATA_BASE_ADDR2 + 0x001C)
5891da177e4SLinus Torvalds #define KDATA_MIXER_ACTIVE (KDATA_BASE_ADDR2 + 0x001D)
5901da177e4SLinus Torvalds #define KDATA_MIXER_BANK_STATUS (KDATA_BASE_ADDR2 + 0x001E)
5911da177e4SLinus Torvalds #define KDATA_DAC_LEFT_VOLUME (KDATA_BASE_ADDR2 + 0x001F)
5921da177e4SLinus Torvalds #define KDATA_DAC_RIGHT_VOLUME (KDATA_BASE_ADDR2 + 0x0020)
5931da177e4SLinus Torvalds
5941da177e4SLinus Torvalds #define MAX_INSTANCE_MINISRC (KDATA_INSTANCE_MINISRC_ENDMARK - KDATA_INSTANCE0_MINISRC)
5951da177e4SLinus Torvalds #define MAX_VIRTUAL_DMA_CHANNELS (KDATA_DMA_XFER_ENDMARK - KDATA_DMA_XFER0)
5961da177e4SLinus Torvalds #define MAX_VIRTUAL_MIXER_CHANNELS (KDATA_MIXER_XFER_ENDMARK - KDATA_MIXER_XFER0)
5971da177e4SLinus Torvalds #define MAX_VIRTUAL_ADC1_CHANNELS (KDATA_ADC1_XFER_ENDMARK - KDATA_ADC1_XFER0)
5981da177e4SLinus Torvalds
5991da177e4SLinus Torvalds /*
6001da177e4SLinus Torvalds * client data area offsets
6011da177e4SLinus Torvalds */
6021da177e4SLinus Torvalds #define CDATA_INSTANCE_READY 0x00
6031da177e4SLinus Torvalds
6041da177e4SLinus Torvalds #define CDATA_HOST_SRC_ADDRL 0x01
6051da177e4SLinus Torvalds #define CDATA_HOST_SRC_ADDRH 0x02
6061da177e4SLinus Torvalds #define CDATA_HOST_SRC_END_PLUS_1L 0x03
6071da177e4SLinus Torvalds #define CDATA_HOST_SRC_END_PLUS_1H 0x04
6081da177e4SLinus Torvalds #define CDATA_HOST_SRC_CURRENTL 0x05
6091da177e4SLinus Torvalds #define CDATA_HOST_SRC_CURRENTH 0x06
6101da177e4SLinus Torvalds
6111da177e4SLinus Torvalds #define CDATA_IN_BUF_CONNECT 0x07
6121da177e4SLinus Torvalds #define CDATA_OUT_BUF_CONNECT 0x08
6131da177e4SLinus Torvalds
6141da177e4SLinus Torvalds #define CDATA_IN_BUF_BEGIN 0x09
6151da177e4SLinus Torvalds #define CDATA_IN_BUF_END_PLUS_1 0x0A
6161da177e4SLinus Torvalds #define CDATA_IN_BUF_HEAD 0x0B
6171da177e4SLinus Torvalds #define CDATA_IN_BUF_TAIL 0x0C
6181da177e4SLinus Torvalds #define CDATA_OUT_BUF_BEGIN 0x0D
6191da177e4SLinus Torvalds #define CDATA_OUT_BUF_END_PLUS_1 0x0E
6201da177e4SLinus Torvalds #define CDATA_OUT_BUF_HEAD 0x0F
6211da177e4SLinus Torvalds #define CDATA_OUT_BUF_TAIL 0x10
6221da177e4SLinus Torvalds
6231da177e4SLinus Torvalds #define CDATA_DMA_CONTROL 0x11
6241da177e4SLinus Torvalds #define CDATA_RESERVED 0x12
6251da177e4SLinus Torvalds
6261da177e4SLinus Torvalds #define CDATA_FREQUENCY 0x13
6271da177e4SLinus Torvalds #define CDATA_LEFT_VOLUME 0x14
6281da177e4SLinus Torvalds #define CDATA_RIGHT_VOLUME 0x15
6291da177e4SLinus Torvalds #define CDATA_LEFT_SUR_VOL 0x16
6301da177e4SLinus Torvalds #define CDATA_RIGHT_SUR_VOL 0x17
6311da177e4SLinus Torvalds
6321da177e4SLinus Torvalds #define CDATA_HEADER_LEN 0x18
6331da177e4SLinus Torvalds
6341da177e4SLinus Torvalds #define SRC3_DIRECTION_OFFSET CDATA_HEADER_LEN
6351da177e4SLinus Torvalds #define SRC3_MODE_OFFSET (CDATA_HEADER_LEN + 1)
6361da177e4SLinus Torvalds #define SRC3_WORD_LENGTH_OFFSET (CDATA_HEADER_LEN + 2)
6371da177e4SLinus Torvalds #define SRC3_PARAMETER_OFFSET (CDATA_HEADER_LEN + 3)
6381da177e4SLinus Torvalds #define SRC3_COEFF_ADDR_OFFSET (CDATA_HEADER_LEN + 8)
6391da177e4SLinus Torvalds #define SRC3_FILTAP_ADDR_OFFSET (CDATA_HEADER_LEN + 10)
6401da177e4SLinus Torvalds #define SRC3_TEMP_INBUF_ADDR_OFFSET (CDATA_HEADER_LEN + 16)
6411da177e4SLinus Torvalds #define SRC3_TEMP_OUTBUF_ADDR_OFFSET (CDATA_HEADER_LEN + 17)
6421da177e4SLinus Torvalds
6431da177e4SLinus Torvalds #define MINISRC_IN_BUFFER_SIZE ( 0x50 * 2 )
6441da177e4SLinus Torvalds #define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2)
6451da177e4SLinus Torvalds #define MINISRC_TMP_BUFFER_SIZE ( 112 + ( MINISRC_BIQUAD_STAGE * 3 + 4 ) * 2 * 2 )
6461da177e4SLinus Torvalds #define MINISRC_BIQUAD_STAGE 2
6471da177e4SLinus Torvalds #define MINISRC_COEF_LOC 0x175
6481da177e4SLinus Torvalds
6491da177e4SLinus Torvalds #define DMACONTROL_BLOCK_MASK 0x000F
6501da177e4SLinus Torvalds #define DMAC_BLOCK0_SELECTOR 0x0000
6511da177e4SLinus Torvalds #define DMAC_BLOCK1_SELECTOR 0x0001
6521da177e4SLinus Torvalds #define DMAC_BLOCK2_SELECTOR 0x0002
6531da177e4SLinus Torvalds #define DMAC_BLOCK3_SELECTOR 0x0003
6541da177e4SLinus Torvalds #define DMAC_BLOCK4_SELECTOR 0x0004
6551da177e4SLinus Torvalds #define DMAC_BLOCK5_SELECTOR 0x0005
6561da177e4SLinus Torvalds #define DMAC_BLOCK6_SELECTOR 0x0006
6571da177e4SLinus Torvalds #define DMAC_BLOCK7_SELECTOR 0x0007
6581da177e4SLinus Torvalds #define DMAC_BLOCK8_SELECTOR 0x0008
6591da177e4SLinus Torvalds #define DMAC_BLOCK9_SELECTOR 0x0009
6601da177e4SLinus Torvalds #define DMAC_BLOCKA_SELECTOR 0x000A
6611da177e4SLinus Torvalds #define DMAC_BLOCKB_SELECTOR 0x000B
6621da177e4SLinus Torvalds #define DMAC_BLOCKC_SELECTOR 0x000C
6631da177e4SLinus Torvalds #define DMAC_BLOCKD_SELECTOR 0x000D
6641da177e4SLinus Torvalds #define DMAC_BLOCKE_SELECTOR 0x000E
6651da177e4SLinus Torvalds #define DMAC_BLOCKF_SELECTOR 0x000F
6661da177e4SLinus Torvalds #define DMACONTROL_PAGE_MASK 0x00F0
6671da177e4SLinus Torvalds #define DMAC_PAGE0_SELECTOR 0x0030
6681da177e4SLinus Torvalds #define DMAC_PAGE1_SELECTOR 0x0020
6691da177e4SLinus Torvalds #define DMAC_PAGE2_SELECTOR 0x0010
6701da177e4SLinus Torvalds #define DMAC_PAGE3_SELECTOR 0x0000
6711da177e4SLinus Torvalds #define DMACONTROL_AUTOREPEAT 0x1000
6721da177e4SLinus Torvalds #define DMACONTROL_STOPPED 0x2000
6731da177e4SLinus Torvalds #define DMACONTROL_DIRECTION 0x0100
6741da177e4SLinus Torvalds
6751da177e4SLinus Torvalds /*
6761da177e4SLinus Torvalds * an arbitrary volume we set the internal
6771da177e4SLinus Torvalds * volume settings to so that the ac97 volume
6781da177e4SLinus Torvalds * range is a little less insane. 0x7fff is
6791da177e4SLinus Torvalds * max.
6801da177e4SLinus Torvalds */
6811da177e4SLinus Torvalds #define ARB_VOLUME ( 0x6800 )
6821da177e4SLinus Torvalds
6831da177e4SLinus Torvalds /*
6841da177e4SLinus Torvalds */
6851da177e4SLinus Torvalds
6861da177e4SLinus Torvalds struct m3_list {
6871da177e4SLinus Torvalds int curlen;
6881da177e4SLinus Torvalds int mem_addr;
6891da177e4SLinus Torvalds int max;
6901da177e4SLinus Torvalds };
6911da177e4SLinus Torvalds
6923470c29dSTakashi Iwai struct m3_dma {
6931da177e4SLinus Torvalds
6941da177e4SLinus Torvalds int number;
6953470c29dSTakashi Iwai struct snd_pcm_substream *substream;
6961da177e4SLinus Torvalds
6971da177e4SLinus Torvalds struct assp_instance {
6981da177e4SLinus Torvalds unsigned short code, data;
6991da177e4SLinus Torvalds } inst;
7001da177e4SLinus Torvalds
7011da177e4SLinus Torvalds int running;
7021da177e4SLinus Torvalds int opened;
7031da177e4SLinus Torvalds
7041da177e4SLinus Torvalds unsigned long buffer_addr;
7051da177e4SLinus Torvalds int dma_size;
7061da177e4SLinus Torvalds int period_size;
7071da177e4SLinus Torvalds unsigned int hwptr;
7081da177e4SLinus Torvalds int count;
7091da177e4SLinus Torvalds
7101da177e4SLinus Torvalds int index[3];
7111da177e4SLinus Torvalds struct m3_list *index_list[3];
7121da177e4SLinus Torvalds
7131da177e4SLinus Torvalds int in_lists;
7141da177e4SLinus Torvalds
7151da177e4SLinus Torvalds struct list_head list;
7161da177e4SLinus Torvalds
7171da177e4SLinus Torvalds };
7181da177e4SLinus Torvalds
7191da177e4SLinus Torvalds struct snd_m3 {
7201da177e4SLinus Torvalds
7213470c29dSTakashi Iwai struct snd_card *card;
7221da177e4SLinus Torvalds
7231da177e4SLinus Torvalds unsigned long iobase;
7241da177e4SLinus Torvalds
7251da177e4SLinus Torvalds int irq;
7261da177e4SLinus Torvalds unsigned int allegro_flag : 1;
7271da177e4SLinus Torvalds
7283470c29dSTakashi Iwai struct snd_ac97 *ac97;
7291da177e4SLinus Torvalds
7303470c29dSTakashi Iwai struct snd_pcm *pcm;
7311da177e4SLinus Torvalds
7321da177e4SLinus Torvalds struct pci_dev *pci;
7331da177e4SLinus Torvalds
7341da177e4SLinus Torvalds int dacs_active;
7351da177e4SLinus Torvalds int timer_users;
7361da177e4SLinus Torvalds
7371da177e4SLinus Torvalds struct m3_list msrc_list;
7381da177e4SLinus Torvalds struct m3_list mixer_list;
7391da177e4SLinus Torvalds struct m3_list adc1_list;
7401da177e4SLinus Torvalds struct m3_list dma_list;
7411da177e4SLinus Torvalds
7421da177e4SLinus Torvalds /* for storing reset state..*/
7431da177e4SLinus Torvalds u8 reset_state;
7441da177e4SLinus Torvalds
7451da177e4SLinus Torvalds int external_amp;
7461061eeb4STakashi Iwai int amp_gpio; /* gpio pin # for external amp, -1 = default */
7471061eeb4STakashi Iwai unsigned int hv_config; /* hardware-volume config bits */
7481061eeb4STakashi Iwai unsigned irda_workaround :1; /* avoid to touch 0x10 on GPIO_DIRECTION
7491061eeb4STakashi Iwai (e.g. for IrDA on Dell Inspirons) */
7501061eeb4STakashi Iwai unsigned is_omnibook :1; /* Do HP OmniBook GPIO magic? */
7511da177e4SLinus Torvalds
7521da177e4SLinus Torvalds /* midi */
7533470c29dSTakashi Iwai struct snd_rawmidi *rmidi;
7541da177e4SLinus Torvalds
7551da177e4SLinus Torvalds /* pcm streams */
7561da177e4SLinus Torvalds int num_substreams;
7573470c29dSTakashi Iwai struct m3_dma *substreams;
7581da177e4SLinus Torvalds
7591da177e4SLinus Torvalds spinlock_t reg_lock;
760db68d15dSVille Syrjala
761eb581adfSHans de Goede #ifdef CONFIG_SND_MAESTRO3_INPUT
762eb581adfSHans de Goede struct input_dev *input_dev;
763eb581adfSHans de Goede char phys[64]; /* physical device path */
764eb581adfSHans de Goede #else
7653470c29dSTakashi Iwai struct snd_kcontrol *master_switch;
7663470c29dSTakashi Iwai struct snd_kcontrol *master_volume;
767eb581adfSHans de Goede #endif
76830bdee02STakashi Iwai struct work_struct hwvol_work;
769eb581adfSHans de Goede
770715aa675SHans de Goede unsigned int in_suspend;
7711da177e4SLinus Torvalds
772c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
7731da177e4SLinus Torvalds u16 *suspend_mem;
7741da177e4SLinus Torvalds #endif
77581d7724aSClemens Ladisch
77681d7724aSClemens Ladisch const struct firmware *assp_kernel_image;
77781d7724aSClemens Ladisch const struct firmware *assp_minisrc_image;
7781da177e4SLinus Torvalds };
7791da177e4SLinus Torvalds
7801da177e4SLinus Torvalds /*
7811da177e4SLinus Torvalds * pci ids
7821da177e4SLinus Torvalds */
7839baa3c34SBenoit Taine static const struct pci_device_id snd_m3_ids[] = {
7841da177e4SLinus Torvalds {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO_1, PCI_ANY_ID, PCI_ANY_ID,
7851da177e4SLinus Torvalds PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
7861da177e4SLinus Torvalds {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO, PCI_ANY_ID, PCI_ANY_ID,
7871da177e4SLinus Torvalds PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
7881da177e4SLinus Torvalds {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_CANYON3D_2LE, PCI_ANY_ID, PCI_ANY_ID,
7891da177e4SLinus Torvalds PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
7901da177e4SLinus Torvalds {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_CANYON3D_2, PCI_ANY_ID, PCI_ANY_ID,
7911da177e4SLinus Torvalds PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
7921da177e4SLinus Torvalds {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3, PCI_ANY_ID, PCI_ANY_ID,
7931da177e4SLinus Torvalds PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
7941da177e4SLinus Torvalds {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3_1, PCI_ANY_ID, PCI_ANY_ID,
7951da177e4SLinus Torvalds PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
7961da177e4SLinus Torvalds {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3_HW, PCI_ANY_ID, PCI_ANY_ID,
7971da177e4SLinus Torvalds PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
7981da177e4SLinus Torvalds {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3_2, PCI_ANY_ID, PCI_ANY_ID,
7991da177e4SLinus Torvalds PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
8001da177e4SLinus Torvalds {0,},
8011da177e4SLinus Torvalds };
8021da177e4SLinus Torvalds
8031da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, snd_m3_ids);
8041da177e4SLinus Torvalds
80588e540a8STakashi Iwai static const struct snd_pci_quirk m3_amp_quirk_list[] = {
8067efbfd1aSHans de Goede SND_PCI_QUIRK(0x0E11, 0x0094, "Compaq Evo N600c", 0x0c),
8071061eeb4STakashi Iwai SND_PCI_QUIRK(0x10f7, 0x833e, "Panasonic CF-28", 0x0d),
8081061eeb4STakashi Iwai SND_PCI_QUIRK(0x10f7, 0x833d, "Panasonic CF-72", 0x0d),
8091061eeb4STakashi Iwai SND_PCI_QUIRK(0x1033, 0x80f1, "NEC LM800J/7", 0x03),
8101061eeb4STakashi Iwai SND_PCI_QUIRK(0x1509, 0x1740, "LEGEND ZhaoYang 3100CF", 0x03),
8111061eeb4STakashi Iwai { } /* END */
8121da177e4SLinus Torvalds };
8131da177e4SLinus Torvalds
81488e540a8STakashi Iwai static const struct snd_pci_quirk m3_irda_quirk_list[] = {
8151061eeb4STakashi Iwai SND_PCI_QUIRK(0x1028, 0x00b0, "Dell Inspiron 4000", 1),
8161061eeb4STakashi Iwai SND_PCI_QUIRK(0x1028, 0x00a4, "Dell Inspiron 8000", 1),
8171061eeb4STakashi Iwai SND_PCI_QUIRK(0x1028, 0x00e6, "Dell Inspiron 8100", 1),
8181061eeb4STakashi Iwai { } /* END */
8191061eeb4STakashi Iwai };
8201061eeb4STakashi Iwai
8211061eeb4STakashi Iwai /* hardware volume quirks */
82288e540a8STakashi Iwai static const struct snd_pci_quirk m3_hv_quirk_list[] = {
82382f008c2SVille Syrjala /* Allegro chips */
8241061eeb4STakashi Iwai SND_PCI_QUIRK(0x0E11, 0x002E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8251061eeb4STakashi Iwai SND_PCI_QUIRK(0x0E11, 0x0094, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8261061eeb4STakashi Iwai SND_PCI_QUIRK(0x0E11, 0xB112, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8271061eeb4STakashi Iwai SND_PCI_QUIRK(0x0E11, 0xB114, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8281061eeb4STakashi Iwai SND_PCI_QUIRK(0x103C, 0x0012, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8291061eeb4STakashi Iwai SND_PCI_QUIRK(0x103C, 0x0018, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8301061eeb4STakashi Iwai SND_PCI_QUIRK(0x103C, 0x001C, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8311061eeb4STakashi Iwai SND_PCI_QUIRK(0x103C, 0x001D, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8321061eeb4STakashi Iwai SND_PCI_QUIRK(0x103C, 0x001E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8331061eeb4STakashi Iwai SND_PCI_QUIRK(0x107B, 0x3350, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8341061eeb4STakashi Iwai SND_PCI_QUIRK(0x10F7, 0x8338, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8351061eeb4STakashi Iwai SND_PCI_QUIRK(0x10F7, 0x833C, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8361061eeb4STakashi Iwai SND_PCI_QUIRK(0x10F7, 0x833D, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8371061eeb4STakashi Iwai SND_PCI_QUIRK(0x10F7, 0x833E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8381061eeb4STakashi Iwai SND_PCI_QUIRK(0x10F7, 0x833F, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8391061eeb4STakashi Iwai SND_PCI_QUIRK(0x13BD, 0x1018, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8401061eeb4STakashi Iwai SND_PCI_QUIRK(0x13BD, 0x1019, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8411061eeb4STakashi Iwai SND_PCI_QUIRK(0x13BD, 0x101A, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8421061eeb4STakashi Iwai SND_PCI_QUIRK(0x14FF, 0x0F03, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8431061eeb4STakashi Iwai SND_PCI_QUIRK(0x14FF, 0x0F04, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8441061eeb4STakashi Iwai SND_PCI_QUIRK(0x14FF, 0x0F05, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8451061eeb4STakashi Iwai SND_PCI_QUIRK(0x156D, 0xB400, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8461061eeb4STakashi Iwai SND_PCI_QUIRK(0x156D, 0xB795, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8471061eeb4STakashi Iwai SND_PCI_QUIRK(0x156D, 0xB797, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8481061eeb4STakashi Iwai SND_PCI_QUIRK(0x156D, 0xC700, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD),
8491061eeb4STakashi Iwai SND_PCI_QUIRK(0x1033, 0x80F1, NULL,
8501061eeb4STakashi Iwai HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
8511061eeb4STakashi Iwai SND_PCI_QUIRK(0x103C, 0x001A, NULL, /* HP OmniBook 6100 */
8521061eeb4STakashi Iwai HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
8531061eeb4STakashi Iwai SND_PCI_QUIRK(0x107B, 0x340A, NULL,
8541061eeb4STakashi Iwai HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
8551061eeb4STakashi Iwai SND_PCI_QUIRK(0x107B, 0x3450, NULL,
8561061eeb4STakashi Iwai HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
8571061eeb4STakashi Iwai SND_PCI_QUIRK(0x109F, 0x3134, NULL,
8581061eeb4STakashi Iwai HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
8591061eeb4STakashi Iwai SND_PCI_QUIRK(0x109F, 0x3161, NULL,
8601061eeb4STakashi Iwai HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
8611061eeb4STakashi Iwai SND_PCI_QUIRK(0x144D, 0x3280, NULL,
8621061eeb4STakashi Iwai HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
8631061eeb4STakashi Iwai SND_PCI_QUIRK(0x144D, 0x3281, NULL,
8641061eeb4STakashi Iwai HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
8651061eeb4STakashi Iwai SND_PCI_QUIRK(0x144D, 0xC002, NULL,
8661061eeb4STakashi Iwai HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
8671061eeb4STakashi Iwai SND_PCI_QUIRK(0x144D, 0xC003, NULL,
8681061eeb4STakashi Iwai HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
8691061eeb4STakashi Iwai SND_PCI_QUIRK(0x1509, 0x1740, NULL,
8701061eeb4STakashi Iwai HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
8711061eeb4STakashi Iwai SND_PCI_QUIRK(0x1610, 0x0010, NULL,
8721061eeb4STakashi Iwai HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE),
8731061eeb4STakashi Iwai SND_PCI_QUIRK(0x1042, 0x1042, NULL, HV_CTRL_ENABLE),
8741061eeb4STakashi Iwai SND_PCI_QUIRK(0x107B, 0x9500, NULL, HV_CTRL_ENABLE),
8751061eeb4STakashi Iwai SND_PCI_QUIRK(0x14FF, 0x0F06, NULL, HV_CTRL_ENABLE),
8761061eeb4STakashi Iwai SND_PCI_QUIRK(0x1558, 0x8586, NULL, HV_CTRL_ENABLE),
8771061eeb4STakashi Iwai SND_PCI_QUIRK(0x161F, 0x2011, NULL, HV_CTRL_ENABLE),
87882f008c2SVille Syrjala /* Maestro3 chips */
8791061eeb4STakashi Iwai SND_PCI_QUIRK(0x103C, 0x000E, NULL, HV_CTRL_ENABLE),
8801061eeb4STakashi Iwai SND_PCI_QUIRK(0x103C, 0x0010, NULL, HV_CTRL_ENABLE),
8811061eeb4STakashi Iwai SND_PCI_QUIRK(0x103C, 0x0011, NULL, HV_CTRL_ENABLE),
8821061eeb4STakashi Iwai SND_PCI_QUIRK(0x103C, 0x001B, NULL, HV_CTRL_ENABLE),
8831061eeb4STakashi Iwai SND_PCI_QUIRK(0x104D, 0x80A6, NULL, HV_CTRL_ENABLE),
8841061eeb4STakashi Iwai SND_PCI_QUIRK(0x104D, 0x80AA, NULL, HV_CTRL_ENABLE),
8851061eeb4STakashi Iwai SND_PCI_QUIRK(0x107B, 0x5300, NULL, HV_CTRL_ENABLE),
8861061eeb4STakashi Iwai SND_PCI_QUIRK(0x110A, 0x1998, NULL, HV_CTRL_ENABLE),
8871061eeb4STakashi Iwai SND_PCI_QUIRK(0x13BD, 0x1015, NULL, HV_CTRL_ENABLE),
8881061eeb4STakashi Iwai SND_PCI_QUIRK(0x13BD, 0x101C, NULL, HV_CTRL_ENABLE),
8891061eeb4STakashi Iwai SND_PCI_QUIRK(0x13BD, 0x1802, NULL, HV_CTRL_ENABLE),
8901061eeb4STakashi Iwai SND_PCI_QUIRK(0x1599, 0x0715, NULL, HV_CTRL_ENABLE),
8911061eeb4STakashi Iwai SND_PCI_QUIRK(0x5643, 0x5643, NULL, HV_CTRL_ENABLE),
8921061eeb4STakashi Iwai SND_PCI_QUIRK(0x144D, 0x3260, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
8931061eeb4STakashi Iwai SND_PCI_QUIRK(0x144D, 0x3261, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
8941061eeb4STakashi Iwai SND_PCI_QUIRK(0x144D, 0xC000, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
8951061eeb4STakashi Iwai SND_PCI_QUIRK(0x144D, 0xC001, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE),
8961061eeb4STakashi Iwai { } /* END */
8971061eeb4STakashi Iwai };
8981061eeb4STakashi Iwai
8991061eeb4STakashi Iwai /* HP Omnibook quirks */
90088e540a8STakashi Iwai static const struct snd_pci_quirk m3_omnibook_quirk_list[] = {
9011061eeb4STakashi Iwai SND_PCI_QUIRK_ID(0x103c, 0x0010), /* HP OmniBook 6000 */
9021061eeb4STakashi Iwai SND_PCI_QUIRK_ID(0x103c, 0x0011), /* HP OmniBook 500 */
9031061eeb4STakashi Iwai { } /* END */
90482f008c2SVille Syrjala };
9051da177e4SLinus Torvalds
9061da177e4SLinus Torvalds /*
9071da177e4SLinus Torvalds * lowlevel functions
9081da177e4SLinus Torvalds */
9091da177e4SLinus Torvalds
snd_m3_outw(struct snd_m3 * chip,u16 value,unsigned long reg)9103470c29dSTakashi Iwai static inline void snd_m3_outw(struct snd_m3 *chip, u16 value, unsigned long reg)
9111da177e4SLinus Torvalds {
9121da177e4SLinus Torvalds outw(value, chip->iobase + reg);
9131da177e4SLinus Torvalds }
9141da177e4SLinus Torvalds
snd_m3_inw(struct snd_m3 * chip,unsigned long reg)9153470c29dSTakashi Iwai static inline u16 snd_m3_inw(struct snd_m3 *chip, unsigned long reg)
9161da177e4SLinus Torvalds {
9171da177e4SLinus Torvalds return inw(chip->iobase + reg);
9181da177e4SLinus Torvalds }
9191da177e4SLinus Torvalds
snd_m3_outb(struct snd_m3 * chip,u8 value,unsigned long reg)9203470c29dSTakashi Iwai static inline void snd_m3_outb(struct snd_m3 *chip, u8 value, unsigned long reg)
9211da177e4SLinus Torvalds {
9221da177e4SLinus Torvalds outb(value, chip->iobase + reg);
9231da177e4SLinus Torvalds }
9241da177e4SLinus Torvalds
snd_m3_inb(struct snd_m3 * chip,unsigned long reg)9253470c29dSTakashi Iwai static inline u8 snd_m3_inb(struct snd_m3 *chip, unsigned long reg)
9261da177e4SLinus Torvalds {
9271da177e4SLinus Torvalds return inb(chip->iobase + reg);
9281da177e4SLinus Torvalds }
9291da177e4SLinus Torvalds
9301da177e4SLinus Torvalds /*
9311da177e4SLinus Torvalds * access 16bit words to the code or data regions of the dsp's memory.
9321da177e4SLinus Torvalds * index addresses 16bit words.
9331da177e4SLinus Torvalds */
snd_m3_assp_read(struct snd_m3 * chip,u16 region,u16 index)9343470c29dSTakashi Iwai static u16 snd_m3_assp_read(struct snd_m3 *chip, u16 region, u16 index)
9351da177e4SLinus Torvalds {
9361da177e4SLinus Torvalds snd_m3_outw(chip, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE);
9371da177e4SLinus Torvalds snd_m3_outw(chip, index, DSP_PORT_MEMORY_INDEX);
9381da177e4SLinus Torvalds return snd_m3_inw(chip, DSP_PORT_MEMORY_DATA);
9391da177e4SLinus Torvalds }
9401da177e4SLinus Torvalds
snd_m3_assp_write(struct snd_m3 * chip,u16 region,u16 index,u16 data)9413470c29dSTakashi Iwai static void snd_m3_assp_write(struct snd_m3 *chip, u16 region, u16 index, u16 data)
9421da177e4SLinus Torvalds {
9431da177e4SLinus Torvalds snd_m3_outw(chip, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE);
9441da177e4SLinus Torvalds snd_m3_outw(chip, index, DSP_PORT_MEMORY_INDEX);
9451da177e4SLinus Torvalds snd_m3_outw(chip, data, DSP_PORT_MEMORY_DATA);
9461da177e4SLinus Torvalds }
9471da177e4SLinus Torvalds
snd_m3_assp_halt(struct snd_m3 * chip)9483470c29dSTakashi Iwai static void snd_m3_assp_halt(struct snd_m3 *chip)
9491da177e4SLinus Torvalds {
9501da177e4SLinus Torvalds chip->reset_state = snd_m3_inb(chip, DSP_PORT_CONTROL_REG_B) & ~REGB_STOP_CLOCK;
9515ba1e7b5STakashi Iwai msleep(10);
9521da177e4SLinus Torvalds snd_m3_outb(chip, chip->reset_state & ~REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);
9531da177e4SLinus Torvalds }
9541da177e4SLinus Torvalds
snd_m3_assp_continue(struct snd_m3 * chip)9553470c29dSTakashi Iwai static void snd_m3_assp_continue(struct snd_m3 *chip)
9561da177e4SLinus Torvalds {
9571da177e4SLinus Torvalds snd_m3_outb(chip, chip->reset_state | REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);
9581da177e4SLinus Torvalds }
9591da177e4SLinus Torvalds
9601da177e4SLinus Torvalds
9611da177e4SLinus Torvalds /*
9621da177e4SLinus Torvalds * This makes me sad. the maestro3 has lists
9631da177e4SLinus Torvalds * internally that must be packed.. 0 terminates,
9641da177e4SLinus Torvalds * apparently, or maybe all unused entries have
9651da177e4SLinus Torvalds * to be 0, the lists have static lengths set
9661da177e4SLinus Torvalds * by the binary code images.
9671da177e4SLinus Torvalds */
9681da177e4SLinus Torvalds
snd_m3_add_list(struct snd_m3 * chip,struct m3_list * list,u16 val)9693470c29dSTakashi Iwai static int snd_m3_add_list(struct snd_m3 *chip, struct m3_list *list, u16 val)
9701da177e4SLinus Torvalds {
9711da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
9721da177e4SLinus Torvalds list->mem_addr + list->curlen,
9731da177e4SLinus Torvalds val);
9741da177e4SLinus Torvalds return list->curlen++;
9751da177e4SLinus Torvalds }
9761da177e4SLinus Torvalds
snd_m3_remove_list(struct snd_m3 * chip,struct m3_list * list,int index)9773470c29dSTakashi Iwai static void snd_m3_remove_list(struct snd_m3 *chip, struct m3_list *list, int index)
9781da177e4SLinus Torvalds {
9791da177e4SLinus Torvalds u16 val;
9801da177e4SLinus Torvalds int lastindex = list->curlen - 1;
9811da177e4SLinus Torvalds
9821da177e4SLinus Torvalds if (index != lastindex) {
9831da177e4SLinus Torvalds val = snd_m3_assp_read(chip, MEMTYPE_INTERNAL_DATA,
9841da177e4SLinus Torvalds list->mem_addr + lastindex);
9851da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
9861da177e4SLinus Torvalds list->mem_addr + index,
9871da177e4SLinus Torvalds val);
9881da177e4SLinus Torvalds }
9891da177e4SLinus Torvalds
9901da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
9911da177e4SLinus Torvalds list->mem_addr + lastindex,
9921da177e4SLinus Torvalds 0);
9931da177e4SLinus Torvalds
9941da177e4SLinus Torvalds list->curlen--;
9951da177e4SLinus Torvalds }
9961da177e4SLinus Torvalds
snd_m3_inc_timer_users(struct snd_m3 * chip)9973470c29dSTakashi Iwai static void snd_m3_inc_timer_users(struct snd_m3 *chip)
9981da177e4SLinus Torvalds {
9991da177e4SLinus Torvalds chip->timer_users++;
10001da177e4SLinus Torvalds if (chip->timer_users != 1)
10011da177e4SLinus Torvalds return;
10021da177e4SLinus Torvalds
10031da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
10041da177e4SLinus Torvalds KDATA_TIMER_COUNT_RELOAD,
10051da177e4SLinus Torvalds 240);
10061da177e4SLinus Torvalds
10071da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
10081da177e4SLinus Torvalds KDATA_TIMER_COUNT_CURRENT,
10091da177e4SLinus Torvalds 240);
10101da177e4SLinus Torvalds
10111da177e4SLinus Torvalds snd_m3_outw(chip,
10121da177e4SLinus Torvalds snd_m3_inw(chip, HOST_INT_CTRL) | CLKRUN_GEN_ENABLE,
10131da177e4SLinus Torvalds HOST_INT_CTRL);
10141da177e4SLinus Torvalds }
10151da177e4SLinus Torvalds
snd_m3_dec_timer_users(struct snd_m3 * chip)10163470c29dSTakashi Iwai static void snd_m3_dec_timer_users(struct snd_m3 *chip)
10171da177e4SLinus Torvalds {
10181da177e4SLinus Torvalds chip->timer_users--;
10191da177e4SLinus Torvalds if (chip->timer_users > 0)
10201da177e4SLinus Torvalds return;
10211da177e4SLinus Torvalds
10221da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
10231da177e4SLinus Torvalds KDATA_TIMER_COUNT_RELOAD,
10241da177e4SLinus Torvalds 0);
10251da177e4SLinus Torvalds
10261da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
10271da177e4SLinus Torvalds KDATA_TIMER_COUNT_CURRENT,
10281da177e4SLinus Torvalds 0);
10291da177e4SLinus Torvalds
10301da177e4SLinus Torvalds snd_m3_outw(chip,
10311da177e4SLinus Torvalds snd_m3_inw(chip, HOST_INT_CTRL) & ~CLKRUN_GEN_ENABLE,
10321da177e4SLinus Torvalds HOST_INT_CTRL);
10331da177e4SLinus Torvalds }
10341da177e4SLinus Torvalds
10351da177e4SLinus Torvalds /*
10361da177e4SLinus Torvalds * start/stop
10371da177e4SLinus Torvalds */
10381da177e4SLinus Torvalds
10391da177e4SLinus Torvalds /* spinlock held! */
snd_m3_pcm_start(struct snd_m3 * chip,struct m3_dma * s,struct snd_pcm_substream * subs)10403470c29dSTakashi Iwai static int snd_m3_pcm_start(struct snd_m3 *chip, struct m3_dma *s,
10413470c29dSTakashi Iwai struct snd_pcm_substream *subs)
10421da177e4SLinus Torvalds {
10431da177e4SLinus Torvalds if (! s || ! subs)
10441da177e4SLinus Torvalds return -EINVAL;
10451da177e4SLinus Torvalds
10461da177e4SLinus Torvalds snd_m3_inc_timer_users(chip);
10471da177e4SLinus Torvalds switch (subs->stream) {
10481da177e4SLinus Torvalds case SNDRV_PCM_STREAM_PLAYBACK:
10491da177e4SLinus Torvalds chip->dacs_active++;
10501da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
10511da177e4SLinus Torvalds s->inst.data + CDATA_INSTANCE_READY, 1);
10521da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
10531da177e4SLinus Torvalds KDATA_MIXER_TASK_NUMBER,
10541da177e4SLinus Torvalds chip->dacs_active);
10551da177e4SLinus Torvalds break;
10561da177e4SLinus Torvalds case SNDRV_PCM_STREAM_CAPTURE:
10573470c29dSTakashi Iwai snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
10581da177e4SLinus Torvalds KDATA_ADC1_REQUEST, 1);
10591da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
10601da177e4SLinus Torvalds s->inst.data + CDATA_INSTANCE_READY, 1);
10611da177e4SLinus Torvalds break;
10621da177e4SLinus Torvalds }
10631da177e4SLinus Torvalds return 0;
10641da177e4SLinus Torvalds }
10651da177e4SLinus Torvalds
10661da177e4SLinus Torvalds /* spinlock held! */
snd_m3_pcm_stop(struct snd_m3 * chip,struct m3_dma * s,struct snd_pcm_substream * subs)10673470c29dSTakashi Iwai static int snd_m3_pcm_stop(struct snd_m3 *chip, struct m3_dma *s,
10683470c29dSTakashi Iwai struct snd_pcm_substream *subs)
10691da177e4SLinus Torvalds {
10701da177e4SLinus Torvalds if (! s || ! subs)
10711da177e4SLinus Torvalds return -EINVAL;
10721da177e4SLinus Torvalds
10731da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
10741da177e4SLinus Torvalds s->inst.data + CDATA_INSTANCE_READY, 0);
10751da177e4SLinus Torvalds snd_m3_dec_timer_users(chip);
10761da177e4SLinus Torvalds switch (subs->stream) {
10771da177e4SLinus Torvalds case SNDRV_PCM_STREAM_PLAYBACK:
10781da177e4SLinus Torvalds chip->dacs_active--;
10791da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
10801da177e4SLinus Torvalds KDATA_MIXER_TASK_NUMBER,
10811da177e4SLinus Torvalds chip->dacs_active);
10821da177e4SLinus Torvalds break;
10831da177e4SLinus Torvalds case SNDRV_PCM_STREAM_CAPTURE:
10841da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
10851da177e4SLinus Torvalds KDATA_ADC1_REQUEST, 0);
10861da177e4SLinus Torvalds break;
10871da177e4SLinus Torvalds }
10881da177e4SLinus Torvalds return 0;
10891da177e4SLinus Torvalds }
10901da177e4SLinus Torvalds
10911da177e4SLinus Torvalds static int
snd_m3_pcm_trigger(struct snd_pcm_substream * subs,int cmd)10923470c29dSTakashi Iwai snd_m3_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
10931da177e4SLinus Torvalds {
10943470c29dSTakashi Iwai struct snd_m3 *chip = snd_pcm_substream_chip(subs);
10953470c29dSTakashi Iwai struct m3_dma *s = subs->runtime->private_data;
10961da177e4SLinus Torvalds int err = -EINVAL;
10971da177e4SLinus Torvalds
1098da3cec35STakashi Iwai if (snd_BUG_ON(!s))
1099da3cec35STakashi Iwai return -ENXIO;
11001da177e4SLinus Torvalds
11011da177e4SLinus Torvalds spin_lock(&chip->reg_lock);
11021da177e4SLinus Torvalds switch (cmd) {
11031da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_START:
11041da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_RESUME:
11051da177e4SLinus Torvalds if (s->running)
11061da177e4SLinus Torvalds err = -EBUSY;
11071da177e4SLinus Torvalds else {
11081da177e4SLinus Torvalds s->running = 1;
11091da177e4SLinus Torvalds err = snd_m3_pcm_start(chip, s, subs);
11101da177e4SLinus Torvalds }
11111da177e4SLinus Torvalds break;
11121da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_STOP:
11131da177e4SLinus Torvalds case SNDRV_PCM_TRIGGER_SUSPEND:
11141da177e4SLinus Torvalds if (! s->running)
11151da177e4SLinus Torvalds err = 0; /* should return error? */
11161da177e4SLinus Torvalds else {
11171da177e4SLinus Torvalds s->running = 0;
11181da177e4SLinus Torvalds err = snd_m3_pcm_stop(chip, s, subs);
11191da177e4SLinus Torvalds }
11201da177e4SLinus Torvalds break;
11211da177e4SLinus Torvalds }
11221da177e4SLinus Torvalds spin_unlock(&chip->reg_lock);
11231da177e4SLinus Torvalds return err;
11241da177e4SLinus Torvalds }
11251da177e4SLinus Torvalds
11261da177e4SLinus Torvalds /*
11271da177e4SLinus Torvalds * setup
11281da177e4SLinus Torvalds */
11291da177e4SLinus Torvalds static void
snd_m3_pcm_setup1(struct snd_m3 * chip,struct m3_dma * s,struct snd_pcm_substream * subs)11303470c29dSTakashi Iwai snd_m3_pcm_setup1(struct snd_m3 *chip, struct m3_dma *s, struct snd_pcm_substream *subs)
11311da177e4SLinus Torvalds {
11321da177e4SLinus Torvalds int dsp_in_size, dsp_out_size, dsp_in_buffer, dsp_out_buffer;
11333470c29dSTakashi Iwai struct snd_pcm_runtime *runtime = subs->runtime;
11341da177e4SLinus Torvalds
11351da177e4SLinus Torvalds if (subs->stream == SNDRV_PCM_STREAM_PLAYBACK) {
11361da177e4SLinus Torvalds dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x20 * 2);
11371da177e4SLinus Torvalds dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x20 * 2);
11381da177e4SLinus Torvalds } else {
11391da177e4SLinus Torvalds dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x10 * 2);
11401da177e4SLinus Torvalds dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x10 * 2);
11411da177e4SLinus Torvalds }
11421da177e4SLinus Torvalds dsp_in_buffer = s->inst.data + (MINISRC_TMP_BUFFER_SIZE / 2);
11431da177e4SLinus Torvalds dsp_out_buffer = dsp_in_buffer + (dsp_in_size / 2) + 1;
11441da177e4SLinus Torvalds
11451da177e4SLinus Torvalds s->dma_size = frames_to_bytes(runtime, runtime->buffer_size);
11461da177e4SLinus Torvalds s->period_size = frames_to_bytes(runtime, runtime->period_size);
11471da177e4SLinus Torvalds s->hwptr = 0;
11481da177e4SLinus Torvalds s->count = 0;
11491da177e4SLinus Torvalds
11501da177e4SLinus Torvalds #define LO(x) ((x) & 0xffff)
11511da177e4SLinus Torvalds #define HI(x) LO((x) >> 16)
11521da177e4SLinus Torvalds
11531da177e4SLinus Torvalds /* host dma buffer pointers */
11541da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
11551da177e4SLinus Torvalds s->inst.data + CDATA_HOST_SRC_ADDRL,
11561da177e4SLinus Torvalds LO(s->buffer_addr));
11571da177e4SLinus Torvalds
11581da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
11591da177e4SLinus Torvalds s->inst.data + CDATA_HOST_SRC_ADDRH,
11601da177e4SLinus Torvalds HI(s->buffer_addr));
11611da177e4SLinus Torvalds
11621da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
11631da177e4SLinus Torvalds s->inst.data + CDATA_HOST_SRC_END_PLUS_1L,
11641da177e4SLinus Torvalds LO(s->buffer_addr + s->dma_size));
11651da177e4SLinus Torvalds
11661da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
11671da177e4SLinus Torvalds s->inst.data + CDATA_HOST_SRC_END_PLUS_1H,
11681da177e4SLinus Torvalds HI(s->buffer_addr + s->dma_size));
11691da177e4SLinus Torvalds
11701da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
11711da177e4SLinus Torvalds s->inst.data + CDATA_HOST_SRC_CURRENTL,
11721da177e4SLinus Torvalds LO(s->buffer_addr));
11731da177e4SLinus Torvalds
11741da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
11751da177e4SLinus Torvalds s->inst.data + CDATA_HOST_SRC_CURRENTH,
11761da177e4SLinus Torvalds HI(s->buffer_addr));
11771da177e4SLinus Torvalds #undef LO
11781da177e4SLinus Torvalds #undef HI
11791da177e4SLinus Torvalds
11801da177e4SLinus Torvalds /* dsp buffers */
11811da177e4SLinus Torvalds
11821da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
11831da177e4SLinus Torvalds s->inst.data + CDATA_IN_BUF_BEGIN,
11841da177e4SLinus Torvalds dsp_in_buffer);
11851da177e4SLinus Torvalds
11861da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
11871da177e4SLinus Torvalds s->inst.data + CDATA_IN_BUF_END_PLUS_1,
11881da177e4SLinus Torvalds dsp_in_buffer + (dsp_in_size / 2));
11891da177e4SLinus Torvalds
11901da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
11911da177e4SLinus Torvalds s->inst.data + CDATA_IN_BUF_HEAD,
11921da177e4SLinus Torvalds dsp_in_buffer);
11931da177e4SLinus Torvalds
11941da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
11951da177e4SLinus Torvalds s->inst.data + CDATA_IN_BUF_TAIL,
11961da177e4SLinus Torvalds dsp_in_buffer);
11971da177e4SLinus Torvalds
11981da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
11991da177e4SLinus Torvalds s->inst.data + CDATA_OUT_BUF_BEGIN,
12001da177e4SLinus Torvalds dsp_out_buffer);
12011da177e4SLinus Torvalds
12021da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
12031da177e4SLinus Torvalds s->inst.data + CDATA_OUT_BUF_END_PLUS_1,
12041da177e4SLinus Torvalds dsp_out_buffer + (dsp_out_size / 2));
12051da177e4SLinus Torvalds
12061da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
12071da177e4SLinus Torvalds s->inst.data + CDATA_OUT_BUF_HEAD,
12081da177e4SLinus Torvalds dsp_out_buffer);
12091da177e4SLinus Torvalds
12101da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
12111da177e4SLinus Torvalds s->inst.data + CDATA_OUT_BUF_TAIL,
12121da177e4SLinus Torvalds dsp_out_buffer);
12131da177e4SLinus Torvalds }
12141da177e4SLinus Torvalds
snd_m3_pcm_setup2(struct snd_m3 * chip,struct m3_dma * s,struct snd_pcm_runtime * runtime)12153470c29dSTakashi Iwai static void snd_m3_pcm_setup2(struct snd_m3 *chip, struct m3_dma *s,
12163470c29dSTakashi Iwai struct snd_pcm_runtime *runtime)
12171da177e4SLinus Torvalds {
12181da177e4SLinus Torvalds u32 freq;
12191da177e4SLinus Torvalds
12201da177e4SLinus Torvalds /*
12211da177e4SLinus Torvalds * put us in the lists if we're not already there
12221da177e4SLinus Torvalds */
12231da177e4SLinus Torvalds if (! s->in_lists) {
12241da177e4SLinus Torvalds s->index[0] = snd_m3_add_list(chip, s->index_list[0],
12251da177e4SLinus Torvalds s->inst.data >> DP_SHIFT_COUNT);
12261da177e4SLinus Torvalds s->index[1] = snd_m3_add_list(chip, s->index_list[1],
12271da177e4SLinus Torvalds s->inst.data >> DP_SHIFT_COUNT);
12281da177e4SLinus Torvalds s->index[2] = snd_m3_add_list(chip, s->index_list[2],
12291da177e4SLinus Torvalds s->inst.data >> DP_SHIFT_COUNT);
12301da177e4SLinus Torvalds s->in_lists = 1;
12311da177e4SLinus Torvalds }
12321da177e4SLinus Torvalds
12331da177e4SLinus Torvalds /* write to 'mono' word */
12341da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
12351da177e4SLinus Torvalds s->inst.data + SRC3_DIRECTION_OFFSET + 1,
12361da177e4SLinus Torvalds runtime->channels == 2 ? 0 : 1);
12371da177e4SLinus Torvalds /* write to '8bit' word */
12381da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
12391da177e4SLinus Torvalds s->inst.data + SRC3_DIRECTION_OFFSET + 2,
12401da177e4SLinus Torvalds snd_pcm_format_width(runtime->format) == 16 ? 0 : 1);
12411da177e4SLinus Torvalds
12421da177e4SLinus Torvalds /* set up dac/adc rate */
124364062869SLars-Peter Clausen freq = DIV_ROUND_CLOSEST(runtime->rate << 15, 48000);
12441da177e4SLinus Torvalds if (freq)
12451da177e4SLinus Torvalds freq--;
12461da177e4SLinus Torvalds
12471da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
12481da177e4SLinus Torvalds s->inst.data + CDATA_FREQUENCY,
12491da177e4SLinus Torvalds freq);
12501da177e4SLinus Torvalds }
12511da177e4SLinus Torvalds
12521da177e4SLinus Torvalds
12530b2dcd5dSAndreas Mohr static const struct play_vals {
12541da177e4SLinus Torvalds u16 addr, val;
12551da177e4SLinus Torvalds } pv[] = {
12561da177e4SLinus Torvalds {CDATA_LEFT_VOLUME, ARB_VOLUME},
12571da177e4SLinus Torvalds {CDATA_RIGHT_VOLUME, ARB_VOLUME},
12581da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET, 0} ,
12591da177e4SLinus Torvalds /* +1, +2 are stereo/16 bit */
12601da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 3, 0x0000}, /* fraction? */
12611da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */
12621da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */
12631da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */
12641da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */
12651da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */
12661da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */
12671da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 10, 0x8000}, /* round */
12681da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 11, 0xFF00}, /* higher bute mark */
12691da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */
12701da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */
12711da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */
12721da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 16, 8}, /* numin */
12731da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 17, 50*2}, /* numout */
12741da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 18, MINISRC_BIQUAD_STAGE - 1}, /* numstage */
12751da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */
12761da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 21, 0} /* booster */
12771da177e4SLinus Torvalds };
12781da177e4SLinus Torvalds
12791da177e4SLinus Torvalds
12801da177e4SLinus Torvalds /* the mode passed should be already shifted and masked */
12811da177e4SLinus Torvalds static void
snd_m3_playback_setup(struct snd_m3 * chip,struct m3_dma * s,struct snd_pcm_substream * subs)12823470c29dSTakashi Iwai snd_m3_playback_setup(struct snd_m3 *chip, struct m3_dma *s,
12833470c29dSTakashi Iwai struct snd_pcm_substream *subs)
12841da177e4SLinus Torvalds {
12851da177e4SLinus Torvalds unsigned int i;
12861da177e4SLinus Torvalds
12871da177e4SLinus Torvalds /*
12881da177e4SLinus Torvalds * some per client initializers
12891da177e4SLinus Torvalds */
12901da177e4SLinus Torvalds
12911da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
12921da177e4SLinus Torvalds s->inst.data + SRC3_DIRECTION_OFFSET + 12,
12931da177e4SLinus Torvalds s->inst.data + 40 + 8);
12941da177e4SLinus Torvalds
12951da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
12961da177e4SLinus Torvalds s->inst.data + SRC3_DIRECTION_OFFSET + 19,
12971da177e4SLinus Torvalds s->inst.code + MINISRC_COEF_LOC);
12981da177e4SLinus Torvalds
12991da177e4SLinus Torvalds /* enable or disable low pass filter? */
13001da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
13011da177e4SLinus Torvalds s->inst.data + SRC3_DIRECTION_OFFSET + 22,
13021da177e4SLinus Torvalds subs->runtime->rate > 45000 ? 0xff : 0);
13031da177e4SLinus Torvalds
13041da177e4SLinus Torvalds /* tell it which way dma is going? */
13051da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
13061da177e4SLinus Torvalds s->inst.data + CDATA_DMA_CONTROL,
13071da177e4SLinus Torvalds DMACONTROL_AUTOREPEAT + DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR);
13081da177e4SLinus Torvalds
13091da177e4SLinus Torvalds /*
13101da177e4SLinus Torvalds * set an armload of static initializers
13111da177e4SLinus Torvalds */
13121da177e4SLinus Torvalds for (i = 0; i < ARRAY_SIZE(pv); i++)
13131da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
13141da177e4SLinus Torvalds s->inst.data + pv[i].addr, pv[i].val);
13151da177e4SLinus Torvalds }
13161da177e4SLinus Torvalds
13171da177e4SLinus Torvalds /*
13181da177e4SLinus Torvalds * Native record driver
13191da177e4SLinus Torvalds */
13200b2dcd5dSAndreas Mohr static const struct rec_vals {
13211da177e4SLinus Torvalds u16 addr, val;
13221da177e4SLinus Torvalds } rv[] = {
13231da177e4SLinus Torvalds {CDATA_LEFT_VOLUME, ARB_VOLUME},
13241da177e4SLinus Torvalds {CDATA_RIGHT_VOLUME, ARB_VOLUME},
13251da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET, 1} ,
13261da177e4SLinus Torvalds /* +1, +2 are stereo/16 bit */
13271da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 3, 0x0000}, /* fraction? */
13281da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */
13291da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */
13301da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */
13311da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */
13321da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */
13331da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */
13341da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 10, 0x8000}, /* round */
13351da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 11, 0xFF00}, /* higher bute mark */
13361da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */
13371da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */
13381da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */
13391da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 16, 50},/* numin */
13401da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 17, 8}, /* numout */
13411da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 18, 0}, /* numstage */
13421da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 19, 0}, /* coef */
13431da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */
13441da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 21, 0}, /* booster */
13451da177e4SLinus Torvalds {SRC3_DIRECTION_OFFSET + 22, 0xff} /* skip lpf */
13461da177e4SLinus Torvalds };
13471da177e4SLinus Torvalds
13481da177e4SLinus Torvalds static void
snd_m3_capture_setup(struct snd_m3 * chip,struct m3_dma * s,struct snd_pcm_substream * subs)13493470c29dSTakashi Iwai snd_m3_capture_setup(struct snd_m3 *chip, struct m3_dma *s, struct snd_pcm_substream *subs)
13501da177e4SLinus Torvalds {
13511da177e4SLinus Torvalds unsigned int i;
13521da177e4SLinus Torvalds
13531da177e4SLinus Torvalds /*
13541da177e4SLinus Torvalds * some per client initializers
13551da177e4SLinus Torvalds */
13561da177e4SLinus Torvalds
13571da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
13581da177e4SLinus Torvalds s->inst.data + SRC3_DIRECTION_OFFSET + 12,
13591da177e4SLinus Torvalds s->inst.data + 40 + 8);
13601da177e4SLinus Torvalds
13611da177e4SLinus Torvalds /* tell it which way dma is going? */
13621da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
13631da177e4SLinus Torvalds s->inst.data + CDATA_DMA_CONTROL,
13641da177e4SLinus Torvalds DMACONTROL_DIRECTION + DMACONTROL_AUTOREPEAT +
13651da177e4SLinus Torvalds DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR);
13661da177e4SLinus Torvalds
13671da177e4SLinus Torvalds /*
13681da177e4SLinus Torvalds * set an armload of static initializers
13691da177e4SLinus Torvalds */
13701da177e4SLinus Torvalds for (i = 0; i < ARRAY_SIZE(rv); i++)
13711da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
13721da177e4SLinus Torvalds s->inst.data + rv[i].addr, rv[i].val);
13731da177e4SLinus Torvalds }
13741da177e4SLinus Torvalds
snd_m3_pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * hw_params)13753470c29dSTakashi Iwai static int snd_m3_pcm_hw_params(struct snd_pcm_substream *substream,
13763470c29dSTakashi Iwai struct snd_pcm_hw_params *hw_params)
13771da177e4SLinus Torvalds {
13783470c29dSTakashi Iwai struct m3_dma *s = substream->runtime->private_data;
13791da177e4SLinus Torvalds
13801da177e4SLinus Torvalds /* set buffer address */
13811da177e4SLinus Torvalds s->buffer_addr = substream->runtime->dma_addr;
13821da177e4SLinus Torvalds if (s->buffer_addr & 0x3) {
1383747ce5b3STakashi Iwai dev_err(substream->pcm->card->dev, "oh my, not aligned\n");
13841da177e4SLinus Torvalds s->buffer_addr = s->buffer_addr & ~0x3;
13851da177e4SLinus Torvalds }
13861da177e4SLinus Torvalds return 0;
13871da177e4SLinus Torvalds }
13881da177e4SLinus Torvalds
snd_m3_pcm_hw_free(struct snd_pcm_substream * substream)13893470c29dSTakashi Iwai static int snd_m3_pcm_hw_free(struct snd_pcm_substream *substream)
13901da177e4SLinus Torvalds {
13913470c29dSTakashi Iwai struct m3_dma *s;
13921da177e4SLinus Torvalds
13931da177e4SLinus Torvalds if (substream->runtime->private_data == NULL)
13941da177e4SLinus Torvalds return 0;
13953470c29dSTakashi Iwai s = substream->runtime->private_data;
13961da177e4SLinus Torvalds s->buffer_addr = 0;
13971da177e4SLinus Torvalds return 0;
13981da177e4SLinus Torvalds }
13991da177e4SLinus Torvalds
14001da177e4SLinus Torvalds static int
snd_m3_pcm_prepare(struct snd_pcm_substream * subs)14013470c29dSTakashi Iwai snd_m3_pcm_prepare(struct snd_pcm_substream *subs)
14021da177e4SLinus Torvalds {
14033470c29dSTakashi Iwai struct snd_m3 *chip = snd_pcm_substream_chip(subs);
14043470c29dSTakashi Iwai struct snd_pcm_runtime *runtime = subs->runtime;
14053470c29dSTakashi Iwai struct m3_dma *s = runtime->private_data;
14061da177e4SLinus Torvalds
1407da3cec35STakashi Iwai if (snd_BUG_ON(!s))
1408da3cec35STakashi Iwai return -ENXIO;
14091da177e4SLinus Torvalds
14101da177e4SLinus Torvalds if (runtime->format != SNDRV_PCM_FORMAT_U8 &&
14111da177e4SLinus Torvalds runtime->format != SNDRV_PCM_FORMAT_S16_LE)
14121da177e4SLinus Torvalds return -EINVAL;
14131da177e4SLinus Torvalds if (runtime->rate > 48000 ||
14141da177e4SLinus Torvalds runtime->rate < 8000)
14151da177e4SLinus Torvalds return -EINVAL;
14161da177e4SLinus Torvalds
14171da177e4SLinus Torvalds spin_lock_irq(&chip->reg_lock);
14181da177e4SLinus Torvalds
14191da177e4SLinus Torvalds snd_m3_pcm_setup1(chip, s, subs);
14201da177e4SLinus Torvalds
14211da177e4SLinus Torvalds if (subs->stream == SNDRV_PCM_STREAM_PLAYBACK)
14221da177e4SLinus Torvalds snd_m3_playback_setup(chip, s, subs);
14231da177e4SLinus Torvalds else
14241da177e4SLinus Torvalds snd_m3_capture_setup(chip, s, subs);
14251da177e4SLinus Torvalds
14261da177e4SLinus Torvalds snd_m3_pcm_setup2(chip, s, runtime);
14271da177e4SLinus Torvalds
14281da177e4SLinus Torvalds spin_unlock_irq(&chip->reg_lock);
14291da177e4SLinus Torvalds
14301da177e4SLinus Torvalds return 0;
14311da177e4SLinus Torvalds }
14321da177e4SLinus Torvalds
14331da177e4SLinus Torvalds /*
14341da177e4SLinus Torvalds * get current pointer
14351da177e4SLinus Torvalds */
14361da177e4SLinus Torvalds static unsigned int
snd_m3_get_pointer(struct snd_m3 * chip,struct m3_dma * s,struct snd_pcm_substream * subs)14373470c29dSTakashi Iwai snd_m3_get_pointer(struct snd_m3 *chip, struct m3_dma *s, struct snd_pcm_substream *subs)
14381da177e4SLinus Torvalds {
14391da177e4SLinus Torvalds u16 hi = 0, lo = 0;
14401da177e4SLinus Torvalds int retry = 10;
14411da177e4SLinus Torvalds u32 addr;
14421da177e4SLinus Torvalds
14431da177e4SLinus Torvalds /*
14441da177e4SLinus Torvalds * try and get a valid answer
14451da177e4SLinus Torvalds */
14461da177e4SLinus Torvalds while (retry--) {
14471da177e4SLinus Torvalds hi = snd_m3_assp_read(chip, MEMTYPE_INTERNAL_DATA,
14481da177e4SLinus Torvalds s->inst.data + CDATA_HOST_SRC_CURRENTH);
14491da177e4SLinus Torvalds
14501da177e4SLinus Torvalds lo = snd_m3_assp_read(chip, MEMTYPE_INTERNAL_DATA,
14511da177e4SLinus Torvalds s->inst.data + CDATA_HOST_SRC_CURRENTL);
14521da177e4SLinus Torvalds
14531da177e4SLinus Torvalds if (hi == snd_m3_assp_read(chip, MEMTYPE_INTERNAL_DATA,
14541da177e4SLinus Torvalds s->inst.data + CDATA_HOST_SRC_CURRENTH))
14551da177e4SLinus Torvalds break;
14561da177e4SLinus Torvalds }
14571da177e4SLinus Torvalds addr = lo | ((u32)hi<<16);
14581da177e4SLinus Torvalds return (unsigned int)(addr - s->buffer_addr);
14591da177e4SLinus Torvalds }
14601da177e4SLinus Torvalds
14611da177e4SLinus Torvalds static snd_pcm_uframes_t
snd_m3_pcm_pointer(struct snd_pcm_substream * subs)14623470c29dSTakashi Iwai snd_m3_pcm_pointer(struct snd_pcm_substream *subs)
14631da177e4SLinus Torvalds {
14643470c29dSTakashi Iwai struct snd_m3 *chip = snd_pcm_substream_chip(subs);
14651da177e4SLinus Torvalds unsigned int ptr;
14663470c29dSTakashi Iwai struct m3_dma *s = subs->runtime->private_data;
1467da3cec35STakashi Iwai
1468da3cec35STakashi Iwai if (snd_BUG_ON(!s))
1469da3cec35STakashi Iwai return 0;
14701da177e4SLinus Torvalds
14711da177e4SLinus Torvalds spin_lock(&chip->reg_lock);
14721da177e4SLinus Torvalds ptr = snd_m3_get_pointer(chip, s, subs);
14731da177e4SLinus Torvalds spin_unlock(&chip->reg_lock);
14741da177e4SLinus Torvalds return bytes_to_frames(subs->runtime, ptr);
14751da177e4SLinus Torvalds }
14761da177e4SLinus Torvalds
14771da177e4SLinus Torvalds
14781da177e4SLinus Torvalds /* update pointer */
14791da177e4SLinus Torvalds /* spinlock held! */
snd_m3_update_ptr(struct snd_m3 * chip,struct m3_dma * s)14803470c29dSTakashi Iwai static void snd_m3_update_ptr(struct snd_m3 *chip, struct m3_dma *s)
14811da177e4SLinus Torvalds {
14823470c29dSTakashi Iwai struct snd_pcm_substream *subs = s->substream;
14831da177e4SLinus Torvalds unsigned int hwptr;
14841da177e4SLinus Torvalds int diff;
14851da177e4SLinus Torvalds
14861da177e4SLinus Torvalds if (! s->running)
14871da177e4SLinus Torvalds return;
14881da177e4SLinus Torvalds
14890b2dcd5dSAndreas Mohr hwptr = snd_m3_get_pointer(chip, s, subs);
14900b2dcd5dSAndreas Mohr
14910b2dcd5dSAndreas Mohr /* try to avoid expensive modulo divisions */
14920b2dcd5dSAndreas Mohr if (hwptr >= s->dma_size)
14930b2dcd5dSAndreas Mohr hwptr %= s->dma_size;
14940b2dcd5dSAndreas Mohr
14950b2dcd5dSAndreas Mohr diff = s->dma_size + hwptr - s->hwptr;
14960b2dcd5dSAndreas Mohr if (diff >= s->dma_size)
14970b2dcd5dSAndreas Mohr diff %= s->dma_size;
14980b2dcd5dSAndreas Mohr
14991da177e4SLinus Torvalds s->hwptr = hwptr;
15001da177e4SLinus Torvalds s->count += diff;
15010b2dcd5dSAndreas Mohr
15021da177e4SLinus Torvalds if (s->count >= (signed)s->period_size) {
15030b2dcd5dSAndreas Mohr
15040b2dcd5dSAndreas Mohr if (s->count < 2 * (signed)s->period_size)
15050b2dcd5dSAndreas Mohr s->count -= (signed)s->period_size;
15060b2dcd5dSAndreas Mohr else
15071da177e4SLinus Torvalds s->count %= s->period_size;
15080b2dcd5dSAndreas Mohr
15091da177e4SLinus Torvalds spin_unlock(&chip->reg_lock);
15101da177e4SLinus Torvalds snd_pcm_period_elapsed(subs);
15111da177e4SLinus Torvalds spin_lock(&chip->reg_lock);
15121da177e4SLinus Torvalds }
15131da177e4SLinus Torvalds }
15141da177e4SLinus Torvalds
151520133d4cSHans de Goede /* The m3's hardware volume works by incrementing / decrementing 2 counters
151620133d4cSHans de Goede (without wrap around) in response to volume button presses and then
151720133d4cSHans de Goede generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7
151820133d4cSHans de Goede of a byte wide register. The meaning of bits 0 and 4 is unknown. */
snd_m3_update_hw_volume(struct work_struct * work)151930bdee02STakashi Iwai static void snd_m3_update_hw_volume(struct work_struct *work)
1520db68d15dSVille Syrjala {
152130bdee02STakashi Iwai struct snd_m3 *chip = container_of(work, struct snd_m3, hwvol_work);
1522db68d15dSVille Syrjala int x, val;
1523db68d15dSVille Syrjala
1524db68d15dSVille Syrjala /* Figure out which volume control button was pushed,
1525db68d15dSVille Syrjala based on differences from the default register
1526db68d15dSVille Syrjala values. */
1527db68d15dSVille Syrjala x = inb(chip->iobase + SHADOW_MIX_REG_VOICE) & 0xee;
1528db68d15dSVille Syrjala
152920133d4cSHans de Goede /* Reset the volume counters to 4. Tests on the allegro integrated
153020133d4cSHans de Goede into a Compaq N600C laptop, have revealed that:
153120133d4cSHans de Goede 1) Writing any value will result in the 2 counters being reset to
153220133d4cSHans de Goede 4 so writing 0x88 is not strictly necessary
153320133d4cSHans de Goede 2) Writing to any of the 4 involved registers will reset all 4
153420133d4cSHans de Goede of them (and reading them always returns the same value for all
153520133d4cSHans de Goede of them)
153620133d4cSHans de Goede It could be that a maestro deviates from this, so leave the code
153720133d4cSHans de Goede as is. */
1538db68d15dSVille Syrjala outb(0x88, chip->iobase + SHADOW_MIX_REG_VOICE);
1539db68d15dSVille Syrjala outb(0x88, chip->iobase + HW_VOL_COUNTER_VOICE);
1540db68d15dSVille Syrjala outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER);
1541db68d15dSVille Syrjala outb(0x88, chip->iobase + HW_VOL_COUNTER_MASTER);
1542db68d15dSVille Syrjala
1543715aa675SHans de Goede /* Ignore spurious HV interrupts during suspend / resume, this avoids
1544715aa675SHans de Goede mistaking them for a mute button press. */
1545715aa675SHans de Goede if (chip->in_suspend)
1546715aa675SHans de Goede return;
1547715aa675SHans de Goede
1548eb581adfSHans de Goede #ifndef CONFIG_SND_MAESTRO3_INPUT
1549db68d15dSVille Syrjala if (!chip->master_switch || !chip->master_volume)
1550db68d15dSVille Syrjala return;
1551db68d15dSVille Syrjala
155230bdee02STakashi Iwai val = snd_ac97_read(chip->ac97, AC97_MASTER);
1553db68d15dSVille Syrjala switch (x) {
1554db68d15dSVille Syrjala case 0x88:
155520133d4cSHans de Goede /* The counters have not changed, yet we've received a HV
155620133d4cSHans de Goede interrupt. According to tests run by various people this
155720133d4cSHans de Goede happens when pressing the mute button. */
1558db68d15dSVille Syrjala val ^= 0x8000;
1559db68d15dSVille Syrjala break;
1560db68d15dSVille Syrjala case 0xaa:
156120133d4cSHans de Goede /* counters increased by 1 -> volume up */
1562db68d15dSVille Syrjala if ((val & 0x7f) > 0)
1563db68d15dSVille Syrjala val--;
1564db68d15dSVille Syrjala if ((val & 0x7f00) > 0)
1565db68d15dSVille Syrjala val -= 0x0100;
1566db68d15dSVille Syrjala break;
1567db68d15dSVille Syrjala case 0x66:
156820133d4cSHans de Goede /* counters decreased by 1 -> volume down */
1569db68d15dSVille Syrjala if ((val & 0x7f) < 0x1f)
1570db68d15dSVille Syrjala val++;
1571db68d15dSVille Syrjala if ((val & 0x7f00) < 0x1f00)
1572db68d15dSVille Syrjala val += 0x0100;
1573db68d15dSVille Syrjala break;
1574db68d15dSVille Syrjala }
157530bdee02STakashi Iwai if (snd_ac97_update(chip->ac97, AC97_MASTER, val))
157630bdee02STakashi Iwai snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
157730bdee02STakashi Iwai &chip->master_switch->id);
1578eb581adfSHans de Goede #else
1579eb581adfSHans de Goede if (!chip->input_dev)
1580eb581adfSHans de Goede return;
1581eb581adfSHans de Goede
1582eb581adfSHans de Goede val = 0;
1583eb581adfSHans de Goede switch (x) {
1584eb581adfSHans de Goede case 0x88:
1585eb581adfSHans de Goede /* The counters have not changed, yet we've received a HV
1586eb581adfSHans de Goede interrupt. According to tests run by various people this
1587eb581adfSHans de Goede happens when pressing the mute button. */
1588eb581adfSHans de Goede val = KEY_MUTE;
1589eb581adfSHans de Goede break;
1590eb581adfSHans de Goede case 0xaa:
1591eb581adfSHans de Goede /* counters increased by 1 -> volume up */
1592eb581adfSHans de Goede val = KEY_VOLUMEUP;
1593eb581adfSHans de Goede break;
1594eb581adfSHans de Goede case 0x66:
1595eb581adfSHans de Goede /* counters decreased by 1 -> volume down */
1596eb581adfSHans de Goede val = KEY_VOLUMEDOWN;
1597eb581adfSHans de Goede break;
1598eb581adfSHans de Goede }
1599eb581adfSHans de Goede
1600eb581adfSHans de Goede if (val) {
1601eb581adfSHans de Goede input_report_key(chip->input_dev, val, 1);
1602eb581adfSHans de Goede input_sync(chip->input_dev);
1603eb581adfSHans de Goede input_report_key(chip->input_dev, val, 0);
1604eb581adfSHans de Goede input_sync(chip->input_dev);
1605eb581adfSHans de Goede }
1606eb581adfSHans de Goede #endif
1607db68d15dSVille Syrjala }
1608db68d15dSVille Syrjala
snd_m3_interrupt(int irq,void * dev_id)16097d12e780SDavid Howells static irqreturn_t snd_m3_interrupt(int irq, void *dev_id)
16101da177e4SLinus Torvalds {
16113470c29dSTakashi Iwai struct snd_m3 *chip = dev_id;
16121da177e4SLinus Torvalds u8 status;
16131da177e4SLinus Torvalds int i;
16141da177e4SLinus Torvalds
16151da177e4SLinus Torvalds status = inb(chip->iobase + HOST_INT_STATUS);
16161da177e4SLinus Torvalds
16171da177e4SLinus Torvalds if (status == 0xff)
16181da177e4SLinus Torvalds return IRQ_NONE;
16191da177e4SLinus Torvalds
1620db68d15dSVille Syrjala if (status & HV_INT_PENDING)
162130bdee02STakashi Iwai schedule_work(&chip->hwvol_work);
1622db68d15dSVille Syrjala
16231da177e4SLinus Torvalds /*
16241da177e4SLinus Torvalds * ack an assp int if its running
16251da177e4SLinus Torvalds * and has an int pending
16261da177e4SLinus Torvalds */
16271da177e4SLinus Torvalds if (status & ASSP_INT_PENDING) {
16281da177e4SLinus Torvalds u8 ctl = inb(chip->iobase + ASSP_CONTROL_B);
16291da177e4SLinus Torvalds if (!(ctl & STOP_ASSP_CLOCK)) {
16301da177e4SLinus Torvalds ctl = inb(chip->iobase + ASSP_HOST_INT_STATUS);
16311da177e4SLinus Torvalds if (ctl & DSP2HOST_REQ_TIMER) {
16321da177e4SLinus Torvalds outb(DSP2HOST_REQ_TIMER, chip->iobase + ASSP_HOST_INT_STATUS);
16331da177e4SLinus Torvalds /* update adc/dac info if it was a timer int */
16341da177e4SLinus Torvalds spin_lock(&chip->reg_lock);
16351da177e4SLinus Torvalds for (i = 0; i < chip->num_substreams; i++) {
16363470c29dSTakashi Iwai struct m3_dma *s = &chip->substreams[i];
16371da177e4SLinus Torvalds if (s->running)
16381da177e4SLinus Torvalds snd_m3_update_ptr(chip, s);
16391da177e4SLinus Torvalds }
16401da177e4SLinus Torvalds spin_unlock(&chip->reg_lock);
16411da177e4SLinus Torvalds }
16421da177e4SLinus Torvalds }
16431da177e4SLinus Torvalds }
16441da177e4SLinus Torvalds
16451da177e4SLinus Torvalds #if 0 /* TODO: not supported yet */
16461da177e4SLinus Torvalds if ((status & MPU401_INT_PENDING) && chip->rmidi)
16471da177e4SLinus Torvalds snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
16481da177e4SLinus Torvalds #endif
16491da177e4SLinus Torvalds
16501da177e4SLinus Torvalds /* ack ints */
165188491386SVille Syrjala outb(status, chip->iobase + HOST_INT_STATUS);
16521da177e4SLinus Torvalds
16531da177e4SLinus Torvalds return IRQ_HANDLED;
16541da177e4SLinus Torvalds }
16551da177e4SLinus Torvalds
16561da177e4SLinus Torvalds
16571da177e4SLinus Torvalds /*
16581da177e4SLinus Torvalds */
16591da177e4SLinus Torvalds
1660dee49895SBhumika Goyal static const struct snd_pcm_hardware snd_m3_playback =
16611da177e4SLinus Torvalds {
16621da177e4SLinus Torvalds .info = (SNDRV_PCM_INFO_MMAP |
16631da177e4SLinus Torvalds SNDRV_PCM_INFO_INTERLEAVED |
16641da177e4SLinus Torvalds SNDRV_PCM_INFO_MMAP_VALID |
16651da177e4SLinus Torvalds SNDRV_PCM_INFO_BLOCK_TRANSFER |
16661da177e4SLinus Torvalds /*SNDRV_PCM_INFO_PAUSE |*/
16671da177e4SLinus Torvalds SNDRV_PCM_INFO_RESUME),
16681da177e4SLinus Torvalds .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
16691da177e4SLinus Torvalds .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
16701da177e4SLinus Torvalds .rate_min = 8000,
16711da177e4SLinus Torvalds .rate_max = 48000,
16721da177e4SLinus Torvalds .channels_min = 1,
16731da177e4SLinus Torvalds .channels_max = 2,
16741da177e4SLinus Torvalds .buffer_bytes_max = (512*1024),
16751da177e4SLinus Torvalds .period_bytes_min = 64,
16761da177e4SLinus Torvalds .period_bytes_max = (512*1024),
16771da177e4SLinus Torvalds .periods_min = 1,
16781da177e4SLinus Torvalds .periods_max = 1024,
16791da177e4SLinus Torvalds };
16801da177e4SLinus Torvalds
1681dee49895SBhumika Goyal static const struct snd_pcm_hardware snd_m3_capture =
16821da177e4SLinus Torvalds {
16831da177e4SLinus Torvalds .info = (SNDRV_PCM_INFO_MMAP |
16841da177e4SLinus Torvalds SNDRV_PCM_INFO_INTERLEAVED |
16851da177e4SLinus Torvalds SNDRV_PCM_INFO_MMAP_VALID |
16861da177e4SLinus Torvalds SNDRV_PCM_INFO_BLOCK_TRANSFER |
16871da177e4SLinus Torvalds /*SNDRV_PCM_INFO_PAUSE |*/
16881da177e4SLinus Torvalds SNDRV_PCM_INFO_RESUME),
16891da177e4SLinus Torvalds .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
16901da177e4SLinus Torvalds .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
16911da177e4SLinus Torvalds .rate_min = 8000,
16921da177e4SLinus Torvalds .rate_max = 48000,
16931da177e4SLinus Torvalds .channels_min = 1,
16941da177e4SLinus Torvalds .channels_max = 2,
16951da177e4SLinus Torvalds .buffer_bytes_max = (512*1024),
16961da177e4SLinus Torvalds .period_bytes_min = 64,
16971da177e4SLinus Torvalds .period_bytes_max = (512*1024),
16981da177e4SLinus Torvalds .periods_min = 1,
16991da177e4SLinus Torvalds .periods_max = 1024,
17001da177e4SLinus Torvalds };
17011da177e4SLinus Torvalds
17021da177e4SLinus Torvalds
17031da177e4SLinus Torvalds /*
17041da177e4SLinus Torvalds */
17051da177e4SLinus Torvalds
17061da177e4SLinus Torvalds static int
snd_m3_substream_open(struct snd_m3 * chip,struct snd_pcm_substream * subs)17073470c29dSTakashi Iwai snd_m3_substream_open(struct snd_m3 *chip, struct snd_pcm_substream *subs)
17081da177e4SLinus Torvalds {
17091da177e4SLinus Torvalds int i;
17103470c29dSTakashi Iwai struct m3_dma *s;
17111da177e4SLinus Torvalds
17121da177e4SLinus Torvalds spin_lock_irq(&chip->reg_lock);
17131da177e4SLinus Torvalds for (i = 0; i < chip->num_substreams; i++) {
17141da177e4SLinus Torvalds s = &chip->substreams[i];
17151da177e4SLinus Torvalds if (! s->opened)
17161da177e4SLinus Torvalds goto __found;
17171da177e4SLinus Torvalds }
17181da177e4SLinus Torvalds spin_unlock_irq(&chip->reg_lock);
17191da177e4SLinus Torvalds return -ENOMEM;
17201da177e4SLinus Torvalds __found:
17211da177e4SLinus Torvalds s->opened = 1;
17221da177e4SLinus Torvalds s->running = 0;
17231da177e4SLinus Torvalds spin_unlock_irq(&chip->reg_lock);
17241da177e4SLinus Torvalds
17251da177e4SLinus Torvalds subs->runtime->private_data = s;
17261da177e4SLinus Torvalds s->substream = subs;
17271da177e4SLinus Torvalds
17281da177e4SLinus Torvalds /* set list owners */
17291da177e4SLinus Torvalds if (subs->stream == SNDRV_PCM_STREAM_PLAYBACK) {
17301da177e4SLinus Torvalds s->index_list[0] = &chip->mixer_list;
17311da177e4SLinus Torvalds } else
17321da177e4SLinus Torvalds s->index_list[0] = &chip->adc1_list;
17331da177e4SLinus Torvalds s->index_list[1] = &chip->msrc_list;
17341da177e4SLinus Torvalds s->index_list[2] = &chip->dma_list;
17351da177e4SLinus Torvalds
17361da177e4SLinus Torvalds return 0;
17371da177e4SLinus Torvalds }
17381da177e4SLinus Torvalds
17391da177e4SLinus Torvalds static void
snd_m3_substream_close(struct snd_m3 * chip,struct snd_pcm_substream * subs)17403470c29dSTakashi Iwai snd_m3_substream_close(struct snd_m3 *chip, struct snd_pcm_substream *subs)
17411da177e4SLinus Torvalds {
17423470c29dSTakashi Iwai struct m3_dma *s = subs->runtime->private_data;
17431da177e4SLinus Torvalds
17441da177e4SLinus Torvalds if (s == NULL)
17451da177e4SLinus Torvalds return; /* not opened properly */
17461da177e4SLinus Torvalds
17471da177e4SLinus Torvalds spin_lock_irq(&chip->reg_lock);
17481da177e4SLinus Torvalds if (s->substream && s->running)
17491da177e4SLinus Torvalds snd_m3_pcm_stop(chip, s, s->substream); /* does this happen? */
17501da177e4SLinus Torvalds if (s->in_lists) {
17511da177e4SLinus Torvalds snd_m3_remove_list(chip, s->index_list[0], s->index[0]);
17521da177e4SLinus Torvalds snd_m3_remove_list(chip, s->index_list[1], s->index[1]);
17531da177e4SLinus Torvalds snd_m3_remove_list(chip, s->index_list[2], s->index[2]);
17541da177e4SLinus Torvalds s->in_lists = 0;
17551da177e4SLinus Torvalds }
17561da177e4SLinus Torvalds s->running = 0;
17571da177e4SLinus Torvalds s->opened = 0;
17581da177e4SLinus Torvalds spin_unlock_irq(&chip->reg_lock);
17591da177e4SLinus Torvalds }
17601da177e4SLinus Torvalds
17611da177e4SLinus Torvalds static int
snd_m3_playback_open(struct snd_pcm_substream * subs)17623470c29dSTakashi Iwai snd_m3_playback_open(struct snd_pcm_substream *subs)
17631da177e4SLinus Torvalds {
17643470c29dSTakashi Iwai struct snd_m3 *chip = snd_pcm_substream_chip(subs);
17653470c29dSTakashi Iwai struct snd_pcm_runtime *runtime = subs->runtime;
17661da177e4SLinus Torvalds int err;
17671da177e4SLinus Torvalds
17685cc16ba6STakashi Iwai err = snd_m3_substream_open(chip, subs);
17695cc16ba6STakashi Iwai if (err < 0)
17701da177e4SLinus Torvalds return err;
17711da177e4SLinus Torvalds
17721da177e4SLinus Torvalds runtime->hw = snd_m3_playback;
17731da177e4SLinus Torvalds
17741da177e4SLinus Torvalds return 0;
17751da177e4SLinus Torvalds }
17761da177e4SLinus Torvalds
17771da177e4SLinus Torvalds static int
snd_m3_playback_close(struct snd_pcm_substream * subs)17783470c29dSTakashi Iwai snd_m3_playback_close(struct snd_pcm_substream *subs)
17791da177e4SLinus Torvalds {
17803470c29dSTakashi Iwai struct snd_m3 *chip = snd_pcm_substream_chip(subs);
17811da177e4SLinus Torvalds
17821da177e4SLinus Torvalds snd_m3_substream_close(chip, subs);
17831da177e4SLinus Torvalds return 0;
17841da177e4SLinus Torvalds }
17851da177e4SLinus Torvalds
17861da177e4SLinus Torvalds static int
snd_m3_capture_open(struct snd_pcm_substream * subs)17873470c29dSTakashi Iwai snd_m3_capture_open(struct snd_pcm_substream *subs)
17881da177e4SLinus Torvalds {
17893470c29dSTakashi Iwai struct snd_m3 *chip = snd_pcm_substream_chip(subs);
17903470c29dSTakashi Iwai struct snd_pcm_runtime *runtime = subs->runtime;
17911da177e4SLinus Torvalds int err;
17921da177e4SLinus Torvalds
17935cc16ba6STakashi Iwai err = snd_m3_substream_open(chip, subs);
17945cc16ba6STakashi Iwai if (err < 0)
17951da177e4SLinus Torvalds return err;
17961da177e4SLinus Torvalds
17971da177e4SLinus Torvalds runtime->hw = snd_m3_capture;
17981da177e4SLinus Torvalds
17991da177e4SLinus Torvalds return 0;
18001da177e4SLinus Torvalds }
18011da177e4SLinus Torvalds
18021da177e4SLinus Torvalds static int
snd_m3_capture_close(struct snd_pcm_substream * subs)18033470c29dSTakashi Iwai snd_m3_capture_close(struct snd_pcm_substream *subs)
18041da177e4SLinus Torvalds {
18053470c29dSTakashi Iwai struct snd_m3 *chip = snd_pcm_substream_chip(subs);
18061da177e4SLinus Torvalds
18071da177e4SLinus Torvalds snd_m3_substream_close(chip, subs);
18081da177e4SLinus Torvalds return 0;
18091da177e4SLinus Torvalds }
18101da177e4SLinus Torvalds
18111da177e4SLinus Torvalds /*
18121da177e4SLinus Torvalds * create pcm instance
18131da177e4SLinus Torvalds */
18141da177e4SLinus Torvalds
18156769e988SJulia Lawall static const struct snd_pcm_ops snd_m3_playback_ops = {
18161da177e4SLinus Torvalds .open = snd_m3_playback_open,
18171da177e4SLinus Torvalds .close = snd_m3_playback_close,
18181da177e4SLinus Torvalds .hw_params = snd_m3_pcm_hw_params,
18191da177e4SLinus Torvalds .hw_free = snd_m3_pcm_hw_free,
18201da177e4SLinus Torvalds .prepare = snd_m3_pcm_prepare,
18211da177e4SLinus Torvalds .trigger = snd_m3_pcm_trigger,
18221da177e4SLinus Torvalds .pointer = snd_m3_pcm_pointer,
18231da177e4SLinus Torvalds };
18241da177e4SLinus Torvalds
18256769e988SJulia Lawall static const struct snd_pcm_ops snd_m3_capture_ops = {
18261da177e4SLinus Torvalds .open = snd_m3_capture_open,
18271da177e4SLinus Torvalds .close = snd_m3_capture_close,
18281da177e4SLinus Torvalds .hw_params = snd_m3_pcm_hw_params,
18291da177e4SLinus Torvalds .hw_free = snd_m3_pcm_hw_free,
18301da177e4SLinus Torvalds .prepare = snd_m3_pcm_prepare,
18311da177e4SLinus Torvalds .trigger = snd_m3_pcm_trigger,
18321da177e4SLinus Torvalds .pointer = snd_m3_pcm_pointer,
18331da177e4SLinus Torvalds };
18341da177e4SLinus Torvalds
1835e23e7a14SBill Pemberton static int
snd_m3_pcm(struct snd_m3 * chip,int device)18363470c29dSTakashi Iwai snd_m3_pcm(struct snd_m3 * chip, int device)
18371da177e4SLinus Torvalds {
18383470c29dSTakashi Iwai struct snd_pcm *pcm;
18391da177e4SLinus Torvalds int err;
18401da177e4SLinus Torvalds
18411da177e4SLinus Torvalds err = snd_pcm_new(chip->card, chip->card->driver, device,
18421da177e4SLinus Torvalds MAX_PLAYBACKS, MAX_CAPTURES, &pcm);
18431da177e4SLinus Torvalds if (err < 0)
18441da177e4SLinus Torvalds return err;
18451da177e4SLinus Torvalds
18461da177e4SLinus Torvalds snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_m3_playback_ops);
18471da177e4SLinus Torvalds snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_m3_capture_ops);
18481da177e4SLinus Torvalds
18491da177e4SLinus Torvalds pcm->private_data = chip;
18501da177e4SLinus Torvalds pcm->info_flags = 0;
18511da177e4SLinus Torvalds strcpy(pcm->name, chip->card->driver);
18521da177e4SLinus Torvalds chip->pcm = pcm;
18531da177e4SLinus Torvalds
1854e485e538STakashi Iwai snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
1855e485e538STakashi Iwai &chip->pci->dev, 64*1024, 64*1024);
18561da177e4SLinus Torvalds
18571da177e4SLinus Torvalds return 0;
18581da177e4SLinus Torvalds }
18591da177e4SLinus Torvalds
18601da177e4SLinus Torvalds
18611da177e4SLinus Torvalds /*
18621da177e4SLinus Torvalds * ac97 interface
18631da177e4SLinus Torvalds */
18641da177e4SLinus Torvalds
18651da177e4SLinus Torvalds /*
18661da177e4SLinus Torvalds * Wait for the ac97 serial bus to be free.
18671da177e4SLinus Torvalds * return nonzero if the bus is still busy.
18681da177e4SLinus Torvalds */
snd_m3_ac97_wait(struct snd_m3 * chip)18693470c29dSTakashi Iwai static int snd_m3_ac97_wait(struct snd_m3 *chip)
18701da177e4SLinus Torvalds {
18711da177e4SLinus Torvalds int i = 10000;
18721da177e4SLinus Torvalds
18731da177e4SLinus Torvalds do {
18741da177e4SLinus Torvalds if (! (snd_m3_inb(chip, 0x30) & 1))
18751da177e4SLinus Torvalds return 0;
18760b2dcd5dSAndreas Mohr cpu_relax();
18771da177e4SLinus Torvalds } while (i-- > 0);
18781da177e4SLinus Torvalds
1879747ce5b3STakashi Iwai dev_err(chip->card->dev, "ac97 serial bus busy\n");
18801da177e4SLinus Torvalds return 1;
18811da177e4SLinus Torvalds }
18821da177e4SLinus Torvalds
18831da177e4SLinus Torvalds static unsigned short
snd_m3_ac97_read(struct snd_ac97 * ac97,unsigned short reg)18843470c29dSTakashi Iwai snd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
18851da177e4SLinus Torvalds {
18863470c29dSTakashi Iwai struct snd_m3 *chip = ac97->private_data;
18870b2dcd5dSAndreas Mohr unsigned short data = 0xffff;
18881da177e4SLinus Torvalds
18891da177e4SLinus Torvalds if (snd_m3_ac97_wait(chip))
18900b2dcd5dSAndreas Mohr goto fail;
18911da177e4SLinus Torvalds snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND);
18921da177e4SLinus Torvalds if (snd_m3_ac97_wait(chip))
189330bdee02STakashi Iwai goto fail;
1894db68d15dSVille Syrjala data = snd_m3_inw(chip, CODEC_DATA);
18950b2dcd5dSAndreas Mohr fail:
1896db68d15dSVille Syrjala return data;
18971da177e4SLinus Torvalds }
18981da177e4SLinus Torvalds
18991da177e4SLinus Torvalds static void
snd_m3_ac97_write(struct snd_ac97 * ac97,unsigned short reg,unsigned short val)19003470c29dSTakashi Iwai snd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
19011da177e4SLinus Torvalds {
19023470c29dSTakashi Iwai struct snd_m3 *chip = ac97->private_data;
19031da177e4SLinus Torvalds
19041da177e4SLinus Torvalds if (snd_m3_ac97_wait(chip))
19051da177e4SLinus Torvalds return;
19061da177e4SLinus Torvalds snd_m3_outw(chip, val, CODEC_DATA);
19071da177e4SLinus Torvalds snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND);
19082c8d0892SOndrej Zary /*
19092c8d0892SOndrej Zary * Workaround for buggy ES1988 integrated AC'97 codec. It remains silent
19102c8d0892SOndrej Zary * until the MASTER volume or mute is touched (alsactl restore does not
19112c8d0892SOndrej Zary * work).
19122c8d0892SOndrej Zary */
19132c8d0892SOndrej Zary if (ac97->id == 0x45838308 && reg == AC97_MASTER) {
19142c8d0892SOndrej Zary snd_m3_ac97_wait(chip);
19152c8d0892SOndrej Zary snd_m3_outw(chip, val, CODEC_DATA);
19162c8d0892SOndrej Zary snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND);
19172c8d0892SOndrej Zary }
19181da177e4SLinus Torvalds }
19191da177e4SLinus Torvalds
19201da177e4SLinus Torvalds
snd_m3_remote_codec_config(struct snd_m3 * chip,int isremote)1921030270baSOndrej Zary static void snd_m3_remote_codec_config(struct snd_m3 *chip, int isremote)
19221da177e4SLinus Torvalds {
1923030270baSOndrej Zary int io = chip->iobase;
1924030270baSOndrej Zary u16 tmp;
1925030270baSOndrej Zary
19261da177e4SLinus Torvalds isremote = isremote ? 1 : 0;
19271da177e4SLinus Torvalds
1928030270baSOndrej Zary tmp = inw(io + RING_BUS_CTRL_B) & ~SECOND_CODEC_ID_MASK;
1929030270baSOndrej Zary /* enable dock on Dell Latitude C810 */
1930030270baSOndrej Zary if (chip->pci->subsystem_vendor == 0x1028 &&
1931030270baSOndrej Zary chip->pci->subsystem_device == 0x00e5)
1932030270baSOndrej Zary tmp |= M3I_DOCK_ENABLE;
1933030270baSOndrej Zary outw(tmp | isremote, io + RING_BUS_CTRL_B);
19341da177e4SLinus Torvalds outw((inw(io + SDO_OUT_DEST_CTRL) & ~COMMAND_ADDR_OUT) | isremote,
19351da177e4SLinus Torvalds io + SDO_OUT_DEST_CTRL);
19361da177e4SLinus Torvalds outw((inw(io + SDO_IN_DEST_CTRL) & ~STATUS_ADDR_IN) | isremote,
19371da177e4SLinus Torvalds io + SDO_IN_DEST_CTRL);
19381da177e4SLinus Torvalds }
19391da177e4SLinus Torvalds
19401da177e4SLinus Torvalds /*
19411da177e4SLinus Torvalds * hack, returns non zero on err
19421da177e4SLinus Torvalds */
snd_m3_try_read_vendor(struct snd_m3 * chip)19433470c29dSTakashi Iwai static int snd_m3_try_read_vendor(struct snd_m3 *chip)
19441da177e4SLinus Torvalds {
19451da177e4SLinus Torvalds u16 ret;
19461da177e4SLinus Torvalds
19471da177e4SLinus Torvalds if (snd_m3_ac97_wait(chip))
19481da177e4SLinus Torvalds return 1;
19491da177e4SLinus Torvalds
19501da177e4SLinus Torvalds snd_m3_outb(chip, 0x80 | (AC97_VENDOR_ID1 & 0x7f), 0x30);
19511da177e4SLinus Torvalds
19521da177e4SLinus Torvalds if (snd_m3_ac97_wait(chip))
19531da177e4SLinus Torvalds return 1;
19541da177e4SLinus Torvalds
19551da177e4SLinus Torvalds ret = snd_m3_inw(chip, 0x32);
19561da177e4SLinus Torvalds
19571da177e4SLinus Torvalds return (ret == 0) || (ret == 0xffff);
19581da177e4SLinus Torvalds }
19591da177e4SLinus Torvalds
snd_m3_ac97_reset(struct snd_m3 * chip)19603470c29dSTakashi Iwai static void snd_m3_ac97_reset(struct snd_m3 *chip)
19611da177e4SLinus Torvalds {
19621da177e4SLinus Torvalds u16 dir;
19631da177e4SLinus Torvalds int delay1 = 0, delay2 = 0, i;
19641da177e4SLinus Torvalds int io = chip->iobase;
19651da177e4SLinus Torvalds
19661da177e4SLinus Torvalds if (chip->allegro_flag) {
19671da177e4SLinus Torvalds /*
19681da177e4SLinus Torvalds * the onboard codec on the allegro seems
19691da177e4SLinus Torvalds * to want to wait a very long time before
19701da177e4SLinus Torvalds * coming back to life
19711da177e4SLinus Torvalds */
19721da177e4SLinus Torvalds delay1 = 50;
19731da177e4SLinus Torvalds delay2 = 800;
19741da177e4SLinus Torvalds } else {
19751da177e4SLinus Torvalds /* maestro3 */
19761da177e4SLinus Torvalds delay1 = 20;
19771da177e4SLinus Torvalds delay2 = 500;
19781da177e4SLinus Torvalds }
19791da177e4SLinus Torvalds
19801da177e4SLinus Torvalds for (i = 0; i < 5; i++) {
19811da177e4SLinus Torvalds dir = inw(io + GPIO_DIRECTION);
19821061eeb4STakashi Iwai if (!chip->irda_workaround)
19831da177e4SLinus Torvalds dir |= 0x10; /* assuming pci bus master? */
19841da177e4SLinus Torvalds
1985030270baSOndrej Zary snd_m3_remote_codec_config(chip, 0);
19861da177e4SLinus Torvalds
19871da177e4SLinus Torvalds outw(IO_SRAM_ENABLE, io + RING_BUS_CTRL_A);
19881da177e4SLinus Torvalds udelay(20);
19891da177e4SLinus Torvalds
19901da177e4SLinus Torvalds outw(dir & ~GPO_PRIMARY_AC97 , io + GPIO_DIRECTION);
19911da177e4SLinus Torvalds outw(~GPO_PRIMARY_AC97 , io + GPIO_MASK);
19921da177e4SLinus Torvalds outw(0, io + GPIO_DATA);
19931da177e4SLinus Torvalds outw(dir | GPO_PRIMARY_AC97, io + GPIO_DIRECTION);
19941da177e4SLinus Torvalds
19958433a509SNishanth Aravamudan schedule_timeout_uninterruptible(msecs_to_jiffies(delay1));
19961da177e4SLinus Torvalds
19971da177e4SLinus Torvalds outw(GPO_PRIMARY_AC97, io + GPIO_DATA);
19981da177e4SLinus Torvalds udelay(5);
19991da177e4SLinus Torvalds /* ok, bring back the ac-link */
20001da177e4SLinus Torvalds outw(IO_SRAM_ENABLE | SERIAL_AC_LINK_ENABLE, io + RING_BUS_CTRL_A);
20011da177e4SLinus Torvalds outw(~0, io + GPIO_MASK);
20021da177e4SLinus Torvalds
20038433a509SNishanth Aravamudan schedule_timeout_uninterruptible(msecs_to_jiffies(delay2));
20041da177e4SLinus Torvalds
20051da177e4SLinus Torvalds if (! snd_m3_try_read_vendor(chip))
20061da177e4SLinus Torvalds break;
20071da177e4SLinus Torvalds
20081da177e4SLinus Torvalds delay1 += 10;
20091da177e4SLinus Torvalds delay2 += 100;
20101da177e4SLinus Torvalds
2011747ce5b3STakashi Iwai dev_dbg(chip->card->dev,
2012747ce5b3STakashi Iwai "retrying codec reset with delays of %d and %d ms\n",
20131da177e4SLinus Torvalds delay1, delay2);
20141da177e4SLinus Torvalds }
20151da177e4SLinus Torvalds
20161da177e4SLinus Torvalds #if 0
20171da177e4SLinus Torvalds /* more gung-ho reset that doesn't
20181da177e4SLinus Torvalds * seem to work anywhere :)
20191da177e4SLinus Torvalds */
20201da177e4SLinus Torvalds tmp = inw(io + RING_BUS_CTRL_A);
20211da177e4SLinus Torvalds outw(RAC_SDFS_ENABLE|LAC_SDFS_ENABLE, io + RING_BUS_CTRL_A);
20225ba1e7b5STakashi Iwai msleep(20);
20231da177e4SLinus Torvalds outw(tmp, io + RING_BUS_CTRL_A);
20245ba1e7b5STakashi Iwai msleep(50);
20251da177e4SLinus Torvalds #endif
20261da177e4SLinus Torvalds }
20271da177e4SLinus Torvalds
snd_m3_mixer(struct snd_m3 * chip)2028e23e7a14SBill Pemberton static int snd_m3_mixer(struct snd_m3 *chip)
20291da177e4SLinus Torvalds {
20303470c29dSTakashi Iwai struct snd_ac97_bus *pbus;
20313470c29dSTakashi Iwai struct snd_ac97_template ac97;
20321da177e4SLinus Torvalds int err;
203351055da5STakashi Iwai static const struct snd_ac97_bus_ops ops = {
20341da177e4SLinus Torvalds .write = snd_m3_ac97_write,
20351da177e4SLinus Torvalds .read = snd_m3_ac97_read,
20361da177e4SLinus Torvalds };
20371da177e4SLinus Torvalds
20385cc16ba6STakashi Iwai err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus);
20395cc16ba6STakashi Iwai if (err < 0)
20401da177e4SLinus Torvalds return err;
20411da177e4SLinus Torvalds
20421da177e4SLinus Torvalds memset(&ac97, 0, sizeof(ac97));
20431da177e4SLinus Torvalds ac97.private_data = chip;
20445cc16ba6STakashi Iwai err = snd_ac97_mixer(pbus, &ac97, &chip->ac97);
20455cc16ba6STakashi Iwai if (err < 0)
20461da177e4SLinus Torvalds return err;
20471da177e4SLinus Torvalds
20481da177e4SLinus Torvalds /* seems ac97 PCM needs initialization.. hack hack.. */
20491da177e4SLinus Torvalds snd_ac97_write(chip->ac97, AC97_PCM, 0x8000 | (15 << 8) | 15);
20508433a509SNishanth Aravamudan schedule_timeout_uninterruptible(msecs_to_jiffies(100));
20511da177e4SLinus Torvalds snd_ac97_write(chip->ac97, AC97_PCM, 0);
20521da177e4SLinus Torvalds
2053eb581adfSHans de Goede #ifndef CONFIG_SND_MAESTRO3_INPUT
2054*233913c0STakashi Iwai chip->master_switch = snd_ctl_find_id_mixer(chip->card,
2055*233913c0STakashi Iwai "Master Playback Switch");
2056*233913c0STakashi Iwai chip->master_volume = snd_ctl_find_id_mixer(chip->card,
2057*233913c0STakashi Iwai "Master Playback Volume");
2058eb581adfSHans de Goede #endif
2059db68d15dSVille Syrjala
20601da177e4SLinus Torvalds return 0;
20611da177e4SLinus Torvalds }
20621da177e4SLinus Torvalds
20631da177e4SLinus Torvalds
20641da177e4SLinus Torvalds /*
20651da177e4SLinus Torvalds * initialize ASSP
20661da177e4SLinus Torvalds */
20671da177e4SLinus Torvalds
20681da177e4SLinus Torvalds #define MINISRC_LPF_LEN 10
2069f40b6890STakashi Iwai static const u16 minisrc_lpf[MINISRC_LPF_LEN] = {
20701da177e4SLinus Torvalds 0X0743, 0X1104, 0X0A4C, 0XF88D, 0X242C,
20711da177e4SLinus Torvalds 0X1023, 0X1AA9, 0X0B60, 0XEFDD, 0X186F
20721da177e4SLinus Torvalds };
20731da177e4SLinus Torvalds
snd_m3_assp_init(struct snd_m3 * chip)2074f40b6890STakashi Iwai static void snd_m3_assp_init(struct snd_m3 *chip)
20751da177e4SLinus Torvalds {
20761da177e4SLinus Torvalds unsigned int i;
20778c0ab942STakashi Iwai const __le16 *data;
20781da177e4SLinus Torvalds
20791da177e4SLinus Torvalds /* zero kernel data */
20801da177e4SLinus Torvalds for (i = 0; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++)
20811da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
20821da177e4SLinus Torvalds KDATA_BASE_ADDR + i, 0);
20831da177e4SLinus Torvalds
20841da177e4SLinus Torvalds /* zero mixer data? */
20851da177e4SLinus Torvalds for (i = 0; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++)
20861da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
20871da177e4SLinus Torvalds KDATA_BASE_ADDR2 + i, 0);
20881da177e4SLinus Torvalds
20891da177e4SLinus Torvalds /* init dma pointer */
20901da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
20911da177e4SLinus Torvalds KDATA_CURRENT_DMA,
20921da177e4SLinus Torvalds KDATA_DMA_XFER0);
20931da177e4SLinus Torvalds
20941da177e4SLinus Torvalds /* write kernel into code memory.. */
20958c0ab942STakashi Iwai data = (const __le16 *)chip->assp_kernel_image->data;
209681d7724aSClemens Ladisch for (i = 0 ; i * 2 < chip->assp_kernel_image->size; i++) {
20971da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE,
2098fa6e1cb6SDavid Woodhouse REV_B_CODE_MEMORY_BEGIN + i,
2099fa6e1cb6SDavid Woodhouse le16_to_cpu(data[i]));
21001da177e4SLinus Torvalds }
21011da177e4SLinus Torvalds
21021da177e4SLinus Torvalds /*
21031da177e4SLinus Torvalds * We only have this one client and we know that 0x400
21041da177e4SLinus Torvalds * is free in our kernel's mem map, so lets just
21051da177e4SLinus Torvalds * drop it there. It seems that the minisrc doesn't
21061da177e4SLinus Torvalds * need vectors, so we won't bother with them..
21071da177e4SLinus Torvalds */
21088c0ab942STakashi Iwai data = (const __le16 *)chip->assp_minisrc_image->data;
210981d7724aSClemens Ladisch for (i = 0; i * 2 < chip->assp_minisrc_image->size; i++) {
21101da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE,
2111fa6e1cb6SDavid Woodhouse 0x400 + i, le16_to_cpu(data[i]));
21121da177e4SLinus Torvalds }
21131da177e4SLinus Torvalds
21141da177e4SLinus Torvalds /*
21151da177e4SLinus Torvalds * write the coefficients for the low pass filter?
21161da177e4SLinus Torvalds */
21171da177e4SLinus Torvalds for (i = 0; i < MINISRC_LPF_LEN ; i++) {
21181da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE,
21191da177e4SLinus Torvalds 0x400 + MINISRC_COEF_LOC + i,
21201da177e4SLinus Torvalds minisrc_lpf[i]);
21211da177e4SLinus Torvalds }
21221da177e4SLinus Torvalds
21231da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE,
21241da177e4SLinus Torvalds 0x400 + MINISRC_COEF_LOC + MINISRC_LPF_LEN,
21251da177e4SLinus Torvalds 0x8000);
21261da177e4SLinus Torvalds
21271da177e4SLinus Torvalds /*
21281da177e4SLinus Torvalds * the minisrc is the only thing on
21291da177e4SLinus Torvalds * our task list..
21301da177e4SLinus Torvalds */
21311da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
21321da177e4SLinus Torvalds KDATA_TASK0,
21331da177e4SLinus Torvalds 0x400);
21341da177e4SLinus Torvalds
21351da177e4SLinus Torvalds /*
21361da177e4SLinus Torvalds * init the mixer number..
21371da177e4SLinus Torvalds */
21381da177e4SLinus Torvalds
21391da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
21401da177e4SLinus Torvalds KDATA_MIXER_TASK_NUMBER,0);
21411da177e4SLinus Torvalds
21421da177e4SLinus Torvalds /*
21431da177e4SLinus Torvalds * EXTREME KERNEL MASTER VOLUME
21441da177e4SLinus Torvalds */
21451da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
21461da177e4SLinus Torvalds KDATA_DAC_LEFT_VOLUME, ARB_VOLUME);
21471da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
21481da177e4SLinus Torvalds KDATA_DAC_RIGHT_VOLUME, ARB_VOLUME);
21491da177e4SLinus Torvalds
21501da177e4SLinus Torvalds chip->mixer_list.curlen = 0;
21511da177e4SLinus Torvalds chip->mixer_list.mem_addr = KDATA_MIXER_XFER0;
21521da177e4SLinus Torvalds chip->mixer_list.max = MAX_VIRTUAL_MIXER_CHANNELS;
21531da177e4SLinus Torvalds chip->adc1_list.curlen = 0;
21541da177e4SLinus Torvalds chip->adc1_list.mem_addr = KDATA_ADC1_XFER0;
21551da177e4SLinus Torvalds chip->adc1_list.max = MAX_VIRTUAL_ADC1_CHANNELS;
21561da177e4SLinus Torvalds chip->dma_list.curlen = 0;
21571da177e4SLinus Torvalds chip->dma_list.mem_addr = KDATA_DMA_XFER0;
21581da177e4SLinus Torvalds chip->dma_list.max = MAX_VIRTUAL_DMA_CHANNELS;
21591da177e4SLinus Torvalds chip->msrc_list.curlen = 0;
21601da177e4SLinus Torvalds chip->msrc_list.mem_addr = KDATA_INSTANCE0_MINISRC;
21611da177e4SLinus Torvalds chip->msrc_list.max = MAX_INSTANCE_MINISRC;
21621da177e4SLinus Torvalds }
21631da177e4SLinus Torvalds
21641da177e4SLinus Torvalds
snd_m3_assp_client_init(struct snd_m3 * chip,struct m3_dma * s,int index)2165e23e7a14SBill Pemberton static int snd_m3_assp_client_init(struct snd_m3 *chip, struct m3_dma *s, int index)
21661da177e4SLinus Torvalds {
21671da177e4SLinus Torvalds int data_bytes = 2 * ( MINISRC_TMP_BUFFER_SIZE / 2 +
21681da177e4SLinus Torvalds MINISRC_IN_BUFFER_SIZE / 2 +
21691da177e4SLinus Torvalds 1 + MINISRC_OUT_BUFFER_SIZE / 2 + 1 );
21701da177e4SLinus Torvalds int address, i;
21711da177e4SLinus Torvalds
21721da177e4SLinus Torvalds /*
21731da177e4SLinus Torvalds * the revb memory map has 0x1100 through 0x1c00
21741da177e4SLinus Torvalds * free.
21751da177e4SLinus Torvalds */
21761da177e4SLinus Torvalds
21771da177e4SLinus Torvalds /*
21780b2dcd5dSAndreas Mohr * align instance address to 256 bytes so that its
21791da177e4SLinus Torvalds * shifted list address is aligned.
21801da177e4SLinus Torvalds * list address = (mem address >> 1) >> 7;
21811da177e4SLinus Torvalds */
21827ab39926SClemens Ladisch data_bytes = ALIGN(data_bytes, 256);
21831da177e4SLinus Torvalds address = 0x1100 + ((data_bytes/2) * index);
21841da177e4SLinus Torvalds
21851da177e4SLinus Torvalds if ((address + (data_bytes/2)) >= 0x1c00) {
2186747ce5b3STakashi Iwai dev_err(chip->card->dev,
2187747ce5b3STakashi Iwai "no memory for %d bytes at ind %d (addr 0x%x)\n",
21881da177e4SLinus Torvalds data_bytes, index, address);
21891da177e4SLinus Torvalds return -ENOMEM;
21901da177e4SLinus Torvalds }
21911da177e4SLinus Torvalds
21921da177e4SLinus Torvalds s->number = index;
21931da177e4SLinus Torvalds s->inst.code = 0x400;
21941da177e4SLinus Torvalds s->inst.data = address;
21951da177e4SLinus Torvalds
21961da177e4SLinus Torvalds for (i = data_bytes / 2; i > 0; address++, i--) {
21971da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
21981da177e4SLinus Torvalds address, 0);
21991da177e4SLinus Torvalds }
22001da177e4SLinus Torvalds
22011da177e4SLinus Torvalds return 0;
22021da177e4SLinus Torvalds }
22031da177e4SLinus Torvalds
22041da177e4SLinus Torvalds
22051da177e4SLinus Torvalds /*
22061da177e4SLinus Torvalds * this works for the reference board, have to find
22071da177e4SLinus Torvalds * out about others
22081da177e4SLinus Torvalds *
22091da177e4SLinus Torvalds * this needs more magic for 4 speaker, but..
22101da177e4SLinus Torvalds */
22111da177e4SLinus Torvalds static void
snd_m3_amp_enable(struct snd_m3 * chip,int enable)22123470c29dSTakashi Iwai snd_m3_amp_enable(struct snd_m3 *chip, int enable)
22131da177e4SLinus Torvalds {
22141da177e4SLinus Torvalds int io = chip->iobase;
22151da177e4SLinus Torvalds u16 gpo, polarity;
22161da177e4SLinus Torvalds
22171da177e4SLinus Torvalds if (! chip->external_amp)
22181da177e4SLinus Torvalds return;
22191da177e4SLinus Torvalds
22201da177e4SLinus Torvalds polarity = enable ? 0 : 1;
22211da177e4SLinus Torvalds polarity = polarity << chip->amp_gpio;
22221da177e4SLinus Torvalds gpo = 1 << chip->amp_gpio;
22231da177e4SLinus Torvalds
22241da177e4SLinus Torvalds outw(~gpo, io + GPIO_MASK);
22251da177e4SLinus Torvalds
22261da177e4SLinus Torvalds outw(inw(io + GPIO_DIRECTION) | gpo,
22271da177e4SLinus Torvalds io + GPIO_DIRECTION);
22281da177e4SLinus Torvalds
22291da177e4SLinus Torvalds outw((GPO_SECONDARY_AC97 | GPO_PRIMARY_AC97 | polarity),
22301da177e4SLinus Torvalds io + GPIO_DATA);
22311da177e4SLinus Torvalds
22321da177e4SLinus Torvalds outw(0xffff, io + GPIO_MASK);
22331da177e4SLinus Torvalds }
22341da177e4SLinus Torvalds
22358b83afe0SVille Syrjälä static void
snd_m3_hv_init(struct snd_m3 * chip)22368b83afe0SVille Syrjälä snd_m3_hv_init(struct snd_m3 *chip)
22378b83afe0SVille Syrjälä {
22388b83afe0SVille Syrjälä unsigned long io = chip->iobase;
22398b83afe0SVille Syrjälä u16 val = GPI_VOL_DOWN | GPI_VOL_UP;
22408b83afe0SVille Syrjälä
22418b83afe0SVille Syrjälä if (!chip->is_omnibook)
22428b83afe0SVille Syrjälä return;
22438b83afe0SVille Syrjälä
22448b83afe0SVille Syrjälä /*
22458b83afe0SVille Syrjälä * Volume buttons on some HP OmniBook laptops
22468b83afe0SVille Syrjälä * require some GPIO magic to work correctly.
22478b83afe0SVille Syrjälä */
22488b83afe0SVille Syrjälä outw(0xffff, io + GPIO_MASK);
22498b83afe0SVille Syrjälä outw(0x0000, io + GPIO_DATA);
22508b83afe0SVille Syrjälä
22518b83afe0SVille Syrjälä outw(~val, io + GPIO_MASK);
22528b83afe0SVille Syrjälä outw(inw(io + GPIO_DIRECTION) & ~val, io + GPIO_DIRECTION);
22538b83afe0SVille Syrjälä outw(val, io + GPIO_MASK);
22548b83afe0SVille Syrjälä
22558b83afe0SVille Syrjälä outw(0xffff, io + GPIO_MASK);
22568b83afe0SVille Syrjälä }
22578b83afe0SVille Syrjälä
22581da177e4SLinus Torvalds static int
snd_m3_chip_init(struct snd_m3 * chip)22593470c29dSTakashi Iwai snd_m3_chip_init(struct snd_m3 *chip)
22601da177e4SLinus Torvalds {
22611da177e4SLinus Torvalds struct pci_dev *pcidev = chip->pci;
2262db68d15dSVille Syrjala unsigned long io = chip->iobase;
22631da177e4SLinus Torvalds u32 n;
22641da177e4SLinus Torvalds u16 w;
22651da177e4SLinus Torvalds u8 t; /* makes as much sense as 'n', no? */
22661da177e4SLinus Torvalds
22671da177e4SLinus Torvalds pci_read_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, &w);
22681da177e4SLinus Torvalds w &= ~(SOUND_BLASTER_ENABLE|FM_SYNTHESIS_ENABLE|
22691da177e4SLinus Torvalds MPU401_IO_ENABLE|MPU401_IRQ_ENABLE|ALIAS_10BIT_IO|
22701da177e4SLinus Torvalds DISABLE_LEGACY);
22711da177e4SLinus Torvalds pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w);
22721da177e4SLinus Torvalds
22731da177e4SLinus Torvalds pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
227482f008c2SVille Syrjala n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD);
22751061eeb4STakashi Iwai n |= chip->hv_config;
227682f008c2SVille Syrjala /* For some reason we must always use reduced debounce. */
227782f008c2SVille Syrjala n |= REDUCED_DEBOUNCE;
22781da177e4SLinus Torvalds n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING;
22791da177e4SLinus Torvalds pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n);
22801da177e4SLinus Torvalds
22811da177e4SLinus Torvalds outb(RESET_ASSP, chip->iobase + ASSP_CONTROL_B);
22821da177e4SLinus Torvalds pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
22831da177e4SLinus Torvalds n &= ~INT_CLK_SELECT;
22841da177e4SLinus Torvalds if (!chip->allegro_flag) {
22851da177e4SLinus Torvalds n &= ~INT_CLK_MULT_ENABLE;
22861da177e4SLinus Torvalds n |= INT_CLK_SRC_NOT_PCI;
22871da177e4SLinus Torvalds }
22881da177e4SLinus Torvalds n &= ~( CLK_MULT_MODE_SELECT | CLK_MULT_MODE_SELECT_2 );
22891da177e4SLinus Torvalds pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n);
22901da177e4SLinus Torvalds
22911da177e4SLinus Torvalds if (chip->allegro_flag) {
22921da177e4SLinus Torvalds pci_read_config_dword(pcidev, PCI_USER_CONFIG, &n);
22931da177e4SLinus Torvalds n |= IN_CLK_12MHZ_SELECT;
22941da177e4SLinus Torvalds pci_write_config_dword(pcidev, PCI_USER_CONFIG, n);
22951da177e4SLinus Torvalds }
22961da177e4SLinus Torvalds
22971da177e4SLinus Torvalds t = inb(chip->iobase + ASSP_CONTROL_A);
22981da177e4SLinus Torvalds t &= ~( DSP_CLK_36MHZ_SELECT | ASSP_CLK_49MHZ_SELECT);
22991da177e4SLinus Torvalds t |= ASSP_CLK_49MHZ_SELECT;
23001da177e4SLinus Torvalds t |= ASSP_0_WS_ENABLE;
23011da177e4SLinus Torvalds outb(t, chip->iobase + ASSP_CONTROL_A);
23021da177e4SLinus Torvalds
2303051b5165SCharles R. Anderson snd_m3_assp_init(chip); /* download DSP code before starting ASSP below */
23041da177e4SLinus Torvalds outb(RUN_ASSP, chip->iobase + ASSP_CONTROL_B);
23051da177e4SLinus Torvalds
2306db68d15dSVille Syrjala outb(0x00, io + HARDWARE_VOL_CTRL);
2307db68d15dSVille Syrjala outb(0x88, io + SHADOW_MIX_REG_VOICE);
2308db68d15dSVille Syrjala outb(0x88, io + HW_VOL_COUNTER_VOICE);
2309db68d15dSVille Syrjala outb(0x88, io + SHADOW_MIX_REG_MASTER);
2310db68d15dSVille Syrjala outb(0x88, io + HW_VOL_COUNTER_MASTER);
2311db68d15dSVille Syrjala
23121da177e4SLinus Torvalds return 0;
23131da177e4SLinus Torvalds }
23141da177e4SLinus Torvalds
23151da177e4SLinus Torvalds static void
snd_m3_enable_ints(struct snd_m3 * chip)23163470c29dSTakashi Iwai snd_m3_enable_ints(struct snd_m3 *chip)
23171da177e4SLinus Torvalds {
23181da177e4SLinus Torvalds unsigned long io = chip->iobase;
23195ba1e7b5STakashi Iwai unsigned short val;
23201da177e4SLinus Torvalds
23211da177e4SLinus Torvalds /* TODO: MPU401 not supported yet */
23225ba1e7b5STakashi Iwai val = ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/;
23231061eeb4STakashi Iwai if (chip->hv_config & HV_CTRL_ENABLE)
23245ba1e7b5STakashi Iwai val |= HV_INT_ENABLE;
23251bde78bcSVille Syrjälä outb(val, chip->iobase + HOST_INT_STATUS);
23265ba1e7b5STakashi Iwai outw(val, io + HOST_INT_CTRL);
23271da177e4SLinus Torvalds outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
23281da177e4SLinus Torvalds io + ASSP_CONTROL_C);
23291da177e4SLinus Torvalds }
23301da177e4SLinus Torvalds
23311da177e4SLinus Torvalds
23321da177e4SLinus Torvalds /*
23331da177e4SLinus Torvalds */
23341da177e4SLinus Torvalds
snd_m3_free(struct snd_card * card)23355c093925STakashi Iwai static void snd_m3_free(struct snd_card *card)
23361da177e4SLinus Torvalds {
23375c093925STakashi Iwai struct snd_m3 *chip = card->private_data;
23383470c29dSTakashi Iwai struct m3_dma *s;
23391da177e4SLinus Torvalds int i;
23401da177e4SLinus Torvalds
234130bdee02STakashi Iwai cancel_work_sync(&chip->hwvol_work);
2342eb581adfSHans de Goede
23431da177e4SLinus Torvalds if (chip->substreams) {
23441da177e4SLinus Torvalds spin_lock_irq(&chip->reg_lock);
23451da177e4SLinus Torvalds for (i = 0; i < chip->num_substreams; i++) {
23461da177e4SLinus Torvalds s = &chip->substreams[i];
23471da177e4SLinus Torvalds /* check surviving pcms; this should not happen though.. */
23481da177e4SLinus Torvalds if (s->substream && s->running)
23491da177e4SLinus Torvalds snd_m3_pcm_stop(chip, s, s->substream);
23501da177e4SLinus Torvalds }
23511da177e4SLinus Torvalds spin_unlock_irq(&chip->reg_lock);
23521da177e4SLinus Torvalds }
23531da177e4SLinus Torvalds if (chip->iobase) {
235488491386SVille Syrjala outw(0, chip->iobase + HOST_INT_CTRL); /* disable ints */
23551da177e4SLinus Torvalds }
23561da177e4SLinus Torvalds
2357c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
23581da177e4SLinus Torvalds vfree(chip->suspend_mem);
23591da177e4SLinus Torvalds #endif
236081d7724aSClemens Ladisch release_firmware(chip->assp_kernel_image);
236181d7724aSClemens Ladisch release_firmware(chip->assp_minisrc_image);
23621da177e4SLinus Torvalds }
23631da177e4SLinus Torvalds
23641da177e4SLinus Torvalds
23651da177e4SLinus Torvalds /*
23661da177e4SLinus Torvalds * APM support
23671da177e4SLinus Torvalds */
2368c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
m3_suspend(struct device * dev)236968cb2b55STakashi Iwai static int m3_suspend(struct device *dev)
23701da177e4SLinus Torvalds {
237168cb2b55STakashi Iwai struct snd_card *card = dev_get_drvdata(dev);
23720e2364a7STakashi Iwai struct snd_m3 *chip = card->private_data;
2373e37273d3SHarvey Harrison int i, dsp_index;
23741da177e4SLinus Torvalds
23751da177e4SLinus Torvalds if (chip->suspend_mem == NULL)
23761da177e4SLinus Torvalds return 0;
23771da177e4SLinus Torvalds
2378715aa675SHans de Goede chip->in_suspend = 1;
237930bdee02STakashi Iwai cancel_work_sync(&chip->hwvol_work);
23800e2364a7STakashi Iwai snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
23811da177e4SLinus Torvalds snd_ac97_suspend(chip->ac97);
23821da177e4SLinus Torvalds
23835ba1e7b5STakashi Iwai msleep(10); /* give the assp a chance to idle.. */
23841da177e4SLinus Torvalds
23851da177e4SLinus Torvalds snd_m3_assp_halt(chip);
23861da177e4SLinus Torvalds
23871da177e4SLinus Torvalds /* save dsp image */
2388e37273d3SHarvey Harrison dsp_index = 0;
23891da177e4SLinus Torvalds for (i = REV_B_CODE_MEMORY_BEGIN; i <= REV_B_CODE_MEMORY_END; i++)
2390e37273d3SHarvey Harrison chip->suspend_mem[dsp_index++] =
23911da177e4SLinus Torvalds snd_m3_assp_read(chip, MEMTYPE_INTERNAL_CODE, i);
23921da177e4SLinus Torvalds for (i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++)
2393e37273d3SHarvey Harrison chip->suspend_mem[dsp_index++] =
23941da177e4SLinus Torvalds snd_m3_assp_read(chip, MEMTYPE_INTERNAL_DATA, i);
23951da177e4SLinus Torvalds return 0;
23961da177e4SLinus Torvalds }
23971da177e4SLinus Torvalds
m3_resume(struct device * dev)239868cb2b55STakashi Iwai static int m3_resume(struct device *dev)
23991da177e4SLinus Torvalds {
240068cb2b55STakashi Iwai struct snd_card *card = dev_get_drvdata(dev);
24010e2364a7STakashi Iwai struct snd_m3 *chip = card->private_data;
2402e37273d3SHarvey Harrison int i, dsp_index;
24031da177e4SLinus Torvalds
24041da177e4SLinus Torvalds if (chip->suspend_mem == NULL)
24051da177e4SLinus Torvalds return 0;
24061da177e4SLinus Torvalds
24071da177e4SLinus Torvalds /* first lets just bring everything back. .*/
24081da177e4SLinus Torvalds snd_m3_outw(chip, 0, 0x54);
24091da177e4SLinus Torvalds snd_m3_outw(chip, 0, 0x56);
24101da177e4SLinus Torvalds
24111da177e4SLinus Torvalds snd_m3_chip_init(chip);
24121da177e4SLinus Torvalds snd_m3_assp_halt(chip);
24131da177e4SLinus Torvalds snd_m3_ac97_reset(chip);
24141da177e4SLinus Torvalds
24151da177e4SLinus Torvalds /* restore dsp image */
2416e37273d3SHarvey Harrison dsp_index = 0;
24171da177e4SLinus Torvalds for (i = REV_B_CODE_MEMORY_BEGIN; i <= REV_B_CODE_MEMORY_END; i++)
24181da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE, i,
2419e37273d3SHarvey Harrison chip->suspend_mem[dsp_index++]);
24201da177e4SLinus Torvalds for (i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++)
24211da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, i,
2422e37273d3SHarvey Harrison chip->suspend_mem[dsp_index++]);
24231da177e4SLinus Torvalds
24241da177e4SLinus Torvalds /* tell the dma engine to restart itself */
24251da177e4SLinus Torvalds snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
24261da177e4SLinus Torvalds KDATA_DMA_ACTIVE, 0);
24271da177e4SLinus Torvalds
24281da177e4SLinus Torvalds /* restore ac97 registers */
24291da177e4SLinus Torvalds snd_ac97_resume(chip->ac97);
24301da177e4SLinus Torvalds
24311da177e4SLinus Torvalds snd_m3_assp_continue(chip);
24321da177e4SLinus Torvalds snd_m3_enable_ints(chip);
24331da177e4SLinus Torvalds snd_m3_amp_enable(chip, 1);
24341da177e4SLinus Torvalds
24358b83afe0SVille Syrjälä snd_m3_hv_init(chip);
24368b83afe0SVille Syrjälä
24370e2364a7STakashi Iwai snd_power_change_state(card, SNDRV_CTL_POWER_D0);
2438715aa675SHans de Goede chip->in_suspend = 0;
24391da177e4SLinus Torvalds return 0;
24401da177e4SLinus Torvalds }
244168cb2b55STakashi Iwai
244268cb2b55STakashi Iwai static SIMPLE_DEV_PM_OPS(m3_pm, m3_suspend, m3_resume);
244368cb2b55STakashi Iwai #define M3_PM_OPS &m3_pm
244468cb2b55STakashi Iwai #else
244568cb2b55STakashi Iwai #define M3_PM_OPS NULL
2446c7561cd8STakashi Iwai #endif /* CONFIG_PM_SLEEP */
24471da177e4SLinus Torvalds
2448eb581adfSHans de Goede #ifdef CONFIG_SND_MAESTRO3_INPUT
snd_m3_input_register(struct snd_m3 * chip)2449e23e7a14SBill Pemberton static int snd_m3_input_register(struct snd_m3 *chip)
2450eb581adfSHans de Goede {
2451eb581adfSHans de Goede struct input_dev *input_dev;
2452eb581adfSHans de Goede int err;
2453eb581adfSHans de Goede
24545c093925STakashi Iwai input_dev = devm_input_allocate_device(&chip->pci->dev);
2455eb581adfSHans de Goede if (!input_dev)
2456eb581adfSHans de Goede return -ENOMEM;
2457eb581adfSHans de Goede
2458eb581adfSHans de Goede snprintf(chip->phys, sizeof(chip->phys), "pci-%s/input0",
2459eb581adfSHans de Goede pci_name(chip->pci));
2460eb581adfSHans de Goede
2461eb581adfSHans de Goede input_dev->name = chip->card->driver;
2462eb581adfSHans de Goede input_dev->phys = chip->phys;
2463eb581adfSHans de Goede input_dev->id.bustype = BUS_PCI;
2464eb581adfSHans de Goede input_dev->id.vendor = chip->pci->vendor;
2465eb581adfSHans de Goede input_dev->id.product = chip->pci->device;
2466eb581adfSHans de Goede input_dev->dev.parent = &chip->pci->dev;
2467eb581adfSHans de Goede
2468eb581adfSHans de Goede __set_bit(EV_KEY, input_dev->evbit);
2469eb581adfSHans de Goede __set_bit(KEY_MUTE, input_dev->keybit);
2470eb581adfSHans de Goede __set_bit(KEY_VOLUMEDOWN, input_dev->keybit);
2471eb581adfSHans de Goede __set_bit(KEY_VOLUMEUP, input_dev->keybit);
2472eb581adfSHans de Goede
2473eb581adfSHans de Goede err = input_register_device(input_dev);
24745c093925STakashi Iwai if (err)
2475eb581adfSHans de Goede return err;
2476eb581adfSHans de Goede
2477eb581adfSHans de Goede chip->input_dev = input_dev;
2478eb581adfSHans de Goede return 0;
2479eb581adfSHans de Goede }
2480eb581adfSHans de Goede #endif /* CONFIG_INPUT */
24811da177e4SLinus Torvalds
24821da177e4SLinus Torvalds /*
24831da177e4SLinus Torvalds */
24841da177e4SLinus Torvalds
2485e23e7a14SBill Pemberton static int
snd_m3_create(struct snd_card * card,struct pci_dev * pci,int enable_amp,int amp_gpio)24863470c29dSTakashi Iwai snd_m3_create(struct snd_card *card, struct pci_dev *pci,
24871da177e4SLinus Torvalds int enable_amp,
24885c093925STakashi Iwai int amp_gpio)
24891da177e4SLinus Torvalds {
24905c093925STakashi Iwai struct snd_m3 *chip = card->private_data;
24911da177e4SLinus Torvalds int i, err;
24921061eeb4STakashi Iwai const struct snd_pci_quirk *quirk;
24931da177e4SLinus Torvalds
24945c093925STakashi Iwai if (pcim_enable_device(pci))
24951da177e4SLinus Torvalds return -EIO;
24961da177e4SLinus Torvalds
24971da177e4SLinus Torvalds /* check, if we can restrict PCI DMA transfers to 28 bits */
2498669f65eaSTakashi Iwai if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(28))) {
2499747ce5b3STakashi Iwai dev_err(card->dev,
2500747ce5b3STakashi Iwai "architecture does not support 28bit PCI busmaster DMA\n");
25011da177e4SLinus Torvalds return -ENXIO;
25021da177e4SLinus Torvalds }
25031da177e4SLinus Torvalds
25041da177e4SLinus Torvalds spin_lock_init(&chip->reg_lock);
25055ba1e7b5STakashi Iwai
25061da177e4SLinus Torvalds switch (pci->device) {
25071da177e4SLinus Torvalds case PCI_DEVICE_ID_ESS_ALLEGRO:
25081da177e4SLinus Torvalds case PCI_DEVICE_ID_ESS_ALLEGRO_1:
25091da177e4SLinus Torvalds case PCI_DEVICE_ID_ESS_CANYON3D_2LE:
25101da177e4SLinus Torvalds case PCI_DEVICE_ID_ESS_CANYON3D_2:
25111da177e4SLinus Torvalds chip->allegro_flag = 1;
25121da177e4SLinus Torvalds break;
25131da177e4SLinus Torvalds }
25141da177e4SLinus Torvalds
25151da177e4SLinus Torvalds chip->card = card;
25161da177e4SLinus Torvalds chip->pci = pci;
25171da177e4SLinus Torvalds chip->irq = -1;
251830bdee02STakashi Iwai INIT_WORK(&chip->hwvol_work, snd_m3_update_hw_volume);
25195c093925STakashi Iwai card->private_free = snd_m3_free;
25201da177e4SLinus Torvalds
25211da177e4SLinus Torvalds chip->external_amp = enable_amp;
25221da177e4SLinus Torvalds if (amp_gpio >= 0 && amp_gpio <= 0x0f)
25231da177e4SLinus Torvalds chip->amp_gpio = amp_gpio;
25241061eeb4STakashi Iwai else {
25251061eeb4STakashi Iwai quirk = snd_pci_quirk_lookup(pci, m3_amp_quirk_list);
25261061eeb4STakashi Iwai if (quirk) {
2527747ce5b3STakashi Iwai dev_info(card->dev, "set amp-gpio for '%s'\n",
252886b27237STakashi Iwai snd_pci_quirk_name(quirk));
25291061eeb4STakashi Iwai chip->amp_gpio = quirk->value;
25301061eeb4STakashi Iwai } else if (chip->allegro_flag)
25311da177e4SLinus Torvalds chip->amp_gpio = GPO_EXT_AMP_ALLEGRO;
25321da177e4SLinus Torvalds else /* presumably this is for all 'maestro3's.. */
25331da177e4SLinus Torvalds chip->amp_gpio = GPO_EXT_AMP_M3;
25341061eeb4STakashi Iwai }
25351061eeb4STakashi Iwai
25361061eeb4STakashi Iwai quirk = snd_pci_quirk_lookup(pci, m3_irda_quirk_list);
25371061eeb4STakashi Iwai if (quirk) {
2538747ce5b3STakashi Iwai dev_info(card->dev, "enabled irda workaround for '%s'\n",
253986b27237STakashi Iwai snd_pci_quirk_name(quirk));
25401061eeb4STakashi Iwai chip->irda_workaround = 1;
25411061eeb4STakashi Iwai }
25421061eeb4STakashi Iwai quirk = snd_pci_quirk_lookup(pci, m3_hv_quirk_list);
25431061eeb4STakashi Iwai if (quirk)
25441061eeb4STakashi Iwai chip->hv_config = quirk->value;
25451061eeb4STakashi Iwai if (snd_pci_quirk_lookup(pci, m3_omnibook_quirk_list))
25461061eeb4STakashi Iwai chip->is_omnibook = 1;
25471da177e4SLinus Torvalds
25481da177e4SLinus Torvalds chip->num_substreams = NR_DSPS;
25495c093925STakashi Iwai chip->substreams = devm_kcalloc(&pci->dev, chip->num_substreams,
25505c093925STakashi Iwai sizeof(struct m3_dma), GFP_KERNEL);
25515c093925STakashi Iwai if (!chip->substreams)
25521da177e4SLinus Torvalds return -ENOMEM;
25531da177e4SLinus Torvalds
2554b7dd2b34STakashi Iwai err = request_firmware(&chip->assp_kernel_image,
2555b7dd2b34STakashi Iwai "ess/maestro3_assp_kernel.fw", &pci->dev);
2556468778a0SMarkus Elfring if (err < 0)
25575c093925STakashi Iwai return err;
255881d7724aSClemens Ladisch
2559b7dd2b34STakashi Iwai err = request_firmware(&chip->assp_minisrc_image,
2560b7dd2b34STakashi Iwai "ess/maestro3_assp_minisrc.fw", &pci->dev);
2561468778a0SMarkus Elfring if (err < 0)
25625c093925STakashi Iwai return err;
256381d7724aSClemens Ladisch
2564468778a0SMarkus Elfring err = pci_request_regions(pci, card->driver);
2565468778a0SMarkus Elfring if (err < 0)
25665c093925STakashi Iwai return err;
2567468778a0SMarkus Elfring
25681da177e4SLinus Torvalds chip->iobase = pci_resource_start(pci, 0);
25691da177e4SLinus Torvalds
25701da177e4SLinus Torvalds /* just to be sure */
25711da177e4SLinus Torvalds pci_set_master(pci);
25721da177e4SLinus Torvalds
25731da177e4SLinus Torvalds snd_m3_chip_init(chip);
25741da177e4SLinus Torvalds snd_m3_assp_halt(chip);
25751da177e4SLinus Torvalds
25761da177e4SLinus Torvalds snd_m3_ac97_reset(chip);
25771da177e4SLinus Torvalds
25781da177e4SLinus Torvalds snd_m3_amp_enable(chip, 1);
25791da177e4SLinus Torvalds
25808b83afe0SVille Syrjälä snd_m3_hv_init(chip);
25818b83afe0SVille Syrjälä
25825c093925STakashi Iwai if (devm_request_irq(&pci->dev, pci->irq, snd_m3_interrupt, IRQF_SHARED,
2583934c2b6dSTakashi Iwai KBUILD_MODNAME, chip)) {
2584747ce5b3STakashi Iwai dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
25855c093925STakashi Iwai return -ENOMEM;
25861da177e4SLinus Torvalds }
25871da177e4SLinus Torvalds chip->irq = pci->irq;
2588a20b8bfeSTakashi Iwai card->sync_irq = chip->irq;
25891da177e4SLinus Torvalds
2590c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
259142bc47b3SKees Cook chip->suspend_mem =
259242bc47b3SKees Cook vmalloc(array_size(sizeof(u16),
259342bc47b3SKees Cook REV_B_CODE_MEMORY_LENGTH +
259442bc47b3SKees Cook REV_B_DATA_MEMORY_LENGTH));
25951da177e4SLinus Torvalds if (chip->suspend_mem == NULL)
2596747ce5b3STakashi Iwai dev_warn(card->dev, "can't allocate apm buffer\n");
25971da177e4SLinus Torvalds #endif
25981da177e4SLinus Torvalds
25995cc16ba6STakashi Iwai err = snd_m3_mixer(chip);
26005cc16ba6STakashi Iwai if (err < 0)
26011da177e4SLinus Torvalds return err;
26021da177e4SLinus Torvalds
26031da177e4SLinus Torvalds for (i = 0; i < chip->num_substreams; i++) {
26043470c29dSTakashi Iwai struct m3_dma *s = &chip->substreams[i];
26055cc16ba6STakashi Iwai err = snd_m3_assp_client_init(chip, s, i);
26065cc16ba6STakashi Iwai if (err < 0)
26071da177e4SLinus Torvalds return err;
26081da177e4SLinus Torvalds }
26091da177e4SLinus Torvalds
26105cc16ba6STakashi Iwai err = snd_m3_pcm(chip, 0);
26115cc16ba6STakashi Iwai if (err < 0)
26121da177e4SLinus Torvalds return err;
26131da177e4SLinus Torvalds
2614eb581adfSHans de Goede #ifdef CONFIG_SND_MAESTRO3_INPUT
2615eb581adfSHans de Goede if (chip->hv_config & HV_CTRL_ENABLE) {
2616eb581adfSHans de Goede err = snd_m3_input_register(chip);
2617eb581adfSHans de Goede if (err)
2618747ce5b3STakashi Iwai dev_warn(card->dev,
2619747ce5b3STakashi Iwai "Input device registration failed with error %i",
2620747ce5b3STakashi Iwai err);
2621eb581adfSHans de Goede }
2622eb581adfSHans de Goede #endif
2623eb581adfSHans de Goede
26241da177e4SLinus Torvalds snd_m3_enable_ints(chip);
26251da177e4SLinus Torvalds snd_m3_assp_continue(chip);
26261da177e4SLinus Torvalds
26271da177e4SLinus Torvalds return 0;
26281da177e4SLinus Torvalds }
26291da177e4SLinus Torvalds
26301da177e4SLinus Torvalds /*
26311da177e4SLinus Torvalds */
2632e23e7a14SBill Pemberton static int
__snd_m3_probe(struct pci_dev * pci,const struct pci_device_id * pci_id)2633ae86bf5cSTakashi Iwai __snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
26341da177e4SLinus Torvalds {
26351da177e4SLinus Torvalds static int dev;
26363470c29dSTakashi Iwai struct snd_card *card;
26373470c29dSTakashi Iwai struct snd_m3 *chip;
26381da177e4SLinus Torvalds int err;
26391da177e4SLinus Torvalds
26401da177e4SLinus Torvalds /* don't pick up modems */
26411da177e4SLinus Torvalds if (((pci->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO)
26421da177e4SLinus Torvalds return -ENODEV;
26431da177e4SLinus Torvalds
26441da177e4SLinus Torvalds if (dev >= SNDRV_CARDS)
26451da177e4SLinus Torvalds return -ENODEV;
26461da177e4SLinus Torvalds if (!enable[dev]) {
26471da177e4SLinus Torvalds dev++;
26481da177e4SLinus Torvalds return -ENOENT;
26491da177e4SLinus Torvalds }
26501da177e4SLinus Torvalds
26515c093925STakashi Iwai err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
26525c093925STakashi Iwai sizeof(*chip), &card);
2653e58de7baSTakashi Iwai if (err < 0)
2654e58de7baSTakashi Iwai return err;
26555c093925STakashi Iwai chip = card->private_data;
26561da177e4SLinus Torvalds
26571da177e4SLinus Torvalds switch (pci->device) {
26581da177e4SLinus Torvalds case PCI_DEVICE_ID_ESS_ALLEGRO:
26591da177e4SLinus Torvalds case PCI_DEVICE_ID_ESS_ALLEGRO_1:
26601da177e4SLinus Torvalds strcpy(card->driver, "Allegro");
26611da177e4SLinus Torvalds break;
26621da177e4SLinus Torvalds case PCI_DEVICE_ID_ESS_CANYON3D_2LE:
26631da177e4SLinus Torvalds case PCI_DEVICE_ID_ESS_CANYON3D_2:
26641da177e4SLinus Torvalds strcpy(card->driver, "Canyon3D-2");
26651da177e4SLinus Torvalds break;
26661da177e4SLinus Torvalds default:
26671da177e4SLinus Torvalds strcpy(card->driver, "Maestro3");
26681da177e4SLinus Torvalds break;
26691da177e4SLinus Torvalds }
26701da177e4SLinus Torvalds
26715c093925STakashi Iwai err = snd_m3_create(card, pci, external_amp[dev], amp_gpio[dev]);
2672468778a0SMarkus Elfring if (err < 0)
26735c093925STakashi Iwai return err;
26741da177e4SLinus Torvalds
26751da177e4SLinus Torvalds sprintf(card->shortname, "ESS %s PCI", card->driver);
26761da177e4SLinus Torvalds sprintf(card->longname, "%s at 0x%lx, irq %d",
26771da177e4SLinus Torvalds card->shortname, chip->iobase, chip->irq);
26781da177e4SLinus Torvalds
2679468778a0SMarkus Elfring err = snd_card_register(card);
2680468778a0SMarkus Elfring if (err < 0)
26815c093925STakashi Iwai return err;
26821da177e4SLinus Torvalds
26831da177e4SLinus Torvalds #if 0 /* TODO: not supported yet */
26840b2dcd5dSAndreas Mohr /* TODO enable MIDI IRQ and I/O */
26851da177e4SLinus Torvalds err = snd_mpu401_uart_new(chip->card, 0, MPU401_HW_MPU401,
2686302e4c2fSTakashi Iwai chip->iobase + MPU401_DATA_PORT,
2687dba8b469SClemens Ladisch MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK,
2688dba8b469SClemens Ladisch -1, &chip->rmidi);
26891da177e4SLinus Torvalds if (err < 0)
2690747ce5b3STakashi Iwai dev_warn(card->dev, "no MIDI support.\n");
26911da177e4SLinus Torvalds #endif
26921da177e4SLinus Torvalds
26931da177e4SLinus Torvalds pci_set_drvdata(pci, card);
26941da177e4SLinus Torvalds dev++;
26951da177e4SLinus Torvalds return 0;
26961da177e4SLinus Torvalds }
26971da177e4SLinus Torvalds
2698ae86bf5cSTakashi Iwai static int
snd_m3_probe(struct pci_dev * pci,const struct pci_device_id * pci_id)2699ae86bf5cSTakashi Iwai snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
2700ae86bf5cSTakashi Iwai {
2701ae86bf5cSTakashi Iwai return snd_card_free_on_error(&pci->dev, __snd_m3_probe(pci, pci_id));
2702ae86bf5cSTakashi Iwai }
2703ae86bf5cSTakashi Iwai
2704e9f66d9bSTakashi Iwai static struct pci_driver m3_driver = {
27053733e424STakashi Iwai .name = KBUILD_MODNAME,
27061da177e4SLinus Torvalds .id_table = snd_m3_ids,
27071da177e4SLinus Torvalds .probe = snd_m3_probe,
270868cb2b55STakashi Iwai .driver = {
270968cb2b55STakashi Iwai .pm = M3_PM_OPS,
271068cb2b55STakashi Iwai },
27111da177e4SLinus Torvalds };
27121da177e4SLinus Torvalds
2713e9f66d9bSTakashi Iwai module_pci_driver(m3_driver);
2714