18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for ESS Maestro3/Allegro (ES1988) soundcards. 48c2ecf20Sopenharmony_ci * Copyright (c) 2000 by Zach Brown <zab@zabbo.net> 58c2ecf20Sopenharmony_ci * Takashi Iwai <tiwai@suse.de> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Most of the hardware init stuffs are based on maestro3 driver for 88c2ecf20Sopenharmony_ci * OSS/Free by Zach Brown. Many thanks to Zach! 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * ChangeLog: 118c2ecf20Sopenharmony_ci * Aug. 27, 2001 128c2ecf20Sopenharmony_ci * - Fixed deadlock on capture 138c2ecf20Sopenharmony_ci * - Added Canyon3D-2 support by Rob Riggs <rob@pangalactic.org> 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define CARD_NAME "ESS Maestro3/Allegro/Canyon3D-2" 178c2ecf20Sopenharmony_ci#define DRIVER_NAME "Maestro3" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/io.h> 208c2ecf20Sopenharmony_ci#include <linux/delay.h> 218c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 228c2ecf20Sopenharmony_ci#include <linux/init.h> 238c2ecf20Sopenharmony_ci#include <linux/pci.h> 248c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 258c2ecf20Sopenharmony_ci#include <linux/slab.h> 268c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 278c2ecf20Sopenharmony_ci#include <linux/module.h> 288c2ecf20Sopenharmony_ci#include <linux/firmware.h> 298c2ecf20Sopenharmony_ci#include <linux/input.h> 308c2ecf20Sopenharmony_ci#include <sound/core.h> 318c2ecf20Sopenharmony_ci#include <sound/info.h> 328c2ecf20Sopenharmony_ci#include <sound/control.h> 338c2ecf20Sopenharmony_ci#include <sound/pcm.h> 348c2ecf20Sopenharmony_ci#include <sound/mpu401.h> 358c2ecf20Sopenharmony_ci#include <sound/ac97_codec.h> 368c2ecf20Sopenharmony_ci#include <sound/initval.h> 378c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ciMODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Takashi Iwai <tiwai@suse.de>"); 408c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ESS Maestro3 PCI"); 418c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 428c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("{{ESS,Maestro3 PCI}," 438c2ecf20Sopenharmony_ci "{ESS,ES1988}," 448c2ecf20Sopenharmony_ci "{ESS,Allegro PCI}," 458c2ecf20Sopenharmony_ci "{ESS,Allegro-1 PCI}," 468c2ecf20Sopenharmony_ci "{ESS,Canyon3D-2/LE PCI}}"); 478c2ecf20Sopenharmony_ciMODULE_FIRMWARE("ess/maestro3_assp_kernel.fw"); 488c2ecf20Sopenharmony_ciMODULE_FIRMWARE("ess/maestro3_assp_minisrc.fw"); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 518c2ecf20Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 528c2ecf20Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* all enabled */ 538c2ecf20Sopenharmony_cistatic bool external_amp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; 548c2ecf20Sopenharmony_cistatic int amp_gpio[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cimodule_param_array(index, int, NULL, 0444); 578c2ecf20Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); 588c2ecf20Sopenharmony_cimodule_param_array(id, charp, NULL, 0444); 598c2ecf20Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); 608c2ecf20Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444); 618c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable this soundcard."); 628c2ecf20Sopenharmony_cimodule_param_array(external_amp, bool, NULL, 0444); 638c2ecf20Sopenharmony_ciMODULE_PARM_DESC(external_amp, "Enable external amp for " CARD_NAME " soundcard."); 648c2ecf20Sopenharmony_cimodule_param_array(amp_gpio, int, NULL, 0444); 658c2ecf20Sopenharmony_ciMODULE_PARM_DESC(amp_gpio, "GPIO pin number for external amp. (default = -1)"); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define MAX_PLAYBACKS 2 688c2ecf20Sopenharmony_ci#define MAX_CAPTURES 1 698c2ecf20Sopenharmony_ci#define NR_DSPS (MAX_PLAYBACKS + MAX_CAPTURES) 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* 738c2ecf20Sopenharmony_ci * maestro3 registers 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* Allegro PCI configuration registers */ 778c2ecf20Sopenharmony_ci#define PCI_LEGACY_AUDIO_CTRL 0x40 788c2ecf20Sopenharmony_ci#define SOUND_BLASTER_ENABLE 0x00000001 798c2ecf20Sopenharmony_ci#define FM_SYNTHESIS_ENABLE 0x00000002 808c2ecf20Sopenharmony_ci#define GAME_PORT_ENABLE 0x00000004 818c2ecf20Sopenharmony_ci#define MPU401_IO_ENABLE 0x00000008 828c2ecf20Sopenharmony_ci#define MPU401_IRQ_ENABLE 0x00000010 838c2ecf20Sopenharmony_ci#define ALIAS_10BIT_IO 0x00000020 848c2ecf20Sopenharmony_ci#define SB_DMA_MASK 0x000000C0 858c2ecf20Sopenharmony_ci#define SB_DMA_0 0x00000040 868c2ecf20Sopenharmony_ci#define SB_DMA_1 0x00000040 878c2ecf20Sopenharmony_ci#define SB_DMA_R 0x00000080 888c2ecf20Sopenharmony_ci#define SB_DMA_3 0x000000C0 898c2ecf20Sopenharmony_ci#define SB_IRQ_MASK 0x00000700 908c2ecf20Sopenharmony_ci#define SB_IRQ_5 0x00000000 918c2ecf20Sopenharmony_ci#define SB_IRQ_7 0x00000100 928c2ecf20Sopenharmony_ci#define SB_IRQ_9 0x00000200 938c2ecf20Sopenharmony_ci#define SB_IRQ_10 0x00000300 948c2ecf20Sopenharmony_ci#define MIDI_IRQ_MASK 0x00003800 958c2ecf20Sopenharmony_ci#define SERIAL_IRQ_ENABLE 0x00004000 968c2ecf20Sopenharmony_ci#define DISABLE_LEGACY 0x00008000 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#define PCI_ALLEGRO_CONFIG 0x50 998c2ecf20Sopenharmony_ci#define SB_ADDR_240 0x00000004 1008c2ecf20Sopenharmony_ci#define MPU_ADDR_MASK 0x00000018 1018c2ecf20Sopenharmony_ci#define MPU_ADDR_330 0x00000000 1028c2ecf20Sopenharmony_ci#define MPU_ADDR_300 0x00000008 1038c2ecf20Sopenharmony_ci#define MPU_ADDR_320 0x00000010 1048c2ecf20Sopenharmony_ci#define MPU_ADDR_340 0x00000018 1058c2ecf20Sopenharmony_ci#define USE_PCI_TIMING 0x00000040 1068c2ecf20Sopenharmony_ci#define POSTED_WRITE_ENABLE 0x00000080 1078c2ecf20Sopenharmony_ci#define DMA_POLICY_MASK 0x00000700 1088c2ecf20Sopenharmony_ci#define DMA_DDMA 0x00000000 1098c2ecf20Sopenharmony_ci#define DMA_TDMA 0x00000100 1108c2ecf20Sopenharmony_ci#define DMA_PCPCI 0x00000200 1118c2ecf20Sopenharmony_ci#define DMA_WBDMA16 0x00000400 1128c2ecf20Sopenharmony_ci#define DMA_WBDMA4 0x00000500 1138c2ecf20Sopenharmony_ci#define DMA_WBDMA2 0x00000600 1148c2ecf20Sopenharmony_ci#define DMA_WBDMA1 0x00000700 1158c2ecf20Sopenharmony_ci#define DMA_SAFE_GUARD 0x00000800 1168c2ecf20Sopenharmony_ci#define HI_PERF_GP_ENABLE 0x00001000 1178c2ecf20Sopenharmony_ci#define PIC_SNOOP_MODE_0 0x00002000 1188c2ecf20Sopenharmony_ci#define PIC_SNOOP_MODE_1 0x00004000 1198c2ecf20Sopenharmony_ci#define SOUNDBLASTER_IRQ_MASK 0x00008000 1208c2ecf20Sopenharmony_ci#define RING_IN_ENABLE 0x00010000 1218c2ecf20Sopenharmony_ci#define SPDIF_TEST_MODE 0x00020000 1228c2ecf20Sopenharmony_ci#define CLK_MULT_MODE_SELECT_2 0x00040000 1238c2ecf20Sopenharmony_ci#define EEPROM_WRITE_ENABLE 0x00080000 1248c2ecf20Sopenharmony_ci#define CODEC_DIR_IN 0x00100000 1258c2ecf20Sopenharmony_ci#define HV_BUTTON_FROM_GD 0x00200000 1268c2ecf20Sopenharmony_ci#define REDUCED_DEBOUNCE 0x00400000 1278c2ecf20Sopenharmony_ci#define HV_CTRL_ENABLE 0x00800000 1288c2ecf20Sopenharmony_ci#define SPDIF_ENABLE 0x01000000 1298c2ecf20Sopenharmony_ci#define CLK_DIV_SELECT 0x06000000 1308c2ecf20Sopenharmony_ci#define CLK_DIV_BY_48 0x00000000 1318c2ecf20Sopenharmony_ci#define CLK_DIV_BY_49 0x02000000 1328c2ecf20Sopenharmony_ci#define CLK_DIV_BY_50 0x04000000 1338c2ecf20Sopenharmony_ci#define CLK_DIV_RESERVED 0x06000000 1348c2ecf20Sopenharmony_ci#define PM_CTRL_ENABLE 0x08000000 1358c2ecf20Sopenharmony_ci#define CLK_MULT_MODE_SELECT 0x30000000 1368c2ecf20Sopenharmony_ci#define CLK_MULT_MODE_SHIFT 28 1378c2ecf20Sopenharmony_ci#define CLK_MULT_MODE_0 0x00000000 1388c2ecf20Sopenharmony_ci#define CLK_MULT_MODE_1 0x10000000 1398c2ecf20Sopenharmony_ci#define CLK_MULT_MODE_2 0x20000000 1408c2ecf20Sopenharmony_ci#define CLK_MULT_MODE_3 0x30000000 1418c2ecf20Sopenharmony_ci#define INT_CLK_SELECT 0x40000000 1428c2ecf20Sopenharmony_ci#define INT_CLK_MULT_RESET 0x80000000 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/* M3 */ 1458c2ecf20Sopenharmony_ci#define INT_CLK_SRC_NOT_PCI 0x00100000 1468c2ecf20Sopenharmony_ci#define INT_CLK_MULT_ENABLE 0x80000000 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci#define PCI_ACPI_CONTROL 0x54 1498c2ecf20Sopenharmony_ci#define PCI_ACPI_D0 0x00000000 1508c2ecf20Sopenharmony_ci#define PCI_ACPI_D1 0xB4F70000 1518c2ecf20Sopenharmony_ci#define PCI_ACPI_D2 0xB4F7B4F7 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci#define PCI_USER_CONFIG 0x58 1548c2ecf20Sopenharmony_ci#define EXT_PCI_MASTER_ENABLE 0x00000001 1558c2ecf20Sopenharmony_ci#define SPDIF_OUT_SELECT 0x00000002 1568c2ecf20Sopenharmony_ci#define TEST_PIN_DIR_CTRL 0x00000004 1578c2ecf20Sopenharmony_ci#define AC97_CODEC_TEST 0x00000020 1588c2ecf20Sopenharmony_ci#define TRI_STATE_BUFFER 0x00000080 1598c2ecf20Sopenharmony_ci#define IN_CLK_12MHZ_SELECT 0x00000100 1608c2ecf20Sopenharmony_ci#define MULTI_FUNC_DISABLE 0x00000200 1618c2ecf20Sopenharmony_ci#define EXT_MASTER_PAIR_SEL 0x00000400 1628c2ecf20Sopenharmony_ci#define PCI_MASTER_SUPPORT 0x00000800 1638c2ecf20Sopenharmony_ci#define STOP_CLOCK_ENABLE 0x00001000 1648c2ecf20Sopenharmony_ci#define EAPD_DRIVE_ENABLE 0x00002000 1658c2ecf20Sopenharmony_ci#define REQ_TRI_STATE_ENABLE 0x00004000 1668c2ecf20Sopenharmony_ci#define REQ_LOW_ENABLE 0x00008000 1678c2ecf20Sopenharmony_ci#define MIDI_1_ENABLE 0x00010000 1688c2ecf20Sopenharmony_ci#define MIDI_2_ENABLE 0x00020000 1698c2ecf20Sopenharmony_ci#define SB_AUDIO_SYNC 0x00040000 1708c2ecf20Sopenharmony_ci#define HV_CTRL_TEST 0x00100000 1718c2ecf20Sopenharmony_ci#define SOUNDBLASTER_TEST 0x00400000 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci#define PCI_USER_CONFIG_C 0x5C 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci#define PCI_DDMA_CTRL 0x60 1768c2ecf20Sopenharmony_ci#define DDMA_ENABLE 0x00000001 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/* Allegro registers */ 1808c2ecf20Sopenharmony_ci#define HOST_INT_CTRL 0x18 1818c2ecf20Sopenharmony_ci#define SB_INT_ENABLE 0x0001 1828c2ecf20Sopenharmony_ci#define MPU401_INT_ENABLE 0x0002 1838c2ecf20Sopenharmony_ci#define ASSP_INT_ENABLE 0x0010 1848c2ecf20Sopenharmony_ci#define RING_INT_ENABLE 0x0020 1858c2ecf20Sopenharmony_ci#define HV_INT_ENABLE 0x0040 1868c2ecf20Sopenharmony_ci#define CLKRUN_GEN_ENABLE 0x0100 1878c2ecf20Sopenharmony_ci#define HV_CTRL_TO_PME 0x0400 1888c2ecf20Sopenharmony_ci#define SOFTWARE_RESET_ENABLE 0x8000 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci/* 1918c2ecf20Sopenharmony_ci * should be using the above defines, probably. 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_ci#define REGB_ENABLE_RESET 0x01 1948c2ecf20Sopenharmony_ci#define REGB_STOP_CLOCK 0x10 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci#define HOST_INT_STATUS 0x1A 1978c2ecf20Sopenharmony_ci#define SB_INT_PENDING 0x01 1988c2ecf20Sopenharmony_ci#define MPU401_INT_PENDING 0x02 1998c2ecf20Sopenharmony_ci#define ASSP_INT_PENDING 0x10 2008c2ecf20Sopenharmony_ci#define RING_INT_PENDING 0x20 2018c2ecf20Sopenharmony_ci#define HV_INT_PENDING 0x40 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci#define HARDWARE_VOL_CTRL 0x1B 2048c2ecf20Sopenharmony_ci#define SHADOW_MIX_REG_VOICE 0x1C 2058c2ecf20Sopenharmony_ci#define HW_VOL_COUNTER_VOICE 0x1D 2068c2ecf20Sopenharmony_ci#define SHADOW_MIX_REG_MASTER 0x1E 2078c2ecf20Sopenharmony_ci#define HW_VOL_COUNTER_MASTER 0x1F 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci#define CODEC_COMMAND 0x30 2108c2ecf20Sopenharmony_ci#define CODEC_READ_B 0x80 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci#define CODEC_STATUS 0x30 2138c2ecf20Sopenharmony_ci#define CODEC_BUSY_B 0x01 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci#define CODEC_DATA 0x32 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci#define RING_BUS_CTRL_A 0x36 2188c2ecf20Sopenharmony_ci#define RAC_PME_ENABLE 0x0100 2198c2ecf20Sopenharmony_ci#define RAC_SDFS_ENABLE 0x0200 2208c2ecf20Sopenharmony_ci#define LAC_PME_ENABLE 0x0400 2218c2ecf20Sopenharmony_ci#define LAC_SDFS_ENABLE 0x0800 2228c2ecf20Sopenharmony_ci#define SERIAL_AC_LINK_ENABLE 0x1000 2238c2ecf20Sopenharmony_ci#define IO_SRAM_ENABLE 0x2000 2248c2ecf20Sopenharmony_ci#define IIS_INPUT_ENABLE 0x8000 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci#define RING_BUS_CTRL_B 0x38 2278c2ecf20Sopenharmony_ci#define SECOND_CODEC_ID_MASK 0x0003 2288c2ecf20Sopenharmony_ci#define SPDIF_FUNC_ENABLE 0x0010 2298c2ecf20Sopenharmony_ci#define SECOND_AC_ENABLE 0x0020 2308c2ecf20Sopenharmony_ci#define SB_MODULE_INTF_ENABLE 0x0040 2318c2ecf20Sopenharmony_ci#define SSPE_ENABLE 0x0040 2328c2ecf20Sopenharmony_ci#define M3I_DOCK_ENABLE 0x0080 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci#define SDO_OUT_DEST_CTRL 0x3A 2358c2ecf20Sopenharmony_ci#define COMMAND_ADDR_OUT 0x0003 2368c2ecf20Sopenharmony_ci#define PCM_LR_OUT_LOCAL 0x0000 2378c2ecf20Sopenharmony_ci#define PCM_LR_OUT_REMOTE 0x0004 2388c2ecf20Sopenharmony_ci#define PCM_LR_OUT_MUTE 0x0008 2398c2ecf20Sopenharmony_ci#define PCM_LR_OUT_BOTH 0x000C 2408c2ecf20Sopenharmony_ci#define LINE1_DAC_OUT_LOCAL 0x0000 2418c2ecf20Sopenharmony_ci#define LINE1_DAC_OUT_REMOTE 0x0010 2428c2ecf20Sopenharmony_ci#define LINE1_DAC_OUT_MUTE 0x0020 2438c2ecf20Sopenharmony_ci#define LINE1_DAC_OUT_BOTH 0x0030 2448c2ecf20Sopenharmony_ci#define PCM_CLS_OUT_LOCAL 0x0000 2458c2ecf20Sopenharmony_ci#define PCM_CLS_OUT_REMOTE 0x0040 2468c2ecf20Sopenharmony_ci#define PCM_CLS_OUT_MUTE 0x0080 2478c2ecf20Sopenharmony_ci#define PCM_CLS_OUT_BOTH 0x00C0 2488c2ecf20Sopenharmony_ci#define PCM_RLF_OUT_LOCAL 0x0000 2498c2ecf20Sopenharmony_ci#define PCM_RLF_OUT_REMOTE 0x0100 2508c2ecf20Sopenharmony_ci#define PCM_RLF_OUT_MUTE 0x0200 2518c2ecf20Sopenharmony_ci#define PCM_RLF_OUT_BOTH 0x0300 2528c2ecf20Sopenharmony_ci#define LINE2_DAC_OUT_LOCAL 0x0000 2538c2ecf20Sopenharmony_ci#define LINE2_DAC_OUT_REMOTE 0x0400 2548c2ecf20Sopenharmony_ci#define LINE2_DAC_OUT_MUTE 0x0800 2558c2ecf20Sopenharmony_ci#define LINE2_DAC_OUT_BOTH 0x0C00 2568c2ecf20Sopenharmony_ci#define HANDSET_OUT_LOCAL 0x0000 2578c2ecf20Sopenharmony_ci#define HANDSET_OUT_REMOTE 0x1000 2588c2ecf20Sopenharmony_ci#define HANDSET_OUT_MUTE 0x2000 2598c2ecf20Sopenharmony_ci#define HANDSET_OUT_BOTH 0x3000 2608c2ecf20Sopenharmony_ci#define IO_CTRL_OUT_LOCAL 0x0000 2618c2ecf20Sopenharmony_ci#define IO_CTRL_OUT_REMOTE 0x4000 2628c2ecf20Sopenharmony_ci#define IO_CTRL_OUT_MUTE 0x8000 2638c2ecf20Sopenharmony_ci#define IO_CTRL_OUT_BOTH 0xC000 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci#define SDO_IN_DEST_CTRL 0x3C 2668c2ecf20Sopenharmony_ci#define STATUS_ADDR_IN 0x0003 2678c2ecf20Sopenharmony_ci#define PCM_LR_IN_LOCAL 0x0000 2688c2ecf20Sopenharmony_ci#define PCM_LR_IN_REMOTE 0x0004 2698c2ecf20Sopenharmony_ci#define PCM_LR_RESERVED 0x0008 2708c2ecf20Sopenharmony_ci#define PCM_LR_IN_BOTH 0x000C 2718c2ecf20Sopenharmony_ci#define LINE1_ADC_IN_LOCAL 0x0000 2728c2ecf20Sopenharmony_ci#define LINE1_ADC_IN_REMOTE 0x0010 2738c2ecf20Sopenharmony_ci#define LINE1_ADC_IN_MUTE 0x0020 2748c2ecf20Sopenharmony_ci#define MIC_ADC_IN_LOCAL 0x0000 2758c2ecf20Sopenharmony_ci#define MIC_ADC_IN_REMOTE 0x0040 2768c2ecf20Sopenharmony_ci#define MIC_ADC_IN_MUTE 0x0080 2778c2ecf20Sopenharmony_ci#define LINE2_DAC_IN_LOCAL 0x0000 2788c2ecf20Sopenharmony_ci#define LINE2_DAC_IN_REMOTE 0x0400 2798c2ecf20Sopenharmony_ci#define LINE2_DAC_IN_MUTE 0x0800 2808c2ecf20Sopenharmony_ci#define HANDSET_IN_LOCAL 0x0000 2818c2ecf20Sopenharmony_ci#define HANDSET_IN_REMOTE 0x1000 2828c2ecf20Sopenharmony_ci#define HANDSET_IN_MUTE 0x2000 2838c2ecf20Sopenharmony_ci#define IO_STATUS_IN_LOCAL 0x0000 2848c2ecf20Sopenharmony_ci#define IO_STATUS_IN_REMOTE 0x4000 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci#define SPDIF_IN_CTRL 0x3E 2878c2ecf20Sopenharmony_ci#define SPDIF_IN_ENABLE 0x0001 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci#define GPIO_DATA 0x60 2908c2ecf20Sopenharmony_ci#define GPIO_DATA_MASK 0x0FFF 2918c2ecf20Sopenharmony_ci#define GPIO_HV_STATUS 0x3000 2928c2ecf20Sopenharmony_ci#define GPIO_PME_STATUS 0x4000 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci#define GPIO_MASK 0x64 2958c2ecf20Sopenharmony_ci#define GPIO_DIRECTION 0x68 2968c2ecf20Sopenharmony_ci#define GPO_PRIMARY_AC97 0x0001 2978c2ecf20Sopenharmony_ci#define GPI_LINEOUT_SENSE 0x0004 2988c2ecf20Sopenharmony_ci#define GPO_SECONDARY_AC97 0x0008 2998c2ecf20Sopenharmony_ci#define GPI_VOL_DOWN 0x0010 3008c2ecf20Sopenharmony_ci#define GPI_VOL_UP 0x0020 3018c2ecf20Sopenharmony_ci#define GPI_IIS_CLK 0x0040 3028c2ecf20Sopenharmony_ci#define GPI_IIS_LRCLK 0x0080 3038c2ecf20Sopenharmony_ci#define GPI_IIS_DATA 0x0100 3048c2ecf20Sopenharmony_ci#define GPI_DOCKING_STATUS 0x0100 3058c2ecf20Sopenharmony_ci#define GPI_HEADPHONE_SENSE 0x0200 3068c2ecf20Sopenharmony_ci#define GPO_EXT_AMP_SHUTDOWN 0x1000 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci#define GPO_EXT_AMP_M3 1 /* default m3 amp */ 3098c2ecf20Sopenharmony_ci#define GPO_EXT_AMP_ALLEGRO 8 /* default allegro amp */ 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci/* M3 */ 3128c2ecf20Sopenharmony_ci#define GPO_M3_EXT_AMP_SHUTDN 0x0002 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci#define ASSP_INDEX_PORT 0x80 3158c2ecf20Sopenharmony_ci#define ASSP_MEMORY_PORT 0x82 3168c2ecf20Sopenharmony_ci#define ASSP_DATA_PORT 0x84 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci#define MPU401_DATA_PORT 0x98 3198c2ecf20Sopenharmony_ci#define MPU401_STATUS_PORT 0x99 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci#define CLK_MULT_DATA_PORT 0x9C 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci#define ASSP_CONTROL_A 0xA2 3248c2ecf20Sopenharmony_ci#define ASSP_0_WS_ENABLE 0x01 3258c2ecf20Sopenharmony_ci#define ASSP_CTRL_A_RESERVED1 0x02 3268c2ecf20Sopenharmony_ci#define ASSP_CTRL_A_RESERVED2 0x04 3278c2ecf20Sopenharmony_ci#define ASSP_CLK_49MHZ_SELECT 0x08 3288c2ecf20Sopenharmony_ci#define FAST_PLU_ENABLE 0x10 3298c2ecf20Sopenharmony_ci#define ASSP_CTRL_A_RESERVED3 0x20 3308c2ecf20Sopenharmony_ci#define DSP_CLK_36MHZ_SELECT 0x40 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci#define ASSP_CONTROL_B 0xA4 3338c2ecf20Sopenharmony_ci#define RESET_ASSP 0x00 3348c2ecf20Sopenharmony_ci#define RUN_ASSP 0x01 3358c2ecf20Sopenharmony_ci#define ENABLE_ASSP_CLOCK 0x00 3368c2ecf20Sopenharmony_ci#define STOP_ASSP_CLOCK 0x10 3378c2ecf20Sopenharmony_ci#define RESET_TOGGLE 0x40 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci#define ASSP_CONTROL_C 0xA6 3408c2ecf20Sopenharmony_ci#define ASSP_HOST_INT_ENABLE 0x01 3418c2ecf20Sopenharmony_ci#define FM_ADDR_REMAP_DISABLE 0x02 3428c2ecf20Sopenharmony_ci#define HOST_WRITE_PORT_ENABLE 0x08 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci#define ASSP_HOST_INT_STATUS 0xAC 3458c2ecf20Sopenharmony_ci#define DSP2HOST_REQ_PIORECORD 0x01 3468c2ecf20Sopenharmony_ci#define DSP2HOST_REQ_I2SRATE 0x02 3478c2ecf20Sopenharmony_ci#define DSP2HOST_REQ_TIMER 0x04 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci/* 3508c2ecf20Sopenharmony_ci * ASSP control regs 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_ci#define DSP_PORT_TIMER_COUNT 0x06 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci#define DSP_PORT_MEMORY_INDEX 0x80 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci#define DSP_PORT_MEMORY_TYPE 0x82 3578c2ecf20Sopenharmony_ci#define MEMTYPE_INTERNAL_CODE 0x0002 3588c2ecf20Sopenharmony_ci#define MEMTYPE_INTERNAL_DATA 0x0003 3598c2ecf20Sopenharmony_ci#define MEMTYPE_MASK 0x0003 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci#define DSP_PORT_MEMORY_DATA 0x84 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci#define DSP_PORT_CONTROL_REG_A 0xA2 3648c2ecf20Sopenharmony_ci#define DSP_PORT_CONTROL_REG_B 0xA4 3658c2ecf20Sopenharmony_ci#define DSP_PORT_CONTROL_REG_C 0xA6 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci#define REV_A_CODE_MEMORY_BEGIN 0x0000 3688c2ecf20Sopenharmony_ci#define REV_A_CODE_MEMORY_END 0x0FFF 3698c2ecf20Sopenharmony_ci#define REV_A_CODE_MEMORY_UNIT_LENGTH 0x0040 3708c2ecf20Sopenharmony_ci#define REV_A_CODE_MEMORY_LENGTH (REV_A_CODE_MEMORY_END - REV_A_CODE_MEMORY_BEGIN + 1) 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci#define REV_B_CODE_MEMORY_BEGIN 0x0000 3738c2ecf20Sopenharmony_ci#define REV_B_CODE_MEMORY_END 0x0BFF 3748c2ecf20Sopenharmony_ci#define REV_B_CODE_MEMORY_UNIT_LENGTH 0x0040 3758c2ecf20Sopenharmony_ci#define REV_B_CODE_MEMORY_LENGTH (REV_B_CODE_MEMORY_END - REV_B_CODE_MEMORY_BEGIN + 1) 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci#define REV_A_DATA_MEMORY_BEGIN 0x1000 3788c2ecf20Sopenharmony_ci#define REV_A_DATA_MEMORY_END 0x2FFF 3798c2ecf20Sopenharmony_ci#define REV_A_DATA_MEMORY_UNIT_LENGTH 0x0080 3808c2ecf20Sopenharmony_ci#define REV_A_DATA_MEMORY_LENGTH (REV_A_DATA_MEMORY_END - REV_A_DATA_MEMORY_BEGIN + 1) 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci#define REV_B_DATA_MEMORY_BEGIN 0x1000 3838c2ecf20Sopenharmony_ci#define REV_B_DATA_MEMORY_END 0x2BFF 3848c2ecf20Sopenharmony_ci#define REV_B_DATA_MEMORY_UNIT_LENGTH 0x0080 3858c2ecf20Sopenharmony_ci#define REV_B_DATA_MEMORY_LENGTH (REV_B_DATA_MEMORY_END - REV_B_DATA_MEMORY_BEGIN + 1) 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci#define NUM_UNITS_KERNEL_CODE 16 3898c2ecf20Sopenharmony_ci#define NUM_UNITS_KERNEL_DATA 2 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci#define NUM_UNITS_KERNEL_CODE_WITH_HSP 16 3928c2ecf20Sopenharmony_ci#define NUM_UNITS_KERNEL_DATA_WITH_HSP 5 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci/* 3958c2ecf20Sopenharmony_ci * Kernel data layout 3968c2ecf20Sopenharmony_ci */ 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci#define DP_SHIFT_COUNT 7 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci#define KDATA_BASE_ADDR 0x1000 4018c2ecf20Sopenharmony_ci#define KDATA_BASE_ADDR2 0x1080 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci#define KDATA_TASK0 (KDATA_BASE_ADDR + 0x0000) 4048c2ecf20Sopenharmony_ci#define KDATA_TASK1 (KDATA_BASE_ADDR + 0x0001) 4058c2ecf20Sopenharmony_ci#define KDATA_TASK2 (KDATA_BASE_ADDR + 0x0002) 4068c2ecf20Sopenharmony_ci#define KDATA_TASK3 (KDATA_BASE_ADDR + 0x0003) 4078c2ecf20Sopenharmony_ci#define KDATA_TASK4 (KDATA_BASE_ADDR + 0x0004) 4088c2ecf20Sopenharmony_ci#define KDATA_TASK5 (KDATA_BASE_ADDR + 0x0005) 4098c2ecf20Sopenharmony_ci#define KDATA_TASK6 (KDATA_BASE_ADDR + 0x0006) 4108c2ecf20Sopenharmony_ci#define KDATA_TASK7 (KDATA_BASE_ADDR + 0x0007) 4118c2ecf20Sopenharmony_ci#define KDATA_TASK_ENDMARK (KDATA_BASE_ADDR + 0x0008) 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci#define KDATA_CURRENT_TASK (KDATA_BASE_ADDR + 0x0009) 4148c2ecf20Sopenharmony_ci#define KDATA_TASK_SWITCH (KDATA_BASE_ADDR + 0x000A) 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci#define KDATA_INSTANCE0_POS3D (KDATA_BASE_ADDR + 0x000B) 4178c2ecf20Sopenharmony_ci#define KDATA_INSTANCE1_POS3D (KDATA_BASE_ADDR + 0x000C) 4188c2ecf20Sopenharmony_ci#define KDATA_INSTANCE2_POS3D (KDATA_BASE_ADDR + 0x000D) 4198c2ecf20Sopenharmony_ci#define KDATA_INSTANCE3_POS3D (KDATA_BASE_ADDR + 0x000E) 4208c2ecf20Sopenharmony_ci#define KDATA_INSTANCE4_POS3D (KDATA_BASE_ADDR + 0x000F) 4218c2ecf20Sopenharmony_ci#define KDATA_INSTANCE5_POS3D (KDATA_BASE_ADDR + 0x0010) 4228c2ecf20Sopenharmony_ci#define KDATA_INSTANCE6_POS3D (KDATA_BASE_ADDR + 0x0011) 4238c2ecf20Sopenharmony_ci#define KDATA_INSTANCE7_POS3D (KDATA_BASE_ADDR + 0x0012) 4248c2ecf20Sopenharmony_ci#define KDATA_INSTANCE8_POS3D (KDATA_BASE_ADDR + 0x0013) 4258c2ecf20Sopenharmony_ci#define KDATA_INSTANCE_POS3D_ENDMARK (KDATA_BASE_ADDR + 0x0014) 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci#define KDATA_INSTANCE0_SPKVIRT (KDATA_BASE_ADDR + 0x0015) 4288c2ecf20Sopenharmony_ci#define KDATA_INSTANCE_SPKVIRT_ENDMARK (KDATA_BASE_ADDR + 0x0016) 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci#define KDATA_INSTANCE0_SPDIF (KDATA_BASE_ADDR + 0x0017) 4318c2ecf20Sopenharmony_ci#define KDATA_INSTANCE_SPDIF_ENDMARK (KDATA_BASE_ADDR + 0x0018) 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci#define KDATA_INSTANCE0_MODEM (KDATA_BASE_ADDR + 0x0019) 4348c2ecf20Sopenharmony_ci#define KDATA_INSTANCE_MODEM_ENDMARK (KDATA_BASE_ADDR + 0x001A) 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci#define KDATA_INSTANCE0_SRC (KDATA_BASE_ADDR + 0x001B) 4378c2ecf20Sopenharmony_ci#define KDATA_INSTANCE1_SRC (KDATA_BASE_ADDR + 0x001C) 4388c2ecf20Sopenharmony_ci#define KDATA_INSTANCE_SRC_ENDMARK (KDATA_BASE_ADDR + 0x001D) 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci#define KDATA_INSTANCE0_MINISRC (KDATA_BASE_ADDR + 0x001E) 4418c2ecf20Sopenharmony_ci#define KDATA_INSTANCE1_MINISRC (KDATA_BASE_ADDR + 0x001F) 4428c2ecf20Sopenharmony_ci#define KDATA_INSTANCE2_MINISRC (KDATA_BASE_ADDR + 0x0020) 4438c2ecf20Sopenharmony_ci#define KDATA_INSTANCE3_MINISRC (KDATA_BASE_ADDR + 0x0021) 4448c2ecf20Sopenharmony_ci#define KDATA_INSTANCE_MINISRC_ENDMARK (KDATA_BASE_ADDR + 0x0022) 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci#define KDATA_INSTANCE0_CPYTHRU (KDATA_BASE_ADDR + 0x0023) 4478c2ecf20Sopenharmony_ci#define KDATA_INSTANCE1_CPYTHRU (KDATA_BASE_ADDR + 0x0024) 4488c2ecf20Sopenharmony_ci#define KDATA_INSTANCE_CPYTHRU_ENDMARK (KDATA_BASE_ADDR + 0x0025) 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci#define KDATA_CURRENT_DMA (KDATA_BASE_ADDR + 0x0026) 4518c2ecf20Sopenharmony_ci#define KDATA_DMA_SWITCH (KDATA_BASE_ADDR + 0x0027) 4528c2ecf20Sopenharmony_ci#define KDATA_DMA_ACTIVE (KDATA_BASE_ADDR + 0x0028) 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci#define KDATA_DMA_XFER0 (KDATA_BASE_ADDR + 0x0029) 4558c2ecf20Sopenharmony_ci#define KDATA_DMA_XFER1 (KDATA_BASE_ADDR + 0x002A) 4568c2ecf20Sopenharmony_ci#define KDATA_DMA_XFER2 (KDATA_BASE_ADDR + 0x002B) 4578c2ecf20Sopenharmony_ci#define KDATA_DMA_XFER3 (KDATA_BASE_ADDR + 0x002C) 4588c2ecf20Sopenharmony_ci#define KDATA_DMA_XFER4 (KDATA_BASE_ADDR + 0x002D) 4598c2ecf20Sopenharmony_ci#define KDATA_DMA_XFER5 (KDATA_BASE_ADDR + 0x002E) 4608c2ecf20Sopenharmony_ci#define KDATA_DMA_XFER6 (KDATA_BASE_ADDR + 0x002F) 4618c2ecf20Sopenharmony_ci#define KDATA_DMA_XFER7 (KDATA_BASE_ADDR + 0x0030) 4628c2ecf20Sopenharmony_ci#define KDATA_DMA_XFER8 (KDATA_BASE_ADDR + 0x0031) 4638c2ecf20Sopenharmony_ci#define KDATA_DMA_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0032) 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci#define KDATA_I2S_SAMPLE_COUNT (KDATA_BASE_ADDR + 0x0033) 4668c2ecf20Sopenharmony_ci#define KDATA_I2S_INT_METER (KDATA_BASE_ADDR + 0x0034) 4678c2ecf20Sopenharmony_ci#define KDATA_I2S_ACTIVE (KDATA_BASE_ADDR + 0x0035) 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci#define KDATA_TIMER_COUNT_RELOAD (KDATA_BASE_ADDR + 0x0036) 4708c2ecf20Sopenharmony_ci#define KDATA_TIMER_COUNT_CURRENT (KDATA_BASE_ADDR + 0x0037) 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci#define KDATA_HALT_SYNCH_CLIENT (KDATA_BASE_ADDR + 0x0038) 4738c2ecf20Sopenharmony_ci#define KDATA_HALT_SYNCH_DMA (KDATA_BASE_ADDR + 0x0039) 4748c2ecf20Sopenharmony_ci#define KDATA_HALT_ACKNOWLEDGE (KDATA_BASE_ADDR + 0x003A) 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci#define KDATA_ADC1_XFER0 (KDATA_BASE_ADDR + 0x003B) 4778c2ecf20Sopenharmony_ci#define KDATA_ADC1_XFER_ENDMARK (KDATA_BASE_ADDR + 0x003C) 4788c2ecf20Sopenharmony_ci#define KDATA_ADC1_LEFT_VOLUME (KDATA_BASE_ADDR + 0x003D) 4798c2ecf20Sopenharmony_ci#define KDATA_ADC1_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x003E) 4808c2ecf20Sopenharmony_ci#define KDATA_ADC1_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x003F) 4818c2ecf20Sopenharmony_ci#define KDATA_ADC1_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x0040) 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci#define KDATA_ADC2_XFER0 (KDATA_BASE_ADDR + 0x0041) 4848c2ecf20Sopenharmony_ci#define KDATA_ADC2_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0042) 4858c2ecf20Sopenharmony_ci#define KDATA_ADC2_LEFT_VOLUME (KDATA_BASE_ADDR + 0x0043) 4868c2ecf20Sopenharmony_ci#define KDATA_ADC2_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x0044) 4878c2ecf20Sopenharmony_ci#define KDATA_ADC2_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x0045) 4888c2ecf20Sopenharmony_ci#define KDATA_ADC2_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x0046) 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci#define KDATA_CD_XFER0 (KDATA_BASE_ADDR + 0x0047) 4918c2ecf20Sopenharmony_ci#define KDATA_CD_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0048) 4928c2ecf20Sopenharmony_ci#define KDATA_CD_LEFT_VOLUME (KDATA_BASE_ADDR + 0x0049) 4938c2ecf20Sopenharmony_ci#define KDATA_CD_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x004A) 4948c2ecf20Sopenharmony_ci#define KDATA_CD_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x004B) 4958c2ecf20Sopenharmony_ci#define KDATA_CD_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x004C) 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci#define KDATA_MIC_XFER0 (KDATA_BASE_ADDR + 0x004D) 4988c2ecf20Sopenharmony_ci#define KDATA_MIC_XFER_ENDMARK (KDATA_BASE_ADDR + 0x004E) 4998c2ecf20Sopenharmony_ci#define KDATA_MIC_VOLUME (KDATA_BASE_ADDR + 0x004F) 5008c2ecf20Sopenharmony_ci#define KDATA_MIC_SUR_VOL (KDATA_BASE_ADDR + 0x0050) 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci#define KDATA_I2S_XFER0 (KDATA_BASE_ADDR + 0x0051) 5038c2ecf20Sopenharmony_ci#define KDATA_I2S_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0052) 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci#define KDATA_CHI_XFER0 (KDATA_BASE_ADDR + 0x0053) 5068c2ecf20Sopenharmony_ci#define KDATA_CHI_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0054) 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci#define KDATA_SPDIF_XFER (KDATA_BASE_ADDR + 0x0055) 5098c2ecf20Sopenharmony_ci#define KDATA_SPDIF_CURRENT_FRAME (KDATA_BASE_ADDR + 0x0056) 5108c2ecf20Sopenharmony_ci#define KDATA_SPDIF_FRAME0 (KDATA_BASE_ADDR + 0x0057) 5118c2ecf20Sopenharmony_ci#define KDATA_SPDIF_FRAME1 (KDATA_BASE_ADDR + 0x0058) 5128c2ecf20Sopenharmony_ci#define KDATA_SPDIF_FRAME2 (KDATA_BASE_ADDR + 0x0059) 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci#define KDATA_SPDIF_REQUEST (KDATA_BASE_ADDR + 0x005A) 5158c2ecf20Sopenharmony_ci#define KDATA_SPDIF_TEMP (KDATA_BASE_ADDR + 0x005B) 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci#define KDATA_SPDIFIN_XFER0 (KDATA_BASE_ADDR + 0x005C) 5188c2ecf20Sopenharmony_ci#define KDATA_SPDIFIN_XFER_ENDMARK (KDATA_BASE_ADDR + 0x005D) 5198c2ecf20Sopenharmony_ci#define KDATA_SPDIFIN_INT_METER (KDATA_BASE_ADDR + 0x005E) 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci#define KDATA_DSP_RESET_COUNT (KDATA_BASE_ADDR + 0x005F) 5228c2ecf20Sopenharmony_ci#define KDATA_DEBUG_OUTPUT (KDATA_BASE_ADDR + 0x0060) 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci#define KDATA_KERNEL_ISR_LIST (KDATA_BASE_ADDR + 0x0061) 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci#define KDATA_KERNEL_ISR_CBSR1 (KDATA_BASE_ADDR + 0x0062) 5278c2ecf20Sopenharmony_ci#define KDATA_KERNEL_ISR_CBER1 (KDATA_BASE_ADDR + 0x0063) 5288c2ecf20Sopenharmony_ci#define KDATA_KERNEL_ISR_CBCR (KDATA_BASE_ADDR + 0x0064) 5298c2ecf20Sopenharmony_ci#define KDATA_KERNEL_ISR_AR0 (KDATA_BASE_ADDR + 0x0065) 5308c2ecf20Sopenharmony_ci#define KDATA_KERNEL_ISR_AR1 (KDATA_BASE_ADDR + 0x0066) 5318c2ecf20Sopenharmony_ci#define KDATA_KERNEL_ISR_AR2 (KDATA_BASE_ADDR + 0x0067) 5328c2ecf20Sopenharmony_ci#define KDATA_KERNEL_ISR_AR3 (KDATA_BASE_ADDR + 0x0068) 5338c2ecf20Sopenharmony_ci#define KDATA_KERNEL_ISR_AR4 (KDATA_BASE_ADDR + 0x0069) 5348c2ecf20Sopenharmony_ci#define KDATA_KERNEL_ISR_AR5 (KDATA_BASE_ADDR + 0x006A) 5358c2ecf20Sopenharmony_ci#define KDATA_KERNEL_ISR_BRCR (KDATA_BASE_ADDR + 0x006B) 5368c2ecf20Sopenharmony_ci#define KDATA_KERNEL_ISR_PASR (KDATA_BASE_ADDR + 0x006C) 5378c2ecf20Sopenharmony_ci#define KDATA_KERNEL_ISR_PAER (KDATA_BASE_ADDR + 0x006D) 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci#define KDATA_CLIENT_SCRATCH0 (KDATA_BASE_ADDR + 0x006E) 5408c2ecf20Sopenharmony_ci#define KDATA_CLIENT_SCRATCH1 (KDATA_BASE_ADDR + 0x006F) 5418c2ecf20Sopenharmony_ci#define KDATA_KERNEL_SCRATCH (KDATA_BASE_ADDR + 0x0070) 5428c2ecf20Sopenharmony_ci#define KDATA_KERNEL_ISR_SCRATCH (KDATA_BASE_ADDR + 0x0071) 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci#define KDATA_OUEUE_LEFT (KDATA_BASE_ADDR + 0x0072) 5458c2ecf20Sopenharmony_ci#define KDATA_QUEUE_RIGHT (KDATA_BASE_ADDR + 0x0073) 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci#define KDATA_ADC1_REQUEST (KDATA_BASE_ADDR + 0x0074) 5488c2ecf20Sopenharmony_ci#define KDATA_ADC2_REQUEST (KDATA_BASE_ADDR + 0x0075) 5498c2ecf20Sopenharmony_ci#define KDATA_CD_REQUEST (KDATA_BASE_ADDR + 0x0076) 5508c2ecf20Sopenharmony_ci#define KDATA_MIC_REQUEST (KDATA_BASE_ADDR + 0x0077) 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci#define KDATA_ADC1_MIXER_REQUEST (KDATA_BASE_ADDR + 0x0078) 5538c2ecf20Sopenharmony_ci#define KDATA_ADC2_MIXER_REQUEST (KDATA_BASE_ADDR + 0x0079) 5548c2ecf20Sopenharmony_ci#define KDATA_CD_MIXER_REQUEST (KDATA_BASE_ADDR + 0x007A) 5558c2ecf20Sopenharmony_ci#define KDATA_MIC_MIXER_REQUEST (KDATA_BASE_ADDR + 0x007B) 5568c2ecf20Sopenharmony_ci#define KDATA_MIC_SYNC_COUNTER (KDATA_BASE_ADDR + 0x007C) 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci/* 5598c2ecf20Sopenharmony_ci * second 'segment' (?) reserved for mixer 5608c2ecf20Sopenharmony_ci * buffers.. 5618c2ecf20Sopenharmony_ci */ 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci#define KDATA_MIXER_WORD0 (KDATA_BASE_ADDR2 + 0x0000) 5648c2ecf20Sopenharmony_ci#define KDATA_MIXER_WORD1 (KDATA_BASE_ADDR2 + 0x0001) 5658c2ecf20Sopenharmony_ci#define KDATA_MIXER_WORD2 (KDATA_BASE_ADDR2 + 0x0002) 5668c2ecf20Sopenharmony_ci#define KDATA_MIXER_WORD3 (KDATA_BASE_ADDR2 + 0x0003) 5678c2ecf20Sopenharmony_ci#define KDATA_MIXER_WORD4 (KDATA_BASE_ADDR2 + 0x0004) 5688c2ecf20Sopenharmony_ci#define KDATA_MIXER_WORD5 (KDATA_BASE_ADDR2 + 0x0005) 5698c2ecf20Sopenharmony_ci#define KDATA_MIXER_WORD6 (KDATA_BASE_ADDR2 + 0x0006) 5708c2ecf20Sopenharmony_ci#define KDATA_MIXER_WORD7 (KDATA_BASE_ADDR2 + 0x0007) 5718c2ecf20Sopenharmony_ci#define KDATA_MIXER_WORD8 (KDATA_BASE_ADDR2 + 0x0008) 5728c2ecf20Sopenharmony_ci#define KDATA_MIXER_WORD9 (KDATA_BASE_ADDR2 + 0x0009) 5738c2ecf20Sopenharmony_ci#define KDATA_MIXER_WORDA (KDATA_BASE_ADDR2 + 0x000A) 5748c2ecf20Sopenharmony_ci#define KDATA_MIXER_WORDB (KDATA_BASE_ADDR2 + 0x000B) 5758c2ecf20Sopenharmony_ci#define KDATA_MIXER_WORDC (KDATA_BASE_ADDR2 + 0x000C) 5768c2ecf20Sopenharmony_ci#define KDATA_MIXER_WORDD (KDATA_BASE_ADDR2 + 0x000D) 5778c2ecf20Sopenharmony_ci#define KDATA_MIXER_WORDE (KDATA_BASE_ADDR2 + 0x000E) 5788c2ecf20Sopenharmony_ci#define KDATA_MIXER_WORDF (KDATA_BASE_ADDR2 + 0x000F) 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci#define KDATA_MIXER_XFER0 (KDATA_BASE_ADDR2 + 0x0010) 5818c2ecf20Sopenharmony_ci#define KDATA_MIXER_XFER1 (KDATA_BASE_ADDR2 + 0x0011) 5828c2ecf20Sopenharmony_ci#define KDATA_MIXER_XFER2 (KDATA_BASE_ADDR2 + 0x0012) 5838c2ecf20Sopenharmony_ci#define KDATA_MIXER_XFER3 (KDATA_BASE_ADDR2 + 0x0013) 5848c2ecf20Sopenharmony_ci#define KDATA_MIXER_XFER4 (KDATA_BASE_ADDR2 + 0x0014) 5858c2ecf20Sopenharmony_ci#define KDATA_MIXER_XFER5 (KDATA_BASE_ADDR2 + 0x0015) 5868c2ecf20Sopenharmony_ci#define KDATA_MIXER_XFER6 (KDATA_BASE_ADDR2 + 0x0016) 5878c2ecf20Sopenharmony_ci#define KDATA_MIXER_XFER7 (KDATA_BASE_ADDR2 + 0x0017) 5888c2ecf20Sopenharmony_ci#define KDATA_MIXER_XFER8 (KDATA_BASE_ADDR2 + 0x0018) 5898c2ecf20Sopenharmony_ci#define KDATA_MIXER_XFER9 (KDATA_BASE_ADDR2 + 0x0019) 5908c2ecf20Sopenharmony_ci#define KDATA_MIXER_XFER_ENDMARK (KDATA_BASE_ADDR2 + 0x001A) 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci#define KDATA_MIXER_TASK_NUMBER (KDATA_BASE_ADDR2 + 0x001B) 5938c2ecf20Sopenharmony_ci#define KDATA_CURRENT_MIXER (KDATA_BASE_ADDR2 + 0x001C) 5948c2ecf20Sopenharmony_ci#define KDATA_MIXER_ACTIVE (KDATA_BASE_ADDR2 + 0x001D) 5958c2ecf20Sopenharmony_ci#define KDATA_MIXER_BANK_STATUS (KDATA_BASE_ADDR2 + 0x001E) 5968c2ecf20Sopenharmony_ci#define KDATA_DAC_LEFT_VOLUME (KDATA_BASE_ADDR2 + 0x001F) 5978c2ecf20Sopenharmony_ci#define KDATA_DAC_RIGHT_VOLUME (KDATA_BASE_ADDR2 + 0x0020) 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci#define MAX_INSTANCE_MINISRC (KDATA_INSTANCE_MINISRC_ENDMARK - KDATA_INSTANCE0_MINISRC) 6008c2ecf20Sopenharmony_ci#define MAX_VIRTUAL_DMA_CHANNELS (KDATA_DMA_XFER_ENDMARK - KDATA_DMA_XFER0) 6018c2ecf20Sopenharmony_ci#define MAX_VIRTUAL_MIXER_CHANNELS (KDATA_MIXER_XFER_ENDMARK - KDATA_MIXER_XFER0) 6028c2ecf20Sopenharmony_ci#define MAX_VIRTUAL_ADC1_CHANNELS (KDATA_ADC1_XFER_ENDMARK - KDATA_ADC1_XFER0) 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci/* 6058c2ecf20Sopenharmony_ci * client data area offsets 6068c2ecf20Sopenharmony_ci */ 6078c2ecf20Sopenharmony_ci#define CDATA_INSTANCE_READY 0x00 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci#define CDATA_HOST_SRC_ADDRL 0x01 6108c2ecf20Sopenharmony_ci#define CDATA_HOST_SRC_ADDRH 0x02 6118c2ecf20Sopenharmony_ci#define CDATA_HOST_SRC_END_PLUS_1L 0x03 6128c2ecf20Sopenharmony_ci#define CDATA_HOST_SRC_END_PLUS_1H 0x04 6138c2ecf20Sopenharmony_ci#define CDATA_HOST_SRC_CURRENTL 0x05 6148c2ecf20Sopenharmony_ci#define CDATA_HOST_SRC_CURRENTH 0x06 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci#define CDATA_IN_BUF_CONNECT 0x07 6178c2ecf20Sopenharmony_ci#define CDATA_OUT_BUF_CONNECT 0x08 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci#define CDATA_IN_BUF_BEGIN 0x09 6208c2ecf20Sopenharmony_ci#define CDATA_IN_BUF_END_PLUS_1 0x0A 6218c2ecf20Sopenharmony_ci#define CDATA_IN_BUF_HEAD 0x0B 6228c2ecf20Sopenharmony_ci#define CDATA_IN_BUF_TAIL 0x0C 6238c2ecf20Sopenharmony_ci#define CDATA_OUT_BUF_BEGIN 0x0D 6248c2ecf20Sopenharmony_ci#define CDATA_OUT_BUF_END_PLUS_1 0x0E 6258c2ecf20Sopenharmony_ci#define CDATA_OUT_BUF_HEAD 0x0F 6268c2ecf20Sopenharmony_ci#define CDATA_OUT_BUF_TAIL 0x10 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci#define CDATA_DMA_CONTROL 0x11 6298c2ecf20Sopenharmony_ci#define CDATA_RESERVED 0x12 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci#define CDATA_FREQUENCY 0x13 6328c2ecf20Sopenharmony_ci#define CDATA_LEFT_VOLUME 0x14 6338c2ecf20Sopenharmony_ci#define CDATA_RIGHT_VOLUME 0x15 6348c2ecf20Sopenharmony_ci#define CDATA_LEFT_SUR_VOL 0x16 6358c2ecf20Sopenharmony_ci#define CDATA_RIGHT_SUR_VOL 0x17 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci#define CDATA_HEADER_LEN 0x18 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci#define SRC3_DIRECTION_OFFSET CDATA_HEADER_LEN 6408c2ecf20Sopenharmony_ci#define SRC3_MODE_OFFSET (CDATA_HEADER_LEN + 1) 6418c2ecf20Sopenharmony_ci#define SRC3_WORD_LENGTH_OFFSET (CDATA_HEADER_LEN + 2) 6428c2ecf20Sopenharmony_ci#define SRC3_PARAMETER_OFFSET (CDATA_HEADER_LEN + 3) 6438c2ecf20Sopenharmony_ci#define SRC3_COEFF_ADDR_OFFSET (CDATA_HEADER_LEN + 8) 6448c2ecf20Sopenharmony_ci#define SRC3_FILTAP_ADDR_OFFSET (CDATA_HEADER_LEN + 10) 6458c2ecf20Sopenharmony_ci#define SRC3_TEMP_INBUF_ADDR_OFFSET (CDATA_HEADER_LEN + 16) 6468c2ecf20Sopenharmony_ci#define SRC3_TEMP_OUTBUF_ADDR_OFFSET (CDATA_HEADER_LEN + 17) 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci#define MINISRC_IN_BUFFER_SIZE ( 0x50 * 2 ) 6498c2ecf20Sopenharmony_ci#define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2) 6508c2ecf20Sopenharmony_ci#define MINISRC_TMP_BUFFER_SIZE ( 112 + ( MINISRC_BIQUAD_STAGE * 3 + 4 ) * 2 * 2 ) 6518c2ecf20Sopenharmony_ci#define MINISRC_BIQUAD_STAGE 2 6528c2ecf20Sopenharmony_ci#define MINISRC_COEF_LOC 0x175 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci#define DMACONTROL_BLOCK_MASK 0x000F 6558c2ecf20Sopenharmony_ci#define DMAC_BLOCK0_SELECTOR 0x0000 6568c2ecf20Sopenharmony_ci#define DMAC_BLOCK1_SELECTOR 0x0001 6578c2ecf20Sopenharmony_ci#define DMAC_BLOCK2_SELECTOR 0x0002 6588c2ecf20Sopenharmony_ci#define DMAC_BLOCK3_SELECTOR 0x0003 6598c2ecf20Sopenharmony_ci#define DMAC_BLOCK4_SELECTOR 0x0004 6608c2ecf20Sopenharmony_ci#define DMAC_BLOCK5_SELECTOR 0x0005 6618c2ecf20Sopenharmony_ci#define DMAC_BLOCK6_SELECTOR 0x0006 6628c2ecf20Sopenharmony_ci#define DMAC_BLOCK7_SELECTOR 0x0007 6638c2ecf20Sopenharmony_ci#define DMAC_BLOCK8_SELECTOR 0x0008 6648c2ecf20Sopenharmony_ci#define DMAC_BLOCK9_SELECTOR 0x0009 6658c2ecf20Sopenharmony_ci#define DMAC_BLOCKA_SELECTOR 0x000A 6668c2ecf20Sopenharmony_ci#define DMAC_BLOCKB_SELECTOR 0x000B 6678c2ecf20Sopenharmony_ci#define DMAC_BLOCKC_SELECTOR 0x000C 6688c2ecf20Sopenharmony_ci#define DMAC_BLOCKD_SELECTOR 0x000D 6698c2ecf20Sopenharmony_ci#define DMAC_BLOCKE_SELECTOR 0x000E 6708c2ecf20Sopenharmony_ci#define DMAC_BLOCKF_SELECTOR 0x000F 6718c2ecf20Sopenharmony_ci#define DMACONTROL_PAGE_MASK 0x00F0 6728c2ecf20Sopenharmony_ci#define DMAC_PAGE0_SELECTOR 0x0030 6738c2ecf20Sopenharmony_ci#define DMAC_PAGE1_SELECTOR 0x0020 6748c2ecf20Sopenharmony_ci#define DMAC_PAGE2_SELECTOR 0x0010 6758c2ecf20Sopenharmony_ci#define DMAC_PAGE3_SELECTOR 0x0000 6768c2ecf20Sopenharmony_ci#define DMACONTROL_AUTOREPEAT 0x1000 6778c2ecf20Sopenharmony_ci#define DMACONTROL_STOPPED 0x2000 6788c2ecf20Sopenharmony_ci#define DMACONTROL_DIRECTION 0x0100 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci/* 6818c2ecf20Sopenharmony_ci * an arbitrary volume we set the internal 6828c2ecf20Sopenharmony_ci * volume settings to so that the ac97 volume 6838c2ecf20Sopenharmony_ci * range is a little less insane. 0x7fff is 6848c2ecf20Sopenharmony_ci * max. 6858c2ecf20Sopenharmony_ci */ 6868c2ecf20Sopenharmony_ci#define ARB_VOLUME ( 0x6800 ) 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci/* 6898c2ecf20Sopenharmony_ci */ 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistruct m3_list { 6928c2ecf20Sopenharmony_ci int curlen; 6938c2ecf20Sopenharmony_ci int mem_addr; 6948c2ecf20Sopenharmony_ci int max; 6958c2ecf20Sopenharmony_ci}; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_cistruct m3_dma { 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci int number; 7008c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci struct assp_instance { 7038c2ecf20Sopenharmony_ci unsigned short code, data; 7048c2ecf20Sopenharmony_ci } inst; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci int running; 7078c2ecf20Sopenharmony_ci int opened; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci unsigned long buffer_addr; 7108c2ecf20Sopenharmony_ci int dma_size; 7118c2ecf20Sopenharmony_ci int period_size; 7128c2ecf20Sopenharmony_ci unsigned int hwptr; 7138c2ecf20Sopenharmony_ci int count; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci int index[3]; 7168c2ecf20Sopenharmony_ci struct m3_list *index_list[3]; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci int in_lists; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci struct list_head list; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci}; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_cistruct snd_m3 { 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci struct snd_card *card; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci unsigned long iobase; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci int irq; 7318c2ecf20Sopenharmony_ci unsigned int allegro_flag : 1; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci struct snd_ac97 *ac97; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci struct snd_pcm *pcm; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci struct pci_dev *pci; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci int dacs_active; 7408c2ecf20Sopenharmony_ci int timer_users; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci struct m3_list msrc_list; 7438c2ecf20Sopenharmony_ci struct m3_list mixer_list; 7448c2ecf20Sopenharmony_ci struct m3_list adc1_list; 7458c2ecf20Sopenharmony_ci struct m3_list dma_list; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci /* for storing reset state..*/ 7488c2ecf20Sopenharmony_ci u8 reset_state; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci int external_amp; 7518c2ecf20Sopenharmony_ci int amp_gpio; /* gpio pin # for external amp, -1 = default */ 7528c2ecf20Sopenharmony_ci unsigned int hv_config; /* hardware-volume config bits */ 7538c2ecf20Sopenharmony_ci unsigned irda_workaround :1; /* avoid to touch 0x10 on GPIO_DIRECTION 7548c2ecf20Sopenharmony_ci (e.g. for IrDA on Dell Inspirons) */ 7558c2ecf20Sopenharmony_ci unsigned is_omnibook :1; /* Do HP OmniBook GPIO magic? */ 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci /* midi */ 7588c2ecf20Sopenharmony_ci struct snd_rawmidi *rmidi; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci /* pcm streams */ 7618c2ecf20Sopenharmony_ci int num_substreams; 7628c2ecf20Sopenharmony_ci struct m3_dma *substreams; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci spinlock_t reg_lock; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_MAESTRO3_INPUT 7678c2ecf20Sopenharmony_ci struct input_dev *input_dev; 7688c2ecf20Sopenharmony_ci char phys[64]; /* physical device path */ 7698c2ecf20Sopenharmony_ci#else 7708c2ecf20Sopenharmony_ci struct snd_kcontrol *master_switch; 7718c2ecf20Sopenharmony_ci struct snd_kcontrol *master_volume; 7728c2ecf20Sopenharmony_ci#endif 7738c2ecf20Sopenharmony_ci struct work_struct hwvol_work; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci unsigned int in_suspend; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 7788c2ecf20Sopenharmony_ci u16 *suspend_mem; 7798c2ecf20Sopenharmony_ci#endif 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci const struct firmware *assp_kernel_image; 7828c2ecf20Sopenharmony_ci const struct firmware *assp_minisrc_image; 7838c2ecf20Sopenharmony_ci}; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci/* 7868c2ecf20Sopenharmony_ci * pci ids 7878c2ecf20Sopenharmony_ci */ 7888c2ecf20Sopenharmony_cistatic const struct pci_device_id snd_m3_ids[] = { 7898c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO_1, PCI_ANY_ID, PCI_ANY_ID, 7908c2ecf20Sopenharmony_ci PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, 7918c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO, PCI_ANY_ID, PCI_ANY_ID, 7928c2ecf20Sopenharmony_ci PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, 7938c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_CANYON3D_2LE, PCI_ANY_ID, PCI_ANY_ID, 7948c2ecf20Sopenharmony_ci PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, 7958c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_CANYON3D_2, PCI_ANY_ID, PCI_ANY_ID, 7968c2ecf20Sopenharmony_ci PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, 7978c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3, PCI_ANY_ID, PCI_ANY_ID, 7988c2ecf20Sopenharmony_ci PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, 7998c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3_1, PCI_ANY_ID, PCI_ANY_ID, 8008c2ecf20Sopenharmony_ci PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, 8018c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3_HW, PCI_ANY_ID, PCI_ANY_ID, 8028c2ecf20Sopenharmony_ci PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, 8038c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3_2, PCI_ANY_ID, PCI_ANY_ID, 8048c2ecf20Sopenharmony_ci PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, 8058c2ecf20Sopenharmony_ci {0,}, 8068c2ecf20Sopenharmony_ci}; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, snd_m3_ids); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic const struct snd_pci_quirk m3_amp_quirk_list[] = { 8118c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x0E11, 0x0094, "Compaq Evo N600c", 0x0c), 8128c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x10f7, 0x833e, "Panasonic CF-28", 0x0d), 8138c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x10f7, 0x833d, "Panasonic CF-72", 0x0d), 8148c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x1033, 0x80f1, "NEC LM800J/7", 0x03), 8158c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x1509, 0x1740, "LEGEND ZhaoYang 3100CF", 0x03), 8168c2ecf20Sopenharmony_ci { } /* END */ 8178c2ecf20Sopenharmony_ci}; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_cistatic const struct snd_pci_quirk m3_irda_quirk_list[] = { 8208c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x1028, 0x00b0, "Dell Inspiron 4000", 1), 8218c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x1028, 0x00a4, "Dell Inspiron 8000", 1), 8228c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x1028, 0x00e6, "Dell Inspiron 8100", 1), 8238c2ecf20Sopenharmony_ci { } /* END */ 8248c2ecf20Sopenharmony_ci}; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci/* hardware volume quirks */ 8278c2ecf20Sopenharmony_cistatic const struct snd_pci_quirk m3_hv_quirk_list[] = { 8288c2ecf20Sopenharmony_ci /* Allegro chips */ 8298c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x0E11, 0x002E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8308c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x0E11, 0x0094, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8318c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x0E11, 0xB112, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8328c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x0E11, 0xB114, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8338c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x103C, 0x0012, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8348c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x103C, 0x0018, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8358c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x103C, 0x001C, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8368c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x103C, 0x001D, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8378c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x103C, 0x001E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8388c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x107B, 0x3350, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8398c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x10F7, 0x8338, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8408c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x10F7, 0x833C, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8418c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x10F7, 0x833D, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8428c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x10F7, 0x833E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8438c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x10F7, 0x833F, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8448c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x13BD, 0x1018, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8458c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x13BD, 0x1019, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8468c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x13BD, 0x101A, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8478c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x14FF, 0x0F03, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8488c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x14FF, 0x0F04, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8498c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x14FF, 0x0F05, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8508c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x156D, 0xB400, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8518c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x156D, 0xB795, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8528c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x156D, 0xB797, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8538c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x156D, 0xC700, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), 8548c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x1033, 0x80F1, NULL, 8558c2ecf20Sopenharmony_ci HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), 8568c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x103C, 0x001A, NULL, /* HP OmniBook 6100 */ 8578c2ecf20Sopenharmony_ci HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), 8588c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x107B, 0x340A, NULL, 8598c2ecf20Sopenharmony_ci HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), 8608c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x107B, 0x3450, NULL, 8618c2ecf20Sopenharmony_ci HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), 8628c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x109F, 0x3134, NULL, 8638c2ecf20Sopenharmony_ci HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), 8648c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x109F, 0x3161, NULL, 8658c2ecf20Sopenharmony_ci HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), 8668c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x144D, 0x3280, NULL, 8678c2ecf20Sopenharmony_ci HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), 8688c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x144D, 0x3281, NULL, 8698c2ecf20Sopenharmony_ci HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), 8708c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x144D, 0xC002, NULL, 8718c2ecf20Sopenharmony_ci HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), 8728c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x144D, 0xC003, NULL, 8738c2ecf20Sopenharmony_ci HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), 8748c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x1509, 0x1740, NULL, 8758c2ecf20Sopenharmony_ci HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), 8768c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x1610, 0x0010, NULL, 8778c2ecf20Sopenharmony_ci HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), 8788c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x1042, 0x1042, NULL, HV_CTRL_ENABLE), 8798c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x107B, 0x9500, NULL, HV_CTRL_ENABLE), 8808c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x14FF, 0x0F06, NULL, HV_CTRL_ENABLE), 8818c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x1558, 0x8586, NULL, HV_CTRL_ENABLE), 8828c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x161F, 0x2011, NULL, HV_CTRL_ENABLE), 8838c2ecf20Sopenharmony_ci /* Maestro3 chips */ 8848c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x103C, 0x000E, NULL, HV_CTRL_ENABLE), 8858c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x103C, 0x0010, NULL, HV_CTRL_ENABLE), 8868c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x103C, 0x0011, NULL, HV_CTRL_ENABLE), 8878c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x103C, 0x001B, NULL, HV_CTRL_ENABLE), 8888c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x104D, 0x80A6, NULL, HV_CTRL_ENABLE), 8898c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x104D, 0x80AA, NULL, HV_CTRL_ENABLE), 8908c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x107B, 0x5300, NULL, HV_CTRL_ENABLE), 8918c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x110A, 0x1998, NULL, HV_CTRL_ENABLE), 8928c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x13BD, 0x1015, NULL, HV_CTRL_ENABLE), 8938c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x13BD, 0x101C, NULL, HV_CTRL_ENABLE), 8948c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x13BD, 0x1802, NULL, HV_CTRL_ENABLE), 8958c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x1599, 0x0715, NULL, HV_CTRL_ENABLE), 8968c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x5643, 0x5643, NULL, HV_CTRL_ENABLE), 8978c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x144D, 0x3260, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE), 8988c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x144D, 0x3261, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE), 8998c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x144D, 0xC000, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE), 9008c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x144D, 0xC001, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE), 9018c2ecf20Sopenharmony_ci { } /* END */ 9028c2ecf20Sopenharmony_ci}; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci/* HP Omnibook quirks */ 9058c2ecf20Sopenharmony_cistatic const struct snd_pci_quirk m3_omnibook_quirk_list[] = { 9068c2ecf20Sopenharmony_ci SND_PCI_QUIRK_ID(0x103c, 0x0010), /* HP OmniBook 6000 */ 9078c2ecf20Sopenharmony_ci SND_PCI_QUIRK_ID(0x103c, 0x0011), /* HP OmniBook 500 */ 9088c2ecf20Sopenharmony_ci { } /* END */ 9098c2ecf20Sopenharmony_ci}; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci/* 9128c2ecf20Sopenharmony_ci * lowlevel functions 9138c2ecf20Sopenharmony_ci */ 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_cistatic inline void snd_m3_outw(struct snd_m3 *chip, u16 value, unsigned long reg) 9168c2ecf20Sopenharmony_ci{ 9178c2ecf20Sopenharmony_ci outw(value, chip->iobase + reg); 9188c2ecf20Sopenharmony_ci} 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_cistatic inline u16 snd_m3_inw(struct snd_m3 *chip, unsigned long reg) 9218c2ecf20Sopenharmony_ci{ 9228c2ecf20Sopenharmony_ci return inw(chip->iobase + reg); 9238c2ecf20Sopenharmony_ci} 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_cistatic inline void snd_m3_outb(struct snd_m3 *chip, u8 value, unsigned long reg) 9268c2ecf20Sopenharmony_ci{ 9278c2ecf20Sopenharmony_ci outb(value, chip->iobase + reg); 9288c2ecf20Sopenharmony_ci} 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_cistatic inline u8 snd_m3_inb(struct snd_m3 *chip, unsigned long reg) 9318c2ecf20Sopenharmony_ci{ 9328c2ecf20Sopenharmony_ci return inb(chip->iobase + reg); 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci/* 9368c2ecf20Sopenharmony_ci * access 16bit words to the code or data regions of the dsp's memory. 9378c2ecf20Sopenharmony_ci * index addresses 16bit words. 9388c2ecf20Sopenharmony_ci */ 9398c2ecf20Sopenharmony_cistatic u16 snd_m3_assp_read(struct snd_m3 *chip, u16 region, u16 index) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci snd_m3_outw(chip, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE); 9428c2ecf20Sopenharmony_ci snd_m3_outw(chip, index, DSP_PORT_MEMORY_INDEX); 9438c2ecf20Sopenharmony_ci return snd_m3_inw(chip, DSP_PORT_MEMORY_DATA); 9448c2ecf20Sopenharmony_ci} 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_cistatic void snd_m3_assp_write(struct snd_m3 *chip, u16 region, u16 index, u16 data) 9478c2ecf20Sopenharmony_ci{ 9488c2ecf20Sopenharmony_ci snd_m3_outw(chip, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE); 9498c2ecf20Sopenharmony_ci snd_m3_outw(chip, index, DSP_PORT_MEMORY_INDEX); 9508c2ecf20Sopenharmony_ci snd_m3_outw(chip, data, DSP_PORT_MEMORY_DATA); 9518c2ecf20Sopenharmony_ci} 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_cistatic void snd_m3_assp_halt(struct snd_m3 *chip) 9548c2ecf20Sopenharmony_ci{ 9558c2ecf20Sopenharmony_ci chip->reset_state = snd_m3_inb(chip, DSP_PORT_CONTROL_REG_B) & ~REGB_STOP_CLOCK; 9568c2ecf20Sopenharmony_ci msleep(10); 9578c2ecf20Sopenharmony_ci snd_m3_outb(chip, chip->reset_state & ~REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B); 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_cistatic void snd_m3_assp_continue(struct snd_m3 *chip) 9618c2ecf20Sopenharmony_ci{ 9628c2ecf20Sopenharmony_ci snd_m3_outb(chip, chip->reset_state | REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B); 9638c2ecf20Sopenharmony_ci} 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci/* 9678c2ecf20Sopenharmony_ci * This makes me sad. the maestro3 has lists 9688c2ecf20Sopenharmony_ci * internally that must be packed.. 0 terminates, 9698c2ecf20Sopenharmony_ci * apparently, or maybe all unused entries have 9708c2ecf20Sopenharmony_ci * to be 0, the lists have static lengths set 9718c2ecf20Sopenharmony_ci * by the binary code images. 9728c2ecf20Sopenharmony_ci */ 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_cistatic int snd_m3_add_list(struct snd_m3 *chip, struct m3_list *list, u16 val) 9758c2ecf20Sopenharmony_ci{ 9768c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 9778c2ecf20Sopenharmony_ci list->mem_addr + list->curlen, 9788c2ecf20Sopenharmony_ci val); 9798c2ecf20Sopenharmony_ci return list->curlen++; 9808c2ecf20Sopenharmony_ci} 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_cistatic void snd_m3_remove_list(struct snd_m3 *chip, struct m3_list *list, int index) 9838c2ecf20Sopenharmony_ci{ 9848c2ecf20Sopenharmony_ci u16 val; 9858c2ecf20Sopenharmony_ci int lastindex = list->curlen - 1; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci if (index != lastindex) { 9888c2ecf20Sopenharmony_ci val = snd_m3_assp_read(chip, MEMTYPE_INTERNAL_DATA, 9898c2ecf20Sopenharmony_ci list->mem_addr + lastindex); 9908c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 9918c2ecf20Sopenharmony_ci list->mem_addr + index, 9928c2ecf20Sopenharmony_ci val); 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 9968c2ecf20Sopenharmony_ci list->mem_addr + lastindex, 9978c2ecf20Sopenharmony_ci 0); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci list->curlen--; 10008c2ecf20Sopenharmony_ci} 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_cistatic void snd_m3_inc_timer_users(struct snd_m3 *chip) 10038c2ecf20Sopenharmony_ci{ 10048c2ecf20Sopenharmony_ci chip->timer_users++; 10058c2ecf20Sopenharmony_ci if (chip->timer_users != 1) 10068c2ecf20Sopenharmony_ci return; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 10098c2ecf20Sopenharmony_ci KDATA_TIMER_COUNT_RELOAD, 10108c2ecf20Sopenharmony_ci 240); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 10138c2ecf20Sopenharmony_ci KDATA_TIMER_COUNT_CURRENT, 10148c2ecf20Sopenharmony_ci 240); 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci snd_m3_outw(chip, 10178c2ecf20Sopenharmony_ci snd_m3_inw(chip, HOST_INT_CTRL) | CLKRUN_GEN_ENABLE, 10188c2ecf20Sopenharmony_ci HOST_INT_CTRL); 10198c2ecf20Sopenharmony_ci} 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_cistatic void snd_m3_dec_timer_users(struct snd_m3 *chip) 10228c2ecf20Sopenharmony_ci{ 10238c2ecf20Sopenharmony_ci chip->timer_users--; 10248c2ecf20Sopenharmony_ci if (chip->timer_users > 0) 10258c2ecf20Sopenharmony_ci return; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 10288c2ecf20Sopenharmony_ci KDATA_TIMER_COUNT_RELOAD, 10298c2ecf20Sopenharmony_ci 0); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 10328c2ecf20Sopenharmony_ci KDATA_TIMER_COUNT_CURRENT, 10338c2ecf20Sopenharmony_ci 0); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci snd_m3_outw(chip, 10368c2ecf20Sopenharmony_ci snd_m3_inw(chip, HOST_INT_CTRL) & ~CLKRUN_GEN_ENABLE, 10378c2ecf20Sopenharmony_ci HOST_INT_CTRL); 10388c2ecf20Sopenharmony_ci} 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci/* 10418c2ecf20Sopenharmony_ci * start/stop 10428c2ecf20Sopenharmony_ci */ 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci/* spinlock held! */ 10458c2ecf20Sopenharmony_cistatic int snd_m3_pcm_start(struct snd_m3 *chip, struct m3_dma *s, 10468c2ecf20Sopenharmony_ci struct snd_pcm_substream *subs) 10478c2ecf20Sopenharmony_ci{ 10488c2ecf20Sopenharmony_ci if (! s || ! subs) 10498c2ecf20Sopenharmony_ci return -EINVAL; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci snd_m3_inc_timer_users(chip); 10528c2ecf20Sopenharmony_ci switch (subs->stream) { 10538c2ecf20Sopenharmony_ci case SNDRV_PCM_STREAM_PLAYBACK: 10548c2ecf20Sopenharmony_ci chip->dacs_active++; 10558c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 10568c2ecf20Sopenharmony_ci s->inst.data + CDATA_INSTANCE_READY, 1); 10578c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 10588c2ecf20Sopenharmony_ci KDATA_MIXER_TASK_NUMBER, 10598c2ecf20Sopenharmony_ci chip->dacs_active); 10608c2ecf20Sopenharmony_ci break; 10618c2ecf20Sopenharmony_ci case SNDRV_PCM_STREAM_CAPTURE: 10628c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 10638c2ecf20Sopenharmony_ci KDATA_ADC1_REQUEST, 1); 10648c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 10658c2ecf20Sopenharmony_ci s->inst.data + CDATA_INSTANCE_READY, 1); 10668c2ecf20Sopenharmony_ci break; 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci return 0; 10698c2ecf20Sopenharmony_ci} 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci/* spinlock held! */ 10728c2ecf20Sopenharmony_cistatic int snd_m3_pcm_stop(struct snd_m3 *chip, struct m3_dma *s, 10738c2ecf20Sopenharmony_ci struct snd_pcm_substream *subs) 10748c2ecf20Sopenharmony_ci{ 10758c2ecf20Sopenharmony_ci if (! s || ! subs) 10768c2ecf20Sopenharmony_ci return -EINVAL; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 10798c2ecf20Sopenharmony_ci s->inst.data + CDATA_INSTANCE_READY, 0); 10808c2ecf20Sopenharmony_ci snd_m3_dec_timer_users(chip); 10818c2ecf20Sopenharmony_ci switch (subs->stream) { 10828c2ecf20Sopenharmony_ci case SNDRV_PCM_STREAM_PLAYBACK: 10838c2ecf20Sopenharmony_ci chip->dacs_active--; 10848c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 10858c2ecf20Sopenharmony_ci KDATA_MIXER_TASK_NUMBER, 10868c2ecf20Sopenharmony_ci chip->dacs_active); 10878c2ecf20Sopenharmony_ci break; 10888c2ecf20Sopenharmony_ci case SNDRV_PCM_STREAM_CAPTURE: 10898c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 10908c2ecf20Sopenharmony_ci KDATA_ADC1_REQUEST, 0); 10918c2ecf20Sopenharmony_ci break; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci return 0; 10948c2ecf20Sopenharmony_ci} 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_cistatic int 10978c2ecf20Sopenharmony_cisnd_m3_pcm_trigger(struct snd_pcm_substream *subs, int cmd) 10988c2ecf20Sopenharmony_ci{ 10998c2ecf20Sopenharmony_ci struct snd_m3 *chip = snd_pcm_substream_chip(subs); 11008c2ecf20Sopenharmony_ci struct m3_dma *s = subs->runtime->private_data; 11018c2ecf20Sopenharmony_ci int err = -EINVAL; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci if (snd_BUG_ON(!s)) 11048c2ecf20Sopenharmony_ci return -ENXIO; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci spin_lock(&chip->reg_lock); 11078c2ecf20Sopenharmony_ci switch (cmd) { 11088c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 11098c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 11108c2ecf20Sopenharmony_ci if (s->running) 11118c2ecf20Sopenharmony_ci err = -EBUSY; 11128c2ecf20Sopenharmony_ci else { 11138c2ecf20Sopenharmony_ci s->running = 1; 11148c2ecf20Sopenharmony_ci err = snd_m3_pcm_start(chip, s, subs); 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci break; 11178c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 11188c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 11198c2ecf20Sopenharmony_ci if (! s->running) 11208c2ecf20Sopenharmony_ci err = 0; /* should return error? */ 11218c2ecf20Sopenharmony_ci else { 11228c2ecf20Sopenharmony_ci s->running = 0; 11238c2ecf20Sopenharmony_ci err = snd_m3_pcm_stop(chip, s, subs); 11248c2ecf20Sopenharmony_ci } 11258c2ecf20Sopenharmony_ci break; 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci spin_unlock(&chip->reg_lock); 11288c2ecf20Sopenharmony_ci return err; 11298c2ecf20Sopenharmony_ci} 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci/* 11328c2ecf20Sopenharmony_ci * setup 11338c2ecf20Sopenharmony_ci */ 11348c2ecf20Sopenharmony_cistatic void 11358c2ecf20Sopenharmony_cisnd_m3_pcm_setup1(struct snd_m3 *chip, struct m3_dma *s, struct snd_pcm_substream *subs) 11368c2ecf20Sopenharmony_ci{ 11378c2ecf20Sopenharmony_ci int dsp_in_size, dsp_out_size, dsp_in_buffer, dsp_out_buffer; 11388c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = subs->runtime; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci if (subs->stream == SNDRV_PCM_STREAM_PLAYBACK) { 11418c2ecf20Sopenharmony_ci dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x20 * 2); 11428c2ecf20Sopenharmony_ci dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x20 * 2); 11438c2ecf20Sopenharmony_ci } else { 11448c2ecf20Sopenharmony_ci dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x10 * 2); 11458c2ecf20Sopenharmony_ci dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x10 * 2); 11468c2ecf20Sopenharmony_ci } 11478c2ecf20Sopenharmony_ci dsp_in_buffer = s->inst.data + (MINISRC_TMP_BUFFER_SIZE / 2); 11488c2ecf20Sopenharmony_ci dsp_out_buffer = dsp_in_buffer + (dsp_in_size / 2) + 1; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci s->dma_size = frames_to_bytes(runtime, runtime->buffer_size); 11518c2ecf20Sopenharmony_ci s->period_size = frames_to_bytes(runtime, runtime->period_size); 11528c2ecf20Sopenharmony_ci s->hwptr = 0; 11538c2ecf20Sopenharmony_ci s->count = 0; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci#define LO(x) ((x) & 0xffff) 11568c2ecf20Sopenharmony_ci#define HI(x) LO((x) >> 16) 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci /* host dma buffer pointers */ 11598c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 11608c2ecf20Sopenharmony_ci s->inst.data + CDATA_HOST_SRC_ADDRL, 11618c2ecf20Sopenharmony_ci LO(s->buffer_addr)); 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 11648c2ecf20Sopenharmony_ci s->inst.data + CDATA_HOST_SRC_ADDRH, 11658c2ecf20Sopenharmony_ci HI(s->buffer_addr)); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 11688c2ecf20Sopenharmony_ci s->inst.data + CDATA_HOST_SRC_END_PLUS_1L, 11698c2ecf20Sopenharmony_ci LO(s->buffer_addr + s->dma_size)); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 11728c2ecf20Sopenharmony_ci s->inst.data + CDATA_HOST_SRC_END_PLUS_1H, 11738c2ecf20Sopenharmony_ci HI(s->buffer_addr + s->dma_size)); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 11768c2ecf20Sopenharmony_ci s->inst.data + CDATA_HOST_SRC_CURRENTL, 11778c2ecf20Sopenharmony_ci LO(s->buffer_addr)); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 11808c2ecf20Sopenharmony_ci s->inst.data + CDATA_HOST_SRC_CURRENTH, 11818c2ecf20Sopenharmony_ci HI(s->buffer_addr)); 11828c2ecf20Sopenharmony_ci#undef LO 11838c2ecf20Sopenharmony_ci#undef HI 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci /* dsp buffers */ 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 11888c2ecf20Sopenharmony_ci s->inst.data + CDATA_IN_BUF_BEGIN, 11898c2ecf20Sopenharmony_ci dsp_in_buffer); 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 11928c2ecf20Sopenharmony_ci s->inst.data + CDATA_IN_BUF_END_PLUS_1, 11938c2ecf20Sopenharmony_ci dsp_in_buffer + (dsp_in_size / 2)); 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 11968c2ecf20Sopenharmony_ci s->inst.data + CDATA_IN_BUF_HEAD, 11978c2ecf20Sopenharmony_ci dsp_in_buffer); 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 12008c2ecf20Sopenharmony_ci s->inst.data + CDATA_IN_BUF_TAIL, 12018c2ecf20Sopenharmony_ci dsp_in_buffer); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 12048c2ecf20Sopenharmony_ci s->inst.data + CDATA_OUT_BUF_BEGIN, 12058c2ecf20Sopenharmony_ci dsp_out_buffer); 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 12088c2ecf20Sopenharmony_ci s->inst.data + CDATA_OUT_BUF_END_PLUS_1, 12098c2ecf20Sopenharmony_ci dsp_out_buffer + (dsp_out_size / 2)); 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 12128c2ecf20Sopenharmony_ci s->inst.data + CDATA_OUT_BUF_HEAD, 12138c2ecf20Sopenharmony_ci dsp_out_buffer); 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 12168c2ecf20Sopenharmony_ci s->inst.data + CDATA_OUT_BUF_TAIL, 12178c2ecf20Sopenharmony_ci dsp_out_buffer); 12188c2ecf20Sopenharmony_ci} 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_cistatic void snd_m3_pcm_setup2(struct snd_m3 *chip, struct m3_dma *s, 12218c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime) 12228c2ecf20Sopenharmony_ci{ 12238c2ecf20Sopenharmony_ci u32 freq; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci /* 12268c2ecf20Sopenharmony_ci * put us in the lists if we're not already there 12278c2ecf20Sopenharmony_ci */ 12288c2ecf20Sopenharmony_ci if (! s->in_lists) { 12298c2ecf20Sopenharmony_ci s->index[0] = snd_m3_add_list(chip, s->index_list[0], 12308c2ecf20Sopenharmony_ci s->inst.data >> DP_SHIFT_COUNT); 12318c2ecf20Sopenharmony_ci s->index[1] = snd_m3_add_list(chip, s->index_list[1], 12328c2ecf20Sopenharmony_ci s->inst.data >> DP_SHIFT_COUNT); 12338c2ecf20Sopenharmony_ci s->index[2] = snd_m3_add_list(chip, s->index_list[2], 12348c2ecf20Sopenharmony_ci s->inst.data >> DP_SHIFT_COUNT); 12358c2ecf20Sopenharmony_ci s->in_lists = 1; 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci /* write to 'mono' word */ 12398c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 12408c2ecf20Sopenharmony_ci s->inst.data + SRC3_DIRECTION_OFFSET + 1, 12418c2ecf20Sopenharmony_ci runtime->channels == 2 ? 0 : 1); 12428c2ecf20Sopenharmony_ci /* write to '8bit' word */ 12438c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 12448c2ecf20Sopenharmony_ci s->inst.data + SRC3_DIRECTION_OFFSET + 2, 12458c2ecf20Sopenharmony_ci snd_pcm_format_width(runtime->format) == 16 ? 0 : 1); 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci /* set up dac/adc rate */ 12488c2ecf20Sopenharmony_ci freq = ((runtime->rate << 15) + 24000 ) / 48000; 12498c2ecf20Sopenharmony_ci if (freq) 12508c2ecf20Sopenharmony_ci freq--; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 12538c2ecf20Sopenharmony_ci s->inst.data + CDATA_FREQUENCY, 12548c2ecf20Sopenharmony_ci freq); 12558c2ecf20Sopenharmony_ci} 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_cistatic const struct play_vals { 12598c2ecf20Sopenharmony_ci u16 addr, val; 12608c2ecf20Sopenharmony_ci} pv[] = { 12618c2ecf20Sopenharmony_ci {CDATA_LEFT_VOLUME, ARB_VOLUME}, 12628c2ecf20Sopenharmony_ci {CDATA_RIGHT_VOLUME, ARB_VOLUME}, 12638c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET, 0} , 12648c2ecf20Sopenharmony_ci /* +1, +2 are stereo/16 bit */ 12658c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 3, 0x0000}, /* fraction? */ 12668c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */ 12678c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */ 12688c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */ 12698c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */ 12708c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */ 12718c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */ 12728c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 10, 0x8000}, /* round */ 12738c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 11, 0xFF00}, /* higher bute mark */ 12748c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */ 12758c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */ 12768c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */ 12778c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 16, 8}, /* numin */ 12788c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 17, 50*2}, /* numout */ 12798c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 18, MINISRC_BIQUAD_STAGE - 1}, /* numstage */ 12808c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */ 12818c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 21, 0} /* booster */ 12828c2ecf20Sopenharmony_ci}; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci/* the mode passed should be already shifted and masked */ 12868c2ecf20Sopenharmony_cistatic void 12878c2ecf20Sopenharmony_cisnd_m3_playback_setup(struct snd_m3 *chip, struct m3_dma *s, 12888c2ecf20Sopenharmony_ci struct snd_pcm_substream *subs) 12898c2ecf20Sopenharmony_ci{ 12908c2ecf20Sopenharmony_ci unsigned int i; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci /* 12938c2ecf20Sopenharmony_ci * some per client initializers 12948c2ecf20Sopenharmony_ci */ 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 12978c2ecf20Sopenharmony_ci s->inst.data + SRC3_DIRECTION_OFFSET + 12, 12988c2ecf20Sopenharmony_ci s->inst.data + 40 + 8); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 13018c2ecf20Sopenharmony_ci s->inst.data + SRC3_DIRECTION_OFFSET + 19, 13028c2ecf20Sopenharmony_ci s->inst.code + MINISRC_COEF_LOC); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci /* enable or disable low pass filter? */ 13058c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 13068c2ecf20Sopenharmony_ci s->inst.data + SRC3_DIRECTION_OFFSET + 22, 13078c2ecf20Sopenharmony_ci subs->runtime->rate > 45000 ? 0xff : 0); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci /* tell it which way dma is going? */ 13108c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 13118c2ecf20Sopenharmony_ci s->inst.data + CDATA_DMA_CONTROL, 13128c2ecf20Sopenharmony_ci DMACONTROL_AUTOREPEAT + DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR); 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci /* 13158c2ecf20Sopenharmony_ci * set an armload of static initializers 13168c2ecf20Sopenharmony_ci */ 13178c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pv); i++) 13188c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 13198c2ecf20Sopenharmony_ci s->inst.data + pv[i].addr, pv[i].val); 13208c2ecf20Sopenharmony_ci} 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci/* 13238c2ecf20Sopenharmony_ci * Native record driver 13248c2ecf20Sopenharmony_ci */ 13258c2ecf20Sopenharmony_cistatic const struct rec_vals { 13268c2ecf20Sopenharmony_ci u16 addr, val; 13278c2ecf20Sopenharmony_ci} rv[] = { 13288c2ecf20Sopenharmony_ci {CDATA_LEFT_VOLUME, ARB_VOLUME}, 13298c2ecf20Sopenharmony_ci {CDATA_RIGHT_VOLUME, ARB_VOLUME}, 13308c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET, 1} , 13318c2ecf20Sopenharmony_ci /* +1, +2 are stereo/16 bit */ 13328c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 3, 0x0000}, /* fraction? */ 13338c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */ 13348c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */ 13358c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */ 13368c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */ 13378c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */ 13388c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */ 13398c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 10, 0x8000}, /* round */ 13408c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 11, 0xFF00}, /* higher bute mark */ 13418c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */ 13428c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */ 13438c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */ 13448c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 16, 50},/* numin */ 13458c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 17, 8}, /* numout */ 13468c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 18, 0}, /* numstage */ 13478c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 19, 0}, /* coef */ 13488c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */ 13498c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 21, 0}, /* booster */ 13508c2ecf20Sopenharmony_ci {SRC3_DIRECTION_OFFSET + 22, 0xff} /* skip lpf */ 13518c2ecf20Sopenharmony_ci}; 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_cistatic void 13548c2ecf20Sopenharmony_cisnd_m3_capture_setup(struct snd_m3 *chip, struct m3_dma *s, struct snd_pcm_substream *subs) 13558c2ecf20Sopenharmony_ci{ 13568c2ecf20Sopenharmony_ci unsigned int i; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci /* 13598c2ecf20Sopenharmony_ci * some per client initializers 13608c2ecf20Sopenharmony_ci */ 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 13638c2ecf20Sopenharmony_ci s->inst.data + SRC3_DIRECTION_OFFSET + 12, 13648c2ecf20Sopenharmony_ci s->inst.data + 40 + 8); 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci /* tell it which way dma is going? */ 13678c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 13688c2ecf20Sopenharmony_ci s->inst.data + CDATA_DMA_CONTROL, 13698c2ecf20Sopenharmony_ci DMACONTROL_DIRECTION + DMACONTROL_AUTOREPEAT + 13708c2ecf20Sopenharmony_ci DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR); 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci /* 13738c2ecf20Sopenharmony_ci * set an armload of static initializers 13748c2ecf20Sopenharmony_ci */ 13758c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rv); i++) 13768c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 13778c2ecf20Sopenharmony_ci s->inst.data + rv[i].addr, rv[i].val); 13788c2ecf20Sopenharmony_ci} 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_cistatic int snd_m3_pcm_hw_params(struct snd_pcm_substream *substream, 13818c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 13828c2ecf20Sopenharmony_ci{ 13838c2ecf20Sopenharmony_ci struct m3_dma *s = substream->runtime->private_data; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci /* set buffer address */ 13868c2ecf20Sopenharmony_ci s->buffer_addr = substream->runtime->dma_addr; 13878c2ecf20Sopenharmony_ci if (s->buffer_addr & 0x3) { 13888c2ecf20Sopenharmony_ci dev_err(substream->pcm->card->dev, "oh my, not aligned\n"); 13898c2ecf20Sopenharmony_ci s->buffer_addr = s->buffer_addr & ~0x3; 13908c2ecf20Sopenharmony_ci } 13918c2ecf20Sopenharmony_ci return 0; 13928c2ecf20Sopenharmony_ci} 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_cistatic int snd_m3_pcm_hw_free(struct snd_pcm_substream *substream) 13958c2ecf20Sopenharmony_ci{ 13968c2ecf20Sopenharmony_ci struct m3_dma *s; 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci if (substream->runtime->private_data == NULL) 13998c2ecf20Sopenharmony_ci return 0; 14008c2ecf20Sopenharmony_ci s = substream->runtime->private_data; 14018c2ecf20Sopenharmony_ci s->buffer_addr = 0; 14028c2ecf20Sopenharmony_ci return 0; 14038c2ecf20Sopenharmony_ci} 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_cistatic int 14068c2ecf20Sopenharmony_cisnd_m3_pcm_prepare(struct snd_pcm_substream *subs) 14078c2ecf20Sopenharmony_ci{ 14088c2ecf20Sopenharmony_ci struct snd_m3 *chip = snd_pcm_substream_chip(subs); 14098c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = subs->runtime; 14108c2ecf20Sopenharmony_ci struct m3_dma *s = runtime->private_data; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci if (snd_BUG_ON(!s)) 14138c2ecf20Sopenharmony_ci return -ENXIO; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci if (runtime->format != SNDRV_PCM_FORMAT_U8 && 14168c2ecf20Sopenharmony_ci runtime->format != SNDRV_PCM_FORMAT_S16_LE) 14178c2ecf20Sopenharmony_ci return -EINVAL; 14188c2ecf20Sopenharmony_ci if (runtime->rate > 48000 || 14198c2ecf20Sopenharmony_ci runtime->rate < 8000) 14208c2ecf20Sopenharmony_ci return -EINVAL; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci snd_m3_pcm_setup1(chip, s, subs); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci if (subs->stream == SNDRV_PCM_STREAM_PLAYBACK) 14278c2ecf20Sopenharmony_ci snd_m3_playback_setup(chip, s, subs); 14288c2ecf20Sopenharmony_ci else 14298c2ecf20Sopenharmony_ci snd_m3_capture_setup(chip, s, subs); 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci snd_m3_pcm_setup2(chip, s, runtime); 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci return 0; 14368c2ecf20Sopenharmony_ci} 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci/* 14398c2ecf20Sopenharmony_ci * get current pointer 14408c2ecf20Sopenharmony_ci */ 14418c2ecf20Sopenharmony_cistatic unsigned int 14428c2ecf20Sopenharmony_cisnd_m3_get_pointer(struct snd_m3 *chip, struct m3_dma *s, struct snd_pcm_substream *subs) 14438c2ecf20Sopenharmony_ci{ 14448c2ecf20Sopenharmony_ci u16 hi = 0, lo = 0; 14458c2ecf20Sopenharmony_ci int retry = 10; 14468c2ecf20Sopenharmony_ci u32 addr; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci /* 14498c2ecf20Sopenharmony_ci * try and get a valid answer 14508c2ecf20Sopenharmony_ci */ 14518c2ecf20Sopenharmony_ci while (retry--) { 14528c2ecf20Sopenharmony_ci hi = snd_m3_assp_read(chip, MEMTYPE_INTERNAL_DATA, 14538c2ecf20Sopenharmony_ci s->inst.data + CDATA_HOST_SRC_CURRENTH); 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci lo = snd_m3_assp_read(chip, MEMTYPE_INTERNAL_DATA, 14568c2ecf20Sopenharmony_ci s->inst.data + CDATA_HOST_SRC_CURRENTL); 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci if (hi == snd_m3_assp_read(chip, MEMTYPE_INTERNAL_DATA, 14598c2ecf20Sopenharmony_ci s->inst.data + CDATA_HOST_SRC_CURRENTH)) 14608c2ecf20Sopenharmony_ci break; 14618c2ecf20Sopenharmony_ci } 14628c2ecf20Sopenharmony_ci addr = lo | ((u32)hi<<16); 14638c2ecf20Sopenharmony_ci return (unsigned int)(addr - s->buffer_addr); 14648c2ecf20Sopenharmony_ci} 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t 14678c2ecf20Sopenharmony_cisnd_m3_pcm_pointer(struct snd_pcm_substream *subs) 14688c2ecf20Sopenharmony_ci{ 14698c2ecf20Sopenharmony_ci struct snd_m3 *chip = snd_pcm_substream_chip(subs); 14708c2ecf20Sopenharmony_ci unsigned int ptr; 14718c2ecf20Sopenharmony_ci struct m3_dma *s = subs->runtime->private_data; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci if (snd_BUG_ON(!s)) 14748c2ecf20Sopenharmony_ci return 0; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci spin_lock(&chip->reg_lock); 14778c2ecf20Sopenharmony_ci ptr = snd_m3_get_pointer(chip, s, subs); 14788c2ecf20Sopenharmony_ci spin_unlock(&chip->reg_lock); 14798c2ecf20Sopenharmony_ci return bytes_to_frames(subs->runtime, ptr); 14808c2ecf20Sopenharmony_ci} 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci/* update pointer */ 14848c2ecf20Sopenharmony_ci/* spinlock held! */ 14858c2ecf20Sopenharmony_cistatic void snd_m3_update_ptr(struct snd_m3 *chip, struct m3_dma *s) 14868c2ecf20Sopenharmony_ci{ 14878c2ecf20Sopenharmony_ci struct snd_pcm_substream *subs = s->substream; 14888c2ecf20Sopenharmony_ci unsigned int hwptr; 14898c2ecf20Sopenharmony_ci int diff; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci if (! s->running) 14928c2ecf20Sopenharmony_ci return; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci hwptr = snd_m3_get_pointer(chip, s, subs); 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci /* try to avoid expensive modulo divisions */ 14978c2ecf20Sopenharmony_ci if (hwptr >= s->dma_size) 14988c2ecf20Sopenharmony_ci hwptr %= s->dma_size; 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci diff = s->dma_size + hwptr - s->hwptr; 15018c2ecf20Sopenharmony_ci if (diff >= s->dma_size) 15028c2ecf20Sopenharmony_ci diff %= s->dma_size; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci s->hwptr = hwptr; 15058c2ecf20Sopenharmony_ci s->count += diff; 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci if (s->count >= (signed)s->period_size) { 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci if (s->count < 2 * (signed)s->period_size) 15108c2ecf20Sopenharmony_ci s->count -= (signed)s->period_size; 15118c2ecf20Sopenharmony_ci else 15128c2ecf20Sopenharmony_ci s->count %= s->period_size; 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci spin_unlock(&chip->reg_lock); 15158c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(subs); 15168c2ecf20Sopenharmony_ci spin_lock(&chip->reg_lock); 15178c2ecf20Sopenharmony_ci } 15188c2ecf20Sopenharmony_ci} 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci/* The m3's hardware volume works by incrementing / decrementing 2 counters 15218c2ecf20Sopenharmony_ci (without wrap around) in response to volume button presses and then 15228c2ecf20Sopenharmony_ci generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7 15238c2ecf20Sopenharmony_ci of a byte wide register. The meaning of bits 0 and 4 is unknown. */ 15248c2ecf20Sopenharmony_cistatic void snd_m3_update_hw_volume(struct work_struct *work) 15258c2ecf20Sopenharmony_ci{ 15268c2ecf20Sopenharmony_ci struct snd_m3 *chip = container_of(work, struct snd_m3, hwvol_work); 15278c2ecf20Sopenharmony_ci int x, val; 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci /* Figure out which volume control button was pushed, 15308c2ecf20Sopenharmony_ci based on differences from the default register 15318c2ecf20Sopenharmony_ci values. */ 15328c2ecf20Sopenharmony_ci x = inb(chip->iobase + SHADOW_MIX_REG_VOICE) & 0xee; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci /* Reset the volume counters to 4. Tests on the allegro integrated 15358c2ecf20Sopenharmony_ci into a Compaq N600C laptop, have revealed that: 15368c2ecf20Sopenharmony_ci 1) Writing any value will result in the 2 counters being reset to 15378c2ecf20Sopenharmony_ci 4 so writing 0x88 is not strictly necessary 15388c2ecf20Sopenharmony_ci 2) Writing to any of the 4 involved registers will reset all 4 15398c2ecf20Sopenharmony_ci of them (and reading them always returns the same value for all 15408c2ecf20Sopenharmony_ci of them) 15418c2ecf20Sopenharmony_ci It could be that a maestro deviates from this, so leave the code 15428c2ecf20Sopenharmony_ci as is. */ 15438c2ecf20Sopenharmony_ci outb(0x88, chip->iobase + SHADOW_MIX_REG_VOICE); 15448c2ecf20Sopenharmony_ci outb(0x88, chip->iobase + HW_VOL_COUNTER_VOICE); 15458c2ecf20Sopenharmony_ci outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER); 15468c2ecf20Sopenharmony_ci outb(0x88, chip->iobase + HW_VOL_COUNTER_MASTER); 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci /* Ignore spurious HV interrupts during suspend / resume, this avoids 15498c2ecf20Sopenharmony_ci mistaking them for a mute button press. */ 15508c2ecf20Sopenharmony_ci if (chip->in_suspend) 15518c2ecf20Sopenharmony_ci return; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci#ifndef CONFIG_SND_MAESTRO3_INPUT 15548c2ecf20Sopenharmony_ci if (!chip->master_switch || !chip->master_volume) 15558c2ecf20Sopenharmony_ci return; 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci val = snd_ac97_read(chip->ac97, AC97_MASTER); 15588c2ecf20Sopenharmony_ci switch (x) { 15598c2ecf20Sopenharmony_ci case 0x88: 15608c2ecf20Sopenharmony_ci /* The counters have not changed, yet we've received a HV 15618c2ecf20Sopenharmony_ci interrupt. According to tests run by various people this 15628c2ecf20Sopenharmony_ci happens when pressing the mute button. */ 15638c2ecf20Sopenharmony_ci val ^= 0x8000; 15648c2ecf20Sopenharmony_ci break; 15658c2ecf20Sopenharmony_ci case 0xaa: 15668c2ecf20Sopenharmony_ci /* counters increased by 1 -> volume up */ 15678c2ecf20Sopenharmony_ci if ((val & 0x7f) > 0) 15688c2ecf20Sopenharmony_ci val--; 15698c2ecf20Sopenharmony_ci if ((val & 0x7f00) > 0) 15708c2ecf20Sopenharmony_ci val -= 0x0100; 15718c2ecf20Sopenharmony_ci break; 15728c2ecf20Sopenharmony_ci case 0x66: 15738c2ecf20Sopenharmony_ci /* counters decreased by 1 -> volume down */ 15748c2ecf20Sopenharmony_ci if ((val & 0x7f) < 0x1f) 15758c2ecf20Sopenharmony_ci val++; 15768c2ecf20Sopenharmony_ci if ((val & 0x7f00) < 0x1f00) 15778c2ecf20Sopenharmony_ci val += 0x0100; 15788c2ecf20Sopenharmony_ci break; 15798c2ecf20Sopenharmony_ci } 15808c2ecf20Sopenharmony_ci if (snd_ac97_update(chip->ac97, AC97_MASTER, val)) 15818c2ecf20Sopenharmony_ci snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, 15828c2ecf20Sopenharmony_ci &chip->master_switch->id); 15838c2ecf20Sopenharmony_ci#else 15848c2ecf20Sopenharmony_ci if (!chip->input_dev) 15858c2ecf20Sopenharmony_ci return; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci val = 0; 15888c2ecf20Sopenharmony_ci switch (x) { 15898c2ecf20Sopenharmony_ci case 0x88: 15908c2ecf20Sopenharmony_ci /* The counters have not changed, yet we've received a HV 15918c2ecf20Sopenharmony_ci interrupt. According to tests run by various people this 15928c2ecf20Sopenharmony_ci happens when pressing the mute button. */ 15938c2ecf20Sopenharmony_ci val = KEY_MUTE; 15948c2ecf20Sopenharmony_ci break; 15958c2ecf20Sopenharmony_ci case 0xaa: 15968c2ecf20Sopenharmony_ci /* counters increased by 1 -> volume up */ 15978c2ecf20Sopenharmony_ci val = KEY_VOLUMEUP; 15988c2ecf20Sopenharmony_ci break; 15998c2ecf20Sopenharmony_ci case 0x66: 16008c2ecf20Sopenharmony_ci /* counters decreased by 1 -> volume down */ 16018c2ecf20Sopenharmony_ci val = KEY_VOLUMEDOWN; 16028c2ecf20Sopenharmony_ci break; 16038c2ecf20Sopenharmony_ci } 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci if (val) { 16068c2ecf20Sopenharmony_ci input_report_key(chip->input_dev, val, 1); 16078c2ecf20Sopenharmony_ci input_sync(chip->input_dev); 16088c2ecf20Sopenharmony_ci input_report_key(chip->input_dev, val, 0); 16098c2ecf20Sopenharmony_ci input_sync(chip->input_dev); 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci#endif 16128c2ecf20Sopenharmony_ci} 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_cistatic irqreturn_t snd_m3_interrupt(int irq, void *dev_id) 16158c2ecf20Sopenharmony_ci{ 16168c2ecf20Sopenharmony_ci struct snd_m3 *chip = dev_id; 16178c2ecf20Sopenharmony_ci u8 status; 16188c2ecf20Sopenharmony_ci int i; 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci status = inb(chip->iobase + HOST_INT_STATUS); 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci if (status == 0xff) 16238c2ecf20Sopenharmony_ci return IRQ_NONE; 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci if (status & HV_INT_PENDING) 16268c2ecf20Sopenharmony_ci schedule_work(&chip->hwvol_work); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci /* 16298c2ecf20Sopenharmony_ci * ack an assp int if its running 16308c2ecf20Sopenharmony_ci * and has an int pending 16318c2ecf20Sopenharmony_ci */ 16328c2ecf20Sopenharmony_ci if (status & ASSP_INT_PENDING) { 16338c2ecf20Sopenharmony_ci u8 ctl = inb(chip->iobase + ASSP_CONTROL_B); 16348c2ecf20Sopenharmony_ci if (!(ctl & STOP_ASSP_CLOCK)) { 16358c2ecf20Sopenharmony_ci ctl = inb(chip->iobase + ASSP_HOST_INT_STATUS); 16368c2ecf20Sopenharmony_ci if (ctl & DSP2HOST_REQ_TIMER) { 16378c2ecf20Sopenharmony_ci outb(DSP2HOST_REQ_TIMER, chip->iobase + ASSP_HOST_INT_STATUS); 16388c2ecf20Sopenharmony_ci /* update adc/dac info if it was a timer int */ 16398c2ecf20Sopenharmony_ci spin_lock(&chip->reg_lock); 16408c2ecf20Sopenharmony_ci for (i = 0; i < chip->num_substreams; i++) { 16418c2ecf20Sopenharmony_ci struct m3_dma *s = &chip->substreams[i]; 16428c2ecf20Sopenharmony_ci if (s->running) 16438c2ecf20Sopenharmony_ci snd_m3_update_ptr(chip, s); 16448c2ecf20Sopenharmony_ci } 16458c2ecf20Sopenharmony_ci spin_unlock(&chip->reg_lock); 16468c2ecf20Sopenharmony_ci } 16478c2ecf20Sopenharmony_ci } 16488c2ecf20Sopenharmony_ci } 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci#if 0 /* TODO: not supported yet */ 16518c2ecf20Sopenharmony_ci if ((status & MPU401_INT_PENDING) && chip->rmidi) 16528c2ecf20Sopenharmony_ci snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); 16538c2ecf20Sopenharmony_ci#endif 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci /* ack ints */ 16568c2ecf20Sopenharmony_ci outb(status, chip->iobase + HOST_INT_STATUS); 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci return IRQ_HANDLED; 16598c2ecf20Sopenharmony_ci} 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci/* 16638c2ecf20Sopenharmony_ci */ 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware snd_m3_playback = 16668c2ecf20Sopenharmony_ci{ 16678c2ecf20Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | 16688c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_INTERLEAVED | 16698c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 16708c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 16718c2ecf20Sopenharmony_ci /*SNDRV_PCM_INFO_PAUSE |*/ 16728c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_RESUME), 16738c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, 16748c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, 16758c2ecf20Sopenharmony_ci .rate_min = 8000, 16768c2ecf20Sopenharmony_ci .rate_max = 48000, 16778c2ecf20Sopenharmony_ci .channels_min = 1, 16788c2ecf20Sopenharmony_ci .channels_max = 2, 16798c2ecf20Sopenharmony_ci .buffer_bytes_max = (512*1024), 16808c2ecf20Sopenharmony_ci .period_bytes_min = 64, 16818c2ecf20Sopenharmony_ci .period_bytes_max = (512*1024), 16828c2ecf20Sopenharmony_ci .periods_min = 1, 16838c2ecf20Sopenharmony_ci .periods_max = 1024, 16848c2ecf20Sopenharmony_ci}; 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware snd_m3_capture = 16878c2ecf20Sopenharmony_ci{ 16888c2ecf20Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | 16898c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_INTERLEAVED | 16908c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 16918c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 16928c2ecf20Sopenharmony_ci /*SNDRV_PCM_INFO_PAUSE |*/ 16938c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_RESUME), 16948c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, 16958c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, 16968c2ecf20Sopenharmony_ci .rate_min = 8000, 16978c2ecf20Sopenharmony_ci .rate_max = 48000, 16988c2ecf20Sopenharmony_ci .channels_min = 1, 16998c2ecf20Sopenharmony_ci .channels_max = 2, 17008c2ecf20Sopenharmony_ci .buffer_bytes_max = (512*1024), 17018c2ecf20Sopenharmony_ci .period_bytes_min = 64, 17028c2ecf20Sopenharmony_ci .period_bytes_max = (512*1024), 17038c2ecf20Sopenharmony_ci .periods_min = 1, 17048c2ecf20Sopenharmony_ci .periods_max = 1024, 17058c2ecf20Sopenharmony_ci}; 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci/* 17098c2ecf20Sopenharmony_ci */ 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_cistatic int 17128c2ecf20Sopenharmony_cisnd_m3_substream_open(struct snd_m3 *chip, struct snd_pcm_substream *subs) 17138c2ecf20Sopenharmony_ci{ 17148c2ecf20Sopenharmony_ci int i; 17158c2ecf20Sopenharmony_ci struct m3_dma *s; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 17188c2ecf20Sopenharmony_ci for (i = 0; i < chip->num_substreams; i++) { 17198c2ecf20Sopenharmony_ci s = &chip->substreams[i]; 17208c2ecf20Sopenharmony_ci if (! s->opened) 17218c2ecf20Sopenharmony_ci goto __found; 17228c2ecf20Sopenharmony_ci } 17238c2ecf20Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 17248c2ecf20Sopenharmony_ci return -ENOMEM; 17258c2ecf20Sopenharmony_ci__found: 17268c2ecf20Sopenharmony_ci s->opened = 1; 17278c2ecf20Sopenharmony_ci s->running = 0; 17288c2ecf20Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci subs->runtime->private_data = s; 17318c2ecf20Sopenharmony_ci s->substream = subs; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci /* set list owners */ 17348c2ecf20Sopenharmony_ci if (subs->stream == SNDRV_PCM_STREAM_PLAYBACK) { 17358c2ecf20Sopenharmony_ci s->index_list[0] = &chip->mixer_list; 17368c2ecf20Sopenharmony_ci } else 17378c2ecf20Sopenharmony_ci s->index_list[0] = &chip->adc1_list; 17388c2ecf20Sopenharmony_ci s->index_list[1] = &chip->msrc_list; 17398c2ecf20Sopenharmony_ci s->index_list[2] = &chip->dma_list; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci return 0; 17428c2ecf20Sopenharmony_ci} 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_cistatic void 17458c2ecf20Sopenharmony_cisnd_m3_substream_close(struct snd_m3 *chip, struct snd_pcm_substream *subs) 17468c2ecf20Sopenharmony_ci{ 17478c2ecf20Sopenharmony_ci struct m3_dma *s = subs->runtime->private_data; 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci if (s == NULL) 17508c2ecf20Sopenharmony_ci return; /* not opened properly */ 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 17538c2ecf20Sopenharmony_ci if (s->substream && s->running) 17548c2ecf20Sopenharmony_ci snd_m3_pcm_stop(chip, s, s->substream); /* does this happen? */ 17558c2ecf20Sopenharmony_ci if (s->in_lists) { 17568c2ecf20Sopenharmony_ci snd_m3_remove_list(chip, s->index_list[0], s->index[0]); 17578c2ecf20Sopenharmony_ci snd_m3_remove_list(chip, s->index_list[1], s->index[1]); 17588c2ecf20Sopenharmony_ci snd_m3_remove_list(chip, s->index_list[2], s->index[2]); 17598c2ecf20Sopenharmony_ci s->in_lists = 0; 17608c2ecf20Sopenharmony_ci } 17618c2ecf20Sopenharmony_ci s->running = 0; 17628c2ecf20Sopenharmony_ci s->opened = 0; 17638c2ecf20Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 17648c2ecf20Sopenharmony_ci} 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_cistatic int 17678c2ecf20Sopenharmony_cisnd_m3_playback_open(struct snd_pcm_substream *subs) 17688c2ecf20Sopenharmony_ci{ 17698c2ecf20Sopenharmony_ci struct snd_m3 *chip = snd_pcm_substream_chip(subs); 17708c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = subs->runtime; 17718c2ecf20Sopenharmony_ci int err; 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci if ((err = snd_m3_substream_open(chip, subs)) < 0) 17748c2ecf20Sopenharmony_ci return err; 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci runtime->hw = snd_m3_playback; 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci return 0; 17798c2ecf20Sopenharmony_ci} 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_cistatic int 17828c2ecf20Sopenharmony_cisnd_m3_playback_close(struct snd_pcm_substream *subs) 17838c2ecf20Sopenharmony_ci{ 17848c2ecf20Sopenharmony_ci struct snd_m3 *chip = snd_pcm_substream_chip(subs); 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci snd_m3_substream_close(chip, subs); 17878c2ecf20Sopenharmony_ci return 0; 17888c2ecf20Sopenharmony_ci} 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_cistatic int 17918c2ecf20Sopenharmony_cisnd_m3_capture_open(struct snd_pcm_substream *subs) 17928c2ecf20Sopenharmony_ci{ 17938c2ecf20Sopenharmony_ci struct snd_m3 *chip = snd_pcm_substream_chip(subs); 17948c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = subs->runtime; 17958c2ecf20Sopenharmony_ci int err; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci if ((err = snd_m3_substream_open(chip, subs)) < 0) 17988c2ecf20Sopenharmony_ci return err; 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci runtime->hw = snd_m3_capture; 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci return 0; 18038c2ecf20Sopenharmony_ci} 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_cistatic int 18068c2ecf20Sopenharmony_cisnd_m3_capture_close(struct snd_pcm_substream *subs) 18078c2ecf20Sopenharmony_ci{ 18088c2ecf20Sopenharmony_ci struct snd_m3 *chip = snd_pcm_substream_chip(subs); 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci snd_m3_substream_close(chip, subs); 18118c2ecf20Sopenharmony_ci return 0; 18128c2ecf20Sopenharmony_ci} 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci/* 18158c2ecf20Sopenharmony_ci * create pcm instance 18168c2ecf20Sopenharmony_ci */ 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_m3_playback_ops = { 18198c2ecf20Sopenharmony_ci .open = snd_m3_playback_open, 18208c2ecf20Sopenharmony_ci .close = snd_m3_playback_close, 18218c2ecf20Sopenharmony_ci .hw_params = snd_m3_pcm_hw_params, 18228c2ecf20Sopenharmony_ci .hw_free = snd_m3_pcm_hw_free, 18238c2ecf20Sopenharmony_ci .prepare = snd_m3_pcm_prepare, 18248c2ecf20Sopenharmony_ci .trigger = snd_m3_pcm_trigger, 18258c2ecf20Sopenharmony_ci .pointer = snd_m3_pcm_pointer, 18268c2ecf20Sopenharmony_ci}; 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_m3_capture_ops = { 18298c2ecf20Sopenharmony_ci .open = snd_m3_capture_open, 18308c2ecf20Sopenharmony_ci .close = snd_m3_capture_close, 18318c2ecf20Sopenharmony_ci .hw_params = snd_m3_pcm_hw_params, 18328c2ecf20Sopenharmony_ci .hw_free = snd_m3_pcm_hw_free, 18338c2ecf20Sopenharmony_ci .prepare = snd_m3_pcm_prepare, 18348c2ecf20Sopenharmony_ci .trigger = snd_m3_pcm_trigger, 18358c2ecf20Sopenharmony_ci .pointer = snd_m3_pcm_pointer, 18368c2ecf20Sopenharmony_ci}; 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_cistatic int 18398c2ecf20Sopenharmony_cisnd_m3_pcm(struct snd_m3 * chip, int device) 18408c2ecf20Sopenharmony_ci{ 18418c2ecf20Sopenharmony_ci struct snd_pcm *pcm; 18428c2ecf20Sopenharmony_ci int err; 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci err = snd_pcm_new(chip->card, chip->card->driver, device, 18458c2ecf20Sopenharmony_ci MAX_PLAYBACKS, MAX_CAPTURES, &pcm); 18468c2ecf20Sopenharmony_ci if (err < 0) 18478c2ecf20Sopenharmony_ci return err; 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_m3_playback_ops); 18508c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_m3_capture_ops); 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci pcm->private_data = chip; 18538c2ecf20Sopenharmony_ci pcm->info_flags = 0; 18548c2ecf20Sopenharmony_ci strcpy(pcm->name, chip->card->driver); 18558c2ecf20Sopenharmony_ci chip->pcm = pcm; 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 18588c2ecf20Sopenharmony_ci &chip->pci->dev, 64*1024, 64*1024); 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci return 0; 18618c2ecf20Sopenharmony_ci} 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci/* 18658c2ecf20Sopenharmony_ci * ac97 interface 18668c2ecf20Sopenharmony_ci */ 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci/* 18698c2ecf20Sopenharmony_ci * Wait for the ac97 serial bus to be free. 18708c2ecf20Sopenharmony_ci * return nonzero if the bus is still busy. 18718c2ecf20Sopenharmony_ci */ 18728c2ecf20Sopenharmony_cistatic int snd_m3_ac97_wait(struct snd_m3 *chip) 18738c2ecf20Sopenharmony_ci{ 18748c2ecf20Sopenharmony_ci int i = 10000; 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci do { 18778c2ecf20Sopenharmony_ci if (! (snd_m3_inb(chip, 0x30) & 1)) 18788c2ecf20Sopenharmony_ci return 0; 18798c2ecf20Sopenharmony_ci cpu_relax(); 18808c2ecf20Sopenharmony_ci } while (i-- > 0); 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci dev_err(chip->card->dev, "ac97 serial bus busy\n"); 18838c2ecf20Sopenharmony_ci return 1; 18848c2ecf20Sopenharmony_ci} 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_cistatic unsigned short 18878c2ecf20Sopenharmony_cisnd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg) 18888c2ecf20Sopenharmony_ci{ 18898c2ecf20Sopenharmony_ci struct snd_m3 *chip = ac97->private_data; 18908c2ecf20Sopenharmony_ci unsigned short data = 0xffff; 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci if (snd_m3_ac97_wait(chip)) 18938c2ecf20Sopenharmony_ci goto fail; 18948c2ecf20Sopenharmony_ci snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND); 18958c2ecf20Sopenharmony_ci if (snd_m3_ac97_wait(chip)) 18968c2ecf20Sopenharmony_ci goto fail; 18978c2ecf20Sopenharmony_ci data = snd_m3_inw(chip, CODEC_DATA); 18988c2ecf20Sopenharmony_cifail: 18998c2ecf20Sopenharmony_ci return data; 19008c2ecf20Sopenharmony_ci} 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_cistatic void 19038c2ecf20Sopenharmony_cisnd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) 19048c2ecf20Sopenharmony_ci{ 19058c2ecf20Sopenharmony_ci struct snd_m3 *chip = ac97->private_data; 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci if (snd_m3_ac97_wait(chip)) 19088c2ecf20Sopenharmony_ci return; 19098c2ecf20Sopenharmony_ci snd_m3_outw(chip, val, CODEC_DATA); 19108c2ecf20Sopenharmony_ci snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND); 19118c2ecf20Sopenharmony_ci /* 19128c2ecf20Sopenharmony_ci * Workaround for buggy ES1988 integrated AC'97 codec. It remains silent 19138c2ecf20Sopenharmony_ci * until the MASTER volume or mute is touched (alsactl restore does not 19148c2ecf20Sopenharmony_ci * work). 19158c2ecf20Sopenharmony_ci */ 19168c2ecf20Sopenharmony_ci if (ac97->id == 0x45838308 && reg == AC97_MASTER) { 19178c2ecf20Sopenharmony_ci snd_m3_ac97_wait(chip); 19188c2ecf20Sopenharmony_ci snd_m3_outw(chip, val, CODEC_DATA); 19198c2ecf20Sopenharmony_ci snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND); 19208c2ecf20Sopenharmony_ci } 19218c2ecf20Sopenharmony_ci} 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_cistatic void snd_m3_remote_codec_config(struct snd_m3 *chip, int isremote) 19258c2ecf20Sopenharmony_ci{ 19268c2ecf20Sopenharmony_ci int io = chip->iobase; 19278c2ecf20Sopenharmony_ci u16 tmp; 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci isremote = isremote ? 1 : 0; 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci tmp = inw(io + RING_BUS_CTRL_B) & ~SECOND_CODEC_ID_MASK; 19328c2ecf20Sopenharmony_ci /* enable dock on Dell Latitude C810 */ 19338c2ecf20Sopenharmony_ci if (chip->pci->subsystem_vendor == 0x1028 && 19348c2ecf20Sopenharmony_ci chip->pci->subsystem_device == 0x00e5) 19358c2ecf20Sopenharmony_ci tmp |= M3I_DOCK_ENABLE; 19368c2ecf20Sopenharmony_ci outw(tmp | isremote, io + RING_BUS_CTRL_B); 19378c2ecf20Sopenharmony_ci outw((inw(io + SDO_OUT_DEST_CTRL) & ~COMMAND_ADDR_OUT) | isremote, 19388c2ecf20Sopenharmony_ci io + SDO_OUT_DEST_CTRL); 19398c2ecf20Sopenharmony_ci outw((inw(io + SDO_IN_DEST_CTRL) & ~STATUS_ADDR_IN) | isremote, 19408c2ecf20Sopenharmony_ci io + SDO_IN_DEST_CTRL); 19418c2ecf20Sopenharmony_ci} 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci/* 19448c2ecf20Sopenharmony_ci * hack, returns non zero on err 19458c2ecf20Sopenharmony_ci */ 19468c2ecf20Sopenharmony_cistatic int snd_m3_try_read_vendor(struct snd_m3 *chip) 19478c2ecf20Sopenharmony_ci{ 19488c2ecf20Sopenharmony_ci u16 ret; 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci if (snd_m3_ac97_wait(chip)) 19518c2ecf20Sopenharmony_ci return 1; 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci snd_m3_outb(chip, 0x80 | (AC97_VENDOR_ID1 & 0x7f), 0x30); 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci if (snd_m3_ac97_wait(chip)) 19568c2ecf20Sopenharmony_ci return 1; 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci ret = snd_m3_inw(chip, 0x32); 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci return (ret == 0) || (ret == 0xffff); 19618c2ecf20Sopenharmony_ci} 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_cistatic void snd_m3_ac97_reset(struct snd_m3 *chip) 19648c2ecf20Sopenharmony_ci{ 19658c2ecf20Sopenharmony_ci u16 dir; 19668c2ecf20Sopenharmony_ci int delay1 = 0, delay2 = 0, i; 19678c2ecf20Sopenharmony_ci int io = chip->iobase; 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci if (chip->allegro_flag) { 19708c2ecf20Sopenharmony_ci /* 19718c2ecf20Sopenharmony_ci * the onboard codec on the allegro seems 19728c2ecf20Sopenharmony_ci * to want to wait a very long time before 19738c2ecf20Sopenharmony_ci * coming back to life 19748c2ecf20Sopenharmony_ci */ 19758c2ecf20Sopenharmony_ci delay1 = 50; 19768c2ecf20Sopenharmony_ci delay2 = 800; 19778c2ecf20Sopenharmony_ci } else { 19788c2ecf20Sopenharmony_ci /* maestro3 */ 19798c2ecf20Sopenharmony_ci delay1 = 20; 19808c2ecf20Sopenharmony_ci delay2 = 500; 19818c2ecf20Sopenharmony_ci } 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) { 19848c2ecf20Sopenharmony_ci dir = inw(io + GPIO_DIRECTION); 19858c2ecf20Sopenharmony_ci if (!chip->irda_workaround) 19868c2ecf20Sopenharmony_ci dir |= 0x10; /* assuming pci bus master? */ 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci snd_m3_remote_codec_config(chip, 0); 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci outw(IO_SRAM_ENABLE, io + RING_BUS_CTRL_A); 19918c2ecf20Sopenharmony_ci udelay(20); 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci outw(dir & ~GPO_PRIMARY_AC97 , io + GPIO_DIRECTION); 19948c2ecf20Sopenharmony_ci outw(~GPO_PRIMARY_AC97 , io + GPIO_MASK); 19958c2ecf20Sopenharmony_ci outw(0, io + GPIO_DATA); 19968c2ecf20Sopenharmony_ci outw(dir | GPO_PRIMARY_AC97, io + GPIO_DIRECTION); 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(msecs_to_jiffies(delay1)); 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci outw(GPO_PRIMARY_AC97, io + GPIO_DATA); 20018c2ecf20Sopenharmony_ci udelay(5); 20028c2ecf20Sopenharmony_ci /* ok, bring back the ac-link */ 20038c2ecf20Sopenharmony_ci outw(IO_SRAM_ENABLE | SERIAL_AC_LINK_ENABLE, io + RING_BUS_CTRL_A); 20048c2ecf20Sopenharmony_ci outw(~0, io + GPIO_MASK); 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(msecs_to_jiffies(delay2)); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci if (! snd_m3_try_read_vendor(chip)) 20098c2ecf20Sopenharmony_ci break; 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci delay1 += 10; 20128c2ecf20Sopenharmony_ci delay2 += 100; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, 20158c2ecf20Sopenharmony_ci "retrying codec reset with delays of %d and %d ms\n", 20168c2ecf20Sopenharmony_ci delay1, delay2); 20178c2ecf20Sopenharmony_ci } 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci#if 0 20208c2ecf20Sopenharmony_ci /* more gung-ho reset that doesn't 20218c2ecf20Sopenharmony_ci * seem to work anywhere :) 20228c2ecf20Sopenharmony_ci */ 20238c2ecf20Sopenharmony_ci tmp = inw(io + RING_BUS_CTRL_A); 20248c2ecf20Sopenharmony_ci outw(RAC_SDFS_ENABLE|LAC_SDFS_ENABLE, io + RING_BUS_CTRL_A); 20258c2ecf20Sopenharmony_ci msleep(20); 20268c2ecf20Sopenharmony_ci outw(tmp, io + RING_BUS_CTRL_A); 20278c2ecf20Sopenharmony_ci msleep(50); 20288c2ecf20Sopenharmony_ci#endif 20298c2ecf20Sopenharmony_ci} 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_cistatic int snd_m3_mixer(struct snd_m3 *chip) 20328c2ecf20Sopenharmony_ci{ 20338c2ecf20Sopenharmony_ci struct snd_ac97_bus *pbus; 20348c2ecf20Sopenharmony_ci struct snd_ac97_template ac97; 20358c2ecf20Sopenharmony_ci#ifndef CONFIG_SND_MAESTRO3_INPUT 20368c2ecf20Sopenharmony_ci struct snd_ctl_elem_id elem_id; 20378c2ecf20Sopenharmony_ci#endif 20388c2ecf20Sopenharmony_ci int err; 20398c2ecf20Sopenharmony_ci static const struct snd_ac97_bus_ops ops = { 20408c2ecf20Sopenharmony_ci .write = snd_m3_ac97_write, 20418c2ecf20Sopenharmony_ci .read = snd_m3_ac97_read, 20428c2ecf20Sopenharmony_ci }; 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0) 20458c2ecf20Sopenharmony_ci return err; 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci memset(&ac97, 0, sizeof(ac97)); 20488c2ecf20Sopenharmony_ci ac97.private_data = chip; 20498c2ecf20Sopenharmony_ci if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97)) < 0) 20508c2ecf20Sopenharmony_ci return err; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci /* seems ac97 PCM needs initialization.. hack hack.. */ 20538c2ecf20Sopenharmony_ci snd_ac97_write(chip->ac97, AC97_PCM, 0x8000 | (15 << 8) | 15); 20548c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(msecs_to_jiffies(100)); 20558c2ecf20Sopenharmony_ci snd_ac97_write(chip->ac97, AC97_PCM, 0); 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci#ifndef CONFIG_SND_MAESTRO3_INPUT 20588c2ecf20Sopenharmony_ci memset(&elem_id, 0, sizeof(elem_id)); 20598c2ecf20Sopenharmony_ci elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 20608c2ecf20Sopenharmony_ci strcpy(elem_id.name, "Master Playback Switch"); 20618c2ecf20Sopenharmony_ci chip->master_switch = snd_ctl_find_id(chip->card, &elem_id); 20628c2ecf20Sopenharmony_ci memset(&elem_id, 0, sizeof(elem_id)); 20638c2ecf20Sopenharmony_ci elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 20648c2ecf20Sopenharmony_ci strcpy(elem_id.name, "Master Playback Volume"); 20658c2ecf20Sopenharmony_ci chip->master_volume = snd_ctl_find_id(chip->card, &elem_id); 20668c2ecf20Sopenharmony_ci#endif 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci return 0; 20698c2ecf20Sopenharmony_ci} 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci/* 20738c2ecf20Sopenharmony_ci * initialize ASSP 20748c2ecf20Sopenharmony_ci */ 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci#define MINISRC_LPF_LEN 10 20778c2ecf20Sopenharmony_cistatic const u16 minisrc_lpf[MINISRC_LPF_LEN] = { 20788c2ecf20Sopenharmony_ci 0X0743, 0X1104, 0X0A4C, 0XF88D, 0X242C, 20798c2ecf20Sopenharmony_ci 0X1023, 0X1AA9, 0X0B60, 0XEFDD, 0X186F 20808c2ecf20Sopenharmony_ci}; 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_cistatic void snd_m3_assp_init(struct snd_m3 *chip) 20838c2ecf20Sopenharmony_ci{ 20848c2ecf20Sopenharmony_ci unsigned int i; 20858c2ecf20Sopenharmony_ci const __le16 *data; 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci /* zero kernel data */ 20888c2ecf20Sopenharmony_ci for (i = 0; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++) 20898c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 20908c2ecf20Sopenharmony_ci KDATA_BASE_ADDR + i, 0); 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci /* zero mixer data? */ 20938c2ecf20Sopenharmony_ci for (i = 0; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++) 20948c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 20958c2ecf20Sopenharmony_ci KDATA_BASE_ADDR2 + i, 0); 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci /* init dma pointer */ 20988c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 20998c2ecf20Sopenharmony_ci KDATA_CURRENT_DMA, 21008c2ecf20Sopenharmony_ci KDATA_DMA_XFER0); 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci /* write kernel into code memory.. */ 21038c2ecf20Sopenharmony_ci data = (const __le16 *)chip->assp_kernel_image->data; 21048c2ecf20Sopenharmony_ci for (i = 0 ; i * 2 < chip->assp_kernel_image->size; i++) { 21058c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE, 21068c2ecf20Sopenharmony_ci REV_B_CODE_MEMORY_BEGIN + i, 21078c2ecf20Sopenharmony_ci le16_to_cpu(data[i])); 21088c2ecf20Sopenharmony_ci } 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci /* 21118c2ecf20Sopenharmony_ci * We only have this one client and we know that 0x400 21128c2ecf20Sopenharmony_ci * is free in our kernel's mem map, so lets just 21138c2ecf20Sopenharmony_ci * drop it there. It seems that the minisrc doesn't 21148c2ecf20Sopenharmony_ci * need vectors, so we won't bother with them.. 21158c2ecf20Sopenharmony_ci */ 21168c2ecf20Sopenharmony_ci data = (const __le16 *)chip->assp_minisrc_image->data; 21178c2ecf20Sopenharmony_ci for (i = 0; i * 2 < chip->assp_minisrc_image->size; i++) { 21188c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE, 21198c2ecf20Sopenharmony_ci 0x400 + i, le16_to_cpu(data[i])); 21208c2ecf20Sopenharmony_ci } 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci /* 21238c2ecf20Sopenharmony_ci * write the coefficients for the low pass filter? 21248c2ecf20Sopenharmony_ci */ 21258c2ecf20Sopenharmony_ci for (i = 0; i < MINISRC_LPF_LEN ; i++) { 21268c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE, 21278c2ecf20Sopenharmony_ci 0x400 + MINISRC_COEF_LOC + i, 21288c2ecf20Sopenharmony_ci minisrc_lpf[i]); 21298c2ecf20Sopenharmony_ci } 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE, 21328c2ecf20Sopenharmony_ci 0x400 + MINISRC_COEF_LOC + MINISRC_LPF_LEN, 21338c2ecf20Sopenharmony_ci 0x8000); 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci /* 21368c2ecf20Sopenharmony_ci * the minisrc is the only thing on 21378c2ecf20Sopenharmony_ci * our task list.. 21388c2ecf20Sopenharmony_ci */ 21398c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 21408c2ecf20Sopenharmony_ci KDATA_TASK0, 21418c2ecf20Sopenharmony_ci 0x400); 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci /* 21448c2ecf20Sopenharmony_ci * init the mixer number.. 21458c2ecf20Sopenharmony_ci */ 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 21488c2ecf20Sopenharmony_ci KDATA_MIXER_TASK_NUMBER,0); 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci /* 21518c2ecf20Sopenharmony_ci * EXTREME KERNEL MASTER VOLUME 21528c2ecf20Sopenharmony_ci */ 21538c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 21548c2ecf20Sopenharmony_ci KDATA_DAC_LEFT_VOLUME, ARB_VOLUME); 21558c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 21568c2ecf20Sopenharmony_ci KDATA_DAC_RIGHT_VOLUME, ARB_VOLUME); 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci chip->mixer_list.curlen = 0; 21598c2ecf20Sopenharmony_ci chip->mixer_list.mem_addr = KDATA_MIXER_XFER0; 21608c2ecf20Sopenharmony_ci chip->mixer_list.max = MAX_VIRTUAL_MIXER_CHANNELS; 21618c2ecf20Sopenharmony_ci chip->adc1_list.curlen = 0; 21628c2ecf20Sopenharmony_ci chip->adc1_list.mem_addr = KDATA_ADC1_XFER0; 21638c2ecf20Sopenharmony_ci chip->adc1_list.max = MAX_VIRTUAL_ADC1_CHANNELS; 21648c2ecf20Sopenharmony_ci chip->dma_list.curlen = 0; 21658c2ecf20Sopenharmony_ci chip->dma_list.mem_addr = KDATA_DMA_XFER0; 21668c2ecf20Sopenharmony_ci chip->dma_list.max = MAX_VIRTUAL_DMA_CHANNELS; 21678c2ecf20Sopenharmony_ci chip->msrc_list.curlen = 0; 21688c2ecf20Sopenharmony_ci chip->msrc_list.mem_addr = KDATA_INSTANCE0_MINISRC; 21698c2ecf20Sopenharmony_ci chip->msrc_list.max = MAX_INSTANCE_MINISRC; 21708c2ecf20Sopenharmony_ci} 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_cistatic int snd_m3_assp_client_init(struct snd_m3 *chip, struct m3_dma *s, int index) 21748c2ecf20Sopenharmony_ci{ 21758c2ecf20Sopenharmony_ci int data_bytes = 2 * ( MINISRC_TMP_BUFFER_SIZE / 2 + 21768c2ecf20Sopenharmony_ci MINISRC_IN_BUFFER_SIZE / 2 + 21778c2ecf20Sopenharmony_ci 1 + MINISRC_OUT_BUFFER_SIZE / 2 + 1 ); 21788c2ecf20Sopenharmony_ci int address, i; 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci /* 21818c2ecf20Sopenharmony_ci * the revb memory map has 0x1100 through 0x1c00 21828c2ecf20Sopenharmony_ci * free. 21838c2ecf20Sopenharmony_ci */ 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci /* 21868c2ecf20Sopenharmony_ci * align instance address to 256 bytes so that its 21878c2ecf20Sopenharmony_ci * shifted list address is aligned. 21888c2ecf20Sopenharmony_ci * list address = (mem address >> 1) >> 7; 21898c2ecf20Sopenharmony_ci */ 21908c2ecf20Sopenharmony_ci data_bytes = ALIGN(data_bytes, 256); 21918c2ecf20Sopenharmony_ci address = 0x1100 + ((data_bytes/2) * index); 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci if ((address + (data_bytes/2)) >= 0x1c00) { 21948c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 21958c2ecf20Sopenharmony_ci "no memory for %d bytes at ind %d (addr 0x%x)\n", 21968c2ecf20Sopenharmony_ci data_bytes, index, address); 21978c2ecf20Sopenharmony_ci return -ENOMEM; 21988c2ecf20Sopenharmony_ci } 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci s->number = index; 22018c2ecf20Sopenharmony_ci s->inst.code = 0x400; 22028c2ecf20Sopenharmony_ci s->inst.data = address; 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci for (i = data_bytes / 2; i > 0; address++, i--) { 22058c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 22068c2ecf20Sopenharmony_ci address, 0); 22078c2ecf20Sopenharmony_ci } 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci return 0; 22108c2ecf20Sopenharmony_ci} 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_ci/* 22148c2ecf20Sopenharmony_ci * this works for the reference board, have to find 22158c2ecf20Sopenharmony_ci * out about others 22168c2ecf20Sopenharmony_ci * 22178c2ecf20Sopenharmony_ci * this needs more magic for 4 speaker, but.. 22188c2ecf20Sopenharmony_ci */ 22198c2ecf20Sopenharmony_cistatic void 22208c2ecf20Sopenharmony_cisnd_m3_amp_enable(struct snd_m3 *chip, int enable) 22218c2ecf20Sopenharmony_ci{ 22228c2ecf20Sopenharmony_ci int io = chip->iobase; 22238c2ecf20Sopenharmony_ci u16 gpo, polarity; 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci if (! chip->external_amp) 22268c2ecf20Sopenharmony_ci return; 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci polarity = enable ? 0 : 1; 22298c2ecf20Sopenharmony_ci polarity = polarity << chip->amp_gpio; 22308c2ecf20Sopenharmony_ci gpo = 1 << chip->amp_gpio; 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci outw(~gpo, io + GPIO_MASK); 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci outw(inw(io + GPIO_DIRECTION) | gpo, 22358c2ecf20Sopenharmony_ci io + GPIO_DIRECTION); 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci outw((GPO_SECONDARY_AC97 | GPO_PRIMARY_AC97 | polarity), 22388c2ecf20Sopenharmony_ci io + GPIO_DATA); 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci outw(0xffff, io + GPIO_MASK); 22418c2ecf20Sopenharmony_ci} 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_cistatic void 22448c2ecf20Sopenharmony_cisnd_m3_hv_init(struct snd_m3 *chip) 22458c2ecf20Sopenharmony_ci{ 22468c2ecf20Sopenharmony_ci unsigned long io = chip->iobase; 22478c2ecf20Sopenharmony_ci u16 val = GPI_VOL_DOWN | GPI_VOL_UP; 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci if (!chip->is_omnibook) 22508c2ecf20Sopenharmony_ci return; 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci /* 22538c2ecf20Sopenharmony_ci * Volume buttons on some HP OmniBook laptops 22548c2ecf20Sopenharmony_ci * require some GPIO magic to work correctly. 22558c2ecf20Sopenharmony_ci */ 22568c2ecf20Sopenharmony_ci outw(0xffff, io + GPIO_MASK); 22578c2ecf20Sopenharmony_ci outw(0x0000, io + GPIO_DATA); 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ci outw(~val, io + GPIO_MASK); 22608c2ecf20Sopenharmony_ci outw(inw(io + GPIO_DIRECTION) & ~val, io + GPIO_DIRECTION); 22618c2ecf20Sopenharmony_ci outw(val, io + GPIO_MASK); 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci outw(0xffff, io + GPIO_MASK); 22648c2ecf20Sopenharmony_ci} 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_cistatic int 22678c2ecf20Sopenharmony_cisnd_m3_chip_init(struct snd_m3 *chip) 22688c2ecf20Sopenharmony_ci{ 22698c2ecf20Sopenharmony_ci struct pci_dev *pcidev = chip->pci; 22708c2ecf20Sopenharmony_ci unsigned long io = chip->iobase; 22718c2ecf20Sopenharmony_ci u32 n; 22728c2ecf20Sopenharmony_ci u16 w; 22738c2ecf20Sopenharmony_ci u8 t; /* makes as much sense as 'n', no? */ 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_ci pci_read_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, &w); 22768c2ecf20Sopenharmony_ci w &= ~(SOUND_BLASTER_ENABLE|FM_SYNTHESIS_ENABLE| 22778c2ecf20Sopenharmony_ci MPU401_IO_ENABLE|MPU401_IRQ_ENABLE|ALIAS_10BIT_IO| 22788c2ecf20Sopenharmony_ci DISABLE_LEGACY); 22798c2ecf20Sopenharmony_ci pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); 22828c2ecf20Sopenharmony_ci n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD); 22838c2ecf20Sopenharmony_ci n |= chip->hv_config; 22848c2ecf20Sopenharmony_ci /* For some reason we must always use reduced debounce. */ 22858c2ecf20Sopenharmony_ci n |= REDUCED_DEBOUNCE; 22868c2ecf20Sopenharmony_ci n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING; 22878c2ecf20Sopenharmony_ci pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n); 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci outb(RESET_ASSP, chip->iobase + ASSP_CONTROL_B); 22908c2ecf20Sopenharmony_ci pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); 22918c2ecf20Sopenharmony_ci n &= ~INT_CLK_SELECT; 22928c2ecf20Sopenharmony_ci if (!chip->allegro_flag) { 22938c2ecf20Sopenharmony_ci n &= ~INT_CLK_MULT_ENABLE; 22948c2ecf20Sopenharmony_ci n |= INT_CLK_SRC_NOT_PCI; 22958c2ecf20Sopenharmony_ci } 22968c2ecf20Sopenharmony_ci n &= ~( CLK_MULT_MODE_SELECT | CLK_MULT_MODE_SELECT_2 ); 22978c2ecf20Sopenharmony_ci pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n); 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci if (chip->allegro_flag) { 23008c2ecf20Sopenharmony_ci pci_read_config_dword(pcidev, PCI_USER_CONFIG, &n); 23018c2ecf20Sopenharmony_ci n |= IN_CLK_12MHZ_SELECT; 23028c2ecf20Sopenharmony_ci pci_write_config_dword(pcidev, PCI_USER_CONFIG, n); 23038c2ecf20Sopenharmony_ci } 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci t = inb(chip->iobase + ASSP_CONTROL_A); 23068c2ecf20Sopenharmony_ci t &= ~( DSP_CLK_36MHZ_SELECT | ASSP_CLK_49MHZ_SELECT); 23078c2ecf20Sopenharmony_ci t |= ASSP_CLK_49MHZ_SELECT; 23088c2ecf20Sopenharmony_ci t |= ASSP_0_WS_ENABLE; 23098c2ecf20Sopenharmony_ci outb(t, chip->iobase + ASSP_CONTROL_A); 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_ci snd_m3_assp_init(chip); /* download DSP code before starting ASSP below */ 23128c2ecf20Sopenharmony_ci outb(RUN_ASSP, chip->iobase + ASSP_CONTROL_B); 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_ci outb(0x00, io + HARDWARE_VOL_CTRL); 23158c2ecf20Sopenharmony_ci outb(0x88, io + SHADOW_MIX_REG_VOICE); 23168c2ecf20Sopenharmony_ci outb(0x88, io + HW_VOL_COUNTER_VOICE); 23178c2ecf20Sopenharmony_ci outb(0x88, io + SHADOW_MIX_REG_MASTER); 23188c2ecf20Sopenharmony_ci outb(0x88, io + HW_VOL_COUNTER_MASTER); 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_ci return 0; 23218c2ecf20Sopenharmony_ci} 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_cistatic void 23248c2ecf20Sopenharmony_cisnd_m3_enable_ints(struct snd_m3 *chip) 23258c2ecf20Sopenharmony_ci{ 23268c2ecf20Sopenharmony_ci unsigned long io = chip->iobase; 23278c2ecf20Sopenharmony_ci unsigned short val; 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci /* TODO: MPU401 not supported yet */ 23308c2ecf20Sopenharmony_ci val = ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/; 23318c2ecf20Sopenharmony_ci if (chip->hv_config & HV_CTRL_ENABLE) 23328c2ecf20Sopenharmony_ci val |= HV_INT_ENABLE; 23338c2ecf20Sopenharmony_ci outb(val, chip->iobase + HOST_INT_STATUS); 23348c2ecf20Sopenharmony_ci outw(val, io + HOST_INT_CTRL); 23358c2ecf20Sopenharmony_ci outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE, 23368c2ecf20Sopenharmony_ci io + ASSP_CONTROL_C); 23378c2ecf20Sopenharmony_ci} 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci/* 23418c2ecf20Sopenharmony_ci */ 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_cistatic int snd_m3_free(struct snd_m3 *chip) 23448c2ecf20Sopenharmony_ci{ 23458c2ecf20Sopenharmony_ci struct m3_dma *s; 23468c2ecf20Sopenharmony_ci int i; 23478c2ecf20Sopenharmony_ci 23488c2ecf20Sopenharmony_ci cancel_work_sync(&chip->hwvol_work); 23498c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_MAESTRO3_INPUT 23508c2ecf20Sopenharmony_ci if (chip->input_dev) 23518c2ecf20Sopenharmony_ci input_unregister_device(chip->input_dev); 23528c2ecf20Sopenharmony_ci#endif 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci if (chip->substreams) { 23558c2ecf20Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 23568c2ecf20Sopenharmony_ci for (i = 0; i < chip->num_substreams; i++) { 23578c2ecf20Sopenharmony_ci s = &chip->substreams[i]; 23588c2ecf20Sopenharmony_ci /* check surviving pcms; this should not happen though.. */ 23598c2ecf20Sopenharmony_ci if (s->substream && s->running) 23608c2ecf20Sopenharmony_ci snd_m3_pcm_stop(chip, s, s->substream); 23618c2ecf20Sopenharmony_ci } 23628c2ecf20Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 23638c2ecf20Sopenharmony_ci kfree(chip->substreams); 23648c2ecf20Sopenharmony_ci } 23658c2ecf20Sopenharmony_ci if (chip->iobase) { 23668c2ecf20Sopenharmony_ci outw(0, chip->iobase + HOST_INT_CTRL); /* disable ints */ 23678c2ecf20Sopenharmony_ci } 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 23708c2ecf20Sopenharmony_ci vfree(chip->suspend_mem); 23718c2ecf20Sopenharmony_ci#endif 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci if (chip->irq >= 0) 23748c2ecf20Sopenharmony_ci free_irq(chip->irq, chip); 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci if (chip->iobase) 23778c2ecf20Sopenharmony_ci pci_release_regions(chip->pci); 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci release_firmware(chip->assp_kernel_image); 23808c2ecf20Sopenharmony_ci release_firmware(chip->assp_minisrc_image); 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_ci pci_disable_device(chip->pci); 23838c2ecf20Sopenharmony_ci kfree(chip); 23848c2ecf20Sopenharmony_ci return 0; 23858c2ecf20Sopenharmony_ci} 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci/* 23898c2ecf20Sopenharmony_ci * APM support 23908c2ecf20Sopenharmony_ci */ 23918c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 23928c2ecf20Sopenharmony_cistatic int m3_suspend(struct device *dev) 23938c2ecf20Sopenharmony_ci{ 23948c2ecf20Sopenharmony_ci struct snd_card *card = dev_get_drvdata(dev); 23958c2ecf20Sopenharmony_ci struct snd_m3 *chip = card->private_data; 23968c2ecf20Sopenharmony_ci int i, dsp_index; 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_ci if (chip->suspend_mem == NULL) 23998c2ecf20Sopenharmony_ci return 0; 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_ci chip->in_suspend = 1; 24028c2ecf20Sopenharmony_ci cancel_work_sync(&chip->hwvol_work); 24038c2ecf20Sopenharmony_ci snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 24048c2ecf20Sopenharmony_ci snd_ac97_suspend(chip->ac97); 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_ci msleep(10); /* give the assp a chance to idle.. */ 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci snd_m3_assp_halt(chip); 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci /* save dsp image */ 24118c2ecf20Sopenharmony_ci dsp_index = 0; 24128c2ecf20Sopenharmony_ci for (i = REV_B_CODE_MEMORY_BEGIN; i <= REV_B_CODE_MEMORY_END; i++) 24138c2ecf20Sopenharmony_ci chip->suspend_mem[dsp_index++] = 24148c2ecf20Sopenharmony_ci snd_m3_assp_read(chip, MEMTYPE_INTERNAL_CODE, i); 24158c2ecf20Sopenharmony_ci for (i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++) 24168c2ecf20Sopenharmony_ci chip->suspend_mem[dsp_index++] = 24178c2ecf20Sopenharmony_ci snd_m3_assp_read(chip, MEMTYPE_INTERNAL_DATA, i); 24188c2ecf20Sopenharmony_ci return 0; 24198c2ecf20Sopenharmony_ci} 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_cistatic int m3_resume(struct device *dev) 24228c2ecf20Sopenharmony_ci{ 24238c2ecf20Sopenharmony_ci struct snd_card *card = dev_get_drvdata(dev); 24248c2ecf20Sopenharmony_ci struct snd_m3 *chip = card->private_data; 24258c2ecf20Sopenharmony_ci int i, dsp_index; 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci if (chip->suspend_mem == NULL) 24288c2ecf20Sopenharmony_ci return 0; 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci /* first lets just bring everything back. .*/ 24318c2ecf20Sopenharmony_ci snd_m3_outw(chip, 0, 0x54); 24328c2ecf20Sopenharmony_ci snd_m3_outw(chip, 0, 0x56); 24338c2ecf20Sopenharmony_ci 24348c2ecf20Sopenharmony_ci snd_m3_chip_init(chip); 24358c2ecf20Sopenharmony_ci snd_m3_assp_halt(chip); 24368c2ecf20Sopenharmony_ci snd_m3_ac97_reset(chip); 24378c2ecf20Sopenharmony_ci 24388c2ecf20Sopenharmony_ci /* restore dsp image */ 24398c2ecf20Sopenharmony_ci dsp_index = 0; 24408c2ecf20Sopenharmony_ci for (i = REV_B_CODE_MEMORY_BEGIN; i <= REV_B_CODE_MEMORY_END; i++) 24418c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE, i, 24428c2ecf20Sopenharmony_ci chip->suspend_mem[dsp_index++]); 24438c2ecf20Sopenharmony_ci for (i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++) 24448c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, i, 24458c2ecf20Sopenharmony_ci chip->suspend_mem[dsp_index++]); 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci /* tell the dma engine to restart itself */ 24488c2ecf20Sopenharmony_ci snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, 24498c2ecf20Sopenharmony_ci KDATA_DMA_ACTIVE, 0); 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci /* restore ac97 registers */ 24528c2ecf20Sopenharmony_ci snd_ac97_resume(chip->ac97); 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci snd_m3_assp_continue(chip); 24558c2ecf20Sopenharmony_ci snd_m3_enable_ints(chip); 24568c2ecf20Sopenharmony_ci snd_m3_amp_enable(chip, 1); 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_ci snd_m3_hv_init(chip); 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci snd_power_change_state(card, SNDRV_CTL_POWER_D0); 24618c2ecf20Sopenharmony_ci chip->in_suspend = 0; 24628c2ecf20Sopenharmony_ci return 0; 24638c2ecf20Sopenharmony_ci} 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(m3_pm, m3_suspend, m3_resume); 24668c2ecf20Sopenharmony_ci#define M3_PM_OPS &m3_pm 24678c2ecf20Sopenharmony_ci#else 24688c2ecf20Sopenharmony_ci#define M3_PM_OPS NULL 24698c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_MAESTRO3_INPUT 24728c2ecf20Sopenharmony_cistatic int snd_m3_input_register(struct snd_m3 *chip) 24738c2ecf20Sopenharmony_ci{ 24748c2ecf20Sopenharmony_ci struct input_dev *input_dev; 24758c2ecf20Sopenharmony_ci int err; 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_ci input_dev = input_allocate_device(); 24788c2ecf20Sopenharmony_ci if (!input_dev) 24798c2ecf20Sopenharmony_ci return -ENOMEM; 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_ci snprintf(chip->phys, sizeof(chip->phys), "pci-%s/input0", 24828c2ecf20Sopenharmony_ci pci_name(chip->pci)); 24838c2ecf20Sopenharmony_ci 24848c2ecf20Sopenharmony_ci input_dev->name = chip->card->driver; 24858c2ecf20Sopenharmony_ci input_dev->phys = chip->phys; 24868c2ecf20Sopenharmony_ci input_dev->id.bustype = BUS_PCI; 24878c2ecf20Sopenharmony_ci input_dev->id.vendor = chip->pci->vendor; 24888c2ecf20Sopenharmony_ci input_dev->id.product = chip->pci->device; 24898c2ecf20Sopenharmony_ci input_dev->dev.parent = &chip->pci->dev; 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci __set_bit(EV_KEY, input_dev->evbit); 24928c2ecf20Sopenharmony_ci __set_bit(KEY_MUTE, input_dev->keybit); 24938c2ecf20Sopenharmony_ci __set_bit(KEY_VOLUMEDOWN, input_dev->keybit); 24948c2ecf20Sopenharmony_ci __set_bit(KEY_VOLUMEUP, input_dev->keybit); 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci err = input_register_device(input_dev); 24978c2ecf20Sopenharmony_ci if (err) { 24988c2ecf20Sopenharmony_ci input_free_device(input_dev); 24998c2ecf20Sopenharmony_ci return err; 25008c2ecf20Sopenharmony_ci } 25018c2ecf20Sopenharmony_ci 25028c2ecf20Sopenharmony_ci chip->input_dev = input_dev; 25038c2ecf20Sopenharmony_ci return 0; 25048c2ecf20Sopenharmony_ci} 25058c2ecf20Sopenharmony_ci#endif /* CONFIG_INPUT */ 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_ci/* 25088c2ecf20Sopenharmony_ci */ 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_cistatic int snd_m3_dev_free(struct snd_device *device) 25118c2ecf20Sopenharmony_ci{ 25128c2ecf20Sopenharmony_ci struct snd_m3 *chip = device->device_data; 25138c2ecf20Sopenharmony_ci return snd_m3_free(chip); 25148c2ecf20Sopenharmony_ci} 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_cistatic int 25178c2ecf20Sopenharmony_cisnd_m3_create(struct snd_card *card, struct pci_dev *pci, 25188c2ecf20Sopenharmony_ci int enable_amp, 25198c2ecf20Sopenharmony_ci int amp_gpio, 25208c2ecf20Sopenharmony_ci struct snd_m3 **chip_ret) 25218c2ecf20Sopenharmony_ci{ 25228c2ecf20Sopenharmony_ci struct snd_m3 *chip; 25238c2ecf20Sopenharmony_ci int i, err; 25248c2ecf20Sopenharmony_ci const struct snd_pci_quirk *quirk; 25258c2ecf20Sopenharmony_ci static const struct snd_device_ops ops = { 25268c2ecf20Sopenharmony_ci .dev_free = snd_m3_dev_free, 25278c2ecf20Sopenharmony_ci }; 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci *chip_ret = NULL; 25308c2ecf20Sopenharmony_ci 25318c2ecf20Sopenharmony_ci if (pci_enable_device(pci)) 25328c2ecf20Sopenharmony_ci return -EIO; 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci /* check, if we can restrict PCI DMA transfers to 28 bits */ 25358c2ecf20Sopenharmony_ci if (dma_set_mask(&pci->dev, DMA_BIT_MASK(28)) < 0 || 25368c2ecf20Sopenharmony_ci dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(28)) < 0) { 25378c2ecf20Sopenharmony_ci dev_err(card->dev, 25388c2ecf20Sopenharmony_ci "architecture does not support 28bit PCI busmaster DMA\n"); 25398c2ecf20Sopenharmony_ci pci_disable_device(pci); 25408c2ecf20Sopenharmony_ci return -ENXIO; 25418c2ecf20Sopenharmony_ci } 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci chip = kzalloc(sizeof(*chip), GFP_KERNEL); 25448c2ecf20Sopenharmony_ci if (chip == NULL) { 25458c2ecf20Sopenharmony_ci pci_disable_device(pci); 25468c2ecf20Sopenharmony_ci return -ENOMEM; 25478c2ecf20Sopenharmony_ci } 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_ci spin_lock_init(&chip->reg_lock); 25508c2ecf20Sopenharmony_ci 25518c2ecf20Sopenharmony_ci switch (pci->device) { 25528c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_ESS_ALLEGRO: 25538c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_ESS_ALLEGRO_1: 25548c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_ESS_CANYON3D_2LE: 25558c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_ESS_CANYON3D_2: 25568c2ecf20Sopenharmony_ci chip->allegro_flag = 1; 25578c2ecf20Sopenharmony_ci break; 25588c2ecf20Sopenharmony_ci } 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci chip->card = card; 25618c2ecf20Sopenharmony_ci chip->pci = pci; 25628c2ecf20Sopenharmony_ci chip->irq = -1; 25638c2ecf20Sopenharmony_ci INIT_WORK(&chip->hwvol_work, snd_m3_update_hw_volume); 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci chip->external_amp = enable_amp; 25668c2ecf20Sopenharmony_ci if (amp_gpio >= 0 && amp_gpio <= 0x0f) 25678c2ecf20Sopenharmony_ci chip->amp_gpio = amp_gpio; 25688c2ecf20Sopenharmony_ci else { 25698c2ecf20Sopenharmony_ci quirk = snd_pci_quirk_lookup(pci, m3_amp_quirk_list); 25708c2ecf20Sopenharmony_ci if (quirk) { 25718c2ecf20Sopenharmony_ci dev_info(card->dev, "set amp-gpio for '%s'\n", 25728c2ecf20Sopenharmony_ci snd_pci_quirk_name(quirk)); 25738c2ecf20Sopenharmony_ci chip->amp_gpio = quirk->value; 25748c2ecf20Sopenharmony_ci } else if (chip->allegro_flag) 25758c2ecf20Sopenharmony_ci chip->amp_gpio = GPO_EXT_AMP_ALLEGRO; 25768c2ecf20Sopenharmony_ci else /* presumably this is for all 'maestro3's.. */ 25778c2ecf20Sopenharmony_ci chip->amp_gpio = GPO_EXT_AMP_M3; 25788c2ecf20Sopenharmony_ci } 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci quirk = snd_pci_quirk_lookup(pci, m3_irda_quirk_list); 25818c2ecf20Sopenharmony_ci if (quirk) { 25828c2ecf20Sopenharmony_ci dev_info(card->dev, "enabled irda workaround for '%s'\n", 25838c2ecf20Sopenharmony_ci snd_pci_quirk_name(quirk)); 25848c2ecf20Sopenharmony_ci chip->irda_workaround = 1; 25858c2ecf20Sopenharmony_ci } 25868c2ecf20Sopenharmony_ci quirk = snd_pci_quirk_lookup(pci, m3_hv_quirk_list); 25878c2ecf20Sopenharmony_ci if (quirk) 25888c2ecf20Sopenharmony_ci chip->hv_config = quirk->value; 25898c2ecf20Sopenharmony_ci if (snd_pci_quirk_lookup(pci, m3_omnibook_quirk_list)) 25908c2ecf20Sopenharmony_ci chip->is_omnibook = 1; 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci chip->num_substreams = NR_DSPS; 25938c2ecf20Sopenharmony_ci chip->substreams = kcalloc(chip->num_substreams, sizeof(struct m3_dma), 25948c2ecf20Sopenharmony_ci GFP_KERNEL); 25958c2ecf20Sopenharmony_ci if (chip->substreams == NULL) { 25968c2ecf20Sopenharmony_ci kfree(chip); 25978c2ecf20Sopenharmony_ci pci_disable_device(pci); 25988c2ecf20Sopenharmony_ci return -ENOMEM; 25998c2ecf20Sopenharmony_ci } 26008c2ecf20Sopenharmony_ci 26018c2ecf20Sopenharmony_ci err = request_firmware(&chip->assp_kernel_image, 26028c2ecf20Sopenharmony_ci "ess/maestro3_assp_kernel.fw", &pci->dev); 26038c2ecf20Sopenharmony_ci if (err < 0) 26048c2ecf20Sopenharmony_ci goto free_chip; 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci err = request_firmware(&chip->assp_minisrc_image, 26078c2ecf20Sopenharmony_ci "ess/maestro3_assp_minisrc.fw", &pci->dev); 26088c2ecf20Sopenharmony_ci if (err < 0) 26098c2ecf20Sopenharmony_ci goto free_chip; 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ci err = pci_request_regions(pci, card->driver); 26128c2ecf20Sopenharmony_ci if (err < 0) 26138c2ecf20Sopenharmony_ci goto free_chip; 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_ci chip->iobase = pci_resource_start(pci, 0); 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_ci /* just to be sure */ 26188c2ecf20Sopenharmony_ci pci_set_master(pci); 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci snd_m3_chip_init(chip); 26218c2ecf20Sopenharmony_ci snd_m3_assp_halt(chip); 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_ci snd_m3_ac97_reset(chip); 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci snd_m3_amp_enable(chip, 1); 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci snd_m3_hv_init(chip); 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_ci if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED, 26308c2ecf20Sopenharmony_ci KBUILD_MODNAME, chip)) { 26318c2ecf20Sopenharmony_ci dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); 26328c2ecf20Sopenharmony_ci err = -ENOMEM; 26338c2ecf20Sopenharmony_ci goto free_chip; 26348c2ecf20Sopenharmony_ci } 26358c2ecf20Sopenharmony_ci chip->irq = pci->irq; 26368c2ecf20Sopenharmony_ci card->sync_irq = chip->irq; 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 26398c2ecf20Sopenharmony_ci chip->suspend_mem = 26408c2ecf20Sopenharmony_ci vmalloc(array_size(sizeof(u16), 26418c2ecf20Sopenharmony_ci REV_B_CODE_MEMORY_LENGTH + 26428c2ecf20Sopenharmony_ci REV_B_DATA_MEMORY_LENGTH)); 26438c2ecf20Sopenharmony_ci if (chip->suspend_mem == NULL) 26448c2ecf20Sopenharmony_ci dev_warn(card->dev, "can't allocate apm buffer\n"); 26458c2ecf20Sopenharmony_ci#endif 26468c2ecf20Sopenharmony_ci 26478c2ecf20Sopenharmony_ci err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); 26488c2ecf20Sopenharmony_ci if (err < 0) 26498c2ecf20Sopenharmony_ci goto free_chip; 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ci if ((err = snd_m3_mixer(chip)) < 0) 26528c2ecf20Sopenharmony_ci return err; 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci for (i = 0; i < chip->num_substreams; i++) { 26558c2ecf20Sopenharmony_ci struct m3_dma *s = &chip->substreams[i]; 26568c2ecf20Sopenharmony_ci if ((err = snd_m3_assp_client_init(chip, s, i)) < 0) 26578c2ecf20Sopenharmony_ci return err; 26588c2ecf20Sopenharmony_ci } 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_ci if ((err = snd_m3_pcm(chip, 0)) < 0) 26618c2ecf20Sopenharmony_ci return err; 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_MAESTRO3_INPUT 26648c2ecf20Sopenharmony_ci if (chip->hv_config & HV_CTRL_ENABLE) { 26658c2ecf20Sopenharmony_ci err = snd_m3_input_register(chip); 26668c2ecf20Sopenharmony_ci if (err) 26678c2ecf20Sopenharmony_ci dev_warn(card->dev, 26688c2ecf20Sopenharmony_ci "Input device registration failed with error %i", 26698c2ecf20Sopenharmony_ci err); 26708c2ecf20Sopenharmony_ci } 26718c2ecf20Sopenharmony_ci#endif 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci snd_m3_enable_ints(chip); 26748c2ecf20Sopenharmony_ci snd_m3_assp_continue(chip); 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci *chip_ret = chip; 26778c2ecf20Sopenharmony_ci 26788c2ecf20Sopenharmony_ci return 0; 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_cifree_chip: 26818c2ecf20Sopenharmony_ci snd_m3_free(chip); 26828c2ecf20Sopenharmony_ci return err; 26838c2ecf20Sopenharmony_ci} 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci/* 26868c2ecf20Sopenharmony_ci */ 26878c2ecf20Sopenharmony_cistatic int 26888c2ecf20Sopenharmony_cisnd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) 26898c2ecf20Sopenharmony_ci{ 26908c2ecf20Sopenharmony_ci static int dev; 26918c2ecf20Sopenharmony_ci struct snd_card *card; 26928c2ecf20Sopenharmony_ci struct snd_m3 *chip; 26938c2ecf20Sopenharmony_ci int err; 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ci /* don't pick up modems */ 26968c2ecf20Sopenharmony_ci if (((pci->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO) 26978c2ecf20Sopenharmony_ci return -ENODEV; 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci if (dev >= SNDRV_CARDS) 27008c2ecf20Sopenharmony_ci return -ENODEV; 27018c2ecf20Sopenharmony_ci if (!enable[dev]) { 27028c2ecf20Sopenharmony_ci dev++; 27038c2ecf20Sopenharmony_ci return -ENOENT; 27048c2ecf20Sopenharmony_ci } 27058c2ecf20Sopenharmony_ci 27068c2ecf20Sopenharmony_ci err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, 27078c2ecf20Sopenharmony_ci 0, &card); 27088c2ecf20Sopenharmony_ci if (err < 0) 27098c2ecf20Sopenharmony_ci return err; 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci switch (pci->device) { 27128c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_ESS_ALLEGRO: 27138c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_ESS_ALLEGRO_1: 27148c2ecf20Sopenharmony_ci strcpy(card->driver, "Allegro"); 27158c2ecf20Sopenharmony_ci break; 27168c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_ESS_CANYON3D_2LE: 27178c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_ESS_CANYON3D_2: 27188c2ecf20Sopenharmony_ci strcpy(card->driver, "Canyon3D-2"); 27198c2ecf20Sopenharmony_ci break; 27208c2ecf20Sopenharmony_ci default: 27218c2ecf20Sopenharmony_ci strcpy(card->driver, "Maestro3"); 27228c2ecf20Sopenharmony_ci break; 27238c2ecf20Sopenharmony_ci } 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci err = snd_m3_create(card, pci, external_amp[dev], amp_gpio[dev], &chip); 27268c2ecf20Sopenharmony_ci if (err < 0) 27278c2ecf20Sopenharmony_ci goto free_card; 27288c2ecf20Sopenharmony_ci 27298c2ecf20Sopenharmony_ci card->private_data = chip; 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_ci sprintf(card->shortname, "ESS %s PCI", card->driver); 27328c2ecf20Sopenharmony_ci sprintf(card->longname, "%s at 0x%lx, irq %d", 27338c2ecf20Sopenharmony_ci card->shortname, chip->iobase, chip->irq); 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_ci err = snd_card_register(card); 27368c2ecf20Sopenharmony_ci if (err < 0) 27378c2ecf20Sopenharmony_ci goto free_card; 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci#if 0 /* TODO: not supported yet */ 27408c2ecf20Sopenharmony_ci /* TODO enable MIDI IRQ and I/O */ 27418c2ecf20Sopenharmony_ci err = snd_mpu401_uart_new(chip->card, 0, MPU401_HW_MPU401, 27428c2ecf20Sopenharmony_ci chip->iobase + MPU401_DATA_PORT, 27438c2ecf20Sopenharmony_ci MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, 27448c2ecf20Sopenharmony_ci -1, &chip->rmidi); 27458c2ecf20Sopenharmony_ci if (err < 0) 27468c2ecf20Sopenharmony_ci dev_warn(card->dev, "no MIDI support.\n"); 27478c2ecf20Sopenharmony_ci#endif 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_ci pci_set_drvdata(pci, card); 27508c2ecf20Sopenharmony_ci dev++; 27518c2ecf20Sopenharmony_ci return 0; 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_cifree_card: 27548c2ecf20Sopenharmony_ci snd_card_free(card); 27558c2ecf20Sopenharmony_ci return err; 27568c2ecf20Sopenharmony_ci} 27578c2ecf20Sopenharmony_ci 27588c2ecf20Sopenharmony_cistatic void snd_m3_remove(struct pci_dev *pci) 27598c2ecf20Sopenharmony_ci{ 27608c2ecf20Sopenharmony_ci snd_card_free(pci_get_drvdata(pci)); 27618c2ecf20Sopenharmony_ci} 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_cistatic struct pci_driver m3_driver = { 27648c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 27658c2ecf20Sopenharmony_ci .id_table = snd_m3_ids, 27668c2ecf20Sopenharmony_ci .probe = snd_m3_probe, 27678c2ecf20Sopenharmony_ci .remove = snd_m3_remove, 27688c2ecf20Sopenharmony_ci .driver = { 27698c2ecf20Sopenharmony_ci .pm = M3_PM_OPS, 27708c2ecf20Sopenharmony_ci }, 27718c2ecf20Sopenharmony_ci}; 27728c2ecf20Sopenharmony_ci 27738c2ecf20Sopenharmony_cimodule_pci_driver(m3_driver); 2774